This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch master updated. glibc-2.24-585-gfc82b0a


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  fc82b0a2dfe7dbd35671c10510a8da1043d746a5 (commit)
      from  3c589b1a8a4401e258ba23a03fcbcc79b82393ab (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=fc82b0a2dfe7dbd35671c10510a8da1043d746a5

commit fc82b0a2dfe7dbd35671c10510a8da1043d746a5
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sat Dec 31 20:22:09 2016 +0100

    CVE-2015-5180: resolv: Fix crash with internal QTYPE [BZ #18784]
    
    Also rename T_UNSPEC because an upcoming public header file
    update will use that name.

diff --git a/ChangeLog b/ChangeLog
index 01ee23b..3beacb0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2016-12-31  Florian Weimer  <fweimer@redhat.com>
 
+	[BZ #18784]
+	CVE-2015-5180
+	* include/arpa/nameser_compat.h (T_QUERY_A_AND_AAAA): Rename from
+	T_UNSPEC.  Adjust value.
+	* resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname4_r): Use it.
+	* resolv/res_query.c (__libc_res_nquery): Likewise.
+	* resolv/res_mkquery.c (res_nmkquery): Check for out-of-range
+	QTYPEs.
+	* resolv/tst-resolv-qtypes.c: New file.
+	* resolv/Makefile (xtests): Add tst-resolv-qtypes.
+	(tst-resolv-qtypes): Link against libresolv and libpthread.
+
+2016-12-31  Florian Weimer  <fweimer@redhat.com>
+
 	* elf/dl-tunables.h (__tunables_init): Fix unused attribute.
 
 2016-12-31  Siddhesh Poyarekar  <siddhesh@sourceware.org>
diff --git a/NEWS b/NEWS
index 7ebce44..08b566d 100644
--- a/NEWS
+++ b/NEWS
@@ -191,12 +191,18 @@ Version 2.25
 
 Security related changes:
 
-  On ARM EABI (32-bit), generating a backtrace for execution contexts which
+* On ARM EABI (32-bit), generating a backtrace for execution contexts which
   have been created with makecontext could fail to terminate due to a
   missing .cantunwind annotation.  This has been observed to lead to a hang
   (denial of service) in some Go applications compiled with gccgo.  Reported
   by Andreas Schwab.  (CVE-2016-6323)
 
+* The DNS stub resolver functions would crash due to a NULL pointer
+  dereference when processing a query with a valid DNS question type which
+  was used internally in the implementation.  The stub resolver now uses a
+  question type which is outside the range of valid question type values.
+  (CVE-2015-5180)
+
 The following bugs are resolved with this release:
 
   [The release manager will add the list generated by
diff --git a/include/arpa/nameser_compat.h b/include/arpa/nameser_compat.h
index 6928000..f7d0e04 100644
--- a/include/arpa/nameser_compat.h
+++ b/include/arpa/nameser_compat.h
@@ -3,9 +3,9 @@
 
 # ifndef _ISOMAC
 
-/* Picksome unused number to represent lookups of IPv4 and IPv6 (i.e.,
-   T_A and T_AAAA).  */
-#define T_UNSPEC 62321
+/* The number is outside the 16-bit RR type range and is used
+   internally by the implementation.  */
+#define T_QUERY_A_AND_AAAA 439963904
 
 # endif /* !_ISOMAC */
 #endif
diff --git a/resolv/Makefile b/resolv/Makefile
index 1e9f562..1089995 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -49,6 +49,8 @@ tests += \
   tst-resolv-network \
   tst-resolv-search \
 
+# This test sends millions of packets and is rather slow.
+xtests += tst-resolv-qtypes
 endif
 extra-libs-others = $(extra-libs)
 libresolv-routines := res_comp res_debug \
@@ -123,6 +125,7 @@ $(objpfx)tst-bug18665: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-res_use_inet6: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
 
 # This test case uses the deprecated RES_USE_INET6 resolver option.
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 901e037..d597faa 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -324,7 +324,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
 
   int olderr = errno;
   enum nss_status status;
-  int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
+  int n = __libc_res_nsearch (&_res, name, C_IN, T_QUERY_A_AND_AAAA,
 			      host_buffer.buf->buf, 2048, &host_buffer.ptr,
 			      &ans2p, &nans2p, &resplen2, &ans2p_malloced);
   if (n >= 0)
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index 12f9730..d80b531 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -103,6 +103,10 @@ res_nmkquery(res_state statp,
 	int n;
 	u_char *dnptrs[20], **dpp, **lastdnptr;
 
+	if (class < 0 || class > 65535
+	    || type < 0 || type > 65535)
+	  return -1;
+
 #ifdef DEBUG
 	if (statp->options & RES_DEBUG)
 		printf(";; res_nmkquery(%s, %s, %s, %s)\n",
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 944d1a9..07dc6f6 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -122,7 +122,7 @@ __libc_res_nquery(res_state statp,
 	int n, use_malloc = 0;
 	u_int oflags = statp->_flags;
 
-	size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE;
+	size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE;
 	u_char *buf = alloca (bufsize);
 	u_char *query1 = buf;
 	int nquery1 = -1;
@@ -137,7 +137,7 @@ __libc_res_nquery(res_state statp,
 		printf(";; res_query(%s, %d, %d)\n", name, class, type);
 #endif
 
-	if (type == T_UNSPEC)
+	if (type == T_QUERY_A_AND_AAAA)
 	  {
 	    n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
 			     query1, bufsize);
@@ -190,7 +190,7 @@ __libc_res_nquery(res_state statp,
 	if (__builtin_expect (n <= 0, 0) && !use_malloc) {
 		/* Retry just in case res_nmkquery failed because of too
 		   short buffer.  Shouldn't happen.  */
-		bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET;
+		bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET;
 		buf = malloc (bufsize);
 		if (buf != NULL) {
 			query1 = buf;
diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c
new file mode 100644
index 0000000..b3e60c6
--- /dev/null
+++ b/resolv/tst-resolv-qtypes.c
@@ -0,0 +1,185 @@
+/* Exercise low-level query functions with different QTYPEs.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <resolv.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xmemstream.h>
+
+/* If ture, the response function will send the actual response packet
+   over TCP instead of UDP.  */
+static volatile bool force_tcp;
+
+/* Send back a fake resource record matching the QTYPE.  */
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  if (force_tcp && ctx->tcp)
+    {
+      resolv_response_init (b, (struct resolv_response_flags) { .tc = 1 });
+      resolv_response_add_question (b, qname, qclass, qtype);
+      return;
+    }
+
+  resolv_response_init (b, (struct resolv_response_flags) { });
+  resolv_response_add_question (b, qname, qclass, qtype);
+  resolv_response_section (b, ns_s_an);
+  resolv_response_open_record (b, qname, qclass, qtype, 0);
+  resolv_response_add_data (b, &qtype, sizeof (qtype));
+  resolv_response_close_record (b);
+}
+
+static const const char *domain = "www.example.com";
+
+static int
+wrap_res_query (int type, unsigned char *answer, int answer_length)
+{
+  return res_query (domain, C_IN, type, answer, answer_length);
+}
+
+static int
+wrap_res_search (int type, unsigned char *answer, int answer_length)
+{
+  return res_query (domain, C_IN, type, answer, answer_length);
+}
+
+static int
+wrap_res_querydomain (int type, unsigned char *answer, int answer_length)
+{
+  return res_querydomain ("www", "example.com", C_IN, type,
+                           answer, answer_length);
+}
+
+static int
+wrap_res_send (int type, unsigned char *answer, int answer_length)
+{
+  unsigned char buf[512];
+  int ret = res_mkquery (QUERY, domain, C_IN, type,
+                         (const unsigned char *) "", 0, NULL,
+                         buf, sizeof (buf));
+  if (type < 0 || type >= 65536)
+    {
+      /* res_mkquery fails for out-of-range record types.  */
+      TEST_VERIFY_EXIT (ret == -1);
+      return -1;
+    }
+  TEST_VERIFY_EXIT (ret > 12);  /* DNS header length.  */
+  return res_send (buf, ret, answer, answer_length);
+}
+
+static int
+wrap_res_nquery (int type, unsigned char *answer, int answer_length)
+{
+  return res_nquery (&_res, domain, C_IN, type, answer, answer_length);
+}
+
+static int
+wrap_res_nsearch (int type, unsigned char *answer, int answer_length)
+{
+  return res_nquery (&_res, domain, C_IN, type, answer, answer_length);
+}
+
+static int
+wrap_res_nquerydomain (int type, unsigned char *answer, int answer_length)
+{
+  return res_nquerydomain (&_res, "www", "example.com", C_IN, type,
+                           answer, answer_length);
+}
+
+static int
+wrap_res_nsend (int type, unsigned char *answer, int answer_length)
+{
+  unsigned char buf[512];
+  int ret = res_nmkquery (&_res, QUERY, domain, C_IN, type,
+                         (const unsigned char *) "", 0, NULL,
+                         buf, sizeof (buf));
+  if (type < 0 || type >= 65536)
+    {
+      /* res_mkquery fails for out-of-range record types.  */
+      TEST_VERIFY_EXIT (ret == -1);
+      return -1;
+    }
+  TEST_VERIFY_EXIT (ret > 12);  /* DNS header length.  */
+  return res_nsend (&_res, buf, ret, answer, answer_length);
+}
+
+static void
+test_function (const char *fname,
+               int (*func) (int type,
+                            unsigned char *answer, int answer_length))
+{
+  unsigned char buf[512];
+  for (int tcp = 0; tcp < 2; ++tcp)
+    {
+      force_tcp = tcp;
+      for (unsigned int type = 1; type <= 65535; ++type)
+        {
+          if (test_verbose)
+            printf ("info: sending QTYPE %d with %s (tcp=%d)\n",
+                    type, fname, tcp);
+          int ret = func (type, buf, sizeof (buf));
+          if (ret != 47)
+            FAIL_EXIT1 ("%s tcp=%d qtype=%d return value %d",
+                        fname,tcp, type, ret);
+          /* One question, one answer record.  */
+          TEST_VERIFY (memcmp (buf + 4, "\0\1\0\1\0\0\0\0", 8) == 0);
+          /* Question section.  */
+          static const char qname[] = "\3www\7example\3com";
+          size_t qname_length = sizeof (qname);
+          TEST_VERIFY (memcmp (buf + 12, qname, qname_length) == 0);
+          /* RDATA part of answer.  */
+          uint16_t type16 = type;
+          TEST_VERIFY (memcmp (buf + ret - 2, &type16, sizeof (type16)) == 0);
+        }
+    }
+
+  TEST_VERIFY (func (-1, buf, sizeof (buf) == -1));
+  TEST_VERIFY (func (65536, buf, sizeof (buf) == -1));
+}
+
+static int
+do_test (void)
+{
+  struct resolv_redirect_config config =
+    {
+      .response_callback = response,
+    };
+  struct resolv_test *obj = resolv_test_start (config);
+
+  test_function ("res_query", &wrap_res_query);
+  test_function ("res_search", &wrap_res_search);
+  test_function ("res_querydomain", &wrap_res_querydomain);
+  test_function ("res_send", &wrap_res_send);
+
+  test_function ("res_nquery", &wrap_res_nquery);
+  test_function ("res_nsearch", &wrap_res_nsearch);
+  test_function ("res_nquerydomain", &wrap_res_nquerydomain);
+  test_function ("res_nsend", &wrap_res_nsend);
+
+  resolv_test_end (obj);
+  return 0;
+}
+
+#define TIMEOUT 300
+#include <support/test-driver.c>

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                     |   14 +++
 NEWS                          |    8 ++-
 include/arpa/nameser_compat.h |    6 +-
 resolv/Makefile               |    3 +
 resolv/nss_dns/dns-host.c     |    2 +-
 resolv/res_mkquery.c          |    4 +
 resolv/res_query.c            |    6 +-
 resolv/tst-resolv-qtypes.c    |  185 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 220 insertions(+), 8 deletions(-)
 create mode 100644 resolv/tst-resolv-qtypes.c


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]