summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--NEWS8
-rw-r--r--Versions.def1
-rw-r--r--debug/Makefile7
-rw-r--r--debug/Versions3
-rw-r--r--debug/longjmp_chk.c28
-rw-r--r--debug/tst-longjmp_chk.c86
-rw-r--r--include/bits/setjmp2.h1
-rw-r--r--include/stdio.h3
-rw-r--r--setjmp/Makefile4
-rw-r--r--setjmp/bits/setjmp2.h41
-rw-r--r--setjmp/longjmp.c5
-rw-r--r--setjmp/setjmp.h8
-rw-r--r--sysdeps/i386/____longjmp_chk.S45
-rw-r--r--sysdeps/i386/__longjmp.S11
-rw-r--r--sysdeps/x86_64/____longjmp_chk.S42
-rw-r--r--sysdeps/x86_64/__longjmp.S3
17 files changed, 306 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index d976903bb1..f317568d35 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
 2009-05-15  Ulrich Drepper  <drepper@redhat.com>
 
+	* Versions.def: Add GLIBC_2.11 for libc.
+	* debug/Makefile (routines): Add longjmp_chk.
+	Add rules to build and run tst-longjmp_chk.
+	* debug/Versions: Export __longjmp_chk for GLIBC_2.11.
+	* debug/longjmp_chk.c: New file.
+	* debug/tst-longjmp_chk.c: New file.
+	* include/bits/setjmp2.: New file.
+	* include/stdio.h: Mark __fortify_fail as internal_function.
+	* setjmp/Makefile (headers): Add bits/setjmp2.h.
+	* setjmp/bits/setjmp2.h: New file.
+	* setjmp/longjmp.c: If __libc_siglongjmp is defined, don't define any
+	of the aliases.
+	* setjmp/setjmp.h: Include <bits/setjmp2.h> if _FORTIFY_SOURCE is
+	defined.
+	* sysdeps/i386/____longjmp_chk.S: New file.
+	* sysdeps/x86_64/____longjmp_chk.S: New file.
+	* sysdeps/i386/__longjmp.S: If CHECK_ESP is defined, use it.
+	* sysdeps/x86_64/__longjmp.S: Likewise.
+
 	* version.h: Bump for 2.11 development.
 
 	* elf/check-execstack.c: New file.
