]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4816. [bug] Don't use a common array for storing EDNS options
authorMark Andrews <marka@isc.org>
Mon, 13 Nov 2017 05:10:35 +0000 (16:10 +1100)
committerMark Andrews <marka@isc.org>
Mon, 13 Nov 2017 05:28:43 +0000 (16:28 +1100)
                        in DiG as it could fill up. [RT #45611]

(cherry picked from commit 3def40b01b79ceb0f20a3fbff857a10e9195352a)

CHANGES
bin/dig/dighost.c

diff --git a/CHANGES b/CHANGES
index cd0e5514e55aa375adabf4c667d3cef40c07233f..26e01af5482838193018487504ec853918f35ebc 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4816.  [bug]           Don't use a common array for storing EDNS options
+                       in DiG as it could fill up. [RT #45611]
+
 4815.  [bug]           rbt_test.c:insert_and_delete needed to call
                        dns_rbt_addnode instead of dns_rbt_addname. [RT #46553]
 
index 2d76fe99f5c010ddbc4321c7ec75013f06b60187..e0c0f0d85a87f7d7630f167530028ed5df27a06a 100644 (file)
@@ -862,6 +862,41 @@ make_empty_lookup(void) {
        return (looknew);
 }
 
+#define EDNSOPT_OPTIONS 100U
+
+static void
+cloneopts(dig_lookup_t *looknew, dig_lookup_t *lookold) {
+       size_t len = sizeof(looknew->ednsopts[0]) * EDNSOPT_OPTIONS;
+       size_t i;
+       looknew->ednsopts = isc_mem_allocate(mctx, len);
+       if (looknew->ednsopts == NULL)
+               fatal("out of memory");
+       for (i = 0; i < EDNSOPT_OPTIONS; i++) {
+               looknew->ednsopts[i].code = 0;
+               looknew->ednsopts[i].length = 0;
+               looknew->ednsopts[i].value = NULL;
+       }
+       looknew->ednsoptscnt = 0;
+       if (lookold == NULL || lookold->ednsopts == NULL)
+               return;
+
+       for (i = 0; i < lookold->ednsoptscnt; i++) {
+               len = lookold->ednsopts[i].length;
+               if (len != 0) {
+                       INSIST(lookold->ednsopts[i].value != NULL);
+                       looknew->ednsopts[i].value =
+                                isc_mem_allocate(mctx, len);
+                       if (looknew->ednsopts[i].value == NULL)
+                               fatal("out of memory");
+                       memmove(looknew->ednsopts[i].value,
+                               lookold->ednsopts[i].value, len);
+               }
+               looknew->ednsopts[i].code = lookold->ednsopts[i].code;
+               looknew->ednsopts[i].length = len;
+       }
+       looknew->ednsoptscnt = lookold->ednsoptscnt;
+}
+
 /*%
  * Clone a lookup, perhaps copying the server list.  This does not clone
  * the query list, since it will be regenerated by the setup_lookup()
@@ -909,8 +944,12 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
        looknew->seenbadcookie = lookold->seenbadcookie;
        looknew->badcookie = lookold->badcookie;
        looknew->cookie = lookold->cookie;
-       looknew->ednsopts = lookold->ednsopts;
-       looknew->ednsoptscnt = lookold->ednsoptscnt;
+       if (lookold->ednsopts != NULL) {
+               cloneopts(looknew, lookold);
+       } else {
+               looknew->ednsopts = NULL;
+               looknew->ednsoptscnt = 0;
+       }
        looknew->ednsneg = lookold->ednsneg;
        looknew->mapped = lookold->mapped;
        looknew->idnout = lookold->idnout;
@@ -1588,10 +1627,6 @@ setup_libs(void) {
        check_result(result, "isc_mutex_init");
 }
 
-#define EDNSOPTS 100U
-static dns_ednsopt_t ednsopts[EDNSOPTS];
-static unsigned char ednsoptscnt = 0;
-
 typedef struct dig_ednsoptname {
        isc_uint32_t code;
        const char  *name;
@@ -1623,7 +1658,7 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) {
        isc_boolean_t found = ISC_FALSE;
        unsigned int i;
 
-       if (ednsoptscnt == EDNSOPTS)
+       if (lookup->ednsoptscnt >= EDNSOPT_OPTIONS)
                fatal("too many ednsopts");
 
        for (i = 0; i < N_EDNS_OPTNAMES; i++) {
@@ -1640,9 +1675,16 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) {
                        fatal("bad edns code point: %s", code);
        }
 
-       ednsopts[ednsoptscnt].code = num;
-       ednsopts[ednsoptscnt].length = 0;
-       ednsopts[ednsoptscnt].value = NULL;
+       if (lookup->ednsopts == NULL) {
+               cloneopts(lookup, NULL);
+       }
+
+       if (lookup->ednsopts[lookup->ednsoptscnt].value != NULL)
+               isc_mem_free(mctx, lookup->ednsopts[lookup->ednsoptscnt].value);
+
+       lookup->ednsopts[lookup->ednsoptscnt].code = num;
+       lookup->ednsopts[lookup->ednsoptscnt].length = 0;
+       lookup->ednsopts[lookup->ednsoptscnt].value = NULL;
 
        if (value != NULL) {
                char *buf;
@@ -1652,14 +1694,13 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) {
                isc_buffer_init(&b, buf, (unsigned int) strlen(value)/2 + 1);
                result = isc_hex_decodestring(value, &b);
                check_result(result, "isc_hex_decodestring");
-               ednsopts[ednsoptscnt].value = isc_buffer_base(&b);
-               ednsopts[ednsoptscnt].length = isc_buffer_usedlength(&b);
+               lookup->ednsopts[lookup->ednsoptscnt].value =
+                                                isc_buffer_base(&b);
+               lookup->ednsopts[lookup->ednsoptscnt].length =
+                                                isc_buffer_usedlength(&b);
        }
 
-       if (lookup->ednsoptscnt == 0)
-               lookup->ednsopts = &ednsopts[ednsoptscnt];
        lookup->ednsoptscnt++;
-       ednsoptscnt++;
 }
 
 /*%
@@ -1838,6 +1879,15 @@ destroy_lookup(dig_lookup_t *lookup) {
        if (lookup->ecs_addr != NULL)
                isc_mem_free(mctx, lookup->ecs_addr);
 
+       if (lookup->ednsopts != NULL) {
+               size_t i;
+               for (i = 0; i < EDNSOPT_OPTIONS; i++) {
+                       if (lookup->ednsopts[i].value != NULL)
+                               isc_mem_free(mctx, lookup->ednsopts[i].value);
+               }
+               isc_mem_free(mctx, lookup->ednsopts);
+       }
+
        isc_mem_free(mctx, lookup);
 }
 
@@ -2565,9 +2615,10 @@ setup_lookup(dig_lookup_t *lookup) {
        if (lookup->udpsize > 0 || lookup->dnssec ||
            lookup->edns > -1 || lookup->ecs_addr != NULL)
        {
-               dns_ednsopt_t opts[EDNSOPTS + DNS_EDNSOPTIONS];
+#define MAXOPTS (EDNSOPT_OPTIONS + DNS_EDNSOPTIONS)
+               dns_ednsopt_t opts[MAXOPTS];
                unsigned int flags;
-               int i = 0;
+               unsigned int i = 0;
 
                if (lookup->udpsize == 0)
                        lookup->udpsize = 4096;
@@ -2575,7 +2626,7 @@ setup_lookup(dig_lookup_t *lookup) {
                        lookup->edns = 0;
 
                if (lookup->nsid) {
-                       INSIST(i < DNS_EDNSOPTIONS);
+                       INSIST(i < MAXOPTS);
                        opts[i].code = DNS_OPT_NSID;
                        opts[i].length = 0;
                        opts[i].value = NULL;
@@ -2597,7 +2648,7 @@ setup_lookup(dig_lookup_t *lookup) {
                        /* Round up prefix len to a multiple of 8 */
                        addrl = (plen + 7) / 8;
 
-                       INSIST(i < DNS_EDNSOPTIONS);
+                       INSIST(i < MAXOPTS);
                        opts[i].code = DNS_OPT_CLIENT_SUBNET;
                        opts[i].length = (isc_uint16_t) addrl + 4;
                        check_result(result, "isc_buffer_allocate");
@@ -2666,7 +2717,7 @@ setup_lookup(dig_lookup_t *lookup) {
                }
 
                if (lookup->sendcookie) {
-                       INSIST(i < DNS_EDNSOPTIONS);
+                       INSIST(i < MAXOPTS);
                        opts[i].code = DNS_OPT_COOKIE;
                        if (lookup->cookie != NULL) {
                                isc_buffer_init(&b, cookiebuf,
@@ -2685,7 +2736,7 @@ setup_lookup(dig_lookup_t *lookup) {
                }
 
                if (lookup->expire) {
-                       INSIST(i < DNS_EDNSOPTIONS);
+                       INSIST(i < MAXOPTS);
                        opts[i].code = DNS_OPT_EXPIRE;
                        opts[i].length = 0;
                        opts[i].value = NULL;
@@ -2693,6 +2744,7 @@ setup_lookup(dig_lookup_t *lookup) {
                }
 
                if (lookup->ednsoptscnt != 0) {
+                       INSIST(i + lookup->ednsoptscnt <= MAXOPTS);
                        memmove(&opts[i], lookup->ednsopts,
                                sizeof(dns_ednsopt_t) * lookup->ednsoptscnt);
                        i += lookup->ednsoptscnt;
@@ -4570,12 +4622,6 @@ destroy_libs(void) {
        debug("Removing log context");
        isc_log_destroy(&lctx);
 
-       while (ednsoptscnt > 0U) {
-               ednsoptscnt--;
-               if (ednsopts[ednsoptscnt].value != NULL)
-                       isc_mem_free(mctx, ednsopts[ednsoptscnt].value);
-       }
-
        debug("Destroy memory");
        if (memdebugging != 0)
                isc_mem_stats(mctx, stderr);