From 5e3f5af7fd64031b38bc1f8fd818a950df6d1307 Mon Sep 17 00:00:00 2001 From: basebuilder_pel7ppc64bebuilder0 Date: Wed, 9 May 2018 14:17:06 +0200 Subject: [PATCH] dnsmasq update to version 2.76-5 Signed-off-by: basebuilder_pel7ppc64bebuilder0 --- SOURCES/dnsmasq-2.76-CVE-2017-14491.patch | 262 ++++++++++ SOURCES/dnsmasq-2.76-CVE-2017-14492.patch | 31 ++ SOURCES/dnsmasq-2.76-CVE-2017-14493.patch | 30 ++ SOURCES/dnsmasq-2.76-CVE-2017-14494.patch | 30 ++ SOURCES/dnsmasq-2.76-CVE-2017-14495.patch | 41 ++ SOURCES/dnsmasq-2.76-CVE-2017-14496.patch | 66 +++ SOURCES/dnsmasq-2.76-dhcp-script-log.patch | 582 +++++++++++++++++++++ SOURCES/dnsmasq-2.76-file_offset32.patch | 12 + SOURCES/dnsmasq-2.76-gita3303e196.patch | 45 ++ SOURCES/dnsmasq-2.76-misc-cleanups.patch | 63 +++ SOURCES/dnsmasq-2.76-underflow.patch | 74 +++ SPECS/dnsmasq.spec | 45 +- 12 files changed, 1280 insertions(+), 1 deletion(-) create mode 100644 SOURCES/dnsmasq-2.76-CVE-2017-14491.patch create mode 100644 SOURCES/dnsmasq-2.76-CVE-2017-14492.patch create mode 100644 SOURCES/dnsmasq-2.76-CVE-2017-14493.patch create mode 100644 SOURCES/dnsmasq-2.76-CVE-2017-14494.patch create mode 100644 SOURCES/dnsmasq-2.76-CVE-2017-14495.patch create mode 100644 SOURCES/dnsmasq-2.76-CVE-2017-14496.patch create mode 100644 SOURCES/dnsmasq-2.76-dhcp-script-log.patch create mode 100644 SOURCES/dnsmasq-2.76-file_offset32.patch create mode 100644 SOURCES/dnsmasq-2.76-gita3303e196.patch create mode 100644 SOURCES/dnsmasq-2.76-misc-cleanups.patch create mode 100644 SOURCES/dnsmasq-2.76-underflow.patch diff --git a/SOURCES/dnsmasq-2.76-CVE-2017-14491.patch b/SOURCES/dnsmasq-2.76-CVE-2017-14491.patch new file mode 100644 index 00000000..4d8dbd54 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-CVE-2017-14491.patch @@ -0,0 +1,262 @@ +From 8868a04895b27d42d42e364f1a0c0196c1505b04 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 18:17:11 +0100 +Subject: [PATCH 1/9] 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. +--- + src/dnsmasq.h | 2 +- + src/dnssec.c | 2 +- + src/option.c | 2 +- + src/rfc1035.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- + src/rfc2131.c | 4 ++-- + src/rfc3315.c | 4 ++-- + src/util.c | 7 ++++++- + 7 files changed, 54 insertions(+), 17 deletions(-) + +diff --git a/src/dnsmasq.h b/src/dnsmasq.h +index 1179492..06e5579 100644 +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -1162,7 +1162,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 --git a/src/dnssec.c b/src/dnssec.c +index 3c77c7d..f45c804 100644 +--- a/src/dnssec.c ++++ b/src/dnssec.c +@@ -2227,7 +2227,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char + + 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 --git a/src/option.c b/src/option.c +index eb78b1a..3469f53 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -1378,7 +1378,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags) + } + + 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 --git a/src/rfc1035.c b/src/rfc1035.c +index 24d08c1..78410d6 100644 +--- a/src/rfc1035.c ++++ b/src/rfc1035.c +@@ -1049,6 +1049,7 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog + 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_header *header, char *limit, int *truncp, int + 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_header *header, char *limit, int *truncp, int + { + 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_header *header, char *limit, int *truncp, int + { + #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_header *header, char *limit, int *truncp, int + #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_header *header, char *limit, int *truncp, int + 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 --git a/src/rfc2131.c b/src/rfc2131.c +index 8b99d4b..75893a6 100644 +--- a/src/rfc2131.c ++++ b/src/rfc2131.c +@@ -2420,10 +2420,10 @@ static void do_options(struct dhcp_context *context, + + 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 --git a/src/rfc3315.c b/src/rfc3315.c +index 3f4d69c..73bdee4 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -1472,10 +1472,10 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh) + 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 --git a/src/util.c b/src/util.c +index 1a9f228..be9f8a6 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -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; +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-CVE-2017-14492.patch b/SOURCES/dnsmasq-2.76-CVE-2017-14492.patch new file mode 100644 index 00000000..b3811488 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-CVE-2017-14492.patch @@ -0,0 +1,31 @@ +From c14b8b511ac55f6933aebefbd6cc27c1ec74ad58 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 18:47:15 +0100 +Subject: [PATCH 2/9] Security fix, CVE-2017-14492, DHCPv6 RA heap + overflow. + + Fix heap overflow in IPv6 router advertisement code. + This is a potentially serious security hole, as a + crafted RA request can overflow a buffer and crash or + control dnsmasq. Attacker must be on the local network. +--- + src/radv.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/radv.c b/src/radv.c +index 749b666..d09fe0e 100644 +--- a/src/radv.c ++++ b/src/radv.c +@@ -198,6 +198,9 @@ void icmp6_packet(time_t now) + /* look for link-layer address option for logging */ + if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz) + { ++ if ((packet[9] * 8 - 2) * 3 - 1 >= MAXDNAME) { ++ return; ++ } + print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2); + mac = daemon->namebuff; + } +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-CVE-2017-14493.patch b/SOURCES/dnsmasq-2.76-CVE-2017-14493.patch new file mode 100644 index 00000000..56348036 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-CVE-2017-14493.patch @@ -0,0 +1,30 @@ +From 5086b12a4b1269d1576b5bab01f72c6fa19c55bc Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 18:52:50 +0100 +Subject: [PATCH 3/9] Security fix, CVE-2017-14493, DHCPv6 - Stack buffer + overflow. + + Fix stack overflow in DHCPv6 code. An attacker who can send + a DHCPv6 request to dnsmasq can overflow the stack frame and + crash or control dnsmasq. +--- + src/rfc3315.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/rfc3315.c b/src/rfc3315.c +index 73bdee4..8d18a28 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -206,6 +206,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, + /* RFC-6939 */ + if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3))) + { ++ if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) { ++ return 0; ++ } + state->mac_type = opt6_uint(opt, 0, 2); + state->mac_len = opt6_len(opt) - 2; + memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len); +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-CVE-2017-14494.patch b/SOURCES/dnsmasq-2.76-CVE-2017-14494.patch new file mode 100644 index 00000000..3743a32f --- /dev/null +++ b/SOURCES/dnsmasq-2.76-CVE-2017-14494.patch @@ -0,0 +1,30 @@ +From 8c8fe650dc17aad0fbafc920fde719218dc4568d Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 20:05:11 +0100 +Subject: [PATCH 4/9] Security fix, CVE-2017-14494, Infoleak handling + DHCPv6 forwarded requests. + + Fix information leak in DHCPv6. A crafted DHCPv6 packet can + cause dnsmasq to forward memory from outside the packet + buffer to a DHCPv6 server when acting as a relay. +--- + src/rfc3315.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/rfc3315.c b/src/rfc3315.c +index 8d18a28..03b3f84 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -216,6 +216,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, + + for (opt = opts; opt; opt = opt6_next(opt, end)) + { ++ if (opt6_ptr(opt, 0) + opt6_len(opt) >= end) { ++ return 0; ++ } + int o = new_opt6(opt6_type(opt)); + if (opt6_type(opt) == OPTION6_RELAY_MSG) + { +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-CVE-2017-14495.patch b/SOURCES/dnsmasq-2.76-CVE-2017-14495.patch new file mode 100644 index 00000000..8ca5d0f3 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-CVE-2017-14495.patch @@ -0,0 +1,41 @@ +From f2ad2cecb55825f7e4409222de1688b9ceebceda Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 20:16:50 +0100 +Subject: [PATCH 6/9] Security fix, CVE-2017-14495, OOM in DNS response + creation. + + Fix out-of-memory Dos vulnerability. An attacker which can + send malicious DNS queries to dnsmasq can trigger memory + allocations in the add_pseudoheader function + The allocated memory is never freed which leads to a DoS + through memory exhaustion. dnsmasq is vulnerable only + if one of the following option is specified: + --add-mac, --add-cpe-id or --add-subnet. +--- + src/edns0.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/edns0.c b/src/edns0.c +index eed135e..5bdc133 100644 +--- a/src/edns0.c ++++ b/src/edns0.c +@@ -192,9 +192,15 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + !(p = skip_section(p, + ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), + header, plen))) ++ { ++ free(buff); + return plen; ++ } + if (p + 11 > limit) +- return plen; /* Too big */ ++ { ++ free(buff); ++ return plen; /* Too big */ ++ } + *p++ = 0; /* empty name */ + PUTSHORT(T_OPT, p); + PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */ +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-CVE-2017-14496.patch b/SOURCES/dnsmasq-2.76-CVE-2017-14496.patch new file mode 100644 index 00000000..f32b9196 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-CVE-2017-14496.patch @@ -0,0 +1,66 @@ +From 5ab67e936085a9e584c9b3e43f442ef5bee7f40e Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 20:11:58 +0100 +Subject: [PATCH 5/9] Security fix, CVE-2017-14496, Integer underflow in + DNS response creation. + + Fix DoS in DNS. Invalid boundary checks in the + add_pseudoheader function allows a memcpy call with negative + size An attacker which can send malicious DNS queries + to dnsmasq can trigger a DoS remotely. + dnsmasq is vulnerable only if one of the following option is + specified: --add-mac, --add-cpe-id or --add-subnet. +--- + src/edns0.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/src/edns0.c b/src/edns0.c +index d2b514b..eed135e 100644 +--- a/src/edns0.c ++++ b/src/edns0.c +@@ -144,7 +144,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + GETSHORT(len, p); + + /* malformed option, delete the whole OPT RR and start again. */ +- if (i + len > rdlen) ++ if (i + 4 + len > rdlen) + { + rdlen = 0; + is_last = 0; +@@ -193,6 +193,8 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), + header, plen))) + return plen; ++ if (p + 11 > limit) ++ return plen; /* Too big */ + *p++ = 0; /* empty name */ + PUTSHORT(T_OPT, p); + PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */ +@@ -204,6 +206,11 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + /* Copy back any options */ + if (buff) + { ++ if (p + rdlen > limit) ++ { ++ free(buff); ++ return plen; /* Too big */ ++ } + memcpy(p, buff, rdlen); + free(buff); + p += rdlen; +@@ -217,8 +224,12 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + /* Add new option */ + if (optno != 0 && replace != 2) + { ++ if (p + 4 > limit) ++ return plen; /* Too big */ + PUTSHORT(optno, p); + PUTSHORT(optlen, p); ++ if (p + optlen > limit) ++ return plen; /* Too big */ + memcpy(p, opt, optlen); + p += optlen; + PUTSHORT(p - datap, lenp); +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-dhcp-script-log.patch b/SOURCES/dnsmasq-2.76-dhcp-script-log.patch new file mode 100644 index 00000000..ac262589 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-dhcp-script-log.patch @@ -0,0 +1,582 @@ +From 87444dc6977b61096127dcdfe87dc6cf2c0167d6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Sun, 16 Apr 2017 20:20:08 +0100 +Subject: [PATCH] Capture and log STDOUT and STDERR output from dhcp-script. + +(cherry picked from commit c77fb9d8f09d136fa71bde2469c4fd11cefa6f4a) + +Compile-time check on buffer sizes for leasefile parsing code. + +(cherry picked from commit bf4e62c19e619f7edf8d03d58d33a5752f190bfd) + +Improve error handling with shcp-script "init" mode. + +(cherry picked from commit 3a8b0f6fccf464b1ec6d24c0e00e540ab2b17705) + +Tweak logging introduced in 3a8b0f6fccf464b1ec6d24c0e00e540ab2b17705 + +(cherry picked from commit efff74c1aea14757ce074db28e02671c7f7bb5f5) + +Don't die() on failing to parse lease-script output. + +(cherry picked from commit 05f76dab89d5b879519a4f45b0cccaa1fc3d162d) +--- + man/dnsmasq.8 | 4 +- + src/dhcp-common.c | 16 +++--- + src/dhcp-protocol.h | 4 ++ + src/dnsmasq.c | 8 +++ + src/dnsmasq.h | 54 +++++++++--------- + src/helper.c | 56 +++++++++++++++++- + src/lease.c | 159 +++++++++++++++++++++++++++++++--------------------- + src/log.c | 4 +- + src/rfc3315.c | 2 +- + 9 files changed, 202 insertions(+), 105 deletions(-) + +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 +index 0521534..97d0a4f 100644 +--- a/man/dnsmasq.8 ++++ b/man/dnsmasq.8 +@@ -1551,8 +1551,8 @@ database. + + + All file descriptors are +-closed except stdin, stdout and stderr which are open to /dev/null +-(except in debug mode). ++closed except stdin, which is open to /dev/null, and stdout and stderr which capture output for logging by dnsmasq. ++(In debug mode, stdio, stdout and stderr file are left as those inherited from the invoker of dnsmasq). + + The script is not invoked concurrently: at most one instance + of the script is ever running (dnsmasq waits for an instance of script to exit +diff --git a/src/dhcp-common.c b/src/dhcp-common.c +index 08528e8..ecc752b 100644 +--- a/src/dhcp-common.c ++++ b/src/dhcp-common.c +@@ -20,11 +20,11 @@ + + void dhcp_common_init(void) + { +- /* These each hold a DHCP option max size 255 +- and get a terminating zero added */ +- daemon->dhcp_buff = safe_malloc(256); +- daemon->dhcp_buff2 = safe_malloc(256); +- daemon->dhcp_buff3 = safe_malloc(256); ++ /* These each hold a DHCP option max size 255 ++ and get a terminating zero added */ ++ daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ); ++ daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ); ++ daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ); + + /* dhcp_packet is used by v4 and v6, outpacket only by v6 + sizeof(struct dhcp_packet) is as good an initial size as any, +@@ -855,14 +855,14 @@ void log_context(int family, struct dhcp_context *context) + if (context->flags & CONTEXT_RA_STATELESS) + { + if (context->flags & CONTEXT_TEMPLATE) +- strncpy(daemon->dhcp_buff, context->template_interface, 256); ++ strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ); + else + strcpy(daemon->dhcp_buff, daemon->addrbuff); + } + else + #endif +- inet_ntop(family, start, daemon->dhcp_buff, 256); +- inet_ntop(family, end, daemon->dhcp_buff3, 256); ++ inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ); ++ inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ); + my_syslog(MS_DHCP | LOG_INFO, + (context->flags & CONTEXT_RA_STATELESS) ? + _("%s stateless on %s%.0s%.0s%s") : +diff --git a/src/dhcp-protocol.h b/src/dhcp-protocol.h +index a31d829..0ea449b 100644 +--- a/src/dhcp-protocol.h ++++ b/src/dhcp-protocol.h +@@ -19,6 +19,10 @@ + #define DHCP_CLIENT_ALTPORT 1068 + #define PXE_PORT 4011 + ++/* These each hold a DHCP option max size 255 ++ and get a terminating zero added */ ++#define DHCP_BUFF_SZ 256 ++ + #define BOOTREQUEST 1 + #define BOOTREPLY 2 + #define DHCP_COOKIE 0x63825363 +diff --git a/src/dnsmasq.c b/src/dnsmasq.c +index 045ec53..9cd4052 100644 +--- a/src/dnsmasq.c ++++ b/src/dnsmasq.c +@@ -1294,6 +1294,7 @@ static void async_event(int pipe, time_t now) + daemon->tcp_pids[i] = 0; + break; + ++#if defined(HAVE_SCRIPT) + case EVENT_KILLED: + my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data); + break; +@@ -1307,12 +1308,19 @@ static void async_event(int pipe, time_t now) + daemon->lease_change_command, strerror(ev.data)); + break; + ++ case EVENT_SCRIPT_LOG: ++ my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : ""); ++ free(msg); ++ msg = NULL; ++ break; ++ + /* necessary for fatal errors in helper */ + case EVENT_USER_ERR: + case EVENT_DIE: + case EVENT_LUA_ERR: + fatal_event(&ev, msg); + break; ++#endif + + case EVENT_REOPEN: + /* Note: this may leave TCP-handling processes with the old file still open. +diff --git a/src/dnsmasq.h b/src/dnsmasq.h +index 1896a64..0cfd3c6 100644 +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -145,30 +145,31 @@ struct event_desc { + int event, data, msg_sz; + }; + +-#define EVENT_RELOAD 1 +-#define EVENT_DUMP 2 +-#define EVENT_ALARM 3 +-#define EVENT_TERM 4 +-#define EVENT_CHILD 5 +-#define EVENT_REOPEN 6 +-#define EVENT_EXITED 7 +-#define EVENT_KILLED 8 +-#define EVENT_EXEC_ERR 9 +-#define EVENT_PIPE_ERR 10 +-#define EVENT_USER_ERR 11 +-#define EVENT_CAP_ERR 12 +-#define EVENT_PIDFILE 13 +-#define EVENT_HUSER_ERR 14 +-#define EVENT_GROUP_ERR 15 +-#define EVENT_DIE 16 +-#define EVENT_LOG_ERR 17 +-#define EVENT_FORK_ERR 18 +-#define EVENT_LUA_ERR 19 +-#define EVENT_TFTP_ERR 20 +-#define EVENT_INIT 21 +-#define EVENT_NEWADDR 22 +-#define EVENT_NEWROUTE 23 +-#define EVENT_TIME_ERR 24 ++#define EVENT_RELOAD 1 ++#define EVENT_DUMP 2 ++#define EVENT_ALARM 3 ++#define EVENT_TERM 4 ++#define EVENT_CHILD 5 ++#define EVENT_REOPEN 6 ++#define EVENT_EXITED 7 ++#define EVENT_KILLED 8 ++#define EVENT_EXEC_ERR 9 ++#define EVENT_PIPE_ERR 10 ++#define EVENT_USER_ERR 11 ++#define EVENT_CAP_ERR 12 ++#define EVENT_PIDFILE 13 ++#define EVENT_HUSER_ERR 14 ++#define EVENT_GROUP_ERR 15 ++#define EVENT_DIE 16 ++#define EVENT_LOG_ERR 17 ++#define EVENT_FORK_ERR 18 ++#define EVENT_LUA_ERR 19 ++#define EVENT_TFTP_ERR 20 ++#define EVENT_INIT 21 ++#define EVENT_NEWADDR 22 ++#define EVENT_NEWROUTE 23 ++#define EVENT_TIME_ERR 24 ++#define EVENT_SCRIPT_LOG 25 + + /* Exit codes. */ + #define EC_GOOD 0 +@@ -242,8 +243,9 @@ struct event_desc { + + /* extra flags for my_syslog, we use a couple of facilities since they are known + not to occupy the same bits as priorities, no matter how syslog.h is set up. */ +-#define MS_TFTP LOG_USER +-#define MS_DHCP LOG_DAEMON ++#define MS_TFTP LOG_USER ++#define MS_DHCP LOG_DAEMON ++#define MS_SCRIPT LOG_MAIL + + struct all_addr { + union { +diff --git a/src/helper.c b/src/helper.c +index 9c37e37..de31383 100644 +--- a/src/helper.c ++++ b/src/helper.c +@@ -14,6 +14,7 @@ + along with this program. If not, see . + */ + ++#include + #include "dnsmasq.h" + + #ifdef HAVE_SCRIPT +@@ -135,7 +136,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + max_fd != STDIN_FILENO && max_fd != pipefd[0] && + max_fd != event_fd && max_fd != err_fd) + close(max_fd); +- ++ + #ifdef HAVE_LUASCRIPT + if (daemon->luascript) + { +@@ -189,6 +190,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + unsigned char *buf = (unsigned char *)daemon->namebuff; + unsigned char *end, *extradata, *alloc_buff = NULL; + int is6, err = 0; ++ int pipeout[2]; + + free(alloc_buff); + +@@ -472,16 +474,54 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + if (!daemon->lease_change_command) + continue; + ++ /* Pipe to capture stdout and stderr from script */ ++ if (!option_bool(OPT_DEBUG) && pipe(pipeout) == -1) ++ continue; ++ + /* possible fork errors are all temporary resource problems */ + while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM)) + sleep(2); + + if (pid == -1) +- continue; ++ { ++ if (!option_bool(OPT_DEBUG)) ++ { ++ close(pipeout[0]); ++ close(pipeout[1]); ++ } ++ continue; ++ } + + /* wait for child to complete */ + if (pid != 0) + { ++ if (!option_bool(OPT_DEBUG)) ++ { ++ FILE *fp; ++ ++ close(pipeout[1]); ++ ++ /* Read lines sent to stdout/err by the script and pass them back to be logged */ ++ if (!(fp = fdopen(pipeout[0], "r"))) ++ close(pipeout[0]); ++ else ++ { ++ while (fgets(daemon->packet, daemon->packet_buff_sz, fp)) ++ { ++ /* do not include new lines, log will append them */ ++ size_t len = strlen(daemon->packet); ++ if (len > 0) ++ { ++ --len; ++ if (daemon->packet[len] == '\n') ++ daemon->packet[len] = 0; ++ } ++ send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet); ++ } ++ fclose(fp); ++ } ++ } ++ + /* reap our children's children, if necessary */ + while (1) + { +@@ -504,6 +544,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + + continue; + } ++ ++ if (!option_bool(OPT_DEBUG)) ++ { ++ /* map stdout/stderr of script to pipeout */ ++ close(pipeout[0]); ++ dup2(pipeout[1], STDOUT_FILENO); ++ dup2(pipeout[1], STDERR_FILENO); ++ close(pipeout[1]); ++ } + + if (data.action != ACTION_TFTP && data.action != ACTION_ARP) + { +@@ -579,7 +628,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + hostname = NULL; + + my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err); +- } ++ } ++ + /* we need to have the event_fd around if exec fails */ + if ((i = fcntl(event_fd, F_GETFD)) != -1) + fcntl(event_fd, F_SETFD, i | FD_CLOEXEC); +diff --git a/src/lease.c b/src/lease.c +index 20cac90..64047f9 100644 +--- a/src/lease.c ++++ b/src/lease.c +@@ -21,94 +21,62 @@ + static struct dhcp_lease *leases = NULL, *old_leases = NULL; + static int dns_dirty, file_dirty, leases_left; + +-void lease_init(time_t now) ++static int read_leases(time_t now, FILE *leasestream) + { + unsigned long ei; + struct all_addr addr; + struct dhcp_lease *lease; + int clid_len, hw_len, hw_type; +- FILE *leasestream; +- +- leases_left = daemon->dhcp_max; +- +- if (option_bool(OPT_LEASE_RO)) +- { +- /* run " init" once to get the +- initial state of the database. If leasefile-ro is +- set without a script, we just do without any +- lease database. */ +-#ifdef HAVE_SCRIPT +- if (daemon->lease_change_command) +- { +- strcpy(daemon->dhcp_buff, daemon->lease_change_command); +- strcat(daemon->dhcp_buff, " init"); +- leasestream = popen(daemon->dhcp_buff, "r"); +- } +- else ++ int items; ++ char *domain = NULL; ++ ++ *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0'; ++ ++ /* client-id max length is 255 which is 255*2 digits + 254 colons ++ borrow DNS packet buffer which is always larger than 1000 bytes ++ ++ Check various buffers are big enough for the code below */ ++ ++#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ < 764) ++# error Buffer size breakage in leasefile parsing. + #endif +- { +- file_dirty = dns_dirty = 0; +- return; +- } + +- } +- else +- { +- /* NOTE: need a+ mode to create file if it doesn't exist */ +- leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+"); +- +- if (!leasestream) +- die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE); +- +- /* a+ mode leaves pointer at end. */ +- rewind(leasestream); +- } +- +- /* client-id max length is 255 which is 255*2 digits + 254 colons +- borrow DNS packet buffer which is always larger than 1000 bytes */ +- if (leasestream) +- while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2) ++ while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2) + { ++ *daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0'; ++ hw_len = hw_type = clid_len = 0; ++ + #ifdef HAVE_DHCP6 + if (strcmp(daemon->dhcp_buff3, "duid") == 0) + { + daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL); ++ if (daemon->duid_len < 0) ++ return 0; + daemon->duid = safe_malloc(daemon->duid_len); + memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len); + continue; + } + #endif +- +- ei = atol(daemon->dhcp_buff3); + + if (fscanf(leasestream, " %64s %255s %764s", + daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3) +- break; ++ return 0; + +- clid_len = 0; +- if (strcmp(daemon->packet, "*") != 0) +- clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); +- +- if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) && +- (lease = lease4_allocate(addr.addr.addr4))) ++ if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4)) + { ++ if ((lease = lease4_allocate(addr.addr.addr4))) ++ domain = get_domain(lease->addr); ++ + hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type); + /* For backwards compatibility, no explict MAC address type means ether. */ + if (hw_type == 0 && hw_len != 0) + hw_type = ARPHRD_ETHER; +- +- lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, +- hw_len, hw_type, clid_len, now, 0); +- +- if (strcmp(daemon->dhcp_buff, "*") != 0) +- lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL); + } + #ifdef HAVE_DHCP6 + else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6)) + { + char *s = daemon->dhcp_buff2; + int lease_type = LEASE_NA; +- int iaid; + + if (s[0] == 'T') + { +@@ -116,23 +84,30 @@ void lease_init(time_t now) + s++; + } + +- iaid = strtoul(s, NULL, 10); +- + if ((lease = lease6_allocate(&addr.addr.addr6, lease_type))) + { +- lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0); +- lease_set_iaid(lease, iaid); +- if (strcmp(daemon->dhcp_buff, "*") != 0) +- lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL); ++ lease_set_iaid(lease, strtoul(s, NULL, 10)); ++ domain = get_domain6((struct in6_addr *)lease->hwaddr); + } + } + #endif + else +- break; ++ return 0; + + if (!lease) + die (_("too many stored leases"), NULL, EC_MISC); +- ++ ++ if (strcmp(daemon->packet, "*") != 0) ++ clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); ++ ++ lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, ++ hw_len, hw_type, clid_len, now, 0); ++ ++ if (strcmp(daemon->dhcp_buff, "*") != 0) ++ lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL); ++ ++ ei = atol(daemon->dhcp_buff3); ++ + #ifdef HAVE_BROKEN_RTC + if (ei != 0) + lease->expires = (time_t)ei + now; +@@ -148,7 +123,62 @@ void lease_init(time_t now) + /* set these correctly: the "old" events are generated later from + the startup synthesised SIGHUP. */ + lease->flags &= ~(LEASE_NEW | LEASE_CHANGED); ++ ++ *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0'; + } ++ ++ return (items == 0 || items == EOF); ++} ++ ++void lease_init(time_t now) ++{ ++ FILE *leasestream; ++ ++ leases_left = daemon->dhcp_max; ++ ++ if (option_bool(OPT_LEASE_RO)) ++ { ++ /* run " init" once to get the ++ initial state of the database. If leasefile-ro is ++ set without a script, we just do without any ++ lease database. */ ++#ifdef HAVE_SCRIPT ++ if (daemon->lease_change_command) ++ { ++ strcpy(daemon->dhcp_buff, daemon->lease_change_command); ++ strcat(daemon->dhcp_buff, " init"); ++ leasestream = popen(daemon->dhcp_buff, "r"); ++ } ++ else ++#endif ++ { ++ file_dirty = dns_dirty = 0; ++ return; ++ } ++ ++ } ++ else ++ { ++ /* NOTE: need a+ mode to create file if it doesn't exist */ ++ leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+"); ++ ++ if (!leasestream) ++ die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE); ++ ++ /* a+ mode leaves pointer at end. */ ++ rewind(leasestream); ++ } ++ ++ if (leasestream) ++ { ++ if (!read_leases(now, leasestream)) ++ my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."), ++ daemon->dhcp_buff3, daemon->dhcp_buff2, ++ daemon->namebuff, daemon->dhcp_buff); ++ ++ if (ferror(leasestream)) ++ die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE); ++ } + + #ifdef HAVE_SCRIPT + if (!daemon->lease_stream) +@@ -162,6 +192,7 @@ void lease_init(time_t now) + errno = ENOENT; + else if (WEXITSTATUS(rc) == 126) + errno = EACCES; ++ + die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE); + } + +diff --git a/src/log.c b/src/log.c +index 8e66629..5fc860b 100644 +--- a/src/log.c ++++ b/src/log.c +@@ -288,7 +288,9 @@ void my_syslog(int priority, const char *format, ...) + func = "-tftp"; + else if ((LOG_FACMASK & priority) == MS_DHCP) + func = "-dhcp"; +- ++ else if ((LOG_FACMASK & priority) == MS_SCRIPT) ++ func = "-script"; ++ + #ifdef LOG_PRI + priority = LOG_PRI(priority); + #else +diff --git a/src/rfc3315.c b/src/rfc3315.c +index 3f4d69c..a3715cd 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -1975,7 +1975,7 @@ static void log6_packet(struct state *state, char *type, struct in6_addr *addr, + + if (addr) + { +- inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, 255); ++ inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1); + strcat(daemon->dhcp_buff2, " "); + } + else +-- +2.9.3 + diff --git a/SOURCES/dnsmasq-2.76-file_offset32.patch b/SOURCES/dnsmasq-2.76-file_offset32.patch new file mode 100644 index 00000000..f06996d1 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-file_offset32.patch @@ -0,0 +1,12 @@ +diff --git a/src/helper.c b/src/helper.c +index de31383..a843b41 100644 +--- a/src/helper.c ++++ b/src/helper.c +@@ -14,7 +14,6 @@ + along with this program. If not, see . + */ + +-#include + #include "dnsmasq.h" + + #ifdef HAVE_SCRIPT diff --git a/SOURCES/dnsmasq-2.76-gita3303e196.patch b/SOURCES/dnsmasq-2.76-gita3303e196.patch new file mode 100644 index 00000000..a437848e --- /dev/null +++ b/SOURCES/dnsmasq-2.76-gita3303e196.patch @@ -0,0 +1,45 @@ +From 2c1aec1e979a209eb2f2b035314a8c973b4ac269 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Thu, 7 Sep 2017 20:45:00 +0100 +Subject: [PATCH 7/9] Don't return arcount=1 if EDNS0 RR won't fit in the + packet. + + Omitting the EDNS0 RR but setting arcount gives a malformed packet. + Also, don't accept UDP packet size less than 512 in recieved EDNS0. +--- + src/edns0.c | 5 ++++- + src/forward.c | 2 ++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/edns0.c b/src/edns0.c +index 5bdc133..a8d0167 100644 +--- a/src/edns0.c ++++ b/src/edns0.c +@@ -221,7 +221,10 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + free(buff); + p += rdlen; + } +- header->arcount = htons(ntohs(header->arcount) + 1); ++ ++ /* Only bump arcount if RR is going to fit */ ++ if (((ssize_t)optlen) <= (limit - (p + 4))) ++ header->arcount = htons(ntohs(header->arcount) + 1); + } + + if (((ssize_t)optlen) > (limit - (p + 4))) +diff --git a/src/forward.c b/src/forward.c +index 9b464d3..0f8f462 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -1408,6 +1408,8 @@ void receive_query(struct listener *listen, time_t now) + defaults to 512 */ + if (udp_size > daemon->edns_pktsz) + udp_size = daemon->edns_pktsz; ++ else if (udp_size < PACKETSZ) ++ udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */ + } + + #ifdef HAVE_AUTH +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-misc-cleanups.patch b/SOURCES/dnsmasq-2.76-misc-cleanups.patch new file mode 100644 index 00000000..e8a21322 --- /dev/null +++ b/SOURCES/dnsmasq-2.76-misc-cleanups.patch @@ -0,0 +1,63 @@ +From 3947ab0069e443e72debe26379b8517fac8f6e41 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 25 Sep 2017 20:19:55 +0100 +Subject: [PATCH 8/9] Misc code cleanups arising from Google analysis. + No security impleications or CVEs. + +--- + src/edns0.c | 2 +- + src/rfc1035.c | 4 +++- + src/rfc2131.c | 2 +- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/edns0.c b/src/edns0.c +index a8d0167..0552d38 100644 +--- a/src/edns0.c ++++ b/src/edns0.c +@@ -159,7 +159,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + /* delete option if we're to replace it. */ + p -= 4; + rdlen -= len + 4; +- memcpy(p, p+len+4, rdlen - i); ++ memmove(p, p+len+4, rdlen - i); + PUTSHORT(rdlen, lenp); + lenp -= 2; + } +diff --git a/src/rfc1035.c b/src/rfc1035.c +index 78410d6..917bac2 100644 +--- a/src/rfc1035.c ++++ b/src/rfc1035.c +@@ -37,7 +37,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, + /* end marker */ + { + /* check that there are the correct no of bytes after the name */ +- if (!CHECK_LEN(header, p, plen, extrabytes)) ++ if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes)) + return 0; + + if (isExtract) +@@ -485,6 +485,8 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header * + { + unsigned int i, len = *p1; + unsigned char *p2 = p1; ++ if ((p1 + len - p) >= rdlen) ++ return 0; /* bad packet */ + /* make counted string zero-term and sanitise */ + for (i = 0; i < len; i++) + { +diff --git a/src/rfc2131.c b/src/rfc2131.c +index 75893a6..71d5846 100644 +--- a/src/rfc2131.c ++++ b/src/rfc2131.c +@@ -155,7 +155,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, + for (offset = 0; offset < (len - 5); offset += elen + 5) + { + elen = option_uint(opt, offset + 4 , 1); +- if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA) ++ if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len) + { + unsigned char *x = option_ptr(opt, offset + 5); + unsigned char *y = option_ptr(opt, offset + elen + 5); +-- +2.9.5 + diff --git a/SOURCES/dnsmasq-2.76-underflow.patch b/SOURCES/dnsmasq-2.76-underflow.patch new file mode 100644 index 00000000..ac8188ec --- /dev/null +++ b/SOURCES/dnsmasq-2.76-underflow.patch @@ -0,0 +1,74 @@ +From d4f2e0b8d8f0b5daa0d468f62a0d5f1df58ac325 Mon Sep 17 00:00:00 2001 +From: Doran Moppert +Date: Tue, 26 Sep 2017 14:48:20 +0930 +Subject: [PATCH 9/9] google patch hand-applied + +--- + src/edns0.c | 10 +++++----- + src/forward.c | 4 ++++ + src/rfc1035.c | 6 ++++-- + 3 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/src/edns0.c b/src/edns0.c +index 0552d38..bec4a36 100644 +--- a/src/edns0.c ++++ b/src/edns0.c +@@ -212,11 +212,11 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l + /* Copy back any options */ + if (buff) + { +- if (p + rdlen > limit) +- { +- free(buff); +- return plen; /* Too big */ +- } ++ if (p + rdlen > limit) ++ { ++ free(buff); ++ return plen; /* Too big */ ++ } + memcpy(p, buff, rdlen); + free(buff); + p += rdlen; +diff --git a/src/forward.c b/src/forward.c +index 0f8f462..a729c06 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -1412,6 +1412,10 @@ void receive_query(struct listener *listen, time_t now) + udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */ + } + ++ // Make sure the udp size is not smaller than the incoming message so that we ++ // do not underflow ++ if (udp_size < n) udp_size = n; ++ + #ifdef HAVE_AUTH + if (auth_dns) + { +diff --git a/src/rfc1035.c b/src/rfc1035.c +index 917bac2..ae65702 100644 +--- a/src/rfc1035.c ++++ b/src/rfc1035.c +@@ -1182,8 +1182,8 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int + va_end(ap); /* clean up variable argument pointer */ + + j = p - sav - 2; +- /* this has already been checked against limit before */ +- 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) +@@ -1243,6 +1243,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, + int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1; + struct mx_srv_record *rec; + size_t len; ++ // Make sure we do not underflow here too. ++ if (qlen > (limit - ((char *)header))) return 0; + + if (ntohs(header->ancount) != 0 || + ntohs(header->nscount) != 0 || +-- +2.9.5 + diff --git a/SPECS/dnsmasq.spec b/SPECS/dnsmasq.spec index 8a6450a0..b312ef33 100644 --- a/SPECS/dnsmasq.spec +++ b/SPECS/dnsmasq.spec @@ -13,7 +13,7 @@ Name: dnsmasq Version: 2.76 -Release: 2%{?extraversion}%{?dist} +Release: 5%{?extraversion}%{?dist} Summary: A lightweight DHCP/caching DNS server Group: System Environment/Daemons @@ -38,6 +38,22 @@ Patch5: dnsmasq-2.76-warning-fixes.patch Patch6: dnsmasq-2.76-label-warning.patch Patch7: dnsmasq-2.76-label-man.patch Patch8: dnsmasq-2.76-coverity.patch +# commit c77fb9d8f09d136fa71bde2469c4fd11cefa6f4a +# commit bf4e62c19e619f7edf8d03d58d33a5752f190bfd +# commit 3a8b0f6fccf464b1ec6d24c0e00e540ab2b17705 +Patch9: dnsmasq-2.76-dhcp-script-log.patch +# Fix possible different sizes of off_t +Patch10: dnsmasq-2.76-file_offset32.patch +Patch11: dnsmasq-2.76-CVE-2017-14491.patch +Patch12: dnsmasq-2.76-CVE-2017-14492.patch +Patch13: dnsmasq-2.76-CVE-2017-14493.patch +Patch14: dnsmasq-2.76-CVE-2017-14494.patch +Patch15: dnsmasq-2.76-CVE-2017-14496.patch +Patch16: dnsmasq-2.76-CVE-2017-14495.patch +# commit a3303e196e5d304ec955c4d63afb923ade66c6e8 +Patch17: dnsmasq-2.76-gita3303e196.patch +Patch18: dnsmasq-2.76-underflow.patch +Patch19: dnsmasq-2.76-misc-cleanups.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -81,6 +97,17 @@ query/remove a DHCP server's leases. %patch6 -p1 %patch7 -p1 %patch8 -p1 -b .coverity +%patch9 -p1 -b .scriptlog +%patch10 -p1 -b .off_t +%patch11 -p1 -b .CVE-2017-14491 +%patch12 -p1 -b .CVE-2017-14492 +%patch13 -p1 -b .CVE-2017-14493 +%patch14 -p1 -b .CVE-2017-14494 +%patch15 -p1 -b .CVE-2017-14496 +%patch16 -p1 -b .CVE-2017-14495 +%patch17 -p1 -b .gita3303e196 +%patch18 -p1 -b .underflow +%patch19 -p1 -b .misc # use /var/lib/dnsmasq instead of /var/lib/misc for file in dnsmasq.conf.example man/dnsmasq.8 man/es/dnsmasq.8 src/config.h; do @@ -167,6 +194,22 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man1/dhcp_* %changelog +* Tue Sep 26 2017 Petr Menšík - 2.76-5 +- Fix CVE-2017-14491 +- Fix CVE-2017-14492 +- Fix CVE-2017-14493 +- Fix CVE-2017-14494 +- Fix CVE-2017-14496 +- Fix CVE-2017-14495 +- extra fixes + +* Thu Sep 14 2017 Petr Menšík - 2.76-4 +- Fix possible stack corruption on 32-bit architectures (#1188259) + +* Fri Mar 24 2017 Petr Menšík - 2.76-3 +- Log output of dhcp-script (#1188259) +- Log format errors in dhcp-script init + * Wed Mar 15 2017 Petr Menšík - 2.76-2 - Fix a few coverity warnings - package is dual-licensed GPL v2 or v3