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]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to