This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "IPFire 2.x development tree".
The branch, master has been updated via fe875de81331d600a78df66e92ac6647d5e91578 (commit) from ffeb717f2d6f456a0f572ae843d8db53f061062c (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit fe875de81331d600a78df66e92ac6647d5e91578 Author: Michael Tremer michael.tremer@ipfire.org Date: Tue Jan 27 22:01:24 2015 +0100
glibc: Backport hotfixes from RHEL
-----------------------------------------------------------------------
Summary of changes: lfs/glibc | 13 +- src/patches/glibc/glibc-rh1019916.patch | 39 +++ ...glibc-rh1091162.patch => glibc-rh1027101.patch} | 0 src/patches/glibc/glibc-rh1027261.patch | 28 ++ src/patches/glibc/glibc-rh1032628.patch | 166 ++++++++++ ...glibc-rh1098050.patch => glibc-rh1044628.patch} | 0 src/patches/glibc/glibc-rh1111460.patch | 341 +++++++++++++++++++++ src/patches/glibc/glibc-rh1139571.patch | 154 ++++++++++ src/patches/glibc/glibc-rh1154563.patch | 333 ++++++++++++++++++++ src/patches/glibc/glibc-rh1170121.patch | 163 ++++++++++ src/patches/glibc/glibc-rh1183533.patch | 210 +++++++++++++ src/patches/glibc/glibc-rh995972.patch | 246 +++++++++++++++ 12 files changed, 1691 insertions(+), 2 deletions(-) create mode 100644 src/patches/glibc/glibc-rh1019916.patch rename src/patches/glibc/{glibc-rh1091162.patch => glibc-rh1027101.patch} (100%) create mode 100644 src/patches/glibc/glibc-rh1027261.patch create mode 100644 src/patches/glibc/glibc-rh1032628.patch rename src/patches/glibc/{glibc-rh1098050.patch => glibc-rh1044628.patch} (100%) create mode 100644 src/patches/glibc/glibc-rh1111460.patch create mode 100644 src/patches/glibc/glibc-rh1139571.patch create mode 100644 src/patches/glibc/glibc-rh1154563.patch create mode 100644 src/patches/glibc/glibc-rh1170121.patch create mode 100644 src/patches/glibc/glibc-rh1183533.patch create mode 100644 src/patches/glibc/glibc-rh995972.patch
Difference in files: diff --git a/lfs/glibc b/lfs/glibc index df3e392..11d374e 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 0000000..f67af90 --- /dev/null +++ b/src/patches/glibc/glibc-rh1019916.patch @@ -0,0 +1,39 @@ +commit 48b67d71ec677d1b3168e52a68b644784cead604 +Author: Andreas Schwab schwab@redhat.com +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-rh1027101.patch b/src/patches/glibc/glibc-rh1027101.patch new file mode 100644 index 0000000..7825682 --- /dev/null +++ b/src/patches/glibc/glibc-rh1027101.patch @@ -0,0 +1,58 @@ +commit 362b47fe09ca9a928d444c7e2f7992f7f61bfc3e +Author: Maxim Kuvyrkov maxim@kugelworks.com +Date: Tue Dec 24 09:44:50 2013 +1300 + + Fix race in free() of fastbin chunk: BZ #15073 + + Perform sanity check only if we have_lock. Due to lockless nature of fastbins + we need to be careful derefencing pointers to fastbin entries (chunksize(old) + in this case) in multithreaded environments. + + The fix is to add have_lock to the if-condition checks. The rest of the patch + only makes code more readable. + + * malloc/malloc.c (_int_free): Perform sanity check only if we + have_lock. + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index b1668b5..5e419ad 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -3783,25 +3783,29 @@ _int_free(mstate av, mchunkptr p, int have_lock) + fb = &fastbin (av, idx); + + #ifdef ATOMIC_FASTBINS +- mchunkptr fd; +- mchunkptr old = *fb; ++ /* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ ++ mchunkptr old = *fb, old2; + unsigned int old_idx = ~0u; + do + { +- /* Another simple check: make sure the top of the bin is not the +- record we are going to add (i.e., double free). */ ++ /* Check that the top of the bin is not the record we are going to add ++ (i.e., double free). */ + if (__builtin_expect (old == p, 0)) + { + errstr = "double free or corruption (fasttop)"; + goto errout; + } +- if (old != NULL) ++ /* Check that size of fastbin chunk at the top is the same as ++ size of the chunk that we are adding. We can dereference OLD ++ only if we have the lock, otherwise it might have already been ++ deallocated. See use of OLD_IDX below for the actual check. */ ++ if (have_lock && old != NULL) + old_idx = fastbin_index(chunksize(old)); +- p->fd = fd = old; ++ p->fd = old2 = old; + } +- while ((old = catomic_compare_and_exchange_val_rel (fb, p, fd)) != fd); ++ while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2); + +- if (fd != NULL && __builtin_expect (old_idx != idx, 0)) ++ if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0)) + { + errstr = "invalid fastbin entry (free)"; + goto errout; diff --git a/src/patches/glibc/glibc-rh1027261.patch b/src/patches/glibc/glibc-rh1027261.patch new file mode 100644 index 0000000..8599cf0 --- /dev/null +++ b/src/patches/glibc/glibc-rh1027261.patch @@ -0,0 +1,28 @@ +commit 4d653a59ffeae0f46f76a40230e2cfa9587b7e7e +Author: Siddhesh Poyarekar siddhesh@redhat.com +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, + "<total type="fast" count="%zu" size="%zu"/>\n" + "<total type="rest" count="%zu" size="%zu"/>\n" ++ "<total type="mmap" count="%d" size="%zu"/>\n" + "<system type="current" size="%zu"/>\n" + "<system type="max" size="%zu"/>\n" + "<aspace type="total" size="%zu"/>\n" + "<aspace type="mprotect" size="%zu"/>\n" + "</malloc>\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 0000000..6140c19 --- /dev/null +++ b/src/patches/glibc/glibc-rh1032628.patch @@ -0,0 +1,166 @@ +commit 028478fa40d85a73b19638dbe3f83b1acebf370c +Author: Ulrich Drepper drepper@gmail.com +Date: Thu Mar 10 12:51:33 2011 -0500 + + Fix copy relocations handling of unique objects. + + 2011-03-06 Ulrich Drepper drepper@gmail.com + +and a part of: + +commit 33f85a3fb9fe432e0ebf6a3481bc2d5e29cb605f +Author: Ulrich Drepper drepper@gmail.com +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 <cstdio> ++#include "../dlfcn/dlfcn.h" ++ ++int t = S<char>::i; ++ ++int ++main (void) ++{ ++ std::printf ("%d %d\n", S<char>::i, t); ++ int result = S<char>::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<typename T> ++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 <cstdio> ++#include "tst-unique3.h" ++template<typename T> int S<T>::i = 1; ++static int i = S<char>::i; ++ ++int ++in_lib (void) ++{ ++ std::printf ("in_lib: %d %d\n", S<char>::i, i); ++ return S<char>::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 <cstdio> ++#include "tst-unique3.h" ++ ++template<typename T> int S<T>::i; ++ ++extern "C" ++int ++in_lib2 () ++{ ++ std::printf ("in_lib2: %d\n", S<char>::i); ++ return S<char>::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 <bits/dlfcn.h> + +-extern void _dl_mcount_wrapper_check (void *__selfpc); + libc_hidden_proto (_dl_mcount_wrapper_check) diff --git a/src/patches/glibc/glibc-rh1044628.patch b/src/patches/glibc/glibc-rh1044628.patch new file mode 100644 index 0000000..e5ff3ca --- /dev/null +++ b/src/patches/glibc/glibc-rh1044628.patch @@ -0,0 +1,28 @@ +commit cf26a0cb6a0bbaca46a01ddad6662e5e5159a32a +Author: Siddhesh Poyarekar siddhesh@redhat.com +Date: Thu May 15 12:33:11 2014 +0530 + + Return EAI_AGAIN for AF_UNSPEC when herrno is TRY_AGAIN (BZ #16849) + + getaddrinfo correctly returns EAI_AGAIN for AF_INET and AF_INET6 + queries. For AF_UNSPEC however, an older change + (a682a1bf553b1efe4dbb03207fece5b719cec482) broke the check and due to + that the returned error was EAI_NONAME. + + This patch fixes the check so that a non-authoritative not-found is + returned as EAI_AGAIN to the user instead of EAI_NONAME. + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 6258330..8f392b9 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -867,8 +867,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (status != NSS_STATUS_TRYAGAIN + || rc != ERANGE || herrno != NETDB_INTERNAL) + { +- if (status == NSS_STATUS_TRYAGAIN +- && herrno == TRY_AGAIN) ++ if (herrno == TRY_AGAIN) + no_data = EAI_AGAIN; + else + no_data = herrno == NO_DATA; diff --git a/src/patches/glibc/glibc-rh1091162.patch b/src/patches/glibc/glibc-rh1091162.patch deleted file mode 100644 index 7825682..0000000 --- a/src/patches/glibc/glibc-rh1091162.patch +++ /dev/null @@ -1,58 +0,0 @@ -commit 362b47fe09ca9a928d444c7e2f7992f7f61bfc3e -Author: Maxim Kuvyrkov maxim@kugelworks.com -Date: Tue Dec 24 09:44:50 2013 +1300 - - Fix race in free() of fastbin chunk: BZ #15073 - - Perform sanity check only if we have_lock. Due to lockless nature of fastbins - we need to be careful derefencing pointers to fastbin entries (chunksize(old) - in this case) in multithreaded environments. - - The fix is to add have_lock to the if-condition checks. The rest of the patch - only makes code more readable. - - * malloc/malloc.c (_int_free): Perform sanity check only if we - have_lock. - -diff --git a/malloc/malloc.c b/malloc/malloc.c -index b1668b5..5e419ad 100644 ---- a/malloc/malloc.c -+++ b/malloc/malloc.c -@@ -3783,25 +3783,29 @@ _int_free(mstate av, mchunkptr p, int have_lock) - fb = &fastbin (av, idx); - - #ifdef ATOMIC_FASTBINS -- mchunkptr fd; -- mchunkptr old = *fb; -+ /* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ -+ mchunkptr old = *fb, old2; - unsigned int old_idx = ~0u; - do - { -- /* Another simple check: make sure the top of the bin is not the -- record we are going to add (i.e., double free). */ -+ /* Check that the top of the bin is not the record we are going to add -+ (i.e., double free). */ - if (__builtin_expect (old == p, 0)) - { - errstr = "double free or corruption (fasttop)"; - goto errout; - } -- if (old != NULL) -+ /* Check that size of fastbin chunk at the top is the same as -+ size of the chunk that we are adding. We can dereference OLD -+ only if we have the lock, otherwise it might have already been -+ deallocated. See use of OLD_IDX below for the actual check. */ -+ if (have_lock && old != NULL) - old_idx = fastbin_index(chunksize(old)); -- p->fd = fd = old; -+ p->fd = old2 = old; - } -- while ((old = catomic_compare_and_exchange_val_rel (fb, p, fd)) != fd); -+ while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2); - -- if (fd != NULL && __builtin_expect (old_idx != idx, 0)) -+ if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0)) - { - errstr = "invalid fastbin entry (free)"; - goto errout; diff --git a/src/patches/glibc/glibc-rh1098050.patch b/src/patches/glibc/glibc-rh1098050.patch deleted file mode 100644 index e5ff3ca..0000000 --- a/src/patches/glibc/glibc-rh1098050.patch +++ /dev/null @@ -1,28 +0,0 @@ -commit cf26a0cb6a0bbaca46a01ddad6662e5e5159a32a -Author: Siddhesh Poyarekar siddhesh@redhat.com -Date: Thu May 15 12:33:11 2014 +0530 - - Return EAI_AGAIN for AF_UNSPEC when herrno is TRY_AGAIN (BZ #16849) - - getaddrinfo correctly returns EAI_AGAIN for AF_INET and AF_INET6 - queries. For AF_UNSPEC however, an older change - (a682a1bf553b1efe4dbb03207fece5b719cec482) broke the check and due to - that the returned error was EAI_NONAME. - - This patch fixes the check so that a non-authoritative not-found is - returned as EAI_AGAIN to the user instead of EAI_NONAME. - -diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c -index 6258330..8f392b9 100644 ---- a/sysdeps/posix/getaddrinfo.c -+++ b/sysdeps/posix/getaddrinfo.c -@@ -867,8 +867,7 @@ gaih_inet (const char *name, const struct gaih_service *service, - if (status != NSS_STATUS_TRYAGAIN - || rc != ERANGE || herrno != NETDB_INTERNAL) - { -- if (status == NSS_STATUS_TRYAGAIN -- && herrno == TRY_AGAIN) -+ if (herrno == TRY_AGAIN) - no_data = EAI_AGAIN; - else - no_data = herrno == NO_DATA; diff --git a/src/patches/glibc/glibc-rh1111460.patch b/src/patches/glibc/glibc-rh1111460.patch new file mode 100644 index 0000000..1a4315d --- /dev/null +++ b/src/patches/glibc/glibc-rh1111460.patch @@ -0,0 +1,341 @@ +commit 7cbcdb3699584db8913ca90f705d6337633ee10f +Author: Siddhesh Poyarekar siddhesh@redhat.com +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 fweimer@redhat.com +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 <sysdeps/unix/readdir_r.c> + diff --git a/src/patches/glibc/glibc-rh1139571.patch b/src/patches/glibc/glibc-rh1139571.patch new file mode 100644 index 0000000..b1320a7 --- /dev/null +++ b/src/patches/glibc/glibc-rh1139571.patch @@ -0,0 +1,154 @@ +commit 41488498b6d9440ee66ab033808cce8323bba7ac +Author: Florian Weimer fweimer@redhat.com +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 0000000..22821b1 --- /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 <stdio.h> ++#include <stdlib.h> ++ ++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 <stdio.h> ++#include <stdlib.h> ++ ++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 drepper@cygnus.com, 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 ++ http://www.gnu.org/licenses/. */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <malloc.h> ++#include <dlfcn.h> ++ ++#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 0000000..1accbf3 --- /dev/null +++ b/src/patches/glibc/glibc-rh1170121.patch @@ -0,0 +1,163 @@ +# +# commit a39208bd7fb76c1b01c127b4c61f9bfd915bfe7c +# Author: Carlos O'Donell carlos@redhat.com +# 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 0000000..9263cd5 --- /dev/null +++ b/src/patches/glibc/glibc-rh1183533.patch @@ -0,0 +1,210 @@ +commit d5dd6189d506068ed11c8bfa1e1e9bffde04decd +Author: Andreas Schwab schwab@suse.de +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 ++ http://www.gnu.org/licenses/. */ ++ ++/* Testcase for BZ #15014 */ ++ ++#include <stdlib.h> ++#include <netdb.h> ++#include <errno.h> ++ ++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 0000000..0178bca --- /dev/null +++ b/src/patches/glibc/glibc-rh995972.patch @@ -0,0 +1,246 @@ +commit d26dfc60edc8c6dd160eefff16a734152a835ca0 +Author: Martin von Gagern Martin.vGagern@gmx.net +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 <stdio.h> ++#include <dlfcn.h> ++ ++ ++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 <stdio.h> ++ ++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 <stdio.h> ++ ++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; ++}
hooks/post-receive -- IPFire 2.x development tree