Commit Graph

4538 Commits

Author SHA1 Message Date
Artem Boldariev
d62eb206f7 Fix isc_nmsocket_set_tlsctx()
During loop manager refactoring isc_nmsocket_set_tlsctx() was not
properly adapted. The function is expected to broadcast the new TLS
context for every worker, but this behaviour was accidentally broken.
2022-10-14 23:06:31 +03:00
Ondřej Surý
cedfc97974 Improve reporting for pthread_once errors
Replace all uses of RUNTIME_CHECK() in lib/isc/include/isc/once.h with
PTHEADS_RUNTIME_CHECK(), in order to improve error reporting for any
once-related run-time failures (by augmenting error messages with
file/line/caller information and the error string corresponding to
errno).
2022-10-14 16:39:21 +02:00
Ondřej Surý
beecde7120 Rewrite isc_httpd using picohttpparser and isc_url_parse
Rewrite the isc_httpd to be more robust.

1. Replace the hand-crafted HTTP request parser with picohttpparser for
   parsing the whole HTTP/1.0 and HTTP/1.1 requests.  Limit the number
   of allowed headers to 10 (arbitrary number).

2. Replace the hand-crafted URL parser with isc_url_parse for parsing
   the URL from the HTTP request.

3. Increase the receive buffer to match the isc_netmgr buffers, so we
   can at least receive two full isc_nm_read()s.  This makes the
   truncation processing much simpler.

4. Process the received buffer from single isc_nm_read() in a single
   loop and schedule the sends to be independent of each other.

The first two changes makes the code simpler and rely on already
existing libraries that we already had (isc_url based on nodejs) or are
used elsewhere (picohttpparser).

The second two changes remove the artificial "truncation" limit on
parsing multiple request.  Now only a request that has too many
headers (currently 10) or is too big (so, the receive buffer fills up
without reaching end of the request) will end the connection.

We can be benevolent here with the limites, because the statschannel
channel is by definition private and access must be allowed only to
administrators of the server.  There are no timers, no rate-limiting, no
upper limit on the number of requests that can be served, etc.
2022-10-14 11:26:54 +02:00
Ondřej Surý
3a8884f024 Add picohttpparser.{c.h} from https://github.com/h2o/picohttpparser
PicoHTTPParser is a tiny, primitive, fast HTTP request/response parser.

Unlike most parsers, it is stateless and does not allocate memory by
itself. All it does is accept pointer to buffer and the output
structure, and setups the pointers in the latter to point at the
necessary portions of the buffer.
2022-10-14 11:26:54 +02:00
Ondřej Surý
b6b7a6886a Don't set load-balancing socket option on the UDP connect sockets
The isc_nm_udpconnect() erroneously set the reuse port with
load-balancing on the outgoing connected UDP sockets.  This socket
option makes only sense for the listening sockets.  Don't set the
load-balancing reuse port option on the outgoing UDP sockets.
2022-10-12 15:36:25 +02:00
Artem Boldariev
eaebb92f3e TLS DNS: fix certificate verification error message reporting
This commit fixes TLS DNS verification error message reporting which
we probably broke during one of the recent networking code
refactorings.

This prevent e.g. dig from producing useful error messages related to
TLS certificates verification.
2022-10-12 16:24:04 +03:00
Artem Boldariev
6789b88d25 TLS: clear error queue before doing IO or calling SSL_get_error()
Ensure that TLS error is empty before calling SSL_get_error() or doing
SSL I/O so that the result will not get affected by prior error
statuses.

In particular, the improper error handling led to intermittent unit
test failure and, thus, could be responsible for some of the system
test failures and other intermittent TLS-related issues.

See here for more details:

https://www.openssl.org/docs/man3.0/man3/SSL_get_error.html

In particular, it mentions the following:

> The current thread's error queue must be empty before the TLS/SSL
> I/O operation is attempted, or SSL_get_error() will not work
> reliably.

As we use the result of SSL_get_error() to decide on I/O operations,
we need to ensure that it works reliably by cleaning the error queue.

