From patchwork Tue May 24 16:58:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 12494 Received: (qmail 75346 invoked by alias); 24 May 2016 16:59:18 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 75074 invoked by uid 89); 24 May 2016 16:59:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy=duty X-HELO: mail-pf0-f174.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition; bh=flvD2dSLMHKHEAHjf3kycsqIqh0lkYJExmM42yFTSJ0=; b=E+xcKIfWyoDMmRxb0VydHBp8Hees9YlcdW/omh/N6QjXUglebeS9fvva6ZB8MYHkXR xEwauX8FBVyECrLBGAMou8phx+eW1Meit5rehkqErMiWmqw78ZibplZGF0FQetbyBE9l qEwCIjMgVKmda9jTK/3E7uCqx7ApMVbi9Mu/xUUPyLsfrJKmGRyIvApuxPxo5+HU9Hqq o9gtuCqBjcbLw2nhRncbSpv82Bxi5qLpjkOnq/r26SsQ9dvJnZ1s3FAnM6GaNfpW5n1u j/IJHz6aAzYuVrw+x/S/pRZAkyN75XvMik+EBtiGC4UJK3oSYxvnOY2ytJGGCHFAprsS p8Ug== X-Gm-Message-State: ALyK8tKHu60lvWn0/yyijuhWtCEhT6Df1G+IcNy1qhiXG8PlbwTNvnYU4gpTHjuFyPIQNDbW X-Received: by 10.98.97.67 with SMTP id v64mr8366232pfb.149.1464109136131; Tue, 24 May 2016 09:58:56 -0700 (PDT) Date: Tue, 24 May 2016 09:58:54 -0700 From: Kees Cook To: libc-alpha@sourceware.org Cc: Mike Frysinger , Florian Weimer , Adam Conrad , Joseph Myers , Yunlian Jiang Subject: [PATCH v3] libio: use PTR_MANGLE/PTR_DEMANGLE for FILE vtables Message-ID: <20160524165854.GA32022@www.outflux.net> MIME-Version: 1.0 Content-Disposition: inline Hi! This is a continuation of an earlier discussion[1] about hardening the FILE vtable with PTR_MANGLE, which previously ended with the request that a new configure variable be used to control it[2]. This series now carries the new "--enable-libio-compatibility" configure flag to retain libio compat with pre-roughly-2007 binaries using libstdc++.so.5 and earlier. Running the glibc test suite shows no regressions for me. (FWIW, this patch has seen a lot of use, as it has been in Chrome OS for over 3 years now.) -Kees [1] https://sourceware.org/ml/libc-alpha/2015-10/msg00009.html [2] https://sourceware.org/ml/libc-alpha/2015-10/msg00057.html v3: - adjust whitespace, rename mangle/demangle inlines (vapier). v2: - added "--enable-libio-compatibility" (fw). v1: - URL [1] above --- 2016-05-23 Kees Cook * configure.ac (AC_ARG_ENABLE(libio-compatibility)): New configure flag. * config.h.in: add USE_COMPAT_LIBIO * configure: Regenerate. * manual/install.texi (--disable-libio-compatibility): Document new flag. * INSTALL: Regenerate. * libio/libioP.h: Create inline helpers to run the PTR_MANGLE and PTR_DEMANGLE routines on vtable pointers when USE_COMPAT_LIBIO is not set. Create _IO_JUMPS_SET and _IO_WIDE_JUMPS_SET macros to use the new inline helpers. Update the _IO_JUMPS_FUNC and _IO_WIDE_JUMPS_FUNC to use the new inline helpers. * debug/obprintf_chk.c: Replace direct vtable assignment with macro. * debug/vasprintf_chk.c: Likewise. * debug/vdprintf_chk.c: Likewise. * debug/vsnprintf_chk.c: Likewise. * debug/vsprintf_chk.c: Likewise. * libio/fileops.c: Likewise. * libio/freopen.c: Likewise. * libio/freopen64.c: Likewise. * libio/genops.c: Likewise. * libio/iofdopen.c: Likewise. * libio/iofopen.c: Likewise. * libio/iofopncook.c: Likewise. * libio/iofwide.c: Likewise. * libio/iopopen.c: Likewise. * libio/iovdprintf.c: Likewise. * libio/iovsprintf.c: Likewise. * libio/iovsscanf.c: Likewise. * libio/memstream.c: Likewise. * libio/obprintf.c: Likewise. * libio/oldiofdopen.c: Likewise. * libio/oldiofopen.c: Likewise. * libio/oldiopopen.c: Likewise. * libio/vasprintf.c: Likewise. * libio/vsnprintf.c: Likewise. * stdio-common/isoc99_vsscanf.c: Likewise. * stdio-common/vfprintf.c: Likewise. * stdlib/strfmon_l.c: Likewise. * misc/init-misc.c: Mangle predefined stdio FILE vtables at startup. --- INSTALL | 5 ++++ config.h.in | 3 ++ configure | 15 ++++++++++ configure.ac | 11 +++++++ debug/obprintf_chk.c | 2 +- debug/vasprintf_chk.c | 2 +- debug/vdprintf_chk.c | 2 +- debug/vsnprintf_chk.c | 2 +- debug/vsprintf_chk.c | 2 +- libio/fileops.c | 28 +++++++++--------- libio/freopen.c | 6 ++-- libio/freopen64.c | 4 +-- libio/genops.c | 2 +- libio/iofdopen.c | 4 +-- libio/iofopen.c | 8 +++--- libio/iofopncook.c | 4 +-- libio/iofwide.c | 2 +- libio/iopopen.c | 2 +- libio/iovdprintf.c | 2 +- libio/iovsprintf.c | 2 +- libio/iovsscanf.c | 2 +- libio/libioP.h | 67 +++++++++++++++++++++++++++++++------------ libio/memstream.c | 2 +- libio/obprintf.c | 2 +- libio/oldiofdopen.c | 2 +- libio/oldiofopen.c | 2 +- libio/oldiopopen.c | 2 +- libio/vasprintf.c | 2 +- libio/vsnprintf.c | 2 +- manual/install.texi | 5 ++++ misc/init-misc.c | 15 ++++++++++ stdio-common/isoc99_vsscanf.c | 2 +- stdio-common/vfprintf.c | 2 +- stdlib/strfmon_l.c | 2 +- 34 files changed, 150 insertions(+), 67 deletions(-) diff --git a/INSTALL b/INSTALL index 31e256d..8b9e610 100644 --- a/INSTALL +++ b/INSTALL @@ -116,6 +116,11 @@ will be used, and CFLAGS sets optimization options for the compiler. program linked statically with the NSS libraries cannot be dynamically reconfigured to use a different name database. +'--enable-libio-compatibility' + Compile libio without PTR_MANGLE of the FILE vtable, in order to + remain compatibile with pre-libstdc++.so.6 binaries that may be + sharing the vtable (i.e. roughly pre-2007 binaries). + '--without-tls' By default the C library is built with support for thread-local storage if the used tools support it. By using '--without-tls' diff --git a/config.h.in b/config.h.in index 0147ba3..9a7894b 100644 --- a/config.h.in +++ b/config.h.in @@ -161,6 +161,9 @@ /* Define if the dynamic linker should consult an ld.so.cache file. */ #undef USE_LDCONFIG +/* Define if we should remain compatibile with pre-libstdc++.so.6 libio. */ +#undef USE_COMPAT_LIBIO + /* Define to 1 if STT_GNU_IFUNC support actually works. */ #define HAVE_IFUNC 0 diff --git a/configure b/configure index 8fe5937..24e4d7a 100755 --- a/configure +++ b/configure @@ -761,6 +761,7 @@ enable_add_ons enable_hidden_plt enable_bind_now enable_static_nss +enable_libio_compatibility enable_force_install enable_maintainer_mode enable_kernel @@ -1422,6 +1423,8 @@ Optional Features: --disable-hidden-plt do not hide internal function calls to avoid PLT --enable-bind-now disable lazy relocations in DSOs --enable-static-nss build static NSS modules [default=no] + --enable-libio-compatibility + remain compatible with pre-libstdc++.so.6 libio --disable-force-install don't force installation of files from this package, even if they are older than the installed files --enable-maintainer-mode @@ -3430,6 +3433,18 @@ if test x"$static_nss" = xyes || test x"$shared" = xno; then fi +# Check whether --enable-libio-compatibility was given. +if test "${enable_libio_compatibility+set}" = set; then : + enableval=$enable_libio_compatibility; libio_compatibility=$enableval +else + libio_compatibility=no +fi + +if test "$libio_compatibility" = yes; then + $as_echo "#define USE_COMPAT_LIBIO 1" >>confdefs.h + +fi + # Check whether --enable-force-install was given. if test "${enable_force_install+set}" = set; then : enableval=$enable_force_install; force_install=$enableval diff --git a/configure.ac b/configure.ac index 3c766b7..347a9ec 100644 --- a/configure.ac +++ b/configure.ac @@ -245,6 +245,17 @@ if test x"$static_nss" = xyes || test x"$shared" = xno; then AC_DEFINE(DO_STATIC_NSS) fi +dnl To enable PTR_MANGLE on the FILE vtable, we break compatibility with +dnl pre-libstdc++.so.6 libio. +AC_ARG_ENABLE([libio-compatibility], + AC_HELP_STRING([--enable-libio-compatibility], + [remain compatible with pre-libstdc++.so.6 libio]), + [libio_compatibility=$enableval], + [libio_compatibility=no]) +if test "$libio_compatibility" = yes; then + AC_DEFINE(USE_COMPAT_LIBIO) +fi + AC_ARG_ENABLE([force-install], AC_HELP_STRING([--disable-force-install], [don't force installation of files from this package, even if they are older than the installed files]), diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c index 8469b5f..77ed19f 100644 --- a/debug/obprintf_chk.c +++ b/debug/obprintf_chk.c @@ -54,7 +54,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format, #endif _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps; + _IO_JUMPS_SET (&new_f.ofile.file, &_IO_obstack_jumps); room = obstack_room (obstack); size = obstack_object_size (obstack) + room; if (size == 0) diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c index cb1f74a..db81a47 100644 --- a/debug/vasprintf_chk.c +++ b/debug/vasprintf_chk.c @@ -52,7 +52,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format, 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_JUMPS_SET (&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 = (_IO_alloc_type) malloc; diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c index 05d0bcd..1daeb4c 100644 --- a/debug/vdprintf_chk.c +++ b/debug/vdprintf_chk.c @@ -38,7 +38,7 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg) 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_JUMPS_SET (&tmpfil, &_IO_file_jumps); _IO_file_init (&tmpfil); #if !_IO_UNIFIED_JUMPTABLES tmpfil.vtable = NULL; diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c index cc559d2..2a91815 100644 --- a/debug/vsnprintf_chk.c +++ b/debug/vsnprintf_chk.c @@ -51,7 +51,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen, } _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps; + _IO_JUMPS_SET (&sf.f._sbf, &_IO_strn_jumps); s[0] = '\0'; /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c index aa1587c..f6605e2 100644 --- a/debug/vsprintf_chk.c +++ b/debug/vsprintf_chk.c @@ -71,7 +71,7 @@ ___vsprintf_chk (char *s, int flags, size_t slen, const char *format, __chk_fail (); _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps; + _IO_JUMPS_SET (&f._sbf, &_IO_str_chk_jumps); s[0] = '\0'; _IO_str_init_static_internal (&f, s, slen - 1, s); diff --git a/libio/fileops.c b/libio/fileops.c index 8e83b1c..bdf30e6 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -414,7 +414,7 @@ _IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode, &result->_wide_data->_IO_state; /* From now on use the wide character callback functions. */ - _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable; + _IO_JUMPS_FILE_plus_SET (fp, _IO_WIDE_JUMPS_FUNC (fp)); /* Set the mode now. */ result->_mode = 1; @@ -466,8 +466,8 @@ _IO_file_setbuf_mmap (_IO_FILE *fp, char *p, _IO_ssize_t len) _IO_FILE *result; /* Change the function table. */ - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps; - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps); + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps); /* And perform the normal operation. */ result = _IO_new_file_setbuf (fp, p, len); @@ -475,8 +475,8 @@ _IO_file_setbuf_mmap (_IO_FILE *fp, char *p, _IO_ssize_t len) /* If the call failed, restore to using mmap. */ if (result == NULL) { - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap; - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps_mmap); + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps_mmap); } return result; @@ -703,10 +703,10 @@ mmap_remap_check (_IO_FILE *fp) fp->_IO_buf_base = fp->_IO_buf_end = NULL; _IO_setg (fp, NULL, NULL, NULL); if (fp->_mode <= 0) - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps); else - _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps; - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps); + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps); return 1; } @@ -773,10 +773,10 @@ decide_maybe_mmap (_IO_FILE *fp) fp->_offset = st.st_size; if (fp->_mode <= 0) - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps_mmap); else - _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_mmap; - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps_mmap); + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps_mmap); return; } @@ -786,10 +786,10 @@ decide_maybe_mmap (_IO_FILE *fp) /* We couldn't use mmap, so revert to the vanilla file operations. */ if (fp->_mode <= 0) - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps); else - _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps; - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps); + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps); } int diff --git a/libio/freopen.c b/libio/freopen.c index 8a2a417..466cce6 100644 --- a/libio/freopen.c +++ b/libio/freopen.c @@ -56,16 +56,16 @@ freopen (const char *filename, const char *mode, FILE *fp) to the old libio may be passed into shared C library and wind up here. */ _IO_old_file_close_it (fp); - _IO_JUMPS_FILE_plus (fp) = &_IO_old_file_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_old_file_jumps); result = _IO_old_file_fopen (fp, gfilename, mode); } else #endif { _IO_file_close_it (fp); - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps); if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL) - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps); result = _IO_file_fopen (fp, gfilename, mode, 1); if (result != NULL) result = __fopen_maybe_mmap (result); diff --git a/libio/freopen64.c b/libio/freopen64.c index ba85c3e..7eccb3e 100644 --- a/libio/freopen64.c +++ b/libio/freopen64.c @@ -47,9 +47,9 @@ freopen64 (const char *filename, const char *mode, FILE *fp) ? fd_to_filename (fd) : filename); fp->_flags2 |= _IO_FLAGS2_NOCLOSE; _IO_file_close_it (fp); - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps); if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL) - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps); result = _IO_file_fopen (fp, gfilename, mode, 0); fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; if (result != NULL) diff --git a/libio/genops.c b/libio/genops.c index 5803cbf..8542f78 100644 --- a/libio/genops.c +++ b/libio/genops.c @@ -615,7 +615,7 @@ _IO_no_init (_IO_FILE *fp, int flags, int orientation, fp->_wide_data->_IO_backup_base = NULL; fp->_wide_data->_IO_save_end = NULL; - fp->_wide_data->_wide_vtable = jmp; + _IO_WIDE_JUMPS_SET (fp, jmp); } else /* Cause predictable crash when a wide function is called on a byte diff --git a/libio/iofdopen.c b/libio/iofdopen.c index e00f337..8633055 100644 --- a/libio/iofdopen.c +++ b/libio/iofdopen.c @@ -148,11 +148,11 @@ _IO_new_fdopen (int fd, const char *mode) ? &_IO_wfile_jumps_maybe_mmap : #endif &_IO_wfile_jumps); - _IO_JUMPS (&new_f->fp) = + _IO_JUMPS_SET (&new_f->fp, #ifdef _G_HAVE_MMAP (use_mmap && (read_write & _IO_NO_WRITES)) ? &_IO_file_jumps_maybe_mmap : #endif - &_IO_file_jumps; + &_IO_file_jumps); _IO_file_init (&new_f->fp); #if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL; diff --git a/libio/iofopen.c b/libio/iofopen.c index 13e3910..6195fec 100644 --- a/libio/iofopen.c +++ b/libio/iofopen.c @@ -46,10 +46,10 @@ __fopen_maybe_mmap (_IO_FILE *fp) vanilla file operations and reset the jump table accordingly. */ if (fp->_mode <= 0) - _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_maybe_mmap; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps_maybe_mmap); else - _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_maybe_mmap; - fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_maybe_mmap; + _IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps_maybe_mmap); + _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps_maybe_mmap); } #endif return fp; @@ -78,7 +78,7 @@ __fopen_internal (const char *filename, const char *mode, int is32) #else _IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL); #endif - _IO_JUMPS (&new_f->fp) = &_IO_file_jumps; + _IO_JUMPS_SET (&new_f->fp, &_IO_file_jumps); _IO_file_init (&new_f->fp); #if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL; diff --git a/libio/iofopncook.c b/libio/iofopncook.c index 9eda7c1..c745e0c 100644 --- a/libio/iofopncook.c +++ b/libio/iofopncook.c @@ -131,7 +131,7 @@ _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_JUMPS (&cfile->__fp) = &_IO_cookie_jumps; + _IO_JUMPS_SET (&cfile->__fp, &_IO_cookie_jumps); cfile->__cookie = cookie; cfile->__io_functions = io_functions; @@ -249,7 +249,7 @@ _IO_old_fopencookie (void *cookie, const char *mode, ret = _IO_fopencookie (cookie, mode, io_functions); if (ret != NULL) - _IO_JUMPS_FILE_plus (ret) = &_IO_old_cookie_jumps; + _IO_JUMPS_FILE_plus_SET (ret, &_IO_old_cookie_jumps); return ret; } diff --git a/libio/iofwide.c b/libio/iofwide.c index bc82e8b..9137d77 100644 --- a/libio/iofwide.c +++ b/libio/iofwide.c @@ -182,7 +182,7 @@ _IO_fwide (_IO_FILE *fp, int mode) #endif /* From now on use the wide character callback functions. */ - _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable; + _IO_JUMPS_FILE_plus_SET (fp, _IO_WIDE_JUMPS_FUNC (fp)); } /* Set the mode now. */ diff --git a/libio/iopopen.c b/libio/iopopen.c index 9ddde23..6029c71 100644 --- a/libio/iopopen.c +++ b/libio/iopopen.c @@ -288,7 +288,7 @@ _IO_new_popen (const char *command, const char *mode) #endif fp = &new_f->fpx.file.file; _IO_init (fp, 0); - _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps; + _IO_JUMPS_SET (&new_f->fpx.file, &_IO_proc_jumps); _IO_new_file_init (&new_f->fpx.file); #if !_IO_UNIFIED_JUMPTABLES new_f->fpx.file.vtable = NULL; diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c index 8ca55fc..f3dcb9a 100644 --- a/libio/iovdprintf.c +++ b/libio/iovdprintf.c @@ -38,7 +38,7 @@ _IO_vdprintf (int d, const char *format, _IO_va_list arg) 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_JUMPS_SET (&tmpfil, &_IO_file_jumps); _IO_file_init (&tmpfil); #if !_IO_UNIFIED_JUMPTABLES tmpfil.vtable = NULL; diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c index 712d178..6baa376 100644 --- a/libio/iovsprintf.c +++ b/libio/iovsprintf.c @@ -37,7 +37,7 @@ __IO_vsprintf (char *string, const char *format, _IO_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_JUMPS_SET (&sf._sbf, &_IO_str_jumps); _IO_str_init_static_internal (&sf, string, -1, string); ret = _IO_vfprintf (&sf._sbf._f, format, args); _IO_putc_unlocked ('\0', &sf._sbf._f); diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c index 18d9aaa..07db19a 100644 --- a/libio/iovsscanf.c +++ b/libio/iovsscanf.c @@ -36,7 +36,7 @@ _IO_vsscanf (const char *string, const char *format, _IO_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_JUMPS_SET (&sf._sbf, &_IO_str_jumps); _IO_str_init_static_internal (&sf, (char*)string, 0, NULL); ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL); return ret; diff --git a/libio/libioP.h b/libio/libioP.h index 8706af2..3efdde8 100644 --- a/libio/libioP.h +++ b/libio/libioP.h @@ -70,17 +70,16 @@ extern "C" { /* THE JUMPTABLE FUNCTIONS. - * The _IO_FILE type is used to implement the FILE type in GNU libc, - * as well as the streambuf class in GNU iostreams for C++. - * These are all the same, just used differently. - * An _IO_FILE (or FILE) object is allows followed by a pointer to - * a jump table (of pointers to functions). The pointer is accessed - * with the _IO_JUMPS macro. The jump table has an eccentric format, - * so as to be compatible with the layout of a C++ virtual function table. - * (as implemented by g++). When a pointer to a streambuf object is - * coerced to an (_IO_FILE*), then _IO_JUMPS on the result just - * happens to point to the virtual function table of the streambuf. - * Thus the _IO_JUMPS function table used for C stdio/libio does + * The _IO_FILE type is used to implement the FILE type in GNU libc, as well + * as the streambuf class in GNU iostreams for C++. These are all the same, + * just used differently. An _IO_FILE (or FILE) object is always followed by + * a pointer to a jump table (of pointers to functions). The pointer is + * accessed with the _IO_JUMPS_SET and _IO_JUMPS_FUNC macros. The jump table + * has an eccentric format, so as to be compatible with the layout of a C++ + * virtual function table (as implemented by g++). When a pointer to a + * streambuf object is coerced to an (_IO_FILE*), then _IO_JUMPS on the + * result just happens to point to the virtual function table of the + * streambuf. Thus the _IO_JUMPS function table used for C stdio/libio does * double duty as the virtual function table for C++ streambuf. * * The entries in the _IO_JUMPS function table (and hence also the @@ -106,6 +105,17 @@ extern "C" { # define _IO_JUMPS_OFFSET 0 #endif +static inline void +_IO_mangle_vtable (const struct _IO_jump_t **vtable, + const struct _IO_jump_t *table) +{ + struct _IO_jump_t *ptr = (struct _IO_jump_t *)table; +#ifndef USE_COMPAT_LIBIO + PTR_MANGLE (ptr); +#endif + *vtable = ptr; +} + /* Type of MEMBER in struct type TYPE. */ #define _IO_MEMBER_TYPE(TYPE, MEMBER) __typeof__ (((TYPE){}).MEMBER) @@ -115,24 +125,43 @@ extern "C" { (*(_IO_MEMBER_TYPE (TYPE, MEMBER) *)(((char *) (THIS)) \ + offsetof(TYPE, MEMBER))) -#define _IO_JUMPS(THIS) (THIS)->vtable -#define _IO_JUMPS_FILE_plus(THIS) \ +#define _IO_JUMPS_RAW(THIS) (THIS)->vtable +#define _IO_JUMPS_SET(THIS, TABLE) \ + _IO_mangle_vtable (&_IO_JUMPS_RAW (THIS), (TABLE)) + +#define _IO_JUMPS_FILE_plus_RAW(THIS) \ _IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE_plus, vtable) -#define _IO_WIDE_JUMPS(THIS) \ +#define _IO_JUMPS_FILE_plus_SET(THIS, TABLE) \ + _IO_mangle_vtable (&_IO_JUMPS_FILE_plus_RAW (THIS), (TABLE)) + +#define _IO_WIDE_JUMPS_RAW(THIS) \ _IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE, _wide_data)->_wide_vtable +#define _IO_WIDE_JUMPS_SET(THIS, TABLE) \ + _IO_mangle_vtable (&_IO_WIDE_JUMPS_RAW (THIS), (TABLE)) + #define _IO_CHECK_WIDE(THIS) \ (_IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE, _wide_data) != NULL) +static inline const struct _IO_jump_t * +_IO_demangle_vtable (const struct _IO_jump_t *vtable) +{ + struct _IO_jump_t *ptr = (struct _IO_jump_t *)vtable; +#ifndef USE_COMPAT_LIBIO + PTR_DEMANGLE (ptr); +#endif + return (const struct _IO_jump_t *)ptr; +} + #if _IO_JUMPS_OFFSET -# define _IO_JUMPS_FUNC(THIS) \ - (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS) \ - + (THIS)->_vtable_offset)) +# define _IO_JUMPS_FUNC(THIS) _IO_demangle_vtable (\ + (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus_RAW (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_demangle_vtable (_IO_JUMPS_FILE_plus_RAW (THIS)) # define _IO_vtable_offset(THIS) 0 #endif -#define _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS) +#define _IO_WIDE_JUMPS_FUNC(THIS) _IO_demangle_vtable (_IO_WIDE_JUMPS_RAW (THIS)) #define JUMP_FIELD(TYPE, NAME) TYPE NAME #define JUMP0(FUNC, THIS) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS) #define JUMP1(FUNC, THIS, X1) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1) diff --git a/libio/memstream.c b/libio/memstream.c index 7fa5245..6ad4355 100644 --- a/libio/memstream.c +++ b/libio/memstream.c @@ -87,7 +87,7 @@ __open_memstream (char **bufloc, _IO_size_t *sizeloc) return NULL; } _IO_init (&new_f->fp._sf._sbf._f, 0); - _IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &_IO_mem_jumps; + _IO_JUMPS_FILE_plus_SET (&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; new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc; diff --git a/libio/obprintf.c b/libio/obprintf.c index aa17b46..1452b8d 100644 --- a/libio/obprintf.c +++ b/libio/obprintf.c @@ -132,7 +132,7 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args) #endif _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps; + _IO_JUMPS_SET (&new_f.ofile.file, &_IO_obstack_jumps); room = obstack_room (obstack); size = obstack_object_size (obstack) + room; if (size == 0) diff --git a/libio/oldiofdopen.c b/libio/oldiofdopen.c index 33406ff..b99e39f 100644 --- a/libio/oldiofdopen.c +++ b/libio/oldiofdopen.c @@ -111,7 +111,7 @@ _IO_old_fdopen (int fd, const char *mode) new_f->fp.file._file._lock = &new_f->lock; #endif _IO_old_init (&new_f->fp.file._file, 0); - _IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps; + _IO_JUMPS_FILE_plus_SET (&new_f->fp, &_IO_old_file_jumps); _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp); #if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL; diff --git a/libio/oldiofopen.c b/libio/oldiofopen.c index cc7c342..89cb848 100644 --- a/libio/oldiofopen.c +++ b/libio/oldiofopen.c @@ -50,7 +50,7 @@ _IO_old_fopen (const char *filename, const char *mode) new_f->fp.file._file._lock = &new_f->lock; #endif _IO_old_init (&new_f->fp.file._file, 0); - _IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps; + _IO_JUMPS_FILE_plus_SET (&new_f->fp, &_IO_old_file_jumps); _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp); #if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL; diff --git a/libio/oldiopopen.c b/libio/oldiopopen.c index ea75b4f..dec2b3c 100644 --- a/libio/oldiopopen.c +++ b/libio/oldiopopen.c @@ -210,7 +210,7 @@ _IO_old_popen (const char *command, const char *mode) #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_JUMPS_FILE_plus_SET (&new_f->fpx.file, &_IO_old_proc_jumps); _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fpx.file); #if !_IO_UNIFIED_JUMPTABLES new_f->fpx.file.vtable = NULL; diff --git a/libio/vasprintf.c b/libio/vasprintf.c index 7460f1e..146bd36 100644 --- a/libio/vasprintf.c +++ b/libio/vasprintf.c @@ -51,7 +51,7 @@ _IO_vasprintf (char **result_ptr, const char *format, _IO_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_JUMPS_SET (&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 = (_IO_alloc_type) malloc; diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c index f1063a1..75a15a9 100644 --- a/libio/vsnprintf.c +++ b/libio/vsnprintf.c @@ -108,7 +108,7 @@ _IO_vsnprintf (char *string, _IO_size_t maxlen, const char *format, } _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); - _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps; + _IO_JUMPS_SET (&sf.f._sbf, &_IO_strn_jumps); string[0] = '\0'; _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string); ret = _IO_vfprintf (&sf.f._sbf._f, format, args); diff --git a/manual/install.texi b/manual/install.texi index 95021b4..c150ee0 100644 --- a/manual/install.texi +++ b/manual/install.texi @@ -146,6 +146,11 @@ This is not recommended because it defeats the purpose of NSS; a program linked statically with the NSS libraries cannot be dynamically reconfigured to use a different name database. +@item --enable-libio-compatibility +Compile libio without PTR_MANGLE of the FILE vtable, in order to remain +compatibile with pre-@file{libstdc++.so.6} binaries that may be sharing the +vtable (i.e. roughly pre-2007 binaries). + @item --without-tls By default the C library is built with support for thread-local storage if the used tools support it. By using @samp{--without-tls} this can be diff --git a/misc/init-misc.c b/misc/init-misc.c index a9bf1da..7491500 100644 --- a/misc/init-misc.c +++ b/misc/init-misc.c @@ -16,7 +16,11 @@ License along with the GNU C Library; if not, see . */ +#include "libioP.h" + #include +#include +#include #include char *__progname_full = (char *) ""; @@ -37,4 +41,15 @@ __init_misc (int argc, char **argv, char **envp) __progname = p + 1; __progname_full = argv[0]; } + +#ifndef USE_COMPAT_LIBIO + PTR_MANGLE (_IO_JUMPS_FILE_plus_RAW (stdin)); + PTR_MANGLE (_IO_WIDE_JUMPS_RAW (stdin)); + + PTR_MANGLE (_IO_JUMPS_FILE_plus_RAW (stdout)); + PTR_MANGLE (_IO_WIDE_JUMPS_RAW (stdout)); + + PTR_MANGLE (_IO_JUMPS_FILE_plus_RAW (stderr)); + PTR_MANGLE (_IO_WIDE_JUMPS_RAW (stderr)); +#endif } diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c index 720f122..edbcf72 100644 --- a/stdio-common/isoc99_vsscanf.c +++ b/stdio-common/isoc99_vsscanf.c @@ -37,7 +37,7 @@ __isoc99_vsscanf (const char *string, const char *format, _IO_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_JUMPS_SET (&sf._sbf, &_IO_str_jumps); _IO_str_init_static_internal (&sf, (char*)string, 0, NULL); sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD; ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL); diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index f24020a..392b48d 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -2318,7 +2318,7 @@ buffered_vfprintf (_IO_FILE *s, const CHAR_T *format, hp->_lock = NULL; #endif hp->_flags2 = s->_flags2; - _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps; + _IO_JUMPS_SET (&helper._f, (struct _IO_jump_t *) &_IO_helper_jumps); /* Now print to helper instead. */ #ifndef COMPILE_WPRINTF diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c index 5851a5b..5efaab0 100644 --- a/stdlib/strfmon_l.c +++ b/stdlib/strfmon_l.c @@ -513,7 +513,7 @@ __vstrfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format, f._sbf._f._lock = NULL; #endif _IO_init (&f._sbf._f, 0); - _IO_JUMPS (&f._sbf) = &_IO_str_jumps; + _IO_JUMPS_SET (&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 the numeric representation is too long. */