arrfab / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

Blame SOURCES/glibc-rh1398413.patch

147e83
commit db3476aff19b75c4fdefbe65fcd5f0a90588ba51
147e83
Author: Florian Weimer <fweimer@redhat.com>
147e83
Date:   Thu Jun 23 20:01:40 2016 +0200
147e83
147e83
    libio: Implement vtable verification [BZ #20191]
147e83
    
147e83
    This commit puts all libio vtables in a dedicated, read-only ELF
147e83
    section, so that they are consecutive in memory.  Before any indirect
147e83
    jump, the vtable pointer is checked against the section boundaries,
147e83
    and the process is terminated if the vtable pointer does not fall into
147e83
    the special ELF section.
147e83
    
147e83
    To enable backwards compatibility, a special flag variable
147e83
    (_IO_accept_foreign_vtables), protected by the pointer guard, avoids
147e83
    process termination if libio stream object constructor functions have
147e83
    been called earlier.  Such constructor functions are called by the GCC
147e83
    2.95 libstdc++ library, and this mechanism ensures compatibility with
147e83
    old binaries.  Existing callers inside glibc of these functions are
147e83
    adjusted to call the original functions, not the wrappers which enable
147e83
    vtable compatiblity.
147e83
    
147e83
    The compatibility mechanism is used to enable passing FILE * objects
147e83
    across a static dlopen boundary, too.
147e83
147e83
diff -rupN a/Makerules b/Makerules
147e83
--- a/Makerules	2017-08-24 14:50:27.000000000 -0400
147e83
+++ b/Makerules	2017-08-24 14:56:40.194819878 -0400
147e83
@@ -520,6 +520,9 @@ $(common-objpfx)shlib.lds: $(common-objp
147e83
 		 PROVIDE(__start___libc_thread_subfreeres = .);\
147e83
 		 __libc_thread_subfreeres : { *(__libc_thread_subfreeres) }\
147e83
 		 PROVIDE(__stop___libc_thread_subfreeres = .);\
147e83
+		 PROVIDE(__start___libc_IO_vtables = .);\
147e83
+		 __libc_IO_vtables : { *(__libc_IO_vtables) }\
147e83
+		 PROVIDE(__stop___libc_IO_vtables = .);\
147e83
 		 /DISCARD/ : { *(.gnu.glibc-stub.*) }@'
147e83
 	test -s $@T
147e83
 	mv -f $@T $@
147e83
diff -rupN a/debug/obprintf_chk.c b/debug/obprintf_chk.c
147e83
--- a/debug/obprintf_chk.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/debug/obprintf_chk.c	2017-08-24 14:56:40.194819878 -0400
147e83
@@ -35,7 +35,7 @@ struct _IO_obstack_file
147e83
   struct obstack *obstack;
147e83
 };
147e83
 
147e83
-extern const struct _IO_jump_t _IO_obstack_jumps attribute_hidden;
147e83
+extern const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden;
147e83
 
147e83
 int
147e83
 __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
147e83
diff -rupN a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
147e83
--- a/debug/vdprintf_chk.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/debug/vdprintf_chk.c	2017-08-24 14:56:40.194819878 -0400
147e83
@@ -39,7 +39,7 @@ __vdprintf_chk (int d, int flags, const
147e83
 #endif
147e83
   _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
147e83
   _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
147e83
-  _IO_file_init (&tmpfil);
147e83
+  _IO_new_file_init_internal (&tmpfil);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   tmpfil.vtable = NULL;
147e83
 #endif
147e83
diff -rupN a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
147e83
--- a/debug/vsnprintf_chk.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/debug/vsnprintf_chk.c	2017-08-24 14:56:40.194819878 -0400
147e83
@@ -20,7 +20,7 @@
147e83
 #include "../libio/libioP.h"
147e83
 #include "../libio/strfile.h"
147e83
 
147e83
-extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden;
147e83
+extern const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden;
147e83
 
147e83
 /* Write formatted output into S, according to the format
147e83
    string FORMAT, writing no more than MAXLEN characters.  */
147e83
diff -rupN a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
147e83
--- a/debug/vsprintf_chk.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/debug/vsprintf_chk.c	2017-08-24 14:56:40.194819878 -0400
147e83
@@ -34,7 +34,7 @@ _IO_str_chk_overflow (fp, c)
147e83
 }
147e83
 
147e83
 
147e83
-static const struct _IO_jump_t _IO_str_chk_jumps =
147e83
+static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_str_finish),
147e83
diff -rupN a/libio/Makefile b/libio/Makefile
147e83
--- a/libio/Makefile	2017-08-24 14:50:22.000000000 -0400
147e83
+++ b/libio/Makefile	2017-08-24 17:29:03.754025266 -0400
147e83
@@ -44,7 +44,7 @@ routines	:=							      \
147e83
 	__fbufsize __freading __fwriting __freadable __fwritable __flbf	      \
