CVE-2016-2088 Backport commit d7ff9a1c41bf0ba9773cb3adb08b48b9fd57c956 from the v9_10_3_patch branch. https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2088 https://kb.isc.org/article/AA-01351 CVE: CVE-2016-2088 Upstream-Status: Backport Signed-off-by: Jussi Kukkonen Original commit message from Mark Andrews below: 4322. [security] Duplicate EDNS COOKIE options in a response could trigger an assertion failure. (CVE-2016-2088) [RT #41809] (cherry picked from commit 455c0848f80a8acda27aad1466c72987cafaa029) (cherry picked from commit 7cd300abd6ee8b8ee8730593daf742ba53f90bc3) --- CHANGES | 4 ++++ bin/dig/dighost.c | 9 +++++++++ bin/named/client.c | 33 +++++++++++++++++++++++---------- doc/arm/notes.xml | 7 +++++++ lib/dns/resolver.c | 14 +++++++++++++- 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index c5b5d2b..d2e3360 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4322. [security] Duplicate EDNS COOKIE options in a response could + trigger an assertion failure. (CVE-2016-2088) + [RT #41809] + 4319. [security] Fix resolver assertion failure due to improper DNAME handling when parsing fetch reply messages. (CVE-2016-1286) [RT #41753] diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index ca82f8e..340904f 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -3458,6 +3458,7 @@ process_opt(dig_lookup_t *l, dns_message_t *msg) { isc_buffer_t optbuf; isc_uint16_t optcode, optlen; dns_rdataset_t *opt = msg->opt; + isc_boolean_t seen_cookie = ISC_FALSE; result = dns_rdataset_first(opt); if (result == ISC_R_SUCCESS) { @@ -3470,7 +3471,15 @@ process_opt(dig_lookup_t *l, dns_message_t *msg) { optlen = isc_buffer_getuint16(&optbuf); switch (optcode) { case DNS_OPT_COOKIE: + /* + * Only process the first cookie option. + */ + if (seen_cookie) { + isc_buffer_forward(&optbuf, optlen); + break; + } process_sit(l, msg, &optbuf, optlen); + seen_cookie = ISC_TRUE; break; default: isc_buffer_forward(&optbuf, optlen); diff --git a/bin/named/client.c b/bin/named/client.c index 683305c..0d7331a 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -120,7 +120,10 @@ */ #endif -#define SIT_SIZE 24U /* 8 + 4 + 4 + 8 */ +#define COOKIE_SIZE 24U /* 8 + 4 + 4 + 8 */ + +#define WANTNSID(x) (((x)->attributes & NS_CLIENTATTR_WANTNSID) != 0) +#define WANTEXPIRE(x) (((x)->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0) /*% nameserver client manager structure */ struct ns_clientmgr { @@ -1395,7 +1398,7 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, { char nsid[BUFSIZ], *nsidp; #ifdef ISC_PLATFORM_USESIT - unsigned char sit[SIT_SIZE]; + unsigned char sit[COOKIE_SIZE]; #endif isc_result_t result; dns_view_t *view; @@ -1420,7 +1423,7 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, flags = client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE; /* Set EDNS options if applicable */ - if ((client->attributes & NS_CLIENTATTR_WANTNSID) != 0 && + if (WANTNSID(client) && (ns_g_server->server_id != NULL || ns_g_server->server_usehostname)) { if (ns_g_server->server_usehostname) { @@ -1453,7 +1456,7 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, INSIST(count < DNS_EDNSOPTIONS); ednsopts[count].code = DNS_OPT_COOKIE; - ednsopts[count].length = SIT_SIZE; + ednsopts[count].length = COOKIE_SIZE; ednsopts[count].value = sit; count++; } @@ -1661,19 +1664,26 @@ compute_sit(ns_client_t *client, isc_uint32_t when, isc_uint32_t nonce, static void process_sit(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { - unsigned char dbuf[SIT_SIZE]; + unsigned char dbuf[COOKIE_SIZE]; unsigned char *old; isc_stdtime_t now; isc_uint32_t when; isc_uint32_t nonce; isc_buffer_t db; + /* + * If we have already seen a ECS option skip this ECS option. + */ + if ((client->attributes & NS_CLIENTATTR_WANTSIT) != 0) { + isc_buffer_forward(buf, optlen); + return; + } client->attributes |= NS_CLIENTATTR_WANTSIT; isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_sitopt); - if (optlen != SIT_SIZE) { + if (optlen != COOKIE_SIZE) { /* * Not our token. */ @@ -1717,14 +1727,13 @@ process_sit(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { isc_buffer_init(&db, dbuf, sizeof(dbuf)); compute_sit(client, when, nonce, &db); - if (!isc_safe_memequal(old, dbuf, SIT_SIZE)) { + if (!isc_safe_memequal(old, dbuf, COOKIE_SIZE)) { isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_sitnomatch); return; } isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_sitmatch); - client->attributes |= NS_CLIENTATTR_HAVESIT; } #endif @@ -1783,7 +1792,9 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { optlen = isc_buffer_getuint16(&optbuf); switch (optcode) { case DNS_OPT_NSID: - isc_stats_increment(ns_g_server->nsstats, + if (!WANTNSID(client)) + isc_stats_increment( + ns_g_server->nsstats, dns_nsstatscounter_nsidopt); client->attributes |= NS_CLIENTATTR_WANTNSID; isc_buffer_forward(&optbuf, optlen); @@ -1794,7 +1805,9 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { break; #endif case DNS_OPT_EXPIRE: - isc_stats_increment(ns_g_server->nsstats, + if (!WANTEXPIRE(client)) + isc_stats_increment( + ns_g_server->nsstats, dns_nsstatscounter_expireopt); client->attributes |= NS_CLIENTATTR_WANTEXPIRE; isc_buffer_forward(&optbuf, optlen); diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index ebf4f55..095eb5b 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -51,6 +51,13 @@ Security Fixes + + Duplicate EDNS COOKIE options in a response could trigger + an assertion failure. This flaw is disclosed in CVE-2016-2088. + [RT #41809] + + + Specific APL data could trigger an INSIST. This flaw was discovered by Brian Mitchell and is disclosed in diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index a797e3f..ba1ae23 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -7502,7 +7502,9 @@ process_opt(resquery_t *query, dns_rdataset_t *opt) { unsigned char *sit; dns_adbaddrinfo_t *addrinfo; unsigned char cookie[8]; + isc_boolean_t seen_cookie = ISC_FALSE; #endif + isc_boolean_t seen_nsid = ISC_FALSE; result = dns_rdataset_first(opt); if (result == ISC_R_SUCCESS) { @@ -7516,14 +7518,23 @@ process_opt(resquery_t *query, dns_rdataset_t *opt) { INSIST(optlen <= isc_buffer_remaininglength(&optbuf)); switch (optcode) { case DNS_OPT_NSID: - if (query->options & DNS_FETCHOPT_WANTNSID) + if (!seen_nsid && + query->options & DNS_FETCHOPT_WANTNSID) log_nsid(&optbuf, optlen, query, ISC_LOG_DEBUG(3), query->fctx->res->mctx); isc_buffer_forward(&optbuf, optlen); + seen_nsid = ISC_TRUE; break; #ifdef ISC_PLATFORM_USESIT case DNS_OPT_COOKIE: + /* + * Only process the first cookie option. + */ + if (seen_cookie) { + isc_buffer_forward(&optbuf, optlen); + break; + } sit = isc_buffer_current(&optbuf); compute_cc(query, cookie, sizeof(cookie)); INSIST(query->fctx->rmessage->sitbad == 0 && @@ -7541,6 +7552,7 @@ process_opt(resquery_t *query, dns_rdataset_t *opt) { isc_buffer_forward(&optbuf, optlen); inc_stats(query->fctx->res, dns_resstatscounter_sitin); + seen_cookie = ISC_TRUE; break; #endif default: -- 2.1.4