diff options
-rw-r--r-- | libc/sysdeps/linux/common/ssp.c | 176 |
1 files changed, 100 insertions, 76 deletions
diff --git a/libc/sysdeps/linux/common/ssp.c b/libc/sysdeps/linux/common/ssp.c index c7a863d53..5ce4d831e 100644 --- a/libc/sysdeps/linux/common/ssp.c +++ b/libc/sysdeps/linux/common/ssp.c @@ -1,97 +1,121 @@ +/* + * Distributed under the terms of the GNU General Public License v2 + * $Header: /var/cvs/uClibc/libc/sysdeps/linux/common/ssp.c,v 1.3 2004/11/11 03:12:37 solar Exp $ + * + * This is a modified version of Hiroaki Etoh's stack smashing routines + * implemented for glibc. + * + * The following people have contributed input to this code. + * Ned Ludd - <solar[@]gentoo.org> + * Alexander Gabert - <pappy[@]gentoo.org> + * The PaX Team - <pageexec[@]freemail.hu> + * Peter S. Mazinger - <ps.m[@]gmx.net> + * Yoann Vandoorselaere - <yoann[@]prelude-ids.org> + * Robert Connolly - <robert[@]linuxfromscratch.org> + * Cory Visi <cory@visi.name> + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> - -#ifdef _POSIX_SOURCE #include <signal.h> -#endif - -#if defined(HAVE_SYSLOG) #include <sys/types.h> -#include <sys/socket.h> #include <sys/un.h> - #include <sys/syslog.h> -#ifndef _PATH_LOG -#define _PATH_LOG "/dev/log" -#endif +#include <sys/time.h> +#include <sys/sysctl.h> + +#ifdef __PROPOLICE_BLOCK_SEGV__ +#define SSP_SIGTYPE SIGSEGV +#elif __PROPOLICE_BLOCK_KILL__ +#define SSP_SIGTYPE SIGKILL +#else +#define SSP_SIGTYPE SIGABRT #endif -long __guard[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +unsigned long __guard = 0UL; -void __guard_setup (void) +void __guard_setup(void) { - int fd; - if (__guard[0]!=0) return; - fd = open ("/dev/urandom", 0); - if (fd != -1) { - ssize_t size = read (fd, (char*)&__guard, sizeof(__guard)); - close (fd) ; - if (size == sizeof(__guard)) return; - } - /* If a random generator can't be used, the protector switches the guard - to the "terminator canary" */ - ((char*)__guard)[0] = 0; ((char*)__guard)[1] = 0; - ((char*)__guard)[2] = '\n'; ((char*)__guard)[3] = 255; -} + size_t size; + struct timeval tv; -void __stack_smash_handler (char func[], int damaged) -{ -#if defined (__GNU_LIBRARY__) - extern char * __progname; -#endif - const char message[] = ": stack smashing attack in function "; - int bufsz = 512, len; - char buf[bufsz]; -#if defined(HAVE_SYSLOG) - int LogFile; - struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */ +#ifdef HAVE_DEV_ERANDOM + int mib[3]; #endif -#ifdef _POSIX_SOURCE - { - sigset_t mask; - sigfillset(&mask); - sigdelset(&mask, SIGABRT); /* Block all signal handlers */ - sigprocmask(SIG_BLOCK, &mask, NULL); /* except SIGABRT */ - } + + if (__guard != 0UL) + return; + +#ifndef __SSP_QUICK_CANARY__ +#ifdef HAVE_DEV_ERANDOM + /* Random is another depth in Linux, hence an array of 3. */ + mib[0] = CTL_KERN; + mib[1] = KERN_RANDOM; + mib[2] = RANDOM_ERANDOM; + + size = sizeof(unsigned long); + if (__sysctl(mib, 3, &__guard, &size, NULL, 0) != (-1)) + if (__guard != 0UL) + return; #endif + /* + * Attempt to open kernel pseudo random device if one exists before + * opening urandom to avoid system entropy depletion. + */ + { + int fd; - strcpy(buf, "<2>"); len=3; /* send LOG_CRIT */ -#if defined (__GNU_LIBRARY__) - strncat(buf, __progname, bufsz-len-1); len = strlen(buf); +#ifdef HAVE_DEV_ERANDOM + if ((fd = open("/dev/erandom", O_RDONLY)) == (-1)) #endif - if (bufsz>len) {strncat(buf, message, bufsz-len-1); len = strlen(buf);} - if (bufsz>len) {strncat(buf, func, bufsz-len-1); len = strlen(buf);} - /* print error message */ - write (STDERR_FILENO, buf+3, len-3); -#if defined(HAVE_SYSLOG) - if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) != -1) { - - /* - * Send "found" message to the "/dev/log" path - */ - SyslogAddr.sun_family = AF_UNIX; - (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, - sizeof(SyslogAddr.sun_path) - 1); - SyslogAddr.sun_path[sizeof(SyslogAddr.sun_path) - 1] = '\0'; - sendto(LogFile, buf, len, 0, (struct sockaddr *)&SyslogAddr, - sizeof(SyslogAddr)); - } + fd = open("/dev/urandom", O_RDONLY); + if (fd != (-1)) { + size = read(fd, (char *) &__guard, sizeof(__guard)); + close(fd); + if (size == sizeof(__guard)) + return; + } + } #endif + /* If sysctl was unsuccessful, use the "terminator canary". */ + __guard = 0xFF0A0D00UL; -#ifdef _POSIX_SOURCE - { /* Make sure the default handler is associated with SIGABRT */ - struct sigaction sa; - - memset(&sa, 0, sizeof(struct sigaction)); - sigfillset(&sa.sa_mask); /* Block all signals */ - sa.sa_flags = 0; - sa.sa_handler = SIG_DFL; - sigaction(SIGABRT, &sa, NULL); - (void)kill(getpid(), SIGABRT); - } -#endif - _exit(127); + /* Everything failed? Or we are using a weakened model of the + * terminator canary */ + + gettimeofday(&tv, NULL); + __guard ^= tv.tv_usec ^ tv.tv_sec; } +void __stack_smash_handler(char func[], int damaged) +{ + extern char *__progname; + const char message[] = ": stack smashing attack in function "; + struct sigaction sa; + sigset_t mask; + + sigfillset(&mask); + + sigdelset(&mask, SSP_SIGTYPE); /* Block all signal handlers */ + sigprocmask(SIG_BLOCK, &mask, NULL); /* except SIGABRT */ + + /* print error message to stderr and syslog */ + fprintf(stderr, "%s%s%s()\n", __progname, message, func); + syslog(KERN_INFO, "%s%s%s()", __progname, message, func); + + /* Make sure the default handler is associated with the our signal handler */ + memset(&sa, 0, sizeof(struct sigaction)); + sigfillset(&sa.sa_mask); /* Block all signals */ + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigaction(SSP_SIGTYPE, &sa, NULL); + (void) kill(getpid(), SSP_SIGTYPE); + _exit(127); +} |