openwrt/package/network/services/dnsmasq/patches/0103-Check-destination-of-DNS-UDP-query-replies.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

107 lines
3.1 KiB
Diff

From 257ac0c5f7732cbc6aa96fdd3b06602234593aca Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Thu, 12 Nov 2020 18:49:23 +0000
Subject: 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.
---
CHANGELOG | 6 +++++-
src/forward.c | 37 ++++++++++++++++++++++++++++---------
2 files changed, 33 insertions(+), 10 deletions(-)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,8 +2,12 @@
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
referenced by CERT VU#434904.
+ Be sure to only accept UDP DNS query replies at the address
+ from which the query was originated. This keeps as much entropy
+ in the {query-ID, random-port} tuple as possible, help defeat
+ cache poisoning attacks. Refer: CERT VU#434904.
+
->>>>>>> Fix remote buffer overflow CERT VU#434904
version 2.81
Impove cache behaviour for TCP connections. For ease of
implementaion, dnsmasq has always forked a new process to handle
--- 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);
@@ -797,7 +797,7 @@ void reply_query(int fd, int family, tim
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
@@ -2289,14 +2289,25 @@ struct frec *get_new_frec(time_t now, in
}
/* 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;
}
@@ -2357,12 +2368,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;
+ }
}