]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
libio: do not attempt to free wide buffers of legacy streams [BZ #24228]
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 13 Feb 2019 01:20:51 +0000 (01:20 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Thu, 20 Jun 2019 17:32:07 +0000 (17:32 +0000)
Commit a601b74d31ca086de38441d316a3dee24c866305 aka glibc-2.23~693
("In preparation for fixing BZ#16734, fix failure in misc/tst-error1-mem
when _G_HAVE_MMAP is turned off.") introduced a regression:
_IO_unbuffer_all now invokes _IO_wsetb to free wide buffers of all
files, including legacy standard files which are small statically
allocated objects that do not have wide buffers and the _mode member,
causing memory corruption.

Another memory corruption in _IO_unbuffer_all happens when -1
is assigned to the _mode member of legacy standard files that
do not have it.

[BZ #24228]
* libio/genops.c (_IO_unbuffer_all)
[SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide
buffers and access _IO_FILE_complete members of legacy libio streams.
* libio/tst-bz24228.c: New file.
* libio/tst-bz24228.map: Likewise.
* libio/Makefile [build-shared] (tests): Add tst-bz24228.
[build-shared] (generated): Add tst-bz24228.mtrace and
tst-bz24228.check.
[run-built-tests && build-shared] (tests-special): Add
$(objpfx)tst-bz24228-mem.out.
(LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables.
($(objpfx)tst-bz24228-mem.out): New rule.

(cherry picked from commit 21cc130b78a4db9113fb6695e2b951e697662440)

ChangeLog
NEWS
libio/Makefile
libio/genops.c
libio/tst-bz24228.c [new file with mode: 0644]
libio/tst-bz24228.map [new file with mode: 0644]

index 7d172901a4d3538fe3f31977f28cda2c6ec5fef2..2c82b3063af0c0e846d6d48dac377563f60bebb4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2019-06-20  Dmitry V. Levin  <ldv@altlinux.org>
+           Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #24228]
+       * libio/genops.c (_IO_unbuffer_all)
+       [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide
+       buffers and access _IO_FILE_complete members of legacy libio streams.
+       * libio/tst-bz24228.c: New file.
+       * libio/tst-bz24228.map: Likewise.
+       * libio/Makefile [build-shared] (tests): Add tst-bz24228.
+       [build-shared] (generated): Add tst-bz24228.mtrace and
+       tst-bz24228.check.
+       [run-built-tests && build-shared] (tests-special): Add
+       $(objpfx)tst-bz24228-mem.out.
+       (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables.
+       ($(objpfx)tst-bz24228-mem.out): New rule.
+
 2019-05-22  Wilco Dijkstra  <wdijkstr@arm.com>
 
        [BZ #24531]
diff --git a/NEWS b/NEWS
index 8bad7b0082bfb910ad642aaaddf29c6a41d35744..0f1bff99e8dc29bd3b4ac3f7a6933786e677ceb0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -58,6 +58,7 @@ The following bugs are resolved with this release:
   [24097] Can't use 64-bit register for size_t in assembly codes for x32 (CVE-2019-6488)
   [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
   [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
+  [24228] old x86 applications that use legacy libio crash on exit
   [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
 
 Security related changes:
index cbfaf3832a45fc229eb81562506ffd7ef53aec4b..314e03d5ce72be2dbaf61644c18ece3e908471f8 100644 (file)
@@ -73,6 +73,9 @@ ifeq (yes,$(build-shared))
 # Add test-fopenloc only if shared library is enabled since it depends on
 # shared localedata objects.
 tests += tst-fopenloc
+# Add tst-bz24228 only if shared library is enabled since it can never meet its
+# objective with static linking because the relevant code just is not there.
+tests += tst-bz24228
 endif
 test-srcs = test-freopen
 
@@ -153,11 +156,14 @@ CFLAGS-oldtmpfile.c += -fexceptions
 
 CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
 
+LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
+
 tst_wprintf2-ARGS = "Some Text"
 
 test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
 tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
 tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
+tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace
 
 generated += test-fmemopen.mtrace test-fmemopen.check
 generated += tst-fopenloc.mtrace tst-fopenloc.check
@@ -166,6 +172,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check
 aux    := fileops genops stdfiles stdio strops
 
 ifeq ($(build-shared),yes)
+generated += tst-bz24228.mtrace tst-bz24228.check
 aux    += oldfileops oldstdfiles
 endif
 
@@ -180,7 +187,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \
 ifeq (yes,$(build-shared))
 # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
 # library is enabled since they depend on tst-fopenloc.out.
-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
+tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
+                $(objpfx)tst-bz24228-mem.out
 endif
 endif
 
@@ -232,3 +240,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out
 $(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out
        $(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \
        $(evaluate-test)
+
+$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out
+       $(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \
+       $(evaluate-test)
index 2fec221b99729718d27cef453db2d3e0c2c56233..a8241dd26640bbcbad21348060eda9bbb3f49096 100644 (file)
@@ -789,9 +789,16 @@ _IO_unbuffer_all (void)
 
   for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain)
     {
+      int legacy = 0;
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+      if (__glibc_unlikely (_IO_vtable_offset (fp) != 0))
+       legacy = 1;
+#endif
+
       if (! (fp->_flags & _IO_UNBUFFERED)
          /* Iff stream is un-orientated, it wasn't used. */
-         && fp->_mode != 0)
+         && (legacy || fp->_mode != 0))
        {
 #ifdef _IO_MTSAFE_IO
          int cnt;
@@ -805,7 +812,7 @@ _IO_unbuffer_all (void)
              __sched_yield ();
 #endif
 
-         if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
+         if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
            {
              fp->_flags |= _IO_USER_BUF;
 
@@ -816,7 +823,7 @@ _IO_unbuffer_all (void)
 
          _IO_SETBUF (fp, NULL, 0);
 
-         if (fp->_mode > 0)
+         if (! legacy && fp->_mode > 0)
            _IO_wsetb (fp, NULL, NULL, 0);
 
 #ifdef _IO_MTSAFE_IO
@@ -827,7 +834,8 @@ _IO_unbuffer_all (void)
 
       /* Make sure that never again the wide char functions can be
         used.  */
-      fp->_mode = -1;
+      if (! legacy)
+       fp->_mode = -1;
     }
 
 #ifdef _IO_MTSAFE_IO
diff --git a/libio/tst-bz24228.c b/libio/tst-bz24228.c
new file mode 100644 (file)
index 0000000..6a74500
--- /dev/null
@@ -0,0 +1,29 @@
+/* BZ #24228 check for memory corruption in legacy libio
+   Copyright (C) 2019 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <mcheck.h>
+#include <support/test-driver.h>
+
+static int
+do_test (void)
+{
+  mtrace ();
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/libio/tst-bz24228.map b/libio/tst-bz24228.map
new file mode 100644 (file)
index 0000000..4383e08
--- /dev/null
@@ -0,0 +1,5 @@
+# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c
+# implementation when it is available for the architecture.
+{
+  local: _IO_stdin_used;
+};