openwrt/package/network/services/dnsmasq/patches/0105-Optimse-RR-digest-calculation-in-DNSSEC.patch
Hauke Mehrtens 8055e38794 dnsmasq: Backport some security updates
This fixes the following security problems in dnsmasq:
* CVE-2020-25681:
  Dnsmasq versions before 2.83 is susceptible to a heap-based buffer
  overflow in sort_rrset() when DNSSEC is used. This can allow a remote
  attacker to write arbitrary data into target device's memory that can
  lead to memory corruption and other unexpected behaviors on the target
  device.
* CVE-2020-25682:
  Dnsmasq versions before 2.83 is susceptible to buffer overflow in
  extract_name() function due to missing length check, when DNSSEC is
  enabled. This can allow a remote attacker to cause memory corruption
  on the target device.
* CVE-2020-25683:
  Dnsmasq version before 2.83 is susceptible to a heap-based buffer
  overflow when DNSSEC is enabled. A remote attacker, who can create
  valid DNS replies, could use this flaw to cause an overflow in a heap-
  allocated memory. This flaw is caused by the lack of length checks in
  rtc1035.c:extract_name(), which could be abused to make the code
  execute memcpy() with a negative size in get_rdata() and cause a crash
  in Dnsmasq, resulting in a Denial of Service.
* CVE-2020-25684:
  A lack of proper address/port check implemented in Dnsmasq version <
  2.83 reply_query function makes forging replies easier to an off-path
  attacker.
* CVE-2020-25685:
  A lack of query resource name (RRNAME) checks implemented in Dnsmasq's
  versions before 2.83 reply_query function allows remote attackers to
  spoof DNS traffic that can lead to DNS cache poisoning.
* CVE-2020-25686:
  Multiple DNS query requests for the same resource name (RRNAME) by
  Dnsmasq versions before 2.83 allows for remote attackers to spoof DNS
  traffic, using a birthday attack (RFC 5452), that can lead to DNS
  cache poisoning.
* CVE-2020-25687:
  Dnsmasq versions before 2.83 is vulnerable to a heap-based buffer
  overflow with large memcpy in sort_rrset() when DNSSEC is enabled. A
  remote attacker, who can create valid DNS replies, could use this flaw
  to cause an overflow in a heap-allocated memory. This flaw is caused
  by the lack of length checks in rtc1035.c:extract_name(), which could
  be abused to make the code execute memcpy() with a negative size in
  sort_rrset() and cause a crash in dnsmasq, resulting in a Denial of
  Service.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
2021-01-19 14:10:02 +01:00

123 lines
3.7 KiB
Diff

From 059aded0700309308dafd9720b0313ce52f6e189 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Thu, 12 Nov 2020 23:09:15 +0000
Subject: Optimse RR digest calculation in DNSSEC.
If an RR is of a type which doesn't need canonicalisation,
bypass the relatively slow canonicalisation code, and insert
it direct into the digest.
---
src/dnssec.c | 82 +++++++++++++++++++++++++++++++---------------------
1 file changed, 49 insertions(+), 33 deletions(-)
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -559,7 +559,7 @@ static int validate_rrset(time_t now, st
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
from_wire(keyname);
-#define RRBUFLEN 300 /* Most RRs are smaller than this. */
+#define RRBUFLEN 128 /* Most RRs are smaller than this. */
for (i = 0; i < rrsetidx; ++i)
{
@@ -597,50 +597,66 @@ static int validate_rrset(time_t now, st
hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
hash->update(ctx, 4, p); /* class and type */
hash->update(ctx, 4, (unsigned char *)&nsigttl);
-
- p += 8; /* skip class, type, ttl */
+
+ p += 8; /* skip type, class, ttl */
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return STAT_BOGUS;
-
- /* 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;
-
- 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)
+ /* Optimisation for RR types which need no cannonicalisation.
+ This includes DNSKEY DS NSEC and NSEC3, which are also long, so
+ it saves lots of calls to get_rdata, and avoids the pessimal
+ segmented insertion, even with a small rrbuf[].
+
+ If canonicalisation is not needed, a simple insertion into the hash works.
+ */
+ if (*rr_desc == (u16)-1)
+ {
+ len = htons(rdlen);
+ hash->update(ctx, 2, (unsigned char *)&len);
+ hash->update(ctx, rdlen, p);
+ }
+ else
{
+ /* 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;
+
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)
{
- rrbuf[j] = *state.op;
-
- if (j == RRBUFLEN - 1)
- {
- hash->update(ctx, RRBUFLEN, rrbuf);
- j = -1;
- }
+ 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;
+ }
+ }
}
+
+ if (j != 0)
+ hash->update(ctx, j, rrbuf);
}
-
- if (j != 0)
- hash->update(ctx, j, rrbuf);
}
hash->digest(ctx, hash->digest_size, digest);