summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott R. Parish <srparish@gmail.com>2016-05-13 23:16:03 -0700
committerScott R. Parish <srparish@gmail.com>2016-05-13 23:47:17 -0700
commit64f5845418a618c510e64c5daac7b194b4d9658e (patch)
treef04b7161054772e112765e9d42cb9e1a906ce5ee
parent3f0518ac4da155faaeb9b9fc3e81d11778f73448 (diff)
downloadnixpkgs-64f5845418a618c510e64c5daac7b194b4d9658e.tar
nixpkgs-64f5845418a618c510e64c5daac7b194b4d9658e.tar.gz
nixpkgs-64f5845418a618c510e64c5daac7b194b4d9658e.tar.bz2
nixpkgs-64f5845418a618c510e64c5daac7b194b4d9658e.tar.lz
nixpkgs-64f5845418a618c510e64c5daac7b194b4d9658e.tar.xz
nixpkgs-64f5845418a618c510e64c5daac7b194b4d9658e.tar.zst
nixpkgs-64f5845418a618c510e64c5daac7b194b4d9658e.zip
glibc: patch 2.23 for CVE-2016-3075, CVE-2016-1234, CVE-2016-3706
This addresses the following security advisories:

+ CVE-2016-3075: Stack overflow in _nss_dns_getnetbyname_r
+ CVE-2016-1234: glob: buffer overflow with GLOB_ALTDIRFUNC due to incorrect
                 NAME_MAX limit assumption
+ CVE-2016-3706: getaddrinfo: stack overflow in hostent conversion

Patches cherry-picked from glibc's release/2.23/master branch.

