Submitted By: Robert Connolly (ashes) Date: 2004-12-02 Initial Package Version: 2.3.2 Upstream Status: Not submitted - They will reject it. Origin: http://www.research.ibm.com/trl/projects/security/ssp/ http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/sys/stack_protector.c Description: Smashing Stack Protector - This patch adds guard functions to Glibc. This patch depends on erandom sysctl from: http://frandom.sourceforge.net/ http://www.linuxfromscratch.org/hints/downloads/files/entropy.txt Also see: http://www.research.ibm.com/trl/projects/security/ssp/ http://www.linuxfromscratch.org/hlfs/ http://www.linuxfromscratch.org/hints/downloads/files/ssp.txt diff -Naur glibc-2.3.2.orig/sysdeps/generic/libc-start.c glibc-2.3.2/sysdeps/generic/libc-start.c --- glibc-2.3.2.orig/sysdeps/generic/libc-start.c 2003-02-14 22:59:15.000000000 +0000 +++ glibc-2.3.2/sysdeps/generic/libc-start.c 2004-12-02 15:15:24.587331216 +0000 @@ -143,6 +143,9 @@ _dl_debug_printf ("\ntransferring control: %s\n\n", argv[0]); #endif + void __guard_setup(void) __attribute__ ((constructor)); + __guard_setup (); + #ifdef HAVE_CANCELBUF if (setjmp (THREAD_SELF->cancelbuf) == 0) #endif diff -Naur glibc-2.3.2.orig/sysdeps/unix/sysv/linux/Dist glibc-2.3.2/sysdeps/unix/sysv/linux/Dist --- glibc-2.3.2.orig/sysdeps/unix/sysv/linux/Dist 2003-02-21 06:30:10.000000000 +0000 +++ glibc-2.3.2/sysdeps/unix/sysv/linux/Dist 2004-12-02 15:14:09.667720728 +0000 @@ -1,3 +1,4 @@ +stack_protector.c bits/initspin.h cmsg_nxthdr.c dl-brk.c diff -Naur glibc-2.3.2.orig/sysdeps/unix/sysv/linux/Makefile glibc-2.3.2/sysdeps/unix/sysv/linux/Makefile --- glibc-2.3.2.orig/sysdeps/unix/sysv/linux/Makefile 2002-12-16 23:36:52.000000000 +0000 +++ glibc-2.3.2/sysdeps/unix/sysv/linux/Makefile 2004-12-02 15:14:09.000000000 +0000 @@ -1,5 +1,5 @@ ifeq ($(subdir),csu) -sysdep_routines += errno-loc +sysdep_routines += errno-loc stack_protector endif ifeq ($(subdir),db2) diff -Naur glibc-2.3.2.orig/sysdeps/unix/sysv/linux/Versions glibc-2.3.2/sysdeps/unix/sysv/linux/Versions --- glibc-2.3.2.orig/sysdeps/unix/sysv/linux/Versions 2002-12-16 23:28:17.000000000 +0000 +++ glibc-2.3.2/sysdeps/unix/sysv/linux/Versions 2004-12-02 15:14:09.000000000 +0000 @@ -108,6 +108,7 @@ GLIBC_2.3.2 { # New kernel interfaces. epoll_create; epoll_ctl; epoll_wait; + __guard; __guard_setup; __stack_smash_handler; } GLIBC_PRIVATE { # needed by libpthread. diff -Naur glibc-2.3.2.orig/sysdeps/unix/sysv/linux/stack_protector.c glibc-2.3.2/sysdeps/unix/sysv/linux/stack_protector.c --- glibc-2.3.2.orig/sysdeps/unix/sysv/linux/stack_protector.c 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.3.2/sysdeps/unix/sysv/linux/stack_protector.c 2004-12-02 15:14:09.000000000 +0000 @@ -0,0 +1,114 @@ +/* $hlfs: stack_protector.c,v 1.5 2004/11/21 00:00:00 robert Exp $ */ + +/* + * Copyright (c) 2002 Hiroaki Etoh, Federico G. Schwindt, and Miodrag Vallat. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +long __guard[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +void __guard_setup(void) __attribute__ ((constructor)); +void __stack_smash_handler(char func[], int damaged __attribute__((unused))); + +void __guard_setup (void) +{ + int i, mib[3]; + size_t len; + + if (__guard[0] != 0) + return; + + /* Random is another depth in Linux, hence an array of 3. */ + mib[0] = CTL_KERN; + mib[1] = KERN_RANDOM; + mib[2] = RANDOM_ERANDOM; + + len = 4; + for (i = 0; i < sizeof(__guard) / 4; i++) { + if (sysctl(mib, 3, (char *)&((int *)__guard)[i], + &len, NULL, 0) == -1) + break; + } + + if (i < sizeof(__guard) / 4) { + int fd; + size_t size; + /* Sysctl Erandom doesn't work? Try /dev/urandom */ + fd = open ("/dev/urandom", O_RDONLY); + if (fd != -1) { + size = read (fd, (char*)&__guard, sizeof(__guard)); + close (fd) ; + if (size == sizeof(__guard)) + return; + } else { + + /* If above was unsuccessful, use the time. */ + struct timeval tv; + gettimeofday (&tv, NULL); + ((unsigned char *)__guard)[0] ^= tv.tv_usec ^ tv.tv_sec; + ((unsigned char *)__guard)[1] = 0; + ((unsigned char *)__guard)[2] = '\n'; + ((unsigned char *)__guard)[3] = 255; + } + } +} + +void __stack_smash_handler (char func[], int damaged) +{ + extern char *__progname; + const char message[] = ": stack overflow in function "; + struct sigaction sa; + sigset_t mask; + + /* Immediately block all signal handlers from running code */ + sigfillset(&mask); + sigdelset(&mask, SIGABRT); + sigprocmask(SIG_BLOCK, &mask, NULL); + + /* Print error message to stderr. */ + fprintf(stderr, "%s%s%s()\n", __progname, message, func); + /* Then to syslog. This may fail on a chroot jail... */ + syslog(LOG_CRIT, "%s%s%s()", __progname, message, func); + + bzero(&sa, sizeof(struct sigaction)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigaction(SIGABRT, &sa, NULL); + + kill(getpid(), SIGABRT); + + _exit(127); +} +