On 3/31/21 9:04 AM, Sana Kazi wrote: > Hi, > > Could you please review below patch to be upstreamed for dnsmasq?
I am seeing this error: ERROR: Applying 'CVE-2020-25681.patch' failed: checking file src/dnssec.c Hunk #1 FAILED at 223. Hunk #2 FAILED at 569. Hunk #3 FAILED at 586. Hunk #4 FAILED at 612. 4 out of 4 hunks FAILED ERROR: Logfile of failure stored in: /home/build/builds/dunfell/tmp/work/core2-64-poky-linux/dnsmasq/2.81-r0/devtooltmp-ywp0fqrq/temp/log.do_patch.912892 > > Thanks & Regards, > > Sana Kazi > KPIT Technologies Limited > > > ------------------------------------------------------------------------ > *From:* Sana Kazi <sana.k...@kpit.com> > *Sent:* Thursday, March 18, 2021 10:44 AM > *To:* Openembedded-devel@lists.openembedded.org > <Openembedded-devel@lists.openembedded.org>; raj.k...@gmail.com > <raj.k...@gmail.com> > *Cc:* Nisha Parrakat <nisha.parra...@kpit.com>; Harpritkaur Bhandari > <harpritkaur.bhand...@kpit.com> > *Subject:* [meta-networking][meta-oe][dunfell][PATCH] dnsmasq: Add > fixes for CVEs reported for dnsmasq > > Applied single patch for below listed CVEs which avoids remote > attacker to overwrite memory: > CVE-2020-25681 > CVE-2020-25682 > CVE-2020-25683 > CVE-2020-25687 > as they are fixed by single commit > http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=4e96a4be685c9e4445f6ee79ad0b36b9119b502a > Link: https://www.openwall.com/lists/oss-security/2021/01/19/1 > > Also, applied patch for below listed CVEs: > > CVE-2020-25684 > CVE-2020-25685 > CVE-2020-25686 > > Signed-off-by: Sana Kazi <sana.k...@kpit.com> > --- > .../recipes-support/dnsmasq/dnsmasq_2.81.bb | 7 +- > .../dnsmasq/files/CVE-2020-25681.patch | 373 +++++++++++ > .../dnsmasq/files/CVE-2020-25684.patch | 100 +++ > .../dnsmasq/files/CVE-2020-25685-1.patch | 590 ++++++++++++++++++ > .../dnsmasq/files/CVE-2020-25685-2.patch | 201 ++++++ > .../dnsmasq/files/CVE-2020-25686-1.patch | 335 ++++++++++ > .../dnsmasq/files/CVE-2020-25686-2.patch | 66 ++ > 7 files changed, 1671 insertions(+), 1 deletion(-) > create mode 100644 > meta-networking/recipes-support/dnsmasq/files/CVE-2020-25681.patch > create mode 100644 > meta-networking/recipes-support/dnsmasq/files/CVE-2020-25684.patch > create mode 100644 > meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-1.patch > create mode 100644 > meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-2.patch > create mode 100644 > meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-1.patch > create mode 100644 > meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-2.patch > > diff --git a/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb > b/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb > index 92415386c..a1dc0f3a0 100644 > --- a/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb > +++ b/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb > @@ -4,5 +4,10 @@ SRC_URI[dnsmasq-2.81.md5sum] = > "e43808177a773014b5892ccba238f7a8" > SRC_URI[dnsmasq-2.81.sha256sum] = > "3c28c68c6c2967c3a96e9b432c0c046a5df17a426d3a43cffe9e693cf05804d0" > SRC_URI += "\ > file://lua.patch \ > + file://CVE-2020-25681.patch \ > + file://CVE-2020-25684.patch \ > + file://CVE-2020-25685-1.patch \ > + file://CVE-2020-25685-2.patch \ > + file://CVE-2020-25686-1.patch \ > + file://CVE-2020-25686-2.patch \ > " > - > diff --git > a/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25681.patch > b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25681.patch > new file mode 100644 > index 000000000..cab734ed1 > --- /dev/null > +++ b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25681.patch > @@ -0,0 +1,373 @@ > +From 4e96a4be685c9e4445f6ee79ad0b36b9119b502a Mon Sep 17 00:00:00 2001 > +From: Simon Kelley <si...@thekelleys.org.uk> > +Date: Wed, 11 Nov 2020 23:25:04 +0000 > +Subject: [PATCH] Fix remote buffer overflow CERT VU#434904 > + > +The problem is in the sort_rrset() function and allows a remote > +attacker to overwrite memory. Any dnsmasq instance with DNSSEC > +enabled is vulnerable. > + > +Signed-off-by: Sana Kazi <sana.k...@kpit.com> > +--- > + CHANGELOG | 7 +- > + src/dnssec.c | 273 ++++++++++++++++++++++++++++----------------------- > + 2 files changed, 158 insertions(+), 122 deletions(-) > + > +CVE: CVE-2020-25681 > +CVE: CVE-2020-25682 > +CVE: CVE-2020-25683 > +CVE: CVE-2020-25687 > +Upstream-Status: Backport > [https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=patch;h=4e96a4be685c9e4445f6ee79ad0b36b9119b502a] > +Comment: No change in any hunk > + > +diff --git a/src/dnssec.c b/src/dnssec.c > +index db5c2d1..e95aa34 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -223,138 +223,147 @@ static int check_date_range(unsigned long > curtime, u32 date_start, u32 date_end) > + && serial_compare_32(curtime, date_end) == SERIAL_LT; > + } > + > +-/* Return bytes of canonicalised rdata, when the return value is > zero, the remaining > +- data, pointed to by *p, should be used raw. */ > +-static int get_rdata(struct dns_header *header, size_t plen, > unsigned char *end, char *buff, int bufflen, > +- unsigned char **p, u16 **desc) > ++/* Return bytes of canonicalised rrdata one by one. > ++ Init state->ip with the RR, and state->end with the end of same. > ++ Init state->op to NULL. > ++ Init state->desc to RR descriptor. > ++ Init state->buff with a MAXDNAME * 2 buffer. > ++ > ++ After each call which returns 1, state->op points to the next > byte of data. > ++ On returning 0, the end has been reached. > ++*/ > ++struct rdata_state { > ++ u16 *desc; > ++ size_t c; > ++ unsigned char *end, *ip, *op; > ++ char *buff; > ++}; > ++ > ++static int get_rdata(struct dns_header *header, size_t plen, struct > rdata_state *state) > + { > +- int d = **desc; > ++ int d; > + > +- /* No more data needs mangling */ > +- if (d == (u16)-1) > ++ if (state->op && state->c != 1) > + { > +- /* If there's more data than we have space for, just return > what fits, > +- we'll get called again for more chunks */ > +- if (end - *p > bufflen) > +- { > +- memcpy(buff, *p, bufflen); > +- *p += bufflen; > +- return bufflen; > +- } > +- > +- return 0; > ++ state->op++; > ++ state->c--; > ++ return 1; > + } > +- > +- (*desc)++; > +- > +- if (d == 0 && extract_name(header, plen, p, buff, 1, 0)) > +- /* domain-name, canonicalise */ > +- return to_wire(buff); > +- else > +- { > +- /* plain data preceding a domain-name, don't run off the end > of the data */ > +- if ((end - *p) < d) > +- d = end - *p; > ++ > ++ while (1) > ++ { > ++ d = *(state->desc); > + > +- if (d != 0) > ++ if (d == (u16)-1) > + { > +- memcpy(buff, *p, d); > +- *p += d; > ++ /* all the bytes to the end. */ > ++ if ((state->c = state->end - state->ip) != 0) > ++ { > ++ state->op = state->ip; > ++ state->ip = state->end;; > ++ } > ++ else > ++ return 0; > ++ } > ++ else > ++ { > ++ state->desc++; > ++ > ++ if (d == (u16)0) > ++ { > ++ /* domain-name, canonicalise */ > ++ int len; > ++ > ++ if (!extract_name(header, plen, &state->ip, state->buff, > 1, 0) || > ++ (len = to_wire(state->buff)) == 0) > ++ continue; > ++ > ++ state->c = len; > ++ state->op = (unsigned char *)state->buff; > ++ } > ++ else > ++ { > ++ /* plain data preceding a domain-name, don't run off the > end of the data */ > ++ if ((state->end - state->ip) < d) > ++ d = state->end - state->ip; > ++ > ++ if (d == 0) > ++ continue; > ++ > ++ state->op = state->ip; > ++ state->c = d; > ++ state->ip += d; > ++ } > + } > + > +- return d; > ++ return 1; > + } > + } > + > +-/* Bubble sort the RRset into the canonical order. > +- Note that the byte-streams from two RRs may get unsynced: consider > +- RRs which have two domain-names at the start and then other data. > +- The domain-names may have different lengths in each RR, but sort > equal > +- > +- ------------ > +- |abcde|fghi| > +- ------------ > +- |abcd|efghi| > +- ------------ > +- > +- leaving the following bytes as deciding the order. Hence the > nasty left1 and left2 variables. > +-*/ > ++/* Bubble sort the RRset into the canonical order. */ > + > + static int sort_rrset(struct dns_header *header, size_t plen, u16 > *rr_desc, int rrsetidx, > + unsigned char **rrset, char *buff1, char *buff2) > + { > +- int swap, quit, i, j; > ++ int swap, i, j; > + > + do > + { > + for (swap = 0, i = 0; i < rrsetidx-1; i++) > + { > +- int rdlen1, rdlen2, left1, left2, len1, len2, len, rc; > +- u16 *dp1, *dp2; > +- unsigned char *end1, *end2; > ++ int rdlen1, rdlen2; > ++ struct rdata_state state1, state2; > ++ > + /* Note that these have been determined to be OK previously, > + so we don't need to check for NULL return here. */ > +- unsigned char *p1 = skip_name(rrset[i], header, plen, 10); > +- unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10); > +- > +- p1 += 8; /* skip class, type, ttl */ > +- GETSHORT(rdlen1, p1); > +- end1 = p1 + rdlen1; > +- > +- p2 += 8; /* skip class, type, ttl */ > +- GETSHORT(rdlen2, p2); > +- end2 = p2 + rdlen2; > ++ state1.ip = skip_name(rrset[i], header, plen, 10); > ++ state2.ip = skip_name(rrset[i+1], header, plen, 10); > ++ state1.op = state2.op = NULL; > ++ state1.buff = buff1; > ++ state2.buff = buff2; > ++ state1.desc = state2.desc = rr_desc; > + > +- dp1 = dp2 = rr_desc; > ++ state1.ip += 8; /* skip class, type, ttl */ > ++ GETSHORT(rdlen1, state1.ip); > ++ if (!CHECK_LEN(header, state1.ip, plen, rdlen1)) > ++ return rrsetidx; /* short packet */ > ++ state1.end = state1.ip + rdlen1; > + > +- for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;) > ++ state2.ip += 8; /* skip class, type, ttl */ > ++ GETSHORT(rdlen2, state2.ip); > ++ if (!CHECK_LEN(header, state2.ip, plen, rdlen2)) > ++ return rrsetidx; /* short packet */ > ++ state2.end = state2.ip + rdlen2; > ++ > ++ while (1) > + { > +- if (left1 != 0) > +- memmove(buff1, buff1 + len1 - left1, left1); > ++ int ok1, ok2; > + > +- if ((len1 = get_rdata(header, plen, end1, buff1 + left1, > (MAXDNAME * 2) - left1, &p1, &dp1)) == 0) > +- { > +- quit = 1; > +- len1 = end1 - p1; > +- memcpy(buff1 + left1, p1, len1); > +- } > +- len1 += left1; > +- > +- if (left2 != 0) > +- memmove(buff2, buff2 + len2 - left2, left2); > +- > +- if ((len2 = get_rdata(header, plen, end2, buff2 + left2, > (MAXDNAME *2) - left2, &p2, &dp2)) == 0) > +- { > +- quit = 1; > +- len2 = end2 - p2; > +- memcpy(buff2 + left2, p2, len2); > +- } > +- len2 += left2; > +- > +- if (len1 > len2) > +- left1 = len1 - len2, left2 = 0, len = len2; > +- else > +- left2 = len2 - len1, left1 = 0, len = len1; > +- > +- rc = (len == 0) ? 0 : memcmp(buff1, buff2, len); > +- > +- if (rc > 0 || (rc == 0 && quit && len1 > len2)) > +- { > +- unsigned char *tmp = rrset[i+1]; > +- rrset[i+1] = rrset[i]; > +- rrset[i] = tmp; > +- swap = quit = 1; > +- } > +- else if (rc == 0 && quit && len1 == len2) > ++ ok1 = get_rdata(header, plen, &state1); > ++ ok2 = get_rdata(header, plen, &state2); > ++ > ++ if (!ok1 && !ok2) > + { > + /* Two RRs are equal, remove one copy. RFC 4034, > para 6.3 */ > + for (j = i+1; j < rrsetidx-1; j++) > + rrset[j] = rrset[j+1]; > + rrsetidx--; > + i--; > ++ break; > ++ } > ++ else if (ok1 && (!ok2 || *state1.op > *state2.op)) > ++ { > ++ unsigned char *tmp = rrset[i+1]; > ++ rrset[i+1] = rrset[i]; > ++ rrset[i] = tmp; > ++ swap = 1; > ++ break; > + } > +- else if (rc < 0) > +- quit = 1; > ++ else if (ok2 && (!ok1 || *state2.op > *state1.op)) > ++ break; > ++ > ++ /* arrive here when bytes are equal, go round the loop again > ++ and compare the next ones. */ > + } > + } > + } while (swap); > +@@ -569,15 +578,18 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > + wire_len = to_wire(keyname); > + hash->update(ctx, (unsigned int)wire_len, (unsigned > char*)keyname); > + from_wire(keyname); > ++ > ++#define RRBUFLEN 300 /* Most RRs are smaller than this. */ > + > + for (i = 0; i < rrsetidx; ++i) > + { > +- int seg; > +- unsigned char *end, *cp; > +- u16 len, *dp; > ++ int j; > ++ struct rdata_state state; > ++ u16 len; > ++ unsigned char rrbuf[RRBUFLEN]; > + > + p = rrset[i]; > +- > ++ > + if (!extract_name(header, plen, &p, name, 1, 10)) > + return STAT_BOGUS; > + > +@@ -586,12 +598,11 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > + /* if more labels than in RRsig name, hash *.<no labels in > rrsig labels field> 4035 5.3.2 */ > + if (labels < name_labels) > + { > +- int k; > +- for (k = name_labels - labels; k != 0; k--) > ++ for (j = name_labels - labels; j != 0; j--) > + { > + while (*name_start != '.' && *name_start != 0) > + name_start++; > +- if (k != 1 && *name_start == '.') > ++ if (j != 1 && *name_start == '.') > + name_start++; > + } > + > +@@ -612,24 +623,44 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > + if (!CHECK_LEN(header, p, plen, rdlen)) > + return STAT_BOGUS; > + > +- end = p + rdlen; > ++ /* canonicalise rdata and calculate length of same, use > ++ name buffer as workspace for get_rdata. */ > ++ state.ip = p; > ++ state.op = NULL; > ++ state.desc = rr_desc; > ++ state.buff = name; > ++ state.end = p + rdlen; > + > +- /* canonicalise rdata and calculate length of same, use name > buffer as workspace. > +- Note that name buffer is twice MAXDNAME long in DNSSEC > mode. */ > +- cp = p; > +- dp = rr_desc; > +- for (len = 0; (seg = get_rdata(header, plen, end, name, > MAXDNAME * 2, &cp, &dp)) != 0; len += seg); > +- len += end - cp; > +- len = htons(len); > ++ for (j = 0; get_rdata(header, plen, &state); j++) > ++ if (j < RRBUFLEN) > ++ rrbuf[j] = *state.op; > ++ > ++ len = htons((u16)j); > + hash->update(ctx, 2, (unsigned char *)&len); > ++ > ++ /* If the RR is shorter than RRBUFLEN (most of them, in > practice) > ++ then we can just digest it now. If it exceeds RRBUFLEN we > have to > ++ go back to the start and do it in chunks. */ > ++ if (j >= RRBUFLEN) > ++ { > ++ state.ip = p; > ++ state.op = NULL; > ++ state.desc = rr_desc; > ++ > ++ for (j = 0; get_rdata(header, plen, &state); j++) > ++ { > ++ rrbuf[j] = *state.op; > ++ > ++ if (j == RRBUFLEN - 1) > ++ { > ++ hash->update(ctx, RRBUFLEN, rrbuf); > ++ j = -1; > ++ } > ++ } > ++ } > + > +- /* Now canonicalise again and digest. */ > +- cp = p; > +- dp = rr_desc; > +- while ((seg = get_rdata(header, plen, end, name, MAXDNAME * > 2, &cp, &dp))) > +- hash->update(ctx, seg, (unsigned char *)name); > +- if (cp != end) > +- hash->update(ctx, end - cp, cp); > ++ if (j != 0) > ++ hash->update(ctx, j, rrbuf); > + } > + > + hash->digest(ctx, hash->digest_size, digest); > +-- > +2.20.1 > diff --git > a/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25684.patch > b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25684.patch > new file mode 100644 > index 000000000..64ebed257 > --- /dev/null > +++ b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25684.patch > @@ -0,0 +1,100 @@ > +From 257ac0c5f7732cbc6aa96fdd3b06602234593aca Mon Sep 17 00:00:00 2001 > +From: Simon Kelley <si...@thekelleys.org.uk> > +Date: Thu, 12 Nov 2020 18:49:23 +0000 > +Subject: [PATCH] Check destination of DNS UDP query replies. > + > +At any time, dnsmasq will have a set of sockets open, bound to > +random ports, on which it sends queries to upstream nameservers. > +This patch fixes the existing problem that a reply for ANY in-flight > +query would be accepted via ANY open port, which increases the > +chances of an attacker flooding answers "in the blind" in an > +attempt to poison the DNS cache. CERT VU#434904 refers. > + > +Signed-off-by: Sana Kazi <sana.k...@kpit.com> > +--- > + CHANGELOG | 6 +++++- > + src/forward.c | 37 ++++++++++++++++++++++++++++--------- > + 2 files changed, 33 insertions(+), 10 deletions(-) > + > +CVE: CVE-2020-25684 > +Upstream-Status: Backport > [https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=patch;h=257ac0c5f7732cbc6aa96fdd3b06602234593aca] > +Comment: No change in any hunk > + > +diff --git a/src/forward.c b/src/forward.c > +index 9c2b2c6..134e0fc 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -16,7 +16,7 @@ > + > + #include "dnsmasq.h" > + > +-static struct frec *lookup_frec(unsigned short id, void *hash); > ++static struct frec *lookup_frec(unsigned short id, int fd, int > family, void *hash); > + static struct frec *lookup_frec_by_sender(unsigned short id, > + union mysockaddr *addr, > + void *hash); > +@@ -805,7 +805,7 @@ void reply_query(int fd, int family, time_t now) > + crc = questions_crc(header, n, daemon->namebuff); > + #endif > + > +- if (!(forward = lookup_frec(ntohs(header->id), hash))) > ++ if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash))) > + return; > + > + #ifdef HAVE_DUMPFILE > +@@ -2339,14 +2339,25 @@ struct frec *get_new_frec(time_t now, int > *wait, struct frec *force) > + } > + > + /* crc is all-ones if not known. */ > +-static struct frec *lookup_frec(unsigned short id, void *hash) > ++static struct frec *lookup_frec(unsigned short id, int fd, int > family, void *hash) > + { > + struct frec *f; > + > + for(f = daemon->frec_list; f; f = f->next) > + if (f->sentto && f->new_id == id && > + (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0)) > +- return f; > ++ { > ++ /* sent from random port */ > ++ if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd) > ++ return f; > ++ > ++ if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd) > ++ return f; > ++ > ++ /* sent to upstream from bound socket. */ > ++ if (f->sentto->sfd && f->sentto->sfd->fd == fd) > ++ return f; > ++ } > + > + return NULL; > + } > +@@ -2407,12 +2418,20 @@ void server_gone(struct server *server) > + static unsigned short get_id(void) > + { > + unsigned short ret = 0; > ++ struct frec *f; > + > +- do > +- ret = rand16(); > +- while (lookup_frec(ret, NULL)); > +- > +- return ret; > ++ while (1) > ++ { > ++ ret = rand16(); > ++ > ++ /* ensure id is unique. */ > ++ for (f = daemon->frec_list; f; f = f->next) > ++ if (f->sentto && f->new_id == ret) > ++ break; > ++ > ++ if (!f) > ++ return ret; > ++ } > + } > + > + > +-- > +2.20.1 > diff --git > a/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-1.patch > b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-1.patch > new file mode 100644 > index 000000000..a8d9b7e3f > --- /dev/null > +++ b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-1.patch > @@ -0,0 +1,590 @@ > +From 2d765867c597db18be9d876c9c17e2c0fe1953cd Mon Sep 17 00:00:00 2001 > +From: Simon Kelley <si...@thekelleys.org.uk> > +Date: Thu, 12 Nov 2020 22:06:07 +0000 > +Subject: [PATCH] Use SHA-256 to provide security against DNS cache > poisoning. > + > +Use the SHA-256 hash function to verify that DNS answers > +received are for the questions originally asked. This replaces > +the slightly insecure SHA-1 (when compiled with DNSSEC) or > +the very insecure CRC32 (otherwise). Refer: CERT VU#434904. > + > +Signed-off-by: Sana Kazi <sana.k...@kpit.com> > +--- > + CHANGELOG | 5 + > + Makefile | 3 +- > + bld/Android.mk | 2 +- > + src/dnsmasq.h | 11 +- > + src/dnssec.c | 31 ----- > + src/forward.c | 43 ++----- > + src/hash_questions.c | 281 +++++++++++++++++++++++++++++++++++++++++++ > + src/rfc1035.c | 49 -------- > + 8 files changed, 301 insertions(+), 124 deletions(-) > + create mode 100644 src/hash_questions.c > + > +CVE: CVE-2020-25685 > +Upstream-Status: Backport > []http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=2d765867c597db18be9d876c9c17e2c0fe1953cd] > +Comment: No change in any hunk > + > +diff --git a/Makefile b/Makefile > +index 78e25f0..0354e0f 100644 > +--- a/Makefile > ++++ b/Makefile > +@@ -77,7 +77,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o > network.o \ > + helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ > + dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ > + domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \ > +- poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o > ++ poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \ > ++ metrics.o hash_questions.o > + > + hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ > + dns-protocol.h radv-protocol.h ip6addr.h metrics.h > +diff --git a/bld/Android.mk b/bld/Android.mk > +index 080a615..f924be9 100644 > +--- a/bld/Android.mk > ++++ b/bld/Android.mk > +@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c > dnsmasq.c \ > + radv.c slaac.c auth.c ipset.c domain.c \ > + dnssec.c dnssec-openssl.c blockdata.c tables.c \ > + loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \ > +- crypto.c dump.c ubus.c > ++ crypto.c dump.c ubus.c metrics.c hash_questions.c > + > + LOCAL_MODULE := dnsmasq > + > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 4d78c37..0a7639f 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -655,11 +655,7 @@ struct hostsfile { > + #define FREC_TEST_PKTSZ 256 > + #define FREC_HAS_EXTRADATA 512 > + > +-#ifdef HAVE_DNSSEC > +-#define HASH_SIZE 20 /* SHA-1 digest size */ > +-#else > +-#define HASH_SIZE sizeof(int) > +-#endif > ++#define HASH_SIZE 32 /* SHA-256 digest size */ > + > + struct frec { > + union mysockaddr source; > +@@ -1229,7 +1225,6 @@ int check_for_bogus_wildcard(struct dns_header > *header, size_t qlen, char *name, > + struct bogus_addr *baddr, time_t now); > + int check_for_ignored_address(struct dns_header *header, size_t > qlen, struct bogus_addr *baddr); > + int check_for_local_domain(char *name, time_t now); > +-unsigned int questions_crc(struct dns_header *header, size_t plen, > char *name); > + size_t resize_packet(struct dns_header *header, size_t plen, > + unsigned char *pheader, size_t hlen); > + int add_resource_record(struct dns_header *header, char *limit, int > *truncp, > +@@ -1254,9 +1249,11 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > + int check_unsigned, int *neganswer, int > *nons, int *nsec_ttl); > + int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen); > + size_t filter_rrsigs(struct dns_header *header, size_t plen); > +-unsigned char* hash_questions(struct dns_header *header, size_t > plen, char *name); > + int setup_timestamp(void); > + > ++/* hash_questions.c */ > ++unsigned char *hash_questions(struct dns_header *header, size_t > plen, char *name); > ++ > + /* crypto.c */ > + const struct nettle_hash *hash_find(char *name); > + int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned > char **digestp); > +diff --git a/src/dnssec.c b/src/dnssec.c > +index e95aa34..9410a7e 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -2087,35 +2087,4 @@ size_t dnssec_generate_query(struct dns_header > *header, unsigned char *end, char > + return ret; > + } > + > +-unsigned char* hash_questions(struct dns_header *header, size_t > plen, char *name) > +-{ > +- int q; > +- unsigned int len; > +- unsigned char *p = (unsigned char *)(header+1); > +- const struct nettle_hash *hash; > +- void *ctx; > +- unsigned char *digest; > +- > +- if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest)) > +- return NULL; > +- > +- for (q = ntohs(header->qdcount); q != 0; q--) > +- { > +- if (!extract_name(header, plen, &p, name, 1, 4)) > +- break; /* bad packet */ > +- > +- len = to_wire(name); > +- hash->update(ctx, len, (unsigned char *)name); > +- /* CRC the class and type as well */ > +- hash->update(ctx, 4, p); > +- > +- p += 4; > +- if (!CHECK_LEN(header, p, plen, 0)) > +- break; /* bad packet */ > +- } > +- > +- hash->digest(ctx, hash->digest_size, digest); > +- return digest; > +-} > +- > + #endif /* HAVE_DNSSEC */ > +diff --git a/src/forward.c b/src/forward.c > +index 134e0fc..4f9a963 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -256,19 +256,16 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + union all_addr *addrp = NULL; > + unsigned int flags = 0; > + struct server *start = NULL; > +-#ifdef HAVE_DNSSEC > + void *hash = hash_questions(header, plen, daemon->namebuff); > ++#ifdef HAVE_DNSSEC > + int do_dnssec = 0; > +-#else > +- unsigned int crc = questions_crc(header, plen, daemon->namebuff); > +- void *hash = &crc; > + #endif > + unsigned int gotname = extract_request(header, plen, > daemon->namebuff, NULL); > + unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, > NULL, NULL); > + (void)do_bit; > + > + /* may be no servers available. */ > +- if (forward || (hash && (forward = > lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))) > ++ if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), > udpaddr, hash))) > + { > + /* If we didn't get an answer advertising a maximal packet in > EDNS, > + fall back to 1280, which should work everywhere on IPv6. > +@@ -769,9 +766,6 @@ void reply_query(int fd, int family, time_t now) > + size_t nn; > + struct server *server; > + void *hash; > +-#ifndef HAVE_DNSSEC > +- unsigned int crc; > +-#endif > + > + /* packet buffer overwritten */ > + daemon->srv_save = NULL; > +@@ -798,12 +792,7 @@ void reply_query(int fd, int family, time_t now) > + if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME) > + server->edns_pktsz = daemon->edns_pktsz; > + > +-#ifdef HAVE_DNSSEC > + hash = hash_questions(header, n, daemon->namebuff); > +-#else > +- hash = &crc; > +- crc = questions_crc(header, n, daemon->namebuff); > +-#endif > + > + if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash))) > + return; > +@@ -1115,8 +1104,7 @@ void reply_query(int fd, int family, time_t now) > + log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, > daemon->keyname, (union all_addr *)&(server->addr.in6.sin6_addr), > + querystr("dnssec-query", querytype)); > + > +- if ((hash = hash_questions(header, nn, > daemon->namebuff))) > +- memcpy(new->hash, hash, HASH_SIZE); > ++ memcpy(new->hash, hash_questions(header, nn, > daemon->namebuff), HASH_SIZE); > + new->new_id = get_id(); > + header->id = htons(new->new_id); > + /* Save query for retransmission */ > +@@ -1970,15 +1958,9 @@ unsigned char *tcp_request(int confd, time_t now, > + if (!flags && last_server) > + { > + struct server *firstsendto = NULL; > +-#ifdef HAVE_DNSSEC > +- unsigned char *newhash, hash[HASH_SIZE]; > +- if ((newhash = hash_questions(header, (unsigned > int)size, daemon->namebuff))) > +- memcpy(hash, newhash, HASH_SIZE); > +- else > +- memset(hash, 0, HASH_SIZE); > +-#else > +- unsigned int crc = questions_crc(header, (unsigned > int)size, daemon->namebuff); > +-#endif > ++ unsigned char hash[HASH_SIZE]; > ++ memcpy(hash, hash_questions(header, (unsigned > int)size, daemon->namebuff), HASH_SIZE); > ++ > + /* Loop round available servers until we succeed in > connecting to one. > + Note that this code subtly ensures that > consecutive queries on this connection > + which can go to the same server, do so. */ > +@@ -2117,20 +2099,11 @@ unsigned char *tcp_request(int confd, time_t now, > + /* If the crc of the question section doesn't > match the crc we sent, then > + someone might be attempting to insert bogus > values into the cache by > + sending replies containing questions and > bogus answers. */ > +-#ifdef HAVE_DNSSEC > +- newhash = hash_questions(header, (unsigned > int)m, daemon->namebuff); > +- if (!newhash || memcmp(hash, newhash, HASH_SIZE) > != 0) > ++ if (memcmp(hash, hash_questions(header, > (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0) > + { > + m = 0; > + break; > + } > +-#else > +- if (crc != questions_crc(header, (unsigned > int)m, daemon->namebuff)) > +- { > +- m = 0; > +- break; > +- } > +-#endif > + > + m = process_reply(header, now, last_server, > (unsigned int)m, > + option_bool(OPT_NO_REBIND) && > !norebind, no_cache_dnssec, cache_secure, bogusanswer, > +@@ -2345,7 +2318,7 @@ static struct frec *lookup_frec(unsigned short > id, int fd, int family, void *has > + > + for(f = daemon->frec_list; f; f = f->next) > + if (f->sentto && f->new_id == id && > +- (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0)) > ++ (memcmp(hash, f->hash, HASH_SIZE) == 0)) > + { > + /* sent from random port */ > + if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd) > +diff --git a/src/hash_questions.c b/src/hash_questions.c > +new file mode 100644 > +index 0000000..ae112ac > +--- /dev/null > ++++ b/src/hash_questions.c > +@@ -0,0 +1,281 @@ > ++/* Copyright (c) 2012-2020 Simon Kelley > ++ > ++ This program is free software; you can redistribute it and/or modify > ++ it under the terms of the GNU General Public License as published by > ++ the Free Software Foundation; version 2 dated June, 1991, or > ++ (at your option) version 3 dated 29 June, 2007. > ++ > ++ This program is distributed in the hope that it will be useful, > ++ but WITHOUT ANY WARRANTY; without even the implied warranty of > ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > ++ GNU General Public License for more details. > ++ > ++ You should have received a copy of the GNU General Public License > ++ along with this program. If not, see <http://www.gnu.org/licenses/>. > ++*/ > ++ > ++ > ++/* Hash the question section. This is used to safely detect query > ++ retransmission and to detect answers to questions we didn't ask, > which > ++ might be poisoning attacks. Note that we decode the name rather > ++ than CRC the raw bytes, since replies might be compressed > differently. > ++ We ignore case in the names for the same reason. > ++ > ++ The hash used is SHA-256. If we're building with DNSSEC support, > ++ we use the Nettle cypto library. If not, we prefer not to > ++ add a dependency on Nettle, and use a stand-alone implementaion. > ++*/ > ++ > ++#include "dnsmasq.h" > ++ > ++#ifdef HAVE_DNSSEC > ++unsigned char *hash_questions(struct dns_header *header, size_t > plen, char *name) > ++{ > ++ int q; > ++ unsigned char *p = (unsigned char *)(header+1); > ++ const struct nettle_hash *hash; > ++ void *ctx; > ++ unsigned char *digest; > ++ > ++ if (!(hash = hash_find("sha256")) || !hash_init(hash, &ctx, &digest)) > ++ { > ++ /* don't think this can ever happen. */ > ++ static unsigned char dummy[HASH_SIZE]; > ++ static int warned = 0; > ++ > ++ if (warned) > ++ my_syslog(LOG_ERR, _("Failed to create SHA-256 hash object")); > ++ warned = 1; > ++ > ++ return dummy; > ++ } > ++ > ++ for (q = ntohs(header->qdcount); q != 0; q--) > ++ { > ++ char *cp, c; > ++ > ++ if (!extract_name(header, plen, &p, name, 1, 4)) > ++ break; /* bad packet */ > ++ > ++ for (cp = name; (c = *cp); cp++) > ++ if (c >= 'A' && c <= 'Z') > ++ *cp += 'a' - 'A'; > ++ > ++ hash->update(ctx, cp - name, (unsigned char *)name); > ++ /* CRC the class and type as well */ > ++ hash->update(ctx, 4, p); > ++ > ++ p += 4; > ++ if (!CHECK_LEN(header, p, plen, 0)) > ++ break; /* bad packet */ > ++ } > ++ > ++ hash->digest(ctx, hash->digest_size, digest); > ++ return digest; > ++} > ++ > ++#else /* HAVE_DNSSEC */ > ++ > ++#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte > digest > ++typedef unsigned char BYTE; // 8-bit byte > ++typedef unsigned int WORD; // 32-bit word, change to > "long" for 16-bit machines > ++ > ++typedef struct { > ++ BYTE data[64]; > ++ WORD datalen; > ++ unsigned long long bitlen; > ++ WORD state[8]; > ++} SHA256_CTX; > ++ > ++static void sha256_init(SHA256_CTX *ctx); > ++static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t > len); > ++static void sha256_final(SHA256_CTX *ctx, BYTE hash[]); > ++ > ++ > ++unsigned char *hash_questions(struct dns_header *header, size_t > plen, char *name) > ++{ > ++ int q; > ++ unsigned char *p = (unsigned char *)(header+1); > ++ SHA256_CTX ctx; > ++ static BYTE digest[SHA256_BLOCK_SIZE]; > ++ > ++ sha256_init(&ctx); > ++ > ++ for (q = ntohs(header->qdcount); q != 0; q--) > ++ { > ++ char *cp, c; > ++ > ++ if (!extract_name(header, plen, &p, name, 1, 4)) > ++ break; /* bad packet */ > ++ > ++ for (cp = name; (c = *cp); cp++) > ++ if (c >= 'A' && c <= 'Z') > ++ *cp += 'a' - 'A'; > ++ > ++ sha256_update(&ctx, (BYTE *)name, cp - name); > ++ /* CRC the class and type as well */ > ++ sha256_update(&ctx, (BYTE *)p, 4); > ++ > ++ p += 4; > ++ if (!CHECK_LEN(header, p, plen, 0)) > ++ break; /* bad packet */ > ++ } > ++ > ++ sha256_final(&ctx, digest); > ++ return (unsigned char *)digest; > ++} > ++ > ++/* Code from here onwards comes from > https://github.com/B-Con/crypto-algorithms > <https://github.com/B-Con/crypto-algorithms> > ++ and was written by Brad Conte (b...@bradconte.com), to whom all > credit is given. > ++ > ++ This code is in the public domain, and the copyright notice at > the head of this > ++ file does not apply to it. > ++*/ > ++ > ++ > ++/****************************** MACROS ******************************/ > ++#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) > ++#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) > ++ > ++#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) > ++#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) > ++#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) > ++#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) > ++#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) > ++#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) > ++ > ++/**************************** VARIABLES *****************************/ > ++static const WORD k[64] = { > ++ > 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, > ++ > 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, > ++ > 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, > ++ > 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, > ++ > 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, > ++ > 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, > ++ > 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, > ++ > 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 > ++}; > ++ > ++/*********************** FUNCTION DEFINITIONS ***********************/ > ++static void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) > ++{ > ++ WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; > ++ > ++ for (i = 0, j = 0; i < 16; ++i, j += 4) > ++ m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << > 8) | (data[j + 3]); > ++ for ( ; i < 64; ++i) > ++ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; > ++ > ++ a = ctx->state[0]; > ++ b = ctx->state[1]; > ++ c = ctx->state[2]; > ++ d = ctx->state[3]; > ++ e = ctx->state[4]; > ++ f = ctx->state[5]; > ++ g = ctx->state[6]; > ++ h = ctx->state[7]; > ++ > ++ for (i = 0; i < 64; ++i) > ++ { > ++ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; > ++ t2 = EP0(a) + MAJ(a,b,c); > ++ h = g; > ++ g = f; > ++ f = e; > ++ e = d + t1; > ++ d = c; > ++ c = b; > ++ b = a; > ++ a = t1 + t2; > ++ } > ++ > ++ ctx->state[0] += a; > ++ ctx->state[1] += b; > ++ ctx->state[2] += c; > ++ ctx->state[3] += d; > ++ ctx->state[4] += e; > ++ ctx->state[5] += f; > ++ ctx->state[6] += g; > ++ ctx->state[7] += h; > ++} > ++ > ++static void sha256_init(SHA256_CTX *ctx) > ++{ > ++ ctx->datalen = 0; > ++ ctx->bitlen = 0; > ++ ctx->state[0] = 0x6a09e667; > ++ ctx->state[1] = 0xbb67ae85; > ++ ctx->state[2] = 0x3c6ef372; > ++ ctx->state[3] = 0xa54ff53a; > ++ ctx->state[4] = 0x510e527f; > ++ ctx->state[5] = 0x9b05688c; > ++ ctx->state[6] = 0x1f83d9ab; > ++ ctx->state[7] = 0x5be0cd19; > ++} > ++ > ++static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t > len) > ++{ > ++ WORD i; > ++ > ++ for (i = 0; i < len; ++i) > ++ { > ++ ctx->data[ctx->datalen] = data[i]; > ++ ctx->datalen++; > ++ if (ctx->datalen == 64) { > ++ sha256_transform(ctx, ctx->data); > ++ ctx->bitlen += 512; > ++ ctx->datalen = 0; > ++ } > ++ } > ++} > ++ > ++static void sha256_final(SHA256_CTX *ctx, BYTE hash[]) > ++{ > ++ WORD i; > ++ > ++ i = ctx->datalen; > ++ > ++ // Pad whatever data is left in the buffer. > ++ if (ctx->datalen < 56) > ++ { > ++ ctx->data[i++] = 0x80; > ++ while (i < 56) > ++ ctx->data[i++] = 0x00; > ++ } > ++ else > ++ { > ++ ctx->data[i++] = 0x80; > ++ while (i < 64) > ++ ctx->data[i++] = 0x00; > ++ sha256_transform(ctx, ctx->data); > ++ memset(ctx->data, 0, 56); > ++ } > ++ > ++ // Append to the padding the total message's length in bits and > transform. > ++ ctx->bitlen += ctx->datalen * 8; > ++ ctx->data[63] = ctx->bitlen; > ++ ctx->data[62] = ctx->bitlen >> 8; > ++ ctx->data[61] = ctx->bitlen >> 16; > ++ ctx->data[60] = ctx->bitlen >> 24; > ++ ctx->data[59] = ctx->bitlen >> 32; > ++ ctx->data[58] = ctx->bitlen >> 40; > ++ ctx->data[57] = ctx->bitlen >> 48; > ++ ctx->data[56] = ctx->bitlen >> 56; > ++ sha256_transform(ctx, ctx->data); > ++ > ++ // Since this implementation uses little endian byte ordering and > SHA uses big endian, > ++ // reverse all the bytes when copying the final state to the > output hash. > ++ for (i = 0; i < 4; ++i) > ++ { > ++ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; > ++ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; > ++ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; > ++ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; > ++ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; > ++ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; > ++ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; > ++ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; > ++ } > ++} > ++ > ++#endif > +diff --git a/src/rfc1035.c b/src/rfc1035.c > +index fefe63d..a8cdc6e 100644 > +--- a/src/rfc1035.c > ++++ b/src/rfc1035.c > +@@ -333,55 +333,6 @@ unsigned char *skip_section(unsigned char *ansp, > int count, struct dns_header *h > + return ansp; > + } > + > +-/* CRC the question section. This is used to safely detect query > +- retransmission and to detect answers to questions we didn't ask, > which > +- might be poisoning attacks. Note that we decode the name rather > +- than CRC the raw bytes, since replies might be compressed > differently. > +- We ignore case in the names for the same reason. Return all-ones > +- if there is not question section. */ > +-#ifndef HAVE_DNSSEC > +-unsigned int questions_crc(struct dns_header *header, size_t plen, > char *name) > +-{ > +- int q; > +- unsigned int crc = 0xffffffff; > +- unsigned char *p1, *p = (unsigned char *)(header+1); > +- > +- for (q = ntohs(header->qdcount); q != 0; q--) > +- { > +- if (!extract_name(header, plen, &p, name, 1, 4)) > +- return crc; /* bad packet */ > +- > +- for (p1 = (unsigned char *)name; *p1; p1++) > +- { > +- int i = 8; > +- char c = *p1; > +- > +- if (c >= 'A' && c <= 'Z') > +- c += 'a' - 'A'; > +- > +- crc ^= c << 24; > +- while (i--) > +- crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1; > +- } > +- > +- /* CRC the class and type as well */ > +- for (p1 = p; p1 < p+4; p1++) > +- { > +- int i = 8; > +- crc ^= *p1 << 24; > +- while (i--) > +- crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1; > +- } > +- > +- p += 4; > +- if (!CHECK_LEN(header, p, plen, 0)) > +- return crc; /* bad packet */ > +- } > +- > +- return crc; > +-} > +-#endif > +- > + size_t resize_packet(struct dns_header *header, size_t plen, > unsigned char *pheader, size_t hlen) > + { > + unsigned char *ansp = skip_questions(header, plen); > +-- > +2.20.1 > diff --git > a/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-2.patch > b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-2.patch > new file mode 100644 > index 000000000..6f60b36ed > --- /dev/null > +++ b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25685-2.patch > @@ -0,0 +1,201 @@ > +From 2024f9729713fd657d65e64c2e4e471baa0a3e5b Mon Sep 17 00:00:00 2001 > +From: =?utf8?q?Petr=20Men=C5=A1=C3=ADk?= <pemen...@redhat.com> > +Date: Wed, 25 Nov 2020 17:18:55 +0100 > +Subject: [PATCH] Support hash function from nettle (only) > + > +Unlike COPTS=-DHAVE_DNSSEC, allow usage of just sha256 function from > +nettle, but keep DNSSEC disabled at build time. Skips use of internal > +hash implementation without support for validation built-in. > + > +Signed-off-by: Sana Kazi <sana.k...@kpit.com> > +--- > + Makefile | 8 +++++--- > + bld/pkg-wrapper | 41 ++++++++++++++++++++++------------------- > + src/config.h | 8 ++++++++ > + src/crypto.c | 7 +++++++ > + src/dnsmasq.h | 2 +- > + src/hash_questions.c | 2 +- > + 6 files changed, 44 insertions(+), 24 deletions(-) > + > +CVE: CVE-2020-25685 > +Upstream-Status: Backport > [https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=patch;h=2024f9729713fd657d65e64c2e4e471baa0a3e5b] > +Comment: No change in any hunk > + > +diff --git a/Makefile b/Makefile > +index 0354e0f..7d2afd1 100644 > +--- a/Makefile > ++++ b/Makefile > +@@ -53,7 +53,7 @@ top?=$(CURDIR) > + > + dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS > $(PKG_CONFIG) --cflags dbus-1` > + dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS > $(PKG_CONFIG) --libs dbus-1` > +-ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" > --copy -lubox -lubus` > ++ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" > --copy '-lubox -lubus'` > + idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN > $(PKG_CONFIG) --cflags libidn` > + idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN > $(PKG_CONFIG) --libs libidn` > + idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 > $(PKG_CONFIG) --cflags libidn2` > +@@ -61,8 +62,10 @@ > + ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper > HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack` > + lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper > HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua` > + lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper > HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua` > +-nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC > $(PKG_CONFIG) --cflags nettle hogweed` > +-nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC > $(PKG_CONFIG) --libs nettle hogweed` > ++nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper > HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \ > ++ > HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle` > ++nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper > HAVE_DNSSEC $(PKG_CONFIG) --libs 'nettle hogweed' \ > ++ > HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle` > + gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC > NO_GMP --copy -lgmp` > + sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo > -lsocket -lnsl -lposix4; fi` > + version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"' > +diff --git a/bld/pkg-wrapper b/bld/pkg-wrapper > +index 704bdd3..89713b4 100755 > +--- a/bld/pkg-wrapper > ++++ b/bld/pkg-wrapper > +@@ -1,35 +1,37 @@ > + #!/bin/sh > + > +-search=$1 > +-shift > +-pkg=$1 > +-shift > +-op=$1 > +-shift > +- > + in=`cat` > + > +-if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h > >/dev/null 2>&1 || \ > +- echo $in | grep $search >/dev/null 2>&1; then > ++search() > ++{ > ++ grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null > 2>&1 || \ > ++ echo $in | grep $1 >/dev/null 2>&1 > ++} > ++ > ++while [ "$#" -gt 0 ]; do > ++ search=$1 > ++ pkg=$2 > ++ op=$3 > ++ lib=$4 > ++ shift 4 > ++if search "$search"; then > ++ > + # Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to > search for, used with NO_GMP > + if [ $op = "--copy" ]; then > + if [ -z "$pkg" ]; then > +- pkg="$*" > +- elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h > >/dev/null 2>&1 || \ > +- echo $in | grep $pkg >/dev/null 2>&1; then > ++ pkg="$lib" > ++ elif search "$pkg"; then > + pkg="" > + else > +- pkg="$*" > ++ pkg="$lib" > + fi > +- elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" > config.h >/dev/null 2>&1 || \ > +- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then > +- pkg=`$pkg --static $op $*` > ++ elif search "${search}_STATIC"; then > ++ pkg=`$pkg --static $op $lib` > + else > +- pkg=`$pkg $op $*` > ++ pkg=`$pkg $op $lib` > + fi > + > +- if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" > config.h >/dev/null 2>&1 || \ > +- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then > ++ if search "${search}_STATIC"; then > + if [ $op = "--libs" ] || [ $op = "--copy" ]; then > + echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic" > + else > +@@ -40,3 +42,4 @@ if grep "^\#[[:space:]]*define[[:space:]]*$search" > config.h >/dev/null 2>&1 || \ > + fi > + fi > + > ++done > +diff --git a/src/config.h b/src/config.h > +index 7187ffa..e71a117 100644 > +--- a/src/config.h > ++++ b/src/config.h > +@@ -120,6 +120,9 @@ HAVE_AUTH > + define this to include the facility to act as an authoritative DNS > + server for one or more zones. > + > ++HAVE_NETTLEHASH > ++ include just hash function from nettle, but no DNSSEC. > ++ > + HAVE_DNSSEC > + include DNSSEC validator. > + > +@@ -187,6 +190,7 @@ RESOLVFILE > + /* #define HAVE_IDN */ > + /* #define HAVE_LIBIDN2 */ > + /* #define HAVE_CONNTRACK */ > ++/* #define HAVE_NETTLEHASH */ > + /* #define HAVE_DNSSEC */ > + > + > +@@ -420,6 +424,10 @@ static char *compile_opts = > + "no-" > + #endif > + "auth " > ++#if !defined(HAVE_NETTLEHASH) && !defined(HAVE_DNSSEC) > ++"no-" > ++#endif > ++"nettlehash " > + #ifndef HAVE_DNSSEC > + "no-" > + #endif > +diff --git a/src/crypto.c b/src/crypto.c > +index ca63111..09525d2 100644 > +--- a/src/crypto.c > ++++ b/src/crypto.c > +@@ -25,6 +25,9 @@ > + #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6 > + # include <nettle/gostdsa.h> > + #endif > ++#endif > ++ > ++#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH) > + #include <nettle/nettle-meta.h> > + #include <nettle/bignum.h> > + > +@@ -167,6 +170,10 @@ int hash_init(const struct nettle_hash *hash, > void **ctxp, unsigned char **diges > + > + return 1; > + } > ++ > ++#endif > ++ > ++#ifdef HAVE_DNSSEC > + > + static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned > int key_len, unsigned char *sig, size_t sig_len, > + unsigned char *digest, size_t > digest_len, int algo) > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 9f74c7a..914f469 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -157,7 +157,7 @@ extern int capget(cap_user_header_t header, > cap_user_data_t data); > + #include <priv.h> > + #endif > + > +-#ifdef HAVE_DNSSEC > ++#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH) > + # include <nettle/nettle-meta.h> > + #endif > + > +diff --git a/src/hash_questions.c b/src/hash_questions.c > +index ae112ac..917c18e 100644 > +--- a/src/hash_questions.c > ++++ b/src/hash_questions.c > +@@ -28,7 +28,7 @@ > + > + #include "dnsmasq.h" > + > +-#ifdef HAVE_DNSSEC > ++#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH) > + unsigned char *hash_questions(struct dns_header *header, size_t > plen, char *name) > + { > + int q; > +-- > +2.20.1 > diff --git > a/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-1.patch > b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-1.patch > new file mode 100644 > index 000000000..b07ab6045 > --- /dev/null > +++ b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-1.patch > @@ -0,0 +1,335 @@ > +From 15b60ddf935a531269bb8c68198de012a4967156 Mon Sep 17 00:00:00 2001 > +From: Simon Kelley <si...@thekelleys.org.uk> > +Date: Wed, 18 Nov 2020 18:34:55 +0000 > +Subject: [PATCH] Handle multiple identical near simultaneous DNS queries > + better. > + > +Previously, such queries would all be forwarded > +independently. This is, in theory, inefficent but in practise > +not a problem, _except_ that is means that an answer for any > +of the forwarded queries will be accepted and cached. > +An attacker can send a query multiple times, and for each repeat, > +another {port, ID} becomes capable of accepting the answer he is > +sending in the blind, to random IDs and ports. The chance of a > +succesful attack is therefore multiplied by the number of repeats > +of the query. The new behaviour detects repeated queries and > +merely stores the clients sending repeats so that when the > +first query completes, the answer can be sent to all the > +clients who asked. Refer: CERT VU#434904. > + > +Signed-off-by: Sana Kazi <sana.k...@kpit.com> > +--- > + CHANGELOG | 16 +++++- > + src/dnsmasq.h | 19 ++++--- > + src/forward.c | 142 ++++++++++++++++++++++++++++++++++++++++++-------- > + 3 files changed, 147 insertions(+), 30 deletions(-) > + > +CVE: CVE-2020-25686 > +Upstream-Status: Backport > [http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=15b60ddf935a531269bb8c68198de012a4967156] > +Comment: No change in any hunk > + > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 0a7639f..fa8c5ea 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -653,19 +653,24 @@ struct hostsfile { > + #define FREC_DO_QUESTION 64 > + #define FREC_ADDED_PHEADER 128 > + #define FREC_TEST_PKTSZ 256 > +-#define FREC_HAS_EXTRADATA 512 > ++#define FREC_HAS_EXTRADATA 512 > ++#define FREC_HAS_PHEADER 1024 > + > + #define HASH_SIZE 32 /* SHA-256 digest size */ > + > + struct frec { > +- union mysockaddr source; > +- union all_addr dest; > ++ struct frec_src { > ++ union mysockaddr source; > ++ union all_addr dest; > ++ unsigned int iface, log_id; > ++ unsigned short orig_id; > ++ struct frec_src *next; > ++ } frec_src; > + struct server *sentto; /* NULL means free */ > + struct randfd *rfd4; > + struct randfd *rfd6; > +- unsigned int iface; > +- unsigned short orig_id, new_id; > +- int log_id, fd, forwardall, flags; > ++ unsigned short new_id; > ++ int fd, forwardall, flags; > + time_t time; > + unsigned char *hash[HASH_SIZE]; > + #ifdef HAVE_DNSSEC > +@@ -1093,6 +1098,8 @@ extern struct daemon { > + int back_to_the_future; > + #endif > + struct frec *frec_list; > ++ struct frec_src *free_frec_src; > ++ int frec_src_count; > + struct serverfd *sfds; > + struct irec *interfaces; > + struct listener *listeners; > +diff --git a/src/forward.c b/src/forward.c > +index 50da095..d9b32b3 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -20,6 +20,8 @@ static struct frec *lookup_frec(unsigned short id, > int fd, int family, void *has > + static struct frec *lookup_frec_by_sender(unsigned short id, > + union mysockaddr *addr, > + void *hash); > ++static struct frec *lookup_frec_by_query(void *hash, unsigned int > flags); > ++ > + static unsigned short get_id(void); > + static void free_frec(struct frec *f); > + > +@@ -255,6 +257,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + int type = SERV_DO_DNSSEC, norebind = 0; > + union all_addr *addrp = NULL; > + unsigned int flags = 0; > ++ unsigned int fwd_flags = 0; > + struct server *start = NULL; > + void *hash = hash_questions(header, plen, daemon->namebuff); > + #ifdef HAVE_DNSSEC > +@@ -263,7 +266,18 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + unsigned int gotname = extract_request(header, plen, > daemon->namebuff, NULL); > + unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, > NULL, NULL); > + (void)do_bit; > +- > ++ > ++ if (header->hb4 & HB4_CD) > ++ fwd_flags |= FREC_CHECKING_DISABLED; > ++ if (ad_reqd) > ++ fwd_flags |= FREC_AD_QUESTION; > ++ if (oph) > ++ fwd_flags |= FREC_HAS_PHEADER; > ++#ifdef HAVE_DNSSEC > ++ if (do_bit) > ++ fwd_flags |= FREC_DO_QUESTION; > ++#endif > ++ > + /* may be no servers available. */ > + if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), > udpaddr, hash))) > + { > +@@ -336,6 +350,39 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + } > + else > + { > ++ /* Query from new source, but the same query may be in progress > ++ from another source. If so, just add this client to the > ++ list that will get the reply. > ++ > ++ Note that is the EDNS client subnet option is in use, we > can't do this, > ++ as the clients (and therefore query EDNS options) will be > different > ++ for each query. The EDNS subnet code has checks to avoid > ++ attacks in this case. */ > ++ if (!option_bool(OPT_CLIENT_SUBNET) && (forward = > lookup_frec_by_query(hash, fwd_flags))) > ++ { > ++ /* Note whine_malloc() zeros memory. */ > ++ if (!daemon->free_frec_src && > ++ daemon->frec_src_count < daemon->ftabsize && > ++ (daemon->free_frec_src = whine_malloc(sizeof(struct > frec_src)))) > ++ daemon->frec_src_count++; > ++ > ++ /* If we've been spammed with many duplicates, just drop the > query. */ > ++ if (daemon->free_frec_src) > ++ { > ++ struct frec_src *new = daemon->free_frec_src; > ++ daemon->free_frec_src = new->next; > ++ new->next = forward->frec_src.next; > ++ forward->frec_src.next = new; > ++ new->orig_id = ntohs(header->id); > ++ new->source = *udpaddr; > ++ new->dest = *dst_addr; > ++ new->log_id = daemon->log_id; > ++ new->iface = dst_iface; > ++ } > ++ > ++ return 1; > ++ } > ++ > + if (gotname) > + flags = search_servers(now, &addrp, gotname, > daemon->namebuff, &type, &domain, &norebind); > + > +@@ -343,22 +390,22 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + do_dnssec = type & SERV_DO_DNSSEC; > + #endif > + type &= ~SERV_DO_DNSSEC; > +- > ++ > + if (daemon->servers && !flags) > + forward = get_new_frec(now, NULL, NULL); > + /* table full - flags == 0, return REFUSED */ > + > + if (forward) > + { > +- forward->source = *udpaddr; > +- forward->dest = *dst_addr; > +- forward->iface = dst_iface; > +- forward->orig_id = ntohs(header->id); > ++ forward->frec_src.source = *udpaddr; > ++ forward->frec_src.orig_id = ntohs(header->id); > ++ forward->frec_src.dest = *dst_addr; > ++ forward->frec_src.iface = dst_iface; > + forward->new_id = get_id(); > + forward->fd = udpfd; > + memcpy(forward->hash, hash, HASH_SIZE); > + forward->forwardall = 0; > +- forward->flags = 0; > ++ forward->flags = fwd_flags; > + if (norebind) > + forward->flags |= FREC_NOREBIND; > + if (header->hb4 & HB4_CD) > +@@ -413,9 +460,9 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + unsigned char *pheader; > + > + /* If a query is retried, use the log_id for the retry when > logging the answer. */ > +- forward->log_id = daemon->log_id; > ++ forward->frec_src.log_id = daemon->log_id; > + > +- plen = add_edns0_config(header, plen, ((unsigned char > *)header) + PACKETSZ, &forward->source, now, &subnet); > ++ plen = add_edns0_config(header, plen, ((unsigned char > *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet); > + > + if (subnet) > + forward->flags |= FREC_HAS_SUBNET; > +@@ -552,7 +599,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + return 1; > + > + /* could not send on, prepare to return */ > +- header->id = htons(forward->orig_id); > ++ header->id = htons(forward->frec_src.orig_id); > + free_frec(forward); /* cancel */ > + } > + > +@@ -804,8 +851,8 @@ void reply_query(int fd, int family, time_t now) > + > + /* log_query gets called indirectly all over the place, so > + pass these in global variables - sorry. */ > +- daemon->log_display_id = forward->log_id; > +- daemon->log_source_addr = &forward->source; > ++ daemon->log_display_id = forward->frec_src.log_id; > ++ daemon->log_source_addr = &forward->frec_src.source; > + > + if (daemon->ignore_addr && RCODE(header) == NOERROR && > + check_for_ignored_address(header, n, daemon->ignore_addr)) > +@@ -1080,6 +1127,7 @@ void reply_query(int fd, int family, time_t now) > + new->sentto = server; > + new->rfd4 = NULL; > + new->rfd6 = NULL; > ++ new->frec_src.next = NULL; > + new->flags &= ~(FREC_DNSKEY_QUERY | > FREC_DS_QUERY | FREC_HAS_EXTRADATA); > + new->forwardall = 0; > + > +@@ -1215,9 +1263,11 @@ void reply_query(int fd, int family, time_t now) > + > + if ((nn = process_reply(header, now, forward->sentto, > (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer, > + forward->flags & FREC_AD_QUESTION, > forward->flags & FREC_DO_QUESTION, > +- forward->flags & FREC_ADDED_PHEADER, > forward->flags & FREC_HAS_SUBNET, &forward->source))) > ++ forward->flags & FREC_ADDED_PHEADER, > forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source))) > + { > +- header->id = htons(forward->orig_id); > ++ struct frec_src *src; > ++ > ++ header->id = htons(forward->frec_src.orig_id); > + header->hb4 |= HB4_RA; /* recursion if available */ > + #ifdef HAVE_DNSSEC > + /* We added an EDNSO header for the purpose of getting > DNSSEC RRs, and set the value of the UDP payload size > +@@ -1233,13 +1283,26 @@ void reply_query(int fd, int family, time_t now) > + } > + #endif > + > ++ for (src = &forward->frec_src; src; src = src->next) > ++ { > ++ header->id = htons(src->orig_id); > ++ > + #ifdef HAVE_DUMPFILE > +- dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, > &forward->source); > ++ dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, > NULL, &src->source); > + #endif > +- > +- send_from(forward->fd, option_bool(OPT_NOWILD) || > option_bool (OPT_CLEVERBIND), daemon->packet, nn, > +- &forward->source, &forward->dest, forward->iface); > ++ > ++ send_from(forward->fd, option_bool(OPT_NOWILD) || > option_bool (OPT_CLEVERBIND), daemon->packet, nn, > ++ &src->source, &src->dest, src->iface); > ++ > ++ if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src) > ++ { > ++ daemon->log_display_id = src->log_id; > ++ daemon->log_source_addr = &src->source; > ++ log_query(F_UPSTREAM, "query", NULL, "duplicate"); > ++ } > ++ } > + } > ++ > + free_frec(forward); /* cancel */ > + } > + } > +@@ -2202,6 +2265,17 @@ void free_rfd(struct randfd *rfd) > + > + static void free_frec(struct frec *f) > + { > ++ struct frec_src *src, *tmp; > ++ > ++ /* add back to freelist of not the record builtin to every frec. */ > ++ for (src = f->frec_src.next; src; src = tmp) > ++ { > ++ tmp = src->next; > ++ src->next = daemon->free_frec_src; > ++ daemon->free_frec_src = src; > ++ } > ++ > ++ f->frec_src.next = NULL; > + free_rfd(f->rfd4); > + f->rfd4 = NULL; > + f->sentto = NULL; > +@@ -2342,17 +2416,39 @@ static struct frec > *lookup_frec_by_sender(unsigned short id, > + void *hash) > + { > + struct frec *f; > ++ struct frec_src *src; > ++ > ++ for (f = daemon->frec_list; f; f = f->next) > ++ if (f->sentto && > ++ !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) && > ++ memcmp(hash, f->hash, HASH_SIZE) == 0) > ++ for (src = &f->frec_src; src; src = src->next) > ++ if (src->orig_id == id && > ++ sockaddr_isequal(&src->source, addr)) > ++ return f; > ++ > ++ return NULL; > ++} > ++ > ++static struct frec *lookup_frec_by_query(void *hash, unsigned int flags) > ++{ > ++ struct frec *f; > ++ > ++ /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the > test below > ++ ensures that no frec created for internal DNSSEC query can be > returned here. */ > ++ > ++#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | > FREC_DO_QUESTION \ > ++ | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY) > + > + for(f = daemon->frec_list; f; f = f->next) > + if (f->sentto && > +- f->orig_id == id && > +- memcmp(hash, f->hash, HASH_SIZE) == 0 && > +- sockaddr_isequal(&f->source, addr)) > ++ (f->flags & FLAGMASK) == flags && > ++ memcmp(hash, f->hash, HASH_SIZE) == 0) > + return f; > +- > ++ > + return NULL; > + } > +- > ++ > + /* Send query packet again, if we can. */ > + void resend_query() > + { > +-- > +2.20.1 > + > diff --git > a/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-2.patch > b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-2.patch > new file mode 100644 > index 000000000..4e03dd92b > --- /dev/null > +++ b/meta-networking/recipes-support/dnsmasq/files/CVE-2020-25686-2.patch > @@ -0,0 +1,66 @@ > +From 6a6e06fbb0d4690507ceaf2bb6f0d8910f3d4914 Mon Sep 17 00:00:00 2001 > +From: Simon Kelley <si...@thekelleys.org.uk> > +Date: Fri, 4 Dec 2020 18:35:11 +0000 > +Subject: [PATCH] Small cleanups in frec_src datastucture handling. > + > +Signed-off-by: Sana Kazi <sana.k...@kpit.com> > +--- > + src/forward.c | 22 +++++++++++++--------- > + 1 file changed, 13 insertions(+), 9 deletions(-) > + > +CVE: CVE-2020-25686 > +Upstream-Status: Backport > [http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=6a6e06fbb0d4690507ceaf2bb6f0d8910f3d4914] > +Comment: No change in any hunk > + > +diff --git a/src/forward.c b/src/forward.c > +index 70b84d7..f94c4cf 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -361,7 +361,10 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + if (!daemon->free_frec_src && > + daemon->frec_src_count < daemon->ftabsize && > + (daemon->free_frec_src = whine_malloc(sizeof(struct > frec_src)))) > +- daemon->frec_src_count++; > ++ { > ++ daemon->frec_src_count++; > ++ daemon->free_frec_src->next = NULL; > ++ } > + > + /* If we've been spammed with many duplicates, just drop > the query. */ > + if (daemon->free_frec_src) > +@@ -398,6 +401,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + forward->frec_src.orig_id = ntohs(header->id); > + forward->frec_src.dest = *dst_addr; > + forward->frec_src.iface = dst_iface; > ++ forward->frec_src.next = NULL; > + forward->new_id = get_id(); > + forward->fd = udpfd; > + memcpy(forward->hash, hash, HASH_SIZE); > +@@ -2265,16 +2265,16 @@ > + > + static void free_frec(struct frec *f) > + { > +- struct frec_src *src, *tmp; > +- > +- /* add back to freelist of not the record builtin to every frec. */ > +- for (src = f->frec_src.next; src; src = tmp) > ++ struct frec_src *last; > ++ > ++ /* add back to freelist if not the record builtin to every frec. */ > ++ for (last = f->frec_src.next; last && last->next; last = last->next) ; > ++ if (last) > + { > +- tmp = src->next; > +- src->next = daemon->free_frec_src; > +- daemon->free_frec_src = src; > ++ last->next = daemon->free_frec_src; > ++ daemon->free_frec_src = f->frec_src.next; > + } > +- > ++ > + f->frec_src.next = NULL; > + free_rfd(f->rfd4); > + f->rfd4 = NULL; > +-- > +2.20.1 > + > -- > 2.17.1 > > This message contains information that may be privileged or > confidential and is the property of the KPIT Technologies Ltd. It is > intended only for the person to whom it is addressed. If you are not > the intended recipient, you are not authorized to read, print, retain > copy, disseminate, distribute, or use this message or any part > thereof. If you receive this message in error, please notify the > sender immediately and delete all copies of this message. KPIT > Technologies Ltd. does not accept any liability for virus infected mails. > > >
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#90500): https://lists.openembedded.org/g/openembedded-devel/message/90500 Mute This Topic: https://lists.openembedded.org/mt/81423054/21656 Group Owner: openembedded-devel+ow...@lists.openembedded.org Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-