Commit Graph

13349 Commits

Author SHA1 Message Date
Mark Andrews
5d7d274e85 Implement fallback to TCP on no DNS COOKIE
named now falls back to TCP if it doesn't get a DNS COOKIE response
when making recursive queries, TSIG queries excepted.  This can be
disabled by setting tcp-on-no-cookie to false.
2021-07-13 13:33:32 +10:00
Ondřej Surý
ce03015d48 Remove nonnull attribute from isc_mem_{get,allocate,reallocate}
The isc_mem_get(), isc_mem_allocate() and isc_mem_reallocate() can
return NULL ptr in case where the allocation size is NULL.  Remove the
nonnull attribute from the functions' declarations.

This stems from the following definition in the C11 standard:

> If the size of the space requested is zero, the behavior is
> implementation-defined: either a null pointer is returned, or the
> behavior is as if the size were some nonzero value, except that the
> returned pointer shall not be used to access an object.

In this case, we return NULL as it's easier to detect errors when
accessing pointer from zero-sized allocation which should obviously
never happen.
2021-07-12 10:02:18 +02:00
Ondřej Surý
d1a9e549b1 Fix the real allocation size in OpenBSD rallocx shim
In the rallocx() shim for OpenBSD (that's the only platform that doesn't
have malloc_size() or malloc_usable_size() equivalent), the newly
allocated size was missing the extra size_t member for storing the
allocation size leading to size_t sized overflow at the end of the
reallocated memory chunk.
2021-07-12 08:43:14 +02:00
Mark Andrews
3945c289bb Reset errcnt at the start of each subtest 2021-07-12 03:47:11 +00:00
Mark Andrews
9528ba5a22 Fix unchecked returns of dns_name_fromtext
(cherry picked from commit 8538c762cb)
2021-07-12 13:26:29 +10:00
Mark Andrews
ce5207699d Fix unchecked return of isc_rwlock_lock and isc_rwlock_unlock
(cherry picked from commit bcaf23dd27)
2021-07-12 13:26:29 +10:00
Mark Andrews
3c942a3e3a Update out of date comment 2021-07-12 12:33:46 +10:00
Mark Andrews
a3fda086f7 Check that there was no OPT record before falling back
to plain DNS on FORMERR.
2021-07-12 12:30:03 +10:00
Mark Andrews
c5e1c35e45 Silence untrusted loop bound on nsec3param.iterations
630
   	    1. tainted_argument: Calling function dns_rdata_tostruct taints argument nsec3param.iterations. [show details]
    631        result = dns_rdata_tostruct(nsec3rdata, &nsec3param, NULL);
   	    2. Condition !!(result == 0), taking true branch.
   	    3. Condition !!(result == 0), taking true branch.
    632        RUNTIME_CHECK(result == ISC_R_SUCCESS);
    633
    634        dns_fixedname_init(&fixed);

            CID 281425 (#1 of 1): Untrusted loop bound (TAINTED_SCALAR)
            4. tainted_data: Passing tainted expression nsec3param.iterations to dns_nsec3_hashname, which uses it as a loop boundary. [show details]
   	    Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range.
    635        result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, vctx->origin,
    636                                    vctx->origin, nsec3param.hash,
    637                                    nsec3param.iterations, nsec3param.salt,
    638                                    nsec3param.salt_length);
