diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | Versions.def | 1 | ||||
-rw-r--r-- | debug/Makefile | 7 | ||||
-rw-r--r-- | debug/Versions | 3 | ||||
-rw-r--r-- | debug/longjmp_chk.c | 28 | ||||
-rw-r--r-- | debug/tst-longjmp_chk.c | 86 | ||||
-rw-r--r-- | include/bits/setjmp2.h | 1 | ||||
-rw-r--r-- | include/stdio.h | 3 | ||||
-rw-r--r-- | setjmp/Makefile | 4 | ||||
-rw-r--r-- | setjmp/bits/setjmp2.h | 41 | ||||
-rw-r--r-- | setjmp/longjmp.c | 5 | ||||
-rw-r--r-- | setjmp/setjmp.h | 8 | ||||
-rw-r--r-- | sysdeps/i386/____longjmp_chk.S | 45 | ||||
-rw-r--r-- | sysdeps/i386/__longjmp.S | 11 | ||||
-rw-r--r-- | sysdeps/x86_64/____longjmp_chk.S | 42 | ||||
-rw-r--r-- | sysdeps/x86_64/__longjmp.S | 3 |
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) |