This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

-fstack-protector: patches for building glibc with -fstack-protector-all, and some (undiagnosed-as-yet) stack corruption in the testsuite


On 6 May 2008, Mark Seaborn uttered the following:
> OK, I found the changes you were referring to.  This file makes ld.so
> build with -fstack-protector:
> http://sources.gentoo.org/viewcvs.py/gentoo-x86/sys-libs/glibc/files/2.6/glibc-2.6-gentoo-stack_chk_fail.c?rev=1.4&view=markup

I just tried that patch. It makes ld.so *build* with -fstack-protector,
sure; but it also crashes instantly, at least with glibc 2.8 / gcc
4.3.1, -fstack-protector-all, and a randomized guard. This is probably
because you can't sensibly enter any stack-protected functions before
the guard is initialized in elf/rtld.c:security_init() (and certainly
protecting security_init() itself is a lost cause). So that rules out
using -fstack-protector-all on csu/ and a big chunk of the rtld code,
including some of the stuff that's pulled in from elsewhere in glibc
with IS_IN_rtld defined: but the patch above doesn't turn it off
anywhere.

For now I'd consider it more of a maintenance burden than it's worth to
isolate the parts of ld.so that are called before security_init(), so
I've just arranged to avoid using the stack-protector in ld.so, and
marked the few things not also in the dynamic loader which are used
during pre-guard-init static library initialization with
-fno-stack-protector. (An improvement might be to mark these with
-fno-stack-protector only when building the static library.)

You can still use -fstack-protector-all in all the rest of glibc, which
is an order of magnitude more code than ld.so and includes really hairy
stuff like malloc() and lots of functions that themselves call
string-manipulation functions, so I'd say this is a pretty good
tradeoff.

Finally, some of the module tests need adjustment: they don't link against
libc, so must specify -fno-stack-protector.

Preliminary patch against glibc 2.8 below, works for me but is perhaps
inelegant as I've not hacked at the glibc makefiles very much before.
(Also includes adjustments to allow -fstack-protector-all in CFLAGS to
work without breaking configure, at least with a GCC new enough to have
libssp: does glibc even build with GCCs older than that?)


As proof that this stuff really is useful, glibc's testsuite triggers
stack corruption inside glibc itself.

stdlib/tst-strtod.c's attempts to strtold() "42.00000000000000000001"
and "42.000000000000000000001" both fail inside __strtold_l_internal(),
i.e. stdlib/strtol_l.c. Of course we spot the problem only at the end of
the function, and this is a sufficiently complex function that I'm
putting off tracking this bug down in the hope that someone more
familiar with the code does so. The backtrace doesn't say much I haven't
already said:

(gdb) bt
#0  0xb8004424 in __kernel_vsyscall ()
#1  0x0806f613 in __stack_chk_fail () at stack_chk_fail.c:295
#2  0x0805b7c7 in ____strtold_l_internal (nptr=0x80ac0e9 "42.", '0' <repeats 20 times>, "1", endptr=0x0, group=0, loc=0x80c93c0) at ../stdlib/strtod_l.c:1571
#3  0x08054c87 in strtold (nptr=0x80ac0e9 "42.", '0' <repeats 20 times>, "1", endptr=0x0) at strtod.c:70
#4  0x0804c8ba in main (argc=1, argv=0xbfc03e24) at tst-strtod.c:170


> I think you should post changes like this.  It helps the rest of us
> understand glibc if nothing else.

Seconded. People say nasty things about glibc's build system, but it has
no equal that I know of when it comes to modelling variations between
systems. It's almost elegant, in a hackish sort of way. (I doubt it's
possible to implement anything this complex in make(1) without being a
bit hackish. :) )



Here's the patch.

2008-07-21  Nix  <nix@esperi.org.uk>

	* configure.in: Use -lssp when linking -nostdlib.

	* Makerules ($(common-objpfx)sysd-rules): Permit CFLAGS overrides
	for sysdep rules.

	Avoid stack protection for certain things.

	* csu/Makefile: Don't build startup files with stack protection.
	* libio/Makefile: Don't build code called by such files with
	stack protection.
	* misc/Makefile: Likewise, for brk and sbrk.
	* string/Makefile: Likewise, for C memcpy implementations.

	* elf/Makefile (CFLAGS-.os): Don't build rtld-specific source, or
	its corresponding code in static libraries, with stack protection.
	Don't build filter modules with stack protection.
	* elf/rtld-Rules: Don't build rtld versions of code from the rest
	of glibc with stack protection. Pass custom CFLAGS down.

	* stdlib/Makefile: Don't build tests not linked against libc with
	stack protection.

nptl:
2008-07-21  Nix  <nix@esperi.org.uk>

	* Makefile: Don't build startup files with stack protection.

