From bcf3103e421a9a00152da27182aa71f10fcd6491 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Feb 08 2016 11:53:33 +0000 Subject: Resolves: #1276761 CVE-2015-8777: Apply additional pointer guard hardening. --- diff --git a/glibc-rh1276761-1.patch b/glibc-rh1276761-1.patch new file mode 100644 index 0000000..2f74625 --- /dev/null +++ b/glibc-rh1276761-1.patch @@ -0,0 +1,66 @@ +commit a014cecd82b71b70a6a843e250e06b541ad524f7 +Author: Florian Weimer +Date: Thu Oct 15 09:23:07 2015 +0200 + + Always enable pointer guard [BZ #18928] + + Honoring the LD_POINTER_GUARD environment variable in AT_SECURE mode + has security implications. This commit enables pointer guard + unconditionally, and the environment variable is now ignored. + +Index: b/elf/rtld.c +=================================================================== +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -160,7 +160,6 @@ struct rtld_global_ro _rtld_global_ro at + ._dl_hwcap_mask = HWCAP_IMPORTANT, + ._dl_lazy = 1, + ._dl_fpu_control = _FPU_DEFAULT, +- ._dl_pointer_guard = 1, + ._dl_pagesize = EXEC_PAGESIZE, + ._dl_inhibit_cache = 0, + +@@ -707,15 +706,12 @@ security_init (void) + #endif + + /* Set up the pointer guard as well, if necessary. */ +- if (GLRO(dl_pointer_guard)) +- { +- uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random, +- stack_chk_guard); ++ uintptr_t pointer_chk_guard ++ = _dl_setup_pointer_guard (_dl_random, stack_chk_guard); + #ifdef THREAD_SET_POINTER_GUARD +- THREAD_SET_POINTER_GUARD (pointer_chk_guard); ++ THREAD_SET_POINTER_GUARD (pointer_chk_guard); + #endif +- __pointer_chk_guard_local = pointer_chk_guard; +- } ++ __pointer_chk_guard_local = pointer_chk_guard; + + /* We do not need the _dl_random value anymore. The less + information we leave behind, the better, so clear the +@@ -2467,9 +2463,6 @@ process_envvars (enum mode *modep) + GLRO(dl_use_load_bias) = envline[14] == '1' ? -1 : 0; + break; + } +- +- if (memcmp (envline, "POINTER_GUARD", 13) == 0) +- GLRO(dl_pointer_guard) = envline[14] != '0'; + break; + + case 14: +Index: b/sysdeps/generic/ldsodefs.h +=================================================================== +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -592,9 +592,6 @@ struct rtld_global_ro + /* List of auditing interfaces. */ + struct audit_ifaces *_dl_audit; + unsigned int _dl_naudit; +- +- /* 0 if internal pointer values should not be guarded, 1 if they should. */ +- EXTERN int _dl_pointer_guard; + }; + # define __rtld_global_attribute__ + # if IS_IN (rtld) diff --git a/glibc-rh1276761-2.patch b/glibc-rh1276761-2.patch new file mode 100644 index 0000000..9bf81f6 --- /dev/null +++ b/glibc-rh1276761-2.patch @@ -0,0 +1,378 @@ +commit 99e1dc0a688d6c25d3f422bc9f3fa29adb483339 +Author: Florian Weimer +Date: Tue Oct 6 21:27:55 2015 +0200 + + Add a test case for C++11 thread_local support + + This requires a C++ compiler with thread_local support, and a new + configure check is needed. + +Index: b/config.make.in +=================================================================== +--- a/config.make.in ++++ b/config.make.in +@@ -66,6 +66,7 @@ bind-now = @bindnow@ + have-hash-style = @libc_cv_hashstyle@ + use-default-link = @use_default_link@ + output-format = @libc_cv_output_format@ ++have-cxx-thread_local = @libc_cv_cxx_thread_local@ + + static-libgcc = @libc_cv_gcc_static_libgcc@ + +Index: b/configure +=================================================================== +--- a/configure ++++ b/configure +@@ -613,6 +613,7 @@ use_nscd + libc_cv_gcc_unwind_find_fde + libc_extra_cppflags + libc_extra_cflags ++libc_cv_cxx_thread_local + CPPUNDEFS + sizeof_long_double + have_selinux +@@ -7047,6 +7048,61 @@ if test $libc_cv_builtin_trap = yes; the + + fi + ++ac_ext=cpp ++ac_cpp='$CXXCPP $CPPFLAGS' ++ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler supports thread_local" >&5 ++$as_echo_n "checking whether the C++ compiler supports thread_local... " >&6; } ++if ${libc_cv_cxx_thread_local+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ++old_CXXFLAGS="$CXXFLAGS" ++CXXFLAGS="$CXXFLAGS -std=gnu++11" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++#include ++ ++// Compiler support. ++struct S ++{ ++ S (); ++ ~S (); ++}; ++thread_local S s; ++S * get () { return &s; } ++ ++// libstdc++ support. ++#ifndef _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL ++#error __cxa_thread_atexit_impl not supported ++#endif ++ ++_ACEOF ++if ac_fn_cxx_try_compile "$LINENO"; then : ++ libc_cv_cxx_thread_local=yes ++else ++ libc_cv_cxx_thread_local=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++CXXFLAGS="$old_CXXFLAGS" ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cxx_thread_local" >&5 ++$as_echo "$libc_cv_cxx_thread_local" >&6; } ++ ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++ ++ + ### End of automated tests. + ### Now run sysdeps configure fragments. + +Index: b/configure.ac +=================================================================== +--- a/configure.ac ++++ b/configure.ac +@@ -1925,6 +1925,39 @@ if test $libc_cv_builtin_trap = yes; the + AC_DEFINE([HAVE_BUILTIN_TRAP]) + fi + ++dnl C++ feature tests. ++AC_LANG_PUSH([C++]) ++ ++AC_CACHE_CHECK([whether the C++ compiler supports thread_local], ++ libc_cv_cxx_thread_local, [ ++old_CXXFLAGS="$CXXFLAGS" ++CXXFLAGS="$CXXFLAGS -std=gnu++11" ++AC_COMPILE_IFELSE([AC_LANG_SOURCE([ ++#include ++ ++// Compiler support. ++struct S ++{ ++ S (); ++ ~S (); ++}; ++thread_local S s; ++S * get () { return &s; } ++ ++// libstdc++ support. ++#ifndef _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL ++#error __cxa_thread_atexit_impl not supported ++#endif ++])], ++ [libc_cv_cxx_thread_local=yes], ++ [libc_cv_cxx_thread_local=no]) ++CXXFLAGS="$old_CXXFLAGS" ++]) ++AC_SUBST(libc_cv_cxx_thread_local) ++ ++AC_LANG_POP([C++]) ++dnl End of C++ feature tests. ++ + ### End of automated tests. + ### Now run sysdeps configure fragments. + +Index: b/nptl/Makefile +=================================================================== +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -205,6 +205,8 @@ CFLAGS-send.c = -fexceptions -fasynchron + + CFLAGS-pt-system.c = -fexceptions + ++CFLAGS-tst-thread_local1.o = -std=gnu++11 ++LDLIBS-tst-thread_local1 = -lstdc++ + + tests = tst-typesizes \ + tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ +@@ -274,7 +276,8 @@ tests = tst-typesizes \ + tst-getpid1 tst-getpid2 tst-getpid3 \ + tst-setuid3 \ + tst-initializers1 $(addprefix tst-initializers1-,c89 gnu89 c99 gnu99) \ +- tst-bad-schedattr ++ tst-bad-schedattr \ ++ tst-thread_local1 + xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ + tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 + test-srcs = tst-oddstacklimit +@@ -385,6 +388,11 @@ tests-special += $(objpfx)tst-tls6.out $ + endif + endif + ++# These tests require a C++ compiler and runtime with thread_local support. ++ifneq ($(have-cxx-thread_local),yes) ++tests-unsupported += tst-thread_local1 ++endif ++ + include ../Rules + + ifeq (yes,$(build-shared)) +Index: b/nptl/tst-thread_local1.cc +=================================================================== +--- /dev/null ++++ b/nptl/tst-thread_local1.cc +@@ -0,0 +1,199 @@ ++/* Test basic thread_local support. ++ Copyright (C) 2015 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++struct counter ++{ ++ int constructed {}; ++ int destructed {}; ++ ++ void reset (); ++}; ++ ++void ++counter::reset () ++{ ++ constructed = 0; ++ destructed = 0; ++} ++ ++static std::string ++to_string (const counter &c) ++{ ++ char buf[128]; ++ snprintf (buf, sizeof (buf), "%d/%d", ++ c.constructed, c.destructed); ++ return buf; ++} ++ ++template ++struct counting ++{ ++ counting () __attribute__ ((noinline, noclone)); ++ ~counting () __attribute__ ((noinline, noclone)); ++ void operation () __attribute__ ((noinline, noclone)); ++}; ++ ++template ++__attribute__ ((noinline, noclone)) ++counting::counting () ++{ ++ ++Counter->constructed; ++} ++ ++template ++__attribute__ ((noinline, noclone)) ++counting::~counting () ++{ ++ ++Counter->destructed; ++} ++ ++template ++void __attribute__ ((noinline, noclone)) ++counting::operation () ++{ ++ // Optimization barrier. ++ asm (""); ++} ++ ++static counter counter_static; ++static counter counter_anonymous_namespace; ++static counter counter_extern; ++static counter counter_function_local; ++static bool errors (false); ++ ++static std::string ++all_counters () ++{ ++ return to_string (counter_static) ++ + ' ' + to_string (counter_anonymous_namespace) ++ + ' ' + to_string (counter_extern) ++ + ' ' + to_string (counter_function_local); ++} ++ ++static void ++check_counters (const char *name, const char *expected) ++{ ++ std::string actual{all_counters ()}; ++ if (actual != expected) ++ { ++ printf ("error: %s: (%s) != (%s)\n", ++ name, actual.c_str (), expected); ++ errors = true; ++ } ++} ++ ++static void ++reset_all () ++{ ++ counter_static.reset (); ++ counter_anonymous_namespace.reset (); ++ counter_extern.reset (); ++ counter_function_local.reset (); ++} ++ ++static thread_local counting<&counter_static> counting_static; ++namespace { ++ thread_local counting<&counter_anonymous_namespace> ++ counting_anonymous_namespace; ++} ++extern thread_local counting<&counter_extern> counting_extern; ++thread_local counting<&counter_extern> counting_extern; ++ ++static void * ++thread_without_access (void *) ++{ ++ return nullptr; ++} ++ ++static void * ++thread_with_access (void *) ++{ ++ thread_local counting<&counter_function_local> counting_function_local; ++ counting_function_local.operation (); ++ check_counters ("early in thread_with_access", "0/0 0/0 0/0 1/0"); ++ counting_static.operation (); ++ counting_anonymous_namespace.operation (); ++ counting_extern.operation (); ++ check_counters ("in thread_with_access", "1/0 1/0 1/0 1/0"); ++ return nullptr; ++} ++ ++static int ++do_test (void) ++{ ++ std::function do_pthread = ++ [](void *(func) (void *)) ++ { ++ pthread_t thr; ++ int ret = pthread_create (&thr, nullptr, func, nullptr); ++ if (ret != 0) ++ { ++ errno = ret; ++ printf ("error: pthread_create: %m\n"); ++ errors = true; ++ return; ++ } ++ ret = pthread_join (thr, nullptr); ++ if (ret != 0) ++ { ++ errno = ret; ++ printf ("error: pthread_join: %m\n"); ++ errors = true; ++ return; ++ } ++ }; ++ std::function do_std_thread = ++ [](void *(func) (void *)) ++ { ++ std::thread thr{[func] {func (nullptr);}}; ++ thr.join (); ++ }; ++ ++ std::array>, 2> ++ do_thread_X ++ {{ ++ {"pthread_create", do_pthread}, ++ {"std::thread", do_std_thread}, ++ }}; ++ ++ for (auto do_thread : do_thread_X) ++ { ++ printf ("info: testing %s\n", do_thread.first); ++ check_counters ("initial", "0/0 0/0 0/0 0/0"); ++ do_thread.second (thread_without_access); ++ check_counters ("after thread_without_access", "0/0 0/0 0/0 0/0"); ++ reset_all (); ++ do_thread.second (thread_with_access); ++ check_counters ("after thread_with_access", "1/1 1/1 1/1 1/1"); ++ reset_all (); ++ } ++ ++ return errors; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" diff --git a/glibc-rh1276761-3.patch b/glibc-rh1276761-3.patch new file mode 100644 index 0000000..09f1d31 --- /dev/null +++ b/glibc-rh1276761-3.patch @@ -0,0 +1,36 @@ +commit f586e1328681b400078c995a0bb6ad301ef73549 +Author: Florian Weimer +Date: Tue Oct 6 13:12:36 2015 +0200 + + Harden tls_dtor_list with pointer mangling [BZ #19018] + +Index: b/stdlib/cxa_thread_atexit_impl.c +=================================================================== +--- a/stdlib/cxa_thread_atexit_impl.c ++++ b/stdlib/cxa_thread_atexit_impl.c +@@ -42,6 +42,10 @@ static __thread struct link_map *lm_cach + int + __cxa_thread_atexit_impl (dtor_func func, void *obj, void *dso_symbol) + { ++#ifdef PTR_MANGLE ++ PTR_MANGLE (func); ++#endif ++ + /* Prepend. */ + struct dtor_list *new = calloc (1, sizeof (struct dtor_list)); + new->func = func; +@@ -83,9 +87,13 @@ __call_tls_dtors (void) + while (tls_dtor_list) + { + struct dtor_list *cur = tls_dtor_list; ++ dtor_func func = cur->func; ++#ifdef PTR_DEMANGLE ++ PTR_DEMANGLE (func); ++#endif + tls_dtor_list = tls_dtor_list->next; + +- cur->func (cur->obj); ++ func (cur->obj); + + __rtld_lock_lock_recursive (GL(dl_load_lock)); + diff --git a/glibc.spec b/glibc.spec index c85343e..3f8eeaf 100644 --- a/glibc.spec +++ b/glibc.spec @@ -225,6 +225,10 @@ Patch1002: glibc-rh1241061.patch Patch1003: glibc-rh1184168.patch +Patch1004: glibc-rh1276761-1.patch +Patch1005: glibc-rh1276761-2.patch +Patch1006: glibc-rh1276761-3.patch + ############################################################################## # # Patches submitted, but not yet approved upstream. @@ -597,6 +601,9 @@ package or when debugging this package. %patch1001 -p1 %patch1002 -p1 %patch1003 -p1 +%patch1004 -p1 +%patch1005 -p1 +%patch1006 -p1 ############################################################################## # %%prep - Additional prep required... @@ -1771,6 +1778,7 @@ rm -f *.filelist* %changelog * Fri Feb 5 2016 Florian Weimer - 2.21-10 - Make locale -a output ASCII-only (#1184168). +- CVE-2015-8777: Apply additional pointer guard hardening. (#1276761) * Wed Oct 28 2015 Florian Weimer - 2.21-9 - Prevent malloc arena free list from becoming cyclic. (#1276112)