~ruther/guix-local

a0ae64a334ce4dda269828bbb3c9182842e5cd50 — Efraim Flashner 8 years ago 575e5e4
gnu: glibc@2.23: Fix CVE-2015-5180, CVE-2016-{3075,3706,4429}.

* gnu/packages/base.scm (glibc@2.23)[source]: Add patches.
* gnu/packages/patches/glibc-CVE-2016-3075.patch,
gnu/packages/patches/glibc-CVE-2016-3706.patch,
gnu/packages/patches/glibc-CVE-2016-4429.patch: New files.
* gnu/local.mk (dist_patch_DATA): Register them.
M gnu/local.mk => gnu/local.mk +3 -0
@@ 645,6 645,9 @@ dist_patch_DATA =						\
  %D%/packages/patches/glib-networking-ssl-cert-file.patch	\
  %D%/packages/patches/glib-tests-timer.patch			\
  %D%/packages/patches/glibc-CVE-2015-5180.patch		\
  %D%/packages/patches/glibc-CVE-2016-3075.patch		\
  %D%/packages/patches/glibc-CVE-2016-3706.patch		\
  %D%/packages/patches/glibc-CVE-2016-4429.patch		\
  %D%/packages/patches/glibc-CVE-2017-1000366-pt1.patch		\
  %D%/packages/patches/glibc-CVE-2017-1000366-pt2.patch		\
  %D%/packages/patches/glibc-CVE-2017-1000366-pt3.patch		\

M gnu/packages/base.scm => gnu/packages/base.scm +4 -0
@@ 953,6 953,10 @@ GLIBC/HURD for a Hurd host"
                                       "glibc-versioned-locpath.patch"
                                       "glibc-o-largefile.patch"
                                       "glibc-vectorized-strcspn-guards.patch"
                                       "glibc-CVE-2015-5180.patch"
                                       "glibc-CVE-2016-3075.patch"
                                       "glibc-CVE-2016-3706.patch"
                                       "glibc-CVE-2016-4429.patch"
                                       "glibc-CVE-2017-1000366-pt1.patch"
                                       "glibc-CVE-2017-1000366-pt2.patch"
                                       "glibc-CVE-2017-1000366-pt3.patch"))))))

A gnu/packages/patches/glibc-CVE-2016-3075.patch => gnu/packages/patches/glibc-CVE-2016-3075.patch +43 -0
@@ 0,0 1,43 @@
From 146b58d11fddbef15b888906e3be4f33900c416f Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Tue, 29 Mar 2016 12:57:56 +0200
Subject: [PATCH] CVE-2016-3075: Stack overflow in _nss_dns_getnetbyname_r [BZ
 #19879]

The defensive copy is not needed because the name may not alias the
output buffer.

(cherry picked from commit 317b199b4aff8cfa27f2302ab404d2bb5032b9a4)
(cherry picked from commit 883dceebc8f11921a9890211a4e202e5be17562f)
---
 ChangeLog                    |  7 +++++++
 NEWS                         | 10 ++++++++--
 resolv/nss_dns/dns-network.c |  5 +----
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index 2eb2f67..8f301a7 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -118,17 +118,14 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
   } net_buffer;
   querybuf *orig_net_buffer;
   int anslen;
-  char *qbuf;
   enum nss_status status;
 
   if (__res_maybe_init (&_res, 0) == -1)
     return NSS_STATUS_UNAVAIL;
 
-  qbuf = strdupa (name);
-
   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
 
