Submitted By: Robert Connolly <robert at linuxfromscratch dot org> (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 <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+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);
+}
+