TLS DNS: empty error queue before attempting I/O
2022-10-12 16:24:04 +03:00
Aram Sargsyan
be95ba0119 Remove a superfluous check of sock->fd against -1
The check is left from when tcp_connect_direct() called isc__nm_socket()
and it was uncertain whether it had succeeded, but now isc__nm_socket()
is called before tcp_connect_direct(), so sock->fd cannot be -1.

    *** CID 357292:    (REVERSE_NEGATIVE)
    /lib/isc/netmgr/tcp.c: 309 in isc_nm_tcpconnect()
    303
    304     	atomic_store(&sock->active, true);
    305
    306     	result = tcp_connect_direct(sock, req);
    307     	if (result != ISC_R_SUCCESS) {
    308     		atomic_store(&sock->active, false);
    >>>     CID 357292:    (REVERSE_NEGATIVE)
    >>>     You might be using variable "sock->fd" before verifying that it is >= 0.
    309     		if (sock->fd != (uv_os_sock_t)(-1)) {
    310     			isc__nm_tcp_close(sock);
    311     		}
    312     		isc__nm_connectcb(sock, req, result, true);
    313     	}
    314
2022-10-12 08:21:35 +00:00
Tony Finch
138908b211 Avoid dead code warning when using a constant boolean
The value of `sign_bit` is platform-dependent but constant at compile
time. Use a cast to convert the boolean `sign_bit` to 0 or 1 instead of
ternary `?:` because one branch of the conditional is dead code. (We
could leave out the cast to `size_t` but our style prefers to handle
booleans more explicitly, hence the `?:` that caused the issue.)

    *** CID 358310:  Possible Control flow issues  (DEADCODE)
    /lib/isc/resource.c: 118 in isc_resource_setlimit()
    112     		 * rlim_t, and whether rlim_t has a sign bit.
    113     		 */
    114     		isc_resourcevalue_t rlim_max = UINT64_MAX;
    115     		size_t wider = sizeof(rlim_max) - sizeof(rlim_t);
    116     		bool sign_bit = (double)(rlim_t)-1 < 0;
    117
    >>>     CID 358310:  Possible Control flow issues  (DEADCODE)
    >>>     Execution cannot reach the expression "1" inside this statement: "rlim_max >>= 8UL * wider + ...".
    118     		rlim_max >>= CHAR_BIT * wider + (sign_bit ? 1 : 0);
    119     		rlim_value = ISC_MIN(value, rlim_max);
    120     	}
    121
    122     	rl.rlim_cur = rl.rlim_max = rlim_value;
    123     	unixresult = setrlimit(unixresource, &rl);
2022-10-05 15:51:05 +00:00
Ondřej Surý
c0598d404c Use designated initializers instead of memset()/MEM_ZERO for structs
In several places, the structures were cleaned with memset(...)) and
thus the semantic patch converted the isc_mem_get(...) to
isc_mem_getx(..., ISC_MEM_ZERO).  Use the designated initializer to
initialized the structures instead of zeroing the memory with
ISC_MEM_ZERO flag as this better matches the intended purpose.
2022-10-05 16:44:05 +02:00
Ondřej Surý
c1d26b53eb Add and use semantic patch to replace isc_mem_get/allocate+memset
Add new semantic patch to replace the straightfoward uses of:

  ptr = isc_mem_{get,allocate}(..., size);
  memset(ptr, 0, size);

with the new API call:

  ptr = isc_mem_{get,allocate}x(..., size, ISC_MEM_ZERO);
2022-10-05 16:44:05 +02:00
Ondřej Surý
dbf5672f32 Replace isc_mem_*_aligned(..., alignment) with isc_mem_*x(..., flags)
Previously, the isc_mem_get_aligned() and friends took alignment size as
one of the arguments.  Replace the specific function with more generic
extended variant that now accepts ISC_MEM_ALIGN(alignment) for aligned
allocations and ISC_MEM_ZERO for allocations that zeroes
the (re-)allocated memory before returning the pointer to the caller.
2022-10-05 16:44:05 +02:00
Ondřej Surý
c14a4ac763 Add a case-insensitive option directly to siphash 2-4 implementation
Formerly, the isc_hash32() would have to change the key in a local copy
to make it case insensitive.  Change the isc_siphash24() and
isc_halfsiphash24() functions to lowercase the input directly when
reading it from the memory and converting the uint8_t * array to
64-bit (respectively 32-bit numbers).
2022-10-04 10:32:40 +02:00
Mark Andrews
5f07fe8cbb Use strnstr implementation from FreeBSD if not provided by OS 2022-10-04 14:21:41 +11:00
Tony Finch
4e37a6f77a Avoid signed integer overflow in isc_resource_setlimit()
On systems with signed rlim_t the old code calculated its maximum
value by shifting 1 into the sign bit, which is undefined behaviour.
Avoid the bug by using an unsigned shift.
2022-10-03 11:37:17 +00:00
Ondřej Surý
477eb22c12 Refactor isc_ratelimiter API
Because the dns_zonemgr_create() was run before the loopmgr was started,
the isc_ratelimiter API was more complicated that it had to be.  Move
the dns_zonemgr_create() to run_server() task which is run on the main
loop, and simplify the isc_ratelimiter API implementation.