2021-07-12 00:48:13 +00:00
Mark Andrews
f0fdca90f2 Silence tainted scalar on rdlen
2042        ttl = isc_buffer_getuint32(&j->it.source);
    	    13. tainted_data_transitive: Call to function isc_buffer_getuint16 with tainted argument *j->it.source.base returns tainted data. [show details]
    	    14. var_assign: Assigning: rdlen = isc_buffer_getuint16(&j->it.source), which taints rdlen.
    2043        rdlen = isc_buffer_getuint16(&j->it.source);
    2044
    2045        /*
    2046         * Parse the rdata.
    2047         */
    	    15. Condition j->it.source.used - j->it.source.current != rdlen, taking false branch.
    2048        if (isc_buffer_remaininglength(&j->it.source) != rdlen) {
    2049                FAIL(DNS_R_FORMERR);
    2050        }
    	    16. var_assign_var: Assigning: j->it.source.active = j->it.source.current + rdlen. Both are now tainted.
    2051        isc_buffer_setactive(&j->it.source, rdlen);
    2052        dns_rdata_reset(&j->it.rdata);
    	    17. lower_bounds: Checking lower bounds of unsigned scalar j->it.source.active by taking the true branch of j->it.source.active > j->it.source.current.

    CID 316506 (#1 of 1): Untrusted loop bound (TAINTED_SCALAR)
    18. tainted_data: Passing tainted expression j->it.source.active to dns_rdata_fromwire, which uses it as a loop boundary. [show details]
    	    Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range.
    2053        CHECK(dns_rdata_fromwire(&j->it.rdata, rdclass, rdtype, &j->it.source,
    2054                                 &j->it.dctx, 0, &j->it.target));
2021-07-12 00:22:07 +00:00
Mark Andrews
83fd38dd2c Silence use of tainted scalar
2607
            43. tainted_argument: Calling function journal_read_xhdr taints argument xhdr.size. [show details]
    2608                        result = journal_read_xhdr(j1, &xhdr);
            44. Condition rewrite, taking true branch.
            45. Condition result == 29, taking false branch.
    2609                        if (rewrite && result == ISC_R_NOMORE) {
    2610                                break;
    2611                        }
            46. Condition result != 0, taking false branch.
    2612                        CHECK(result);
    2613
            47. var_assign_var: Assigning: size = xhdr.size. Both are now tainted.
    2614                        size = xhdr.size;

            CID 331088 (#3 of 3): Untrusted allocation size (TAINTED_SCALAR)
            48. tainted_data: Passing tainted expression size to isc__mem_get, which uses it as an allocation size. [show details]
            Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range.
    2615                        buf = isc_mem_get(mctx, size);
2021-07-12 00:22:07 +00:00
Ondřej Surý
29a285a67d Revert the allocate/free -> get/put change from jemalloc change
In the jemalloc merge request, we missed the fact that ah_frees and ah_handles
are reallocated which is not compatible with using isc_mem_get() for allocation
and isc_mem_put() for deallocation.  This commit reverts that part and restores
use of isc_mem_allocate() and isc_mem_free().
2021-07-09 18:19:57 +02:00
Ondřej Surý
9c3bebc26f Properly disable the "water" in isc_mem
The proper way how to disable the water limit in the isc_mem context is
to call:

    isc_mem_setwater(ctx, NULL, NULL, 0, 0);

this ensures that the old water callback is called with ISC_MEM_LOWATER
if the callback was called with ISC_MEM_HIWATER before.

Historically, there were some places where the limits were disabled by
calling:

    isc_mem_setwater(ctx, water, water_arg, 0, 0);

which would also call the old callback, but it also causes the water_t
to be allocated and extra check to be executed because water callback is
not NULL.

This commits unifies the calls to disable water to the preferred form.
2021-07-09 15:58:02 +02:00
Artem Boldariev
3673abc53c Use restrict and const in isc_mempool_t
This commit makes add restrict and const modifiers to some variables
to aid compiler to do its optimizations.
2021-07-09 15:58:02 +02:00
Artem Boldariev
c11a401add Do not use atomic variables in isc_mempool_t
As now mempool objects intended to be used in a thread-local manner,
there is no point in using atomic here.
2021-07-09 15:58:02 +02:00
Ondřej Surý
63b06571b9 Use isc_mem_get() and isc_mem_put() in isc_mem_total test
Previously, the isc_mem_allocate() and isc_mem_free() would be used for
isc_mem_total test, but since we now use the real allocation
size (sallocx, malloc_size, malloc_usable_size) to track the allocation
size, it's impossible to get the test value right.  Changing the test to
use isc_mem_get() and isc_mem_put() will use the exact size provided, so
the test would work again on all the platforms even when jemalloc is not
being used.
2021-07-09 15:58:02 +02:00
Ondřej Surý
6f162e8aa4 Rewrite isc_mem water to use single atomic exchange operation
This commit refactors the water mechanism in the isc_mem API to use
single pointer to a water_t structure that can be swapped with
atomic_exchange operation instead of having four different
values (water, water_arg, hi_water, lo_water) in the flat namespace.

This reduces the need for locking and prevents a race when water and
water_arg could be desynchronized.
2021-07-09 15:58:02 +02:00
Ondřej Surý
798333d456 Allow size == 0 in isc_mem_{get,allocate,reallocate}
Calls to jemalloc extended API with size == 0 ends up in undefined
behaviour.  This commit makes the isc_mem_get() and friends calls
more POSIX aligned:

  If size is 0, either a null pointer or a unique pointer that can be
  successfully passed to free() shall be returned.

We picked the easier route (which have been already supported in the old
code) and return NULL on calls to the API where size == 0.
2021-07-09 15:58:02 +02:00
Ondřej Surý
e20cc41e56 Use system allocator when jemalloc is unavailable
This commit adds support for systems where the jemalloc library is not
available as a package, here's the quick summary:

  * On Linux - the jemalloc is usually available as a package, if
    configured --without-jemalloc, the shim would be used around
    malloc(), free(), realloc() and malloc_usable_size()

  * On macOS - the jemalloc is available from homebrew or macports, if
    configured --without-jemalloc, the shim would be used around
    malloc(), free(), realloc() and malloc_size()

  * On FreeBSD - the jemalloc is *the* system allocator, we just need
    to check for <malloc_np.h> header to get access to non-standard API

  * On NetBSD - the jemalloc is *the* system allocator, we just need to
    check for <jemalloc/jemalloc.h> header to get access to non-standard
    API

  * On a system hostile to users and developers (read OpenBSD) - the
    jemalloc API is emulated by using ((size_t *)ptr)[-1] field to hold
    the size information.  The OpenBSD developers care only for
    themselves, so why should we care about speed on OpenBSD?
2021-07-09 15:58:02 +02:00
Evan Hunt
2ce0de6995 Remove error checks in dns_message for mem allocations
Removed error checks for several functions that can no longer fail due
to failed memory allocation.
2021-07-09 15:58:02 +02:00
Ondřej Surý
e754360170 Remove atomic thread synchronization from the memory hot-path
This commit refactors the hi/lo-water related code to remove contention
on the hot path in the memory allocator.
2021-07-09 15:58:02 +02:00
Ondřej Surý
efb385ecdc Clean up isc_mempool API
- isc_mempool_get() can no longer fail; when there are no more objects
  in the pool, more are always allocated. checking for NULL return is
  no longer necessary.
- the isc_mempool_setmaxalloc() and isc_mempool_getmaxalloc() functions
  are no longer used and have been removed.
2021-07-09 15:58:02 +02:00
Ondřej Surý
7cbfbc8faa Clean up the dns_dispatch_getudp API
Cleanup unused parts of dns_dispatch_getudp API, remove
dns_dispatch_getudp_dup() function and related code.
2021-07-09 15:58:02 +02:00
Ondřej Surý
f487c6948b Replace locked mempools with memory contexts
Current mempools are kind of hybrid structures - they serve two
purposes:

 1. mempool with a lock is basically static sized allocator with
    pre-allocated free items

 2. mempool without a lock is a doubly-linked list of preallocated items

The first kind of usage could be easily replaced with jemalloc small
sized arena objects and thread-local caches.

The second usage not-so-much and we need to keep this (in
libdns:message.c) for performance reasons.
2021-07-09 15:58:02 +02:00
Ondřej Surý
fd3ceec475 Add debug tracing capability to isc_mempool_create/destroy
Previously, we only had capability to trace the mempool gets and puts,
but for debugging, it's sometimes also important to keep track how many
and where do the memory pools get created and destroyed.  This commit
adds such tracking capability.
2021-07-09 15:58:02 +02:00
Ondřej Surý
5ab05d1696 Replace isc_mem_allocate() usage with isc_mem_get() in netmgr.c
The isc_mem_allocate() comes with additional cost because of the memory
tracking.  In this commit, we replace the usage with isc_mem_get()
because we track the allocated sizes anyway, so it's possible to also
replace isc_mem_free() with isc_mem_put().
2021-07-09 15:58:02 +02:00
Ondřej Surý
fcc6814776 Replace internal memory calls with non-standard jemalloc API
The jemalloc non-standard API fits nicely with our memory contexts, so
just rewrite the memory context internals to use the non-public API.

There's just one caveat - since we no longer track the size of the
allocation for isc_mem_allocate/isc_mem_free combination, we need to use
sallocx() to get real allocation size in both allocator and deallocator
because otherwise the sizes would not match.
2021-07-09 15:58:02 +02:00
Ondřej Surý
4b3d0c6600 Remove ISC_MEM_DEBUGSIZE and ISC_MEM_DEBUGRECORD
The ISC_MEM_DEBUGSIZE and ISC_MEM_DEBUGCTX did sanity checks on matching
size and memory context on the memory returned to the allocator.  Those
will no longer needed when most of the allocator will be replaced with
jemalloc.
2021-07-09 15:58:02 +02:00
Ondřej Surý
692fd2a216 Remove default_memalloc and default_memfree
Now that we have xmalloc:true enabled, we can remove our xmalloc-like
wrappers around malloc and free.
2021-07-09 15:58:02 +02:00
Ondřej Surý
5184384efd Add recommended jemalloc configuration for our load
There's global variable called `malloc_conf` that can be used to
configure jemalloc behaviour at the program startup.  We use following
configuration:

  * xmalloc:true - abort-on-out-of-memory enabled.

  * background_thread:true - Enable internal background worker threads
    to handle purging asynchronously.

  * metadata_thp:auto - allow jemalloc to use transparent huge page
    (THP) for internal metadata initially, but may begin to do so when
    metadata usage reaches certain level.

  * dirty_decay_ms:30000 - Approximate time in milliseconds from the
    creation of a set of unused dirty pages until an equivalent set of
    unused dirty pages is purged and/or reused.

  * muzzy_decay_ms:30000 - Approximate time in milliseconds from the
    creation of a set of unused muzzy pages until an equivalent set of
    unused muzzy pages is purged and/or reused.

More information about the specific meaning can be found in the jemalloc
manpage or online at http://jemalloc.net/jemalloc.3.html
2021-07-09 15:58:02 +02:00
Ondřej Surý
7f1c525625 Compile with jemalloc to reduce memory allocator contention
The jemalloc allocator is scalable high performance allocator, this is
the first in the series of commits that will add jemalloc as a memory
allocator for BIND 9.

This commit adds configure.ac check and Makefile modifications to use
jemalloc as BIND 9 allocator.
2021-07-09 15:58:02 +02:00
Ondřej Surý
63924968d1 Add debug tracing capability to isc_mem_create/isc_mem_destroy
Previously, we only had capability to trace the memory gets and puts,
but for debugging, it's sometimes also important to keep track how many
and where do the memory contexts get created and destroyed.  This commit
adds such tracking capability.
2021-07-09 15:58:02 +02:00
Artem Boldariev
c6d0e3d3a7 Return HTTP status code for small/malformed requests
This commit makes BIND return HTTP status codes for malformed or too
small requests.

DNS request processing code would ignore such requests. Such an
approach works well for other DNS transport but does not make much
sense for HTTP, not allowing it to complete the request/response
sequence.

Suppose execution has reached the point where DNS message handling
code has been called. In that case, it means that the HTTP request has
been successfully processed, and, thus, we are expected to respond to
it either with a message containing some DNS payload or at least to
return an error status code. This commit ensures that BIND behaves
this way.
2021-07-09 16:37:08 +03:00
Artem Boldariev
fedff2cd6c Return "Bad Request" (400) in a case of Base64 decoding error
This error code fits better than the more generic "Internal Server
Error" (500) which implies that the problem is on the server.

Also, do not end the whole HTTP/2 session on a bad request.
2021-07-09 16:26:46 +03:00
Artem Boldariev
1792740075 Ignore an "Accept" HTTP header value
We were too strict regarding the value and presence of "Accept" HTTP
header, slightly breaking compatibility with the specification.

According to RFC8484 client SHOULD add "Accept" header to the requests
but MUST be able to handle "application/dns-message" media type
regardless of the value of the header. That basically suggests we
ignore its value.

Besides, verifying the value of the "Accept" header is a bit tricky
because it could contain multiple media types, thus requiring proper
parsing. That is doable but does not provide us with any benefits.

Among other things, not verifying the value also fixes compatibility
with clients, which could advertise multiple media types as supported,
which we should accept. For example, it is possible for a perfectly
valid request to contain "application/dns-message", "application/*",
and "*/*" in the "Accept" header value. Still, we would treat such a
request as invalid.
2021-07-09 16:26:46 +03:00
Artem Boldariev
7b6945fb60 Fix BIND hanging when browsers end HTTP/2 streams prematurely
The commit fixes BIND hanging when browsers end HTTP/2 streams
prematurely (for example, by sending RST_STREAM). It ensures that
isc__nmsocket_prep_destroy() will be called for an HTTP/2 stream,
allowing it to be properly disposed.

The problem was impossible to reproduce using dig or DoH benchmarking
software (e.g. flamethrower) because these do not tend to end HTTP/2
streams prematurely.
2021-07-09 15:42:44 +03:00
Artem Boldariev
094fcc10e7 Move the code which calls server read callback into a separate func
This commit moves the code which calls server read callback into a
separate function to avoid code repetition.
2021-07-09 15:42:44 +03:00
Ondřej Surý
2bb454182b Make the DNS over HTTPS support optional
This commit adds two new autoconf options `--enable-doh` (enabled by
default) and `--with-libnghttp2` (mandatory when DoH is enabled).

When DoH support is disabled the library is not linked-in and support
for http(s) protocol is disabled in the netmgr, named and dig.
2021-07-07 09:50:53 +02:00
Ondřej Surý
29c2e52484 The isc/platform.h header has been completely removed
The isc/platform.h header was left empty which things either already
moved to config.h or to appropriate headers.  This is just the final
cleanup commit.
2021-07-06 05:33:48 +00:00
Ondřej Surý
bf4a0e26dc Move NAME_MAX and PATH_MAX from isc/platform.h to isc/dir.h
The last remaining defines needed for platforms without NAME_MAX and
PATH_MAX (I'm looking at you, GNU Hurd) were moved to isc/dir.h where
it's prevalently used.
2021-07-06 05:33:48 +00:00
Ondřej Surý
4da0c49e80 Move ISC_STRERRORSIZE to isc/strerr.h header
The ISC_STRERRORSIZE was defined in isc/platform.h header as the
value was different between Windows and POSIX platforms.  Now that
Windows is gone, move the define to where it belongs.
2021-07-06 05:33:48 +00:00
Ondřej Surý
d881e30b0a Remove LIB<*>_EXTERNAL_DATA defines
After Windows has been removed, the LIB<*>_EXTERNAL_DATA defines
were just dummy leftovers.  Remove them.
2021-07-06 05:33:48 +00:00
Matthijs Mekking
b4a0e19290 Fix CID 332468: Memory - illegal accesses (UNINIT)
*** CID 332468:  Memory - illegal accesses  (UNINIT)
/lib/dns/zone.c: 6613 in dns_zone_getdnsseckeys()
6607                 ISC_LIST_UNLINK(dnskeys, k1, link);
6608                 ISC_LIST_APPEND(*keys, k1, link);
6609             }
6610         }
6611     6612     failure:
>>>     CID 332468:  Memory - illegal accesses  (UNINIT)
>>>     Using uninitialized value "keyset.methods" when calling
>>>     "dns_rdataset_isassociated".
6613         if (dns_rdataset_isassociated(&keyset)) {
6614             dns_rdataset_disassociate(&keyset);
6615         }
6616         if (node != NULL) {
6617             dns_db_detachnode(db, &node);
6618         }

Fix by initializing the 'keyset' with 'dns_rdataset_init'.
2021-07-01 15:49:43 +02:00
Mark Andrews
c6fa8a1d45 Handle placeholder KEYDATA record
A placeholder keydata record can appear in a zone file.  Allow them
to be read back in.
2021-07-01 14:34:28 +10:00
Matthijs Mekking
39df3f0475 Protect dst key metadata with lock
The DST key metadata can be written by several threads in parralel.
Protect the dst_key_get* and dst_key_set* functions with a mutex.
2021-06-30 17:28:49 +02:00
Matthijs Mekking
28c5179904 Replace zone keyflock with zonemgr keymgmt
The old approach where each zone structure has its own mutex that
a thread needs to obtain multiple locks to do safe keyfile I/O
operations lead to a race condition ending in a possible deadlock.

Consider a zone in two views. Each such zone is stored in a separate
zone structure. A thread that needs to read or write the key files for
this zone needs to obtain both mutexes in seperate structures. If
another thread is working on the same zone in a different view, they
race to get the locks. It would be possible that thread1 grabs the
lock of the zone in view1, while thread2 wins the race for the lock
of the zone in view2. Now both threads try to get the other lock,  both
of them are already locked.

Ideally, when a thread wants to do key file operations, it only needs
to lock a single mutex. This commit introduces a key management hash
table, stored in the zonemgr structure. Each time a zone is being
managed, an object is added to the hash table (and removed when the
zone is being released). This object is identified by the zone name
and contains a mutex that needs to be locked prior to reading or
writing key files.

(cherry-picked from commit ef4619366d49efd46f9fae5f75c4a67c246ba2e6)
2021-06-30 17:28:49 +02:00
Matthijs Mekking
f7872dbd20 Add checkds code
Similar to notify, add code to send and keep track of checkds requests.

On every zone_rekey event, we will check the DS at parental agents
(but we will only actually query parental agents if theree is a DS
scheduled to be published/withdrawn).

On a zone_rekey event, we will first clear the ongoing checkds requests.
Reset the counter, to avoid continuing KSK rollover premature.

This has the risk that if zone_rekey events happen too soon after each
other, there are redundant DS queries to the parental agents. But
if TTLs and the configured durations in the dnssec-policy are sane (as
in not ridiculous short) the chance of this happening is low.
2021-06-30 17:28:49 +02:00
Matthijs Mekking
1a50554963 Add checkds log notice
When the checkds published/withdrawn is activated, log a notice. Can
be used for testing, but also operationally useful.
2021-06-30 17:28:48 +02:00
Matthijs Mekking
6e2c24be7c Add key metadata for DS published/withdrawn
In order to keep track of how many parents have the DS for a given key
published or withdrawn, keep a counter.
2021-06-30 17:28:48 +02:00
Matthijs Mekking
40331a20c4 Add helpful function 'dns_zone_getdnsseckeys'
This code gathers DNSSEC keys from key files and from the DNSKEY RRset.
It is used for the 'rndc dnssec -status' command, but will also be
needed for "checkds". Turn it into a function.
2021-06-30 17:28:48 +02:00