diff options
| -rw-r--r-- | ChangeLog | 74 | ||||
| -rw-r--r-- | Makerules | 3 | ||||
| -rw-r--r-- | debug/obprintf_chk.c | 2 | ||||
| -rw-r--r-- | debug/vdprintf_chk.c | 2 | ||||
| -rw-r--r-- | debug/vsnprintf_chk.c | 2 | ||||
| -rw-r--r-- | debug/vsprintf_chk.c | 2 | ||||
| -rw-r--r-- | libio/Makefile | 2 | ||||
| -rw-r--r-- | libio/fileops.c | 18 | ||||
| -rw-r--r-- | libio/genops.c | 10 | ||||
| -rw-r--r-- | libio/iofdopen.c | 12 | ||||
| -rw-r--r-- | libio/iofopen.c | 2 | ||||
| -rw-r--r-- | libio/iofopncook.c | 8 | ||||
| -rw-r--r-- | libio/iopopen.c | 6 | ||||
| -rw-r--r-- | libio/iovdprintf.c | 2 | ||||
| -rw-r--r-- | libio/libioP.h | 76 | ||||
| -rw-r--r-- | libio/memstream.c | 4 | ||||
| -rw-r--r-- | libio/obprintf.c | 2 | ||||
| -rw-r--r-- | libio/oldfileops.c | 12 | ||||
| -rw-r--r-- | libio/oldiofdopen.c | 2 | ||||
| -rw-r--r-- | libio/oldiofopen.c | 2 | ||||
| -rw-r--r-- | libio/oldiopopen.c | 4 | ||||
| -rw-r--r-- | libio/strops.c | 2 | ||||
| -rw-r--r-- | libio/vsnprintf.c | 2 | ||||
| -rw-r--r-- | libio/vswprintf.c | 2 | ||||
| -rw-r--r-- | libio/vtables.c | 70 | ||||
| -rw-r--r-- | libio/wfileops.c | 6 | ||||
| -rw-r--r-- | libio/wmemstream.c | 2 | ||||
| -rw-r--r-- | libio/wstrops.c | 2 | ||||
| -rw-r--r-- | stdio-common/vfprintf.c | 4 | ||||
| -rw-r--r-- | stdlib/strfmon_l.c | 2 |
30 files changed, 279 insertions, 60 deletions
@@ -1,5 +1,79 @@ 2016-06-23 Florian Weimer <fweimer@redhat.com> + [BZ #20191] + Implement vtable verification in libio. + * Makerules (shlib.lds): Place __libc_IO_vtables section. + * debug/obprintf_chk.c (_IO_obstack_jumps): Define as vtable. + * debug/vdprintf_chk.c (__vdprintf_chk): Call + _IO_new_file_init_internal instead of _IO_file_init. + * debug/vsnprintf_chk.c (_IO_strn_jumps): Define as vtable. + * debug/vsprintf_chk.c (_IO_str_chk_jumps): Likewise. + * libio/Makefile (routines): Add vtables. + * libio/libioP.h (_IO_JUMPS_FUNC): Call IO_validate_vtable. + (_IO_init): Remove, not for internal use. + (_IO_init_internal): Declare, internal replacement for _IO_init. + (_IO_file_init): Remove, not for internal use. + (_IO_new_file_init): Remove, not for internal use. + (_IO_new_file_init_internal): Declare, internal replacement for + _IO_new_file_init. + (_IO_old_file_init): Remove, not for internal use. + (_IO_old_file_init_internal): Declare, internal replacement for + _IO_old_file_init. + (_IO_str_init_static, _IO_str_init_readonly): Remove, not for + internal use. + (__libc_IO_vtables, IO_accept_foreign_vtables, _IO_vtable_check): + Declare. + (libio_vtable): New macro. + (IO_set_accept_foreign_vtables, _IO_validate_vtable): New inline + functions. + * libio/fileops.c (_IO_new_file_init_internal): Rename from + _IO_new_file_init. + (_IO_new_file_init): New externally visible wrapper which disables + vtable verification. + (_IO_file_jumps, _IO_file_jumps_mmap, _IO_file_jumps_maybe_mmap): + Define as vtables. + * libio/genops.c (_IO_init_internal): Rename from _IO_init. + (_IO_init): New externally visible wrapper which disables + vtable verification. + * libio/iofdopen.c (_IO_new_fdopen): Call + _IO_new_file_init_internal instead of _IO_file_init. Adjust + comment. + * libio/iofopen.c (__fopen_internal): Call + _IO_new_file_init_internal instead of _IO_file_init. + * libio/iofopncook.c (_IO_cookie_jumps, _IO_old_cookie_jumps): + Define as vtables. + (_IO_cookie_init): Call _IO_init_internal instead of _IO_init, + _IO_new_file_init_internal instead of _IO_file_init. + * libio/iopopen.c (_IO_new_popen): Likewise. + (_IO_proc_jumps): Define as vtable. + * libio/iovdprintf.c (_IO_vdprintf): Call + _IO_new_file_init_internal instead of _IO_file_init. + * libio/memstream.c (_IO_mem_jumps): Define as vtable. + (__open_memstream): Call _IO_init_internal instead of _IO_init. + * libio/obprintf.c (_IO_obstack_jumps): Define as vtable. + * libio/oldfileops.c (_IO_old_file_init_internal): Rename from + _IO_old_file_init. + (_IO_old_file_init): New externally visible wrapper which disables + vtable verification. + (_IO_old_file_jumps): Define as vtable. + * libio/oldiofdopen.c (_IO_old_fdopen): Call + _IO_old_file_init_internal instead of _IO_old_file_init. + * libio/oldiofopen.c (_IO_old_fopen): Likewise. + * libio/oldiopopen.c (_IO_old_popen): Likewise. + (_IO_old_proc_jumps): Define as vtable. + * libio/strops.c (_IO_str_jumps, _IO_strn_jumps, _IO_wstrn_jumps): + Define as vtables. + * libio/vtables.c: New file. + * libio/wfileops.c (_IO_wfile_jumps, _IO_wfile_jumps_mmap) + (_IO_wfile_jumps_maybe_mmap): Define as vtables. + * libio/wmemstream.c (_IO_wmem_jumps): Define as vtable. + * libio/wstrops.c (_IO_wstr_jumps): Likewise. + * stdio-common/vfprintf.c (_IO_helper_jumps): Likewise. + * stdlib/strfmon_l.c (__vstrfmon_l): Call _IO_init_internal + instead of _IO_init. + +2016-06-23 Florian Weimer <fweimer@redhat.com> + * test-skeleton.c (xrealloc): Support deallocation with n == 0. 2016-06-23 Florian Weimer <fweimer@redhat.com> @@ -562,6 +562,9 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules PROVIDE(__start___libc_thread_subfreeres = .);\ __libc_thread_subfreeres : { *(__libc_thread_subfreeres) }\ PROVIDE(__stop___libc_thread_subfreeres = .);\ + PROVIDE(__start___libc_IO_vtables = .);\ + __libc_IO_vtables : { *(__libc_IO_vtables) }\ + PROVIDE(__stop___libc_IO_vtables = .);\ /DISCARD/ : { *(.gnu.glibc-stub.*) }@' test -s $@T mv -f $@T $@ diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c index 8469b5f675..09655ba7a3 100644 --- a/debug/obprintf_chk.c +++ b/debug/obprintf_chk.c @@ -35,7 +35,7 @@ struct _IO_obstack_file struct obstack *obstack; }; -extern const struct _IO_jump_t _IO_obstack_jumps attribute_hidden; +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, diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c index 05d0bcd7e7..ce0ddb028c 100644 --- a/debug/vdprintf_chk.c +++ b/debug/vdprintf_chk.c @@ -39,7 +39,7 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg) #endif _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps); _IO_JUMPS (&tmpfil) = &_IO_file_jumps; - _IO_file_init (&tmpfil); + _IO_new_file_init_internal (&tmpfil); #if !_IO_UNIFIED_JUMPTABLES tmpfil.vtable = NULL; #endif diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c index cc559d2b1d..a6bb051234 100644 --- a/debug/vsnprintf_chk.c +++ b/debug/vsnprintf_chk.c @@ -20,7 +20,7 @@ #include "../libio/libioP.h" #include "../libio/strfile.h" -extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden; +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. */ diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c index aa1587ce6f..02e7372849 100644 --- a/debug/vsprintf_chk.c +++ b/debug/vsprintf_chk.c @@ -32,7 +32,7 @@ _IO_str_chk_overflow (_IO_FILE *fp, int c) } -static const struct _IO_jump_t _IO_str_chk_jumps = +static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_str_finish), diff --git a/libio/Makefile b/libio/Makefile index 4189bc4ad0..12589f2875 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -46,7 +46,7 @@ routines := \ __fbufsize __freading __fwriting __freadable __fwritable __flbf \ __fpurge __fpending __fsetlocking \ \ - libc_fatal fmemopen oldfmemopen + libc_fatal fmemopen oldfmemopen vtables tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \ diff --git a/libio/fileops.c b/libio/fileops.c index 8e83b1cd7b..1315735427 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -140,7 +140,7 @@ extern struct __gconv_trans_data __libio_translit attribute_hidden; void -_IO_new_file_init (struct _IO_FILE_plus *fp) +_IO_new_file_init_internal (struct _IO_FILE_plus *fp) { /* POSIX.1 allows another file handle to be used to change the position of our file descriptor. Hence we actually don't know the actual @@ -151,7 +151,15 @@ _IO_new_file_init (struct _IO_FILE_plus *fp) _IO_link_in (fp); fp->file._fileno = -1; } -libc_hidden_ver (_IO_new_file_init, _IO_file_init) + +/* External version of _IO_new_file_init_internal which switches off + vtable validation. */ +void +_IO_new_file_init (struct _IO_FILE_plus *fp) +{ + IO_set_accept_foreign_vtables (&_IO_vtable_check); + _IO_new_file_init_internal (fp); +} int _IO_new_file_close_it (_IO_FILE *fp) @@ -1534,7 +1542,7 @@ versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1); versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1); #endif -const struct _IO_jump_t _IO_file_jumps = +const struct _IO_jump_t _IO_file_jumps libio_vtable = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_file_finish), @@ -1559,7 +1567,7 @@ const struct _IO_jump_t _IO_file_jumps = }; libc_hidden_data_def (_IO_file_jumps) -const struct _IO_jump_t _IO_file_jumps_mmap = +const struct _IO_jump_t _IO_file_jumps_mmap libio_vtable = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_file_finish), @@ -1583,7 +1591,7 @@ const struct _IO_jump_t _IO_file_jumps_mmap = JUMP_INIT(imbue, _IO_default_imbue) }; -const struct _IO_jump_t _IO_file_jumps_maybe_mmap = +const struct _IO_jump_t _IO_file_jumps_maybe_mmap libio_vtable = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_file_finish), diff --git a/libio/genops.c b/libio/genops.c index 5803cbf04f..6234bf9046 100644 --- a/libio/genops.c +++ b/libio/genops.c @@ -558,11 +558,17 @@ _IO_default_doallocate (_IO_FILE *fp) libc_hidden_def (_IO_default_doallocate) void -_IO_init (_IO_FILE *fp, int flags) +_IO_init_internal (_IO_FILE *fp, int flags) { _IO_no_init (fp, flags, -1, NULL, NULL); } -libc_hidden_def (_IO_init) + +void +_IO_init (_IO_FILE *fp, int flags) +{ + IO_set_accept_foreign_vtables (&_IO_vtable_check); + _IO_init_internal (fp, flags); +} void _IO_old_init (_IO_FILE *fp, int flags) diff --git a/libio/iofdopen.c b/libio/iofdopen.c index e00f337521..a4b6757942 100644 --- a/libio/iofdopen.c +++ b/libio/iofdopen.c @@ -153,15 +153,15 @@ _IO_new_fdopen (int fd, const char *mode) (use_mmap && (read_write & _IO_NO_WRITES)) ? &_IO_file_jumps_maybe_mmap : #endif &_IO_file_jumps; - _IO_file_init (&new_f->fp); + _IO_new_file_init_internal (&new_f->fp); #if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL; #endif - /* We only need to record the fd because _IO_file_init will have unset the - offset. It is important to unset the cached offset because the real - offset in the file could change between now and when the handle is - activated and we would then mislead ftell into believing that we have a - valid offset. */ + /* We only need to record the fd because _IO_file_init_internal will + have unset the offset. It is important to unset the cached + offset because the real offset in the file could change between + now and when the handle is activated and we would then mislead + ftell into believing that we have a valid offset. */ new_f->fp.file._fileno = fd; new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE; diff --git a/libio/iofopen.c b/libio/iofopen.c index 13e3910b63..855fe2fae5 100644 --- a/libio/iofopen.c +++ b/libio/iofopen.c @@ -79,7 +79,7 @@ __fopen_internal (const char *filename, const char *mode, int is32) _IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL); #endif _IO_JUMPS (&new_f->fp) = &_IO_file_jumps; - _IO_file_init (&new_f->fp); + _IO_new_file_init_internal (&new_f->fp); #if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL; #endif diff --git a/libio/iofopncook.c b/libio/iofopncook.c index ceb444af7e..ae5df1707a 100644 --- a/libio/iofopncook.c +++ b/libio/iofopncook.c @@ -110,7 +110,7 @@ _IO_cookie_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode) } -static const struct _IO_jump_t _IO_cookie_jumps = { +static const struct _IO_jump_t _IO_cookie_jumps libio_vtable = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_file_finish), JUMP_INIT(overflow, _IO_file_overflow), @@ -151,13 +151,13 @@ void _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write, void *cookie, _IO_cookie_io_functions_t io_functions) { - _IO_init (&cfile->__fp.file, 0); + _IO_init_internal (&cfile->__fp.file, 0); _IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps; cfile->__cookie = cookie; set_callbacks (&cfile->__io_functions, io_functions); - _IO_file_init (&cfile->__fp); + _IO_new_file_init_internal (&cfile->__fp); _IO_mask_flags (&cfile->__fp.file, read_write, _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); @@ -238,7 +238,7 @@ _IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir) return (ret == -1) ? _IO_pos_BAD : ret; } -static const struct _IO_jump_t _IO_old_cookie_jumps = { +static const struct _IO_jump_t _IO_old_cookie_jumps libio_vtable = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_file_finish), JUMP_INIT(overflow, _IO_file_overflow), diff --git a/libio/iopopen.c b/libio/iopopen.c index 9ddde23494..d85370c01f 100644 --- a/libio/iopopen.c +++ b/libio/iopopen.c @@ -287,9 +287,9 @@ _IO_new_popen (const char *command, const char *mode) new_f->fpx.file.file._lock = &new_f->lock; #endif fp = &new_f->fpx.file.file; - _IO_init (fp, 0); + _IO_init_internal (fp, 0); _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps; - _IO_new_file_init (&new_f->fpx.file); + _IO_new_file_init_internal (&new_f->fpx.file); #if !_IO_UNIFIED_JUMPTABLES new_f->fpx.file.vtable = NULL; #endif @@ -344,7 +344,7 @@ _IO_new_proc_close (_IO_FILE *fp) return wstatus; } -static const struct _IO_jump_t _IO_proc_jumps = { +static const struct _IO_jump_t _IO_proc_jumps libio_vtable = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_new_file_finish), JUMP_INIT(overflow, _IO_new_file_overflow), diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c index 8ca55fccae..d279e34e87 100644 --- a/libio/iovdprintf.c +++ b/libio/iovdprintf.c @@ -39,7 +39,7 @@ _IO_vdprintf (int d, const char *format, _IO_va_list arg) #endif _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps); _IO_JUMPS (&tmpfil) = &_IO_file_jumps; - _IO_file_init (&tmpfil); + _IO_new_file_init_internal (&tmpfil); #if !_IO_UNIFIED_JUMPTABLES tmpfil.vtable = NULL; #endif diff --git a/libio/libioP.h b/libio/libioP.h index 8706af2d90..54dc35cdb6 100644 --- a/libio/libioP.h +++ b/libio/libioP.h @@ -125,11 +125,12 @@ extern "C" { #if _IO_JUMPS_OFFSET # define _IO_JUMPS_FUNC(THIS) \ - (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS) \ - + (THIS)->_vtable_offset)) + (IO_validate_vtable \ + (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS) \ + + (THIS)->_vtable_offset))) # define _IO_vtable_offset(THIS) (THIS)->_vtable_offset #else -# define _IO_JUMPS_FUNC(THIS) _IO_JUMPS_FILE_plus (THIS) +# define _IO_JUMPS_FUNC(THIS) (IO_validate_vtable (_IO_JUMPS_FILE_plus (THIS))) # define _IO_vtable_offset(THIS) 0 #endif #define _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS) @@ -378,8 +379,7 @@ extern void _IO_switch_to_main_get_area (_IO_FILE *) __THROW; extern void _IO_switch_to_backup_area (_IO_FILE *) __THROW; extern int _IO_switch_to_get_mode (_IO_FILE *); libc_hidden_proto (_IO_switch_to_get_mode) -extern void _IO_init (_IO_FILE *, int) __THROW; -libc_hidden_proto (_IO_init) +extern void _IO_init_internal (_IO_FILE *, int) attribute_hidden; extern int _IO_sputbackc (_IO_FILE *, int) __THROW; libc_hidden_proto (_IO_sputbackc) extern int _IO_sungetc (_IO_FILE *) __THROW; @@ -587,8 +587,6 @@ extern int _IO_file_underflow_maybe_mmap (_IO_FILE *); extern int _IO_file_overflow (_IO_FILE *, int); libc_hidden_proto (_IO_file_overflow) #define _IO_file_is_open(__fp) ((__fp)->_fileno != -1) -extern void _IO_file_init (struct _IO_FILE_plus *) __THROW; -libc_hidden_proto (_IO_file_init) extern _IO_FILE* _IO_file_attach (_IO_FILE *, int); libc_hidden_proto (_IO_file_attach) extern _IO_FILE* _IO_file_open (_IO_FILE *, const char *, int, int, int, int); @@ -614,7 +612,8 @@ extern _IO_FILE* _IO_new_file_fopen (_IO_FILE *, const char *, const char *, int); extern void _IO_no_init (_IO_FILE *, int, int, struct _IO_wide_data *, const struct _IO_jump_t *) __THROW; -extern void _IO_new_file_init (struct _IO_FILE_plus *) __THROW; +extern void _IO_new_file_init_internal (struct _IO_FILE_plus *) + __THROW attribute_hidden; extern _IO_FILE* _IO_new_file_setbuf (_IO_FILE *, char *, _IO_ssize_t); extern _IO_FILE* _IO_file_setbuf_mmap (_IO_FILE *, char *, _IO_ssize_t); extern int _IO_new_file_sync (_IO_FILE *); @@ -629,7 +628,8 @@ extern _IO_off64_t _IO_old_file_seekoff (_IO_FILE *, _IO_off64_t, int, int); extern _IO_size_t _IO_old_file_xsputn (_IO_FILE *, const void *, _IO_size_t); extern int _IO_old_file_underflow (_IO_FILE *); extern int _IO_old_file_overflow (_IO_FILE *, int); -extern void _IO_old_file_init (struct _IO_FILE_plus *) __THROW; +extern void _IO_old_file_init_internal (struct _IO_FILE_plus *) + __THROW attribute_hidden; extern _IO_FILE* _IO_old_file_attach (_IO_FILE *, int); extern _IO_FILE* _IO_old_file_fopen (_IO_FILE *, const char *, const char *); extern _IO_ssize_t _IO_old_file_write (_IO_FILE *, const void *, _IO_ssize_t); @@ -673,10 +673,6 @@ extern void _IO_str_finish (_IO_FILE *, int) __THROW; /* Other strfile functions */ struct _IO_strfile_; -extern void _IO_str_init_static (struct _IO_strfile_ *, char *, int, char *) - __THROW; -extern void _IO_str_init_readonly (struct _IO_strfile_ *, const char *, int) - __THROW; extern _IO_ssize_t _IO_str_count (_IO_FILE *) __THROW; /* And the wide character versions. */ @@ -890,3 +886,57 @@ _IO_acquire_lock_clear_flags2_fct (_IO_FILE **p) | _IO_FLAGS2_SCANF_STD); \ } while (0) #endif + +/* Collect all vtables in a special section for vtable verification. + These symbols cover the extent of this section. */ +symbol_set_declare (__libc_IO_vtables) + +/* libio vtables need to carry this attribute so that they pass + validation. */ +#define libio_vtable __attribute__ ((section ("__libc_IO_vtables"))) + +#ifdef SHARED +/* If equal to &_IO_vtable_check (with pointer guard protection), + unknown vtable pointers are valid. This function pointer is solely + used as a flag. */ +extern void (*IO_accept_foreign_vtables) (void |