The isc_timer is now created in the isc_ratelimiter_create() and
starting the timer is now separate async task as is destroying the timer
in case it's not launched from the loop it was created on.  The
ratelimiter tick now doesn't have to create and destroy timer logic and
just stops the timer when there's no more work to do.

This should also solve all the races that were causing the
isc_ratelimiter to be left dangling because the timer was stopped before
the last reference would be detached.
2022-09-30 10:36:30 +02:00
Ondřej Surý
09b50d2237 Fix small problems in the isc_ratelimiter 2022-09-30 09:50:17 +02:00
Ondřej Surý
1e2ededb07 Add missing DbC check for name##_detach in ISC_REFCOUNT_IMPL macro
The detach function in the ISC_REFCOUNT_IMPL macro was missing DbC
checks, add them.
2022-09-30 09:50:17 +02:00
Tony Finch
a4930e1969 Improve DBC in isc_mem_free
Unlike standard free(), isc_mem_free() is not a no-op when passed a
NULL pointer. For size accounting purposes it calls sallocx(), which
crashes when passed a NULL pointer. To get more helpful diagnostics,
REQUIRE() that the pointer is not NULL so that when the programmer
makes a mistake they get a backtrace that shows what went wrong.
2022-09-29 10:07:34 +00:00
Ondřej Surý
173c352452 Call the isc__nm_udp_send() callbacks asynchronously on shutdown
The isc__nm_udp_send() callback would be called synchronously when
shutting down or when the socket has been closed.  This could lead to
double locking in the calling code and thus those callbacks needs to be
called asynchronously.
2022-09-29 11:06:58 +02:00
Ondřej Surý
3b31f7f563 Add autoconf option to enable memory leak detection in libraries
There's a known memory leak in the engine_pkcs11 at the time of writing
this and it interferes with the named ability to check for memory leaks
in the OpenSSL memory context by default.

Add an autoconf option to explicitly enable the memory leak detection,
and use it in the CI except for pkcs11 enabled builds.  When this gets
fixed in the engine_pkc11, the option can be enabled by default.
2022-09-27 17:53:04 +02:00
Ondřej Surý
e537fea861 Use custom isc_mem based allocator for libxml2
The libxml2 library provides a way to replace the default allocator with
user supplied allocator (malloc, realloc, strdup and free).

Create a memory context specifically for libxml2 to allow tracking the
memory usage that has originated from within libxml2.  This will provide
a separate memory context for libxml2 to track the allocations and when
shutting down the application it will check that all libxml2 allocations
were returned to the allocator.

Additionally, move the xmlInitParser() and xmlCleanupParser() calls from
bin/named/main.c to library constructor/destructor in libisc library.
2022-09-27 17:10:42 +02:00
Ondřej Surý
236d4b7739 Use custom isc_mem based allocator for OpenSSL
The OpenSSL library provides a way to replace the default allocator with
user supplied allocator (malloc, realloc, and free).

Create a memory context specifically for OpenSSL to allow tracking the
memory usage that has originated from within OpenSSL.  This will provide
a separate memory context for OpenSSL to track the allocations and when
shutting down the application it will check that all OpenSSL allocations
were returned to the allocator.
2022-09-27 17:10:42 +02:00
Ondřej Surý
a32d06dd42 Use custom isc_mem based allocator for libuv
The libuv library provides a way to replace the default allocator with
user supplied allocator (malloc, realloc, calloc and free).

