April 2016 nss_dns hardening
This commit is contained in:
Florian Weimer 2016-05-06 17:02:34 +02:00
parent 116e17a138
commit 217d136f41
6 changed files with 427 additions and 0 deletions

24
glibc-rh1332914-1.patch Normal file
View File

@ -0,0 +1,24 @@
commit d29fb41f4431ca35ea360498ef9d37558ce90d76
Author: Florian Weimer <fweimer@redhat.com>
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:

78
glibc-rh1332914-2.patch Normal file
View File

@ -0,0 +1,78 @@
commit f749498fa53df9ead81e291cd9378d67483c2452
Author: Florian Weimer <fweimer@redhat.com>
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;

148
glibc-rh1332914-3.patch Normal file
View File

@ -0,0 +1,148 @@
commit b9b026c9c00db1a1b5b4a3caa28162655a04a882
Author: Florian Weimer <fweimer@redhat.com>
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 <resolv.h>
#include <ctype.h>
#include <errno.h>
-#include <syslog.h>
#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 <stdlib.h>
#include <stddef.h>
#include <string.h>
-#include <sys/syslog.h>
#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;
}

109
glibc-rh1332914-4.patch Normal file
View File

@ -0,0 +1,109 @@
commit 5e0c421cc07e2d06945b863ed3bb92395472705d
Author: Florian Weimer <fweimer@redhat.com>
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;

57
glibc-rh1332914-5.patch Normal file
View File

@ -0,0 +1,57 @@
commit a12f9431b3808e78b9ed397e4fce7de69410d94d
Author: Florian Weimer <fweimer@redhat.com>
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)

View File

@ -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 <fweimer@redhat.com> - 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 <mfabian@redhat.com> - 2.22-11
- Add the C.UTF-8 locale