diff --git a/glibc-rh1315648-1.patch b/glibc-rh1315648-1.patch new file mode 100644 index 0000000..ef6c5e2 --- /dev/null +++ b/glibc-rh1315648-1.patch @@ -0,0 +1,213 @@ +commit 137fe72eca6923a00381a3ca9f0e7672c1f85e3f +Author: Florian Weimer +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. + +Index: b/manual/examples/mkdirent.c +=================================================================== +--- /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 . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++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; ++} +Index: b/manual/pattern.texi +=================================================================== +--- a/manual/pattern.texi ++++ b/manual/pattern.texi +@@ -237,7 +237,44 @@ function used to read the contents of a + @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} +Index: b/posix/bug-glob2.c +=================================================================== +--- 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; +Index: b/posix/glob.c +=================================================================== +--- a/posix/glob.c ++++ b/posix/glob.c +@@ -57,10 +57,8 @@ + + #if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ + # include +-# define NAMLEN(dirent) strlen((dirent)->d_name) + #else + # define dirent direct +-# define NAMLEN(dirent) (dirent)->d_namlen + # ifdef HAVE_SYS_NDIR_H + # include + # endif +@@ -76,12 +74,6 @@ + #endif + + +-/* In GNU systems, 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 +@@ -1562,7 +1547,6 @@ glob_in_dir (const char *pattern, const + while (1) + { + const char *name; +- size_t len; + #if defined _LIBC && !defined COMPILE_GLOB64 + struct dirent64 *d; + union +@@ -1630,12 +1614,10 @@ glob_in_dir (const char *pattern, const + 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; + } + } +Index: b/posix/tst-gnuglob.c +=================================================================== +--- 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; diff --git a/glibc-rh1315648-2.patch b/glibc-rh1315648-2.patch new file mode 100644 index 0000000..7357100 --- /dev/null +++ b/glibc-rh1315648-2.patch @@ -0,0 +1,370 @@ +commit 5171f3079f2cc53e0548fc4967361f4d1ce9d7ea +Author: Florian Weimer +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. + +Index: b/posix/bug-glob2.c +=================================================================== +--- 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; + + +Index: b/posix/glob.c +=================================================================== +--- a/posix/glob.c ++++ b/posix/glob.c +@@ -24,7 +24,9 @@ + #include + #include + #include ++#include + #include ++#include + + /* 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 + #include +- +-/* NAME_MAX is usually defined in or . */ +-#include +-#ifndef NAME_MAX +-# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name)) +-#endif +- + #include + + #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 +@@ -1546,55 +1590,36 @@ glob_in_dir (const char *pattern, const + + 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) + { +@@ -1614,7 +1639,7 @@ glob_in_dir (const char *pattern, const + 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; +Index: b/sysdeps/unix/sysv/linux/i386/glob64.c +=================================================================== +--- 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 ++ . */ ++ + #include + #include + #include +@@ -38,11 +56,15 @@ int __old_glob64 (const char *__pattern, + + #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/glibc.spec b/glibc.spec index bb9a6a5..320c2fd 100644 --- a/glibc.spec +++ b/glibc.spec @@ -243,6 +243,8 @@ Patch1020: glibc-rh1333901-2.patch Patch1021: glibc-rh1333901-3.patch Patch1022: glibc-rh1333901-4.patch Patch1023: glibc-rh1333901-5.patch +Patch1024: glibc-rh1315648-1.patch +Patch1025: glibc-rh1315648-2.patch ############################################################################## # @@ -685,6 +687,8 @@ microbenchmark tests on the system. %patch1021 -p1 %patch1022 -p1 %patch1023 -p1 +%patch1024 -p1 +%patch1025 -p1 %patch0059 -p1 ############################################################################## @@ -1907,6 +1911,7 @@ rm -f *.filelist* %changelog * Fri May 6 2016 Florian Weimer - 2.22-14 - Fix getnameinfo memory leak and incorrect truncation (#1333901) +- CVE-2016-1234: buffer overflow in glob with GLOB_ALTDIRFUNC (#1315648) * Fri May 6 2016 Florian Weimer - 2.22-13 - Avoid build failure in TZ tests (#1333940)