Index: libc-patched/configure.in
===================================================================
--- libc-patched.orig/configure.in	2008-07-20 14:05:13.000000000 +0100
+++ libc-patched/configure.in	2008-07-20 14:05:23.000000000 +0100
@@ -1132,7 +1132,7 @@
 EOF
 if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
 	    -nostartfiles -nostdlib \
-	    -o conftest conftest.s conftest1.c 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
+	    -o conftest conftest.s conftest1.c -lssp 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
   libc_cv_asm_set_directive=yes
 else
   libc_cv_asm_set_directive=no
@@ -1194,7 +1194,7 @@
 EOF
   if ${CC-cc} -c $ASFLAGS conftest.s 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
     if AC_TRY_COMMAND([${CC-cc} $CFLAGS $LDFLAGS -shared
-				-o conftest.so conftest.o
+				-o conftest.so conftest.o -lssp
 				-nostartfiles -nostdlib
 				-Wl,--version-script,conftest.map
 		       1>&AS_MESSAGE_LOG_FD]);
@@ -1367,7 +1367,7 @@
 int foo (void) { return 1; }
 int (*fp) (void) __attribute__ ((section (".init_array"))) = foo;
 EOF
-  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -o conftest conftest.c
+  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -fno-stack-protector -o conftest conftest.c
 		     -static -nostartfiles -nostdlib 1>&AS_MESSAGE_LOG_FD])
   then
     if readelf -S conftest | fgrep INIT_ARRAY > /dev/null; then
@@ -1407,7 +1407,7 @@
 EOF
   if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 		     -fPIC -shared -o conftest.so conftest.c
-		     -nostartfiles -nostdlib
+		     -nostartfiles -nostdlib -lssp
 		     -Wl,--enable-new-dtags,-z,nodelete 1>&AS_MESSAGE_LOG_FD])
   then
     libc_cv_z_nodelete=yes
@@ -1423,7 +1423,7 @@
 EOF
   if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			-fPIC -shared -o conftest.so conftest.c
-			-nostartfiles -nostdlib
+			-nostartfiles -nostdlib -lssp
 			-Wl,--enable-new-dtags,-z,nodlopen 1>&AS_MESSAGE_LOG_FD])
   then
     libc_cv_z_nodlopen=yes
@@ -1439,7 +1439,7 @@
 EOF
   if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			-fPIC -shared -o conftest.so conftest.c
-			-nostartfiles -nostdlib
+			-nostartfiles -nostdlib -lssp
 			-Wl,--enable-new-dtags,-z,initfirst 1>&AS_MESSAGE_LOG_FD])
   then
     libc_cv_z_initfirst=yes
@@ -1474,7 +1474,7 @@
   cat > conftest.c <<EOF
 int _start (void) { return 42; }
 EOF
-  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -fno-stack-protector
 			      -fPIC -shared -o conftest.so conftest.c
 			      -Wl,-Bgroup -nostdlib 1>&AS_MESSAGE_LOG_FD])
   then
@@ -1507,7 +1507,7 @@
   if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			      -fPIC -shared -o conftest.so conftest.c
 			      -lgcc_s$libc_cv_libgcc_s_suffix -Wl,--as-needed
-			      -nostdlib 1>&AS_MESSAGE_LOG_FD])
+			      -nostdlib -lssp 1>&AS_MESSAGE_LOG_FD])
   then
     libc_cv_as_needed=yes
   else
@@ -1547,7 +1547,7 @@
 EOF
   if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			-fPIC -shared -o conftest.so conftest.c
-			-nostdlib -nostartfiles
+			-nostdlib -nostartfiles -lssp
 			-Wl,-z,combreloc 1>&AS_MESSAGE_LOG_FD])
   then
 dnl The following test is a bit weak.  We must use a tool which can test
@@ -1576,7 +1576,7 @@
 EOF
   if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			      -fPIC -shared -o conftest.so conftest.c
-			      -Wl,-z,execstack -nostdlib
+			      -Wl,-z,execstack -nostdlib -lssp
 			      1>&AS_MESSAGE_LOG_FD])
   then
     libc_cv_z_execstack=yes
@@ -1609,7 +1609,7 @@
 EOF
   if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			      -fPIC -shared -o conftest.so conftest.c
-			      -Wl,--hash-style=both -nostdlib 1>&AS_MESSAGE_LOG_FD])
+			      -Wl,--hash-style=both -nostdlib -lssp 1>&AS_MESSAGE_LOG_FD])
   then
     libc_cv_hashstyle=yes
   else
@@ -1838,7 +1838,7 @@
 dnl No \ in command here because it ends up inside ''.
 if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			    -nostdlib -nostartfiles -Wl,--no-whole-archive