-  anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+  anslen = __libc_res_nsearch (&_res, name, C_IN, T_PTR, net_buffer.buf->buf,
 			       1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
   if (anslen < 0)
     {
-- 
2.9.3


A gnu/packages/patches/glibc-CVE-2016-3706.patch => gnu/packages/patches/glibc-CVE-2016-3706.patch +188 -0
@@ 0,0 1,188 @@
From 1a8a7c12950a0026a3c406a7cb1608f96aa1460e Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 29 Apr 2016 10:35:34 +0200
Subject: [PATCH] CVE-2016-3706: getaddrinfo: stack overflow in hostent
 conversion [BZ #20010]

When converting a struct hostent response to struct gaih_addrtuple, the
gethosts macro (which is called from gaih_inet) used alloca, without
malloc fallback for large responses.  This commit changes this code to
use calloc unconditionally.

This commit also consolidated a second hostent-to-gaih_addrtuple
conversion loop (in gaih_inet) to use the new conversion function.

(cherry picked from commit 4ab2ab03d4351914ee53248dc5aef4a8c88ff8b9)
---
 ChangeLog                   |  10 ++++
 sysdeps/posix/getaddrinfo.c | 130 +++++++++++++++++++++++---------------------
 2 files changed, 79 insertions(+), 61 deletions(-)

diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 1ef3f20..fed2d3b 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -168,9 +168,58 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
   return 0;
 }
 
+/* Convert struct hostent to a list of struct gaih_addrtuple objects.
+   h_name is not copied, and the struct hostent object must not be
+   deallocated prematurely.  *RESULT must be NULL or a pointer to an
+   object allocated using malloc, which is freed.  */
+static bool
+convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
+				   int family,
+				   struct hostent *h,
+				   struct gaih_addrtuple **result)
+{
+  free (*result);
+  *result = NULL;
+
+  /* Count the number of addresses in h->h_addr_list.  */
+  size_t count = 0;
+  for (char **p = h->h_addr_list; *p != NULL; ++p)
+    ++count;
+
+  /* Report no data if no addresses are available, or if the incoming
+     address size is larger than what we can store.  */
+  if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
+    return true;
+
+  struct gaih_addrtuple *array = calloc (count, sizeof (*array));
+  if (array == NULL)
+    return false;
+
+  for (size_t i = 0; i < count; ++i)
+    {
+      if (family == AF_INET && req->ai_family == AF_INET6)
+	{
+	  /* Perform address mapping. */
+	  array[i].family = AF_INET6;
+	  memcpy(array[i].addr + 3, h->h_addr_list[i], sizeof (uint32_t));
+	  array[i].addr[2] = htonl (0xffff);
+	}
+      else
+	{
+	  array[i].family = family;
+	  memcpy (array[i].addr, h->h_addr_list[i], h->h_length);
+	}
+      array[i].next = array + i + 1;
+    }
+  array[0].name = h->h_name;
+  array[count - 1].next = NULL;
+
+  *result = array;
+  return true;
+}
+
 #define gethosts(_family, _type) \
  {									      \
-  int i;								      \
   int herrno;								      \
   struct hostent th;							      \
   struct hostent *h;							      \
@@ -219,36 +268,23 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
     }									      \
   else if (h != NULL)							      \
     {									      \
-      for (i = 0; h->h_addr_list[i]; i++)				      \
+      /* Make sure that addrmem can be freed.  */			      \
+      if (!malloc_addrmem)						      \
+	addrmem = NULL;							      \
+      if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem))      \
 	{								      \
-	  if (*pat == NULL)						      \
-	    {								      \
-	      *pat = __alloca (sizeof (struct gaih_addrtuple));		      \
-	      (*pat)->scopeid = 0;					      \
-	    }								      \
-	  uint32_t *addr = (*pat)->addr;				      \
-	  (*pat)->next = NULL;						      \
-	  (*pat)->name = i == 0 ? strdupa (h->h_name) : NULL;		      \
-	  if (_family == AF_INET && req->ai_family == AF_INET6)		      \
-	    {								      \
-	      (*pat)->family = AF_INET6;				      \
-	      addr[3] = *(uint32_t *) h->h_addr_list[i];		      \
-	      addr[2] = htonl (0xffff);					      \
-	      addr[1] = 0;						      \
-	      addr[0] = 0;						      \
-	    }								      \
-	  else								      \
-	    {								      \
-	      (*pat)->family = _family;					      \
-	      memcpy (addr, h->h_addr_list[i], sizeof(_type));		      \
-	    }								      \
-	  pat = &((*pat)->next);					      \
+	  _res.options |= old_res_options & RES_USE_INET6;		      \
+	  result = -EAI_SYSTEM;						      \
+	  goto free_and_return;						      \
 	}								      \
+      *pat = addrmem;							      \
+      /* The conversion uses malloc unconditionally.  */		      \
+      malloc_addrmem = true;						      \
 									      \
       if (localcanon !=	NULL && canon == NULL)				      \
 	canon = strdupa (localcanon);					      \
 									      \