147e83
 	__fpurge __fpending __fsetlocking				      \
147e83
 									      \
147e83
-	libc_fatal fmemopen
147e83
+	libc_fatal fmemopen vtables
147e83
 
147e83
 include ../Makeconfig
147e83
 
147e83
diff -rupN a/libio/fileops.c b/libio/fileops.c
147e83
--- a/libio/fileops.c	2017-08-24 14:50:23.000000000 -0400
147e83
+++ b/libio/fileops.c	2017-08-24 14:57:57.765902179 -0400
147e83
@@ -139,7 +139,7 @@ extern struct __gconv_trans_data __libio
147e83
 
147e83
 
147e83
 void
147e83
-_IO_new_file_init (fp)
147e83
+_IO_new_file_init_internal (fp)
147e83
      struct _IO_FILE_plus *fp;
147e83
 {
147e83
   /* POSIX.1 allows another file handle to be used to change the position
147e83
@@ -151,7 +151,15 @@ _IO_new_file_init (fp)
147e83
   _IO_link_in (fp);
147e83
   fp->file._fileno = -1;
147e83
 }
147e83
-libc_hidden_ver (_IO_new_file_init, _IO_file_init)
147e83
+
147e83
+/* External version of _IO_new_file_init_internal which switches off
147e83
+   vtable validation.  */
147e83
+void
147e83
+_IO_new_file_init (struct _IO_FILE_plus *fp)
147e83
+{
147e83
+  IO_set_accept_foreign_vtables (&_IO_vtable_check);
147e83
+  _IO_new_file_init_internal (fp);
147e83
+}
147e83
 
147e83
 int
147e83
 _IO_new_file_close_it (fp)
147e83
@@ -1586,7 +1594,7 @@ versioned_symbol (libc, _IO_new_file_wri
147e83
 versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1);
147e83
 #endif
147e83
 
147e83
-const struct _IO_jump_t _IO_file_jumps =
147e83
+const struct _IO_jump_t _IO_file_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_file_finish),
147e83
@@ -1611,7 +1619,7 @@ const struct _IO_jump_t _IO_file_jumps =
147e83
 };
147e83
 libc_hidden_data_def (_IO_file_jumps)
147e83
 
147e83
-const struct _IO_jump_t _IO_file_jumps_mmap =
147e83
+const struct _IO_jump_t _IO_file_jumps_mmap libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_file_finish),
147e83
@@ -1635,7 +1643,7 @@ const struct _IO_jump_t _IO_file_jumps_m
147e83
   JUMP_INIT(imbue, _IO_default_imbue)
147e83
 };
147e83
 
147e83
-const struct _IO_jump_t _IO_file_jumps_maybe_mmap =
147e83
+const struct _IO_jump_t _IO_file_jumps_maybe_mmap libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_file_finish),
147e83
diff -rupN a/libio/genops.c b/libio/genops.c
147e83
--- a/libio/genops.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/genops.c	2017-08-24 15:44:28.757584527 -0400
147e83
@@ -595,13 +595,19 @@ _IO_default_doallocate (fp)
147e83
 libc_hidden_def (_IO_default_doallocate)
147e83
 
147e83
 void
147e83
-_IO_init (fp, flags)
147e83
+_IO_init_internal (fp, flags)
147e83
      _IO_FILE *fp;
147e83
      int flags;
147e83
 {
147e83
   _IO_no_init (fp, flags, -1, NULL, NULL);
147e83
 }
147e83
-libc_hidden_def (_IO_init)
147e83
+
147e83
+void
147e83
+_IO_init (_IO_FILE *fp, int flags)
147e83
+{
147e83
+  IO_set_accept_foreign_vtables (&_IO_vtable_check);
147e83
+  _IO_init_internal (fp, flags);
147e83
+}
147e83
 
147e83
 void
147e83
 _IO_old_init (fp, flags)
147e83
diff -rupN a/libio/iofdopen.c b/libio/iofdopen.c
147e83
--- a/libio/iofdopen.c	2017-08-24 14:50:21.000000000 -0400
147e83
+++ b/libio/iofdopen.c	2017-08-24 14:56:40.220819906 -0400
147e83
@@ -158,15 +158,15 @@ _IO_new_fdopen (fd, mode)
147e83
     (use_mmap && (read_write & _IO_NO_WRITES)) ? &_IO_file_jumps_maybe_mmap :
147e83
 #endif
147e83
       &_IO_file_jumps;
