Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 1 | CVE-2016-2088 |
| 2 | |
| 3 | Backport commit d7ff9a1c41bf0ba9773cb3adb08b48b9fd57c956 from the |
| 4 | v9_10_3_patch branch. |
| 5 | |
| 6 | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2088 |
| 7 | https://kb.isc.org/article/AA-01351 |
| 8 | |
| 9 | CVE: CVE-2016-2088 |
| 10 | Upstream-Status: Backport |
| 11 | Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com> |
| 12 | |
| 13 | |
| 14 | Original commit message from Mark Andrews <marka@isc.org> below: |
| 15 | |
| 16 | 4322. [security] Duplicate EDNS COOKIE options in a response could |
| 17 | trigger an assertion failure. (CVE-2016-2088) |
| 18 | [RT #41809] |
| 19 | |
| 20 | (cherry picked from commit 455c0848f80a8acda27aad1466c72987cafaa029) |
| 21 | (cherry picked from commit 7cd300abd6ee8b8ee8730593daf742ba53f90bc3) |
| 22 | --- |
| 23 | CHANGES | 4 ++++ |
| 24 | bin/dig/dighost.c | 9 +++++++++ |
| 25 | bin/named/client.c | 33 +++++++++++++++++++++++---------- |
| 26 | doc/arm/notes.xml | 7 +++++++ |
| 27 | lib/dns/resolver.c | 14 +++++++++++++- |
| 28 | 5 files changed, 56 insertions(+), 11 deletions(-) |
| 29 | |
| 30 | diff --git a/CHANGES b/CHANGES |
| 31 | index c5b5d2b..d2e3360 100644 |
| 32 | --- a/CHANGES |
| 33 | +++ b/CHANGES |
| 34 | @@ -1,3 +1,7 @@ |
| 35 | +4322. [security] Duplicate EDNS COOKIE options in a response could |
| 36 | + trigger an assertion failure. (CVE-2016-2088) |
| 37 | + [RT #41809] |
| 38 | + |
| 39 | 4319. [security] Fix resolver assertion failure due to improper |
| 40 | DNAME handling when parsing fetch reply messages. |
| 41 | (CVE-2016-1286) [RT #41753] |
| 42 | diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c |
| 43 | index ca82f8e..340904f 100644 |
| 44 | --- a/bin/dig/dighost.c |
| 45 | +++ b/bin/dig/dighost.c |
| 46 | @@ -3458,6 +3458,7 @@ process_opt(dig_lookup_t *l, dns_message_t *msg) { |
| 47 | isc_buffer_t optbuf; |
| 48 | isc_uint16_t optcode, optlen; |
| 49 | dns_rdataset_t *opt = msg->opt; |
| 50 | + isc_boolean_t seen_cookie = ISC_FALSE; |
| 51 | |
| 52 | result = dns_rdataset_first(opt); |
| 53 | if (result == ISC_R_SUCCESS) { |
| 54 | @@ -3470,7 +3471,15 @@ process_opt(dig_lookup_t *l, dns_message_t *msg) { |
| 55 | optlen = isc_buffer_getuint16(&optbuf); |
| 56 | switch (optcode) { |
| 57 | case DNS_OPT_COOKIE: |
| 58 | + /* |
| 59 | + * Only process the first cookie option. |
| 60 | + */ |
| 61 | + if (seen_cookie) { |
| 62 | + isc_buffer_forward(&optbuf, optlen); |
| 63 | + break; |
| 64 | + } |
| 65 | process_sit(l, msg, &optbuf, optlen); |
| 66 | + seen_cookie = ISC_TRUE; |
| 67 | break; |
| 68 | default: |
| 69 | isc_buffer_forward(&optbuf, optlen); |
| 70 | diff --git a/bin/named/client.c b/bin/named/client.c |
| 71 | index 683305c..0d7331a 100644 |
| 72 | --- a/bin/named/client.c |
| 73 | +++ b/bin/named/client.c |
| 74 | @@ -120,7 +120,10 @@ |
| 75 | */ |
| 76 | #endif |
| 77 | |
| 78 | -#define SIT_SIZE 24U /* 8 + 4 + 4 + 8 */ |
| 79 | +#define COOKIE_SIZE 24U /* 8 + 4 + 4 + 8 */ |
| 80 | + |
| 81 | +#define WANTNSID(x) (((x)->attributes & NS_CLIENTATTR_WANTNSID) != 0) |
| 82 | +#define WANTEXPIRE(x) (((x)->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0) |
| 83 | |
| 84 | /*% nameserver client manager structure */ |
| 85 | struct ns_clientmgr { |
| 86 | @@ -1395,7 +1398,7 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, |
| 87 | { |
| 88 | char nsid[BUFSIZ], *nsidp; |
| 89 | #ifdef ISC_PLATFORM_USESIT |
| 90 | - unsigned char sit[SIT_SIZE]; |
| 91 | + unsigned char sit[COOKIE_SIZE]; |
| 92 | #endif |
| 93 | isc_result_t result; |
| 94 | dns_view_t *view; |
| 95 | @@ -1420,7 +1423,7 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, |
| 96 | flags = client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE; |
| 97 | |
| 98 | /* Set EDNS options if applicable */ |
| 99 | - if ((client->attributes & NS_CLIENTATTR_WANTNSID) != 0 && |
| 100 | + if (WANTNSID(client) && |
| 101 | (ns_g_server->server_id != NULL || |
| 102 | ns_g_server->server_usehostname)) { |
| 103 | if (ns_g_server->server_usehostname) { |
| 104 | @@ -1453,7 +1456,7 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, |
| 105 | |
| 106 | INSIST(count < DNS_EDNSOPTIONS); |
| 107 | ednsopts[count].code = DNS_OPT_COOKIE; |
| 108 | - ednsopts[count].length = SIT_SIZE; |
| 109 | + ednsopts[count].length = COOKIE_SIZE; |
| 110 | ednsopts[count].value = sit; |
| 111 | count++; |
| 112 | } |
| 113 | @@ -1661,19 +1664,26 @@ compute_sit(ns_client_t *client, isc_uint32_t when, isc_uint32_t nonce, |
| 114 | |
| 115 | static void |
| 116 | process_sit(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { |
| 117 | - unsigned char dbuf[SIT_SIZE]; |
| 118 | + unsigned char dbuf[COOKIE_SIZE]; |
| 119 | unsigned char *old; |
| 120 | isc_stdtime_t now; |
| 121 | isc_uint32_t when; |
| 122 | isc_uint32_t nonce; |
| 123 | isc_buffer_t db; |
| 124 | |
| 125 | + /* |
| 126 | + * If we have already seen a ECS option skip this ECS option. |
| 127 | + */ |
| 128 | + if ((client->attributes & NS_CLIENTATTR_WANTSIT) != 0) { |
| 129 | + isc_buffer_forward(buf, optlen); |
| 130 | + return; |
| 131 | + } |
| 132 | client->attributes |= NS_CLIENTATTR_WANTSIT; |
| 133 | |
| 134 | isc_stats_increment(ns_g_server->nsstats, |
| 135 | dns_nsstatscounter_sitopt); |
| 136 | |
| 137 | - if (optlen != SIT_SIZE) { |
| 138 | + if (optlen != COOKIE_SIZE) { |
| 139 | /* |
| 140 | * Not our token. |
| 141 | */ |
| 142 | @@ -1717,14 +1727,13 @@ process_sit(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { |
| 143 | isc_buffer_init(&db, dbuf, sizeof(dbuf)); |
| 144 | compute_sit(client, when, nonce, &db); |
| 145 | |
| 146 | - if (!isc_safe_memequal(old, dbuf, SIT_SIZE)) { |
| 147 | + if (!isc_safe_memequal(old, dbuf, COOKIE_SIZE)) { |
| 148 | isc_stats_increment(ns_g_server->nsstats, |
| 149 | dns_nsstatscounter_sitnomatch); |
| 150 | return; |
| 151 | } |
| 152 | isc_stats_increment(ns_g_server->nsstats, |
| 153 | dns_nsstatscounter_sitmatch); |
| 154 | - |
| 155 | client->attributes |= NS_CLIENTATTR_HAVESIT; |
| 156 | } |
| 157 | #endif |
| 158 | @@ -1783,7 +1792,9 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { |
| 159 | optlen = isc_buffer_getuint16(&optbuf); |
| 160 | switch (optcode) { |
| 161 | case DNS_OPT_NSID: |
| 162 | - isc_stats_increment(ns_g_server->nsstats, |
| 163 | + if (!WANTNSID(client)) |
| 164 | + isc_stats_increment( |
| 165 | + ns_g_server->nsstats, |
| 166 | dns_nsstatscounter_nsidopt); |
| 167 | client->attributes |= NS_CLIENTATTR_WANTNSID; |
| 168 | isc_buffer_forward(&optbuf, optlen); |
| 169 | @@ -1794,7 +1805,9 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { |
| 170 | break; |
| 171 | #endif |
| 172 | case DNS_OPT_EXPIRE: |
| 173 | - isc_stats_increment(ns_g_server->nsstats, |
| 174 | + if (!WANTEXPIRE(client)) |
| 175 | + isc_stats_increment( |
| 176 | + ns_g_server->nsstats, |
| 177 | dns_nsstatscounter_expireopt); |
| 178 | client->attributes |= NS_CLIENTATTR_WANTEXPIRE; |
| 179 | isc_buffer_forward(&optbuf, optlen); |
| 180 | diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml |
| 181 | index ebf4f55..095eb5b 100644 |
| 182 | --- a/doc/arm/notes.xml |
| 183 | +++ b/doc/arm/notes.xml |
| 184 | @@ -51,6 +51,13 @@ |
| 185 | <title>Security Fixes</title> |
| 186 | <itemizedlist> |
| 187 | <listitem> |
| 188 | + <para> |
| 189 | + Duplicate EDNS COOKIE options in a response could trigger |
| 190 | + an assertion failure. This flaw is disclosed in CVE-2016-2088. |
| 191 | + [RT #41809] |
| 192 | + </para> |
| 193 | + </listitem> |
| 194 | + <listitem> |
| 195 | <para> |
| 196 | Specific APL data could trigger an INSIST. This flaw |
| 197 | was discovered by Brian Mitchell and is disclosed in |
| 198 | diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c |
| 199 | index a797e3f..ba1ae23 100644 |
| 200 | --- a/lib/dns/resolver.c |
| 201 | +++ b/lib/dns/resolver.c |
| 202 | @@ -7502,7 +7502,9 @@ process_opt(resquery_t *query, dns_rdataset_t *opt) { |
| 203 | unsigned char *sit; |
| 204 | dns_adbaddrinfo_t *addrinfo; |
| 205 | unsigned char cookie[8]; |
| 206 | + isc_boolean_t seen_cookie = ISC_FALSE; |
| 207 | #endif |
| 208 | + isc_boolean_t seen_nsid = ISC_FALSE; |
| 209 | |
| 210 | result = dns_rdataset_first(opt); |
| 211 | if (result == ISC_R_SUCCESS) { |
| 212 | @@ -7516,14 +7518,23 @@ process_opt(resquery_t *query, dns_rdataset_t *opt) { |
| 213 | INSIST(optlen <= isc_buffer_remaininglength(&optbuf)); |
| 214 | switch (optcode) { |
| 215 | case DNS_OPT_NSID: |
| 216 | - if (query->options & DNS_FETCHOPT_WANTNSID) |
| 217 | + if (!seen_nsid && |
| 218 | + query->options & DNS_FETCHOPT_WANTNSID) |
| 219 | log_nsid(&optbuf, optlen, query, |
| 220 | ISC_LOG_DEBUG(3), |
| 221 | query->fctx->res->mctx); |
| 222 | isc_buffer_forward(&optbuf, optlen); |
| 223 | + seen_nsid = ISC_TRUE; |
| 224 | break; |
| 225 | #ifdef ISC_PLATFORM_USESIT |
| 226 | case DNS_OPT_COOKIE: |
| 227 | + /* |
| 228 | + * Only process the first cookie option. |
| 229 | + */ |
| 230 | + if (seen_cookie) { |
| 231 | + isc_buffer_forward(&optbuf, optlen); |
| 232 | + break; |
| 233 | + } |
| 234 | sit = isc_buffer_current(&optbuf); |
| 235 | compute_cc(query, cookie, sizeof(cookie)); |
| 236 | INSIST(query->fctx->rmessage->sitbad == 0 && |
| 237 | @@ -7541,6 +7552,7 @@ process_opt(resquery_t *query, dns_rdataset_t *opt) { |
| 238 | isc_buffer_forward(&optbuf, optlen); |
| 239 | inc_stats(query->fctx->res, |
| 240 | dns_resstatscounter_sitin); |
| 241 | + seen_cookie = ISC_TRUE; |
| 242 | break; |
| 243 | #endif |
| 244 | default: |
| 245 | -- |
| 246 | 2.1.4 |
| 247 | |