Create a memory context specifically for libuv to allow tracking the
memory usage that has originated from within libuv.  This requires
libuv >= 1.38.0 which provides uv_library_shutdown() function that
assures no more allocations will be made.
2022-09-27 17:10:42 +02:00
Ondřej Surý
a30e75db86 Check for working __builtin_mul_overflow() implementation
Instead of using generic HAVE_BUILTIN_OVERFLOW, we need to check whether
the overflow functions actually work as there was a bug in GCC that it
would not detect mul overflow when compiled with `-m32` option without
optimizations and the bug was fixed only for GCC 6.5+ and 7.3+/8+.

For further details see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82274
2022-09-27 17:10:42 +02:00
Ondřej Surý
2d2022a509 Make the debugging flags local to the memory context
Previously, the isc_mem_debugging would be single global variable that
would affect the behavior of the memory context whenever it would be
changed which could be after some allocation were already done.

Change the memory debugging options to be local to the memory context
and immutable, so all allocations within the same memory context are
treated the same.
2022-09-27 17:10:41 +02:00
Ondřej Surý
0086ebf3fc Bump the libuv requirement to libuv >= 1.34.0
By bumping the minimum libuv version to 1.34.0, it allows us to remove
all libuv shims we ever had and makes the code much cleaner.  The
up-to-date libuv is available in all distributions supported by BIND
9.19+ either natively or as a backport.
2022-09-27 17:09:10 +02:00
Evan Hunt
1926ddc987 change ISC__BUFFER macros to inline functions
previously, when ISC_BUFFER_USEINLINE was defined, macros were
used to implement isc_buffer primitives (isc_buffer_init(),
isc_buffer_region(), etc). these macros were missing the DbC
assertions for those primitives, which made it possible for
coding errors to go undetected.

adding the assertions to the macros caused compiler warnings on
some platforms. therefore, this commit converts the ISC__BUFFER
macros to static inline functions instead, with assertions included,
and eliminates the non-inline implementation from buffer.c.

the --enable-buffer-useinline configure option has been removed.
2022-09-26 23:49:27 -07:00
Ondřej Surý
1baed21688 Switch the CSPRNG function from RAND_bytes() to uv_random()
The RAND_bytes() implementation differs between the OpenSSL versions and
uses the system entropy only for seeding its internal CSPRNG.  The
uv_random() on the other hand uses the system provided CSPRNG.