147e83
-  _IO_file_init (&new_f->fp);
147e83
+  _IO_new_file_init_internal (&new_f->fp);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   new_f->fp.vtable = NULL;
147e83
 #endif
147e83
-  /* We only need to record the fd because _IO_file_init will have unset the
147e83
-     offset.  It is important to unset the cached offset because the real
147e83
-     offset in the file could change between now and when the handle is
147e83
-     activated and we would then mislead ftell into believing that we have a
147e83
-     valid offset.  */
147e83
+  /* We only need to record the fd because _IO_file_init_internal will
147e83
+     have unset the offset.  It is important to unset the cached
147e83
+     offset because the real offset in the file could change between
147e83
+     now and when the handle is activated and we would then mislead
147e83
+     ftell into believing that we have a valid offset.  */
147e83
   new_f->fp.file._fileno = fd;
147e83
   new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE;
147e83
 
147e83
diff -rupN a/libio/iofopen.c b/libio/iofopen.c
147e83
--- a/libio/iofopen.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/iofopen.c	2017-08-24 14:56:40.223819909 -0400
147e83
@@ -83,7 +83,7 @@ __fopen_internal (filename, mode, is32)
147e83
   _IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL);
147e83
 #endif
147e83
   _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
147e83
-  _IO_file_init (&new_f->fp);
147e83
+  _IO_new_file_init_internal (&new_f->fp);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   new_f->fp.vtable = NULL;
147e83
 #endif
147e83
diff -rupN a/libio/iofopncook.c b/libio/iofopncook.c
147e83
--- a/libio/iofopncook.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/iofopncook.c	2017-08-24 15:46:49.061694225 -0400
147e83
@@ -116,7 +116,7 @@ _IO_cookie_seekoff (fp, offset, dir, mod
147e83
 }
147e83
 
147e83
 
147e83
-static const struct _IO_jump_t _IO_cookie_jumps = {
147e83
+static const struct _IO_jump_t _IO_cookie_jumps libio_vtable = {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_file_finish),
147e83
   JUMP_INIT(overflow, _IO_file_overflow),
147e83
@@ -144,13 +144,13 @@ void
147e83
 _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write,
147e83
 		 void *cookie, _IO_cookie_io_functions_t io_functions)
