64f5845418
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".
217 lines
7.2 KiB
Diff
217 lines
7.2 KiB
Diff
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;
|