The "glob-simplify-interface.patch" was a dependency for
"cve-2016-1234.patch".
-rw-r--r--pkgs/development/libraries/glibc/common.nix5
-rw-r--r--pkgs/development/libraries/glibc/cve-2016-1234.patch372
-rw-r--r--pkgs/development/libraries/glibc/cve-2016-3075.patch35
-rw-r--r--pkgs/development/libraries/glibc/cve-2016-3706.patch181
-rw-r--r--pkgs/development/libraries/glibc/glob-simplify-interface.patch216
5 files changed, 809 insertions, 0 deletions
diff --git a/pkgs/development/libraries/glibc/common.nix b/pkgs/development/libraries/glibc/common.nix
index 893f65c3e20..a189edb9832 100644
--- a/pkgs/development/libraries/glibc/common.nix
+++ b/pkgs/development/libraries/glibc/common.nix
@@ -49,6 +49,11 @@ stdenv.mkDerivation ({
          "/bin:/usr/bin", which is inappropriate on NixOS machines. This
          patch extends the search path by "/run/current-system/sw/bin". */
       ./fix_path_attribute_in_getconf.patch
+
+      ./cve-2016-3075.patch
+      ./glob-simplify-interface.patch
+      ./cve-2016-1234.patch
+      ./cve-2016-3706.patch
     ];
 
   postPatch =
diff --git a/pkgs/development/libraries/glibc/cve-2016-1234.patch b/pkgs/development/libraries/glibc/cve-2016-1234.patch
new file mode 100644
index 00000000000..d98577868a9
--- /dev/null
+++ b/pkgs/development/libraries/glibc/cve-2016-1234.patch
@@ -0,0 +1,372 @@
+commit c87db3fcbdf890990b44d956621763538c878cd3
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed May 4 12:09:35 2016 +0200
+
+    CVE-2016-1234: glob: Do not copy d_name field of struct dirent [BZ #19779]
+    
+    Instead, we store the data we need from the return value of
+    readdir in an object of the new type struct readdir_result.
+    This type is independent of the layout of struct dirent.
+    
+    (cherry picked from commit 5171f3079f2cc53e0548fc4967361f4d1ce9d7ea)
+
+diff --git a/posix/bug-glob2.c b/posix/bug-glob2.c
+index 0fdc5d0..5873e08 100644
+--- a/posix/bug-glob2.c
++++ b/posix/bug-glob2.c
+@@ -40,6 +40,17 @@
+ # define PRINTF(fmt, args...)
+ #endif
+ 
++#define LONG_NAME \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ 
+ static struct
+ {
+@@ -58,6 +69,7 @@ static struct
+       { ".", 3, DT_DIR, 0755 },
+       { "..", 3, DT_DIR, 0755 },
+       { "a", 3, DT_REG, 0644 },
++      { LONG_NAME, 3, DT_REG, 0644 },
+     { "unreadable", 2, DT_DIR, 0111 },
+       { ".", 3, DT_DIR, 0111 },
+       { "..", 3, DT_DIR, 0755 },
+@@ -75,7 +87,7 @@ typedef struct
+   int level;
+   int idx;
+   struct dirent d;
+-  char room_for_dirent[NAME_MAX];
++  char room_for_dirent[sizeof (LONG_NAME)];
+ } my_DIR;
+ 
+ 
+diff --git a/posix/glob.c b/posix/glob.c
+index 9ae76ac..ea4b0b6 100644
+--- a/posix/glob.c
++++ b/posix/glob.c
+@@ -24,7 +24,9 @@
+ #include <errno.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <stdbool.h>
+ #include <stddef.h>
++#include <stdint.h>
+ 
+ /* Outcomment the following line for production quality code.  */
+ /* #define NDEBUG 1 */
+@@ -73,69 +75,8 @@
+ # endif /* HAVE_VMSDIR_H */
+ #endif
+ 
+-
+-/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+-   if the `d_type' member for `struct dirent' is available.
+-   HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB.  */
+-#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+-/* True if the directory entry D must be of type T.  */
+-# define DIRENT_MUST_BE(d, t)	((d)->d_type == (t))
+-
+-/* True if the directory entry D might be a symbolic link.  */
+-# define DIRENT_MIGHT_BE_SYMLINK(d) \
+-    ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
+-
+-/* True if the directory entry D might be a directory.  */
+-# define DIRENT_MIGHT_BE_DIR(d)	 \
+-    ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
+-
+-#else /* !HAVE_D_TYPE */
+-# define DIRENT_MUST_BE(d, t)		false
+-# define DIRENT_MIGHT_BE_SYMLINK(d)	true
+-# define DIRENT_MIGHT_BE_DIR(d)		true
+-#endif /* HAVE_D_TYPE */
+-
+-/* If the system has the `struct dirent64' type we use it internally.  */
+-#if defined _LIBC && !defined COMPILE_GLOB64
+-
+-# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+-#  define CONVERT_D_INO(d64, d32)
+-# else
+-#  define CONVERT_D_INO(d64, d32) \
+-  (d64)->d_ino = (d32)->d_ino;
+-# endif
+-
+-# ifdef _DIRENT_HAVE_D_TYPE
+-#  define CONVERT_D_TYPE(d64, d32) \
+-  (d64)->d_type = (d32)->d_type;
+-# else
+-#  define CONVERT_D_TYPE(d64, d32)
+-# endif
+-
+-# define CONVERT_DIRENT_DIRENT64(d64, d32) \
+-  strcpy ((d64)->d_name, (d32)->d_name);				      \
+-  CONVERT_D_INO (d64, d32)						      \
+-  CONVERT_D_TYPE (d64, d32)
+-#endif
+-
+-
+-#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+-/* Posix does not require that the d_ino field be present, and some
+-   systems do not provide it. */
+-# define REAL_DIR_ENTRY(dp) 1
+-#else
+-# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+-#endif /* POSIX */
+-
+ #include <stdlib.h>
+ #include <string.h>
+-
+-/* NAME_MAX is usually defined in <dirent.h> or <limits.h>.  */
+-#include <limits.h>
+-#ifndef NAME_MAX
+-# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name))
+-#endif
+-
+ #include <alloca.h>
+ 
+ #ifdef _LIBC
+@@ -180,8 +121,111 @@
+ 
+ static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
+ 
++/* A representation of a directory entry which does not depend on the
++   layout of struct dirent, or the size of ino_t.  */
++struct readdir_result
++{
++  const char *name;
++# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
++  uint8_t type;
++# endif
++  bool skip_entry;
++};
++
++# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
++/* Initializer based on the d_type member of struct dirent.  */
++#  define D_TYPE_TO_RESULT(source) (source)->d_type,
++
++/* True if the directory entry D might be a symbolic link.  */
++static bool
++readdir_result_might_be_symlink (struct readdir_result d)
++{
++  return d.type == DT_UNKNOWN || d.type == DT_LNK;
++}
++
++/* True if the directory entry D might be a directory.  */
++static bool
++readdir_result_might_be_dir (struct readdir_result d)
++{
++  return d.type == DT_DIR || readdir_result_might_be_symlink (d);
++}
++# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
++#  define D_TYPE_TO_RESULT(source)
++
++/* If we do not have type information, symbolic links and directories
++   are always a possibility.  */
++
++static bool
++readdir_result_might_be_symlink (struct readdir_result d)
++{
++  return true;
++}
++
++static bool
++readdir_result_might_be_dir (struct readdir_result d)
++{
++  return true;
++}
++
++# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
++
++# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
++/* Initializer for skip_entry.  POSIX does not require that the d_ino
++   field be present, and some systems do not provide it. */
++#  define D_INO_TO_RESULT(source) false,
++# else
++#  define D_INO_TO_RESULT(source) (source)->d_ino == 0,
++# endif
++
++/* Construct an initializer for a struct readdir_result object from a
++   struct dirent *.  No copy of the name is made.  */
++#define READDIR_RESULT_INITIALIZER(source) \
++  {					   \
++    source->d_name,			   \
++    D_TYPE_TO_RESULT (source)		   \
++    D_INO_TO_RESULT (source)		   \
++  }
++
+ #endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+ 
++/* Call gl_readdir on STREAM.  This macro can be overridden to reduce
++   type safety if an old interface version needs to be supported.  */
++#ifndef GL_READDIR
++# define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream))
++#endif
++
++/* Extract name and type from directory entry.  No copy of the name is
++   made.  If SOURCE is NULL, result name is NULL.  Keep in sync with
++   convert_dirent64 below.  */
++static struct readdir_result
++convert_dirent (const struct dirent *source)
++{
++  if (source == NULL)
++    {
++      struct readdir_result result = { NULL, };
++      return result;
++    }
++  struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
++  return result;
++}
++
++#ifndef COMPILE_GLOB64
++/* Like convert_dirent, but works on struct dirent64 instead.  Keep in
++   sync with convert_dirent above.  */
++static struct readdir_result
++convert_dirent64 (const struct dirent64 *source)
++{
++  if (source == NULL)
++    {
++      struct readdir_result result = { NULL, };
++      return result;
++    }
++  struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
++  return result;
++}
++#endif
++
++
+ #ifndef attribute_hidden
+ # define attribute_hidden
+ #endif
+@@ -1538,55 +1582,36 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
+ 
+ 	  while (1)
+ 	    {
+-	      const char *name;
+-#if defined _LIBC && !defined COMPILE_GLOB64
+-	      struct dirent64 *d;
+-	      union
+-		{
+-		  struct dirent64 d64;
+-		  char room [offsetof (struct dirent64, d_name[0])
+-			     + NAME_MAX + 1];
+-		}
+-	      d64buf;
+-
+-	      if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC))
+-		{
+-		  struct dirent *d32 = (*pglob->gl_readdir) (stream);
+-		  if (d32 != NULL)
+-		    {
+-		      CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
+-		      d = &d64buf.d64;
+-		    }
+-		  else
+-		    d = NULL;
+-		}
+-	      else
+-		d = __readdir64 (stream);
++	      struct readdir_result d;
++	      {
++		if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
++		  d = convert_dirent (GL_READDIR (pglob, stream));
++		else
++		  {
++#ifdef COMPILE_GLOB64
++		    d = convert_dirent (__readdir (stream));
+ #else
+-	      struct dirent *d = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+-				  ? ((struct dirent *)
+-				     (*pglob->gl_readdir) (stream))
+-				  : __readdir (stream));
++		    d = convert_dirent64 (__readdir64 (stream));
+ #endif
+-	      if (d == NULL)
++		  }
++	      }
++	      if (d.name == NULL)
+ 		break;
+-	      if (! REAL_DIR_ENTRY (d))
++	      if (d.skip_entry)
+ 		continue;
+ 
+ 	      /* If we shall match only directories use the information
+ 		 provided by the dirent call if possible.  */
+-	      if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
++	      if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
+ 		continue;
+ 
+-	      name = d->d_name;
+-
+-	      if (fnmatch (pattern, name, fnm_flags) == 0)
++	      if (fnmatch (pattern, d.name, fnm_flags) == 0)
+ 		{
+ 		  /* If the file we found is a symlink we have to
+ 		     make sure the target file exists.  */
+-		  if (!DIRENT_MIGHT_BE_SYMLINK (d)
+-		      || link_exists_p (dfd, directory, dirlen, name, pglob,
+-					flags))
++		  if (!readdir_result_might_be_symlink (d)
++		      || link_exists_p (dfd, directory, dirlen, d.name,
++					pglob, flags))
+ 		    {
+ 		      if (cur == names->count)
+ 			{
+@@ -1606,7 +1631,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
+ 			  names = newnames;
+ 			  cur = 0;
+ 			}
+-		      names->name[cur] = strdup (d->d_name);
++		      names->name[cur] = strdup (d.name);
+ 		      if (names->name[cur] == NULL)
+ 			goto memory_error;
+ 		      ++cur;
+diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c
+index b4fcd1a..802c957 100644
+--- a/sysdeps/unix/sysv/linux/i386/glob64.c
++++ b/sysdeps/unix/sysv/linux/i386/glob64.c
+@@ -1,3 +1,21 @@
++/* Two glob variants with 64-bit support, for dirent64 and __olddirent64.
++   Copyright (C) 1998-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 <dirent.h>
+ #include <glob.h>
+ #include <sys/stat.h>
+@@ -38,11 +56,15 @@ int __old_glob64 (const char *__pattern, int __flags,
+ 
+ #undef dirent
+ #define dirent __old_dirent64
++#undef GL_READDIR
++# define GL_READDIR(pglob, stream) \
++  ((struct __old_dirent64 *) (pglob)->gl_readdir (stream))
+ #undef __readdir
+ #define __readdir(dirp) __old_readdir64 (dirp)
+ #undef glob
+ #define glob(pattern, flags, errfunc, pglob) \
+   __old_glob64 (pattern, flags, errfunc, pglob)
++#define convert_dirent __old_convert_dirent
+ #define glob_in_dir __old_glob_in_dir
+ #define GLOB_ATTRIBUTE attribute_compat_text_section
+ 
diff --git a/pkgs/development/libraries/glibc/cve-2016-3075.patch b/pkgs/development/libraries/glibc/cve-2016-3075.patch
new file mode 100644
index 00000000000..0da10167bef
--- /dev/null
+++ b/pkgs/development/libraries/glibc/cve-2016-3075.patch
@@ -0,0 +1,35 @@
+commit 146b58d11fddbef15b888906e3be4f33900c416f
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Mar 29 12:57:56 2016 +0200
+
+    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)
+
+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)
+     {
diff --git a/pkgs/development/libraries/glibc/cve-2016-3706.patch b/pkgs/development/libraries/glibc/cve-2016-3706.patch
new file mode 100644
index 00000000000..cf9fb060355
--- /dev/null
+++ b/pkgs/development/libraries/glibc/cve-2016-3706.patch
@@ -0,0 +1,181 @@
+commit 1a8a7c12950a0026a3c406a7cb1608f96aa1460e
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Apr 29 10:35:34 2016 +0200
+
+    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)
+
+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
diff --git a/pkgs/development/libraries/glibc/glob-simplify-interface.patch b/pkgs/development/libraries/glibc/glob-simplify-interface.patch
new file mode 100644
index 00000000000..647cca8b3a6
--- /dev/null
+++ b/pkgs/development/libraries/glibc/glob-simplify-interface.patch
@@ -0,0 +1,216 @@
+commit 68302147ee061c69eb447e243ad9a18ef4cfbc4c
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Apr 29 09:33:07 2016 +0200
+
+    glob: Simplify the interface for the GLOB_ALTDIRFUNC callback gl_readdir
+    
+    Previously, application code had to set up the d_namlen member if
+    the target supported it, involving conditional compilation.  After
+    this change, glob will use the length of the string in d_name instead
+    of d_namlen to determine the file name length.  All glibc targets
+    provide the d_type and d_ino members, and setting them as needed for
+    gl_readdir is straightforward.
+    
+    Changing the behavior with regards to d_ino is left to a future
+    cleanup.
+    
+    (cherry picked from commit 137fe72eca6923a00381a3ca9f0e7672c1f85e3f)
+
+diff --git a/manual/examples/mkdirent.c b/manual/examples/mkdirent.c
+new file mode 100644
+index 0000000..f8400f4
+--- /dev/null
++++ b/manual/examples/mkdirent.c
+@@ -0,0 +1,42 @@
++/* Example for creating a struct dirent object for use with glob.
++   Copyright (C) 2016 Free Software Foundation, Inc.
++
++   This program is free software; you can redistribute it and/or
++   modify it under the terms of the GNU General Public License
++   as published by the Free Software Foundation; either version 2
++   of the License, or (at your option) any later version.
++
++   This program 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 General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, if not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <dirent.h>
++#include <errno.h>
++#include <stddef.h>
++#include <stdlib.h>
++#include <string.h>
++
++struct dirent *
++mkdirent (const char *name)
++{
++  size_t dirent_size = offsetof (struct dirent, d_name) + 1;
++  size_t name_length = strlen (name);
++  size_t total_size = dirent_size + name_length;
++  if (total_size < dirent_size)
++    {
++      errno = ENOMEM;
++      return NULL;
++    }
++  struct dirent *result = malloc (total_size);
++  if (result == NULL)
++    return NULL;
++  result->d_type = DT_UNKNOWN;
++  result->d_ino = 1;            /* Do not skip this entry.  */
++  memcpy (result->d_name, name, name_length + 1);
++  return result;
++}
+diff --git a/manual/pattern.texi b/manual/pattern.texi
+index d1b9275..565e7eb 100644
+--- a/manual/pattern.texi
++++ b/manual/pattern.texi
+@@ -237,7 +237,44 @@ function used to read the contents of a directory.  It is used if the
+ @code{GLOB_ALTDIRFUNC} bit is set in the flag parameter.  The type of
+ this field is @w{@code{struct dirent *(*) (void *)}}.
+ 
+-This is a GNU extension.
++An implementation of @code{gl_readdir} needs to initialize the following
++members of the @code{struct dirent} object:
++
++@table @code
++@item d_type
++This member should be set to the file type of the entry if it is known.
++Otherwise, the value @code{DT_UNKNOWN} can be used.  The @code{glob}
++function may use the specified file type to avoid callbacks in cases
++where the file type indicates that the data is not required.
++
++@item d_ino
++This member needs to be non-zero, otherwise @code{glob} may skip the
++current entry and call the @code{gl_readdir} callback function again to
++retrieve another entry.
++
++@item d_name
++This member must be set to the name of the entry.  It must be
++null-terminated.
++@end table
++
++The example below shows how to allocate a @code{struct dirent} object
++containing a given name.
++
++@smallexample
++@include mkdirent.c.texi
++@end smallexample
++
++The @code{glob} function reads the @code{struct dirent} members listed
++above and makes a copy of the file name in the @code{d_name} member
++immediately after the @code{gl_readdir} callback function returns.
++Future invocations of any of the callback functions may dealloacte or
++reuse the buffer.  It is the responsibility of the caller of the
++@code{glob} function to allocate and deallocate the buffer, around the
++call to @code{glob} or using the callback functions.  For example, an
++application could allocate the buffer in the @code{gl_readdir} callback
++function, and deallocate it in the @code{gl_closedir} callback function.
++
++The @code{gl_readdir} member is a GNU extension.
+ 
+ @item gl_opendir
+ The address of an alternative implementation of the @code{opendir}
+diff --git a/posix/bug-glob2.c b/posix/bug-glob2.c
+index ddf5ec9..0fdc5d0 100644
+--- a/posix/bug-glob2.c
++++ b/posix/bug-glob2.c
+@@ -193,7 +193,7 @@ my_readdir (void *gdir)
+       return NULL;
+     }
+ 
+-  dir->d.d_ino = dir->idx;
++  dir->d.d_ino = 1;		/* glob should not skip this entry.  */
+ 
+ #ifdef _DIRENT_HAVE_D_TYPE
+   dir->d.d_type = filesystem[dir->idx].type;
+diff --git a/posix/glob.c b/posix/glob.c
+index 0c04c3c..9ae76ac 100644
+--- a/posix/glob.c
++++ b/posix/glob.c
+@@ -57,10 +57,8 @@
+ 
+ #if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+ # include <dirent.h>
+-# define NAMLEN(dirent) strlen((dirent)->d_name)
+ #else
+ # define dirent direct
+-# define NAMLEN(dirent) (dirent)->d_namlen
+ # ifdef HAVE_SYS_NDIR_H
+ #  include <sys/ndir.h>
+ # endif
+@@ -76,12 +74,6 @@
+ #endif
+ 
+ 
+-/* In GNU systems, <dirent.h> defines this macro for us.  */
+-#ifdef _D_NAMLEN
+-# undef NAMLEN
+-# define NAMLEN(d) _D_NAMLEN(d)
+-#endif
+-
+ /* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+    if the `d_type' member for `struct dirent' is available.
+    HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB.  */
+@@ -105,12 +97,6 @@
+ 
+ /* If the system has the `struct dirent64' type we use it internally.  */
+ #if defined _LIBC && !defined COMPILE_GLOB64
+-# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+-#  define CONVERT_D_NAMLEN(d64, d32)
+-# else
+-#  define CONVERT_D_NAMLEN(d64, d32) \
+-  (d64)->d_namlen = (d32)->d_namlen;
+-# endif
+ 
+ # if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+ #  define CONVERT_D_INO(d64, d32)
+@@ -127,8 +113,7 @@
+ # endif
+ 
+ # define CONVERT_DIRENT_DIRENT64(d64, d32) \
+-  memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1);		      \
+-  CONVERT_D_NAMLEN (d64, d32)						      \
++  strcpy ((d64)->d_name, (d32)->d_name);				      \
+   CONVERT_D_INO (d64, d32)						      \
+   CONVERT_D_TYPE (d64, d32)
+ #endif
+@@ -1554,7 +1539,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
+ 	  while (1)
+ 	    {
+ 	      const char *name;
+-	      size_t len;
+ #if defined _LIBC && !defined COMPILE_GLOB64
+ 	      struct dirent64 *d;
+ 	      union
+@@ -1622,12 +1606,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
+ 			  names = newnames;
+ 			  cur = 0;
+ 			}
+-		      len = NAMLEN (d);
+-		      names->name[cur] = (char *) malloc (len + 1);
++		      names->name[cur] = strdup (d->d_name);
+ 		      if (names->name[cur] == NULL)
+ 			goto memory_error;
+-		      *((char *) mempcpy (names->name[cur++], name, len))
+-			= '\0';
++		      ++cur;
+ 		      ++nfound;
+ 		    }
+ 		}
+diff --git a/posix/tst-gnuglob.c b/posix/tst-gnuglob.c
+index 992b997..b7b859b 100644
+--- a/posix/tst-gnuglob.c
++++ b/posix/tst-gnuglob.c
+@@ -211,7 +211,7 @@ my_readdir (void *gdir)
+       return NULL;
+     }
+ 
+-  dir->d.d_ino = dir->idx;
++  dir->d.d_ino = 1;		/* glob should not skip this entry.  */
+ 
+ #ifdef _DIRENT_HAVE_D_TYPE
+   dir->d.d_type = filesystem[dir->idx].type;