147e83
 {
147e83
-  _IO_init (&cfile->__fp.file, 0);
147e83
+  _IO_init_internal (&cfile->__fp.file, 0);
147e83
   _IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps;
147e83
 
147e83
   cfile->__cookie = cookie;
147e83
   cfile->__io_functions = io_functions;
147e83
 
147e83
-  _IO_file_init (&cfile->__fp);
147e83
+  _IO_new_file_init_internal (&cfile->__fp);
147e83
 
147e83
   _IO_mask_flags (&cfile->__fp.file, read_write,
147e83
 		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
147e83
@@ -235,7 +235,7 @@ _IO_old_cookie_seek (fp, offset, dir)
147e83
   return (ret == -1) ? _IO_pos_BAD : ret;
147e83
 }
147e83
 
147e83
-static const struct _IO_jump_t _IO_old_cookie_jumps = {
147e83
+static const struct _IO_jump_t _IO_old_cookie_jumps libio_vtable = {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_file_finish),
147e83
   JUMP_INIT(overflow, _IO_file_overflow),
147e83
diff -rupN a/libio/iopopen.c b/libio/iopopen.c
147e83
--- a/libio/iopopen.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/iopopen.c	2017-08-24 14:56:40.234819921 -0400
147e83
@@ -292,9 +292,9 @@ _IO_new_popen (command, mode)
147e83
   new_f->fpx.file.file._lock = &new_f->lock;
147e83
 #endif
147e83
   fp = &new_f->fpx.file.file;
147e83
-  _IO_init (fp, 0);
147e83
+  _IO_init_internal (fp, 0);
147e83
   _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps;
147e83
-  _IO_new_file_init (&new_f->fpx.file);
147e83
+  _IO_new_file_init_internal (&new_f->fpx.file);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   new_f->fpx.file.vtable = NULL;
147e83
 #endif
147e83
@@ -350,7 +350,7 @@ _IO_new_proc_close (fp)
147e83
   return wstatus;
147e83
 }
147e83
 
147e83
-static const struct _IO_jump_t _IO_proc_jumps = {
147e83
+static const struct _IO_jump_t _IO_proc_jumps libio_vtable = {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_new_file_finish),
147e83
   JUMP_INIT(overflow, _IO_new_file_overflow),
147e83
diff -rupN a/libio/iovdprintf.c b/libio/iovdprintf.c
147e83
--- a/libio/iovdprintf.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/iovdprintf.c	2017-08-24 14:56:40.237819924 -0400
147e83
@@ -42,7 +42,7 @@ _IO_vdprintf (d, format, arg)
147e83
 #endif
147e83
   _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
147e83
   _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
147e83
-  _IO_file_init (&tmpfil);
147e83
+  _IO_new_file_init_internal (&tmpfil);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   tmpfil.vtable = NULL;
147e83
 #endif
147e83
diff -rupN a/libio/libioP.h b/libio/libioP.h
147e83
--- a/libio/libioP.h	2017-08-24 14:50:26.000000000 -0400
147e83
+++ b/libio/libioP.h	2017-08-24 17:26:39.918165252 -0400
147e83
@@ -108,11 +108,12 @@ extern "C" {
147e83
 
147e83
 #if _IO_JUMPS_OFFSET
147e83
 # define _IO_JUMPS_FUNC(THIS) \
147e83
- (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS ((struct _IO_FILE_plus *) (THIS)) \
147e83
-			   + (THIS)->_vtable_offset))
147e83
+  (IO_validate_vtable                                                   \
147e83
+   (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS ((struct _IO_FILE_plus *) (THIS)) \
147e83
+			     + (THIS)->_vtable_offset)))
147e83
 # define _IO_vtable_offset(THIS) (THIS)->_vtable_offset
147e83
 #else
147e83
-# define _IO_JUMPS_FUNC(THIS) _IO_JUMPS ((struct _IO_FILE_plus *) (THIS))
147e83
+# define _IO_JUMPS_FUNC(THIS) (IO_validate_vtable (_IO_JUMPS ((struct _IO_FILE_plus *) (THIS))))
147e83
 # define _IO_vtable_offset(THIS) 0
147e83
 #endif
147e83
 #define _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS)
147e83
@@ -361,8 +362,7 @@ extern void _IO_switch_to_main_get_area
147e83
 extern void _IO_switch_to_backup_area (_IO_FILE *) __THROW;
147e83
 extern int _IO_switch_to_get_mode (_IO_FILE *);
147e83
 libc_hidden_proto (_IO_switch_to_get_mode)
147e83
-extern void _IO_init (_IO_FILE *, int) __THROW;
147e83
-libc_hidden_proto (_IO_init)
147e83
+extern void _IO_init_internal (_IO_FILE *, int) attribute_hidden;
147e83
 extern int _IO_sputbackc (_IO_FILE *, int) __THROW;
147e83
 libc_hidden_proto (_IO_sputbackc)
147e83
 extern int _IO_sungetc (_IO_FILE *) __THROW;
147e83
@@ -570,8 +570,6 @@ extern int _IO_file_underflow_maybe_mmap
147e83
 extern int _IO_file_overflow (_IO_FILE *, int);
147e83
 libc_hidden_proto (_IO_file_overflow)
147e83
 #define _IO_file_is_open(__fp) ((__fp)->_fileno != -1)
147e83
-extern void _IO_file_init (struct _IO_FILE_plus *) __THROW;
147e83
-libc_hidden_proto (_IO_file_init)
147e83
 extern _IO_FILE* _IO_file_attach (_IO_FILE *, int);
147e83
 libc_hidden_proto (_IO_file_attach)
147e83
 extern _IO_FILE* _IO_file_open (_IO_FILE *, const char *, int, int, int, int);
147e83
@@ -597,7 +595,8 @@ extern _IO_FILE* _IO_new_file_fopen (_IO
147e83
 				     int);
147e83
 extern void _IO_no_init (_IO_FILE *, int, int, struct _IO_wide_data *,
147e83
 			 const struct _IO_jump_t *) __THROW;
147e83
-extern void _IO_new_file_init (struct _IO_FILE_plus *) __THROW;
147e83
+extern void _IO_new_file_init_internal (struct _IO_FILE_plus *)
147e83
+  __THROW attribute_hidden;
147e83
 extern _IO_FILE* _IO_new_file_setbuf (_IO_FILE *, char *, _IO_ssize_t);
147e83
 extern _IO_FILE* _IO_file_setbuf_mmap (_IO_FILE *, char *, _IO_ssize_t);
147e83
 extern int _IO_new_file_sync (_IO_FILE *);
147e83
@@ -612,7 +611,8 @@ extern _IO_off64_t _IO_old_file_seekoff
147e83
 extern _IO_size_t _IO_old_file_xsputn (_IO_FILE *, const void *, _IO_size_t);
147e83
 extern int _IO_old_file_underflow (_IO_FILE *);
147e83
 extern int _IO_old_file_overflow (_IO_FILE *, int);
147e83
-extern void _IO_old_file_init (struct _IO_FILE_plus *) __THROW;
147e83
+extern void _IO_old_file_init_internal (struct _IO_FILE_plus *)
147e83
+  __THROW attribute_hidden;
147e83
 extern _IO_FILE* _IO_old_file_attach (_IO_FILE *, int);
147e83
 extern _IO_FILE* _IO_old_file_fopen (_IO_FILE *, const char *, const char *);
147e83
 extern _IO_ssize_t _IO_old_file_write (_IO_FILE *, const void *, _IO_ssize_t);
147e83
@@ -656,10 +656,6 @@ extern void _IO_str_finish (_IO_FILE *,
147e83
 
147e83
 /* Other strfile functions */
147e83
 struct _IO_strfile_;
147e83
-extern void _IO_str_init_static (struct _IO_strfile_ *, char *, int, char *)
147e83
-     __THROW;
147e83
-extern void _IO_str_init_readonly (struct _IO_strfile_ *, const char *, int)
147e83
-     __THROW;
147e83
 extern _IO_ssize_t _IO_str_count (_IO_FILE *) __THROW;
147e83
 
147e83
 /* And the wide character versions.  */
147e83
@@ -913,3 +909,57 @@ _IO_acquire_lock_clear_flags2_fct (_IO_F
147e83
                                           | _IO_FLAGS2_SCANF_STD);	      \
147e83
   } while (0)
147e83
 #endif
147e83
+
147e83
+/* Collect all vtables in a special section for vtable verification.
147e83
+   These symbols cover the extent of this section.  */
147e83
+symbol_set_declare (__libc_IO_vtables)
147e83
+
147e83
+/* libio vtables need to carry this attribute so that they pass
147e83
+   validation.  */
147e83
+#define libio_vtable __attribute__ ((section ("__libc_IO_vtables")))
147e83
+
147e83
+#ifdef SHARED
147e83
+/* If equal to &_IO_vtable_check (with pointer guard protection),
147e83
+   unknown vtable pointers are valid.  This function pointer is solely
147e83
+   used as a flag.  */
147e83
+extern void (*IO_accept_foreign_vtables) (void) attribute_hidden;
147e83
+
147e83
+/* Assigns the passed function pointer (either NULL or
147e83
+   &_IO_vtable_check) to IO_accept_foreign_vtables.  */
147e83
+static inline void
147e83
+IO_set_accept_foreign_vtables (void (*flag) (void))
147e83
+{
147e83
+  PTR_MANGLE (flag);
147e83
+  atomic_store_relaxed (&IO_accept_foreign_vtables, flag);
147e83
+}
147e83
+
147e83
+#else  /* !SHARED */
147e83
+
147e83
+/* The statically-linked version does nothing. */
147e83
+static inline void
147e83
+IO_set_accept_foreign_vtables (void (*flag) (void))
147e83
+{
147e83
+}
147e83
+
147e83
+#endif
147e83
+
147e83
+/* Check if unknown vtable pointers are permitted; otherwise,
147e83
+   terminate the process.  */
147e83
+void _IO_vtable_check (void) attribute_hidden;
147e83
+
147e83
+/* Perform vtable pointer validation.  If validation fails, terminate
147e83
+   the process.  */
147e83
+static inline const struct _IO_jump_t *
147e83
+IO_validate_vtable (const struct _IO_jump_t *vtable)
147e83
+{
147e83
+  /* Fast path: The vtable pointer is within the __libc_IO_vtables
147e83
+     section.  */
147e83
+  uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
147e83
+  const char *ptr = (const char *) vtable;
147e83
+  uintptr_t offset = ptr - __start___libc_IO_vtables;
147e83
+  if (__glibc_unlikely (offset >= section_length))
147e83
+    /* The vtable pointer is not in the expected section.  Use the
147e83
+       slow path, which will terminate the process if necessary.  */
147e83
+    _IO_vtable_check ();
147e83
+  return vtable;
147e83
+}
147e83
diff -rupN a/libio/memstream.c b/libio/memstream.c
147e83
--- a/libio/memstream.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/memstream.c	2017-08-24 15:56:02.643120827 -0400
147e83
@@ -33,7 +33,7 @@ static int _IO_mem_sync (_IO_FILE* fp) _
147e83
 static void _IO_mem_finish (_IO_FILE* fp, int) __THROW;
147e83
 
147e83
 
147e83
-static const struct _IO_jump_t _IO_mem_jumps =
147e83
+static const struct _IO_jump_t _IO_mem_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT (finish, _IO_mem_finish),
147e83
@@ -85,7 +85,7 @@ open_memstream (bufloc, sizeloc)
147e83
   buf = calloc (1, _IO_BUFSIZ);
147e83
   if (buf == NULL)
147e83
     return NULL;
147e83
-  _IO_init (&new_f->fp._sf._sbf._f, 0);
147e83
+  _IO_init_internal (&new_f->fp._sf._sbf._f, 0);
147e83
   _IO_JUMPS ((struct _IO_FILE_plus *) &new_f->fp._sf._sbf) = &_IO_mem_jumps;
147e83
   _IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf);
