From: Michael Tremer Date: Tue, 27 Jan 2015 21:01:24 +0000 (+0100) Subject: glibc: Backport hotfixes from RHEL X-Git-Tag: v2.17-core87~36 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fe875de81331d600a78df66e92ac6647d5e91578;p=people%2Fstevee%2Fipfire-2.x.git glibc: Backport hotfixes from RHEL --- diff --git a/lfs/glibc b/lfs/glibc index df3e39224f..11d374e3b8 100644 --- a/lfs/glibc +++ b/lfs/glibc @@ -268,12 +268,21 @@ endif cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966775.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966778.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970090.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh995972.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1008310.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1019916.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1022022.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1091162.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1098050.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027101.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027261.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1032628.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1044628.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1111460.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-1.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-2.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1139571.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1154563.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1170121.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1183533.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-resolv-stack_chk_fail.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-remove-ctors-dtors-output-sections.patch diff --git a/src/patches/glibc/glibc-rh1019916.patch b/src/patches/glibc/glibc-rh1019916.patch new file mode 100644 index 0000000000..f67af90c4f --- /dev/null +++ b/src/patches/glibc/glibc-rh1019916.patch @@ -0,0 +1,39 @@ +commit 48b67d71ec677d1b3168e52a68b644784cead604 +Author: Andreas Schwab +Date: Wed Sep 14 12:12:25 2011 +0200 + + Also relocate in dependency order when doing symbol dependency testing + +diff --git a/elf/rtld.c b/elf/rtld.c +index 764140d..324d979 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2027,24 +2027,21 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + { + /* We have to do symbol dependency testing. */ + struct relocate_args args; +- struct link_map *l; ++ unsigned int i; + + args.reloc_mode = GLRO(dl_lazy) ? RTLD_LAZY : 0; + +- l = main_map; +- while (l->l_next != NULL) +- l = l->l_next; +- do ++ i = main_map->l_searchlist.r_nlist; ++ while (i-- > 0) + { ++ struct link_map *l = main_map->l_initfini[i]; + if (l != &GL(dl_rtld_map) && ! l->l_faked) + { + args.l = l; + _dl_receive_error (print_unresolved, relocate_doit, + &args); + } +- l = l->l_prev; + } +- while (l != NULL); + + if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) + && rtld_multiple_ref) diff --git a/src/patches/glibc/glibc-rh1091162.patch b/src/patches/glibc/glibc-rh1027101.patch similarity index 100% rename from src/patches/glibc/glibc-rh1091162.patch rename to src/patches/glibc/glibc-rh1027101.patch diff --git a/src/patches/glibc/glibc-rh1027261.patch b/src/patches/glibc/glibc-rh1027261.patch new file mode 100644 index 0000000000..8599cf02e2 --- /dev/null +++ b/src/patches/glibc/glibc-rh1027261.patch @@ -0,0 +1,28 @@ +commit 4d653a59ffeae0f46f76a40230e2cfa9587b7e7e +Author: Siddhesh Poyarekar +Date: Fri May 30 22:43:52 2014 +0530 + + Add mmap usage in malloc_info output + + The current malloc_info xml output only has information about + allocations on the heap. Display information about number of mappings + and total mmapped size to this to complete the picture. + +diff -pruN a/malloc/malloc.c b/malloc/malloc.c +--- a/malloc/malloc.c 2014-06-02 07:35:22.573256155 +0530 ++++ b/malloc/malloc.c 2014-06-02 07:34:58.856257177 +0530 +@@ -6553,12 +6553,14 @@ malloc_info (int options, FILE *fp) + fprintf (fp, + "\n" + "\n" ++ "\n" + "\n" + "\n" + "\n" + "\n" + "\n", + total_nfastblocks, total_fastavail, total_nblocks, total_avail, ++ mp_.n_mmaps, mp_.mmapped_mem, + total_system, total_max_system, + total_aspace, total_aspace_mprotect); + diff --git a/src/patches/glibc/glibc-rh1032628.patch b/src/patches/glibc/glibc-rh1032628.patch new file mode 100644 index 0000000000..6140c190d6 --- /dev/null +++ b/src/patches/glibc/glibc-rh1032628.patch @@ -0,0 +1,166 @@ +commit 028478fa40d85a73b19638dbe3f83b1acebf370c +Author: Ulrich Drepper +Date: Thu Mar 10 12:51:33 2011 -0500 + + Fix copy relocations handling of unique objects. + + 2011-03-06 Ulrich Drepper + +and a part of: + +commit 33f85a3fb9fe432e0ebf6a3481bc2d5e29cb605f +Author: Ulrich Drepper +Date: Thu Mar 10 03:18:21 2011 -0500 + + Don't run tests checking xecutable stack when SELinux is enforcing. + +since the latter incorrectly had a bit of the former changes. + +Additionally, the test case needs -lstdc++ to build. + +diff --git a/elf/Makefile b/elf/Makefile +index c427679..56cb1b1 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -201,7 +201,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ + unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \ + tst-audit1 tst-audit2 tst-audit9 \ + tst-stackguard1 tst-addr1 tst-thrlock \ +- tst-unique1 tst-unique2 ++ tst-unique1 tst-unique2 tst-unique3 + # reldep9 + test-srcs = tst-pathopt + tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog +@@ -255,6 +255,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + order2mod1 order2mod2 order2mod3 order2mod4 \ + tst-unique1mod1 tst-unique1mod2 \ + tst-unique2mod1 tst-unique2mod2 \ ++ tst-unique3lib tst-unique3lib2 \ + tst-auditmod9a tst-auditmod9b + ifeq (yes,$(have-initfini-array)) + modules-names += tst-array2dep tst-array5dep +@@ -1178,6 +1179,11 @@ $(objpfx)tst-unique1.out: $(objpfx)tst-unique1mod1.so \ + $(objpfx)tst-unique2: $(libdl) $(objpfx)tst-unique2mod1.so + $(objpfx)tst-unique2.out: $(objpfx)tst-unique2mod2.so + ++LDLIBS-tst-unique3lib.so = -lstdc++ ++LDLIBS-tst-unique3lib2.so = -lstdc++ ++$(objpfx)tst-unique3: $(libdl) $(objpfx)tst-unique3lib.so ++$(objpfx)tst-unique3.out: $(objpfx)tst-unique3lib2.so ++ + ifeq (yes,$(config-cflags-avx)) + CFLAGS-tst-audit4.c += -mavx + CFLAGS-tst-auditmod4a.c += -mavx +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 78c8669..874a4bb 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -364,8 +363,19 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + if (entries[idx].hashval == new_hash + && strcmp (entries[idx].name, undef_name) == 0) + { +- result->s = entries[idx].sym; +- result->m = (struct link_map *) entries[idx].map; ++ if ((type_class & ELF_RTYPE_CLASS_COPY) != 0) ++ { ++ /* We possibly have to initialize the central ++ copy from the copy addressed through the ++ relocation. */ ++ result->s = sym; ++ result->m = (struct link_map *) map; ++ } ++ else ++ { ++ result->s = entries[idx].sym; ++ result->m = (struct link_map *) entries[idx].map; ++ } + __rtld_lock_unlock_recursive (tab->lock); + return 1; + } +diff --git a/elf/tst-unique3.cc b/elf/tst-unique3.cc +new file mode 100644 +index 0000000..b2c9593 +--- /dev/null ++++ b/elf/tst-unique3.cc +@@ -0,0 +1,23 @@ ++#include "tst-unique3.h" ++#include ++#include "../dlfcn/dlfcn.h" ++ ++int t = S::i; ++ ++int ++main (void) ++{ ++ std::printf ("%d %d\n", S::i, t); ++ int result = S::i++ != 1 || t != 1; ++ result |= in_lib (); ++ void *d = dlopen ("$ORIGIN/tst-unique3lib2.so", RTLD_LAZY); ++ int (*fp) (); ++ if (d == NULL || (fp = (int(*)()) dlsym (d, "in_lib2")) == NULL) ++ { ++ std::printf ("failed to get symbol in_lib2\n"); ++ return 1; ++ } ++ result |= fp (); ++ dlclose (d); ++ return result; ++} +diff --git a/elf/tst-unique3.h b/elf/tst-unique3.h +new file mode 100644 +index 0000000..716d236 +--- /dev/null ++++ b/elf/tst-unique3.h +@@ -0,0 +1,8 @@ ++// BZ 12510 ++template ++struct S ++{ ++ static int i; ++}; ++ ++extern int in_lib (void); +diff --git a/elf/tst-unique3lib.cc b/elf/tst-unique3lib.cc +new file mode 100644 +index 0000000..fa8e85a +--- /dev/null ++++ b/elf/tst-unique3lib.cc +@@ -0,0 +1,11 @@ ++#include ++#include "tst-unique3.h" ++template int S::i = 1; ++static int i = S::i; ++ ++int ++in_lib (void) ++{ ++ std::printf ("in_lib: %d %d\n", S::i, i); ++ return S::i++ != 2 || i != 1; ++} +diff --git a/elf/tst-unique3lib2.cc b/elf/tst-unique3lib2.cc +new file mode 100644 +index 0000000..17d817e +--- /dev/null ++++ b/elf/tst-unique3lib2.cc +@@ -0,0 +1,12 @@ ++#include ++#include "tst-unique3.h" ++ ++template int S::i; ++ ++extern "C" ++int ++in_lib2 () ++{ ++ std::printf ("in_lib2: %d\n", S::i); ++ return S::i != 3; ++} +diff --git a/include/bits/dlfcn.h b/include/bits/dlfcn.h +index cb4a5c2..c31a645 100644 +--- a/include/bits/dlfcn.h ++++ b/include/bits/dlfcn.h +@@ -1,4 +1,3 @@ + #include_next + +-extern void _dl_mcount_wrapper_check (void *__selfpc); + libc_hidden_proto (_dl_mcount_wrapper_check) diff --git a/src/patches/glibc/glibc-rh1098050.patch b/src/patches/glibc/glibc-rh1044628.patch similarity index 100% rename from src/patches/glibc/glibc-rh1098050.patch rename to src/patches/glibc/glibc-rh1044628.patch diff --git a/src/patches/glibc/glibc-rh1111460.patch b/src/patches/glibc/glibc-rh1111460.patch new file mode 100644 index 0000000000..1a4315d5bf --- /dev/null +++ b/src/patches/glibc/glibc-rh1111460.patch @@ -0,0 +1,341 @@ +commit 7cbcdb3699584db8913ca90f705d6337633ee10f +Author: Siddhesh Poyarekar +Date: Fri Oct 25 10:22:12 2013 +0530 + + Fix stack overflow due to large AF_INET6 requests + + Resolves #16072 (CVE-2013-4458). + + This patch fixes another stack overflow in getaddrinfo when it is + called with AF_INET6. The AF_UNSPEC case was fixed as CVE-2013-1914, + but the AF_INET6 case went undetected back then. + +commit 91ce40854d0b7f865cf5024ef95a8026b76096f3 +Author: Florian Weimer +Date: Fri Aug 16 09:38:52 2013 +0200 + + CVE-2013-4237, BZ #14699: Buffer overflow in readdir_r + + * sysdeps/posix/dirstream.h (struct __dirstream): Add errcode + member. + * sysdeps/posix/opendir.c (__alloc_dir): Initialize errcode + member. + * sysdeps/posix/rewinddir.c (rewinddir): Reset errcode member. + * sysdeps/posix/readdir_r.c (__READDIR_R): Enforce NAME_MAX limit. + Return delayed error code. Remove GETDENTS_64BIT_ALIGNED + conditional. + * sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c: Do not define + GETDENTS_64BIT_ALIGNED. + * sysdeps/unix/sysv/linux/i386/readdir64_r.c: Likewise. + * manual/filesys.texi (Reading/Closing Directory): Document + ENAMETOOLONG return value of readdir_r. Recommend readdir more + strongly. + * manual/conf.texi (Limits for Files): Add portability note to + NAME_MAX, PATH_MAX. + (Pathconf): Add portability note for _PC_NAME_MAX, _PC_PATH_MAX. + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index e6ce4cf..8ff74b4 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -197,7 +197,22 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + &rc, &herrno, NULL, &localcanon)); \ + if (rc != ERANGE || herrno != NETDB_INTERNAL) \ + break; \ +- tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ ++ if (!malloc_tmpbuf && __libc_use_alloca (alloca_used + 2 * tmpbuflen)) \ ++ tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen, 2 * tmpbuflen, \ ++ alloca_used); \ ++ else \ ++ { \ ++ char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL, \ ++ 2 * tmpbuflen); \ ++ if (newp == NULL) \ ++ { \ ++ result = -EAI_MEMORY; \ ++ goto free_and_return; \ ++ } \ ++ tmpbuf = newp; \ ++ malloc_tmpbuf = true; \ ++ tmpbuflen = 2 * tmpbuflen; \ ++ } \ + } \ + if (status == NSS_STATUS_SUCCESS && rc == 0) \ + h = &th; \ +@@ -209,7 +224,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + { \ + __set_h_errno (herrno); \ + _res.options = old_res_options; \ +- return -EAI_SYSTEM; \ ++ result = -EAI_SYSTEM; \ ++ goto free_and_return; \ + } \ + if (herrno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ + +diff --git a/manual/conf.texi b/manual/conf.texi +index 7eb8b36..c720063 100644 +--- a/manual/conf.texi ++++ b/manual/conf.texi +@@ -1149,6 +1149,9 @@ typed ahead as input. @xref{I/O Queues}. + @comment POSIX.1 + @deftypevr Macro int NAME_MAX + The uniform system limit (if any) for the length of a file name component. ++ ++@strong{Portability Note:} On some systems, the GNU C Library defines ++@code{NAME_MAX}, but does not actually enforce this limit. + @end deftypevr + + @comment limits.h +@@ -1157,6 +1160,9 @@ including the terminating null character. + @deftypevr Macro int PATH_MAX + The uniform system limit (if any) for the length of an entire file name (that + is, the argument given to system calls such as @code{open}). ++ ++@strong{Portability Note:} The GNU C Library does not enforce this limit ++even if @code{PATH_MAX} is defined. + @end deftypevr + + @cindex limits, pipe buffer size +@@ -1476,6 +1482,9 @@ Inquire about the value of @code{POSIX_REC_MIN_XFER_SIZE}. + Inquire about the value of @code{POSIX_REC_XFER_ALIGN}. + @end table + ++@strong{Portability Note:} On some systems, the GNU C Library does not ++enforce @code{_PC_NAME_MAX} or @code{_PC_PATH_MAX} limits. ++ + @node Utility Limits + @section Utility Program Capacity Limits + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index 1df9cf2..814c210 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -444,9 +444,9 @@ symbols are declared in the header file @file{dirent.h}. + @comment POSIX.1 + @deftypefun {struct dirent *} readdir (DIR *@var{dirstream}) + This function reads the next entry from the directory. It normally +-returns a pointer to a structure containing information about the file. +-This structure is statically allocated and can be rewritten by a +-subsequent call. ++returns a pointer to a structure containing information about the ++file. This structure is associated with the @var{dirstream} handle ++and can be rewritten by a subsequent call. + + @strong{Portability Note:} On some systems @code{readdir} may not + return entries for @file{.} and @file{..}, even though these are always +@@ -461,19 +461,61 @@ conditions are defined for this function: + The @var{dirstream} argument is not valid. + @end table + +-@code{readdir} is not thread safe. Multiple threads using +-@code{readdir} on the same @var{dirstream} may overwrite the return +-value. Use @code{readdir_r} when this is critical. ++To distinguish between an end-of-directory condition or an error, you ++must set @code{errno} to zero before calling @code{readdir}. To avoid ++entering an infinite loop, you should stop reading from the directory ++after the first error. ++ ++In POSIX.1-2008, @code{readdir} is not thread-safe. In the GNU C Library ++implementation, it is safe to call @code{readdir} concurrently on ++different @var{dirstream}s, but multiple threads accessing the same ++@var{dirstream} result in undefined behavior. @code{readdir_r} is a ++fully thread-safe alternative, but suffers from poor portability (see ++below). It is recommended that you use @code{readdir}, with external ++locking if multiple threads access the same @var{dirstream}. + @end deftypefun + + @comment dirent.h + @comment GNU + @deftypefun int readdir_r (DIR *@var{dirstream}, struct dirent *@var{entry}, struct dirent **@var{result}) +-This function is the reentrant version of @code{readdir}. Like +-@code{readdir} it returns the next entry from the directory. But to +-prevent conflicts between simultaneously running threads the result is +-not stored in statically allocated memory. Instead the argument +-@var{entry} points to a place to store the result. ++This function is a version of @code{readdir} which performs internal ++locking. Like @code{readdir} it returns the next entry from the ++directory. To prevent conflicts between simultaneously running ++threads the result is stored inside the @var{entry} object. ++ ++@strong{Portability Note:} It is recommended to use @code{readdir} ++instead of @code{readdir_r} for the following reasons: ++ ++@itemize @bullet ++@item ++On systems which do not define @code{NAME_MAX}, it may not be possible ++to use @code{readdir_r} safely because the caller does not specify the ++length of the buffer for the directory entry. ++ ++@item ++On some systems, @code{readdir_r} cannot read directory entries with ++very long names. If such a name is encountered, the GNU C Library ++implementation of @code{readdir_r} returns with an error code of ++@code{ENAMETOOLONG} after the final directory entry has been read. On ++other systems, @code{readdir_r} may return successfully, but the ++@code{d_name} member may not be NUL-terminated or may be truncated. ++ ++@item ++POSIX-1.2008 does not guarantee that @code{readdir} is thread-safe, ++even when access to the same @var{dirstream} is serialized. But in ++current implementations (including the GNU C Library), it is safe to call ++@code{readdir} concurrently on different @var{dirstream}s, so there is ++no need to use @code{readdir_r} in most multi-threaded programs. In ++the rare case that multiple threads need to read from the same ++@var{dirstream}, it is still better to use @code{readdir} and external ++synchronization. ++ ++@item ++It is expected that future versions of POSIX will obsolete ++@code{readdir_r} and mandate the level of thread safety for ++@code{readdir} which is provided by the GNU C Library and other ++implementations today. ++@end itemize + + Normally @code{readdir_r} returns zero and sets @code{*@var{result}} + to @var{entry}. If there are no more entries in the directory or an +@@ -481,15 +523,6 @@ error is detected, @code{readdir_r} sets @code{*@var{result}} to a + null pointer and returns a nonzero error code, also stored in + @code{errno}, as described for @code{readdir}. + +-@strong{Portability Note:} On some systems @code{readdir_r} may not +-return a NUL terminated string for the file name, even when there is no +-@code{d_reclen} field in @code{struct dirent} and the file +-name is the maximum allowed size. Modern systems all have the +-@code{d_reclen} field, and on old systems multi-threading is not +-critical. In any case there is no such problem with the @code{readdir} +-function, so that even on systems without the @code{d_reclen} member one +-could use multiple threads by using external locking. +- + It is also important to look at the definition of the @code{struct + dirent} type. Simply passing a pointer to an object of this type for + the second parameter of @code{readdir_r} might not be enough. Some +diff --git a/sysdeps/unix/dirstream.h b/sysdeps/unix/dirstream.h +index a7a074d..8e8570d 100644 +--- a/sysdeps/unix/dirstream.h ++++ b/sysdeps/unix/dirstream.h +@@ -39,6 +39,8 @@ struct __dirstream + + off_t filepos; /* Position of next entry to read. */ + ++ int errcode; /* Delayed error code. */ ++ + /* Directory block. */ + char data[0] __attribute__ ((aligned (__alignof__ (void*)))); + }; +diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c +index ddfc3a7..fc05b0f 100644 +--- a/sysdeps/unix/opendir.c ++++ b/sysdeps/unix/opendir.c +@@ -231,6 +231,7 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) + dirp->size = 0; + dirp->offset = 0; + dirp->filepos = 0; ++ dirp->errcode = 0; + + return dirp; + } +diff --git a/sysdeps/unix/readdir_r.c b/sysdeps/unix/readdir_r.c +index b5a8e2e..8ed5c3f 100644 +--- a/sysdeps/unix/readdir_r.c ++++ b/sysdeps/unix/readdir_r.c +@@ -40,6 +40,7 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) + DIRENT_TYPE *dp; + size_t reclen; + const int saved_errno = errno; ++ int ret; + + __libc_lock_lock (dirp->lock); + +@@ -70,10 +71,10 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) + bytes = 0; + __set_errno (saved_errno); + } ++ if (bytes < 0) ++ dirp->errcode = errno; + + dp = NULL; +- /* Reclen != 0 signals that an error occurred. */ +- reclen = bytes != 0; + break; + } + dirp->size = (size_t) bytes; +@@ -106,28 +107,46 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) + dirp->filepos += reclen; + #endif + +- /* Skip deleted files. */ ++#ifdef NAME_MAX ++ if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1) ++ { ++ /* The record is very long. It could still fit into the ++ caller-supplied buffer if we can skip padding at the ++ end. */ ++ size_t namelen = _D_EXACT_NAMLEN (dp); ++ if (namelen <= NAME_MAX) ++ reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1; ++ else ++ { ++ /* The name is too long. Ignore this file. */ ++ dirp->errcode = ENAMETOOLONG; ++ dp->d_ino = 0; ++ continue; ++ } ++ } ++#endif ++ ++ /* Skip deleted and ignored files. */ + } + while (dp->d_ino == 0); + + if (dp != NULL) + { +-#ifdef GETDENTS_64BIT_ALIGNED +- /* The d_reclen value might include padding which is not part of +- the DIRENT_TYPE data structure. */ +- reclen = MIN (reclen, sizeof (DIRENT_TYPE)); +-#endif + *result = memcpy (entry, dp, reclen); +-#ifdef GETDENTS_64BIT_ALIGNED ++#ifdef _DIRENT_HAVE_D_RECLEN + entry->d_reclen = reclen; + #endif ++ ret = 0; + } + else +- *result = NULL; ++ { ++ *result = NULL; ++ ret = dirp->errcode; ++ } + + __libc_lock_unlock (dirp->lock); + +- return dp != NULL ? 0 : reclen ? errno : 0; ++ return ret; + } + + #ifdef __READDIR_R_ALIAS +diff --git a/sysdeps/unix/rewinddir.c b/sysdeps/unix/rewinddir.c +index 2935a8e..d4991ad 100644 +--- a/sysdeps/unix/rewinddir.c ++++ b/sysdeps/unix/rewinddir.c +@@ -33,5 +33,6 @@ rewinddir (dirp) + dirp->filepos = 0; + dirp->offset = 0; + dirp->size = 0; ++ dirp->errcode = 0; + __libc_lock_unlock (dirp->lock); + } +diff --git a/sysdeps/unix/sysv/linux/i386/readdir64_r.c b/sysdeps/unix/sysv/linux/i386/readdir64_r.c +index 8ebbcfd..a7d114e 100644 +--- a/sysdeps/unix/sysv/linux/i386/readdir64_r.c ++++ b/sysdeps/unix/sysv/linux/i386/readdir64_r.c +@@ -18,7 +18,6 @@ + #define __READDIR_R __readdir64_r + #define __GETDENTS __getdents64 + #define DIRENT_TYPE struct dirent64 +-#define GETDENTS_64BIT_ALIGNED 1 + + #include + diff --git a/src/patches/glibc/glibc-rh1139571.patch b/src/patches/glibc/glibc-rh1139571.patch new file mode 100644 index 0000000000..b1320a7378 --- /dev/null +++ b/src/patches/glibc/glibc-rh1139571.patch @@ -0,0 +1,154 @@ +commit 41488498b6d9440ee66ab033808cce8323bba7ac +Author: Florian Weimer +Date: Wed Sep 3 19:45:43 2014 +0200 + + CVE-2014-6040: Crashes on invalid input in IBM gconv modules [BZ #17325] + + These changes are based on the fix for BZ #14134 in commit + 6e230d11837f3ae7b375ea69d7905f0d18eb79e5. + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index 0a410a1..b6327d6 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -297,6 +297,7 @@ $(objpfx)tst-iconv7.out: $(objpfx)gconv-modules \ + $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \ + $(addprefix $(objpfx),$(modules.so)) \ + $(common-objdir)/iconv/iconv_prog TESTS ++ iconv_modules="$(modules)" \ + $(SHELL) -e $< $(common-objdir) > $@ + + $(objpfx)tst-tables.out: tst-tables.sh $(objpfx)gconv-modules \ +diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c +index 0b5484f..cf80993 100644 +--- a/iconvdata/ibm1364.c ++++ b/iconvdata/ibm1364.c +@@ -221,7 +221,8 @@ enum + ++rp2; \ + \ + uint32_t res; \ +- if (__builtin_expect (ch < rp2->start, 0) \ ++ if (__builtin_expect (rp2->start == 0xffff, 0) \ ++ || __builtin_expect (ch < rp2->start, 0) \ + || (res = DB_TO_UCS4[ch + rp2->idx], \ + __builtin_expect (res, L'\1') == L'\0' && ch != '\0')) \ + { \ +diff --git a/iconvdata/ibm932.c b/iconvdata/ibm932.c +index f5dca59..aa69d65 100644 +--- a/iconvdata/ibm932.c ++++ b/iconvdata/ibm932.c +@@ -74,11 +74,12 @@ + } \ + \ + ch = (ch * 0x100) + inptr[1]; \ ++ /* ch was less than 0xfd. */ \ ++ assert (ch < 0xfd00); \ + while (ch > rp2->end) \ + ++rp2; \ + \ +- if (__builtin_expect (rp2 == NULL, 0) \ +- || __builtin_expect (ch < rp2->start, 0) \ ++ if (__builtin_expect (ch < rp2->start, 0) \ + || (res = __ibm932db_to_ucs4[ch + rp2->idx], \ + __builtin_expect (res, '\1') == 0 && ch !=0)) \ + { \ +diff --git a/iconvdata/ibm933.c b/iconvdata/ibm933.c +index f46dfb5..461fb5e 100644 +--- a/iconvdata/ibm933.c ++++ b/iconvdata/ibm933.c +@@ -162,7 +162,7 @@ enum + while (ch > rp2->end) \ + ++rp2; \ + \ +- if (__builtin_expect (rp2 == NULL, 0) \ ++ if (__builtin_expect (rp2->start == 0xffff, 0) \ + || __builtin_expect (ch < rp2->start, 0) \ + || (res = __ibm933db_to_ucs4[ch + rp2->idx], \ + __builtin_expect (res, L'\1') == L'\0' && ch != '\0')) \ +diff --git a/iconvdata/ibm935.c b/iconvdata/ibm935.c +index a8e4e6c..132d816 100644 +--- a/iconvdata/ibm935.c ++++ b/iconvdata/ibm935.c +@@ -162,7 +162,7 @@ enum + while (ch > rp2->end) \ + ++rp2; \ + \ +- if (__builtin_expect (rp2 == NULL, 0) \ ++ if (__builtin_expect (rp2->start == 0xffff, 0) \ + || __builtin_expect (ch < rp2->start, 0) \ + || (res = __ibm935db_to_ucs4[ch + rp2->idx], \ + __builtin_expect (res, L'\1') == L'\0' && ch != '\0')) \ +diff --git a/iconvdata/ibm937.c b/iconvdata/ibm937.c +index 239be61..69b154d 100644 +--- a/iconvdata/ibm937.c ++++ b/iconvdata/ibm937.c +@@ -162,7 +162,7 @@ enum + while (ch > rp2->end) \ + ++rp2; \ + \ +- if (__builtin_expect (rp2 == NULL, 0) \ ++ if (__builtin_expect (rp2->start == 0xffff, 0) \ + || __builtin_expect (ch < rp2->start, 0) \ + || (res = __ibm937db_to_ucs4[ch + rp2->idx], \ + __builtin_expect (res, L'\1') == L'\0' && ch != '\0')) \ +diff --git a/iconvdata/ibm939.c b/iconvdata/ibm939.c +index 5d0db36..9936e2c 100644 +--- a/iconvdata/ibm939.c ++++ b/iconvdata/ibm939.c +@@ -162,7 +162,7 @@ enum + while (ch > rp2->end) \ + ++rp2; \ + \ +- if (__builtin_expect (rp2 == NULL, 0) \ ++ if (__builtin_expect (rp2->start == 0xffff, 0) \ + || __builtin_expect (ch < rp2->start, 0) \ + || (res = __ibm939db_to_ucs4[ch + rp2->idx], \ + __builtin_expect (res, L'\1') == L'\0' && ch != '\0')) \ +diff --git a/iconvdata/ibm943.c b/iconvdata/ibm943.c +index be0c14f..c5d5742 100644 +--- a/iconvdata/ibm943.c ++++ b/iconvdata/ibm943.c +@@ -75,11 +75,12 @@ + } \ + \ + ch = (ch * 0x100) + inptr[1]; \ ++ /* ch was less than 0xfd. */ \ ++ assert (ch < 0xfd00); \ + while (ch > rp2->end) \ + ++rp2; \ + \ +- if (__builtin_expect (rp2 == NULL, 0) \ +- || __builtin_expect (ch < rp2->start, 0) \ ++ if (__builtin_expect (ch < rp2->start, 0) \ + || (res = __ibm943db_to_ucs4[ch + rp2->idx], \ + __builtin_expect (res, '\1') == 0 && ch !=0)) \ + { \ +diff --git a/iconvdata/run-iconv-test.sh b/iconvdata/run-iconv-test.sh +index c98c929..5dfb69f 100755 +--- a/iconvdata/run-iconv-test.sh ++++ b/iconvdata/run-iconv-test.sh +@@ -184,6 +184,24 @@ while read utf8 from filename; do + + done < TESTS2 + ++# Check for crashes in decoders. ++printf '\016\377\377\377\377\377\377\377' > $temp1 ++for from in $iconv_modules ; do ++ echo $ac_n "test decoder $from $ac_c" ++ PROG=`eval echo $ICONV` ++ if $PROG < $temp1 >/dev/null 2>&1 ; then ++ : # fall through ++ else ++ status=$? ++ if test $status -gt 1 ; then ++ echo "/FAILED" ++ failed=1 ++ continue ++ fi ++ fi ++ echo "OK" ++done ++ + exit $failed + # Local Variables: + # mode:shell-script diff --git a/src/patches/glibc/glibc-rh1154563.patch b/src/patches/glibc/glibc-rh1154563.patch new file mode 100644 index 0000000000..22821b1f9f --- /dev/null +++ b/src/patches/glibc/glibc-rh1154563.patch @@ -0,0 +1,333 @@ +# +# This is a special patch for rhel-6 to fix recursive dlopen. +# It is likely the upstream patch will always be too risky for +# rhel-6 and will involve reorganizing the way in which recursive +# dlopen is allowed to operate and how the _r_debug and stap +# points are used by gdb for the recursive case. +# +# This fix changes the internal API to duplicate the ldconfig +# cache data. This means that at any point the cache can be +# unmapped without any consequences. The caller is responsible +# fore freeing the returned string. +# +# A regression test is added to verify the assertion for _r_debug +# is no longer triggered due to the recursive dlopen. The test to +# verify the fix in _dl_load_cache_lookup is not automated and +# has to be run by hand. +# +diff -urN glibc-2.12-2-gc4ccff1/elf/dl-cache.c glibc-2.12-2-gc4ccff1.mod/elf/dl-cache.c +--- glibc-2.12-2-gc4ccff1/elf/dl-cache.c 2010-05-04 07:27:23.000000000 -0400 ++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-cache.c 2014-12-10 21:54:08.801985045 -0500 +@@ -175,9 +175,12 @@ + + + /* Look up NAME in ld.so.cache and return the file name stored there, +- or null if none is found. */ +- +-const char * ++ or null if none is found. ++ The caller is responsible for freeing the returned string. The ld.so.cache ++ may be unmapped at any time by a completing recursive dlopen and ++ this function must take care that it does not return references to ++ any data in the mapping. */ ++char * + internal_function + _dl_load_cache_lookup (const char *name) + { +@@ -290,7 +293,17 @@ + && best != NULL) + _dl_debug_printf (" trying file=%s\n", best); + +- return best; ++ if (best == NULL) ++ return NULL; ++ ++ /* The double copy is *required* since malloc may be interposed ++ and call dlopen itself whose completion would unmap the data ++ we are accessing. Therefore we must make the copy of the ++ mapping data without using malloc. */ ++ char *temp; ++ temp = alloca (strlen (best) + 1); ++ strcpy (temp, best); ++ return strdup (temp); + } + + #ifndef MAP_COPY +diff -urN glibc-2.12-2-gc4ccff1/elf/dl-load.c glibc-2.12-2-gc4ccff1.mod/elf/dl-load.c +--- glibc-2.12-2-gc4ccff1/elf/dl-load.c 2014-12-10 11:03:17.966048404 -0500 ++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-load.c 2014-12-10 21:47:29.319387538 -0500 +@@ -2126,7 +2126,7 @@ + { + /* Check the list of libraries in the file /etc/ld.so.cache, + for compatibility with Linux's ldconfig program. */ +- const char *cached = _dl_load_cache_lookup (name); ++ char *cached = _dl_load_cache_lookup (name); + + if (cached != NULL) + { +@@ -2156,6 +2156,7 @@ + if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0) + { + /* The prefix matches. Don't use the entry. */ ++ free (cached); + cached = NULL; + break; + } +@@ -2172,14 +2173,9 @@ + &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, + LA_SER_CONFIG, &found_other_class, false); + if (__builtin_expect (fd != -1, 1)) +- { +- realname = local_strdup (cached); +- if (realname == NULL) +- { +- __close (fd); +- fd = -1; +- } +- } ++ realname = cached; ++ else ++ free (cached); + } + } + } +diff -urN glibc-2.12-2-gc4ccff1/elf/dl-open.c glibc-2.12-2-gc4ccff1.mod/elf/dl-open.c +--- glibc-2.12-2-gc4ccff1/elf/dl-open.c 2014-12-10 11:03:18.083048497 -0500 ++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-open.c 2014-12-10 20:34:16.017503638 -0500 +@@ -220,7 +220,11 @@ + } + } + +- assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); ++ /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that ++ may not be true if this is a recursive call to dlopen. ++ TODO: Fix all of the debug state so we end up at RT_CONSISTENT only when the last ++ recursive dlopen completes. */ ++ _dl_debug_initialize (0, args->nsid); + + /* Load the named object. */ + struct link_map *new; +diff -urN glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h glibc-2.12-2-gc4ccff1.mod/sysdeps/generic/ldsodefs.h +--- glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h 2014-12-10 11:03:17.944048387 -0500 ++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/generic/ldsodefs.h 2014-12-10 21:46:14.071344018 -0500 +@@ -996,8 +996,8 @@ + internal_function; + + /* Look up NAME in ld.so.cache and return the file name stored there, +- or null if none is found. */ +-extern const char *_dl_load_cache_lookup (const char *name) ++ or null if none is found. Caller must free returned string. */ ++extern char *_dl_load_cache_lookup (const char *name) + internal_function; + + /* If the system does not support MAP_COPY we cannot leave the file open +diff -urN glibc-2.12-2-gc4ccff1/dlfcn/Makefile glibc-2.12-2-gc4ccff1.mod/dlfcn/Makefile +--- glibc-2.12-2-gc4ccff1/dlfcn/Makefile 2010-05-04 07:27:23.000000000 -0400 ++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/Makefile 2014-12-11 16:58:55.719803063 -0500 +@@ -42,12 +42,12 @@ + ifeq (yes,$(build-shared)) + tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \ + bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \ +- bug-atexit3 tstatexit ++ bug-atexit3 tstatexit tst-rec-dlopen + endif + modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \ + defaultmod2 errmsg1mod modatexit modcxaatexit \ + bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \ +- bug-atexit2-lib bug-atexit3-lib ++ bug-atexit2-lib bug-atexit3-lib moddummy1 moddummy2 + + failtestmod.so-no-z-defs = yes + glreflib2.so-no-z-defs = yes +@@ -142,6 +142,8 @@ + $(objpfx)bug-atexit3-lib.so: $(common-objpfx)libc.so \ + $(common-objpfx)libc_nonshared.a + ++LDLIBS-tst-rec-dlopen = -ldl ++$(objpfx)tst-rec-dlopen: $(libdl) + + # Depend on libc.so so a DT_NEEDED is generated in the shared objects. + # This ensures they will load libc.so for needed symbols if loaded by +diff -urN glibc-2.12-2-gc4ccff1/dlfcn/moddummy1.c glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy1.c +--- glibc-2.12-2-gc4ccff1/dlfcn/moddummy1.c 1969-12-31 19:00:00.000000000 -0500 ++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy1.c 2014-12-11 16:57:54.108797285 -0500 +@@ -0,0 +1,13 @@ ++/* Provide a dummy DSO for tst-recursive-dlopen to use. */ ++#include ++#include ++ ++int called_dummy1; ++ ++void ++dummy1 (void) ++{ ++ printf ("Called dummy1()\n"); ++ called_dummy1++; ++} ++ +diff -urN glibc-2.12-2-gc4ccff1/dlfcn/moddummy2.c glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy2.c +--- glibc-2.12-2-gc4ccff1/dlfcn/moddummy2.c 1969-12-31 19:00:00.000000000 -0500 ++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy2.c 2014-12-11 16:57:54.108797285 -0500 +@@ -0,0 +1,13 @@ ++/* Provide a dummy DSO for tst-recursive-dlopen to use. */ ++#include ++#include ++ ++int called_dummy2; ++ ++void ++dummy2 (void) ++{ ++ printf ("Called dummy2()\n"); ++ called_dummy2++; ++} ++ +diff -urN glibc-2.12-2-gc4ccff1/dlfcn/tst-rec-dlopen.c glibc-2.12-2-gc4ccff1.mod/dlfcn/tst-rec-dlopen.c +--- glibc-2.12-2-gc4ccff1/dlfcn/tst-rec-dlopen.c 1969-12-31 19:00:00.000000000 -0500 ++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/tst-rec-dlopen.c 2014-12-11 20:53:28.617848774 -0500 +@@ -0,0 +1,145 @@ ++/* Test recursive dlopen using malloc hooks. ++ Copyright (C) 1998-2014 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 1998. ++ ++ 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 ++#include ++ ++#define DSO "moddummy1.so" ++#define FUNC "dummy1" ++ ++#define DSO1 "moddummy2.so" ++#define FUNC1 "dummy2" ++ ++/* Prevent the compiler from moving the assignment to called_func ++ before (*func)() since the compiler doesn't know we might abort ++ or catch a SIGSEGV signal and it may move the store. */ ++volatile int called_func; ++ ++/* Prototype for my hook. */ ++void *custom_malloc_hook (size_t, const void *); ++ ++/* Pointer to old malloc hooks. */ ++void *(*old_malloc_hook) (size_t, const void *); ++ ++/* Call function func_name in DSO dso_name via dlopen. */ ++void ++call_func (const char *dso_name, const char *func_name) ++{ ++ int ret; ++ void *dso; ++ void (*func) (void); ++ char *err; ++ ++ /* Open the DSO. */ ++ dso = dlopen (dso_name, RTLD_NOW|RTLD_GLOBAL); ++ if (dso == NULL) ++ { ++ err = dlerror (); ++ fprintf (stderr, "%s\n", err); ++ exit (1); ++ } ++ /* Clear any errors. */ ++ dlerror (); ++ ++ /* Lookup func. */ ++ *(void **) (&func) = dlsym (dso, func_name); ++ if (func == NULL) ++ { ++ err = dlerror (); ++ if (err != NULL) ++ { ++ fprintf (stderr, "%s\n", err); ++ exit (1); ++ } ++ } ++ /* Call func. */ ++ (*func) (); ++ called_func = 1; ++ ++ /* Close the library and look for errors too. */ ++ ret = dlclose (dso); ++ if (ret != 0) ++ { ++ err = dlerror (); ++ fprintf (stderr, "%s\n", err); ++ exit (1); ++ } ++ ++} ++ ++/* Empty hook that does nothing. */ ++void * ++custom_malloc_hook (size_t size, const void *caller) ++{ ++ void *result; ++ /* Restore old hooks. */ ++ __malloc_hook = old_malloc_hook; ++ /* First call a function in another library via dlopen. */ ++ call_func (DSO1, FUNC1); ++ /* Called recursively. */ ++ result = malloc (size); ++ /* Restore new hooks. */ ++ __malloc_hook = custom_malloc_hook; ++ return result; ++} ++ ++static int ++do_test (void) ++{ ++ /* Save old hook. */ ++ old_malloc_hook = __malloc_hook; ++ /* Install new hook. */ ++ __malloc_hook = custom_malloc_hook; ++ ++ /* Bug 17702 fixes two things: ++ * A recursive dlopen unmapping the ld.so.cache. ++ * An assertion that _r_debug is RT_CONSISTENT at entry to dlopen. ++ We can only test the latter. Testing the former requires modifying ++ ld.so.conf to cache the dummy libraries, then running ldconfig, ++ then run the test. If you do all of that (and glibc's test ++ infrastructure doesn't support that yet) then the test will ++ SEGFAULT without the fix. If you don't do that, then the test ++ will abort because of the assert described in detail below. */ ++ call_func (DSO, FUNC); ++ ++ /* Restore old hook. */ ++ __malloc_hook = old_malloc_hook; ++ ++ /* The function dummy2() is called by the malloc hook. Check to ++ see that it was called. This ensures the second recursive ++ dlopen happened and we called the function in that library. ++ ++ Before the fix you either get a SIGSEGV when accessing mmap'd ++ ld.so.cache data or an assertion failure about _r_debug not ++ beint RT_CONSISTENT. We don't test for the SIGSEGV since it ++ would require finding moddummy1 or moddummy2 in the cache and ++ we don't have any infrastructure to test that, but the _r_debug ++ assertion triggers. */ ++ if (called_func > 0) ++ printf ("PASS: Function call_func() called more than once.\n"); ++ else ++ printf ("FAIL: Function call_func() not called.\n"); ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" diff --git a/src/patches/glibc/glibc-rh1170121.patch b/src/patches/glibc/glibc-rh1170121.patch new file mode 100644 index 0000000000..1accbf3e7f --- /dev/null +++ b/src/patches/glibc/glibc-rh1170121.patch @@ -0,0 +1,163 @@ +# +# commit a39208bd7fb76c1b01c127b4c61f9bfd915bfe7c +# Author: Carlos O'Donell +# Date: Wed Nov 19 11:44:12 2014 -0500 +# +# CVE-2014-7817: wordexp fails to honour WRDE_NOCMD. +# +# The function wordexp() fails to properly handle the WRDE_NOCMD +# flag when processing arithmetic inputs in the form of "$((... ``))" +# where "..." can be anything valid. The backticks in the arithmetic +# epxression are evaluated by in a shell even if WRDE_NOCMD forbade +# command substitution. This allows an attacker to attempt to pass +# dangerous commands via constructs of the above form, and bypass +# the WRDE_NOCMD flag. This patch fixes this by checking for WRDE_NOCMD +# in exec_comm(), the only place that can execute a shell. All other +# checks for WRDE_NOCMD are superfluous and removed. +# +# We expand the testsuite and add 3 new regression tests of roughly +# the same form but with a couple of nested levels. +# +# On top of the 3 new tests we add fork validation to the WRDE_NOCMD +# testing. If any forks are detected during the execution of a wordexp() +# call with WRDE_NOCMD, the test is marked as failed. This is slightly +# heuristic since vfork might be used in the future, but it provides a +# higher level of assurance that no shells were executed as part of +# command substitution with WRDE_NOCMD in effect. In addition it doesn't +# require libpthread or libdl, instead we use the public implementation +# namespace function __register_atfork (already part of the public ABI +# for libpthread). +# +# Tested on x86_64 with no regressions. +# +diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c +index 4957006..bdd65e4 100644 +--- a/posix/wordexp-test.c ++++ b/posix/wordexp-test.c +@@ -27,6 +27,25 @@ + + #define IFS " \n\t" + ++extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden"))); ++extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *); ++ ++static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void)) ++{ ++ return __register_atfork (prepare, parent, child, ++ &__dso_handle == NULL ? NULL : __dso_handle); ++} ++ ++/* Number of forks seen. */ ++static int registered_forks; ++ ++/* For each fork increment the fork count. */ ++static void ++register_fork (void) ++{ ++ registered_forks++; ++} ++ + struct test_case_struct + { + int retval; +@@ -206,6 +225,12 @@ struct test_case_struct + { WRDE_SYNTAX, NULL, "$((2+))", 0, 0, { NULL, }, IFS }, + { WRDE_SYNTAX, NULL, "`", 0, 0, { NULL, }, IFS }, + { WRDE_SYNTAX, NULL, "$((010+4+))", 0, 0, { NULL }, IFS }, ++ /* Test for CVE-2014-7817. We test 3 combinations of command ++ substitution inside an arithmetic expression to make sure that ++ no commands are executed and error is returned. */ ++ { WRDE_CMDSUB, NULL, "$((`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS }, ++ { WRDE_CMDSUB, NULL, "$((1+`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS }, ++ { WRDE_CMDSUB, NULL, "$((1+$((`echo 1`))))", WRDE_NOCMD, 0, { NULL, }, IFS }, + + { -1, NULL, NULL, 0, 0, { NULL, }, IFS }, + }; +@@ -258,6 +283,15 @@ main (int argc, char *argv[]) + return -1; + } + ++ /* If we are not allowed to do command substitution, we install ++ fork handlers to verify that no forks happened. No forks should ++ happen at all if command substitution is disabled. */ ++ if (__app_register_atfork (register_fork, NULL, NULL) != 0) ++ { ++ printf ("Failed to register fork handler.\n"); ++ return -1; ++ } ++ + for (test = 0; test_case[test].retval != -1; test++) + if (testit (&test_case[test])) + ++fail; +@@ -367,6 +401,9 @@ testit (struct test_case_struct *tc) + + printf ("Test %d (%s): ", ++tests, tc->words); + ++ if (tc->flags & WRDE_NOCMD) ++ registered_forks = 0; ++ + if (tc->flags & WRDE_APPEND) + { + /* initial wordexp() call, to be appended to */ +@@ -378,6 +415,13 @@ testit (struct test_case_struct *tc) + } + retval = wordexp (tc->words, &we, tc->flags); + ++ if ((tc->flags & WRDE_NOCMD) ++ && (registered_forks > 0)) ++ { ++ printf ("FAILED fork called for WRDE_NOCMD\n"); ++ return 1; ++ } ++ + if (tc->flags & WRDE_DOOFFS) + start_offs = sav_we.we_offs; + +diff --git a/posix/wordexp.c b/posix/wordexp.c +index b6b65dd..26f3a26 100644 +--- a/posix/wordexp.c ++++ b/posix/wordexp.c +@@ -893,6 +893,10 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length, + pid_t pid; + int noexec = 0; + ++ /* Do nothing if command substitution should not succeed. */ ++ if (flags & WRDE_NOCMD) ++ return WRDE_CMDSUB; ++ + /* Don't fork() unless necessary */ + if (!comm || !*comm) + return 0; +@@ -2082,9 +2086,6 @@ parse_dollars (char **word, size_t *word_length, size_t *max_length, + } + } + +- if (flags & WRDE_NOCMD) +- return WRDE_CMDSUB; +- + (*offset) += 2; + return parse_comm (word, word_length, max_length, words, offset, flags, + quoted? NULL : pwordexp, ifs, ifs_white); +@@ -2196,9 +2197,6 @@ parse_dquote (char **word, size_t *word_length, size_t *max_length, + break; + + case '`': +- if (flags & WRDE_NOCMD) +- return WRDE_CMDSUB; +- + ++(*offset); + error = parse_backtick (word, word_length, max_length, words, + offset, flags, NULL, NULL, NULL); +@@ -2357,12 +2355,6 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) + break; + + case '`': +- if (flags & WRDE_NOCMD) +- { +- error = WRDE_CMDSUB; +- goto do_error; +- } +- + ++words_offset; + error = parse_backtick (&word, &word_length, &max_length, words, + &words_offset, flags, pwordexp, ifs, diff --git a/src/patches/glibc/glibc-rh1183533.patch b/src/patches/glibc/glibc-rh1183533.patch new file mode 100644 index 0000000000..9263cd5b68 --- /dev/null +++ b/src/patches/glibc/glibc-rh1183533.patch @@ -0,0 +1,210 @@ +commit d5dd6189d506068ed11c8bfa1e1e9bffde04decd +Author: Andreas Schwab +Date: Mon Jan 21 17:41:28 2013 +0100 + + Fix parsing of numeric hosts in gethostbyname_r + +diff --git a/nss/digits_dots.c b/nss/digits_dots.c +index 2b86295..e007ef4 100644 +--- a/nss/digits_dots.c ++++ b/nss/digits_dots.c +@@ -46,7 +46,10 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + { + if (h_errnop) + *h_errnop = NETDB_INTERNAL; +- *result = NULL; ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_TRYAGAIN; ++ else ++ *result = NULL; + return -1; + } + +@@ -83,14 +86,16 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + } + + size_needed = (sizeof (*host_addr) +- + sizeof (*h_addr_ptrs) + strlen (name) + 1); ++ + sizeof (*h_addr_ptrs) ++ + sizeof (*h_alias_ptr) + strlen (name) + 1); + + if (buffer_size == NULL) + { + if (buflen < size_needed) + { ++ *status = NSS_STATUS_TRYAGAIN; + if (h_errnop != NULL) +- *h_errnop = TRY_AGAIN; ++ *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + goto done; + } +@@ -109,7 +114,7 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + *buffer_size = 0; + __set_errno (save); + if (h_errnop != NULL) +- *h_errnop = TRY_AGAIN; ++ *h_errnop = NETDB_INTERNAL; + *result = NULL; + goto done; + } +@@ -149,7 +154,9 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + if (! ok) + { + *h_errnop = HOST_NOT_FOUND; +- if (buffer_size) ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_NOTFOUND; ++ else + *result = NULL; + goto done; + } +@@ -190,7 +197,7 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + if (buffer_size == NULL) + *status = NSS_STATUS_SUCCESS; + else +- *result = resbuf; ++ *result = resbuf; + goto done; + } + +@@ -201,15 +208,6 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + + if ((isxdigit (name[0]) && strchr (name, ':') != NULL) || name[0] == ':') + { +- const char *cp; +- char *hostname; +- typedef unsigned char host_addr_t[16]; +- host_addr_t *host_addr; +- typedef char *host_addr_list_t[2]; +- host_addr_list_t *h_addr_ptrs; +- size_t size_needed; +- int addr_size; +- + switch (af) + { + default: +@@ -225,7 +223,10 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + /* This is not possible. We cannot represent an IPv6 address + in an `struct in_addr' variable. */ + *h_errnop = HOST_NOT_FOUND; +- *result = NULL; ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_NOTFOUND; ++ else ++ *result = NULL; + goto done; + + case AF_INET6: +@@ -233,42 +234,6 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + break; + } + +- size_needed = (sizeof (*host_addr) +- + sizeof (*h_addr_ptrs) + strlen (name) + 1); +- +- if (buffer_size == NULL && buflen < size_needed) +- { +- if (h_errnop != NULL) +- *h_errnop = TRY_AGAIN; +- __set_errno (ERANGE); +- goto done; +- } +- else if (buffer_size != NULL && *buffer_size < size_needed) +- { +- char *new_buf; +- *buffer_size = size_needed; +- new_buf = realloc (*buffer, *buffer_size); +- +- if (new_buf == NULL) +- { +- save = errno; +- free (*buffer); +- __set_errno (save); +- *buffer = NULL; +- *buffer_size = 0; +- *result = NULL; +- goto done; +- } +- *buffer = new_buf; +- } +- +- memset (*buffer, '\0', size_needed); +- +- host_addr = (host_addr_t *) *buffer; +- h_addr_ptrs = (host_addr_list_t *) +- ((char *) host_addr + sizeof (*host_addr)); +- hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs); +- + for (cp = name;; ++cp) + { + if (!*cp) +@@ -281,7 +246,9 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + if (inet_pton (AF_INET6, name, host_addr) <= 0) + { + *h_errnop = HOST_NOT_FOUND; +- if (buffer_size) ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_NOTFOUND; ++ else + *result = NULL; + goto done; + } +diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c +index 1067744..44d00f4 100644 +--- a/nss/getXXbyYY_r.c ++++ b/nss/getXXbyYY_r.c +@@ -179,6 +179,9 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, + case -1: + return errno; + case 1: ++#ifdef NEED_H_ERRNO ++ any_service = true; ++#endif + goto done; + } + #endif +diff --git a/nss/test-digits-dots.c b/nss/test-digits-dots.c +new file mode 100644 +index 0000000..1efa344 +--- /dev/null ++++ b/nss/test-digits-dots.c +@@ -0,0 +1,38 @@ ++/* Copyright (C) 2013 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 ++ . */ ++ ++/* Testcase for BZ #15014 */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char buf[32]; ++ struct hostent *result = NULL; ++ struct hostent ret; ++ int h_err = 0; ++ int err; ++ ++ err = gethostbyname_r ("1.2.3.4", &ret, buf, sizeof (buf), &result, &h_err); ++ return err == ERANGE && h_err == NETDB_INTERNAL ? EXIT_SUCCESS : EXIT_FAILURE; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" diff --git a/src/patches/glibc/glibc-rh995972.patch b/src/patches/glibc/glibc-rh995972.patch new file mode 100644 index 0000000000..0178bca761 --- /dev/null +++ b/src/patches/glibc/glibc-rh995972.patch @@ -0,0 +1,246 @@ +commit d26dfc60edc8c6dd160eefff16a734152a835ca0 +Author: Martin von Gagern +Date: Sat May 14 21:25:43 2011 -0400 + + Fix handling of static TLS in dlopen'ed objects + + When dynamically loading a library along with several dependencies, calls to + _dl_add_to_slotinfo and _dl_update_slotinfo can become intermixed. As a + consequence, _dl_update_slotinfo will update the generation counter of the dtv + although not all of the slots belonging to that generation have been added. + Subsequent calls to _dl_add_to_slotinfo will add more slots to the same + generation, for which no storage will be allocated, as the dtv generation + checks will claim no work is necessary. This will lead to uninitialized dtv + entries and will likely cause a SIGSEGV when thread local variables are + accessed. + +diff --git a/elf/Makefile b/elf/Makefile +index 8d9657d..6efb86c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -76,6 +76,7 @@ distribute := rtld-Rules \ + tst-tlsmod12.c tst-tls10.h tst-alignmod.c tst-alignmod2.c \ + circlemod1.c circlemod1a.c circlemod2.c circlemod2a.c \ + circlemod3.c circlemod3a.c nodlopenmod2.c \ ++ tst-tls19mod1.c tst-tls19mod2.c tst-tls19mod3.c \ + tls-macros.h \ + reldep8mod1.c reldep8mod2.c reldep8mod3.c \ + nodel2mod1.c nodel2mod2.c nodel2mod3.c \ +@@ -194,7 +195,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ + restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \ + circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \ + tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \ +- tst-tls16 tst-tls17 tst-tls18 tst-tls-dlinfo \ ++ tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \ + tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \ + tst-dlmodcount tst-dlopenrpath tst-deep1 \ + tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \ +@@ -240,6 +241,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + $(patsubst %,tst-tlsmod17a%,$(tlsmod17a-suffixes)) \ + tst-tlsmod17b \ + $(patsubst %,tst-tlsmod18a%,$(tlsmod18a-suffixes)) \ ++ tst-tls19mod1 tst-tls19mod2 tst-tls19mod3 \ + circlemod1 circlemod1a circlemod2 circlemod2a \ + circlemod3 circlemod3a \ + reldep8mod1 reldep8mod2 reldep8mod3 \ +@@ -525,6 +527,8 @@ $(objpfx)tst-tlsmod13a.so: $(objpfx)tst-tlsmod13.so + # For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED + $(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so + $(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so ++$(objpfx)tst-tls19mod1.so: $(objpfx)tst-tls19mod2.so $(objpfx)tst-tls19mod3.so ++$(objpfx)tst-tls19mod3.so: $(objpfx)ld.so + $(objpfx)reldep8mod3.so: $(objpfx)reldep8mod1.so $(objpfx)reldep8mod2.so + $(objpfx)nodel2mod3.so: $(objpfx)nodel2mod1.so $(objpfx)nodel2mod2.so + $(objpfx)reldep9mod2.so: $(objpfx)reldep9mod1.so +@@ -822,6 +826,9 @@ $(patsubst %,$(objpfx)%.os,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.os : t + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ -DN=$* -DNOT_IN_libc=1 $< + $(patsubst %,$(objpfx)tst-tlsmod18a%.so,$(tlsmod18a-suffixes)): $(objpfx)tst-tlsmod18a%.so: $(objpfx)ld.so + ++$(objpfx)tst-tls19: $(libdl) ++$(objpfx)tst-tls19.out: $(objpfx)tst-tls19mod1.so ++ + CFLAGS-tst-align.c = $(stack-align-test-flags) + CFLAGS-tst-align2.c = $(stack-align-test-flags) + CFLAGS-tst-alignmod.c = $(stack-align-test-flags) +diff --git a/elf/dl-open.c b/elf/dl-open.c +index cf8e8cc..8d90b56 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -347,6 +347,7 @@ dl_open_worker (void *a) + /* If the file is not loaded now as a dependency, add the search + list of the newly loaded object to the scope. */ + bool any_tls = false; ++ unsigned int first_static_tls = new->l_searchlist.r_nlist; + for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) + { + struct link_map *imap = new->l_searchlist.r_list[i]; +@@ -425,30 +426,9 @@ dl_open_worker (void *a) + might have to increase its size. */ + _dl_add_to_slotinfo (imap); + +- if (imap->l_need_tls_init) +- { +- /* For static TLS we have to allocate the memory here +- and now. This includes allocating memory in the DTV. +- But we cannot change any DTV other than our own. So, +- if we cannot guarantee that there is room in the DTV +- we don't even try it and fail the load. +- +- XXX We could track the minimum DTV slots allocated in +- all threads. */ +- if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS) +- _dl_signal_error (0, "dlopen", NULL, N_("\ +-cannot load any more object with static TLS")); +- +- imap->l_need_tls_init = 0; +-#ifdef SHARED +- /* Update the slot information data for at least the +- generation of the DSO we are allocating data for. */ +- _dl_update_slotinfo (imap->l_tls_modid); +-#endif +- +- GL(dl_init_static_tls) (imap); +- assert (imap->l_need_tls_init == 0); +- } ++ if (imap->l_need_tls_init ++ && first_static_tls == new->l_searchlist.r_nlist) ++ first_static_tls = i; + + /* We have to bump the generation counter. */ + any_tls = true; +@@ -460,6 +440,40 @@ cannot load any more object with static TLS")); + _dl_fatal_printf (N_("\ + TLS generation counter wrapped! Please report this.")); + ++ /* We need a second pass for static tls data, because _dl_update_slotinfo ++ must not be run while calls to _dl_add_to_slotinfo are still pending. */ ++ for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ if (imap->l_need_tls_init ++ && ! imap->l_init_called ++ && imap->l_tls_blocksize > 0) ++ { ++ /* For static TLS we have to allocate the memory here and ++ now. This includes allocating memory in the DTV. But we ++ cannot change any DTV other than our own. So, if we ++ cannot guarantee that there is room in the DTV we don't ++ even try it and fail the load. ++ ++ XXX We could track the minimum DTV slots allocated in ++ all threads. */ ++ if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS) ++ _dl_signal_error (0, "dlopen", NULL, N_("\ ++cannot load any more object with static TLS")); ++ ++ imap->l_need_tls_init = 0; ++#ifdef SHARED ++ /* Update the slot information data for at least the ++ generation of the DSO we are allocating data for. */ ++ _dl_update_slotinfo (imap->l_tls_modid); ++#endif ++ ++ GL(dl_init_static_tls) (imap); ++ assert (imap->l_need_tls_init == 0); ++ } ++ } ++ + /* Notify the debugger all new objects have been relocated. */ + if (relocation_in_progress) + LIBC_PROBE (rtld_reloc_complete, 3, args->nsid, r, new); +diff --git a/elf/tst-tls19.c b/elf/tst-tls19.c +new file mode 100644 +index 0000000..acbc1d6 +--- /dev/null ++++ b/elf/tst-tls19.c +@@ -0,0 +1,27 @@ ++// BZ 12453 ++#include ++#include ++ ++ ++static int ++do_test (void) ++{ ++ void* dl = dlopen ("tst-tls19mod1.so", RTLD_LAZY | RTLD_GLOBAL); ++ if (dl == NULL) ++ { ++ printf ("Error loading tst-tls19mod1.so: %s\n", dlerror ()); ++ return 1; ++ } ++ ++ int (*fn) (void) = dlsym (dl, "foo"); ++ if (fn == NULL) ++ { ++ printf("Error obtaining symbol foo\n"); ++ return 1; ++ } ++ ++ return fn (); ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" +diff --git a/elf/tst-tls19mod1.c b/elf/tst-tls19mod1.c +new file mode 100644 +index 0000000..2790097 +--- /dev/null ++++ b/elf/tst-tls19mod1.c +@@ -0,0 +1,15 @@ ++#include ++ ++extern int bar (void); ++extern int baz (void); ++ ++int ++foo (void) ++{ ++ int v1 = bar (); ++ int v2 = baz (); ++ ++ printf ("bar=%d, baz=%d\n", v1, v2); ++ ++ return v1 != 666 || v2 != 42; ++} +diff --git a/elf/tst-tls19mod2.c b/elf/tst-tls19mod2.c +new file mode 100644 +index 0000000..cae702f +--- /dev/null ++++ b/elf/tst-tls19mod2.c +@@ -0,0 +1,13 @@ ++static int __thread tbar __attribute__ ((tls_model ("initial-exec"))) = 666; ++ ++void ++setter (int a) ++{ ++ tbar = a; ++} ++ ++int ++bar (void) ++{ ++ return tbar; ++} +diff --git a/elf/tst-tls19mod3.c b/elf/tst-tls19mod3.c +new file mode 100644 +index 0000000..e7b2801 +--- /dev/null ++++ b/elf/tst-tls19mod3.c +@@ -0,0 +1,16 @@ ++#include ++ ++static int __thread tbaz __attribute__ ((tls_model ("local-dynamic"))) = 42; ++ ++void ++setter2 (int a) ++{ ++ tbaz = a; ++} ++ ++int ++baz (void) ++{ ++ printf ("&tbaz=%p\n", &tbaz); ++ return tbaz; ++}