Switch from RAND_bytes() to uv_random() to use system provided CSPRNG.
2022-09-26 15:13:11 +02:00
Ondřej Surý
fffd444440 Cleanup the asychronous code in the stream implementations
After the loopmgr work has been merged, we can now cleanup the TCP and
TLS protocols a little bit, because there are stronger guarantees that
the sockets will be kept on the respective loops/threads.  We only need
asynchronous call for listening sockets (start, stop) and reading from
the TCP (because the isc_nm_read() might be called from read callback
again.

This commit does the following changes (they are intertwined together):

1. Cleanup most of the asynchronous events in the TCP code, and add
   comments for the events that needs to be kept asynchronous.

2. Remove isc_nm_resumeread() from the netmgr API, and replace
   isc_nm_resumeread() calls with existing isc_nm_read() calls.

3. Remove isc_nm_pauseread() from the netmgr API, and replace
   isc_nm_pauseread() calls with a new isc_nm_read_stop() call.

4. Disable the isc_nm_cancelread() for the streaming protocols, only the
   datagram-like protocols can use isc_nm_cancelread().

5. Add isc_nmhandle_close() that can be used to shutdown the socket
  earlier than after the last detach.  Formerly, the socket would be
  closed only after all reading and sending would be finished and the
  last reference would be detached.  The new isc_nmhandle_close() can
  be used to close the underlying socket earlier, so all the other
  asynchronous calls would call their respective callbacks immediately.

Co-authored-by: Ondřej Surý <ondrej@isc.org>
Co-authored-by: Artem Boldariev <artem@isc.org>
2022-09-22 14:51:15 +02:00
Ondřej Surý
5319d4f6c5 Require isc_timer to be manipulated on the timer loop
Each isc_timer needs to be created, started and destroyed on the current
loop.  The isc_timer_stop() can be run on any loop, but when run from
different loop than the one associated with the timer, the request to
stop the timer will be recorded in atomic variable and the underlying
uv_timer_t will be stopped on next uv_timer_t callback call.  This
allows any thread to stop the timer.
2022-09-21 14:25:33 -07:00
Ondřej Surý
869c6d77a2 Convert isc_ratelimiter API to use on-loop timers
In preparation for the on-loop timers, the isc_ratelimiter API was
converted to use the timer on main loop and start and stop the timer
asynchronously on the main loop.
2022-09-21 14:25:33 -07:00
Ondřej Surý
27d1e498b8 Add isc_timer_async_destroy() helper function
As it sometimes happens that the object using isc_timer_t is destroyed
via detaching all the references with no guarantee that the last thread
will be matching thread, add a helper isc_timer_async_destroy() function
that stops the timer and runs the destroy function via isc_async_run()
on the matching thread.
2022-09-21 14:25:33 -07:00
Evan Hunt
4b7248545e additional code cleanups in httpd.c
- use isc_buffer functions when appropriate, rather than converting
  to and from isc_region unnecessarily
- use the zlib total_out value instead of calculating it
- use c99 struct initialization
2022-09-21 11:45:12 -07:00
Tony Finch
4b9af22830 Ensure the first random number is non-zero when fuzzing
In fuzzing mode, `isc_random` uses a fixed seed for reproducibility.
The particular seed chosen happened to produce zero as its first
number, however commit bd251de0 introduced an initialization check in
`random_test` that required it to be non-zero. This change adjusts the
seed to avoid spurious test failures.

Also, remove the temporary variable that was used for initialization
because it did not match the type of the thread-local seed array.
2022-09-21 12:47:26 +01:00
Michał Kępień
2ee16067c5 Merge tag 'v9_19_5'
BIND 9.19.5
2022-09-21 13:04:58 +02:00
Tony Finch
bd251de035 Move random number re-seeding out of the hot path
Instead of checking if we need to re-seed for every isc_random call,
seed the random number generator in the libisc global initializer
and the per-thread initializer.
2022-09-19 16:27:12 +02:00
Ondřej Surý
f6e4f620b3 Use the semantic patch to do the unsigned -> unsigned int change
Apply the semantic patch on the whole code base to get rid of 'unsigned'
usage in favor of explicit 'unsigned int'.
2022-09-19 15:56:02 +02:00
Ondřej Surý
b1026dd4c1 Add missing isc_refcount_destroy() for isc__nmsocket_t
The destructor for the isc__nmsocket_t was missing call to the
isc_refcount_destroy() on the reference counter, which might lead to
spurious ThreadSanitizer data race warnings if we ever change the
acquire-release memory order in the isc_refcount_decrement().
2022-09-19 14:38:56 +02:00
Ondřej Surý
9b8d432403 Reorder the uv_close() calls to close the socket immediately
Simplify the closing code - during the loopmgr implementation, it was
discovered that the various lists used by the uv_loop_t aren't FIFO, but
LIFO.  See doc/dev/libuv.md for more details.

With this knowledge, we can close the protocol handles (uv_udp_t and
uv_tcp_t) and uv_timer_t at the same time by reordering the uv_close()
calls, and thus making sure that after calling the
isc__nm_stoplistening(), the code will not issue any additional callback
calls (accept, read) on the socket that stopped listening.

This might help with the TLS and DoH shutting down sequence as described
in the [GL #3509] as we now stop the reading, stop the timer and call
the uv_close() as earliest as possible.
2022-09-19 14:38:56 +02:00
Ondřej Surý
eac8bc5c1a Prevent unexpected UDP client read callbacks
The network manager UDP code was misinterpreting when the libuv called
the udp_recv_cb with nrecv == 0 and addr == NULL -> this doesn't really
mean that the "stream" has ended, but the libuv indicates that the
receive buffer can be freed.  This could lead to assertion failure in
the code that calls isc_nm_read() from the network manager read callback
due to the extra spurious callbacks.

Properly handle the extra callback calls from the libuv in the client
read callback, and refactor the UDP isc_nm_read() implementation to be
synchronous, so no datagram is lost between the time that we stop the
reading from the UDP socket and we restart it again in the asychronous
udpread event.

Add a unit test that tests the isc_nm_read() call from the read
callback to receive two datagrams.
2022-09-19 12:20:41 +02:00
Ondřej Surý
6562227cc8 Handle canceled read during sending data over stats channel
An assertion failure would be triggered when the TCP connection
is canceled during sending the data back to the client.

Don't require the state to be `RECV` on non successful read to
gracefully handle canceled TCP connection during the SEND state of the
HTTPD channel.
2022-09-15 10:29:37 +02:00
Tony Finch
21a383a8fd General-purpose unrolled ASCII tolower() loops
When converting a string to lower case, the compiler is able to
autovectorize nicely, so a nice simple implementation is also very
fast, comparable to memcpy().

Comparisons are more difficult for the compiler, so we convert eight
bytes at a time using "SIMD within a register" tricks. Experiments
indicate it's best to stick to simple loops for shorter strings and
the remainder of long strings.
2022-09-12 12:18:57 +01:00
Tony Finch
27a561273e Consolidate some ASCII tables in isc/ascii and isc/hex
There were a number of places that had copies of various ASCII
tables (case conversion, hex and decimal conversion) that are intended
to be faster than the ctype.h macros, or avoid locale pollution.

Move them into libisc, and wrap the lookup tables with macros that
avoid the ctype.h gotchas.
2022-09-12 12:18:57 +01:00
Michał Kępień
3b1c80fd0f Fix error reporting for POSIX Threads functions
Commit 3608abc8fa inadvertently carried
over a mistake in logging pthread_cond_init() errors to the
ERRNO_CHECK() preprocessor macro: instead of passing the value returned
by a given pthread_*() function to strerror_r(), ERRNO_CHECK() passes
the errno variable to strerror_r().  This causes bogus error reports
because POSIX Threads API functions do not set the errno variable.

Fix by passing the value returned by a given pthread_*() function
instead of the errno variable to strerror_r().  Since this change makes
the name of the affected macro (ERRNO_CHECK()) confusing, rename the
latter to PTHREADS_RUNTIME_CHECK().  Also log the integer error value
returned by a given pthread_*() function verbatim to rule out any
further confusion in runtime error reporting.
2022-09-09 20:25:47 +02:00
Evan Hunt
47e9fa981e compression buffer was not reused correctly
when the compression buffer was reused for multiple statistics
requests, responses could grow beyond the correct size. this was
because the buffer was not cleared before reuse; compressed data
was still written to the beginning of the buffer, but then the size
of used region was increased by the amount written, rather than set
to the amount written. this caused responses to grow larger and
larger, potentially reading past the end of the allocated buffer.
2022-09-08 11:15:52 +02:00
Michał Kępień
4c49068531 Fix building with --disable-doh
Commit b69e783164 inadvertently caused
builds using the --disable-doh switch to fail, by putting the
declaration of the isc__nm_async_settlsctx() function inside an #ifdef
block that is only evaluated when DNS-over-HTTPS support is enabled.
This results in the following compilation errors being triggered:

    netmgr/netmgr.c:2657:1: error: no previous prototype for 'isc__nm_async_settlsctx' [-Werror=missing-prototypes]
     2657 | isc__nm_async_settlsctx(isc__networker_t *worker, isc__netievent_t *ev0) {
          | ^~~~~~~~~~~~~~~~~~~~~~~

Fix by making the declaration of the isc__nm_async_settlsctx() function
in lib/isc/netmgr/netmgr-int.h visible regardless of whether
DNS-over-HTTPS support is enabled or not.
2022-09-07 12:50:08 +02:00
Aram Sargsyan
2f11e48f0d Fix isc_nm_listentlsdns() error path bug
The isc_nm_listentlsdns() function erroneously calls
isc__nm_tcpdns_stoplistening() instead of isc__nm_tlsdns_stoplistening()
when something goes wrong, which can cause an assertion failure.
2022-09-05 14:58:52 +00:00
Aram Sargsyan
e97c3eea95 Add mctx attach/detach when creating/destroying a memory pool
This should make sure that the memory context is not destroyed
before the memory pool, which is using the context.
2022-09-02 08:16:17 +00:00
Ondřej Surý
718e92c31a Clear the callbacks when isc_nm_stoplistening() is called
When we are closing the listening sockets, there's a time window in
which the TCP connection could be accepted although the respective
stoplistening function has already returned to control to the caller.
Clear the accept callback function early, so it doesn't get called when
we are not interested in the incoming connections anymore.
2022-08-26 09:09:25 +02:00