Modifications to glibc-2.4 to allow it to build with stack-protection enabled throughout, and to provide a logging stack_chk_fail handler. debug/stack_chk_fail.c: provide stack_chk_fail handler that logs to syslog, and uses syscalls directly inline. debug/Makefile: build stack_chk_fail_local -fno-stack-protector Leave stack_chk_fail alone, so checking __SSP__ will show whether compiler is rigged to build SSP, and hence that we want the modified handler (which will never trigger SSP because there are no function calls). csu/Makefile, linuxthreads/Makefile, nptl/Makefile: inihibit SSP on crti/crtn (i.e. compilation of initfini) elf/rtld-Rules: Add compilation rules for .oS targets (so that stack_chk_fail_local will build for rtld). elf/Makefile: Add libc_nonshared.a to rtld build set so that stack_chk_fail_local can be found (and other modifications so that static objects are considered). Makerules: add stack_chk_fail_local.os to libc_pic.os (needed for SSP builds on x86 so that it can resolve __stack_chk_fail_local). Note this is a whole-archive link so adding libc_nonshared.a is causes too much stuff to be included. Kevin F. Quinn 2006-09-30 --- debug/stack_chk_fail.c.orig 2006-09-29 17:04:58.000000000 +0200 +++ debug/stack_chk_fail.c 2006-09-29 17:06:37.000000000 +0200 @@ -16,22 +16,269 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#if defined __SSP__ || defined __SSP_ALL__ + +/* An SSP failure handler that: + * 1) does not use any function calls - which would + * otherwise lead to nested calls to stack_chk_fail() + * 2) uses no functions from the rest of libc, which + * can lead to build problems pulling in copies of + * swathes of libc into the other libraries. + * This handler would not be valid on architectures for + * which a pointer is not either a 32-bit or 64-bit + * integer. It's definitely ok for i386, x86_64, and ppc. + */ + +#if defined __linux__ + +/* When including headers, define out the function names used + * via syscalls, since the syscall macros require that the functions + * they declare have the predefined names. This prevents duplicate + * declaration issues, which are warnings on gcc-3 but have become + * errors on gcc-4. + */ +#include +#include +#include +#include +#include + + +#ifndef __dietlibc__ + +#include + +/* from sysdeps */ +#include + +/* for the stuff in bits/socket.h */ +#include +#include + +#endif + +/* Re-configure errno to a local one */ +#ifdef errno +#undef errno +#endif +#define errno __stack_chk_fail_errno +static unsigned long int __stack_chk_fail_errno; + +#define __NR_stack_chk_fail_write __NR_write +static inline ssize_t stack_chk_fail_write(int fd, const void *buf, size_t count) __attribute__ ((always_inline)); +static inline _syscall3(ssize_t,stack_chk_fail_write, int,fd, const void *,buf, size_t,count); + +#define __NR_stack_chk_fail_exit __NR_exit +static inline void stack_chk_fail_exit(int status) __attribute__ ((always_inline)); +static inline _syscall1(void,stack_chk_fail_exit, int,status); + +#define __NR_stack_chk_fail_kill __NR_kill +static inline int stack_chk_fail_kill(pid_t pid, int sig) __attribute__ ((always_inline)); +static inline _syscall2(int,stack_chk_fail_kill, pid_t,pid, int,sig); + +#define __NR_stack_chk_fail_getpid __NR_getpid +static inline pid_t stack_chk_fail_getpid(void) __attribute__ ((always_inline)); +static inline _syscall0(pid_t,stack_chk_fail_getpid); + +#ifndef __dietlibc__ + +#define __NR_stack_chk_fail_close __NR_close +static inline int stack_chk_fail_close(int fd) __attribute__ ((always_inline)); +static inline _syscall1(int,stack_chk_fail_close, int,fd); + + +/* socketcall is present on most arches (including x86, arm (some), ppc, ppc64, mips, mips64, sparc, sparc64) + * x86_86 and some arm do not have it, but does have socket and connect syscalls + * Assume this when socketcall is not available. + */ +#ifdef __NR_socketcall + +#define __NR_stack_chk_fail_socketcall __NR_socketcall +static inline long stack_chk_fail_socketcall(int call, unsigned long *args) __attribute__ ((always_inline)); +static inline _syscall2(long,stack_chk_fail_socketcall, int,call, unsigned long *,args); + +#define DO_SOCKET(result,domain,type,protocol) \ + socketargs[0] = domain; \ + socketargs[1] = type; \ + socketargs[2] = protocol; \ + socketargs[3] = 0; \ + result = stack_chk_fail_socketcall(SOCKOP_socket, socketargs) + +#define DO_CONNECT(result,sockfd,serv_addr,addrlen) \ + socketargs[0] = sockfd; \ + socketargs[1] = (unsigned long int)serv_addr; \ + socketargs[2] = addrlen; \ + socketargs[3] = 0; \ + result = stack_chk_fail_socketcall(SOCKOP_connect, socketargs) + +#else + +#define __NR_stack_chk_fail_socket __NR_socket +static inline int stack_chk_fail_socket(int domain, int type, int protocol) __attribute__ ((always_inline)); +static inline _syscall3(int,stack_chk_fail_socket, int,domain, int,type, int,protocol); + +#define DO_SOCKET(result,domain,type,protocol) \ + result = stack_chk_fail_socket(domain,type,protocol) + +#define __NR_stack_chk_fail_connect __NR_connect +static inline int stack_chk_fail_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) __attribute__ ((always_inline)); +static inline _syscall3(int,stack_chk_fail_connect, int,sockfd, const struct sockaddr *,serv_addr, socklen_t,addrlen); + +#define DO_CONNECT(result,sockfd,serv_addr,addrlen) \ + result = stack_chk_fail_connect(sockfd,(struct sockaddr *)serv_addr, addrlen) + +#endif + +#ifndef _PATH_LOG +#define _PATH_LOG "/dev/log" +#endif + +const char path_log[]=_PATH_LOG; + +#ifdef IS_IN_rtld +static char *__progname = ""; +#else +extern char *__progname; +#endif + +#else + +static char *__progname = ""; + +#endif + +#else +/* not building on linux */ + +#error "Gentoo SSP support: glibc can only be built with SSP on Linux" + +#endif + +#else +/* not SSP */ + +#warning "Gentoo SSP support: building standard upstream handler, glibc itself is not protected" + #include #include extern char **__libc_argv attribute_hidden; +#endif +/* endif SSP */ + void -__attribute__ ((noreturn)) +__attribute__ ((__noreturn__)) __stack_chk_fail (void) { +#if defined __SSP__ || defined __SSP_ALL__ + + #define MESSAGE_BUFSIZ 512 + pid_t pid; + int plen, i; + char message[MESSAGE_BUFSIZ]; + const char msg_prefix[]="*** stack smashing detected ***: "; + const char msg_suffix[]=" terminated\n"; + const char msg_unknown[]=""; +#ifndef __dietlibc__ + int log_socket, connect_result; + struct sockaddr_un sock; +#ifdef __NR_socketcall + unsigned long int *socketargs=(unsigned long int *)alloca(sizeof(unsigned long int)*4); +#endif +#endif + + /* build message */ +#define strconcat(str) \ + i=0; while ((str[i] != '\0') && ((i+plen)<(MESSAGE_BUFSIZ-1))) {\ + message[plen+i]=str[i];\ + i++;\ + }\ + plen+=i; + plen=0; + strconcat(msg_prefix); + if (__progname != (char *)0) { + strconcat(__progname); + } else { + strconcat(msg_unknown); + } + strconcat(msg_suffix); + message[plen++]='\0'; + + /* Write out error message to STDERR */ + stack_chk_fail_write(STDERR_FILENO, message, plen); + +#ifndef __dietlibc__ + /* Log to syslog; socket write to /dev/log */ + + /* Build socket address */ + sock.sun_family = AF_UNIX; + i=0; while ((path_log[i] != '\0') && (i<(sizeof(sock.sun_path)-1))) { + sock.sun_path[i]=path_log[i]; + i++; + } + sock.sun_path[i]='\0'; + + /* Try SOCK_DGRAM connection to syslog */ + connect_result=-1; + DO_SOCKET(log_socket,AF_UNIX,SOCK_DGRAM,0); + if (log_socket != -1) { + DO_CONNECT(connect_result,log_socket,(&sock),(sizeof(sock))); + } + if (connect_result == -1) { + if (log_socket != -1) { + stack_chk_fail_close(log_socket); + } + /* Try SOCK_STREAM connection to syslog */ + DO_SOCKET(log_socket,AF_UNIX,SOCK_STREAM,0); + if (log_socket != -1) { + DO_CONNECT(connect_result,log_socket,(&sock),(sizeof(sock))); + } + } + /* If a successful connection was made, log the message */ + if (connect_result != -1) { + stack_chk_fail_write(log_socket,message,plen); + } + if (log_socket != -1) { + stack_chk_fail_close(log_socket); + } +#endif + + /* Suicide - note; sigactions can't be added to SIGKILL, nor can it be masked */ + pid=stack_chk_fail_getpid(); + stack_chk_fail_kill(pid,SIGKILL); + + /* In case the kill didn't work, exit anyway + * The loop prevents gcc thinking this routine returns + */ + while (1) stack_chk_fail_exit(EXIT_FAILURE); + +#else + /* The loop is added only to keep gcc happy. */ while (1) __libc_message (1, "*** stack smashing detected ***: %s terminated\n", __libc_argv[0] ?: ""); + +#endif } #ifdef ENABLE_OLD_SSP_COMPAT +#ifdef __x86_64 +/* For reasons that are not yet clear, x86_64 refuses to allow the alias to + * be setup, giving the error: + * '__stack_smash_handler' aliased to external symbol '__stack_chk_fail' + * which usually means the same-file rule has been violated, although this + * is not the case here. + */ +void +__attribute__ ((__noreturn__)) +__stack_smash_handler(void) +{ + __stack_chk_fail(); +} +#else strong_alias (__stack_chk_fail, __stack_smash_handler) #endif +#endif --- debug/Makefile.orig 2006-09-30 17:06:31.000000000 +0200 +++ debug/Makefile 2006-09-30 17:12:45.000000000 +0200 @@ -70,6 +71,7 @@ CFLAGS-pread64_chk.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-recv_chk.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-recvfrom_chk.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-stack_chk_fail_local.c = -fno-stack-protector tst-chk1-ENV = LOCPATH=$(common-objpfx)localedata tst-chk2-ENV = LOCPATH=$(common-objpfx)localedata --- csu/Makefile.orig 2006-09-30 13:22:19.000000000 +0200 +++ csu/Makefile 2006-09-30 13:22:38.000000000 +0200 @@ -93,7 +93,7 @@ $(crtstuff:%=$(objpfx)%.o): %.o: %.S $(objpfx)defs.h $(compile.S) -g0 $(ASFLAGS-.os) -o $@ -CFLAGS-initfini.s = -g0 -fPIC -fno-inline-functions $(fno-unit-at-a-time) +CFLAGS-initfini.s = -g0 -fPIC -fno-inline-functions -fno-stack-protector $(fno-unit-at-a-time) vpath initfini.c $(sysdirs) --- linuxthreads/Makefile.orig 2006-09-30 14:39:33.000000000 +0200 +++ linuxthreads/Makefile 2006-09-30 14:39:42.000000000 +0200 @@ -102,7 +102,7 @@ extra-objs += $(crti-objs) $(crtn-objs) omit-deps += crti crtn -CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions $(fno-unit-at-a-time) +CFLAGS-pt-initfini.s = -g0 -fPIC -fno-stack-protector -fno-inline-functions $(fno-unit-at-a-time) endif librt-tests = ex10 ex11 tst-clock1 --- nptl/Makefile.orig 2006-09-30 14:36:46.000000000 +0200 +++ nptl/Makefile 2006-09-30 14:37:06.000000000 +0200 @@ -335,7 +335,7 @@ extra-objs += $(crti-objs) $(crtn-objs) omit-deps += crti crtn -CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions $(fno-unit-at-a-time) +CFLAGS-pt-initfini.s = -g0 -fPIC -fno-stack-protector -fno-inline-functions $(fno-unit-at-a-time) endif CFLAGS-flockfile.c = -D_IO_MTSAFE_IO --- elf/Makefile.orig 2006-10-01 01:37:29.000000000 +0200 +++ elf/Makefile 2006-10-01 01:44:19.000000000 +0200 @@ -263,7 +263,7 @@ # are compiled with special flags, and puts these modules into rtld-libc.a # for us. Then we do the real link using rtld-libc.a instead of libc_pic.a. -$(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a +$(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a $(common-objpfx)libc_nonshared.a @-rm -f $@T $(reloc-link) -o $@.o '-Wl,-(' $^ -lgcc '-Wl,-)' -Wl,-Map,$@T rm -f $@.o @@ -271,7 +271,7 @@ $(objpfx)librtld.mk: $(objpfx)librtld.map Makefile LC_ALL=C \ - sed -n 's@^$(common-objpfx)\([^(]*\)(\([^)]*\.os\)) *.*$$@\1 \2@p' \ + sed -n 's@^$(common-objpfx)\([^(]*\)(\([^)]*\.o[Ss]\)) *.*$$@\1 \2@p' \ $< | \ while read lib file; do \ case $$lib in \ @@ -281,6 +281,12 @@ LC_ALL=C \ sed 's@^$(common-objpfx)\([^/]*\)/stamp\.os$$@rtld-\1'" +=$$file@"\ ;; \ + libc_nonshared.a) \ + LC_ALL=C fgrep -l /$$file \ + $(common-objpfx)stamp.oS $(common-objpfx)*/stamp.oS | \ + LC_ALL=C \ + sed 's@^$(common-objpfx)\([^/]*\)/stamp\.oS$$@rtld-\1'" +=$$file@"\ + ;; \ */*.a) \ echo rtld-$${lib%%/*} += $$file ;; \ *) echo "Wasn't expecting $$lib($$file)" >&2; exit 1 ;; \ --- elf/rtld-Rules.orig 2006-10-01 01:41:07.000000000 +0200 +++ elf/rtld-Rules 2006-10-01 01:41:40.000000000 +0200 @@ -96,11 +96,13 @@ $(objpfx)rtld-%.os: %.S $(before-compile); $(compile-command.S) $(objpfx)rtld-%.os: %.s $(before-compile); $(compile-command.s) $(objpfx)rtld-%.os: %.c $(before-compile); $(compile-command.c) +$(objpfx)rtld-%.oS: %.c $(before-compile); $(compile-command.c) # The rules for generated source files. $(objpfx)rtld-%.os: $(objpfx)%.S $(before-compile); $(compile-command.S) $(objpfx)rtld-%.os: $(objpfx)%.s $(before-compile); $(compile-command.s) $(objpfx)rtld-%.os: $(objpfx)%.c $(before-compile); $(compile-command.c) +$(objpfx)rtld-%.oS: $(objpfx)%.c $(before-compile); $(compile-command.c) # The command line setting of rtld-modules (see above) tells us # what we need to build, and that tells us what dependency files we need. --- Makerules.orig 2006-10-01 11:26:40.000000000 +0200 +++ Makerules 2006-10-01 11:27:30.000000000 +0200 @@ -602,7 +602,7 @@ # from being allocated in libc.so, which introduces evil dependencies # between libc.so and ld.so, which can make it impossible to upgrade. ifeq ($(elf),yes) -$(common-objpfx)libc_pic.os: $(common-objpfx)libc_pic.a +$(common-objpfx)libc_pic.os: $(common-objpfx)libc_pic.a $(common-objpfx)debug/stack_chk_fail_local.oS $(LINK.o) -nostdlib -nostartfiles -r -o $@ \ $(LDFLAGS-c_pic.os) -Wl,-d -Wl,--whole-archive $^ # Use our own special initializer and finalizer files for libc.so.