diff options
65 files changed, 3220 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog index d610e693d7..4b52d54a0a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,122 @@ +2004-10-15 Jakub Jelinek <jakub@redhat.com> + + * elf/dl-minimal.c (__chk_fail): New. Add rtld_hidden_def. + * sysdeps/unix/sysv/linux/readonly-area.c: New file. + * sysdeps/i386/i686/memmove.S (__memmove_chk): Add checking + routine. + * sysdeps/i386/i686/memcpy.S (__memcpy_chk): Likewise. + * sysdeps/i386/i686/mempcpy.S (__mempcpy_chk): Likewise. + * sysdeps/i386/i686/memset.S (__memset_chk): Likewise. + * sysdeps/i386/i686/memmove-chk.S: New file. + * sysdeps/i386/i686/memcpy-chk.S: Likewise. + * sysdeps/i386/i686/mempcpy-chk.S: Likewise. + * sysdeps/i386/i686/memset-chk.S: Likewise. + * sysdeps/generic/strcat-chk.c (__strcat_chk): Don't __chk_fail + if exactly fitting into buffer. + * sysdeps/generic/strncat-chk.c (__strncat_chk): Likewise. + * sysdeps/generic/readonly-area.c: New file. + * sysdeps/generic/strncpy-chk.c (__strncpy_chk): Only test + destlen once. + * sysdeps/x86_64/memset.S (__memset_chk): Add checking routine. + * sysdeps/x86_64/memcpy.S (__memcpy_chk): Likewise. + * sysdeps/x86_64/mempcpy.S (__memcpy_chk): Define to __mempcpy_chk. + * sysdeps/x86_64/memcpy-chk.S: New file. + * sysdeps/x86_64/mempcpy-chk.S: Likewise. + * sysdeps/x86_64/memset-chk.S: Likewise. + * sysdeps/x86_64/strcpy-chk.S: Likewise. + * sysdeps/x86_64/stpcpy-chk.S: Likewise. + * argp/argp-xinl.c (__OPTIMIZE__): Define to 1 instead of nothing. + * argp/argp-fs-xinl.c (__OPTIMIZE__): Likewise. + * debug/tst-chk1.c: New test. + * debug/tst-chk2.c: Likewise. + * debug/tst-chk3.c: Likewise. + * debug/test-strcpy_chk.c: Likewise. + * debug/test-stpcpy_chk.c: Likewise. + * debug/vsprintf_chk.c (__vsprintf_chk): If flags > 0, request + _IO_FLAGS2_CHECK_PERCENT_N. Add libc_hidden_def. + * debug/Makefile (routines): Add printf_chk, fprintf_chk, vprintf_chk, + vfprintf_chk, gets_chk and readonly-area. + (CFLAGS-*_chk.c): Set. + (tests): Add tst-chk1, tst-chk2, tst-chk3, test-strcpy_chk and + test-stpcpy_chk. + * debug/vprintf_chk.c: New file. + * debug/printf_chk.c: Likewise. + * debug/vfprintf_chk.c: Likewise. + * debug/fprintf_chk.c: Likewise. + * debug/gets_chk.c: Likewise. + * debug/chk_fail.c (__chk_fail): Add libc_hidden_def. + * debug/snprintf_chk.c (__snprintf_chk): Fix order of arguments + passed to __vsnprintf_chk. + * debug/Versions (libc): Export __printf_chk, __fprintf_chk, + __vprintf_chk, __vfprintf_chk and __gets_chk @GLIBC_2.3.4. + * debug/vsnprintf_chk.c (__vsnprintf_chk): Don't call + __vsnprintf, instead create a temporary file with + _IO_strn_jumps jumptable. If flags > 0, request + _IO_FLAGS2_CHECK_PERCENT_N. Add libc_hidden_def. + * libio/Makefile (headers): Add bits/stdio2.h. + * libio/stdio.h: Include <bits/stdio2.h> if __USE_FORTIFY_LEVEL. + (sprintf, snprintf, vsprintf, vsnprintf): Remove defines. + * libio/strfile.h (_IO_strnfile): New type. + (_IO_strn_jumps): New extern. + * libio/vsnprintf.c (_IO_strnfile): Remove. + (_IO_strn_jumps): Remove static. + * libio/bits/stdio2.h: New file. + * libio/vswprintf.c (_IO_strnfile): Rename type to... + (_IO_wstrnfile): ...this. Adjust all uses. + * libio/libio.h (_IO_FLAGS2_CHECK_PERCENT_N): Define. + * stdio-common/vfprintf.c (STR_LEN): Define. + (vfprintf): Add readonly_format variable. + Handle _IO_FLAGS2_CHECK_PERCENT_N. + (buffered_vfprintf): Copy _flags2. + * include/stdio.h (__sprintf_chk, __snprintf_chk, __vsprintf_chk, + __vsnprintf_chk, __printf_chk, __fprintf_chk, __vprintf_chk, + __vfprintf_chk): New prototypes. + (__vsprintf_chk, __vsnprintf_chk): Add libc_hidden_proto. + * include/string.h (__memcpy_chk, __memmove_chk, __mempcpy_chk, + __memset_chk, __strcpy_chk, __stpcpy_chk, __strncpy_chk, __strcat_chk, + __strncat_chk): New prototypes. + * include/bits/string3.h: New file. + * include/sys/cdefs.h (__chk_fail): Add libc_hidden_proto + and rtld_hidden_proto. + * string/Makefile (headers): Add bits/string3.h. + * string/bits/string3.h (bcopy, bzero): New defines. + (memset, memcpy, memmove, strcpy, strncpy, strcat, strncat): Change + macros so that inlines are used only if unknown destination size + or side-effects in destination argument. + (mempcpy, stpcpy): Likewise. Protect with #ifdef __USE_GNU. + +2004-09-16 Ulrich Drepper <drepper@redhat.com> + + * debug/Makefile (routines): Add *_chk. + * debug/Versions (libc): Export __chk_fail, __memcpy_chk, + __memmove_chk, __mempcpy_chk, __memset_chk, __stpcpy_chk, + __strcat_chk, __strcpy_chk, __strncat_chk, __strncpy_chk, + __sprintf_chk, __vsprintf_chk, __snprintf_chk, __vsnprintf_chk + @GLIBC_2.3.4. + * debug/chk_fail.c: New file. + * debug/snprintf_chk.c: Likewise. + * debug/sprintf_chk.c: Likewise. + * debug/vsnprintf_chk.c: Likewise. + * debug/vsprintf_chk.c: Likewise. + * include/features.h (_FORTIFY_SOURCE): Document, handle. + (__USE_FORTIFY_LEVEL): Define. + (__GNUC_PREREQ): Move to earlier location. + * include/sys/cdefs.h (__chk_fail): New prototype. + * libio/bits/stdio.h (sprintf, vsprintf, snprintf, vsnprintf): + Define if __USE_FORTIFY_LEVEL. + * misc/sys/cdefs.h (__bos, __bos0): Define. + * string/string.h: Include <bits/string3.h> if __USE_FORTIFY_LEVEL. + * bits/string/string3.h: New header. + * sysdeps/generic/memcpy_chk.c: New file. + * sysdeps/generic/memmove_chk.c: Likewise. + * sysdeps/generic/mempcpy_chk.c: Likewise. + * sysdeps/generic/memset_chk.c: Likewise. + * sysdeps/generic/stpcpy_chk.c: Likewise. + * sysdeps/generic/strcat_chk.c: Likewise. + * sysdeps/generic/strcpy_chk.c: Likewise. + * sysdeps/generic/strncat_chk.c: Likewise. + * sysdeps/generic/strncpy_chk.c: Likewise. + 2004-10-17 Roland McGrath <roland@frob.com> * manual/memory.texi (Page Lock Functions): Typo fix. diff --git a/argp/argp-fs-xinl.c b/argp/argp-fs-xinl.c index 21f9bd9f71..3cf1f9827d 100644 --- a/argp/argp-fs-xinl.c +++ b/argp/argp-fs-xinl.c @@ -1,5 +1,5 @@ /* Real definitions for extern inline functions in argp-fmtstream.h - Copyright (C) 1997, 2003 Free Software Foundation, Inc. + Copyright (C) 1997, 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -24,7 +24,7 @@ #define ARGP_FS_EI #undef __OPTIMIZE__ -#define __OPTIMIZE__ +#define __OPTIMIZE__ 1 #include "argp-fmtstream.h" #if 0 diff --git a/argp/argp-xinl.c b/argp/argp-xinl.c index 2431093ea3..73177585e8 100644 --- a/argp/argp-xinl.c +++ b/argp/argp-xinl.c @@ -1,5 +1,5 @@ /* Real definitions for extern inline functions in argp.h - Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -31,7 +31,7 @@ #endif #define ARGP_EI #undef __OPTIMIZE__ -#define __OPTIMIZE__ +#define __OPTIMIZE__ 1 #include "argp.h" /* Add weak aliases. */ diff --git a/debug/Makefile b/debug/Makefile index aba98926da..fed60d78b5 100644 --- a/debug/Makefile +++ b/debug/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. +# Copyright (C) 1998, 1999, 2000, 2001, 2004 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 @@ -24,11 +24,26 @@ subdir := debug headers := execinfo.h distribute = sigcontextinfo.h register-dump.h frame.h -routines := backtrace backtracesyms backtracesymsfd noophooks +routines := backtrace backtracesyms backtracesymsfd noophooks \ + memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \ + strcat_chk strcpy_chk strncat_chk strncpy_chk \ + sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \ + printf_chk fprintf_chk vprintf_chk vfprintf_chk \ + gets_chk chk_fail readonly-area CFLAGS-backtrace.c = -fno-omit-frame-pointer - -tests = backtrace-tst +CFLAGS-sprintf_chk.c = -D_IO_MTSAFE_IO +CFLAGS-snprintf_chk.c = -D_IO_MTSAFE_IO +CFLAGS-vsprintf_chk.c = -D_IO_MTSAFE_IO +CFLAGS-vsnprintf_chk.c = -D_IO_MTSAFE_IO +CFLAGS-printf_chk.c = -D_IO_MTSAFE_IO $(exceptions) +CFLAGS-fprintf_chk.c = -D_IO_MTSAFE_IO $(exceptions) +CFLAGS-vprintf_chk.c = -D_IO_MTSAFE_IO $(exceptions) +CFLAGS-vfprintf_chk.c = -D_IO_MTSAFE_IO $(exceptions) +CFLAGS-gets_chk.c = -D_IO_MTSAFE_IO $(exceptions) + +tests = backtrace-tst tst-chk1 tst-chk2 tst-chk3 \ + test-strcpy_chk test-stpcpy_chk extra-libs = libSegFault libpcprofile extra-libs-others = $(extra-libs) diff --git a/debug/Versions b/debug/Versions index c2b6396d82..07d6fbb830 100644 --- a/debug/Versions +++ b/debug/Versions @@ -10,4 +10,12 @@ libc { # These are to support some gcc features. __cyg_profile_func_enter; __cyg_profile_func_exit; } + GLIBC_2.3.4 { + __chk_fail; + __memcpy_chk; __memmove_chk; __mempcpy_chk; __memset_chk; __stpcpy_chk; + __strcat_chk; __strcpy_chk; __strncat_chk; __strncpy_chk; + __sprintf_chk; __vsprintf_chk; __snprintf_chk; __vsnprintf_chk; + __printf_chk; __fprintf_chk; __vprintf_chk; __vfprintf_chk; + __gets_chk; + } } diff --git a/debug/chk_fail.c b/debug/chk_fail.c new file mode 100644 index 0000000000..48848fbe35 --- /dev/null +++ b/debug/chk_fail.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2004 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 <stdlib.h> +#include <unistd.h> +#include <abort-instr.h> + + +void +__attribute__ ((noreturn)) +__chk_fail (void) +{ + while (1) + { + /* This will leave a nice backtrace. */ + abort (); +#ifdef ABORT_INSTRUCTION + ABORT_INSTRUCTION; +#endif + _exit (127); + } +} +libc_hidden_def (__chk_fail) diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c new file mode 100644 index 0000000000..77508b902e --- /dev/null +++ b/debug/fprintf_chk.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004 + 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 <stdarg.h> +#include <stdio.h> +#include "../libio/libioP.h" + + +/* Write formatted output to FP from the format string FORMAT. */ +int +__fprintf_chk (FILE *fp, int flag, const char *format, ...) +{ + va_list ap; + int done; + + _IO_acquire_lock (fp); + if (flag > 0) + fp->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N; + + va_start (ap, format); + done = vfprintf (fp, format, ap); + va_end (ap); + + if (flag > 0) + fp->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N; + _IO_release_lock (fp); + + return done; +} diff --git a/debug/gets_chk.c b/debug/gets_chk.c new file mode 100644 index 0000000000..3715a39672 --- /dev/null +++ b/debug/gets_chk.c @@ -0,0 +1,77 @@ +/* Copyright (C) 1993, 1996, 1997, 1998, 2002, 2003, 2004 + 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. + + As a special exception, if you link the code in this file with + files compiled with a GNU compiler to produce an executable, + that does not cause the resulting executable to be covered by + the GNU Lesser General Public License. This exception does not + however invalidate any other reasons why the executable file + might be covered by the GNU Lesser General Public License. + This exception applies to code released by its copyright holders + in files containing the exception. */ + +#include "../libio/libioP.h" +#include <limits.h> + +char * +__gets_chk (char *buf, size_t size) +{ + _IO_size_t count; + int ch; + char *retval; + + if (size == 0) + __chk_fail (); + + _IO_acquire_lock (_IO_stdin); + ch = _IO_getc_unlocked (_IO_stdin); + if (ch == EOF) + { + retval = NULL; + goto unlock_return; + } + if (ch == '\n') + count = 0; + else + { + /* This is very tricky since a file descriptor may be in the + non-blocking mode. The error flag doesn't mean much in this + case. We return an error only when there is a new error. */ + int old_error = _IO_stdin->_IO_file_flags & _IO_ERR_SEEN; + _IO_stdin->_IO_file_flags &= ~_IO_ERR_SEEN; + buf[0] = (char) ch; + count = INTUSE(_IO_getline) (_IO_stdin, buf + 1, size - 1, '\n', 0) + 1; + if (_IO_stdin->_IO_file_flags & _IO_ERR_SEEN) + { + retval = NULL; + goto unlock_return; + } + else + _IO_stdin->_IO_file_flags |= old_error; + } + if (count >= size) + __chk_fail (); + buf[count] = 0; + retval = buf; +unlock_return: + _IO_release_lock (_IO_stdin); + return retval; +} + +link_warning (__gets_chk, "the `gets' function is dangerous and should not be used.") diff --git a/debug/printf_chk.c b/debug/printf_chk.c new file mode 100644 index 0000000000..d2b387323d --- /dev/null +++ b/debug/printf_chk.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004 + 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 <stdarg.h> +#include <stdio.h> +#include "../libio/libioP.h" + + +/* Write formatted output to stdout from the format string FORMAT. */ +int +__printf_chk (int flag, const char *format, ...) +{ + va_list ap; + int done; + + _IO_acquire_lock (stdout); + if (flag > 0) + stdout->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N; + + va_start (ap, format); + done = vfprintf (stdout, format, ap); + va_end (ap); + + if (flag > 0) + stdout->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N; + _IO_release_lock (stdout); + + return done; +} diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c new file mode 100644 index 0000000000..5a77afef29 --- /dev/null +++ b/debug/snprintf_chk.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1991, 1995, 1997, 1998, 2004 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 <stdarg.h> +#include <stdio.h> + + +/* Write formatted output into S, according to the format + string FORMAT, writing no more than MAXLEN characters. */ +/* VARARGS5 */ +int +__snprintf_chk (char *s, size_t maxlen, int flags, size_t slen, + const char *format, ...) +{ + va_list arg; + int done; + + va_start (arg, format); + done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg); + va_end (arg); + + return done; +} diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c new file mode 100644 index 0000000000..d141633b9f --- /dev/null +++ b/debug/sprintf_chk.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991,1995,1997,1998,2002,2004 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 <stdarg.h> +#include <stdio.h> + +/* Write formatted output into S, according to the format string FORMAT. */ +/* VARARGS4 */ +int +__sprintf_chk (char *s, int flags, size_t slen, const char *format, ...) +{ + va_list arg; + int done; + + va_start (arg, format); + done = __vsprintf_chk (s, flags, slen, format, arg); + va_end (arg); + + return done; +} diff --git a/debug/test-stpcpy_chk.c b/debug/test-stpcpy_chk.c new file mode 100644 index 0000000000..d717ca7363 --- /dev/null +++ b/debug/test-stpcpy_chk.c @@ -0,0 +1,46 @@ +/* Test and measure stpcpy checking functions. + Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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. */ + +#define STRCPY_RESULT(dst, len) ((dst) + (len)) +#define TEST_MAIN +#include "../string/test-string.h" + +extern void __attribute__ ((noreturn)) __chk_fail (void); +char *simple_stpcpy_chk (char *, const char *, size_t); +extern char *normal_stpcpy (char *, const char *, size_t) + __asm ("stpcpy"); +extern char *__stpcpy_chk (char *, const char *, size_t); + +IMPL (simple_stpcpy_chk, 0) +IMPL (normal_stpcpy, 1) +IMPL (__stpcpy_chk, 2) + +char * +simple_stpcpy_chk (char *dst, const char *src, size_t len) +{ + if (! len) + __chk_fail (); + while ((*dst++ = *src++) != '\0') + if (--len == 0) + __chk_fail (); + return dst - 1; +} + +#include "test-strcpy_chk.c" diff --git a/debug/test-strcpy_chk.c b/debug/test-strcpy_chk.c new file mode 100644 index 0000000000..4c61f4fb43 --- /dev/null +++ b/debug/test-strcpy_chk.c @@ -0,0 +1,370 @@ +/* Test and measure __strcpy_chk functions. + Copyright (C) 1999, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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 STRCPY_RESULT +# define STRCPY_RESULT(dst, len) dst +# define TEST_MAIN +# include "../string/test-string.h" + +extern void __attribute__ ((noreturn)) __chk_fail (void); +char *simple_strcpy_chk (char *, const char *, size_t); +extern char *normal_strcpy (char *, const char *, size_t) + __asm ("strcpy"); +extern char *__strcpy_chk (char *, const char *, size_t); + +IMPL (simple_strcpy_chk, 0) +IMPL (normal_strcpy, 1) +IMPL (__strcpy_chk, 2) + +char * +simple_strcpy_chk (char *dst, const char *src, size_t len) +{ + char *ret = dst; + if (! len) + __chk_fail (); + while ((*dst++ = *src++) != '\0') + if (--len == 0) + __chk_fail (); + return ret; +} +#endif + +#include <setjmp.h> +#include <signal.h> + +volatile int chk_fail_ok; +jmp_buf chk_fail_buf; + +static void +handler (int sig) +{ + if (chk_fail_ok) + { + chk_fail_ok = 0; + longjmp (chk_fail_buf, 1); + } + else + _exit (127); +} + +typedef char *(*proto_t) (char *, const char *, size_t); + +static void +do_one_test (impl_t *impl, char *dst, const char *src, + size_t len, size_t dlen) +{ + char *res; + if (dlen <= len) + { + if (impl->test == 1) + return; + + chk_fail_ok = 1; + if (setjmp (chk_fail_buf) == 0) + { + res = CALL (impl, dst, src, dlen); + error (0, 0, "Function %s (%zd; %zd) did not __chk_fail", + impl->name, len, dlen); + chk_fail_ok = 0; + ret = 1; + } + return; + } + else + res = CALL (impl, dst, src, dlen); + + if (res != STRCPY_RESULT (dst, len)) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + res, STRCPY_RESULT (dst, len)); + ret = 1; + return; + } + + if (strcmp (dst, src) != 0) + { + error (0, 0, "Wrong result in function %s dst \"%s\" src \"%s\"", + impl->name, dst, src); + ret = 1; + return; + } + + if (HP_TIMING_AVAIL) + { + hp_timing_t start __attribute ((unused)); + hp_timing_t stop __attribute ((unused));; + hp_timing_t best_time = ~ (hp_timing_t) 0; + size_t i; + + for (i = 0; i < 32; ++i) + { + HP_TIMING_NOW (start); + CALL (impl, dst, src, dlen); + HP_TIMING_NOW (stop); + HP_TIMING_BEST (best_time, start, stop); + } + + printf ("\t%zd", (size_t) best_time); + } +} + +static void +do_test (size_t align1, size_t align2, size_t len, size_t dlen, int max_char) +{ + size_t i; + char *s1, *s2; + + align1 &= 7; + if (align1 + len >= page_size) + return; + + align2 &= 7; + if (align2 + len >= page_size) + return; + + s1 = buf1 + align1; + s2 = buf2 + align2; + + for (i = 0; i < len; i++) + s1[i] = 32 + 23 * i % (max_char - 32); + s1[len] = 0; + + if (HP_TIMING_AVAIL && dlen > len) + printf ("Length %4zd, alignment %2zd/%2zd:", len, align1, align2); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s2, s1, len, dlen); + + if (HP_TIMING_AVAIL && dlen > len) + putchar ('\n'); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, len, dlen; + unsigned char *p1 = buf1 + page_size - 512; + unsigned char *p2 = buf2 + page_size - 512; + unsigned char *res; + + for (n = 0; n < ITERATIONS; n++) + { + align1 = random () & 31; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + len = random () & 511; + j = align1; + if (align2 > j) + j = align2; + if (len + j >= 511) + len = 510 - j - (random () & 7); + j = len + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; i++) + { + if (i == len + align1) + p1[i] = 0; + else + { + p1[i] = random () & 255; + if (i >= align1 && i < len + align1 && !p1[i]) + p1[i] = (random () & 127) + 3; + } + } + + switch (random () & 7) + { + case 0: + dlen = len - (random () & 31); + if (dlen > len) + dlen = len; + break; + case 1: + dlen = (size_t) -1; + break; + case 2: + dlen = len + 1 + (random () & 65535); + break; + case 3: + dlen = len + 1 + (random () & 255); + break; + case 4: + dlen = len + 1 + (random () & 31); + break; + case 5: + dlen = len + 1 + (random () & 7); + break; + case 6: + dlen = len + 1 + (random () & 3); + break; + default: + dlen = len + 1; + break; + } + + FOR_EACH_IMPL (impl, 1) + { + if (dlen <= len) + { + if (impl->test != 1) + { + chk_fail_ok = 1; + if (setjmp (chk_fail_buf) == 0) + { + res = CALL (impl, p2 + align2, p1 + align1, dlen); + error (0, 0, "Iteration %zd - did not __chk_fail", n); + chk_fail_ok = 0; + ret = 1; + } + } + continue; + } + memset (p2 - 64, '\1', 512 + 64); + res = CALL (impl, p2 + align2, p1 + align1, dlen); + if (res != STRCPY_RESULT (p2 + align2, len)) + { + error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p", + n, impl->name, align1, align2, len, res, + STRCPY_RESULT (p2 + align2, len)); + ret = 1; + } + for (j = 0; j < align2 + 64; ++j) + { + if (p2[j - 64] != '\1') + { + error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + for (j = align2 + len + 1; j < 512; ++j) + { + if (p2[j] != '\1') + { + error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + if (memcmp (p1 + align1, p2 + align2, len + 1)) + { + error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + } + } + } +} + +int +test_main (void) +{ + size_t i; + + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGABRT, &sa, NULL); + + test_init (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < 16; ++i) + { + do_test (0, 0, i, i + 1, 127); + do_test (0, 0, i, i + 1, 255); + do_test (0, i, i, i + 1, 127); + do_test (i, 0, i, i + 1, 255); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 8 << i, (8 << i) + 1, 127); + do_test (8 - i, 2 * i, (8 << i), (8 << i) + 1, 127); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, (8 << i), (8 << i) + 1, 127); + do_test (2 * i, i, (8 << i), (8 << i) + 1, 255); + do_test (i, i, (8 << i), (8 << i) + 1, 127); + do_test (i, i, (8 << i), (8 << i) + 1, 255); + } + + for (i = 0; i < 16; ++i) + { + do_test (0, 0, i, i + 256, 127); + do_test (0, 0, i, i + 256, 255); + do_test (0, i, i, i + 256, 127); + do_test (i, 0, i, i + 256, 255); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 8 << i, (8 << i) + 256, 127); + do_test (8 - i, 2 * i, (8 << i), (8 << i) + 256, 127); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, (8 << i), (8 << i) + 256, 127); + do_test (2 * i, i, (8 << i), (8 << i) + 256, 255); + do_test (i, i, (8 << i), (8 << i) + 256, 127); + do_test (i, i, (8 << i), (8 << i) + 256, 255); + } + + for (i = 0; i < 16; ++i) + { + do_test (0, 0, i, i, 127); + do_test (0, 0, i, i + 2, 255); + do_test (0, i, i, i + 3, 127); + do_test (i, 0, i, i + 4, 255); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 8 << i, (8 << i) - 15, 127); + do_test (8 - i, 2 * i, (8 << i), (8 << i) + 5, 127); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, (8 << i), (8 << i) + i, 127); + do_test (2 * i, i, (8 << i), (8 << i) + (i - 1), 255); + do_test (i, i, (8 << i), (8 << i) + i + 2, 127); + do_test (i, i, (8 << i), (8 << i) + i + 3, 255); + } + + do_random_tests (); + return ret; +} + +#include "../test-skeleton.c" diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c new file mode 100644 index 0000000000..639da3847c --- /dev/null +++ b/debug/tst-chk1.c @@ -0,0 +1,466 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +char *temp_filename; +static void do_prepare (void); +static int do_test (void); +#define PREPARE(argc, argv) do_prepare () +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +static void +do_prepare (void) +{ + int temp_fd = create_temp_file ("tst-chk1.", &temp_filename); + if (temp_fd == -1) + { + printf ("cannot create temporary file: %m\n"); + exit (1); + } + + const char *strs = "abcdefgh\nABCDEFGHI\nabcdefghij\nABCDEFGHIJ"; + if (write (temp_fd, strs, strlen (strs)) != strlen (strs)) + { + puts ("could not write test strings into file"); + unlink (temp_filename); + exit (1); + } +} + +volatile int chk_fail_ok; +jmp_buf chk_fail_buf; + +static void +handler (int sig) +{ + if (chk_fail_ok) + { + chk_fail_ok = 0; + longjmp (chk_fail_buf, 1); + } + else + _exit (127); +} + +char buf[10]; +volatile size_t l0; +volatile char *p; +const char *str1 = "JIHGFEDCBA"; +const char *str2 = "F"; +const char *str3 = "%s%n%s%n"; +const char *str4 = "Hello, "; +const char *str5 = "World!\n"; +char buf2[10] = "%s"; +int num1 = 67; +int num2 = 987654; + +#define FAIL() \ + do { printf ("Failure on line %d\n", __LINE__); ret = 1; } while (0) +#define CHK_FAIL_START \ + chk_fail_ok = 1; \ + if (! setjmp (chk_fail_buf)) \ + { +#define CHK_FAIL_END \ + chk_fail_ok = 0; \ + FAIL (); \ + ret = 1; \ + } +#if __USE_FORTIFY_LEVEL >= 2 +#define CHK_FAIL2_START CHK_FAIL_START +#define CHK_FAIL2_END CHK_FAIL_END +#else +#define CHK_FAIL2_START +#define CHK_FAIL2_END +#endif + +static int +do_test (void) +{ + int ret = 0; + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGABRT, &sa, NULL); + + struct A { char buf1[9]; char buf2[1]; } a; + + printf ("Test checking routines at fortify level %d\n", +#ifdef __USE_FORTIFY_LEVEL + (int) __USE_FORTIFY_LEVEL +#else + 0 +#endif + ); + + /* These ops can be done without runtime checking of object size. */ + memcpy (buf, "abcdefghij", 10); + memmove (buf + 1, buf, 9); + if (memcmp (buf, "aabcdefghi", 10)) + FAIL (); + + if (mempcpy (buf + 5, "abcde", 5) != buf + 10 || memcmp (buf, "aabcdabcde", 10)) + FAIL (); + + memset (buf + 8, 'j', 2); + if (memcmp (buf, "aabcdabcjj", 10)) + FAIL (); + + strcpy (buf + 4, "EDCBA"); + if (memcmp (buf, "aabcEDCBA", 10)) + FAIL (); + + if (stpcpy (buf + 8, "F") != buf + 9 || memcmp (buf, "aabcEDCBF", 10)) + FAIL (); + + strncpy (buf + 6, "X", 4); + if (memcmp (buf, "aabcEDX\0\0", 10)) + FAIL (); + + if (sprintf (buf + 7, "%s", "67") != 2 || memcmp (buf, "aabcEDX67", 10)) + FAIL (); + + if (snprintf (buf + 7, 3, "%s", "987654") != 6 + || memcmp (buf, "aabcEDX98", 10)) + FAIL (); + + /* These ops need runtime checking, but shouldn't __chk_fail. */ + memcpy (buf, "abcdefghij", l0 + 10); + memmove (buf + 1, buf, l0 + 9); + if (memcmp (buf, "aabcdefghi", 10)) + FAIL (); + + if (mempcpy (buf + 5, "abcde", l0 + 5) != buf + 10 || memcmp (buf, "aabcdabcde", 10)) + FAIL (); + + memset (buf + 8, 'j', l0 + 2); + if (memcmp (buf, "aabcdabcjj", 10)) + FAIL (); + + strcpy (buf + 4, str1 + 5); + if (memcmp (buf, "aabcEDCBA", 10)) + FAIL (); + + if (stpcpy (buf + 8, str2) != buf + 9 || memcmp (buf, "aabcEDCBF", 10)) + FAIL (); + + strncpy (buf + 6, "X", l0 + 4); + if (memcmp (buf, "aabcEDX\0\0", 10)) + FAIL (); + + if (sprintf (buf + 7, "%d", num1) != 2 || memcmp (buf, "aabcEDX67", 10)) + FAIL (); + + if (snprintf (buf + 7, 3, "%d", num2) != 6 || memcmp (buf, "aabcEDX98", 10)) + FAIL (); + + buf[l0 + 8] = '\0'; + strcat (buf, "A"); + if (memcmp (buf, "aabcEDX9A", 10)) + FAIL (); + + buf[l0 + 7] = '\0'; + strncat (buf, "ZYXWV", l0 + 2); + if (memcmp (buf, "aabcEDXZY", 10)) + FAIL (); + + memcpy (a.buf1, "abcdefghij", l0 + 10); + memmove (a.buf1 + 1, a.buf1, l0 + 9); + if (memcmp (a.buf1, "aabcdefghi", 10)) + FAIL (); + + if (mempcpy (a.buf1 + 5, "abcde", l0 + 5) != a.buf1 + 10 + || memcmp (a.buf1, "aabcdabcde", 10)) + FAIL (); + + memset (a.buf1 + 8, 'j', l0 + 2); + if (memcmp (a.buf1, "aabcdabcjj", 10)) + FAIL (); + +#if __USE_FORTIFY_LEVEL < 2 + /* The following tests are supposed to crash with -D_FORTIFY_SOURCE=2 + and sufficient GCC support, as the string operations overflow + from a.buf1 into a.buf2. */ + strcpy (a.buf1 + 4, str1 + 5); + if (memcmp (a.buf1, "aabcEDCBA", 10)) + FAIL (); + + if (stpcpy (a.buf1 + 8, str2) != a.buf1 + 9 || memcmp (a.buf1, "aabcEDCBF", 10)) + FAIL (); + + strncpy (a.buf1 + 6, "X", l0 + 4); + if (memcmp (a.buf1, "aabcEDX\0\0", 10)) + FAIL (); + + if (sprintf (a.buf1 + 7, "%d", num1) != 2 || memcmp (a.buf1, "aabcEDX67", 10)) + FAIL (); + + if (snprintf (a.buf1 + 7, 3, "%d", num2) != 6 + || memcmp (a.buf1, "aabcEDX98", 10)) + FAIL (); + + a.buf1[l0 + 8] = '\0'; + strcat (a.buf1, "A"); + if (memcmp (a.buf1, "aabcEDX9A", 10)) + FAIL (); + + a.buf1[l0 + 7] = '\0'; + strncat (a.buf1, "ZYXWV", l0 + 2); + if (memcmp (a.buf1, "aabcEDXZY", 10)) + FAIL (); + +#endif + +#if __USE_FORTIFY_LEVEL >= 1 + /* Now check if all buffer overflows are caught at runtime. */ + + CHK_FAIL_START + memcpy (buf + 1, "abcdefghij", l0 + 10); + CHK_FAIL_END + + CHK_FAIL_START + memmove (buf + 2, buf + 1, l0 + 9); + CHK_FAIL_END + + CHK_FAIL_START + p = mempcpy (buf + 6, "abcde", l0 + 5); + CHK_FAIL_END + + CHK_FAIL_START + memset (buf + 9, 'j', l0 + 2); + CHK_FAIL_END + + CHK_FAIL_START + strcpy (buf + 5, str1 + 5); + CHK_FAIL_END + + CHK_FAIL_START + p = stpcpy (buf + 9, str2); + CHK_FAIL_END + + CHK_FAIL_START + strncpy (buf + 7, "X", l0 + 4); + CHK_FAIL_END + + CHK_FAIL_START + sprintf (buf + 8, "%d", num1); + CHK_FAIL_END + + CHK_FAIL_START + snprintf (buf + 8, l0 + 3, "%d", num2); + CHK_FAIL_END + + memcpy (buf, str1 + 2, l0 + 9); + CHK_FAIL_START + strcat (buf, "AB"); + CHK_FAIL_END + + memcpy (buf, str1 + 3, l0 + 8); + CHK_FAIL_START + strncat (buf, "ZYXWV", l0 + 3); + CHK_FAIL_END + + CHK_FAIL_START + memcpy (a.buf1 + 1, "abcdefghij", l0 + 10); + CHK_FAIL_END + + CHK_FAIL_START + memmove (a.buf1 + 2, a.buf1 + 1, l0 + 9); + CHK_FAIL_END + + CHK_FAIL_START + p = mempcpy (a.buf1 + 6, "abcde", l0 + 5); + CHK_FAIL_END + + CHK_FAIL_START + memset (a.buf1 + 9, 'j', l0 + 2); + CHK_FAIL_END + +#if __USE_FORTIFY_LEVEL >= 2 +# define O 0 +#else +# define O 1 +#endif + + CHK_FAIL_START + strcpy (a.buf1 + (O + 4), str1 + 5); + CHK_FAIL_END + + CHK_FAIL_START + p = stpcpy (a.buf1 + (O + 8), str2); + CHK_FAIL_END + + CHK_FAIL_START + strncpy (a.buf1 + (O + 6), "X", l0 + 4); + CHK_FAIL_END + + CHK_FAIL_START + sprintf (a.buf1 + (O + 7), "%d", num1); + CHK_FAIL_END + + CHK_FAIL_START + snprintf (a.buf1 + (O + 7), l0 + 3, "%d", num2); + CHK_FAIL_END + + memcpy (a.buf1, str1 + (3 - O), l0 + 8 + O); + CHK_FAIL_START + strcat (a.buf1, "AB"); + CHK_FAIL_END + + memcpy (a.buf1, str1 + (4 - O), l0 + 7 + O); + CHK_FAIL_START + strncat (a.buf1, "ZYXWV", l0 + 3); + CHK_FAIL_END +#endif + + /* Now checks for %n protection. */ + + /* Constant literals passed directly are always ok + (even with warnings about possible bugs from GCC). */ + int n1, n2; + if (sprintf (buf, "%s%n%s%n", str2, &n1, str2, &n2) != 2 + || n1 != 1 || n2 != 2) + FAIL (); + + /* In this case the format string is not known at compile time, + but resides in read-only memory, so is ok. */ + if (snprintf (buf, 4, str3, str2, &n1, str2, &n2) != 2 + || n1 != 1 || n2 != 2) + FAIL (); + + strcpy (buf2 + 2, "%n%s%n"); + /* When the format string is writable and contains %n, + with -D_FORTIFY_SOURCE=2 it causes __chk_fail. */ + CHK_FAIL2_START + if (sprintf (buf, buf2, str2, &n1, str2, &n1) != 2) + FAIL (); + CHK_FAIL2_END + + CHK_FAIL2_START + if (snprintf (buf, 3, buf2, str2, &n1, str2, &n1) != 2) + FAIL (); + CHK_FAIL2_END + + /* But if there is no %n, even writable format string + should work. */ + buf2[6] = '\0'; + if (sprintf (buf, buf2 + 4, str2) != 1) + FAIL (); + + /* Constant literals passed directly are always ok + (even with warnings about possible bugs from GCC). */ + if (printf ("%s%n%s%n", str4, &n1, str5, &n2) != 14 + || n1 != 7 || n2 != 14) + FAIL (); + + /* In this case the format string is not known at compile time, + but resides in read-only memory, so is ok. */ + if (printf (str3, str4, &n1, str5, &n2) != 14 + || n1 != 7 || n2 != 14) + FAIL (); + + strcpy (buf2 + 2, "%n%s%n"); + /* When the format string is writable and contains %n, + with -D_FORTIFY_SOURCE=2 it causes __chk_fail. */ + CHK_FAIL2_START + if (printf (buf2, str4, &n1, str5, &n1) != 14) + FAIL (); + CHK_FAIL2_END + + /* But if there is no %n, even writable format string + should work. */ + buf2[6] = '\0'; + if (printf (buf2 + 4, str5) != 7) + FAIL (); + + FILE *fp = stdout; + + /* Constant literals passed directly are always ok + (even with warnings about possible bugs from GCC). */ + if (fprintf (fp, "%s%n%s%n", str4, &n1, str5, &n2) != 14 + || n1 != 7 || n2 != 14) + FAIL (); + + /* In this case the format string is not known at compile time, + but resides in read-only memory, so is ok. */ + if (fprintf (fp, str3, str4, &n1, str5, &n2) != 14 + || n1 != 7 || n2 != 14) + FAIL (); + + strcpy (buf2 + 2, "%n%s%n"); + /* When the format string is writable and contains %n, + with -D_FORTIFY_SOURCE=2 it causes __chk_fail. */ + CHK_FAIL2_START + if (fprintf (fp, buf2, str4, &n1, str5, &n1) != 14) + FAIL (); + CHK_FAIL2_END + + /* But if there is no %n, even writable format string + should work. */ + buf2[6] = '\0'; + if (fprintf (fp, buf2 + 4, str5) != 7) + FAIL (); + + if (freopen (temp_filename, "r", stdin) == NULL) + { + puts ("could not open temporary file"); + exit (1); + } + + if (gets (buf) != buf || memcmp (buf, "abcdefgh", 9)) + FAIL (); + if (gets (buf) != buf || memcmp (buf, "ABCDEFGHI", 10)) + FAIL (); + +#if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START + if (gets (buf) != buf) + FAIL (); + CHK_FAIL_END +#endif + + if (freopen (temp_filename, "r", stdin) == NULL) + { + puts ("could not open temporary file"); + exit (1); + } + + if (fseek (stdin, 9 + 10 + 11, SEEK_SET)) + { + puts ("could not seek in test file"); + exit (1); + } + +#if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START + if (gets (buf) != buf) + FAIL (); + CHK_FAIL_END +#endif + + return ret; +} diff --git a/debug/tst-chk2.c b/debug/tst-chk2.c new file mode 100644 index 0000000000..be37ce2d22 --- /dev/null +++ b/debug/tst-chk2.c @@ -0,0 +1,2 @@ +#define _FORTIFY_SOURCE 1 +#include "tst-chk1.c" diff --git a/debug/tst-chk3.c b/debug/tst-chk3.c new file mode 100644 index 0000000000..38b8e4fb36 --- /dev/null +++ b/debug/tst-chk3.c @@ -0,0 +1,2 @@ +#define _FORTIFY_SOURCE 2 +#include "tst-chk1.c" diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c new file mode 100644 index 0000000000..a9e107d8e5 --- /dev/null +++ b/debug/vfprintf_chk.c @@ -0,0 +1,42 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004 + 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 <stdarg.h> +#include <stdio.h> +#include "../libio/libioP.h" + + +/* Write formatted output to FP from the format string FORMAT. */ +int +__vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap) +{ + int done; + + _IO_acquire_lock (fp); + if (flag > 0) + fp->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N; + + done = vfprintf (fp, format, ap); + + if (flag > 0) + fp->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N; + _IO_release_lock (fp); + + return done; +} diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c new file mode 100644 index 0000000000..f477f15411 --- /dev/null +++ b/debug/vprintf_chk.c @@ -0,0 +1,42 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004 + 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 <stdarg.h> +#include <stdio.h> +#include "../libio/libioP.h" + + +/* Write formatted output to stdout from the format string FORMAT. */ +int +__vprintf_chk (int flag, const char *format, va_list ap) +{ + int done; + + _IO_acquire_lock (stdout); + if (flag > 0) + stdout->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N; + + done = vfprintf (stdout, format, ap); + + if (flag > 0) + stdout->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N; + _IO_release_lock (stdout); + + return done; +} diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c new file mode 100644 index 0000000000..850cd5af5a --- /dev/null +++ b/debug/vsnprintf_chk.c @@ -0,0 +1,70 @@ +/* Copyright (C) 1991, 1995, 1997, 1998, 2004 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 <stdarg.h> +#include <stdio.h> +#include "../libio/libioP.h" +#include "../libio/strfile.h" + +extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden; + +/* Write formatted output into S, according to the format + string FORMAT, writing no more than MAXLEN characters. */ +/* VARARGS5 */ +int +__vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen, + const char *format, va_list args) +{ + /* XXX Maybe for less strict version do not fail immediately. + Though, maxlen is supposed to be the size of buffer pointed + to by s, so a conforming program can't pass such maxlen + to *snprintf. */ + if (__builtin_expect (slen < maxlen, 0)) + __chk_fail (); + + _IO_strnfile sf; + int ret; +#ifdef _IO_MTSAFE_IO + sf.f._sbf._f._lock = NULL; +#endif + + /* We need to handle the special case where MAXLEN is 0. Use the + overflow buffer right from the start. */ + if (maxlen == 0) + { + s = sf.overflow_buf; + maxlen = sizeof (sf.overflow_buf); + } + + _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); + _IO_JUMPS ((struct _IO_FILE_plus *) &sf.f._sbf) = &_IO_strn_jumps; + s[0] = '\0'; + + /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + if (flags > 0) + sf.f._sbf._f._flags2 |= _IO_FLAGS2_CHECK_PERCENT_N; + + _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s); + ret = INTUSE(_IO_vfprintf) ((_IO_FILE *) &sf.f._sbf, format, args); + + if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf) + *sf.f._sbf._f._IO_write_ptr = '\0'; + return ret; +} +libc_hidden_def (__vsnprintf_chk) diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c new file mode 100644 index 0000000000..83383286da --- /dev/null +++ b/debug/vsprintf_chk.c @@ -0,0 +1,91 @@ +/* Copyright (C) 1994, 1997, 1999-2003, 2004 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 <stdarg.h> +#include <stdio.h> +#include "../libio/libioP.h" +#include "../libio/strfile.h" + + +static int _IO_str_chk_overflow (_IO_FILE *fp, int c) __THROW; + +static int +_IO_str_chk_overflow (fp, c) + _IO_FILE *fp; + int c; +{ + /* When we come to here this means the user supplied buffer is + filled. */ + __chk_fail (); +} + + +static const struct _IO_jump_t _IO_str_chk_jumps = +{ + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_str_finish), + JUMP_INIT(overflow, _IO_str_chk_overflow), + JUMP_INIT(underflow, INTUSE(_IO_str_underflow)), + JUMP_INIT(uflow, INTUSE(_IO_default_uflow)), + JUMP_INIT(pbackfail, INTUSE(_IO_str_pbackfail)), + JUMP_INIT(xsputn, INTUSE(_IO_default_xsputn)), + JUMP_INIT(xsgetn, INTUSE(_IO_default_xsgetn)), + JUMP_INIT(seekoff, INTUSE(_IO_str_seekoff)), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_default_setbuf), + JUMP_INIT(sync, _IO_default_sync), + JUMP_INIT(doallocate, INTUSE(_IO_default_doallocate)), + JUMP_INIT(read, _IO_default_read), + JUMP_INIT(write, _IO_default_write), + JUMP_INIT(seek, _IO_default_seek), + JUMP_INIT(close, _IO_default_close), + JUMP_INIT(stat, _IO_default_stat), + JUMP_INIT(showmanyc, _IO_default_showmanyc), + JUMP_INIT(imbue, _IO_default_imbue) +}; + + +int +__vsprintf_chk (char *s, int flags, size_t slen, const char *format, + va_list args) +{ + _IO_strfile f; + int ret; +#ifdef _IO_MTSAFE_IO + f._sbf._f._lock = NULL; +#endif + + if (slen == 0) + __chk_fail (); + + _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); + _IO_JUMPS ((struct _IO_FILE_plus *) &f._sbf) = &_IO_str_chk_jumps; + s[0] = '\0'; + _IO_str_init_static_internal (&f, s, slen - 1, s); + + /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + if (flags > 0) + f._sbf._f._flags2 |= _IO_FLAGS2_CHECK_PERCENT_N; + + ret = INTUSE(_IO_vfprintf) ((_IO_FILE *) &f._sbf, format, args); + + *f._sbf._f._IO_write_ptr = '\0'; + return ret; +} +libc_hidden_def (__vsprintf_chk) diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c index 4ec2ebcbb4..adb85e6753 100644 --- a/elf/dl-minimal.c +++ b/elf/dl-minimal.c @@ -354,6 +354,13 @@ __strsep (char **stringp, const char *delim) weak_alias (__strsep, strsep) strong_alias (__strsep, __strsep_g) +void +__attribute__ ((noreturn)) +__chk_fail (void) +{ + _exit (127); +} +rtld_hidden_def (__chk_fail) /* The '_itoa_lower_digits' variable in libc.so is able to handle bases up to 36. We don't need this here. */ diff --git a/include/bits/string3.h b/include/bits/string3.h new file mode 100644 index 0000000000..1ddd981a90 --- /dev/null +++ b/include/bits/string3.h @@ -0,0 +1 @@ +#include <string/bits/string3.h> diff --git a/include/features.h b/include/features.h index 59ae3c4d13..8b03e165f9 100644 --- a/include/features.h +++ b/include/features.h @@ -41,6 +41,8 @@ _GNU_SOURCE All of the above, plus GNU extensions. _REENTRANT Select additionally reentrant object. _THREAD_SAFE Same as _REENTRANT, often used by other systems. + _FORTIFY_SOURCE If set to numeric value > 0 additional security + measures are defined, according to level. The `-ansi' switch to the GNU C compiler defines __STRICT_ANSI__. If none of these are defined, the default is to have _SVID_SOURCE, @@ -69,6 +71,7 @@ __USE_MISC Define things common to BSD and System V Unix. __USE_GNU Define GNU extensions. __USE_REENTRANT Define reentrant/thread-safe *_r functions. + __USE_FORTIFY_LEVEL Additional security measures used, according to level. __FAVOR_BSD Favor 4.3BSD things in cases of conflict. The macros `__GNU_LIBRARY__', `__GLIBC__', and `__GLIBC_MINOR__' are @@ -101,6 +104,7 @@ #undef __USE_MISC #undef __USE_GNU #undef __USE_REENTRANT +#undef __USE_FORTIFY_LEVEL #undef __FAVOR_BSD #undef __KERNEL_STRICT_NAMES @@ -113,6 +117,20 @@ /* Always use ISO C things. */ #define __USE_ANSI 1 +/* Convenience macros to test the versions of glibc and gcc. + Use them like this: + #if __GNUC_PREREQ (2,8) + ... code requiring gcc 2.8 or later ... + #endif + Note - they won't work for gcc1 or glibc1, since the _MINOR macros + were not defined then. */ +#if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define __GNUC_PREREQ(maj, min) 0 +#endif + /* If _BSD_SOURCE was defined by the user, favor BSD over POSIX. */ #if defined _BSD_SOURCE && \ @@ -244,6 +262,14 @@ # define __USE_REENTRANT 1 #endif +#if _FORTIFY_SOURCE > 0 && __GNUC_PREREQ (4, 1) && __OPTIMIZE__ > 0 +# if _FORTIFY_SOURCE == 1 +# define __USE_FORTIFY_LEVEL 1 +# elif _FORTIFY_SOURCE > 1 +# define __USE_FORTIFY_LEVEL 2 +# endif +#endif + /* We do support the IEC 559 math functionality, real and complex. */ #define __STDC_IEC_559__ 1 #define __STDC_IEC_559_COMPLEX__ 1 @@ -265,20 +291,6 @@ #define __GLIBC__ 2 #define __GLIBC_MINOR__ 3 -/* Convenience macros to test the versions of glibc and gcc. - Use them like this: - #if __GNUC_PREREQ (2,8) - ... code requiring gcc 2.8 or later ... - #endif - Note - they won't work for gcc1 or glibc1, since the _MINOR macros - were not defined then. */ -#if defined __GNUC__ && defined __GNUC_MINOR__ -# define __GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -# define __GNUC_PREREQ(maj, min) 0 -#endif - #define __GLIBC_PREREQ(maj, min) \ ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min)) diff --git a/include/stdio.h b/include/stdio.h index b871abc15e..05a91b4cb3 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -27,6 +27,18 @@ extern int __vsscanf (__const char *__restrict __s, _G_va_list __arg) __attribute__ ((__format__ (__scanf__, 2, 0))); +extern int __sprintf_chk (char *, int, size_t, const char *, ...) __THROW; +extern int __snprintf_chk (char *, size_t, int, size_t, const char *, ...) + __THROW; +extern int __vsprintf_chk (char *, int, size_t, const char *, + _G_va_list) __THROW; +extern int __vsnprintf_chk (char *, size_t, int, size_t, const char *, + _G_va_list) __THROW; +extern int __printf_chk (int, const char *, ...); +extern int __fprintf_chk (FILE *, int, const char *, ...); +extern int __vprintf_chk (int, const char *, _G_va_list); +extern int __vfprintf_chk (FILE *, int, const char *, _G_va_list); + /* Prototypes for compatibility functions. */ extern FILE *__new_tmpfile (void); extern FILE *__old_tmpfile (void); @@ -109,6 +121,8 @@ libc_hidden_proto (fgets_unlocked) libc_hidden_proto (fputs_unlocked) libc_hidden_proto (open_memstream) libc_hidden_proto (__libc_fatal) +libc_hidden_proto (__vsprintf_chk) +libc_hidden_proto (__vsnprintf_chk) # if !defined NOT_IN_libc && defined SHARED && defined DO_VERSIONING \ && defined HAVE_VISIBILITY_ATTRIBUTE && !defined HAVE_BROKEN_ALIAS_ATTRIBUTE\ diff --git a/include/string.h b/include/string.h index afc6adfbda..738dd8e27c 100644 --- a/include/string.h +++ b/include/string.h @@ -3,7 +3,7 @@ #include <sys/types.h> extern void *__memccpy (void *__dest, __const void *__src, - int __c, size_t __n); + int __c, size_t __n); extern size_t __strnlen (__const char *__string, size_t __maxlen) __attribute_pure__; @@ -114,4 +114,30 @@ libc_hidden_builtin_proto (ffs) # endif # endif +extern void *__memcpy_chk (void *__restrict __dest, + const void *__restrict __src, size_t __len, + size_t __destlen) __THROW; +extern void *__memmove_chk (void *__dest, const void *__src, size_t __len, + size_t __destlen) __THROW; +extern void *__mempcpy_chk (void *__restrict __dest, + const void *__restrict __src, size_t __len, + size_t __destlen) __THROW; +extern void *__memset_chk (void *__dest, int __ch, size_t __len, + size_t __destlen) __THROW; +extern char *__strcpy_chk (char *__restrict __dest, + const char *__restrict __src, + size_t __destlen) __THROW; +extern char *__stpcpy_chk (char *__restrict __dest, + const char *__restrict __src, + size_t __destlen) __THROW; +extern char *__strncpy_chk (char *__restrict __dest, + const char *__restrict __src, + size_t __len, size_t __destlen) __THROW; +extern char *__strcat_chk (char *__restrict __dest, + const char *__restrict __src, + size_t __destlen) __THROW; +extern char *__strncat_chk (char *__restrict __dest, + const char *__restrict __src, + size_t __len, size_t __destlen) __THROW; + #endif diff --git a/include/sys/cdefs.h b/include/sys/cdefs.h index 200abb4f02..8ba980477d 100644 --- a/include/sys/cdefs.h +++ b/include/sys/cdefs.h @@ -1 +1,9 @@ +#ifndef _SYS_CDEFS_H + #include <misc/sys/cdefs.h> + +extern void __chk_fail (void) __attribute__ ((__noreturn__)); +libc_hidden_proto (__chk_fail) +rtld_hidden_proto (__chk_fail) + +#endif diff --git a/libio/Makefile b/libio/Makefile index c7253ff571..a9384b55a9 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc. +# Copyright (C) 1995-2002, 2003, 2004 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 @@ -22,7 +22,7 @@ subdir := libio headers := stdio.h libio.h _G_config.h bits/stdio.h bits/stdio-lock.h \ - bits/sys_errlist.h + bits/sys_errlist.h bits/stdio2.h routines := \ filedoalloc iofclose iofdopen iofflush iofgetpos iofgets iofopen \ diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h new file mode 100644 index 0000000000..acf07ea91b --- /dev/null +++ b/libio/bits/stdio2.h @@ -0,0 +1,78 @@ +/* Checking macros for stdio functions. + Copyright (C) 2004 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 _STDIO_H +# error "Never include <bits/stdio2.h> directly; use <stdio.h> instead." +#endif + +extern int __sprintf_chk (char *__restrict __s, int __flag, size_t __slen, + __const char *__restrict __format, ...) __THROW; +extern int __vsprintf_chk (char *__restrict __s, int __flag, size_t __slen, + __const char *__restrict __format, + _G_va_list __ap) __THROW; + +#define sprintf(str, ...) \ + __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __bos (str), \ + __VA_ARGS__) +#define vsprintf(str, fmt, ap) \ + __builtin___vsprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __bos (str), fmt, ap) + +#if defined __USE_BSD || defined __USE_ISOC99 || defined __USE_UNIX98 + +extern int __snprintf_chk (char *__restrict __s, size_t __n, int __flag, + size_t __slen, __const char *__restrict __format, + ...) __THROW; +extern int __vsnprintf_chk (char *__restrict __s, size_t __n, int __flag, + size_t __slen, __const char *__restrict __format, + _G_va_list __ap) __THROW; + +# define snprintf(str, len, ...) \ + __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, __bos (str), \ + __VA_ARGS__) +# define vsnprintf(str, len, fmt, ap) \ + __builtin___vsnprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, __bos (str), \ + fmt, ap) + +#endif + +#if __USE_FORTIFY_LEVEL > 1 + +extern int __fprintf_chk (FILE *__restrict __stream, int __flag, + __const char *__restrict __format, ...); +extern int __printf_chk (int __flag, __const char *__restrict __format, ...); +extern int __vfprintf_chk (FILE *__restrict __stream, int __flag, + __const char *__restrict __format, _G_va_list __ap); +extern int __vprintf_chk (int __flag, __const char *__restrict __format, + _G_va_list __ap); + +# define printf(...) \ + __printf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__) +# define fprintf(stream, ...) \ + __fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__) +# define vprintf(format, ap) \ + __vprintf_chk (__USE_FORTIFY_LEVEL - 1, format, ap) +# define vfprintf(stream, format, ap) \ + __vfprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, format, ap) + +#endif + +extern char *__gets_chk (char *__str, size_t); +#define gets(__str) \ + ((__bos (__str) == (size_t) -1) \ + ? (gets) (__str) : __gets_chk (__str, __bos (__str))) diff --git a/libio/libio.h b/libio/libio.h index 1672f7b54f..645f9fb83c 100644 --- a/libio/libio.h +++ b/libio/libio.h @@ -139,6 +139,9 @@ #define _IO_FLAGS2_MMAP 1 #define _IO_FLAGS2_NOTCANCEL 2 +#ifdef _LIBC +# define _IO_FLAGS2_CHECK_PERCENT_N 4 +#endif /* These are "formatting flags" matching the iostream fmtflags enum values. */ #define _IO_SKIPWS 01 diff --git a/libio/stdio.h b/libio/stdio.h index 599094296a..e1081c9039 100644 --- a/libio/stdio.h +++ b/libio/stdio.h @@ -827,6 +827,9 @@ extern void funlockfile (FILE *__stream) __THROW; #ifdef __USE_EXTERN_INLINES # include <bits/stdio.h> #endif +#if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus +# include <bits/stdio2.h> +#endif __END_DECLS diff --git a/libio/strfile.h b/libio/strfile.h index bcac784717..b91111a9d6 100644 --- a/libio/strfile.h +++ b/libio/strfile.h @@ -63,3 +63,13 @@ typedef struct _IO_strfile_ /* frozen: set when the program has requested that the array object not be altered, reallocated, or freed. */ #define _IO_STR_FROZEN(FP) ((FP)->_f._IO_file_flags & _IO_USER_BUF) + +typedef struct +{ + _IO_strfile f; + /* This is used for the characters which do not fit in the buffer + provided by the user. */ + char overflow_buf[64]; +} _IO_strnfile; + +extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden; diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c index e2cfb16d8a..4250c2d2de 100644 --- a/libio/vsnprintf.c +++ b/libio/vsnprintf.c @@ -28,16 +28,6 @@ #include "libioP.h" #include "strfile.h" - -typedef struct -{ - _IO_strfile f; - /* This is used for the characters which do not fit in the buffer - provided by the user. */ - char overflow_buf[64]; -} _IO_strnfile; - - static int _IO_strn_overflow (_IO_FILE *fp, int c) __THROW; static int @@ -77,7 +67,7 @@ _IO_strn_overflow (fp, c) } -static const struct _IO_jump_t _IO_strn_jumps = +const struct _IO_jump_t _IO_strn_jumps attribute_hidden = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_str_finish), diff --git a/libio/vswprintf.c b/libio/vswprintf.c index 3cf01e2c84..42168aade4 100644 --- a/libio/vswprintf.c +++ b/libio/vswprintf.c @@ -35,7 +35,7 @@ typedef struct /* This is used for the characters which do not fit in the buffer provided by the user. */ wchar_t overflow_buf[64]; -} _IO_strnfile; +} _IO_wstrnfile; static wint_t _IO_wstrn_overflow (_IO_FILE *fp, wint_t c) __THROW; @@ -49,8 +49,8 @@ _IO_wstrn_overflow (fp, c) filled. But since we must return the number of characters which would have been written in total we must provide a buffer for further use. We can do this by writing on and on in the overflow - buffer in the _IO_strnfile structure. */ - _IO_strnfile *snf = (_IO_strnfile *) fp; + buffer in the _IO_wstrnfile structure. */ + _IO_wstrnfile *snf = (_IO_wstrnfile *) fp; if (fp->_wide_data->_IO_buf_base != snf->overflow_buf) { @@ -107,7 +107,7 @@ _IO_vswprintf (string, maxlen, format, args) const wchar_t *format; _IO_va_list args; { - _IO_strnfile sf; + _IO_wstrnfile sf; int ret; struct _IO_wide_data wd; #ifdef _IO_MTSAFE_IO diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h index 8894d0d5fc..475cf62961 100644 --- a/misc/sys/cdefs.h +++ b/misc/sys/cdefs.h @@ -127,6 +127,11 @@ #endif +/* Fortify support. */ +#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1) +#define __bos0(ptr) __builtin_object_size (ptr, 0) + + /* Support for flexible arrays. */ #if __GNUC_PREREQ (2,97) /* GCC 2.97 supports C99 flexible array members. */ diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 38da382efa..5e480ad52b 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -70,6 +70,7 @@ # define INT_T int # define L_(Str) Str # define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10) +# define STR_LEN(Str) strlen (Str) # define PUT(F, S, N) _IO_sputn ((F), (S), (N)) # define PAD(Padchar) \ @@ -86,6 +87,7 @@ # define INT_T wint_t # define L_(Str) L##Str # define ISDIGIT(Ch) ((unsigned int) ((Ch) - L'0') < 10) +# define STR_LEN(Str) __wcslen (Str) # include "_itowa.h" @@ -219,6 +221,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) /* For the %m format we may need the current `errno' value. */ int save_errno = errno; + /* 1 if format is in read-only memory, -1 if it is in writable memory, + 0 if unknown. */ + int readonly_format = 0; /* This table maps a character into a number representing a class. In each step there is a destination label for each @@ -877,6 +882,19 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) /* NOTREACHED */ \ \ LABEL (form_number): \ + if (s->_flags2 & _IO_FLAGS2_CHECK_PERCENT_N) \ + { \ + if (! readonly_format) \ + { \ + extern int __readonly_area (const void *, size_t) \ + attribute_hidden; \ + readonly_format \ + = __readonly_area (format, (STR_LEN (format) + 1) \ + * sizeof (CHAR_T)); \ + } \ + if (readonly_format < 0) \ + __chk_fail (); \ + } \ /* Answer the count of characters written. */ \ if (fspec == NULL) \ { \ @@ -2091,6 +2109,7 @@ buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format, #ifdef _IO_MTSAFE_IO hp->_lock = NULL; #endif + hp->_flags2 = s->_flags2; _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps; /* Now print to helper instead. */ diff --git a/string/Makefile b/string/Makefile index 5ab487f5ba..66469f586e 100644 --- a/string/Makefile +++ b/string/Makefile @@ -23,7 +23,7 @@ subdir := string headers := string.h strings.h memory.h endian.h bits/endian.h \ argz.h envz.h byteswap.h bits/byteswap.h bits/string.h \ - bits/string2.h + bits/string2.h bits/string3.h routines := strcat strchr strcmp strcoll strcpy strcspn \ strverscmp strdup strndup \ diff --git a/string/bits/string3.h b/string/bits/string3.h new file mode 100644 index 0000000000..87cbe35bb1 --- /dev/null +++ b/string/bits/string3.h @@ -0,0 +1,167 @@ +/* Copyright (C) 2004 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 _STRING_H +# error "Never use <bits/string3.h> directly; include <string.h> instead." +#endif + +/* XXX This is temporarily. We should not redefine any of the symbols + and instead integrate the error checking into the original + definitions. */ +#undef memcpy +#undef memmove +#undef memset +#undef strcat +#undef strcpy +#undef strncat +#undef strncpy +#ifdef __USE_GNU +# undef mempcpy +# undef stpcpy +#endif +#ifdef __USE_BSD +# undef bcopy +# undef bzero +#endif + + +#define memcpy(dest, src, len) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memcpy_chk (dest, src, len, __bos0 (dest)) \ + : __memcpy_ichk (dest, src, len)) +static __inline__ void * +__attribute__ ((__always_inline__)) +__memcpy_ichk (void *__restrict __dest, const void *__restrict __src, + size_t __len) +{ + return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest)); +} + + +#define memmove(dest, src, len) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memmove_chk (dest, src, len, __bos0 (dest)) \ + : __memmove_ichk (dest, src, len)) +static __inline__ void * +__attribute__ ((__always_inline__)) +__memmove_ichk (void *__dest, const void *__src, size_t __len) +{ + return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest)); +} + + +#ifdef __USE_GNU +# define mempcpy(dest, src, len) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___mempcpy_chk (dest, src, len, __bos0 (dest)) \ + : __mempcpy_ichk (dest, src, len)) +static __inline__ void * +__attribute__ ((__always_inline__)) +__mempcpy_ichk (void *__restrict __dest, const void *__restrict __src, + size_t __len) +{ + return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest)); +} +#endif + + +#define memset(dest, ch, len) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memset_chk (dest, ch, len, __bos0 (dest)) \ + : __memset_ichk (dest, ch, len)) +static __inline__ void * +__attribute__ ((__always_inline__)) +__memset_ichk (void *__dest, int __ch, size_t __len) +{ + return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest)); +} + +#ifdef __USE_BSD +# define bcopy(src, dest, len) ((void) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memmove_chk (dest, src, len, __bos0 (dest)) \ + : __memmove_ichk (dest, src, len))) +# define bzero(dest, len) ((void) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memset_chk (dest, '\0', len, __bos0 (dest)) \ + : __memset_ichk (dest, '\0', len))) +#endif + + +#define strcpy(dest, src) \ + ((__bos (dest) != (size_t) -1) \ + ? __builtin___strcpy_chk (dest, src, __bos (dest)) \ + : __strcpy_ichk (dest, src)) +static __inline__ char * +__attribute__ ((__always_inline__)) +__strcpy_ichk (char *__restrict __dest, const char *__restrict __src) +{ + return __builtin___strcpy_chk (__dest, __src, __bos (__dest)); +} + + +#ifdef __USE_GNU +# define stpcpy(dest, src) \ + ((__bos (dest) != (size_t) -1) \ + ? __builtin___stpcpy_chk (dest, src, __bos (dest)) \ + : __stpcpy_ichk (dest, src)) +static __inline__ char * +__attribute__ ((__always_inline__)) +__stpcpy_ichk (char *__restrict __dest, const char *__restrict __src) +{ + return __builtin___stpcpy_chk (__dest, __src, __bos (__dest)); +} +#endif + + +#define strncpy(dest, src, len) \ + ((__bos (dest) != (size_t) -1) \ + ? __builtin___strncpy_chk (dest, src, len, __bos (dest)) \ + : __strncpy_ichk (dest, src, len)) +static __inline__ char * +__attribute__ ((__always_inline__)) +__strncpy_ichk (char *__restrict __dest, const char *__restrict __src, + size_t __len) +{ + return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest)); +} + + +#define strcat(dest, src) \ + ((__bos (dest) != (size_t) -1) \ + ? __builtin___strcat_chk (dest, src, __bos (dest)) \ + : __strcat_ichk (dest, src)) +static __inline__ char * +__attribute__ ((__always_inline__)) +__strcat_ichk (char *__restrict __dest, const char *__restrict __src) +{ + return __builtin___strcat_chk (__dest, __src, __bos (__dest)); +} + + +#define strncat(dest, src, len) \ + ((__bos (dest) != (size_t) -1) \ + ? __builtin___strncat_chk (dest, src, len, __bos (dest)) \ + : __strncat_ichk (dest, src, len)) +static __inline__ char * +__attribute__ ((__always_inline__)) +__strncat_ichk (char *__restrict __dest, const char *__restrict __src, + size_t __len) +{ + return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest)); +} diff --git a/string/string.h b/string/string.h index 4ea3a74ca7..1adf925bb0 100644 --- a/string/string.h +++ b/string/string.h @@ -416,6 +416,11 @@ extern char *basename (__const char *__filename) __THROW __nonnull ((1)); /* These are generic optimizations which do not add too much inline code. */ # include <bits/string2.h> # endif + +# if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus +/* Functions with security checks. */ +# include <bits/string3.h> +# endif #endif __END_DECLS diff --git a/sysdeps/generic/memcpy_chk.c b/sysdeps/generic/memcpy_chk.c new file mode 100644 index 0000000000..638cd0e4fb --- /dev/null +++ b/sysdeps/generic/memcpy_chk.c @@ -0,0 +1,66 @@ +/* Copy memory to memory until the specified number of bytes + has been copied with error checking. Overlap is NOT handled correctly. + Copyright (C) 1991, 1997, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + 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 <string.h> +#include <memcopy.h> +#include <pagecopy.h> + +void * +__memcpy_chk (dstpp, srcpp, len, dstlen) + void *dstpp; + const void *srcpp; + size_t len; + size_t dstlen; +{ + if (__builtin_expect (dstlen < len, 0)) + __chk_fail (); + + unsigned long int dstp = (long int) dstpp; + unsigned long int srcp = (long int) srcpp; + + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); + + /* Copy whole pages from SRCP to DSTP by virtual address manipulation, + as much as possible. */ + + PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); + + /* Copy from SRCP to DSTP taking advantage of the known alignment of + DSTP. Number of bytes remaining is put in the third argument, + i.e. in LEN. This number may vary from machine to machine. */ + + WORD_COPY_FWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD (dstp, srcp, len); + + return dstpp; +} diff --git a/sysdeps/generic/memmove_chk.c b/sysdeps/generic/memmove_chk.c new file mode 100644 index 0000000000..f3b74d23d9 --- /dev/null +++ b/sysdeps/generic/memmove_chk.c @@ -0,0 +1,98 @@ +/* Copy memory to memory until the specified number of bytes + has been copied with error checking. Overlap is handled correctly. + Copyright (C) 1991,1995,1996,1997,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + 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 <string.h> +#include <memcopy.h> +#include <pagecopy.h> + +void * +__memmove_chk (dest, src, len, destlen) + void *dest; + const void *src; + size_t len; + size_t destlen; +{ + if (__builtin_expect (destlen < len, 0)) + __chk_fail (); + + unsigned long int dstp = (long int) dest; + unsigned long int srcp = (long int) src; + + /* This test makes the forward copying code be used whenever possible. + Reduces the working set. */ + if (dstp - srcp >= len) /* *Unsigned* compare! */ + { + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); + + /* Copy whole pages from SRCP to DSTP by virtual address + manipulation, as much as possible. */ + + PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); + + /* Copy from SRCP to DSTP taking advantage of the known + alignment of DSTP. Number of bytes remaining is put + in the third argument, i.e. in LEN. This number may + vary from machine to machine. */ + + WORD_COPY_FWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD (dstp, srcp, len); + } + else + { + /* Copy from the end to the beginning. */ + srcp += len; + dstp += len; + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= dstp % OPSIZ; + BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ); + + /* Copy from SRCP to DSTP taking advantage of the known + alignment of DSTP. Number of bytes remaining is put + in the third argument, i.e. in LEN. This number may + vary from machine to machine. */ + + WORD_COPY_BWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_BWD (dstp, srcp, len); + } + + return dest; +} diff --git a/sysdeps/generic/mempcpy_chk.c b/sysdeps/generic/mempcpy_chk.c new file mode 100644 index 0000000000..5297bbab92 --- /dev/null +++ b/sysdeps/generic/mempcpy_chk.c @@ -0,0 +1,67 @@ +/* Copy memory to memory until the specified number of bytes + has been copied, return pointer to following byte, with error checking. + Overlap is NOT handled correctly. + Copyright (C) 1991, 1997, 1998, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + 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 <string.h> +#include <memcopy.h> +#include <pagecopy.h> + +void * +__mempcpy_chk (dstpp, srcpp, len, dstlen) + void *dstpp; + const void *srcpp; + size_t len; + size_t dstlen; +{ + if (__builtin_expect (dstlen < len, 0)) + __chk_fail (); + + unsigned long int dstp = (long int) dstpp; + unsigned long int srcp = (long int) srcpp; + + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); + + /* Copy whole pages from SRCP to DSTP by virtual address manipulation, + as much as possible. */ + + PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); + + /* Copy from SRCP to DSTP taking advantage of the known alignment of + DSTP. Number of bytes remaining is put in the third argument, + i.e. in LEN. This number may vary from machine to machine. */ + + WORD_COPY_FWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD (dstp, srcp, len); + + return (void *) dstp; +} diff --git a/sysdeps/generic/memset_chk.c b/sysdeps/generic/memset_chk.c new file mode 100644 index 0000000000..c311914395 --- /dev/null +++ b/sysdeps/generic/memset_chk.c @@ -0,0 +1,92 @@ +/* Copyright (C) 1991, 1997, 2003, 2004 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 <string.h> +#include <memcopy.h> + +void * +__memset_chk (dstpp, c, len, dstlen) + void *dstpp; + int c; + size_t len; + size_t dstlen; +{ + if (__builtin_expect (dstlen < len, 0)) + __chk_fail (); + + long int dstp = (long int) dstpp; + + if (len >= 8) + { + size_t xlen; + op_t cccc; + + cccc = (unsigned char) c; + cccc |= cccc << 8; + cccc |= cccc << 16; + if (OPSIZ > 4) + /* Do the shift in two steps to avoid warning if long has 32 bits. */ + cccc |= (cccc << 16) << 16; + + /* There are at least some bytes to set. + No need to test for LEN == 0 in this alignment loop. */ + while (dstp % OPSIZ != 0) + { + ((byte *) dstp)[0] = c; + dstp += 1; + len -= 1; + } + + /* Write 8 `op_t' per iteration until less than 8 `op_t' remain. */ + xlen = len / (OPSIZ * 8); + while (xlen > 0) + { + ((op_t *) dstp)[0] = cccc; + ((op_t *) dstp)[1] = cccc; + ((op_t *) dstp)[2] = cccc; + ((op_t *) dstp)[3] = cccc; + ((op_t *) dstp)[4] = cccc; + ((op_t *) dstp)[5] = cccc; + ((op_t *) dstp)[6] = cccc; + ((op_t *) dstp)[7] = cccc; + dstp += 8 * OPSIZ; + xlen -= 1; + } + len %= OPSIZ * 8; + + /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain. */ + xlen = len / OPSIZ; + while (xlen > 0) + { + ((op_t *) dstp)[0] = cccc; + dstp += OPSIZ; + xlen -= 1; + } + len %= OPSIZ; + } + + /* Write the last few bytes. */ + while (len > 0) + { + ((byte *) dstp)[0] = c; + dstp += 1; + len -= 1; + } + + return dstpp; +} diff --git a/sysdeps/generic/readonly-area.c b/sysdeps/generic/readonly-area.c new file mode 100644 index 0000000000..df5b96015c --- /dev/null +++ b/sysdeps/generic/readonly-area.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2004 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. */ + +/* Return 1 if the whole area PTR .. PTR+SIZE is not writable. + Return -1 if it is writable. */ + +#include <stdlib.h> + +int +__readonly_str (const void *ptr, size_t size) +{ + /* The conservative answer is that all strings are writable. */ + return -1; +} diff --git a/sysdeps/generic/stpcpy_chk.c b/sysdeps/generic/stpcpy_chk.c new file mode 100644 index 0000000000..dacda0115a --- /dev/null +++ b/sysdeps/generic/stpcpy_chk.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1992, 1995, 1997, 2002, 2004 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. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + + +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +char * +__stpcpy_chk (dest, src, destlen) + char *dest; + const char *src; + size_t destlen; +{ + register char *d = dest; + register const char *s = src; + + do + { + if (__builtin_expect (destlen-- == 0, 0)) + __chk_fail (); + *d++ = *s; + } + while (*s++ != '\0'); + + return d - 1; +} diff --git a/sysdeps/generic/strcat_chk.c b/sysdeps/generic/strcat_chk.c new file mode 100644 index 0000000000..b3fb3470b7 --- /dev/null +++ b/sysdeps/generic/strcat_chk.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1991, 1997, 2003, 2004 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 <string.h> +#include <memcopy.h> + + +/* Append SRC on the end of DEST. */ +char * +__strcat_chk (dest, src, destlen) + char *dest; + const char *src; + size_t destlen; +{ + char *s1 = dest; + const char *s2 = src; + reg_char c; + + /* Find the end of the string. */ + do + { + if (__builtin_expect (destlen-- == 0, 0)) + __chk_fail (); + c = *s1++; + } + while (c != '\0'); + + /* Make S1 point before the next character, so we can increment + it while memory is read (wins on pipelined cpus). */ + ++destlen; + s1 -= 2; + + do + { + if (__builtin_expect (destlen-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + } + while (c != '\0'); + + return dest; +} diff --git a/sysdeps/generic/strcpy_chk.c b/sysdeps/generic/strcpy_chk.c new file mode 100644 index 0000000000..5c1ae44cd0 --- /dev/null +++ b/sysdeps/generic/strcpy_chk.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1991, 1997, 2000, 2003, 2004 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 <stddef.h> +#include <string.h> +#include <memcopy.h> + +#undef strcpy + +/* Copy SRC to DEST with checking of destination buffer overflow. */ +char * +__strcpy_chk (dest, src, destlen) + char *dest; + const char *src; + size_t destlen; +{ + reg_char c; + char *s = (char *) src; + const ptrdiff_t off = dest - s - 1; + + do + { + if (__builtin_expect (destlen-- == 0, 0)) + __chk_fail (); + c = *s++; + s[off] = c; + } + while (c != '\0'); + + return dest; +} diff --git a/sysdeps/generic/strncat_chk.c b/sysdeps/generic/strncat_chk.c new file mode 100644 index 0000000000..953b435a4b --- /dev/null +++ b/sysdeps/generic/strncat_chk.c @@ -0,0 +1,100 @@ +/* Copyright (C) 1991, 1997, 2004 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 <string.h> + +#include <memcopy.h> + + +char * +__strncat_chk (s1, s2, n, s1len) + char *s1; + const char *s2; + size_t n; + size_t s1len; +{ + reg_char c; + char *s = s1; + + /* Find the end of S1. */ + do + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s1++; + } + while (c != '\0'); + + /* Make S1 point before next character, so we can increment + it while memory is read (wins on pipelined cpus). */ + ++s1len; + s1 -= 2; + + if (n >= 4) + { + size_t n4 = n >> 2; + do + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + } while (--n4 > 0); + n &= 3; + } + + while (n > 0) + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + n--; + } + + if (c != '\0') + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + *++s1 = '\0'; + } + + return s; +} diff --git a/sysdeps/generic/strncpy_chk.c b/sysdeps/generic/strncpy_chk.c new file mode 100644 index 0000000000..bdede7738b --- /dev/null +++ b/sysdeps/generic/strncpy_chk.c @@ -0,0 +1,89 @@ +/* Copyright (C) 1991, 1997, 2003, 2004 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 <string.h> +#include <memcopy.h> + + +char * +__strncpy_chk (s1, s2, n, s1len) + char *s1; + const char *s2; + size_t n; + size_t s1len; +{ + reg_char c; + char *s = s1; + + if (__builtin_expect (s1len < n, 0)) + __chk_fail (); + + --s1; + + if (n >= 4) + { + size_t n4 = n >> 2; + + for (;;) + { + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + if (--n4 == 0) + goto last_chars; + } + n = n - (s1 - s) - 1; + if (n == 0) + return s; + goto zero_fill; + } + + last_chars: + n &= 3; + if (n == 0) + return s; + + do + { + c = *s2++; + *++s1 = c; + if (--n == 0) + return s; + } + while (c != '\0'); + + zero_fill: + do + *++s1 = '\0'; + while (--n > 0); + + return s; +} diff --git a/sysdeps/i386/i686/memcpy.S b/sysdeps/i386/i686/memcpy.S index 865967c5c8..00e84ec2e5 100644 --- a/sysdeps/i386/i686/memcpy.S +++ b/sysdeps/i386/i686/memcpy.S @@ -1,7 +1,7 @@ /* Copy memory block and return pointer to beginning of destination block For Intel 80x86, x>=6. This file is part of the GNU C Library. - Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999. The GNU C Library is free software; you can redistribute it and/or @@ -31,6 +31,13 @@ #define LEN SRC+PTR_SIZE .text +#if defined PIC && !defined NOT_IN_libc +ENTRY (__memcpy_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb HIDDEN_JUMPTARGET (__chk_fail) +END (__memcpy_chk) +#endif ENTRY (BP_SYM (memcpy)) ENTER diff --git a/sysdeps/i386/i686/memcpy_chk.S b/sysdeps/i386/i686/memcpy_chk.S new file mode 100644 index 0000000000..561263f9bf --- /dev/null +++ b/sysdeps/i386/i686/memcpy_chk.S @@ -0,0 +1,35 @@ +/* Checking memcpy for x86-64. + Copyright (C) 2004 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 <sysdep.h> +#include "asm-syntax.h" + +#ifndef PIC + /* For libc.so this is defined in memcpy.S. + For libc.a, this is a separate source to avoid + memcpy bringing in __chk_fail and all routines + it calls. */ + .text +ENTRY (__memcpy_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb __chk_fail + jmp memcpy +END (__memcpy_chk) +#endif diff --git a/sysdeps/i386/i686/memmove.S b/sysdeps/i386/i686/memmove.S index 421b4effda..951e139ad4 100644 --- a/sysdeps/i386/i686/memmove.S +++ b/sysdeps/i386/i686/memmove.S @@ -1,7 +1,7 @@ /* Copy memory block and return pointer to beginning of destination block For Intel 80x86, x>=6. This file is part of the GNU C Library. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. Contributed by Ulrich Drepper <drepper@cygnus.com>, 2003. The GNU C Library is free software; you can redistribute it and/or @@ -31,6 +31,13 @@ #define LEN SRC+PTR_SIZE .text +#if defined PIC && !defined NOT_IN_libc +ENTRY (__memmove_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb HIDDEN_JUMPTARGET (__chk_fail) +END (__memmove_chk) +#endif ENTRY (BP_SYM (memmove)) ENTER diff --git a/sysdeps/i386/i686/memmove_chk.S b/sysdeps/i386/i686/memmove_chk.S new file mode 100644 index 0000000000..23382ea8bf --- /dev/null +++ b/sysdeps/i386/i686/memmove_chk.S @@ -0,0 +1,35 @@ +/* Checking memmove for x86-64. + Copyright (C) 2004 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 <sysdep.h> +#include "asm-syntax.h" + +#ifndef PIC + /* For libc.so this is defined in memmove.S. + For libc.a, this is a separate source to avoid + memmove bringing in __chk_fail and all routines + it calls. */ + .text +ENTRY (__memmove_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb __chk_fail + jmp memmove +END (__memmove_chk) +#endif diff --git a/sysdeps/i386/i686/mempcpy.S b/sysdeps/i386/i686/mempcpy.S index 3ea89d4a17..843a35823a 100644 --- a/sysdeps/i386/i686/mempcpy.S +++ b/sysdeps/i386/i686/mempcpy.S @@ -31,6 +31,13 @@ #define LEN SRC+PTR_SIZE .text +#if defined PIC && !defined NOT_IN_libc +ENTRY (__mempcpy_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb HIDDEN_JUMPTARGET (__chk_fail) +END (__mempcpy_chk) +#endif ENTRY (BP_SYM (__mempcpy)) ENTER diff --git a/sysdeps/i386/i686/mempcpy_chk.S b/sysdeps/i386/i686/mempcpy_chk.S new file mode 100644 index 0000000000..dc9c6095f0 --- /dev/null +++ b/sysdeps/i386/i686/mempcpy_chk.S @@ -0,0 +1,35 @@ +/* Checking mempcpy for x86-64. + Copyright (C) 2004 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 <sysdep.h> +#include "asm-syntax.h" + +#ifndef PIC + /* For libc.so this is defined in mempcpy.S. + For libc.a, this is a separate source to avoid + mempcpy bringing in __chk_fail and all routines + it calls. */ + .text +ENTRY (__mempcpy_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb __chk_fail + jmp mempcpy +END (__mempcpy_chk) +#endif diff --git a/sysdeps/i386/i686/memset.S b/sysdeps/i386/i686/memset.S index 4ddcb39731..561188ffec 100644 --- a/sysdeps/i386/i686/memset.S +++ b/sysdeps/i386/i686/memset.S @@ -39,6 +39,13 @@ #endif .text +#if defined PIC && !defined NOT_IN_libc && !BZERO_P +ENTRY (__memset_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb HIDDEN_JUMPTARGET (__chk_fail) +END (__memset_chk) +#endif ENTRY (BP_SYM (memset)) ENTER diff --git a/sysdeps/i386/i686/memset_chk.S b/sysdeps/i386/i686/memset_chk.S new file mode 100644 index 0000000000..d178654994 --- /dev/null +++ b/sysdeps/i386/i686/memset_chk.S @@ -0,0 +1,35 @@ +/* Checking memset for x86-64. + Copyright (C) 2004 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 <sysdep.h> +#include "asm-syntax.h" + +#ifndef PIC + /* For libc.so this is defined in memset.S. + For libc.a, this is a separate source to avoid + memset bringing in __chk_fail and all routines + it calls. */ + .text +ENTRY (__memset_chk) + movl 12(%esp), %eax + cmpl %eax, 16(%esp) + jb __chk_fail + jmp memset +END (__memset_chk) +#endif diff --git a/sysdeps/unix/sysv/linux/readonly-area.c b/sysdeps/unix/sysv/linux/readonly-area.c new file mode 100644 index 0000000000..ce5321bcef --- /dev/null +++ b/sysdeps/unix/sysv/linux/readonly-area.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2004 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 <stdint.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include "libio/libioP.h" + +/* Return 1 if the whole area PTR .. PTR+SIZE is not writable. + Return -1 if it is writable. */ + +int +__readonly_area (const char *ptr, size_t size) +{ + const void *ptr_end = ptr + size; + + FILE *fp = fopen ("/proc/self/maps", "rc"); + if (fp == NULL) + return -1; + + /* We need no locking. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + char *line = NULL; + size_t linelen = 0; + + while (! feof_unlocked (fp)) + { + if (_IO_getdelim (&line, &linelen, '\n', fp) <= 0) + break; + + char *p; + uintptr_t from = strtoul (line, &p, 16); + + if (p == line || *p++ != '-') + break; + + char *q; + uintptr_t to = strtoul (p, &q, 16); + + if (q == p || *q++ != ' ') + break; + + if (from < (uintptr_t) ptr_end && to > (uintptr_t) ptr) + { + /* Found an entry that at least partially covers the area. */ + if (*q++ != 'r' || *q++ != '-') + break; + + if (from <= (uintptr_t) ptr && to >= (uintptr_t) ptr_end) + { + size = 0; + break; + } + else if (from <= (uintptr_t) ptr) + size -= to - (uintptr_t) ptr; + else if (to >= (uintptr_t) ptr_end) + size -= (uintptr_t) ptr_end - from; + else + size -= to - from; + + if (!size) + break; + } + } + + fclose (fp); + free (line); + + /* If the whole area between ptr and ptr_end is covered by read-only + VMAs, return 1. Otherwise return -1. */ + return size == 0 ? 1 : -1; +} diff --git a/sysdeps/x86_64/memcpy.S b/sysdeps/x86_64/memcpy.S index de47688241..5f06198b5d 100644 --- a/sysdeps/x86_64/memcpy.S +++ b/sysdeps/x86_64/memcpy.S @@ -29,6 +29,12 @@ #define MEMPCPY_P (defined memcpy) .text +#if defined PIC && !defined NOT_IN_libc +ENTRY (__memcpy_chk) + cmpq %rdx, %rcx + jb HIDDEN_JUMPTARGET (__chk_fail) +END (__memcpy_chk) +#endif ENTRY (BP_SYM (memcpy)) /* Cutoff for the big loop is a size of 32 bytes since otherwise the loop will never be entered. */ diff --git a/sysdeps/x86_64/memcpy_chk.S b/sysdeps/x86_64/memcpy_chk.S new file mode 100644 index 0000000000..c5251ea2d4 --- /dev/null +++ b/sysdeps/x86_64/memcpy_chk.S @@ -0,0 +1,34 @@ +/* Checking memcpy for x86-64. + Copyright (C) 2004 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 <sysdep.h> +#include "asm-syntax.h" + +#ifndef PIC + /* For libc.so this is defined in memcpy.S. + For libc.a, this is a separate source to avoid + memcpy bringing in __chk_fail and all routines + it calls. */ + .text +ENTRY (__memcpy_chk) + cmpq %rdx, %rcx + jb __chk_fail + jmp memcpy +END (__memcpy_chk) +#endif diff --git a/sysdeps/x86_64/mempcpy.S b/sysdeps/x86_64/mempcpy.S index 03aa743fba..4558a1699a 100644 --- a/sysdeps/x86_64/mempcpy.S +++ b/sysdeps/x86_64/mempcpy.S @@ -1,4 +1,5 @@ #define memcpy __mempcpy +#define __memcpy_chk __mempcpy_chk #include <sysdeps/x86_64/memcpy.S> libc_hidden_def (BP_SYM (__mempcpy)) diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S new file mode 100644 index 0000000000..c333a4adb3 --- /dev/null +++ b/sysdeps/x86_64/mempcpy_chk.S @@ -0,0 +1,34 @@ +/* Checking mempcpy for x86-64. + Copyright (C) 2004 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 <sysdep.h> +#include "asm-syntax.h" + +#ifndef PIC + /* For libc.so this is defined in memcpy.S. + For libc.a, this is a separate source to avoid + mempcpy bringing in __chk_fail and all routines + it calls. */ + .text +ENTRY (__mempcpy_chk) + cmpq %rdx, %rcx + jb __chk_fail + jmp mempcpy +END (__mempcpy_chk) +#endif diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S index 29afa63e7e..6c47f4c863 100644 --- a/sysdeps/x86_64/memset.S +++ b/sysdeps/x86_64/memset.S @@ -1,6 +1,6 @@ /* memset/bzero -- set memory area to CH/0 Optimized version for x86-64. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Andreas Jaeger <aj@suse.de>. @@ -32,6 +32,12 @@ #define LARGE $120000 .text +#if !BZERO_P && defined PIC && !defined NOT_IN_libc +ENTRY (__memset_chk) + cmpq %rdx, %rcx + jb HIDDEN_JUMPTARGET (__chk_fail) +END (__memset_chk) +#endif ENTRY (memset) #if BZERO_P mov %rsi,%rdx /* Adjust parameter. */ diff --git a/sysdeps/x86_64/memset_chk.S b/sysdeps/x86_64/memset_chk.S new file mode 100644 index 0000000000..e62cb58cc0 --- /dev/null +++ b/sysdeps/x86_64/memset_chk.S @@ -0,0 +1,34 @@ +/* Checking memset for x86-64. + Copyright (C) 2004 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 <sysdep.h> +#include "asm-syntax.h" + +#ifndef PIC + /* For libc.so this is defined in memset.S. + For libc.a, this is a separate source to avoid + memset bringing in __chk_fail and all routines + it calls. */ + .text +ENTRY (__memset_chk) + cmpq %rdx, %rcx + jb __chk_fail + jmp memset +END (__memset_chk) +#endif diff --git a/sysdeps/x86_64/stpcpy_chk.S b/sysdeps/x86_64/stpcpy_chk.S new file mode 100644 index 0000000000..905e8d7ee3 --- /dev/null +++ b/sysdeps/x86_64/stpcpy_chk.S @@ -0,0 +1,3 @@ +#define USE_AS_STPCPY_CHK +#define STRCPY_CHK __stpcpy_chk +#include <sysdeps/x86_64/strcpy_chk.S> diff --git a/sysdeps/x86_64/strcpy_chk.S b/sysdeps/x86_64/strcpy_chk.S new file mode 100644 index 0000000000..364331553a --- /dev/null +++ b/sysdeps/x86_64/strcpy_chk.S @@ -0,0 +1,211 @@ +/* strcpy/stpcpy checking implementation for x86-64. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Jaeger <aj@suse.de>, 2002. + Adopted into checking version by Jakub Jelinek <jakub@redhat.com>. + + 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 <sysdep.h> +#include "asm-syntax.h" +#include "bp-sym.h" +#include "bp-asm.h" + +#ifndef USE_AS_STPCPY_CHK +# define STRCPY_CHK __strcpy_chk +#endif + + .text +ENTRY (STRCPY_CHK) + movq %rsi, %rcx /* Source register. */ + andl $7, %ecx /* mask alignment bits */ +#ifndef USE_AS_STPCPY_CHK + movq %rdi, %r10 /* Duplicate destination pointer. */ +#endif + jz 5f /* aligned => start loop */ + + cmpq $8, %rdx /* Check if only few bytes left in + destination. */ + jb 50f + + subq $8, %rcx /* We need to align to 8 bytes. */ + addq %rcx, %rdx /* Subtract count of stored bytes + in the cycle below from destlen. */ + + /* Search the first bytes directly. */ +0: + movb (%rsi), %al /* Fetch a byte */ + testb %al, %al /* Is it NUL? */ + movb %al, (%rdi) /* Store it */ + jz 4f /* If it was NUL, done! */ + incq %rsi + incq %rdi + incl %ecx + jnz 0b + +5: + movq $0xfefefefefefefeff,%r8 + cmpq $32, %rdx /* Are there enough bytes in destination + for the next unrolled round? */ + jb 60f /* If not, avoid the unrolled loop. */ + + /* Now the sources is aligned. Unfortunatly we cannot force + to have both source and destination aligned, so ignore the + alignment of the destination. */ + .p2align 4 +1: + /* 1st unroll. */ + movq (%rsi), %rax /* Read double word (8 bytes). */ + addq $8, %rsi /* Adjust pointer for next word. */ + movq %rax, %r9 /* Save a copy for NUL finding. */ + addq %r8, %r9 /* add the magic value to the word. We get + carry bits reported for each byte which + is *not* 0 */ + jnc 3f /* highest byte is NUL => return pointer */ + xorq %rax, %r9 /* (word+magic)^word */ + orq %r8, %r9 /* set all non-carry bits */ + incq %r9 /* add 1: if one carry bit was *not* set + the addition will not result in 0. */ + + jnz 3f /* found NUL => return pointer */ + + movq %rax, (%rdi) /* Write value to destination. */ + addq $8, %rdi /* Adjust pointer. */ + + /* 2nd unroll. */ + movq (%rsi), %rax /* Read double word (8 bytes). */ + addq $8, %rsi /* Adjust pointer for next word. */ + movq %rax, %r9 /* Save a copy for NUL finding. */ + addq %r8, %r9 /* add the magic value to the word. We get + carry bits reported for each byte which + is *not* 0 */ + jnc 3f /* highest byte is NUL => return pointer */ + xorq %rax, %r9 /* (word+magic)^word */ + orq %r8, %r9 /* set all non-carry bits */ + incq %r9 /* add 1: if one carry bit was *not* set + the addition will not result in 0. */ + + jnz 3f /* found NUL => return pointer */ + + movq %rax, (%rdi) /* Write value to destination. */ + addq $8, %rdi /* Adjust pointer. */ + + /* 3rd unroll. */ + movq (%rsi), %rax /* Read double word (8 bytes). */ + addq $8, %rsi /* Adjust pointer for next word. */ + movq %rax, %r9 /* Save a copy for NUL finding. */ + addq %r8, %r9 /* add the magic value to the word. We get + carry bits reported for each byte which + is *not* 0 */ + jnc 3f /* highest byte is NUL => return pointer */ + xorq %rax, %r9 /* (word+magic)^word */ + orq %r8, %r9 /* set all non-carry bits */ + incq %r9 /* add 1: if one carry bit was *not* set + the addition will not result in 0. */ + + jnz 3f /* found NUL => return pointer */ + + movq %rax, (%rdi) /* Write value to destination. */ + addq $8, %rdi /* Adjust pointer. */ + + /* 4th unroll. */ + movq (%rsi), %rax /* Read double word (8 bytes). */ + addq $8, %rsi /* Adjust pointer for next word. */ + movq %rax, %r9 /* Save a copy for NUL finding. */ + addq %r8, %r9 /* add the magic value to the word. We get + carry bits reported for each byte which + is *not* 0 */ + jnc 3f /* highest byte is NUL => return pointer */ + xorq %rax, %r9 /* (word+magic)^word */ + orq %r8, %r9 /* set all non-carry bits */ + incq %r9 /* add 1: if one carry bit was *not* set + the addition will not result in 0. */ + + jnz 3f /* found NUL => return pointer */ + + subq $32, %rdx /* Adjust destlen. */ + movq %rax, (%rdi) /* Write value to destination. */ + addq $8, %rdi /* Adjust pointer. */ + cmpq $32, %rdx /* Are there enough bytes in destination + for the next unrolled round? */ + jae 1b /* Next iteration. */ + +60: + cmpq $8, %rdx /* Are there enough bytes in destination + for the next unrolled round? */ + jb 50f /* Now, copy and check byte by byte. */ + + movq (%rsi), %rax /* Read double word (8 bytes). */ + addq $8, %rsi /* Adjust pointer for next word. */ + movq %rax, %r9 /* Save a copy for NUL finding. */ + addq %r8, %r9 /* add the magic value to the word. We get + carry bits reported for each byte which + is *not* 0 */ + jnc 3f /* highest byte is NUL => return pointer */ + xorq %rax, %r9 /* (word+magic)^word */ + orq %r8, %r9 /* set all non-carry bits */ + incq %r9 /* add 1: if one carry bit was *not* set + the addition will not result in 0. */ + + jnz 3f /* found NUL => return pointer */ + + subq $8, %rdx /* Adjust destlen. */ + movq %rax, (%rdi) /* Write value to destination. */ + addq $8, %rdi /* Adjust pointer. */ + jmp 60b /* Next iteration. */ + + /* Do the last few bytes. %rax contains the value to write. + The loop is unrolled twice. */ + .p2align 4 +3: + /* Note that stpcpy needs to return with the value of the NUL + byte. */ + movb %al, (%rdi) /* 1st byte. */ + testb %al, %al /* Is it NUL. */ + jz 4f /* yes, finish. */ + incq %rdi /* Increment destination. */ + movb %ah, (%rdi) /* 2nd byte. */ + testb %ah, %ah /* Is it NUL?. */ + jz 4f /* yes, finish. */ + incq %rdi /* Increment destination. */ + shrq $16, %rax /* Shift... */ + jmp 3b /* and look at next two bytes in %rax. */ + +51: + /* Search the bytes directly, checking for overflows. */ + incq %rsi + incq %rdi + decq %rdx + jz HIDDEN_JUMPTARGET (__chk_fail) +52: + movb (%rsi), %al /* Fetch a byte */ + testb %al, %al /* Is it NUL? */ + movb %al, (%rdi) /* Store it */ + jnz 51b /* If it was NUL, done! */ +4: +#ifdef USE_AS_STPCPY_CHK + movq %rdi, %rax /* Destination is return value. */ +#else + movq %r10, %rax /* Source is return value. */ +#endif + retq + +50: + testq %rdx, %rdx + jnz 52b + jmp HIDDEN_JUMPTARGET (__chk_fail) + +END (STRCPY_CHK) |