-      if (_family == AF_INET6 && i > 0)					      \
+      if (_family == AF_INET6 && *pat != NULL)				      \
 	got_ipv6 = true;						      \
     }									      \
  }
@@ -612,44 +648,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		{
 		  if (h != NULL)
 		    {
-		      int i;
-		      /* We found data, count the number of addresses.  */
-		      for (i = 0; h->h_addr_list[i]; ++i)
-			;
-		      if (i > 0 && *pat != NULL)
-			--i;
-
-		      if (__libc_use_alloca (alloca_used
-					     + i * sizeof (struct gaih_addrtuple)))
-			addrmem = alloca_account (i * sizeof (struct gaih_addrtuple),
-						  alloca_used);
-		      else
-			{
-			  addrmem = malloc (i
-					    * sizeof (struct gaih_addrtuple));
-			  if (addrmem == NULL)
-			    {
-			      result = -EAI_MEMORY;
-			      goto free_and_return;
-			    }
-			  malloc_addrmem = true;
-			}
-
-		      /* Now convert it into the list.  */
-		      struct gaih_addrtuple *addrfree = addrmem;
-		      for (i = 0; h->h_addr_list[i]; ++i)
+		      /* We found data, convert it.  */
+		      if (!convert_hostent_to_gaih_addrtuple
+			  (req, AF_INET, h, &addrmem))
 			{
-			  if (*pat == NULL)
-			    {
-			      *pat = addrfree++;
-			      (*pat)->scopeid = 0;
-			    }
-			  (*pat)->next = NULL;
-			  (*pat)->family = AF_INET;
-			  memcpy ((*pat)->addr, h->h_addr_list[i],
-				  h->h_length);
-			  pat = &((*pat)->next);
+			  result = -EAI_MEMORY;
+			  goto free_and_return;
 			}
+		      *pat = addrmem;
+		      /* The conversion uses malloc unconditionally.  */
+		      malloc_addrmem = true;
 		    }
 		}
 	      else
-- 
2.9.3


A gnu/packages/patches/glibc-CVE-2016-4429.patch => gnu/packages/patches/glibc-CVE-2016-4429.patch +58 -0
@@ 0,0 1,58 @@
From bdce95930e1d9a7d013d1ba78740243491262879 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Mon, 23 May 2016 20:18:34 +0200
Subject: [PATCH] CVE-2016-4429: sunrpc: Do not use alloca in clntudp_call [BZ
 #20112]

The call is technically in a loop, and under certain circumstances
(which are quite difficult to reproduce in a test case), alloca
can be invoked repeatedly during a single call to clntudp_call.
As a result, the available stack space can be exhausted (even
though individual alloca sizes are bounded implicitly by what
can fit into a UDP packet, as a side effect of the earlier
successful send operation).

(cherry picked from commit bc779a1a5b3035133024b21e2f339fe4219fb11c)
---
 ChangeLog         |  7 +++++++
 NEWS              |  4 ++++
 sunrpc/clnt_udp.c | 10 +++++++++-
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
index a6cf5f1..4d9acb1 100644
--- a/sunrpc/clnt_udp.c
+++ b/sunrpc/clnt_udp.c
@@ -388,9 +388,15 @@ send_again:
 	  struct sock_extended_err *e;
 	  struct sockaddr_in err_addr;
 	  struct iovec iov;
-	  char *cbuf = (char *) alloca (outlen + 256);
+	  char *cbuf = malloc (outlen + 256);
 	  int ret;
 
+	  if (cbuf == NULL)
+	    {
+	      cu->cu_error.re_errno = errno;
+	      return (cu->cu_error.re_status = RPC_CANTRECV);
+	    }
+
 	  iov.iov_base = cbuf + 256;
 	  iov.iov_len = outlen;
 	  msg.msg_name = (void *) &err_addr;
@@ -415,10 +421,12 @@ send_again:
 		 cmsg = CMSG_NXTHDR (&msg, cmsg))
 	      if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
 		{
+		  free (cbuf);
 		  e = (struct sock_extended_err *) CMSG_DATA(cmsg);
 		  cu->cu_error.re_errno = e->ee_errno;
 		  return (cu->cu_error.re_status = RPC_CANTRECV);
 		}
+	  free (cbuf);
 	}
 #endif
       do
-- 
2.9.3