From c0e94368c6227307fb3cde96f90b350fc9572686 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Mon, 23 Sep 2013 02:05:55 -0400 Subject: [PATCH] Resolves: #985625 - Fix CVE-2013-4788: Static applications now support pointer mangling. Existing static applications must be recompiled (#985625). --- glibc-rh985625-CVE-2013-4788.patch | 504 +++++++++++++++++++++++++++++ glibc.spec | 8 +- 2 files changed, 511 insertions(+), 1 deletion(-) create mode 100644 glibc-rh985625-CVE-2013-4788.patch diff --git a/glibc-rh985625-CVE-2013-4788.patch b/glibc-rh985625-CVE-2013-4788.patch new file mode 100644 index 0000000..bdedffc --- /dev/null +++ b/glibc-rh985625-CVE-2013-4788.patch @@ -0,0 +1,504 @@ +# +# Already upstream. +# +# commit 0b1f8e35640f5b3f7af11764ade3ff060211c309 +# Author: Carlos O'Donell +# Date: Mon Sep 23 01:44:38 2013 -0400 +# +# BZ #15754: Fix test case for ARM. +# +# Statically built binaries use __pointer_chk_guard_local, +# while dynamically built binaries use __pointer_chk_guard. +# Provide the right definition depending on the test case +# we are building. +# +# commit c61b4d41c9647a54a329aa021341c0eb032b793e +# Author: Carlos O'Donell +# Date: Mon Sep 23 00:52:09 2013 -0400 +# +# BZ #15754: CVE-2013-4788 +# +# The pointer guard used for pointer mangling was not initialized for +# static applications resulting in the security feature being disabled. +# The pointer guard is now correctly initialized to a random value for +# static applications. Existing static applications need to be +# recompiled to take advantage of the fix. +# +# The test tst-ptrguard1-static and tst-ptrguard1 add regression +# coverage to ensure the pointer guards are sufficiently random +# and initialized to a default value. +# +# +diff --git a/csu/libc-start.c b/csu/libc-start.c +index e5da3ef..c898d06 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -37,6 +37,12 @@ extern void __pthread_initialize_minimal (void); + in thread local area. */ + uintptr_t __stack_chk_guard attribute_relro; + # endif ++# ifndef THREAD_SET_POINTER_GUARD ++/* Only exported for architectures that don't store the pointer guard ++ value in thread local area. */ ++uintptr_t __pointer_chk_guard_local ++ attribute_relro attribute_hidden __attribute__ ((nocommon)); ++# endif + #endif + + #ifdef HAVE_PTR_NTHREADS +@@ -195,6 +201,16 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + # else + __stack_chk_guard = stack_chk_guard; + # endif ++ ++ /* Set up the pointer guard value. */ ++ 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); ++# else ++ __pointer_chk_guard_local = pointer_chk_guard; ++# endif ++ + #endif + + /* Register the destructor of the dynamic linker if there is any. */ +diff --git a/elf/tst-ptrguard1-static.c b/elf/tst-ptrguard1-static.c +new file mode 100644 +index 0000000..7aff3b7 +--- /dev/null ++++ b/elf/tst-ptrguard1-static.c +@@ -0,0 +1 @@ ++#include "tst-ptrguard1.c" +diff --git a/elf/tst-ptrguard1.c b/elf/tst-ptrguard1.c +new file mode 100644 +index 0000000..c344a04 +--- /dev/null ++++ b/elf/tst-ptrguard1.c +@@ -0,0 +1,202 @@ ++/* 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef POINTER_CHK_GUARD ++extern uintptr_t __pointer_chk_guard; ++# define POINTER_CHK_GUARD __pointer_chk_guard ++#endif ++ ++static const char *command; ++static bool child; ++static uintptr_t ptr_chk_guard_copy; ++static bool ptr_chk_guard_copy_set; ++static int fds[2]; ++ ++static void __attribute__ ((constructor)) ++con (void) ++{ ++ ptr_chk_guard_copy = POINTER_CHK_GUARD; ++ ptr_chk_guard_copy_set = true; ++} ++ ++static int ++uintptr_t_cmp (const void *a, const void *b) ++{ ++ if (*(uintptr_t *) a < *(uintptr_t *) b) ++ return 1; ++ if (*(uintptr_t *) a > *(uintptr_t *) b) ++ return -1; ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ if (!ptr_chk_guard_copy_set) ++ { ++ puts ("constructor has not been run"); ++ return 1; ++ } ++ ++ if (ptr_chk_guard_copy != POINTER_CHK_GUARD) ++ { ++ puts ("POINTER_CHK_GUARD changed between constructor and do_test"); ++ return 1; ++ } ++ ++ if (child) ++ { ++ write (2, &ptr_chk_guard_copy, sizeof (ptr_chk_guard_copy)); ++ return 0; ++ } ++ ++ if (command == NULL) ++ { ++ puts ("missing --command or --child argument"); ++ return 1; ++ } ++ ++#define N 16 ++ uintptr_t child_ptr_chk_guards[N + 1]; ++ child_ptr_chk_guards[N] = ptr_chk_guard_copy; ++ int i; ++ for (i = 0; i < N; ++i) ++ { ++ if (pipe (fds) < 0) ++ { ++ printf ("couldn't create pipe: %m\n"); ++ return 1; ++ } ++ ++ pid_t pid = fork (); ++ if (pid < 0) ++ { ++ printf ("fork failed: %m\n"); ++ return 1; ++ } ++ ++ if (!pid) ++ { ++ if (ptr_chk_guard_copy != POINTER_CHK_GUARD) ++ { ++ puts ("POINTER_CHK_GUARD changed after fork"); ++ exit (1); ++ } ++ ++ close (fds[0]); ++ close (2); ++ dup2 (fds[1], 2); ++ close (fds[1]); ++ ++ system (command); ++ exit (0); ++ } ++ ++ close (fds[1]); ++ ++ if (TEMP_FAILURE_RETRY (read (fds[0], &child_ptr_chk_guards[i], ++ sizeof (uintptr_t))) != sizeof (uintptr_t)) ++ { ++ puts ("could not read ptr_chk_guard value from child"); ++ return 1; ++ } ++ ++ close (fds[0]); ++ ++ pid_t termpid; ++ int status; ++ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); ++ if (termpid == -1) ++ { ++ printf ("waitpid failed: %m\n"); ++ return 1; ++ } ++ else if (termpid != pid) ++ { ++ printf ("waitpid returned %ld != %ld\n", ++ (long int) termpid, (long int) pid); ++ return 1; ++ } ++ else if (!WIFEXITED (status) || WEXITSTATUS (status)) ++ { ++ puts ("child hasn't exited with exit status 0"); ++ return 1; ++ } ++ } ++ ++ qsort (child_ptr_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp); ++ ++ /* The default pointer guard is the same as the default stack guard. ++ They are only set to default if dl_random is NULL. */ ++ uintptr_t default_guard = 0; ++ unsigned char *p = (unsigned char *) &default_guard; ++ p[sizeof (uintptr_t) - 1] = 255; ++ p[sizeof (uintptr_t) - 2] = '\n'; ++ p[0] = 0; ++ ++ /* Test if the pointer guard canaries are either randomized, ++ or equal to the default pointer guard value. ++ Even with randomized pointer guards it might happen ++ that the random number generator generates the same ++ values, but if that happens in more than half from ++ the 16 runs, something is very wrong. */ ++ int ndifferences = 0; ++ int ndefaults = 0; ++ for (i = 0; i < N; ++i) ++ { ++ if (child_ptr_chk_guards[i] != child_ptr_chk_guards[i+1]) ++ ndifferences++; ++ else if (child_ptr_chk_guards[i] == default_guard) ++ ndefaults++; ++ } ++ ++ printf ("differences %d defaults %d\n", ndifferences, ndefaults); ++ ++ if (ndifferences < N / 2 && ndefaults < N / 2) ++ { ++ puts ("pointer guard values are not randomized enough"); ++ puts ("nor equal to the default value"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++#define OPT_COMMAND 10000 ++#define OPT_CHILD 10001 ++#define CMDLINE_OPTIONS \ ++ { "command", required_argument, NULL, OPT_COMMAND }, \ ++ { "child", no_argument, NULL, OPT_CHILD }, ++#define CMDLINE_PROCESS \ ++ case OPT_COMMAND: \ ++ command = optarg; \ ++ break; \ ++ case OPT_CHILD: \ ++ child = true; \ ++ break; ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" +diff --git a/ports/sysdeps/ia64/stackguard-macros.h b/ports/sysdeps/ia64/stackguard-macros.h +index dc683c2..3907293 100644 +--- a/ports/sysdeps/ia64/stackguard-macros.h ++++ b/ports/sysdeps/ia64/stackguard-macros.h +@@ -2,3 +2,6 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("adds %0 = -8, r13;; ld8 %0 = [%0]" : "=r" (x)); x; }) ++ ++#define POINTER_CHK_GUARD \ ++ ({ uintptr_t x; asm ("adds %0 = -16, r13;; ld8 %0 = [%0]" : "=r" (x)); x; }) +diff --git a/ports/sysdeps/tile/stackguard-macros.h b/ports/sysdeps/tile/stackguard-macros.h +index 589ea2b..f2e041b 100644 +--- a/ports/sysdeps/tile/stackguard-macros.h ++++ b/ports/sysdeps/tile/stackguard-macros.h +@@ -4,11 +4,17 @@ + # if __WORDSIZE == 64 + # define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("addi %0, tp, -16; ld %0, %0" : "=r" (x)); x; }) ++# define POINTER_CHK_GUARD \ ++ ({ uintptr_t x; asm ("addi %0, tp, -24; ld %0, %0" : "=r" (x)); x; }) + # else + # define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("addi %0, tp, -8; ld4s %0, %0" : "=r" (x)); x; }) ++# define POINTER_CHK_GUARD \ ++ ({ uintptr_t x; asm ("addi %0, tp, -12; ld4s %0, %0" : "=r" (x)); x; }) + # endif + #else + # define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("addi %0, tp, -8; lw %0, %0" : "=r" (x)); x; }) ++# define POINTER_CHK_GUARD \ ++ ({ uintptr_t x; asm ("addi %0, tp, -12; lw %0, %0" : "=r" (x)); x; }) + #endif +diff --git a/sysdeps/generic/stackguard-macros.h b/sysdeps/generic/stackguard-macros.h +index ababf65..77408c6 100644 +--- a/sysdeps/generic/stackguard-macros.h ++++ b/sysdeps/generic/stackguard-macros.h +@@ -2,3 +2,6 @@ + + extern uintptr_t __stack_chk_guard; + #define STACK_CHK_GUARD __stack_chk_guard ++ ++extern uintptr_t __pointer_chk_guard_local; ++#define POINTER_CHK_GUARD __pointer_chk_guard_local +diff --git a/sysdeps/i386/stackguard-macros.h b/sysdeps/i386/stackguard-macros.h +index 8c31e19..0397629 100644 +--- a/sysdeps/i386/stackguard-macros.h ++++ b/sysdeps/i386/stackguard-macros.h +@@ -2,3 +2,11 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("movl %%gs:0x14, %0" : "=r" (x)); x; }) ++ ++#define POINTER_CHK_GUARD \ ++ ({ \ ++ uintptr_t x; \ ++ asm ("movl %%gs:%c1, %0" : "=r" (x) \ ++ : "i" (offsetof (tcbhead_t, pointer_guard))); \ ++ x; \ ++ }) +diff --git a/sysdeps/powerpc/powerpc32/stackguard-macros.h b/sysdeps/powerpc/powerpc32/stackguard-macros.h +index 839f6a4..b3d0af8 100644 +--- a/sysdeps/powerpc/powerpc32/stackguard-macros.h ++++ b/sysdeps/powerpc/powerpc32/stackguard-macros.h +@@ -2,3 +2,13 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; }) ++ ++#define POINTER_CHK_GUARD \ ++ ({ \ ++ uintptr_t x; \ ++ asm ("lwz %0,%1(2)" \ ++ : "=r" (x) \ ++ : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) \ ++ ); \ ++ x; \ ++ }) +diff --git a/sysdeps/powerpc/powerpc64/stackguard-macros.h b/sysdeps/powerpc/powerpc64/stackguard-macros.h +index 9da879c..4620f96 100644 +--- a/sysdeps/powerpc/powerpc64/stackguard-macros.h ++++ b/sysdeps/powerpc/powerpc64/stackguard-macros.h +@@ -2,3 +2,13 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; }) ++ ++#define POINTER_CHK_GUARD \ ++ ({ \ ++ uintptr_t x; \ ++ asm ("ld %0,%1(2)" \ ++ : "=r" (x) \ ++ : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) \ ++ ); \ ++ x; \ ++ }) +diff --git a/sysdeps/s390/s390-32/stackguard-macros.h b/sysdeps/s390/s390-32/stackguard-macros.h +index b74c579..449e8d4 100644 +--- a/sysdeps/s390/s390-32/stackguard-macros.h ++++ b/sysdeps/s390/s390-32/stackguard-macros.h +@@ -2,3 +2,14 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("ear %0,%%a0; l %0,0x14(%0)" : "=a" (x)); x; }) ++ ++/* On s390/s390x there is no unique pointer guard, instead we use the ++ same value as the stack guard. */ ++#define POINTER_CHK_GUARD \ ++ ({ \ ++ uintptr_t x; \ ++ asm ("ear %0,%%a0; l %0,%1(%0)" \ ++ : "=a" (x) \ ++ : "i" (offsetof (tcbhead_t, stack_guard))); \ ++ x; \ ++ }) +diff --git a/sysdeps/s390/s390-64/stackguard-macros.h b/sysdeps/s390/s390-64/stackguard-macros.h +index 0cebb5f..c8270fb 100644 +--- a/sysdeps/s390/s390-64/stackguard-macros.h ++++ b/sysdeps/s390/s390-64/stackguard-macros.h +@@ -2,3 +2,17 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("ear %0,%%a0; sllg %0,%0,32; ear %0,%%a1; lg %0,0x28(%0)" : "=a" (x)); x; }) ++ ++/* On s390/s390x there is no unique pointer guard, instead we use the ++ same value as the stack guard. */ ++#define POINTER_CHK_GUARD \ ++ ({ \ ++ uintptr_t x; \ ++ asm ("ear %0,%%a0;" \ ++ "sllg %0,%0,32;" \ ++ "ear %0,%%a1;" \ ++ "lg %0,%1(%0)" \ ++ : "=a" (x) \ ++ : "i" (offsetof (tcbhead_t, stack_guard))); \ ++ x; \ ++ }) +diff --git a/sysdeps/sparc/sparc32/stackguard-macros.h b/sysdeps/sparc/sparc32/stackguard-macros.h +index c0b02b0..1eef0f1 100644 +--- a/sysdeps/sparc/sparc32/stackguard-macros.h ++++ b/sysdeps/sparc/sparc32/stackguard-macros.h +@@ -2,3 +2,6 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("ld [%%g7+0x14], %0" : "=r" (x)); x; }) ++ ++#define POINTER_CHK_GUARD \ ++ ({ uintptr_t x; asm ("ld [%%g7+0x18], %0" : "=r" (x)); x; }) +diff --git a/sysdeps/sparc/sparc64/stackguard-macros.h b/sysdeps/sparc/sparc64/stackguard-macros.h +index 80f0635..cc0c12c 100644 +--- a/sysdeps/sparc/sparc64/stackguard-macros.h ++++ b/sysdeps/sparc/sparc64/stackguard-macros.h +@@ -2,3 +2,6 @@ + + #define STACK_CHK_GUARD \ + ({ uintptr_t x; asm ("ldx [%%g7+0x28], %0" : "=r" (x)); x; }) ++ ++#define POINTER_CHK_GUARD \ ++ ({ uintptr_t x; asm ("ldx [%%g7+0x30], %0" : "=r" (x)); x; }) +diff --git a/sysdeps/x86_64/stackguard-macros.h b/sysdeps/x86_64/stackguard-macros.h +index d7fedb3..1948800 100644 +--- a/sysdeps/x86_64/stackguard-macros.h ++++ b/sysdeps/x86_64/stackguard-macros.h +@@ -4,3 +4,8 @@ + ({ uintptr_t x; \ + asm ("mov %%fs:%c1, %0" : "=r" (x) \ + : "i" (offsetof (tcbhead_t, stack_guard))); x; }) ++ ++#define POINTER_CHK_GUARD \ ++ ({ uintptr_t x; \ ++ asm ("mov %%fs:%c1, %0" : "=r" (x) \ ++ : "i" (offsetof (tcbhead_t, pointer_guard))); x; }) +diff --git a/sysdeps/generic/stackguard-macros.h b/sysdeps/generic/stackguard-macros.h +index 4fa3d96..b4a6b23 100644 +--- a/sysdeps/generic/stackguard-macros.h ++++ b/sysdeps/generic/stackguard-macros.h +@@ -3,5 +3,10 @@ + extern uintptr_t __stack_chk_guard; + #define STACK_CHK_GUARD __stack_chk_guard + ++#ifdef PTRGUARD_LOCAL + extern uintptr_t __pointer_chk_guard_local; +-#define POINTER_CHK_GUARD __pointer_chk_guard_local ++# define POINTER_CHK_GUARD __pointer_chk_guard_local ++#else ++extern uintptr_t __pointer_chk_guard; ++# define POINTER_CHK_GUARD __pointer_chk_guard ++#endif +diff --git a/elf/Makefile b/elf/Makefile +index aaa9534..cb8da93 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -121,7 +121,8 @@ endif + tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 \ + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 + tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static \ +- tst-leaks1-static tst-array1-static tst-array5-static ++ tst-leaks1-static tst-array1-static tst-array5-static \ ++ tst-ptrguard1-static + ifeq (yes,$(build-shared)) + tests-static += tst-tls9-static + tst-tls9-static-ENV = \ +@@ -146,7 +146,7 @@ + tst-audit1 tst-audit2 tst-audit8 \ + tst-stackguard1 tst-addr1 tst-thrlock \ + tst-unique1 tst-unique2 tst-unique3 tst-unique4 \ +- tst-initorder tst-initorder2 tst-relsort1 ++ tst-initorder tst-initorder2 tst-relsort1 tst-ptrguard1 + # reldep9 + test-srcs = tst-pathopt + selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) +@@ -1056,6 +1056,12 @@ + tst-stackguard1-ARGS = --command "$(host-built-program-cmd) --child" + tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child" + ++tst-ptrguard1-ARGS = --command "$(host-test-program-cmd) --child" ++# When built statically, the pointer guard interface uses ++# __pointer_chk_guard_local. ++CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL ++tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child" ++ + $(objpfx)tst-leaks1: $(libdl) + $(objpfx)tst-leaks1-mem: $(objpfx)tst-leaks1.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@ diff --git a/glibc.spec b/glibc.spec index c58f2fd..56c5ff0 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.17-c758a686 %define glibcversion 2.17 -%define glibcrelease 17%{?dist} +%define glibcrelease 18%{?dist} ### glibc.spec.in follows: %define run_glibc_tests 1 %define auxarches athlon alphaev6 @@ -132,6 +132,7 @@ Patch1009: %{name}-rh995841.patch Patch1010: %{name}-rh947892.patch Patch1011: %{name}-rh1008299.patch Patch1012: %{name}-rh985342.patch +Patch1013: %{name}-rh985625-CVE-2013-4788.patch # # Patches submitted, but not yet approved upstream. @@ -457,6 +458,7 @@ package or when debugging this package. %patch0042 -p1 %patch1011 -p1 %patch1012 -p1 +%patch1013 -p1 # On powerpc32, hp timing is only available in power4/power6 # libs, not in base, so pre-power4 dynamic linker is incompatible @@ -1247,6 +1249,10 @@ rm -f *.filelist* %endif %changelog +* Sun Sep 22 2013 Carlos O'Donell - 2.17-18 +- Fix CVE-2013-4788: Static applications now support pointer mangling. + Existing static applications must be recompiled (#985625). + * Sun Sep 22 2013 Carlos O'Donell - 2.17-17 - Fix indirect function support to avoid calling optimized routines for the wrong hardware (#985342).