147e83
   new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF;
147e83
diff -rupN a/libio/obprintf.c b/libio/obprintf.c
147e83
--- a/libio/obprintf.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/obprintf.c	2017-08-24 14:56:40.255819944 -0400
147e83
@@ -91,7 +91,7 @@ _IO_obstack_xsputn (_IO_FILE *fp, const
147e83
 
147e83
 
147e83
 /* the jump table.  */
147e83
-const struct _IO_jump_t _IO_obstack_jumps attribute_hidden =
147e83
+const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, NULL),
147e83
diff -rupN a/libio/oldfileops.c b/libio/oldfileops.c
147e83
--- a/libio/oldfileops.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/oldfileops.c	2017-08-24 15:56:27.333139635 -0400
147e83
@@ -113,7 +113,7 @@ extern int errno;
147e83
 
147e83
 void
147e83
 attribute_compat_text_section
147e83
-_IO_old_file_init (fp)
147e83
+_IO_old_file_init_internal (fp)
147e83
      struct _IO_FILE_plus *fp;
147e83
 {
147e83
   /* POSIX.1 allows another file handle to be used to change the position
147e83
@@ -138,6 +138,14 @@ _IO_old_file_init (fp)
147e83
 #endif
147e83
 }
147e83
 
147e83
+void
147e83
+attribute_compat_text_section
147e83
+_IO_old_file_init (struct _IO_FILE_plus *fp)
147e83
+{
147e83
+  IO_set_accept_foreign_vtables (&_IO_vtable_check);
147e83
+  _IO_old_file_init_internal (fp);
147e83
+}
147e83
+
147e83
 int
147e83
 attribute_compat_text_section
147e83
 _IO_old_file_close_it (fp)
147e83
@@ -776,7 +784,7 @@ _IO_old_file_xsputn (f, data, n)
147e83
 }
147e83
 
147e83
 
147e83
-const struct _IO_jump_t _IO_old_file_jumps =
147e83
+const struct _IO_jump_t _IO_old_file_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_old_file_finish),
147e83
diff -rupN a/libio/oldiofdopen.c b/libio/oldiofdopen.c
147e83
--- a/libio/oldiofdopen.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/oldiofdopen.c	2017-08-24 15:57:15.823176524 -0400
147e83
@@ -114,7 +114,7 @@ _IO_old_fdopen (fd, mode)
147e83
 #endif
147e83
   _IO_old_init (&new_f->fp.file._file, 0);
147e83
   _IO_JUMPS ((struct _IO_FILE_plus *) &new_f->fp) = &_IO_old_file_jumps;
147e83
-  _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
147e83
+  _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fp);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   new_f->fp.vtable = NULL;
147e83
 #endif
147e83
diff -rupN a/libio/oldiofopen.c b/libio/oldiofopen.c
147e83
--- a/libio/oldiofopen.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/oldiofopen.c	2017-08-24 15:58:13.978220676 -0400
147e83
@@ -53,7 +53,7 @@ _IO_old_fopen (filename, mode)
147e83
 #endif
147e83
   _IO_old_init (&new_f->fp.file._file, 0);
147e83
   _IO_JUMPS ((struct _IO_FILE_plus *) &new_f->fp) = &_IO_old_file_jumps;
147e83
-  _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
147e83
+  _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fp);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   new_f->fp.vtable = NULL;
147e83
 #endif
147e83
diff -rupN a/libio/oldiopopen.c b/libio/oldiopopen.c
147e83
--- a/libio/oldiopopen.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/oldiopopen.c	2017-08-24 15:58:32.060234383 -0400
147e83
@@ -216,7 +216,7 @@ _IO_old_popen (command, mode)
147e83
   fp = &new_f->fpx.file.file._file;
147e83
   _IO_old_init (fp, 0);
147e83
   _IO_JUMPS ((struct _IO_FILE_plus *) &new_f->fpx.file) = &_IO_old_proc_jumps;
147e83
-  _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fpx.file);
147e83
+  _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fpx.file);
147e83
 #if  !_IO_UNIFIED_JUMPTABLES
147e83
   new_f->fpx.file.vtable = NULL;
147e83
 #endif
147e83
@@ -273,7 +273,7 @@ _IO_old_proc_close (fp)
147e83
   return wstatus;
147e83
 }
147e83
 
147e83
-const struct _IO_jump_t _IO_old_proc_jumps = {
147e83
+const struct _IO_jump_t _IO_old_proc_jumps libio_vtable = {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_old_file_finish),
147e83
   JUMP_INIT(overflow, _IO_old_file_overflow),
147e83
diff -rupN a/libio/strops.c b/libio/strops.c
147e83
--- a/libio/strops.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/strops.c	2017-08-24 14:56:40.289819980 -0400
147e83
@@ -345,7 +345,7 @@ _IO_str_finish (fp, dummy)
147e83
   _IO_default_finish (fp, 0);
147e83
 }
147e83
 
147e83
-const struct _IO_jump_t _IO_str_jumps =
147e83
+const struct _IO_jump_t _IO_str_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_str_finish),
147e83
diff -rupN a/libio/vsnprintf.c b/libio/vsnprintf.c
147e83
--- a/libio/vsnprintf.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/vsnprintf.c	2017-08-24 14:56:40.292819983 -0400
147e83
@@ -66,7 +66,7 @@ _IO_strn_overflow (fp, c)
147e83
 }
147e83
 
147e83
 
147e83
-const struct _IO_jump_t _IO_strn_jumps attribute_hidden =
147e83
+const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_str_finish),
147e83
diff -rupN a/libio/vswprintf.c b/libio/vswprintf.c
147e83
--- a/libio/vswprintf.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/vswprintf.c	2017-08-24 14:56:40.296819988 -0400
147e83
@@ -65,7 +65,7 @@ _IO_wstrn_overflow (fp, c)
147e83
 }
147e83
 
147e83
 
147e83
-const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden =
147e83
+const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_wstr_finish),
147e83
diff -rupN a/libio/vtables.c b/libio/vtables.c
147e83
--- a/libio/vtables.c	1969-12-31 19:00:00.000000000 -0500
147e83
+++ b/libio/vtables.c	2017-08-24 14:56:40.299819991 -0400
147e83
@@ -0,0 +1,70 @@
147e83
+/* libio vtable validation.
147e83
+   Copyright (C) 2016 Free Software Foundation, Inc.
147e83
+   This file is part of the GNU C Library.
147e83
+
147e83
+   The GNU C Library is free software; you can redistribute it and/or
147e83
+   modify it under the terms of the GNU Lesser General Public
147e83
+   License as published by the Free Software Foundation; either
147e83
+   version 2.1 of the License, or (at your option) any later version.
147e83
+
147e83
+   The GNU C Library is distributed in the hope that it will be useful,
147e83
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
147e83
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147e83
+   Lesser General Public License for more details.
147e83
+
147e83
+   You should have received a copy of the GNU Lesser General Public
147e83
+   License along with the GNU C Library; if not, see
147e83
+   <http://www.gnu.org/licenses/>.  */
147e83
+
147e83
+#include <dlfcn.h>
147e83
+#include <libioP.h>
147e83
+#include <stdio.h>
147e83
+
147e83
+#ifdef SHARED
147e83
+
147e83
+void (*IO_accept_foreign_vtables) (void) attribute_hidden;
147e83
+
147e83
+/* Used to detected multiple libcs.  */
147e83
+extern struct dl_open_hook *_dl_open_hook;
147e83
+libc_hidden_proto (_dl_open_hook);
147e83
+
147e83
+#else  /* !SHARED */
147e83
+
147e83
+/* Used to check whether static dlopen support is needed.  */
147e83
+# pragma weak __dlopen
147e83
+
147e83
+#endif
147e83
+
147e83
+void attribute_hidden
147e83
+_IO_vtable_check (void)
147e83
+{
147e83
+#ifdef SHARED
147e83
+  /* Honor the compatibility flag.  */
147e83
+  void (*flag) (void) = atomic_load_relaxed (&IO_accept_foreign_vtables);
147e83
+  PTR_DEMANGLE (flag);
147e83
+  if (flag == &_IO_vtable_check)
147e83
+    return;
147e83
+
147e83
+  /* In case this libc copy is in a non-default namespace, we always
147e83
+     need to accept foreign vtables because there is always a
147e83
+     possibility that FILE * objects are passed across the linking
147e83
+     boundary.  */
147e83
+  {
147e83
+    Dl_info di;
147e83
+    struct link_map *l;
147e83
+    if (_dl_open_hook != NULL
147e83
+        || (_dl_addr (_IO_vtable_check, &di, &l, NULL) != 0
147e83
+            && l->l_ns != LM_ID_BASE))
147e83
+      return;
147e83
+  }
147e83
+
147e83
+#else /* !SHARED */
147e83
+  /* We cannot perform vtable validation in the static dlopen case
147e83
+     because FILE * handles might be passed back and forth across the
147e83
+     boundary.  Therefore, we disable checking in this case.  */
147e83
+  if (__dlopen != NULL)
147e83
+    return;
147e83
+#endif
147e83
+
147e83
+  __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n");
147e83
+}
147e83
diff -rupN a/libio/wfileops.c b/libio/wfileops.c
147e83
--- a/libio/wfileops.c	2017-08-24 14:50:25.000000000 -0400
147e83
+++ b/libio/wfileops.c	2017-08-24 14:56:40.303819995 -0400
147e83
@@ -1035,7 +1035,7 @@ _IO_wfile_xsputn (f, data, n)
147e83
 libc_hidden_def (_IO_wfile_xsputn)
147e83
 
147e83
 
147e83
-const struct _IO_jump_t _IO_wfile_jumps =
147e83
+const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_new_file_finish),
147e83
@@ -1061,7 +1061,7 @@ const struct _IO_jump_t _IO_wfile_jumps
147e83
 libc_hidden_data_def (_IO_wfile_jumps)
