From 4a1d1cdf2bf53dedfdb25ae1a045dfbcfda77c85 Mon Sep 17 00:00:00 2001 From: Sona Sarmadi Date: Wed, 4 Oct 2017 12:34:25 +0200 Subject: dnsmasq: CVE-2017-14491 Heap based overflow (2 bytes). Before 2.76 and this commit overflow was unrestricted. References: https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-14491 https://security.googleblog.com/2017/10/behind-masq-yet-more-dns-and-dhcp.html Signed-off-by: Sona Sarmadi Signed-off-by: Adrian Dudau --- .../dnsmasq/dnsmasq/0001-CVE-2017-14491.patch | 269 +++++++++++++++++++++ .../dnsmasq/dnsmasq/0002-CVE-2017-14491.patch | 73 ++++++ recipes-networking/dnsmasq/dnsmasq_%.bbappend | 6 + 3 files changed, 348 insertions(+) create mode 100644 recipes-networking/dnsmasq/dnsmasq/0001-CVE-2017-14491.patch create mode 100644 recipes-networking/dnsmasq/dnsmasq/0002-CVE-2017-14491.patch create mode 100644 recipes-networking/dnsmasq/dnsmasq_%.bbappend diff --git a/recipes-networking/dnsmasq/dnsmasq/0001-CVE-2017-14491.patch b/recipes-networking/dnsmasq/dnsmasq/0001-CVE-2017-14491.patch new file mode 100644 index 0000000..1eda591 --- /dev/null +++ b/recipes-networking/dnsmasq/dnsmasq/0001-CVE-2017-14491.patch @@ -0,0 +1,269 @@ +From 0549c73b7ea6b22a3c49beb4d432f185a81efcbc Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 18:17:11 +0100 +Subject: [PATCH] Security fix, CVE-2017-14491 DNS heap buffer overflow. + +Fix heap overflow in DNS code. This is a potentially serious +security hole. It allows an attacker who can make DNS +requests to dnsmasq, and who controls the contents of +a domain, which is thereby queried, to overflow +(by 2 bytes) a heap buffer and either crash, or +even take control of, dnsmasq. + +CVE: CVE-2017-14491 +Upstream-Status: Backport [src/dnsmasq.h patch failed, modified manually] + +Signed-off-by: Sona Sarmadi + +diff -Nurp a/CHANGELOG b/CHANGELOG +--- a/CHANGELOG 2016-05-18 16:51:54.000000000 +0200 ++++ b/CHANGELOG 2017-10-04 09:38:20.445498463 +0200 +@@ -123,6 +123,18 @@ version 2.75 + dhcp-script is configured. Thanks to Adrian Davey for + reporting the bug and testing the fix. + ++ Fix heap overflow in DNS code. This is a potentially serious ++ security hole. It allows an attacker who can make DNS ++ requests to dnsmasq, and who controls the contents of ++ a domain, which is thereby queried, to overflow ++ (by 2 bytes) a heap buffer and either crash, or ++ even take control of, dnsmasq. ++ CVE-2017-14491 applies. ++ Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana ++ and Kevin Hamacher of the Google Security Team for ++ finding this. ++ ++ + + version 2.74 + Fix reversion in 2.73 where --conf-file would attempt to +diff -Nurp a/src/dnsmasq.h b/src/dnsmasq.h +--- a/src/dnsmasq.h 2016-05-18 16:51:54.000000000 +0200 ++++ b/src/dnsmasq.h 2017-10-04 09:39:39.366156718 +0200 +@@ -1161,7 +1161,7 @@ u32 rand32(void); + u64 rand64(void); + int legal_hostname(char *c); + char *canonicalise(char *s, int *nomem); +-unsigned char *do_rfc1035_name(unsigned char *p, char *sval); ++unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit); + void *safe_malloc(size_t size); + void safe_pipe(int *fd, int read_noblock); + void *whine_malloc(size_t size); +diff -Nurp a/src/dnssec.c b/src/dnssec.c +--- a/src/dnssec.c 2016-05-18 16:51:54.000000000 +0200 ++++ b/src/dnssec.c 2017-10-04 09:38:20.445498463 +0200 +@@ -2227,7 +2227,7 @@ size_t dnssec_generate_query(struct dns_ + + p = (unsigned char *)(header+1); + +- p = do_rfc1035_name(p, name); ++ p = do_rfc1035_name(p, name, NULL); + *p++ = 0; + PUTSHORT(type, p); + PUTSHORT(class, p); +diff -Nurp a/src/option.c b/src/option.c +--- a/src/option.c 2016-05-18 16:51:54.000000000 +0200 ++++ b/src/option.c 2017-10-04 09:38:20.449498294 +0200 +@@ -1378,7 +1378,7 @@ static int parse_dhcp_opt(char *errstr, + } + + p = newp; +- end = do_rfc1035_name(p + len, dom); ++ end = do_rfc1035_name(p + len, dom, NULL); + *end++ = 0; + len = end - p; + free(dom); +diff -Nurp a/src/rfc1035.c b/src/rfc1035.c +--- a/src/rfc1035.c 2016-05-18 16:51:54.000000000 +0200 ++++ b/src/rfc1035.c 2017-10-04 09:38:20.449498294 +0200 +@@ -1049,6 +1049,7 @@ int check_for_ignored_address(struct dns + return 0; + } + ++ + int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp, + unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...) + { +@@ -1058,12 +1059,21 @@ int add_resource_record(struct dns_heade + unsigned short usval; + long lval; + char *sval; ++#define CHECK_LIMIT(size) \ ++ if (limit && p + (size) > (unsigned char*)limit) \ ++ { \ ++ va_end(ap); \ ++ goto truncated; \ ++ } + + if (truncp && *truncp) + return 0; +- ++ + va_start(ap, format); /* make ap point to 1st unamed argument */ +- ++ ++ /* nameoffset (1 or 2) + type (2) + class (2) + ttl (4) + 0 (2) */ ++ CHECK_LIMIT(12); ++ + if (nameoffset > 0) + { + PUTSHORT(nameoffset | 0xc000, p); +@@ -1072,7 +1082,13 @@ int add_resource_record(struct dns_heade + { + char *name = va_arg(ap, char *); + if (name) +- p = do_rfc1035_name(p, name); ++ p = do_rfc1035_name(p, name, limit); ++ if (!p) ++ { ++ va_end(ap); ++ goto truncated; ++ } ++ + if (nameoffset < 0) + { + PUTSHORT(-nameoffset | 0xc000, p); +@@ -1093,6 +1109,7 @@ int add_resource_record(struct dns_heade + { + #ifdef HAVE_IPV6 + case '6': ++ CHECK_LIMIT(IN6ADDRSZ); + sval = va_arg(ap, char *); + memcpy(p, sval, IN6ADDRSZ); + p += IN6ADDRSZ; +@@ -1100,36 +1117,47 @@ int add_resource_record(struct dns_heade + #endif + + case '4': ++ CHECK_LIMIT(INADDRSZ); + sval = va_arg(ap, char *); + memcpy(p, sval, INADDRSZ); + p += INADDRSZ; + break; + + case 'b': ++ CHECK_LIMIT(1); + usval = va_arg(ap, int); + *p++ = usval; + break; + + case 's': ++ CHECK_LIMIT(2); + usval = va_arg(ap, int); + PUTSHORT(usval, p); + break; + + case 'l': ++ CHECK_LIMIT(4); + lval = va_arg(ap, long); + PUTLONG(lval, p); + break; + + case 'd': +- /* get domain-name answer arg and store it in RDATA field */ +- if (offset) +- *offset = p - (unsigned char *)header; +- p = do_rfc1035_name(p, va_arg(ap, char *)); +- *p++ = 0; ++ /* get domain-name answer arg and store it in RDATA field */ ++ if (offset) ++ *offset = p - (unsigned char *)header; ++ p = do_rfc1035_name(p, va_arg(ap, char *), limit); ++ if (!p) ++ { ++ va_end(ap); ++ goto truncated; ++ } ++ CHECK_LIMIT(1); ++ *p++ = 0; + break; + + case 't': + usval = va_arg(ap, int); ++ CHECK_LIMIT(usval); + sval = va_arg(ap, char *); + if (usval != 0) + memcpy(p, sval, usval); +@@ -1141,20 +1169,24 @@ int add_resource_record(struct dns_heade + usval = sval ? strlen(sval) : 0; + if (usval > 255) + usval = 255; ++ CHECK_LIMIT(usval + 1); + *p++ = (unsigned char)usval; + memcpy(p, sval, usval); + p += usval; + break; + } + ++#undef CHECK_LIMIT + va_end(ap); /* clean up variable argument pointer */ + + j = p - sav - 2; +- PUTSHORT(j, sav); /* Now, store real RDLength */ ++ /* this has already been checked against limit before */ ++ PUTSHORT(j, sav); /* Now, store real RDLength */ + + /* check for overflow of buffer */ + if (limit && ((unsigned char *)limit - p) < 0) + { ++truncated: + if (truncp) + *truncp = 1; + return 0; +diff -Nurp a/src/rfc2131.c b/src/rfc2131.c +--- a/src/rfc2131.c 2016-05-18 16:51:54.000000000 +0200 ++++ b/src/rfc2131.c 2017-10-04 09:38:20.449498294 +0200 +@@ -2419,10 +2419,10 @@ static void do_options(struct dhcp_conte + + if (fqdn_flags & 0x04) + { +- p = do_rfc1035_name(p, hostname); ++ p = do_rfc1035_name(p, hostname, NULL); + if (domain) + { +- p = do_rfc1035_name(p, domain); ++ p = do_rfc1035_name(p, domain, NULL); + *p++ = 0; + } + } +diff -Nurp a/src/rfc3315.c b/src/rfc3315.c +--- a/src/rfc3315.c 2016-05-18 16:51:54.000000000 +0200 ++++ b/src/rfc3315.c 2017-10-04 09:38:20.449498294 +0200 +@@ -1472,10 +1472,10 @@ static struct dhcp_netid *add_options(st + if ((p = expand(len + 2))) + { + *(p++) = state->fqdn_flags; +- p = do_rfc1035_name(p, state->hostname); ++ p = do_rfc1035_name(p, state->hostname, NULL); + if (state->send_domain) + { +- p = do_rfc1035_name(p, state->send_domain); ++ p = do_rfc1035_name(p, state->send_domain, NULL); + *p = 0; + } + } +diff -Nurp a/src/util.c b/src/util.c +--- a/src/util.c 2016-05-18 16:51:54.000000000 +0200 ++++ b/src/util.c 2017-10-04 09:38:20.453498124 +0200 +@@ -218,15 +218,20 @@ char *canonicalise(char *in, int *nomem) + return ret; + } + +-unsigned char *do_rfc1035_name(unsigned char *p, char *sval) ++unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit) + { + int j; + + while (sval && *sval) + { ++ if (limit && p + 1 > (unsigned char*)limit) ++ return p; ++ + unsigned char *cp = p++; + for (j = 0; *sval && (*sval != '.'); sval++, j++) + { ++ if (limit && p + 1 > (unsigned char*)limit) ++ return p; + #ifdef HAVE_DNSSEC + if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE) + *p++ = (*(++sval))-1; diff --git a/recipes-networking/dnsmasq/dnsmasq/0002-CVE-2017-14491.patch b/recipes-networking/dnsmasq/dnsmasq/0002-CVE-2017-14491.patch new file mode 100644 index 0000000..6f27667 --- /dev/null +++ b/recipes-networking/dnsmasq/dnsmasq/0002-CVE-2017-14491.patch @@ -0,0 +1,73 @@ +From 62cb936cb7ad5f219715515ae7d32dd281a5aa1f Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Tue, 26 Sep 2017 22:00:11 +0100 +Subject: [PATCH] Security fix, CVE-2017-14491, DNS heap buffer overflow. + +Further fix to 0549c73b7ea6b22a3c49beb4d432f185a81efcbc +Handles case when RR name is not a pointer to the question, +only occurs for some auth-mode replies, therefore not +detected by fuzzing (?) + +CVE: CVE-2017-14491 +Upstream-Status: Backport + +Signed-off-by: Sona Sarmadi +--- + src/rfc1035.c | 27 +++++++++++++++------------ + 1 file changed, 15 insertions(+), 12 deletions(-) + +diff --git a/src/rfc1035.c b/src/rfc1035.c +index 27af023..56ab88b 100644 +--- a/src/rfc1035.c ++++ b/src/rfc1035.c +@@ -1086,32 +1086,35 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int + + va_start(ap, format); /* make ap point to 1st unamed argument */ + +- /* nameoffset (1 or 2) + type (2) + class (2) + ttl (4) + 0 (2) */ +- CHECK_LIMIT(12); +- + if (nameoffset > 0) + { ++ CHECK_LIMIT(2); + PUTSHORT(nameoffset | 0xc000, p); + } + else + { + char *name = va_arg(ap, char *); +- if (name) +- p = do_rfc1035_name(p, name, limit); +- if (!p) +- { +- va_end(ap); +- goto truncated; +- } +- ++ if (name && !(p = do_rfc1035_name(p, name, limit))) ++ { ++ va_end(ap); ++ goto truncated; ++ } ++ + if (nameoffset < 0) + { ++ CHECK_LIMIT(2); + PUTSHORT(-nameoffset | 0xc000, p); + } + else +- *p++ = 0; ++ { ++ CHECK_LIMIT(1); ++ *p++ = 0; ++ } + } + ++ /* type (2) + class (2) + ttl (4) + rdlen (2) */ ++ CHECK_LIMIT(10); ++ + PUTSHORT(type, p); + PUTSHORT(class, p); + PUTLONG(ttl, p); /* TTL */ +-- +1.7.10.4 + diff --git a/recipes-networking/dnsmasq/dnsmasq_%.bbappend b/recipes-networking/dnsmasq/dnsmasq_%.bbappend new file mode 100644 index 0000000..e228035 --- /dev/null +++ b/recipes-networking/dnsmasq/dnsmasq_%.bbappend @@ -0,0 +1,6 @@ +# look for files in the layer first +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-CVE-2017-14491.patch \ + file://0002-CVE-2017-14491.patch \ +" -- cgit v1.2.3-54-g00ecf