diff options
author | Zack Weinberg <zackw@panix.com> | 2018-03-07 14:32:03 -0500 |
---|---|---|
committer | Gabriel F. T. Gomes <gabriel@inconstante.eti.br> | 2018-12-05 18:15:43 -0200 |
commit | 4e2f43f842ef5e253cc23383645adbaa03cedb86 (patch) | |
tree | ca359423ba6ed4bb4d5ec247905a6ee13d456864 | |
parent | 124fc732c15ef37b7ee9db25b1e9f9b20c799623 (diff) | |
download | glibc-4e2f43f842ef5e253cc23383645adbaa03cedb86.tar.gz |
Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
The _chk variants of all of the printf functions become much simpler.
This is the last thing that we needed _IO_acquire_lock_clear_flags2
for, so it can go as well. I took the opportunity to make the headers
included and the names of all local variables consistent across all the
affected files.
Since we ultimately want to get rid of __no_long_double as well, it
must be possible to get all of the nontrivial effects of the _chk
functions by calling the _internal functions with appropriate flags.
For most of the __(v)xprintf_chk functions, this is covered by
PRINTF_FORTIFY plus some up-front argument checks that can be
duplicated. However, __(v)sprintf_chk installs a custom jump table so
that it can crash instead of overflowing the output buffer. This
functionality is moved to __vsprintf_internal, which now has a
'maxlen' argument like __vsnprintf_internal; to get the unsafe
behavior of ordinary (v)sprintf, pass -1 for that argument.
obstack_printf_chk and obstack_vprintf_chk are no longer in the same
file.
As a side-effect of the unification of both fortified and non-fortified
vdprintf initialization, this patch fixes bug 11319 for __dprintf_chk
and __vdprintf_chk, which was previously fixed only for dprintf and
vdprintf by the commit
commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Author: Ulrich Drepper <drepper@redhat.com>
Date: Wed Feb 24 16:07:57 2010 -0800
Fix reporting of I/O errors in *dprintf functions.
This patch adds a test case to avoid regressions.
Tested for powerpc and powerpc64le.
35 files changed, 413 insertions, 551 deletions
@@ -1,6 +1,95 @@ 2018-12-05 Zack Weinberg <zackw@panix.com> Gabriel F. T. Gomes <gabriel@inconstante.eti.br> + [BZ #11319] + * libio/iovsprintf.c (_IO_str_chk_overflow, libio_vtable): + Moved here from debug/vsprintf_chk.c. + (__vsprintf_internal): Add 'maxlen' argument. Change the setup + and completion logic for the strfile to match exactly what + __vsprintf_chk used to do, except, when maxlen is -1, pass -1 to + _IO_str_init_static_internal instead of maxlen-1. + (__vsprintf): Pass -1 as maxlen to __vsprintf_internal. + * stdio-common/sprintf.c (__sprintf): Pass -1 as maxlen to + __vsprintf_internal. + + * debug/vsprintf_chk.c (__vsprintf_chk) + * debug/sprintf_chk.c (__sprintf_chk): + Directly call __vsprintf_internal, passing PRINTF_FORTIFY if + 'flags' argument is positive, and slen as maxlen. No need to lock + the FILE and/or construct a temporary FILE. Minimize and normalize + header inclusions and variable names. Do not libc_hidden_def anything. + + * debug/asprintf_chk.c (__asprintf_chk) + * debug/dprintf_chk.c (__dprintf_chk) + * debug/fprintf_chk.c (__fprintf_chk) + * debug/fwprintf_chk.c (__fwprintf_chk) + * debug/printf_chk.c (__printf_chk) + * debug/snprintf_chk.c (__snprintf_chk) + * debug/swprintf_chk.c (__swprintf_chk) + * debug/vasprintf_chk.c (__vasprintf_chk) + * debug/vdprintf_chk.c (__vdprintf_chk) + * debug/vfprintf_chk.c (__vfprintf_chk) + * debug/vfwprintf_chk.c (__vfwprintf_chk) + * debug/vprintf_chk.c (__vprintf_chk) + * debug/vsnprintf_chk.c (__vsnprintf_chk) + * debug/vswprintf_chk.c (__vswprintf_chk) + * debug/vwprintf_chk.c (__vwprintf_chk) + * debug/wprintf_chk.c (__wprintf_chk): + Directly call the corresponding vxxprintf_internal function, passing + PRINTF_FORTIFY if 'flag' argument is positive. No need to lock + the FILE and/or construct a temporary FILE. Minimize and normalize + header inclusions and variable names. Do not libc_hidden_def anything. + + * debug/obprintf_chk.c (__obstack_printf_chk): Directly call + __obstack_vprintf_internal. + (__obstack_vprintf_chk): Convert into a wrapper that calls + __obstack_vprintf_internal (these two functions already had the + same code) and move to new file... + * debug/vobprintf_chk.c (__obstack_vprintf_chk): ... here. New + file. + * debug/obprintf.c (__obstack_vprintf_internal): Remove the checking of + the flags argument and the setting of _IO_FLAGS2_FORTIFY. + * debug/Makefile (routines): Add vobprintf_chk. + + * sysdeps/ieee754/ldbl-opt/nldbl-compat.c + (__nldbl___vsprintf): Pass -1 as maxlen to __vsprintf_internal. + (__nldbl___vfprintf_chk, __nldbl___vsnprintf_chk) + (__nldbl___vsprintf_chk, __nldbl___vswprintf_chk) + (__nldbl___vasprintf_chk, __nldbl___vdprintf_chk) + (__nldbl___obstack_vfprintf_chk): + Directly call the corresponding vxxprintf_internal function, + passing PRINTF_FORTIFY if 'flag' argument is positive. If necessary, + duplicate comparison of slen with 0 or maxlen from the corresponding + non-__nldbl function. + + * include/stdio.h (__vsnprintf_chk, __vfprintf_chk, __vasprintf_chk) + (__vdprintf_chk, __obstack_vfprintf_chk): Remove libc_hidden_proto. + * include/wchar.h (__vfwprintf_chk, __vswprintf_chk): + Remove libc_hidden_proto. + + * stdio-common/vfprintf-internal.c + (__vfprintf_internal, __vfwprintf_internal): + Do not check _IO_FLAGS2_FORTIFY. + * libio/libio.h (_IO_FLAGS2_FORTIFY): Remove. + * libio/libioP.h: Update prototype of __vsprintf_internal and add + a comment explaining why it has the maxlen argument. + (_IO_acquire_lock_clear_flags2_fct): Remove. + (_IO_acquire_lock_clear_flags2): Remove. + (_IO_release_lock): Remove conditional statement which will + now never execute. + (_IO_acquire_lock): Remove variable which is now unused. + * sysdeps/generic/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove. + * sysdeps/nptl/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove. + + * stdio-common/Makefile (tests): Add tst-bz11319 and + tst-bz11319-fortify2. + (CFLAGS-tst-bz11319-fortify2.c): New macro. + * stdio-common/tst-bz11319-fortify2.c: New file. + * stdio-common/tst-bz11319.c: Likewise. + +2018-12-05 Zack Weinberg <zackw@panix.com> + Gabriel F. T. Gomes <gabriel@inconstante.eti.br> + * misc/syslog.c: Include libioP.h, not iolibio.h. (__vsyslog_internal): New function with the former body of __vsyslog_chk; takes mode_flags argument same as diff --git a/debug/Makefile b/debug/Makefile index 506cebc3c4..2ef08cf23b 100644 --- a/debug/Makefile +++ b/debug/Makefile @@ -45,7 +45,7 @@ routines = backtrace backtracesyms backtracesymsfd noophooks \ gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \ wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \ wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \ - vdprintf_chk obprintf_chk \ + vdprintf_chk obprintf_chk vobprintf_chk \ longjmp_chk ____longjmp_chk \ fdelt_chk poll_chk ppoll_chk \ explicit_bzero_chk \ diff --git a/debug/asprintf_chk.c b/debug/asprintf_chk.c index 9cd4143f2e..eb885c35ca 100644 --- a/debug/asprintf_chk.c +++ b/debug/asprintf_chk.c @@ -15,22 +15,24 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <libioP.h> #include <stdarg.h> -#include <stdio.h> +#include <libio/libioP.h> /* Write formatted output from FORMAT to a string which is allocated with malloc and stored in *STRING_PTR. */ int -__asprintf_chk (char **result_ptr, int flags, const char *format, ...) +__asprintf_chk (char **result_ptr, int flag, const char *format, ...) { - va_list arg; - int done; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; + va_list ap; + int ret; - va_start (arg, format); - done = __vasprintf_chk (result_ptr, flags, format, arg); - va_end (arg); + va_start (ap, format); + ret = __vasprintf_internal (result_ptr, format, ap, mode); + va_end (ap); - return done; + return ret; } diff --git a/debug/dprintf_chk.c b/debug/dprintf_chk.c index df3867c61c..b5c62827c0 100644 --- a/debug/dprintf_chk.c +++ b/debug/dprintf_chk.c @@ -15,21 +15,23 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <libioP.h> #include <stdarg.h> -#include <stdio.h> +#include <libio/libioP.h> /* Write formatted output to D, according to the format string FORMAT. */ int -__dprintf_chk (int d, int flags, const char *format, ...) +__dprintf_chk (int d, int flag, const char *format, ...) { - va_list arg; - int done; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; + va_list ap; + int ret; - va_start (arg, format); - done = __vdprintf_chk (d, flags, format, arg); - va_end (arg); + va_start (ap, format); + ret = __vdprintf_internal (d, format, ap, mode); + va_end (ap); - return done; + return ret; } diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c index cff4438afb..14afc073b2 100644 --- a/debug/fprintf_chk.c +++ b/debug/fprintf_chk.c @@ -16,29 +16,23 @@ <http://www.gnu.org/licenses/>. */ #include <stdarg.h> -#include <stdio.h> -#include "../libio/libioP.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, ...) { + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; va_list ap; - int done; - - _IO_acquire_lock_clear_flags2 (fp); - if (flag > 0) - fp->_flags2 |= _IO_FLAGS2_FORTIFY; + int ret; va_start (ap, format); - done = vfprintf (fp, format, ap); + ret = __vfprintf_internal (fp, format, ap, mode); va_end (ap); - if (flag > 0) - fp->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (fp); - - return done; + return ret; } ldbl_strong_alias (___fprintf_chk, __fprintf_chk) diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c index 63167c1839..10d84ce98b 100644 --- a/debug/fwprintf_chk.c +++ b/debug/fwprintf_chk.c @@ -16,28 +16,22 @@ <http://www.gnu.org/licenses/>. */ #include <stdarg.h> -#include <wchar.h> -#include "../libio/libioP.h" +#include <libio/libioP.h> /* Write formatted output to FP from the format string FORMAT. */ int __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...) { + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; va_list ap; - int done; - - _IO_acquire_lock_clear_flags2 (fp); - if (flag > 0) - fp->_flags2 |= _IO_FLAGS2_FORTIFY; + int ret; va_start (ap, format); - done = __vfwprintf_internal (fp, format, ap, 0); + ret = __vfwprintf_internal (fp, format, ap, mode); va_end (ap); - if (flag > 0) - fp->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (fp); - - return done; + return ret; } diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c index 41dd481c34..c1a8f9e9a9 100644 --- a/debug/obprintf_chk.c +++ b/debug/obprintf_chk.c @@ -17,99 +17,23 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ - -#include <stdlib.h> -#include <libioP.h> -#include "../libio/strfile.h" -#include <assert.h> -#include <string.h> -#include <errno.h> -#include <obstack.h> +#include <libio/libioP.h> #include <stdarg.h> -#include <stdio_ext.h> - - -struct _IO_obstack_file -{ - struct _IO_FILE_plus file; - struct obstack *obstack; -}; - -extern const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden; - -int -__obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format, - va_list args) -{ - struct obstack_FILE - { - struct _IO_obstack_file ofile; - } new_f; - int result; - int size; - int room; - -#ifdef _IO_MTSAFE_IO - new_f.ofile.file.file._lock = NULL; -#endif - - _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps; - room = obstack_room (obstack); - size = obstack_object_size (obstack) + room; - if (size == 0) - { - /* We have to handle the allocation a bit different since the - `_IO_str_init_static' function would handle a size of zero - different from what we expect. */ - - /* Get more memory. */ - obstack_make_room (obstack, 64); - - /* Recompute how much room we have. */ - room = obstack_room (obstack); - size = room; - - assert (size != 0); - } - - _IO_str_init_static_internal ((struct _IO_strfile_ *) &new_f.ofile, - obstack_base (obstack), - size, obstack_next_free (obstack)); - /* Now allocate the rest of the current chunk. */ - assert (size == (new_f.ofile.file.file._IO_write_end - - new_f.ofile.file.file._IO_write_base)); - assert (new_f.ofile.file.file._IO_write_ptr - == (new_f.ofile.file.file._IO_write_base - + obstack_object_size (obstack))); - obstack_blank_fast (obstack, room); - - new_f.ofile.obstack = obstack; - - /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n - can only come from read-only format strings. */ - if (flags > 0) - new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY; - - result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0); - - /* Shrink the buffer to the space we really currently need. */ - obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr - - new_f.ofile.file.file._IO_write_end)); - - return result; -} -libc_hidden_def (__obstack_vprintf_chk) int -__obstack_printf_chk (struct obstack *obstack, int flags, const char *format, +__obstack_printf_chk (struct obstack *obstack, int flag, const char *format, ...) { - int result; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; va_list ap; + int ret; + va_start (ap, format); - result = __obstack_vprintf_chk (obstack, flags, format, ap); + ret = __obstack_vprintf_internal (obstack, format, ap, mode); va_end (ap); - return result; + + return ret; } diff --git a/debug/printf_chk.c b/debug/printf_chk.c index 426dc78386..e035b42590 100644 --- a/debug/printf_chk.c +++ b/debug/printf_chk.c @@ -16,29 +16,23 @@ <http://www.gnu.org/licenses/>. */ #include <stdarg.h> -#include <stdio.h> -#include "../libio/libioP.h" +#include <libio/libioP.h> /* Write formatted output to stdout from the format string FORMAT. */ int ___printf_chk (int flag, const char *format, ...) { + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; va_list ap; - int done; - - _IO_acquire_lock_clear_flags2 (stdout); - if (flag > 0) - stdout->_flags2 |= _IO_FLAGS2_FORTIFY; + int ret; va_start (ap, format); - done = vfprintf (stdout, format, ap); + ret = __vfprintf_internal (stdout, format, ap, mode); va_end (ap); - if (flag > 0) - stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (stdout); - - return done; + return ret; } ldbl_strong_alias (___printf_chk, __printf_chk) diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c index cddba37109..984b5e8932 100644 --- a/debug/snprintf_chk.c +++ b/debug/snprintf_chk.c @@ -15,25 +15,29 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <libioP.h> #include <stdarg.h> -#include <stdio.h> +#include <libio/libioP.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, +___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen, const char *format, ...) { - va_list arg; - int done; + if (__glibc_unlikely (slen < maxlen)) + __chk_fail (); - va_start (arg, format); - done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg); - va_end (arg); + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; + va_list ap; + int ret; - return done; + va_start (ap, format); + ret = __vsnprintf_internal (s, maxlen, format, ap, mode); + va_end (ap); + + return ret; } ldbl_strong_alias (___snprintf_chk, __snprintf_chk) diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c index 78214563dd..649e8ab4d5 100644 --- a/debug/sprintf_chk.c +++ b/debug/sprintf_chk.c @@ -15,22 +15,27 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <libioP.h> #include <stdarg.h> -#include <stdio.h> +#include <libio/libioP.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, ...) +___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...) { - va_list arg; - int done; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; + va_list ap; + int ret; + + if (slen == 0) + __chk_fail (); - va_start (arg, format); - done = __vsprintf_chk (s, flags, slen, format, arg); - va_end (arg); + va_start (ap, format); + ret = __vsprintf_internal (s, slen, format, ap, mode); + va_end (ap); - return done; + return ret; } ldbl_strong_alias (___sprintf_chk, __sprintf_chk) diff --git a/debug/swprintf_chk.c b/debug/swprintf_chk.c index 35887e48e2..186c17751c 100644 --- a/debug/swprintf_chk.c +++ b/debug/swprintf_chk.c @@ -16,20 +16,27 @@ <http://www.gnu.org/licenses/>. */ #include <stdarg.h> -#include <wchar.h> +#include <libio/libioP.h> -/* Write formatted output into S, according to the format string FORMAT. */ -/* VARARGS5 */ + +/* Write formatted output into S, according to the format string FORMAT, + writing no more than MAXLEN characters. */ int -__swprintf_chk (wchar_t *s, size_t n, int flag, size_t s_len, +__swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen, const wchar_t *format, ...) { - va_list arg; - int done; + if (__glibc_unlikely (slen < maxlen)) + __chk_fail (); + + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; + va_list ap; + int ret; - va_start (arg, format); - done = __vswprintf_chk (s, n, flag, s_len, format, arg); - va_end (arg); + va_start (ap, format); + ret = __vswprintf_internal (s, maxlen, format, ap, mode); + va_end (ap); - return done; + return ret; } diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c index dbfebff83f..f5975ea02a 100644 --- a/debug/vasprintf_chk.c +++ b/debug/vasprintf_chk.c @@ -24,72 +24,14 @@ This exception applies to code released by its copyright holders in files containing the exception. */ -#include <malloc.h> -#include <string.h> -#include <stdio.h> -#include <stdio_ext.h> -#include "../libio/libioP.h" -#include "../libio/strfile.h" +#include <libio/libioP.h> int -__vasprintf_chk (char **result_ptr, int flags, const char *format, - va_list args) +__vasprintf_chk (char **result_ptr, int flag, const char *format, va_list ap) { - /* Initial size of the buffer to be used. Will be doubled each time an - overflow occurs. */ - const size_t init_string_size = 100; - char *string; - _IO_strfile sf; - int ret; - size_t needed; - size_t allocated; - /* No need to clear the memory here (unlike for open_memstream) since - we know we will never seek on the stream. */ - string = (char *) malloc (init_string_size); - if (string == NULL) - return -1; -#ifdef _IO_MTSAFE_IO - sf._sbf._f._lock = NULL; -#endif - _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; - _IO_str_init_static_internal (&sf, string, init_string_size, string); - sf._sbf._f._flags &= ~_IO_USER_BUF; - sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; - sf._s._free_buffer_unused = (_IO_free_type) free; - - /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n can only come from read-only format strings. */ - if (flags > 0) - sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY; + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - ret = __vfprintf_internal (&sf._sbf._f, format, args, 0); - if (ret < 0) - { - free (sf._sbf._f._IO_buf_base); - return ret; - } - /* Only use realloc if the size we need is of the same (binary) - order of magnitude then the memory we allocated. */ - needed = sf._sbf._f._IO_write_ptr - sf._sbf._f._IO_write_base + 1; - allocated = sf._sbf._f._IO_write_end - sf._sbf._f._IO_write_base; - if ((allocated >> 1) <= needed) - *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed); - else - { - *result_ptr = (char *) malloc (needed); - if (*result_ptr != NULL) - { - memcpy (*result_ptr, sf._sbf._f._IO_buf_base, needed - 1); - free (sf._sbf._f._IO_buf_base); - } - else - /* We have no choice, use the buffer we already have. */ - *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed); - } - if (*result_ptr == NULL) - *result_ptr = sf._sbf._f._IO_buf_base; - (*result_ptr)[needed - 1] = '\0'; - return ret; + return __vasprintf_internal (result_ptr, format, ap, mode); } -libc_hidden_def (__vasprintf_chk) diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c index 4386127cfe..e04514e355 100644 --- a/debug/vdprintf_chk.c +++ b/debug/vdprintf_chk.c @@ -24,41 +24,14 @@ This exception applies to code released by its copyright holders in files containing the exception. */ -#include <libioP.h> -#include <stdio_ext.h> +#include <libio/libioP.h> int -__vdprintf_chk (int d, int flags, const char *format, va_list arg) +__vdprintf_chk (int d, int flag, const char *format, va_list ap) { - struct _IO_FILE_plus tmpfil; - struct _IO_wide_data wd; - int done; - -#ifdef _IO_MTSAFE_IO - tmpfil.file._lock = NULL; -#endif - _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps); - _IO_JUMPS (&tmpfil) = &_IO_file_jumps; - _IO_new_file_init_internal (&tmpfil); - if (_IO_file_attach (&tmpfil.file, d) == NULL) - { - _IO_un_link (&tmpfil); - return EOF; - } - tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE; - - _IO_mask_flags (&tmpfil.file, _IO_NO_READS, - _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); - - /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n can only come from read-only format strings. */ - if (flags > 0) - tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY; - - done = __vfprintf_internal (&tmpfil.file, format, arg, 0); - - _IO_FINISH (&tmpfil.file); + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - return done; + return __vdprintf_internal (d, format, ap, mode); } -libc_hidden_def (__vdprintf_chk) diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c index 5babbf611e..44426e14fd 100644 --- a/debug/vfprintf_chk.c +++ b/debug/vfprintf_chk.c @@ -15,28 +15,17 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <stdio.h> -#include "../libio/libioP.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; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - _IO_acquire_lock_clear_flags2 (fp); - if (flag > 0) - fp->_flags2 |= _IO_FLAGS2_FORTIFY; - - done = vfprintf (fp, format, ap); - - if (flag > 0) - fp->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (fp); - - return done; + return __vfprintf_internal (fp, format, ap, mode); } -ldbl_hidden_def (___vfprintf_chk, __vfprintf_chk) ldbl_strong_alias (___vfprintf_chk, __vfprintf_chk) diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c index abf2bd6517..3aed308156 100644 --- a/debug/vfwprintf_chk.c +++ b/debug/vfwprintf_chk.c @@ -15,27 +15,16 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <wchar.h> -#include "../libio/libioP.h" +#include <libio/libioP.h> /* Write formatted output to FP from the format string FORMAT. */ int __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap) { - int done; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - _IO_acquire_lock_clear_flags2 (fp); - if (flag > 0) - fp->_flags2 |= _IO_FLAGS2_FORTIFY; - - done = __vfwprintf_internal (fp, format, ap, 0); - - if (flag > 0) - fp->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (fp); - - return done; + return __vfwprintf_internal (fp, format, ap, mode); } -libc_hidden_def (__vfwprintf_chk) diff --git a/debug/vobprintf_chk.c b/debug/vobprintf_chk.c new file mode 100644 index 0000000000..bed2c98eac --- /dev/null +++ b/debug/vobprintf_chk.c @@ -0,0 +1,31 @@ +/* Print output of stream to given obstack. + Copyright (C) 2018 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, see + <http://www.gnu.org/licenses/>. */ + +#include <libio/libioP.h> + + +int +__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format, + va_list ap) +{ + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; + + return __obstack_vprintf_internal (obstack, format, ap, mode); +} diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c index b3b2c53df2..69fcb721ac 100644 --- a/debug/vprintf_chk.c +++ b/debug/vprintf_chk.c @@ -15,27 +15,17 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <stdio.h> -#include "../libio/libioP.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; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - _IO_acquire_lock_clear_flags2 (stdout); - if (flag > 0) - stdout->_flags2 |= _IO_FLAGS2_FORTIFY; - - done = vfprintf (stdout, format, ap); - - if (flag > 0) - stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (stdout); - - return done; + return __vfprintf_internal (stdout, format, ap, mode); } ldbl_strong_alias (___vprintf_chk, __vprintf_chk) diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c index 95d286f416..666a83b701 100644 --- a/debug/vsnprintf_chk.c +++ b/debug/vsnprintf_chk.c @@ -15,56 +15,22 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <stdio.h> -#include "../libio/libioP.h" -#include "../libio/strfile.h" +#include <libio/libioP.h> -extern const struct _IO_jump_t _IO_strn_jumps libio_vtable 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) +___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t slen, + const char *format, va_list ap) { - /* 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 (__glibc_unlikely (slen < maxlen)) __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 (&sf.f._sbf) = &_IO_strn_jumps; - s[0] = '\0'; - - /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + /* For flag > 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_FORTIFY; - - _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s); - ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0); + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf) - *sf.f._sbf._f._IO_write_ptr = '\0'; - return ret; + return __vsnprintf_internal (s, maxlen, format, ap, mode); } -ldbl_hidden_def (___vsnprintf_chk, __vsnprintf_chk) ldbl_strong_alias (___vsnprintf_chk, __vsnprintf_chk) diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c index 53f07236ae..c1b1a8da4f 100644 --- a/debug/vsprintf_chk.c +++ b/debug/vsprintf_chk.c @@ -15,75 +15,20 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <stdio.h> -#include "../libio/libioP.h" -#include "../libio/strfile.h" - - -static int _IO_str_chk_overflow (FILE *fp, int c) __THROW; - -static int -_IO_str_chk_overflow (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 libio_vtable = -{ - JUMP_INIT_DUMMY, - JUMP_INIT(finish, _IO_str_finish), - JUMP_INIT(overflow, _IO_str_chk_overflow), - JUMP_INIT(underflow, _IO_str_underflow), - JUMP_INIT(uflow, _IO_default_uflow), - JUMP_INIT(pbackfail, _IO_str_pbackfail), - JUMP_INIT(xsputn, _IO_default_xsputn), - JUMP_INIT(xsgetn, _IO_default_xsgetn), - JUMP_INIT(seekoff, _IO_str_seekoff), - JUMP_INIT(seekpos, _IO_default_seekpos), - JUMP_INIT(setbuf, _IO_default_setbuf), - JUMP_INIT(sync, _IO_default_sync), - JUMP_INIT(doallocate, _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) -}; - +#include <libio/libioP.h> int -___vsprintf_chk (char *s, int flags, size_t slen, const char *format, - va_list args) +___vsprintf_chk (char *s, int flag, size_t slen, const char *format, + va_list ap) { - _IO_strfile f; - int ret; -#ifdef _IO_MTSAFE_IO - f._sbf._f._lock = NULL; -#endif + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; if (slen == 0) __chk_fail (); - _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&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_FORTIFY; - - ret = __vfprintf_internal (&f._sbf._f, format, args, 0); - - *f._sbf._f._IO_write_ptr = '\0'; - return ret; + return __vsprintf_internal (s, slen, format, ap, mode); } ldbl_hidden_def (___vsprintf_chk, __vsprintf_chk) ldbl_strong_alias (___vsprintf_chk, __vsprintf_chk) diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c index 4d616f8835..2c6fadd463 100644 --- a/debug/vswprintf_chk.c +++ b/debug/vswprintf_chk.c @@ -15,60 +15,21 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <wchar.h> -#include "../libio/libioP.h" -#include "../libio/strfile.h" +#include <libio/libioP.h> /* Write formatted output into S, according to the format string FORMAT, writing no more than MAXLEN characters. */ -/* VARARGS5 */ int -__vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen, - const wchar_t *format, va_list args) +__vswprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen, + const wchar_t *format, va_list ap) { - /* 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 (__glibc_unlikely (slen < maxlen)) __chk_fail (); - _IO_wstrnfile sf; - struct _IO_wide_data wd; - 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 (__glibc_unlikely (maxlen == 0)) - /* Since we have to write at least the terminating L'\0' a buffer - length of zero always makes the function fail. */ - return -1; - - _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps); - _IO_fwide (&sf.f._sbf._f, 1); - s[0] = L'\0'; - - /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + /* For flag > 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_FORTIFY; - - _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s); - ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0); - - if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf) - /* ISO C99 requires swprintf/vswprintf to return an error if the - output does not fit int he provided buffer. */ - return -1; - - /* Terminate the string. */ - *sf.f._sbf._f._wide_data->_IO_write_ptr = '\0'; + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - return ret; + return __vswprintf_internal (s, maxlen, format, ap, mode); } -libc_hidden_def (__vswprintf_chk) diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c index fedc7a46bf..f1e8878a54 100644 --- a/debug/vwprintf_chk.c +++ b/debug/vwprintf_chk.c @@ -15,27 +15,16 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <stdio.h> -#include <wchar.h> -#include "../libio/libioP.h" +#include <libio/libioP.h> /* Write formatted output to stdout from the format string FORMAT. */ int __vwprintf_chk (int flag, const wchar_t *format, va_list ap) { - int done; + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; - _IO_acquire_lock_clear_flags2 (stdout); - if (flag > 0) - stdout->_flags2 |= _IO_FLAGS2_FORTIFY; - - done = __vfwprintf_internal (stdout, format, ap, 0); - - if (flag > 0) - stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (stdout); - - return done; + return __vfwprintf_internal (stdout, format, ap, mode); } diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c index 819050e5af..9f406e95f8 100644 --- a/debug/wprintf_chk.c +++ b/debug/wprintf_chk.c @@ -16,29 +16,22 @@ <http://www.gnu.org/licenses/>. */ #include <stdarg.h> -#include <stdio.h> -#include <wchar.h> -#include "../libio/libioP.h" +#include <libio/libioP.h> /* Write formatted output to stdout from the format string FORMAT. */ int __wprintf_chk (int flag, const wchar_t *format, ...) { + /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ + unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0; va_list ap; - int done; - - _IO_acquire_lock_clear_flags2 (stdout); - if (flag > 0) - stdout->_flags2 |= _IO_FLAGS2_FORTIFY; + int ret; va_start (ap, format); - done = __vfwprintf_internal (stdout, format, ap, 0); + ret = __vfwprintf_internal (stdout, format, ap, mode); va_end (ap); - if (flag > 0) - stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY; - _IO_release_lock (stdout); - - return done; + return ret; } diff --git a/include/stdio.h b/include/stdio.h index 0856d729d9..1b7da0f74d 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -216,11 +216,6 @@ libc_hidden_proto (__open_memstream) libc_hidden_proto (__libc_fatal) rtld_hidden_proto (__libc_fatal) libc_hidden_proto (__vsprintf_chk) -libc_hidden_proto (__vsnprintf_chk) -libc_hidden_proto (__vfprintf_chk) -libc_hidden_proto (__vasprintf_chk) -libc_hidden_proto (__vdprintf_chk) -libc_hidden_proto (__obstack_vprintf_chk) extern FILE * __fmemopen (void *buf, size_t len, const char *mode); libc_hidden_proto (__fmemopen) diff --git a/include/wchar.h b/include/wchar.h index d0fe45c3a6..86506d28e9 100644 --- a/include/wchar.h +++ b/include/wchar.h @@ -216,8 +216,6 @@ extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, const wchar_t *__restrict __format, __gnuc_va_list __arg) /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; -libc_hidden_proto (__vfwprintf_chk) -libc_hidden_proto (__vswprintf_chk) extern int __isoc99_fwscanf (__FILE *__restrict __stream, const wchar_t *__restrict __format, ...); diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c index 3b1e8292b5..08e4002625 100644 --- a/libio/iovsprintf.c +++ b/libio/iovsprintf.c @@ -27,8 +27,47 @@ #include "libioP.h" #include "strfile.h" +static int __THROW +_IO_str_chk_overflow (FILE *fp, int c) +{ + /* If we get here, the user-supplied buffer would be overrun by + further output. */ + __chk_fail (); +} + +static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable = +{ + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_str_finish), + JUMP_INIT(overflow, _IO_str_chk_overflow), + JUMP_INIT(underflow, _IO_str_underflow), + JUMP_INIT(uflow, _IO_default_uflow), + JUMP_INIT(pbackfail, _IO_str_pbackfail), + JUMP_INIT(xsputn, _IO_default_xsputn), + JUMP_INIT(xsgetn, _IO_default_xsgetn), + JUMP_INIT(seekoff, _IO_str_seekoff), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_default_setbuf), + JUMP_INIT(sync, _IO_default_sync), + JUMP_INIT(doallocate, _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) +}; + +/* This function is called by regular vsprintf with maxlen set to -1, + and by vsprintf_chk with maxlen set to the size of the output + string. In the former case, _IO_str_chk_overflow will never be + called; in the latter case it will crash the program if the buffer + overflows. */ + int -__vsprintf_internal (char *string, const char *format, va_list args, +__vsprintf_internal (char *string, size_t maxlen, + const char *format, va_list args, unsigned int mode_flags) { _IO_strfile sf; @@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args, sf._sbf._f._lock = NULL; #endif _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; - _IO_str_init_static_internal (&sf, string, -1, string); + _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps; + string[0] = '\0'; + _IO_str_init_static_internal (&sf, string, + (maxlen == -1) ? -1 : maxlen - 1, + string); + ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags); - _IO_putc_unlocked ('\0', &sf._sbf._f); + + *sf._sbf._f._IO_write_ptr = '\0'; return ret; } int __vsprintf (char *string, const char *format, va_list args) { - return __vsprintf_internal (string, format, args, 0); + return __vsprintf_internal (string, -1, format, args, 0); } ldbl_strong_alias (__vsprintf, _IO_vsprintf) diff --git a/libio/libio.h b/libio/libio.h index c188814ccc..3a93807efc 100644 --- a/libio/libio.h +++ b/libio/libio.h @@ -90,7 +90,6 @@ typedef union /* Bits for the _flags2 field. */ #define _IO_FLAGS2_MMAP 1 #define _IO_FLAGS2_NOTCANCEL 2 -#define _IO_FLAGS2_FORTIFY 4 #define _IO_FLAGS2_USER_WBUF 8 #define _IO_FLAGS2_NOCLOSE 32 #define _IO_FLAGS2_CLOEXEC 64 diff --git a/libio/libioP.h b/libio/libioP.h index fe52ef1752..ce5228e382 100644 --- a/libio/libioP.h +++ b/libio/libioP.h @@ -677,9 +677,16 @@ extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt, va_list ap, unsigned int mode_flags) attribute_hidden; -extern int __vsprintf_internal (char *string, const char *format, va_list ap, +/* Note: __vsprintf_internal, unlike vsprintf, does take a maxlen argument, + because it's called by both vsprintf and vsprintf_chk. If maxlen is + not set to -1, overrunning the buffer will cause a prompt crash. + This is the behavior of ordinary (v)sprintf functions, thus they call + __vsprintf_internal with that argument set to -1. */ +extern int __vsprintf_internal (char *string, size_t maxlen, + const char *format, va_list ap, unsigned int mode_flags) attribute_hidden; + extern int __vsnprintf_internal (char *string, size_t maxlen, const char *format, va_list ap, unsigned int mode_flags) @@ -818,26 +825,10 @@ _IO_acquire_lock_fct (FILE **p) _IO_funlockfile (fp); } -static inline void -__attribute__ ((__always_inline__)) -_IO_acquire_lock_clear_flags2_fct (FILE **p) -{ - FILE *fp = *p; - fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY); - if ((fp->_flags & _IO_USER_LOCK) == 0) - _IO_funlockfile (fp); -} - #if !defined _IO_MTSAFE_IO && IS_IN (libc) # define _IO_acquire_lock(_fp) \ - do { \ - FILE *_IO_acquire_lock_file = NULL -# define _IO_acquire_lock_clear_flags2(_fp) \ - do { \ - FILE *_IO_acquire_lock_file = (_fp) + do { # define _IO_release_lock(_fp) \ - if (_IO_acquire_lock_file != NULL) \ - _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY); \ } while (0) #endif diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 84bad1fafe..8978b3fb1f 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ tst-vfprintf-user-type \ tst-vfprintf-mbs-prec \ tst-scanf-round \ - tst-renameat2 \ + tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \ test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble @@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\" # tst-gets.c tests a deprecated function. CFLAGS-tst-gets.c += -Wno-deprecated-declarations +# BZ #11319 was first fixed for regular vdprintf, then reopened because +# the fortified version had the same bug. +CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2 + CPPFLAGS += $(libio-mtsafe) $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1 diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c index 77423b292f..447faa4e25 100644 --- a/stdio-common/sprintf.c +++ b/stdio-common/sprintf.c @@ -27,7 +27,7 @@ __sprintf (char *s, const char *format, ...) int done; va_start (arg, format); - done = __vsprintf_internal (s, format, arg, 0); + done = __vsprintf_internal (s, -1, format, arg, 0); va_end (arg); return done; diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c new file mode 100644 index 0000000000..a8df9a39bd --- /dev/null +++ b/stdio-common/tst-bz11319-fortify2.c @@ -0,0 +1 @@ +#include <tst-bz11319.c> diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c new file mode 100644 index 0000000000..f986c39a66 --- /dev/null +++ b/stdio-common/tst-bz11319.c @@ -0,0 +1,49 @@ +/* Regression test for bug 11319. + Copyright (C) 2018 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, see + <http://www.gnu.org/licenses/>. */ + +#define _GNU_SOURCE 1 + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <support/check.h> +#include <support/temp_file.h> +#include <support/xunistd.h> + +static int +do_test (void) +{ + char *tempfile; + int fd; + + /* Create a temporary file and open it in read-only mode. */ + TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile)); + fd = xopen (tempfile, O_RDONLY, 0660); + + /* Try and write to the temporary file to intentionally fail, then + check that dprintf (or __dprintf_chk) return EOF. */ + TEST_COMPARE (dprintf (fd, "%d", 0), EOF); + + xclose (fd); + free (tempfile); + + return 0; +} + +#include <support/test-driver.c> diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c index b0c86e99bd..4cc4261ead 100644 --- a/stdio-common/vfprintf-internal.c +++ b/stdio-common/vfprintf-internal.c @@ -1283,8 +1283,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) /* Temporarily honor environmental settings. */ if (__ldbl_is_dbl) mode_flags |= PRINTF_LDBL_IS_DBL; - if (s->_flags2 & _IO_FLAGS2_FORTIFY) - mode_flags |= PRINTF_FORTIFY; /* Orient the stream. */ #ifdef ORIENT diff --git a/sysdeps/generic/stdio-lock.h b/sysdeps/generic/stdio-lock.h index 4a40618545..25ccd07f29 100644 --- a/sysdeps/generic/stdio-lock.h +++ b/sysdeps/generic/stdio-lock.h @@ -54,15 +54,8 @@ __libc_lock_define_recursive (typedef, _IO_lock_t) __attribute__((cleanup (_IO_acquire_lock_fct))) \ = (_fp); \ _IO_flockfile (_IO_acquire_lock_file); -# define _IO_acquire_lock_clear_flags2(_fp) \ - do { \ - FILE *_IO_acquire_lock_file \ - __attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct))) \ - = (_fp); \ - _IO_flockfile (_IO_acquire_lock_file); # else # define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled -# define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp) # endif # define _IO_release_lock(_fp) ; } while (0) diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c index 958bbc1834..59b2c9fcdd 100644 --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c @@ -179,7 +179,7 @@ __nldbl___vsprintf (char *string, const char *fmt, va_list ap) { int done; __no_long_double = 1; - done = __vsprintf_internal (string, fmt, ap, 0); + done = __vsprintf_internal (string, -1, fmt, ap, 0); __no_long_double = 0; return done; } @@ -579,7 +579,7 @@ __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap) { int res; set_no_long_double (); - res = __vfprintf_chk (s, flag, fmt, ap); + res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0); clear_no_long_double (); return res; } @@ -591,7 +591,7 @@ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap) { int res; set_no_long_double (); - res = __vfwprintf_chk (s, flag, fmt, ap); + res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0); clear_no_long_double (); return res; } @@ -609,9 +609,13 @@ attribute_compat_text_section __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen, const char *fmt, va_list ap) { + if (__glibc_unlikely (slen < maxlen)) + __chk_fail (); + int res; __no_long_double = 1; - res = __vsnprintf_chk (string, maxlen, flag, slen, fmt, ap); + res = __vsnprintf_internal (string, maxlen, fmt, ap, + (flag > 0) ? PRINTF_FORTIFY : 0); __no_long_double = 0; return res; } @@ -622,9 +626,13 @@ attribute_compat_text_section __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt, va_list ap) { + if (slen == 0) + __chk_fail (); + int res; __no_long_double = 1; - res = __vsprintf_chk (string, flag, slen, fmt, ap); + res = __vsprintf_internal (string, slen, fmt, ap, + (flag > 0) ? PRINTF_FORTIFY : 0); __no_long_double = 0; return res; } @@ -635,9 +643,13 @@ attribute_compat_text_section __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen, const wchar_t *fmt, va_list ap) { + if (__glibc_unlikely (slen < maxlen)) + __chk_fail (); + int res; __no_long_double = 1; - res = __vswprintf_chk (string, maxlen, flag, slen, fmt, ap); + res = __vswprintf_internal (string, maxlen, fmt, ap, + (flag > 0) ? PRINTF_FORTIFY : 0); __no_long_double = 0; return res; } @@ -670,7 +682,8 @@ __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg) { int res; __no_long_double = 1; - res = __vasprintf_chk (ptr, flag, fmt, arg); + res = __vasprintf_internal (ptr, fmt, arg, + (flag > 0) ? PRINTF_FORTIFY : 0); __no_long_double = 0; return res; } @@ -696,7 +709,7 @@ __nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg) { int res; set_no_long_double (); - res = __vdprintf_chk (d, flag, fmt, arg); + res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0); clear_no_long_double (); return res; } @@ -723,7 +736,8 @@ __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag, { int res; __no_long_double = 1; - res = __obstack_vprintf_chk (obstack, flag, fmt, arg); + res = __obstack_vprintf_internal (obstack, fmt, arg, + (flag > 0) ? PRINTF_FORTIFY : 0); __no_long_double = 0; return res; } diff --git a/sysdeps/nptl/stdio-lock.h b/sysdeps/nptl/stdio-lock.h index 5b9782452f..1d6a81c5bf 100644 --- a/sysdeps/nptl/stdio-lock.h +++ b/sysdeps/nptl/stdio-lock.h @@ -94,15 +94,8 @@ typedef struct { int lock; int cnt; void *owner; } _IO_lock_t; __attribute__((cleanup (_IO_acquire_lock_fct))) \ = (_fp); \ _IO_flockfile (_IO_acquire_lock_file); -# define _IO_acquire_lock_clear_flags2(_fp) \ - do { \ - FILE *_IO_acquire_lock_file \ - __attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct))) \ - = (_fp); \ - _IO_flockfile (_IO_acquire_lock_file); # else # define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled -# define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp) # endif # define _IO_release_lock(_fp) ; } while (0) |