147e83
 
147e83
 
147e83
-const struct _IO_jump_t _IO_wfile_jumps_mmap =
147e83
+const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_new_file_finish),
147e83
@@ -1085,7 +1085,7 @@ const struct _IO_jump_t _IO_wfile_jumps_
147e83
   JUMP_INIT(imbue, _IO_default_imbue)
147e83
 };
147e83
 
147e83
-const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
147e83
+const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_new_file_finish),
147e83
diff -rupN a/libio/wmemstream.c b/libio/wmemstream.c
147e83
--- a/libio/wmemstream.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/libio/wmemstream.c	2017-08-24 14:56:40.307819999 -0400
147e83
@@ -34,7 +34,7 @@ static int _IO_wmem_sync (_IO_FILE* fp)
147e83
 static void _IO_wmem_finish (_IO_FILE* fp, int) __THROW;
147e83
 
147e83
 
147e83
-static const struct _IO_jump_t _IO_wmem_jumps =
147e83
+static const struct _IO_jump_t _IO_wmem_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT (finish, _IO_wmem_finish),
147e83
diff -rupN a/libio/wstrops.c b/libio/wstrops.c
147e83
--- a/libio/wstrops.c	2017-08-24 14:50:23.000000000 -0400
147e83
+++ b/libio/wstrops.c	2017-08-24 14:56:40.310820002 -0400
147e83
@@ -347,7 +347,7 @@ _IO_wstr_finish (fp, dummy)
147e83
   _IO_wdefault_finish (fp, 0);