-			    -o conftest conftest.c 1>&AS_MESSAGE_LOG_FD]); then
+			    -o conftest conftest.c -lssp 1>&AS_MESSAGE_LOG_FD]); then
   libc_cv_ld_no_whole_archive=yes
 else
   libc_cv_ld_no_whole_archive=no
@@ -1858,7 +1858,7 @@
 dnl No \ in command here because it ends up inside ''.
 if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
 			    -nostdlib -nostartfiles -fexceptions
-			    -o conftest conftest.c 1>&AS_MESSAGE_LOG_FD]); then
+			    -o conftest conftest.c -lssp 1>&AS_MESSAGE_LOG_FD]); then
   libc_cv_gcc_exceptions=yes
 else
   libc_cv_gcc_exceptions=no
@@ -1893,7 +1893,7 @@
 EOF
 dnl No \ in command here because it ends up inside ''.
 if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostdlib -nostartfiles
-			    -o conftest conftest.c -lgcc >&AS_MESSAGE_LOG_FD]); then
+			    -o conftest conftest.c -lgcc -lssp >&AS_MESSAGE_LOG_FD]); then
   libc_cv_gcc_builtin_expect=yes
 else
   libc_cv_gcc_builtin_expect=no
Index: libc-patched/csu/Makefile
===================================================================
--- libc-patched.orig/csu/Makefile	2008-07-20 14:05:22.000000000 +0100
+++ libc-patched/csu/Makefile	2008-07-21 13:33:58.000000000 +0100
@@ -51,6 +51,11 @@
 
 include ../Makeconfig
 
+CFLAGS-.o += -fno-stack-protector
+CFLAGS-.og += -fno-stack-protector
+CFLAGS-.op += -fno-stack-protector
+CFLAGS-.os += -fno-stack-protector
+
 ifeq (yes,$(build-shared))
 extra-objs += S$(start-installed-name)
 install-lib += S$(start-installed-name)
Index: libc-patched/Makerules
===================================================================
--- libc-patched.orig/Makerules	2008-07-20 14:05:22.000000000 +0100
+++ libc-patched/Makerules	2008-07-21 10:06:52.000000000 +0100
@@ -236,7 +236,7 @@
 	     while [ $$# -ge 2 ]; do					      \
 	       t=$$1; shift; 						      \
 	       d=$$1; shift;						      \
-	       v=$${t%%%}; [ x"$$v" = x ] || v="\$$($${v}CPPFLAGS)";	      \
+	       v=$${t%%%}; [ x"$$v" = x ] || v="\$$($${v}CPPFLAGS) \$$($${v}CFLAGS)";	      \
 	       for s in $$asm .c; do					      \
 		 echo "\$$(objpfx)$$t$$o: $$dir/$$d$$s \$$(before-compile)";  \
 		 echo "	\$$(compile-command$$s) $$v";			      \
Index: libc-patched/elf/rtld-Rules
===================================================================
--- libc-patched.orig/elf/rtld-Rules	2008-07-19 16:19:10.000000000 +0100
+++ libc-patched/elf/rtld-Rules	2008-07-21 09:28:58.000000000 +0100
@@ -98,7 +98,7 @@
 $(objpfx)rtld-%.os: %.s $(before-compile)
 	$(compile-command.s) $(rtld-CPPFLAGS)
 $(objpfx)rtld-%.os: %.c $(before-compile)
-	$(compile-command.c) $(rtld-CPPFLAGS)
+	$(compile-command.c) $(rtld-CPPFLAGS) $(rtld-CFLAGS)
 
 # The rules for generated source files.
 $(objpfx)rtld-%.os: $(objpfx)%.S $(before-compile); $(compile-command.S)
@@ -123,5 +123,6 @@
 
 # This here is the whole point of all the shenanigans.
 rtld-CPPFLAGS := -DNOT_IN_libc=1 -DIS_IN_rtld=1
+rtld-CFLAGS := -fno-stack-protector
 
 endif
Index: libc-patched/elf/Makefile
===================================================================
--- libc-patched.orig/elf/Makefile	2008-07-20 14:05:13.000000000 +0100
+++ libc-patched/elf/Makefile	2008-07-21 23:21:08.000000000 +0100
@@ -105,6 +105,14 @@
 
 include ../Makeconfig
 
+# In the dynamic loader,  routines (which include routines called before
+# the stack guard is initialized) are compiled without stack protection.
+# Do the same when they are found in the static library.
+
+CFLAGS-.o += $(if $(filter $(@F),$(patsubst %,%.o,$(elide-routines.os))),-fno-stack-protector)
+CFLAGS-.op += $(if $(filter $(@F),$(patsubst %,%.op,$(elide-routines.os))),-fno-stack-protector)
+CFLAGS-.og += $(if $(filter $(@F),$(patsubst %,%.og,$(elide-routines.os))),-fno-stack-protector)
+
 ifeq ($(unwind-find-fde),yes)
 routines += unwind-dw2-fde-glibc
 shared-only-routines += unwind-dw2-fde-glibc
@@ -395,6 +403,7 @@
 CFLAGS-cache.c = $(SYSCONF-FLAGS)
 
 CPPFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),-DNOT_IN_libc=1 -DIS_IN_rtld=1)
+CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),-fno-stack-protector)
 
 test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(strip $(modules-names))))
 generated += $(addsuffix .so,$(strip $(modules-names)))
@@ -616,6 +625,10 @@
 		  $< -Wl,-F,$(objpfx)filtmod2.so
 $(objpfx)filter: $(objpfx)filtmod1.so
 
+# These do not link against libc.
+CFLAGS-filtmod1.c = -fno-stack-protector
+CFLAGS-filtmod2.c = -fno-stack-protector
+
 $(objpfx)unload: $(libdl)
 $(objpfx)unload.out: $(objpfx)unloadmod.so
 
Index: libc-patched/nptl/Makefile
===================================================================
--- libc-patched.orig/nptl/Makefile	2008-07-19 15:05:55.000000000 +0100
+++ libc-patched/nptl/Makefile	2008-07-21 15:56:15.000000000 +0100
@@ -139,8 +139,9 @@
 # we have to compile some files with exception handling enabled, some
 # even with asynchronous unwind tables.
 
-# init.c contains sigcancel_handler().
-CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables
+# init.c contains sigcancel_handler(); parts of it are called before the
+# stack guard is initialized.
+CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables -fno-stack-protector
 # The unwind code itself,
 CFLAGS-unwind.c = -fexceptions
 CFLAGS-unwind-forcedunwind.c = -fexceptions -fasynchronous-unwind-tables
Index: libc-patched/libio/Makefile
===================================================================
--- libc-patched.orig/libio/Makefile	2007-10-13 08:32:50.000000000 +0100
+++ libc-patched/libio/Makefile	2008-07-21 17:02:22.000000000 +0100
@@ -140,6 +140,10 @@
 CFLAGS-oldtmpfile.c = $(exceptions)
 # XXX Do we need filedoalloc and wfiledoalloc?  Others?
 
+# libc_fatal() is called in extremis, and before static initialization
+# is complete: don't stack-protect it.
+CFLAGS-libc_fatal.o = -fno-stack-protector
+
 CFLAGS-tst_putwc.c = -DOBJPFX=\"$(objpfx)\"
 
 tst_wprintf2-ARGS = "Some Text"
Index: libc-patched/misc/Makefile
===================================================================
--- libc-patched.orig/misc/Makefile	2007-10-12 22:18:18.000000000 +0100
+++ libc-patched/misc/Makefile	2008-07-21 17:32:37.000000000 +0100
@@ -101,6 +101,10 @@
 CFLAGS-tst-tsearch.c = $(stack-align-test-flags)
 CFLAGS-mntent_r.c = -D_IO_MTSAFE_IO
 
+# Called during static library initialization.
+CFLAGS-sbrk.c = -fno-stack-protector
+CFLAGS-brk.c = -fno-stack-protector
+
 include ../Rules
 
 $(objpfx)libbsd-compat.a: $(dep-dummy-lib); $(make-dummy-lib)
Index: libc-patched/string/Makefile
===================================================================
--- libc-patched.orig/string/Makefile	2008-07-19 15:06:21.000000000 +0100
+++ libc-patched/string/Makefile	2008-07-21 17:03:56.000000000 +0100
@@ -73,6 +73,9 @@
 CFLAGS-test-ffs.c = -fno-builtin
 CFLAGS-tst-inlcall.c = -fno-builtin
 
+# This is used in early initialization.
+CFLAGS-memcpy.c = -fno-stack-protector
+
 ifeq ($(cross-compiling),no)
 tests: $(objpfx)tst-svc.out
 $(objpfx)tst-svc.out: tst-svc.input $(objpfx)tst-svc
Index: libc-patched/stdlib/Makefile
===================================================================
--- libc-patched.orig/stdlib/Makefile	2008-03-08 21:31:19.000000000 +0000
+++ libc-patched/stdlib/Makefile	2008-07-21 19:56:03.000000000 +0100
@@ -142,4 +142,5 @@
 
 $(objpfx)tst-putenvmod.so: $(objpfx)tst-putenvmod.os
 	$(build-module)
-CFLAGS-tst-putenvmod.c = -DNOT_IN_libc=1
+# This is not only not in libc, it's not even linked with it.
+CFLAGS-tst-putenvmod.c = -DNOT_IN_libc=1 -fno-stack-protector


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]