diff --git a/glibc-rh1332914-1.patch b/glibc-rh1332914-1.patch new file mode 100644 index 0000000..b811f10 --- /dev/null +++ b/glibc-rh1332914-1.patch @@ -0,0 +1,24 @@ +commit d29fb41f4431ca35ea360498ef9d37558ce90d76 +Author: Florian Weimer +Date: Mon Apr 11 10:55:43 2016 +0200 + + nss_dns: Fix assertion failure in _nss_dns_getcanonname_r [BZ #19865] + +diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c +index 27255fd..fd73f19 100644 +--- a/resolv/nss_dns/dns-canon.c ++++ b/resolv/nss_dns/dns-canon.c +@@ -144,6 +144,13 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, + ptr += sizeof (uint16_t) + __ns_get16 (ptr); + } + } ++ ++ /* Restore original buffer before retry. */ ++ if (ansp.ptr != buf) ++ { ++ free (ansp.ptr); ++ ansp.ptr = buf; ++ } + } + + out: diff --git a/glibc-rh1332914-2.patch b/glibc-rh1332914-2.patch new file mode 100644 index 0000000..4b470d5 --- /dev/null +++ b/glibc-rh1332914-2.patch @@ -0,0 +1,78 @@ +commit f749498fa53df9ead81e291cd9378d67483c2452 +Author: Florian Weimer +Date: Wed Apr 27 15:11:41 2016 +0200 + + nss_dns: Validate RDATA length against packet length [BZ #19830] + + In _nss_dns_getcanonname_r, a check for the availability of RR metadata + was missing as well. + +diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c +index fd73f19..072104f 100644 +--- a/resolv/nss_dns/dns-canon.c ++++ b/resolv/nss_dns/dns-canon.c +@@ -103,6 +103,11 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, + + ptr += s; + ++ /* Check that there are enough bytes for the RR ++ metadata. */ ++ if (endptr - ptr < 10) ++ goto unavail; ++ + /* Check whether type and class match. */ + uint_fast16_t type; + NS_GET16 (type, ptr); +@@ -137,11 +142,16 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, + if (__ns_get16 (ptr) != ns_c_in) + goto unavail; + +- /* Also skip over the TTL. */ ++ /* Also skip over class and TTL. */ + ptr += sizeof (uint16_t) + sizeof (uint32_t); + +- /* Skip over the data length and data. */ +- ptr += sizeof (uint16_t) + __ns_get16 (ptr); ++ /* Skip over RDATA length and RDATA itself. */ ++ uint16_t rdatalen = __ns_get16 (ptr); ++ ptr += sizeof (uint16_t); ++ /* Not enough room for RDATA. */ ++ if (endptr - ptr < rdatalen) ++ goto unavail; ++ ptr += rdatalen; + } + } + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 8599f4c..4bb0e62 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -751,6 +751,14 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, + cp += INT32SZ; /* TTL */ + n = __ns_get16 (cp); + cp += INT16SZ; /* len */ ++ ++ if (end_of_message - cp < n) ++ { ++ /* RDATA extends beyond the end of the packet. */ ++ ++had_error; ++ continue; ++ } ++ + if (__glibc_unlikely (class != C_IN)) + { + /* XXX - debug? syslog? */ +@@ -1077,6 +1085,13 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, + n = __ns_get16 (cp); + cp += INT16SZ; /* len */ + ++ if (end_of_message - cp < n) ++ { ++ /* RDATA extends beyond the end of the packet. */ ++ ++had_error; ++ continue; ++ } ++ + if (class != C_IN) + { + cp += n; diff --git a/glibc-rh1332914-3.patch b/glibc-rh1332914-3.patch new file mode 100644 index 0000000..250655b --- /dev/null +++ b/glibc-rh1332914-3.patch @@ -0,0 +1,148 @@ +commit b9b026c9c00db1a1b5b4a3caa28162655a04a882 +Author: Florian Weimer +Date: Wed Apr 27 16:12:32 2016 +0200 + + resolv, nss_dns: Remove remaining syslog logging [BZ #19862] + + The fix for bug 14841 only removed part of the logging. + +Index: b/resolv/gethnamaddr.c +=================================================================== +--- a/resolv/gethnamaddr.c ++++ b/resolv/gethnamaddr.c +@@ -70,7 +70,6 @@ static char sccsid[] = "@(#)gethostnamad + #include + #include + #include +-#include + + #define RESOLVSORT + +@@ -100,9 +99,6 @@ static char sccsid[] = "@(#)gethostnamad + #define MAXALIASES 35 + #define MAXADDRS 35 + +-static const char AskedForGot[] = +- "gethostby*.getanswer: asked for \"%s\", got \"%s\""; +- + static char *h_addr_ptrs[MAXADDRS + 1]; + + static struct hostent host; +@@ -337,20 +333,12 @@ getanswer (const querybuf *answer, int a + * uses many different types in responses that do not + * match QTYPE. + */ +- if ((_res.options & RES_USE_DNSSEC) == 0) { +- syslog(LOG_NOTICE|LOG_AUTH, +- "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", +- qname, p_class(C_IN), p_type(qtype), +- p_type(type)); +- } + cp += n; + continue; /* XXX - had_error++ ? */ + } + switch (type) { + case T_PTR: + if (strcasecmp(tname, bp) != 0) { +- syslog(LOG_NOTICE|LOG_AUTH, +- AskedForGot, qname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } +@@ -399,8 +387,6 @@ getanswer (const querybuf *answer, int a + case T_A: + case T_AAAA: + if (strcasecmp(host.h_name, bp) != 0) { +- syslog(LOG_NOTICE|LOG_AUTH, +- AskedForGot, host.h_name, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } +@@ -748,9 +734,6 @@ gethostbyaddr(addr, len, af) + _res.options &= ~RES_DNSRCH; + _res.options |= RES_DEFNAMES; + if (!(rhp = gethostbyname(hname2))) { +- syslog(LOG_NOTICE|LOG_AUTH, +- "gethostbyaddr: No A record for %s (verifying [%s])", +- hname2, inet_ntoa(*((struct in_addr *)addr))); + _res.options = old_options; + __set_h_errno (HOST_NOT_FOUND); + return (NULL); +@@ -760,9 +743,6 @@ gethostbyaddr(addr, len, af) + if (!memcmp(*haddr, addr, INADDRSZ)) + break; + if (!*haddr) { +- syslog(LOG_NOTICE|LOG_AUTH, +- "gethostbyaddr: A record of %s != PTR record [%s]", +- hname2, inet_ntoa(*((struct in_addr *)addr))); + __set_h_errno (HOST_NOT_FOUND); + return (NULL); + } +Index: b/resolv/nss_dns/dns-host.c +=================================================================== +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -78,7 +78,6 @@ + #include + #include + #include +-#include + + #include "nsswitch.h" + +@@ -99,10 +98,6 @@ + #endif + #define MAXHOSTNAMELEN 256 + +-static const char AskedForGot[] = "\ +-gethostby*.getanswer: asked for \"%s\", got \"%s\""; +- +- + /* We need this time later. */ + typedef union querybuf + { +@@ -838,14 +833,6 @@ getanswer_r (const querybuf *answer, int + have_to_map = 1; + else if (__glibc_unlikely (type != qtype)) + { +- /* Log a low priority message if we get an unexpected record, but +- skip it if we are using DNSSEC since it uses many different types +- in responses that do not match QTYPE. */ +- if ((_res.options & RES_USE_DNSSEC) == 0) +- syslog (LOG_NOTICE | LOG_AUTH, +- "gethostby*.getanswer: asked for \"%s %s %s\", " +- "got type \"%s\"", +- qname, p_class (C_IN), p_type (qtype), p_type (type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } +@@ -855,7 +842,6 @@ getanswer_r (const querybuf *answer, int + case T_PTR: + if (__glibc_unlikely (strcasecmp (tname, bp) != 0)) + { +- syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } +@@ -899,7 +885,6 @@ getanswer_r (const querybuf *answer, int + case T_AAAA: + if (__builtin_expect (strcasecmp (result->h_name, bp), 0) != 0) + { +- syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } +@@ -1152,13 +1137,6 @@ gaih_getanswer_slice (const querybuf *an + || __builtin_expect (type == T_DNAME, 0)) + #endif + { +- /* We don't support DNSSEC yet. For now, ignore the record +- and send a low priority message to syslog. +- +- We also don't expect T_PTR or T_DNAME messages. */ +- syslog (LOG_DEBUG | LOG_AUTH, +- "getaddrinfo*.gaih_getanswer: got type \"%s\"", +- p_type (type)); + cp += n; + continue; + } diff --git a/glibc-rh1332914-4.patch b/glibc-rh1332914-4.patch new file mode 100644 index 0000000..b33c4c0 --- /dev/null +++ b/glibc-rh1332914-4.patch @@ -0,0 +1,109 @@ +commit 5e0c421cc07e2d06945b863ed3bb92395472705d +Author: Florian Weimer +Date: Wed Apr 27 16:39:12 2016 +0200 + + nss_dns: Check address length before creating addrinfo result [BZ #19831] + + Previously, we allocated room in the result space before the check, + leaving uninitialized data there in case the check failed. + + This also consolidates the behavior between single (A or AAAA) and + dual (A and AAAA in parallel) queries. Single queries checked + the record length against the QTYPE, not the RRTYPE. + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index fb1d21c..403a005 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -134,6 +134,22 @@ extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af, + char **canonp); + hidden_proto (_nss_dns_gethostbyname3_r) + ++/* Return the expected RDATA length for an address record type (A or ++ AAAA). */ ++static int ++rrtype_to_rdata_length (int type) ++{ ++ switch (type) ++ { ++ case T_A: ++ return INADDRSZ; ++ case T_AAAA: ++ return IN6ADDRSZ; ++ default: ++ return -1; ++ } ++} ++ + enum nss_status + _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, +@@ -888,6 +904,15 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, + cp += n; + continue; /* XXX - had_error++ ? */ + } ++ ++ /* Stop parsing at a record whose length is incorrect. */ ++ if (n != rrtype_to_rdata_length (type)) ++ { ++ ++had_error; ++ break; ++ } ++ ++ /* Skip records of the wrong type. */ + if (n != result->h_length) + { + cp += n; +@@ -1124,25 +1149,25 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, + } + continue; + } +-#if 1 +- // We should not see any types other than those explicitly listed +- // below. Some types sent by server seem missing, though. Just +- // collect the data for now. +- if (__glibc_unlikely (type != T_A && type != T_AAAA)) +-#else +- if (__builtin_expect (type == T_SIG, 0) +- || __builtin_expect (type == T_KEY, 0) +- || __builtin_expect (type == T_NXT, 0) +- || __builtin_expect (type == T_PTR, 0) +- || __builtin_expect (type == T_DNAME, 0)) +-#endif ++ ++ /* Stop parsing if we encounter a record with incorrect RDATA ++ length. */ ++ if (type == T_A || type == T_AAAA) ++ { ++ if (n != rrtype_to_rdata_length (type)) ++ { ++ ++had_error; ++ continue; ++ } ++ } ++ else + { ++ /* Skip unknown records. */ + cp += n; + continue; + } +- if (type != T_A && type != T_AAAA) +- abort (); + ++ assert (type == T_A || type == T_AAAA); + if (*pat == NULL) + { + uintptr_t pad = (-(uintptr_t) buffer +@@ -1176,12 +1201,6 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, + } + + (*pat)->family = type == T_A ? AF_INET : AF_INET6; +- if (__builtin_expect ((type == T_A && n != INADDRSZ) +- || (type == T_AAAA && n != IN6ADDRSZ), 0)) +- { +- ++had_error; +- continue; +- } + memcpy ((*pat)->addr, cp, n); + cp += n; + (*pat)->scopeid = 0; diff --git a/glibc-rh1332914-5.patch b/glibc-rh1332914-5.patch new file mode 100644 index 0000000..0530acc --- /dev/null +++ b/glibc-rh1332914-5.patch @@ -0,0 +1,57 @@ +commit a12f9431b3808e78b9ed397e4fce7de69410d94d +Author: Florian Weimer +Date: Wed Apr 27 17:15:57 2016 +0200 + + nss_dns: Skip over non-PTR records in the netent code [BZ #19868] + + This requires additional checks for the RDATA length and the + availability of record metadata. + +Index: b/resolv/nss_dns/dns-network.c +=================================================================== +--- a/resolv/nss_dns/dns-network.c ++++ b/resolv/nss_dns/dns-network.c +@@ -345,10 +345,23 @@ getanswer_r (const querybuf *answer, int + if (n < 0 || res_dnok (bp) == 0) + break; + cp += n; ++ ++ if (end_of_message - cp < 10) ++ { ++ __set_h_errno (NO_RECOVERY); ++ return NSS_STATUS_UNAVAIL; ++ } ++ + GETSHORT (type, cp); + GETSHORT (class, cp); + cp += INT32SZ; /* TTL */ +- GETSHORT (n, cp); ++ uint16_t rdatalen; ++ GETSHORT (rdatalen, cp); ++ if (end_of_message - cp < rdatalen) ++ { ++ __set_h_errno (NO_RECOVERY); ++ return NSS_STATUS_UNAVAIL; ++ } + + if (class == C_IN && type == T_PTR) + { +@@ -370,7 +383,7 @@ getanswer_r (const querybuf *answer, int + cp += n; + return NSS_STATUS_UNAVAIL; + } +- cp += n; ++ cp += rdatalen; + if (alias_pointer + 2 < &net_data->aliases[MAX_NR_ALIASES]) + { + *alias_pointer++ = bp; +@@ -381,6 +394,9 @@ getanswer_r (const querybuf *answer, int + ++have_answer; + } + } ++ else ++ /* Skip over unknown record data. */ ++ cp += rdatalen; + } + + if (have_answer) diff --git a/glibc.spec b/glibc.spec index 3b8b3e1..ec3d903 100644 --- a/glibc.spec +++ b/glibc.spec @@ -226,6 +226,11 @@ Patch1003: glibc-rh1276761-2.patch Patch1004: glibc-rh1276761-3.patch Patch1005: glibc-rh1332912.patch Patch1006: glibc-rh1321954.patch +Patch1007: glibc-rh1332914-1.patch +Patch1008: glibc-rh1332914-2.patch +Patch1009: glibc-rh1332914-3.patch +Patch1010: glibc-rh1332914-4.patch +Patch1011: glibc-rh1332914-5.patch ############################################################################## # @@ -651,6 +656,11 @@ microbenchmark tests on the system. %patch1004 -p1 %patch1005 -p1 %patch1006 -p1 +%patch1007 -p1 +%patch1008 -p1 +%patch1009 -p1 +%patch1010 -p1 +%patch1011 -p1 %patch0059 -p1 ############################################################################## @@ -1874,6 +1884,7 @@ rm -f *.filelist* * Fri May 6 2016 Florian Weimer - 2.22-12 - Fix heap-based buffer overflow in get_txt_records (#1332912) - CVE-2016-3075: Stack overflow in _nss_dns_getnetbyname_r (#1321954) +- April 2016 nss_dns hardening (#1332914) * Wed Mar 02 2016 Mike FABIAN - 2.22-11 - Add the C.UTF-8 locale