147e83
 }
147e83
 
147e83
-const struct _IO_jump_t _IO_wstr_jumps =
147e83
+const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT(finish, _IO_wstr_finish),
147e83
diff -rupN a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
147e83
--- a/stdio-common/vfprintf.c	2017-08-24 14:50:20.000000000 -0400
147e83
+++ b/stdio-common/vfprintf.c	2017-08-24 14:56:40.314820007 -0400
147e83
@@ -2234,7 +2234,7 @@ _IO_helper_overflow (_IO_FILE *s, int c)
147e83
 }
147e83
 
147e83
 #ifdef COMPILE_WPRINTF
147e83
-static const struct _IO_jump_t _IO_helper_jumps =
147e83
+static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT (finish, _IO_wdefault_finish),
147e83
@@ -2256,7 +2256,7 @@ static const struct _IO_jump_t _IO_helpe
147e83
   JUMP_INIT (stat, _IO_default_stat)
147e83
 };
147e83
 #else
147e83
-static const struct _IO_jump_t _IO_helper_jumps =
147e83
+static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
147e83
 {
147e83
   JUMP_INIT_DUMMY,
147e83
   JUMP_INIT (finish, _IO_default_finish),
147e83
diff -rupN a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
147e83
--- a/stdlib/strfmon_l.c	2012-12-24 22:02:13.000000000 -0500
147e83
+++ b/stdlib/strfmon_l.c	2017-08-24 14:56:40.314820007 -0400
147e83
@@ -515,7 +515,7 @@ __vstrfmon_l (char *s, size_t maxsize, _
147e83
 #ifdef _IO_MTSAFE_IO
147e83
       f._sbf._f._lock = NULL;
147e83
 #endif
147e83
-      _IO_init (&f._sbf._f, 0);
147e83
+      _IO_init_internal (&f._sbf._f, 0);
147e83
       _IO_JUMPS (&f._sbf) = &_IO_str_jumps;
147e83
       _IO_str_init_static_internal (&f, dest, (s + maxsize) - dest, dest);
147e83
       /* We clear the last available byte so we can find out whether