Blame SOURCES/dnsmasq-2.79-CVE-2020-25684.patch

bc86c2
From 04ef96f428beebd07b457b51b5d2f26d3099f1a5 Mon Sep 17 00:00:00 2001
bc86c2
From: Simon Kelley <simon@thekelleys.org.uk>
bc86c2
Date: Thu, 12 Nov 2020 18:49:23 +0000
bc86c2
Subject: [PATCH 2/4] Check destination of DNS UDP query replies.
bc86c2
bc86c2
At any time, dnsmasq will have a set of sockets open, bound to
bc86c2
random ports, on which it sends queries to upstream nameservers.
bc86c2
This patch fixes the existing problem that a reply for ANY in-flight
bc86c2
query would be accepted via ANY open port, which increases the
bc86c2
chances of an attacker flooding answers "in the blind" in an
bc86c2
attempt to poison the DNS cache. CERT VU#434904 refers.
bc86c2
---
bc86c2
 src/forward.c | 37 ++++++++++++++++++++++++++++---------
bc86c2
 1 file changed, 28 insertions(+), 9 deletions(-)
bc86c2
bc86c2
diff --git a/src/forward.c b/src/forward.c
bc86c2
index cdd11d3..85eab27 100644
bc86c2
--- a/src/forward.c
bc86c2
+++ b/src/forward.c
bc86c2
@@ -16,7 +16,7 @@
bc86c2
 
bc86c2
 #include "dnsmasq.h"
bc86c2
 
bc86c2
-static struct frec *lookup_frec(unsigned short id, void *hash);
bc86c2
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
bc86c2
 static struct frec *lookup_frec_by_sender(unsigned short id,
bc86c2
 					  union mysockaddr *addr,
bc86c2
 					  void *hash);
bc86c2
@@ -780,7 +780,7 @@ void reply_query(int fd, int family, time_t now)
bc86c2
   crc = questions_crc(header, n, daemon->namebuff);
bc86c2
 #endif
bc86c2
   
bc86c2
-  if (!(forward = lookup_frec(ntohs(header->id), hash)))
bc86c2
+  if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
bc86c2
     return;
bc86c2
   
bc86c2
   /* log_query gets called indirectly all over the place, so 
bc86c2
@@ -2195,14 +2195,25 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
bc86c2
 }
bc86c2
 
bc86c2
 /* crc is all-ones if not known. */
bc86c2
-static struct frec *lookup_frec(unsigned short id, void *hash)
bc86c2
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
bc86c2
 {
bc86c2
   struct frec *f;
bc86c2
 
bc86c2
   for(f = daemon->frec_list; f; f = f->next)
bc86c2
     if (f->sentto && f->new_id == id && 
bc86c2
 	(!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
bc86c2
-      return f;
bc86c2
+      {
bc86c2
+	/* sent from random port */
bc86c2
+	if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
bc86c2
+	  return f;
bc86c2
+
bc86c2
+	if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
bc86c2
+	  return f;
bc86c2
+
bc86c2
+	/* sent to upstream from bound socket. */
bc86c2
+	if (f->sentto->sfd && f->sentto->sfd->fd == fd)
bc86c2
+	  return f;
bc86c2
+      }
bc86c2
       
bc86c2
   return NULL;
bc86c2
 }
bc86c2
@@ -2263,12 +2274,20 @@ void server_gone(struct server *server)
bc86c2
 static unsigned short get_id(void)
bc86c2
 {
bc86c2
   unsigned short ret = 0;
bc86c2
+  struct frec *f;
bc86c2
   
bc86c2
-  do 
bc86c2
-    ret = rand16();
bc86c2
-  while (lookup_frec(ret, NULL));
bc86c2
-  
bc86c2
-  return ret;
bc86c2
+  while (1)
bc86c2
+    {
bc86c2
+      ret = rand16();
bc86c2
+
bc86c2
+      /* ensure id is unique. */
bc86c2
+      for (f = daemon->frec_list; f; f = f->next)
bc86c2
+	if (f->sentto && f->new_id == ret)
bc86c2
+	  break;
bc86c2
+
bc86c2
+      if (!f)
bc86c2
+	return ret;
bc86c2
+    }
bc86c2
 }
bc86c2
 
bc86c2
 
bc86c2
-- 
bc86c2
2.26.2
bc86c2