diff --git a/NEWS b/NEWS
index 411c2c3bc8..9ba8f3579c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,16 @@
-GNU C Library NEWS -- history of user-visible changes.  2009-4-23
+GNU C Library NEWS -- history of user-visible changes.  2009-5-15
 Copyright (C) 1992-2008, 2009 Free Software Foundation, Inc.
 See the end for copying conditions.
 
 Please send GNU C library bug reports via <http://sources.redhat.com/bugzilla/>
 using `glibc' in the "product" field.
 
+Version 2.11
+
+* checking version of longjmp added that fails if an uninitialized stack
+  frame would be created.  Implemented by Ulrich Drepper.
+
+
 Version 2.10
 
 * New interfaces: preadv, preadv64, pwritev, pwritev64, malloc_info
diff --git a/Versions.def b/Versions.def
index 031e2a3541..558f7c3ed8 100644
--- a/Versions.def
+++ b/Versions.def
@@ -27,6 +27,7 @@ libc {
   GLIBC_2.8
   GLIBC_2.9
   GLIBC_2.10
+  GLIBC_2.11
 %ifdef USE_IN_LIBIO
   HURD_CTHREADS_0.3
 %endif
diff --git a/debug/Makefile b/debug/Makefile
index ece7ee6bd7..181169b90d 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2001,2004-2008 Free Software Foundation, Inc.
+# Copyright (C) 1998-2001,2004-2008, 2009 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -43,6 +43,7 @@ routines  = backtrace backtracesyms backtracesymsfd noophooks \
 	    wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
 	    wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
 	    vdprintf_chk obprintf_chk \
+	    longjmp_chk ____longjmp_chk \
 	    stack_chk_fail fortify_fail \
 	    $(static-only-routines)
 static-only-routines := warning-nop stack_chk_fail_local
@@ -79,6 +80,8 @@ CFLAGS-pread_chk.c = -fexceptions -fasynchronous-unwind-tables
 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-tst-longjmp_chk.c = -fexceptions -fasynchronous-unwind-tables \
+			   -D_FORTIFY_SOURCE=1
 
 # We know these tests have problems with format strings, this is what
 # we are testing.  Disable that warning.
@@ -113,7 +116,7 @@ LDFLAGS-tst-lfschk4 = -lstdc++
 LDFLAGS-tst-lfschk5 = -lstdc++
 LDFLAGS-tst-lfschk6 = -lstdc++
 
-tests = backtrace-tst tst-chk1 tst-chk2 tst-chk3 \
+tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
 	tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
 	tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6
 
diff --git a/debug/Versions b/debug/Versions
index ef6b08b7b3..ff40107b77 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -46,6 +46,9 @@ libc {
     __asprintf_chk; __vasprintf_chk;  __dprintf_chk; __vdprintf_chk;
     __obstack_printf_chk; __obstack_vprintf_chk;
   }
+  GLIBC_2.11 {
+    __longjmp_chk;
+  }
   GLIBC_PRIVATE {
     __fortify_fail;
   }
diff --git a/debug/longjmp_chk.c b/debug/longjmp_chk.c
new file mode 100644
index 0000000000..7de2a98a30
--- /dev/null
+++ b/debug/longjmp_chk.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+
+// XXX Should move to include/setjmp.h
+extern void ____longjmp_chk (__jmp_buf __env, int __val)
+     __attribute__ ((__noreturn__));
+
+#define __longjmp ____longjmp_chk
+#define __libc_siglongjmp __longjmp_chk
+
+#include <setjmp/longjmp.c>
diff --git a/debug/tst-longjmp_chk.c b/debug/tst-longjmp_chk.c
new file mode 100644
index 0000000000..8892974cc7
--- /dev/null
+++ b/debug/tst-longjmp_chk.c
@@ -0,0 +1,86 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static jmp_buf b;
+
+
+static void
+__attribute__ ((noinline))
+f (void)
+{
+  char buf[1000];
+  asm volatile ("" : "=m" (buf));
+
+  if (setjmp (b) != 0)
+    {
+      puts ("second longjmp succeeded");
+      exit (1);
+    }
+}
+
+
+static bool expected_to_fail;
+
+
+static void
+handler (int sig)
+{
+  if (expected_to_fail)
+    _exit (0);
+  else
+    {
+      static const char msg[] = "unexpected longjmp failure\n";
+      TEMP_FAILURE_RETRY (write (STDOUT_FILENO, msg, sizeof (msg) - 1));
+      _exit (1);
+    }
+}
+
+
+int
+main (void)
+{
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  sigaction (SIGABRT, &sa, NULL);
+
+  /* Avoid all the buffer overflow messages on stderr.  */
+  int fd = open (_PATH_DEVNULL, O_WRONLY);
+  if (fd == -1)
+    close (STDERR_FILENO);
+  else
+    {
+      dup2 (fd, STDERR_FILENO);
+      close (fd);
+    }
+  setenv ("LIBC_FATAL_STDERR_", "1", 1);
+
+
+  expected_to_fail = false;
+
+  if (setjmp (b) == 0)
+    {
+      longjmp (b, 1);
+      /* NOTREACHED */
+      printf ("first longjmp returned\n");
+      return 1;
+    }
+
+
+  expected_to_fail = true;
+
+  f ();
+  longjmp (b, 1);
+
+  puts ("second longjmp returned");
+  return 1;
+}
diff --git a/include/bits/setjmp2.h b/include/bits/setjmp2.h
new file mode 100644
index 0000000000..bdb222cd2c
--- /dev/null
+++ b/include/bits/setjmp2.h
@@ -0,0 +1 @@
+#include <setjmp/bits/setjmp2.h>
diff --git a/include/stdio.h b/include/stdio.h
index 9fdafe4a85..a8aab92aef 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -90,7 +90,8 @@ extern int __gen_tempname (char *__tmpl, int __flags, int __kind);
 extern void __libc_fatal (__const char *__message)
      __attribute__ ((__noreturn__));
 extern void __libc_message (int do_abort, __const char *__fnt, ...);
-extern void __fortify_fail (const char *msg) __attribute__ ((noreturn));
+extern void __fortify_fail (const char *msg)
+     __attribute__ ((__noreturn__)) internal_function;
 libc_hidden_proto (__fortify_fail)
 
 /* Acquire ownership of STREAM.  */
diff --git a/setjmp/Makefile b/setjmp/Makefile
index b94370d858..509c1d9a0c 100644
--- a/setjmp/Makefile
+++ b/setjmp/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1991, 92, 93, 94, 95, 97 Free Software Foundation, Inc.
+# Copyright (C) 1991, 92, 93, 94, 95, 97, 2009 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -21,7 +21,7 @@
 #
 subdir	:= setjmp
 
-headers	:= setjmp.h bits/setjmp.h
+headers	:= setjmp.h bits/setjmp.h bits/setjmp2.h
 
 routines	:= setjmp sigjmp bsd-setjmp bsd-_setjmp \
 		   longjmp __longjmp jmp-unwind
diff --git a/setjmp/bits/setjmp2.h b/setjmp/bits/setjmp2.h
new file mode 100644
index 0000000000..ba900b8d03
--- /dev/null
+++ b/setjmp/bits/setjmp2.h
@@ -0,0 +1,41 @@
+/* Checking macros for setjmp functions.
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ *
+ * The GNU C Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The GNU C Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.  */
+
+#ifndef _SETJMP_H
+# error "Never include <bits/setjmp2.h> directly; use <setjmp.h> instead."
+#endif
+
+/* Variant of the longjmp functions which perform some sanity checking.  */
+#ifdef __REDIRECT_NTH
+extern void __REDIRECT_NTH (longjmp,
+			    (struct __jmp_buf_tag __env[1], int __val),
+			    __longjmp_chk) __attribute__ ((__noreturn__));
+extern void __REDIRECT_NTH (_longjmp,
+			    (struct __jmp_buf_tag __env[1], int __val),
+			    __longjmp_chk) __attribute__ ((__noreturn__));
+extern void __REDIRECT_NTH (siglongjmp,
+			    (struct __jmp_buf_tag __env[1], int __val),
+			    __longjmp_chk) __attribute__ ((__noreturn__));
+#else
+extern void __longjmp_chk (struct __jmp_buf_tag __env[1], int __val),
+     __THROW __attribute__ ((__noreturn__));
+# define longjmp __longjmp_chk
+# define _longjmp __longjmp_chk
+# define siglongjmp __longjmp_chk
+#endif
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 9b1bda1caa..8545b36627 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991,92,94,95,97,98,2000,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,94,95,97,98,2000,2002,2009
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -39,8 +40,10 @@ __libc_siglongjmp (sigjmp_buf env, int val)
   __longjmp (env[0].__jmpbuf, val ?: 1);
 }
 
+#ifndef __libc_siglongjmp
 strong_alias (__libc_siglongjmp, __libc_longjmp)
 libc_hidden_def (__libc_longjmp)
 weak_alias (__libc_siglongjmp, _longjmp)
 weak_alias (__libc_siglongjmp, longjmp)
 weak_alias (__libc_siglongjmp, siglongjmp)
+#endif
diff --git a/setjmp/setjmp.h b/setjmp/setjmp.h
index 6b1037fabd..3bc382ff1e 100644
--- a/setjmp/setjmp.h
+++ b/setjmp/setjmp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-1999, 2001, 2002, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1999,2001,2002,2007,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -111,6 +111,12 @@ extern void siglongjmp (sigjmp_buf __env, int __val)
      __THROW __attribute__ ((__noreturn__));
 #endif /* Use POSIX.  */
 
+
+/* Define helper functions to catch unsafe code.  */
+#if __USE_FORTIFY_LEVEL > 0
+# include <bits/setjmp2.h>
+#endif
+
 __END_DECLS
 
 #endif /* setjmp.h  */
diff --git a/sysdeps/i386/____longjmp_chk.S b/sysdeps/i386/____longjmp_chk.S
new file mode 100644
index 0000000000..6cd74968a2
--- /dev/null
+++ b/sysdeps/i386/____longjmp_chk.S
@@ -0,0 +1,45 @@
+/* Copyright (C) 2001,2004,2005,2006,2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+	.section .rodata.str1.1,"aMS",@progbits,1
+	.type	longjmp_msg,@object
+longjmp_msg:
+	.string "longjmp causes uninitialized stack frame"
+	.size	longjmp_msg, .-longjmp_msg
+
+
+#define __longjmp ____longjmp_chk
+
+#ifdef PIC
+# define CALL_FAIL	movl	%ebx, %ecx;				      \
+			cfi_register(%ebx,%ecx);			      \
+			LOAD_PIC_REG (bx);				      \
+			leal	longjmp_msg@GOTOFF(%ebx), %eax;		      \
+			call	__GI___fortify_fail@PLT
+#else
+# define CALL_FAIL	movl	$longjmp_msg, %eax;			      \
+			call	__fortify_fail
+#endif
+
+#define CHECK_ESP(reg) \
+	cmpl	reg, %esp;						      \
+	jbe	.Lok;							      \
+	CALL_FAIL;							      \
+.Lok:
+
+#include "__longjmp.S"
diff --git a/sysdeps/i386/__longjmp.S b/sysdeps/i386/__longjmp.S
index 559d56b250..15c9e55ec7 100644
--- a/sysdeps/i386/__longjmp.S
+++ b/sysdeps/i386/__longjmp.S
@@ -1,5 +1,6 @@
 /* longjmp for i386.
-   Copyright (C) 1995-1998,2000,2002,2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998,2000,2002,2005,2006,2009
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -40,6 +41,9 @@ ENTRY (BP_SYM (__longjmp))
 	movl (JB_SP*4)(%eax), %ecx
 	PTR_DEMANGLE (%edx)
 	PTR_DEMANGLE (%ecx)
+# ifdef CHECK_ESP
+	CHECK_ESP (%ecx)
+# endif
 	cfi_def_cfa(%eax, 0)
 	cfi_register(%eip, %edx)
 	cfi_register(%esp, %ecx)
@@ -63,6 +67,11 @@ ENTRY (BP_SYM (__longjmp))
 	movl JBUF(%esp), %ecx	/* User's jmp_buf in %ecx.  */
 	CHECK_BOUNDS_BOTH_WIDE (%ecx, JBUF(%esp), $JB_SIZE)
 
+# ifdef CHECK_ESP
+	movl (JB_SP*4)(%ecx), %eax
+	CHECK_ESP (%eax)
+# endif
+
 	movl VAL(%esp), %eax	/* Second argument is return value.  */
 	/* Save the return address now.  */
 	movl (JB_PC*4)(%ecx), %edx
diff --git a/sysdeps/x86_64/____longjmp_chk.S b/sysdeps/x86_64/____longjmp_chk.S
new file mode 100644
index 0000000000..030a0dcaa7
--- /dev/null
+++ b/sysdeps/x86_64/____longjmp_chk.S
@@ -0,0 +1,42 @@
+/* Copyright (C) 2001,2004,2005,2006,2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+	.section .rodata.str1.1,"aMS",@progbits,1
+	.type	longjmp_msg,@object
+longjmp_msg:
+	.string "longjmp causes uninitialized stack frame"
+	.size	longjmp_msg, .-longjmp_msg
+
+
+#define __longjmp ____longjmp_chk
+
+#ifdef PIC
+# define CALL_FAIL	leaq	longjmp_msg(%rip), %rdi;		      \
+			call	__GI___fortify_fail
+#else
+# define CALL_FAIL	movq	$longjmp_msg, %rdi;			      \
+			call	__fortify_fail
+#endif
+
+#define CHECK_RSP(reg) \
+	cmpq	reg, %rsp;						      \
+	jbe	.Lok;							      \
+	CALL_FAIL;							      \
+.Lok:
+
+#include "__longjmp.S"
diff --git a/sysdeps/x86_64/__longjmp.S b/sysdeps/x86_64/__longjmp.S
index a68e7a8a4f..7649e99242 100644
--- a/sysdeps/x86_64/__longjmp.S
+++ b/sysdeps/x86_64/__longjmp.S
@@ -33,6 +33,9 @@ ENTRY(__longjmp)
 	PTR_DEMANGLE (%r9)
 	PTR_DEMANGLE (%rdx)
 #endif
+#ifdef CHECK_RSP
+	CHECK_RSP (%r8)
+#endif
 	/* We add unwind information for the target here.  */
 	cfi_def_cfa(%rdi, 0)
 	cfi_register(%rsp,%r8)