0103-Check-destination-of-DNS-UDP-query-replies.patch 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. From 257ac0c5f7732cbc6aa96fdd3b06602234593aca Mon Sep 17 00:00:00 2001
  2. From: Simon Kelley <simon@thekelleys.org.uk>
  3. Date: Thu, 12 Nov 2020 18:49:23 +0000
  4. Subject: Check destination of DNS UDP query replies.
  5. At any time, dnsmasq will have a set of sockets open, bound to
  6. random ports, on which it sends queries to upstream nameservers.
  7. This patch fixes the existing problem that a reply for ANY in-flight
  8. query would be accepted via ANY open port, which increases the
  9. chances of an attacker flooding answers "in the blind" in an
  10. attempt to poison the DNS cache. CERT VU#434904 refers.
  11. ---
  12. CHANGELOG | 6 +++++-
  13. src/forward.c | 37 ++++++++++++++++++++++++++++---------
  14. 2 files changed, 33 insertions(+), 10 deletions(-)
  15. --- a/CHANGELOG
  16. +++ b/CHANGELOG
  17. @@ -2,8 +2,12 @@
  18. dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
  19. referenced by CERT VU#434904.
  20. + Be sure to only accept UDP DNS query replies at the address
  21. + from which the query was originated. This keeps as much entropy
  22. + in the {query-ID, random-port} tuple as possible, help defeat
  23. + cache poisoning attacks. Refer: CERT VU#434904.
  24. +
  25. ->>>>>>> Fix remote buffer overflow CERT VU#434904
  26. version 2.81
  27. Impove cache behaviour for TCP connections. For ease of
  28. implementaion, dnsmasq has always forked a new process to handle
  29. --- a/src/forward.c
  30. +++ b/src/forward.c
  31. @@ -16,7 +16,7 @@
  32. #include "dnsmasq.h"
  33. -static struct frec *lookup_frec(unsigned short id, void *hash);
  34. +static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
  35. static struct frec *lookup_frec_by_sender(unsigned short id,
  36. union mysockaddr *addr,
  37. void *hash);
  38. @@ -797,7 +797,7 @@ void reply_query(int fd, int family, tim
  39. crc = questions_crc(header, n, daemon->namebuff);
  40. #endif
  41. - if (!(forward = lookup_frec(ntohs(header->id), hash)))
  42. + if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
  43. return;
  44. #ifdef HAVE_DUMPFILE
  45. @@ -2289,14 +2289,25 @@ struct frec *get_new_frec(time_t now, in
  46. }
  47. /* crc is all-ones if not known. */
  48. -static struct frec *lookup_frec(unsigned short id, void *hash)
  49. +static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
  50. {
  51. struct frec *f;
  52. for(f = daemon->frec_list; f; f = f->next)
  53. if (f->sentto && f->new_id == id &&
  54. (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
  55. - return f;
  56. + {
  57. + /* sent from random port */
  58. + if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
  59. + return f;
  60. +
  61. + if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
  62. + return f;
  63. +
  64. + /* sent to upstream from bound socket. */
  65. + if (f->sentto->sfd && f->sentto->sfd->fd == fd)
  66. + return f;
  67. + }
  68. return NULL;
  69. }
  70. @@ -2357,12 +2368,20 @@ void server_gone(struct server *server)
  71. static unsigned short get_id(void)
  72. {
  73. unsigned short ret = 0;
  74. + struct frec *f;
  75. - do
  76. - ret = rand16();
  77. - while (lookup_frec(ret, NULL));
  78. -
  79. - return ret;
  80. + while (1)
  81. + {
  82. + ret = rand16();
  83. +
  84. + /* ensure id is unique. */
  85. + for (f = daemon->frec_list; f; f = f->next)
  86. + if (f->sentto && f->new_id == ret)
  87. + break;
  88. +
  89. + if (!f)
  90. + return ret;
  91. + }
  92. }