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>
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 $@
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,
#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
#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. */
}
-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),
__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 \
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
_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)
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),
};
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),
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),
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)
(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;
_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
}
-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),
_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);
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),
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
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),
#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
#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)
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;
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);
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 *);
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);
/* 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. */
| _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) attribute_hidden;
+
+/* Assigns the passed function pointer (either NULL or
+ &_IO_vtable_check) to IO_accept_foreign_vtables. */
+static inline void
+IO_set_accept_foreign_vtables (void (*flag) (void))
+{
+ PTR_MANGLE (flag);
+ atomic_store_relaxed (&IO_accept_foreign_vtables, flag);
+}
+
+#else /* !SHARED */
+
+/* The statically-linked version does nothing. */
+static inline void
+IO_set_accept_foreign_vtables (void (*flag) (void))
+{
+}
+
+#endif
+
+/* Check if unknown vtable pointers are permitted; otherwise,
+ terminate the process. */
+void _IO_vtable_check (void) attribute_hidden;
+
+/* Perform vtable pointer validation. If validation fails, terminate
+ the process. */
+static inline const struct _IO_jump_t *
+IO_validate_vtable (const struct _IO_jump_t *vtable)
+{
+ /* Fast path: The vtable pointer is within the __libc_IO_vtables
+ section. */
+ uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
+ const char *ptr = (const char *) vtable;
+ uintptr_t offset = ptr - __start___libc_IO_vtables;
+ if (__glibc_unlikely (offset >= section_length))
+ /* The vtable pointer is not in the expected section. Use the
+ slow path, which will terminate the process if necessary. */
+ _IO_vtable_check ();
+ return vtable;
+}
static void _IO_mem_finish (_IO_FILE* fp, int) __THROW;
-static const struct _IO_jump_t _IO_mem_jumps =
+static const struct _IO_jump_t _IO_mem_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_mem_finish),
free (new_f);
return NULL;
}
- _IO_init (&new_f->fp._sf._sbf._f, 0);
+ _IO_init_internal (&new_f->fp._sf._sbf._f, 0);
_IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &_IO_mem_jumps;
_IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf);
new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF;
/* the jump table. */
-const struct _IO_jump_t _IO_obstack_jumps attribute_hidden =
+const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, NULL),
void
attribute_compat_text_section
-_IO_old_file_init (struct _IO_FILE_plus *fp)
+_IO_old_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
#endif
}
+void
+attribute_compat_text_section
+_IO_old_file_init (struct _IO_FILE_plus *fp)
+{
+ IO_set_accept_foreign_vtables (&_IO_vtable_check);
+ _IO_old_file_init_internal (fp);
+}
+
int
attribute_compat_text_section
_IO_old_file_close_it (_IO_FILE *fp)
}
-const struct _IO_jump_t _IO_old_file_jumps =
+const struct _IO_jump_t _IO_old_file_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_old_file_finish),
#endif
_IO_old_init (&new_f->fp.file._file, 0);
_IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps;
- _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
+ _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fp);
#if !_IO_UNIFIED_JUMPTABLES
new_f->fp.vtable = NULL;
#endif
#endif
_IO_old_init (&new_f->fp.file._file, 0);
_IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps;
- _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
+ _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fp);
#if !_IO_UNIFIED_JUMPTABLES
new_f->fp.vtable = NULL;
#endif
fp = &new_f->fpx.file.file._file;
_IO_old_init (fp, 0);
_IO_JUMPS_FILE_plus (&new_f->fpx.file) = &_IO_old_proc_jumps;
- _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fpx.file);
+ _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fpx.file);
#if !_IO_UNIFIED_JUMPTABLES
new_f->fpx.file.vtable = NULL;
#endif
return wstatus;
}
-const struct _IO_jump_t _IO_old_proc_jumps = {
+const struct _IO_jump_t _IO_old_proc_jumps libio_vtable = {
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_old_file_finish),
JUMP_INIT(overflow, _IO_old_file_overflow),
_IO_default_finish (fp, 0);
}
-const struct _IO_jump_t _IO_str_jumps =
+const struct _IO_jump_t _IO_str_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_str_finish),
}
-const struct _IO_jump_t _IO_strn_jumps attribute_hidden =
+const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_str_finish),
}
-const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden =
+const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_wstr_finish),
--- /dev/null
+/* libio vtable validation.
+ Copyright (C) 2016 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 <dlfcn.h>
+#include <libioP.h>
+#include <stdio.h>
+
+#ifdef SHARED
+
+void (*IO_accept_foreign_vtables) (void) attribute_hidden;
+
+/* Used to detected multiple libcs. */
+extern struct dl_open_hook *_dl_open_hook;
+libc_hidden_proto (_dl_open_hook);
+
+#else /* !SHARED */
+
+/* Used to check whether static dlopen support is needed. */
+# pragma weak __dlopen
+
+#endif
+
+void attribute_hidden
+_IO_vtable_check (void)
+{
+#ifdef SHARED
+ /* Honor the compatibility flag. */
+ void (*flag) (void) = atomic_load_relaxed (&IO_accept_foreign_vtables);
+ PTR_DEMANGLE (flag);
+ if (flag == &_IO_vtable_check)
+ return;
+
+ /* In case this libc copy is in a non-default namespace, we always
+ need to accept foreign vtables because there is always a
+ possibility that FILE * objects are passed across the linking
+ boundary. */
+ {
+ Dl_info di;
+ struct link_map *l;
+ if (_dl_open_hook != NULL
+ || (_dl_addr (_IO_vtable_check, &di, &l, NULL) != 0
+ && l->l_ns != LM_ID_BASE))
+ return;
+ }
+
+#else /* !SHARED */
+ /* We cannot perform vtable validation in the static dlopen case
+ because FILE * handles might be passed back and forth across the
+ boundary. Therefore, we disable checking in this case. */
+ if (__dlopen != NULL)
+ return;
+#endif
+
+ __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n");
+}
libc_hidden_def (_IO_wfile_xsputn)
-const struct _IO_jump_t _IO_wfile_jumps =
+const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_new_file_finish),
libc_hidden_data_def (_IO_wfile_jumps)
-const struct _IO_jump_t _IO_wfile_jumps_mmap =
+const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_new_file_finish),
JUMP_INIT(imbue, _IO_default_imbue)
};
-const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
+const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_new_file_finish),
static void _IO_wmem_finish (_IO_FILE* fp, int) __THROW;
-static const struct _IO_jump_t _IO_wmem_jumps =
+static const struct _IO_jump_t _IO_wmem_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_wmem_finish),
_IO_wdefault_finish (fp, 0);
}
-const struct _IO_jump_t _IO_wstr_jumps =
+const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_wstr_finish),
}
#ifdef COMPILE_WPRINTF
-static const struct _IO_jump_t _IO_helper_jumps =
+static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_wdefault_finish),
JUMP_INIT (stat, _IO_default_stat)
};
#else
-static const struct _IO_jump_t _IO_helper_jumps =
+static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_default_finish),
#ifdef _IO_MTSAFE_IO
f._sbf._f._lock = NULL;
#endif
- _IO_init (&f._sbf._f, 0);
+ _IO_init_internal (&f._sbf._f, 0);
_IO_JUMPS (&f._sbf) = &_IO_str_jumps;
_IO_str_init_static_internal (&f, dest, (s + maxsize) - dest, dest);
/* We clear the last available byte so we can find out whether