5f7b84
commit 21cc130b78a4db9113fb6695e2b951e697662440
5f7b84
Author: Dmitry V. Levin <ldv@altlinux.org>
5f7b84
Date:   Wed Feb 13 01:20:51 2019 +0000
5f7b84
5f7b84
    libio: do not attempt to free wide buffers of legacy streams [BZ #24228]
5f7b84
    
5f7b84
    Commit a601b74d31ca086de38441d316a3dee24c866305 aka glibc-2.23~693
5f7b84
    ("In preparation for fixing BZ#16734, fix failure in misc/tst-error1-mem
5f7b84
    when _G_HAVE_MMAP is turned off.") introduced a regression:
5f7b84
    _IO_unbuffer_all now invokes _IO_wsetb to free wide buffers of all
5f7b84
    files, including legacy standard files which are small statically
5f7b84
    allocated objects that do not have wide buffers and the _mode member,
5f7b84
    causing memory corruption.
5f7b84
    
5f7b84
    Another memory corruption in _IO_unbuffer_all happens when -1
5f7b84
    is assigned to the _mode member of legacy standard files that
5f7b84
    do not have it.
5f7b84
    
5f7b84
    [BZ #24228]
5f7b84
    * libio/genops.c (_IO_unbuffer_all)
5f7b84
    [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide
5f7b84
    buffers and access _IO_FILE_complete members of legacy libio streams.
5f7b84
    * libio/tst-bz24228.c: New file.
5f7b84
    * libio/tst-bz24228.map: Likewise.
5f7b84
    * libio/Makefile [build-shared] (tests): Add tst-bz24228.
5f7b84
    [build-shared] (generated): Add tst-bz24228.mtrace and
5f7b84
    tst-bz24228.check.
5f7b84
    [run-built-tests && build-shared] (tests-special): Add
5f7b84
    $(objpfx)tst-bz24228-mem.out.
5f7b84
    (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables.
5f7b84
    ($(objpfx)tst-bz24228-mem.out): New rule.
5f7b84
5f7b84
# Conflicts:
5f7b84
#	libio/Makefile
5f7b84
5f7b84
diff --git a/libio/Makefile b/libio/Makefile
5f7b84
index cbfaf3832a45fc22..314e03d5ce72be2d 100644
5f7b84
--- a/libio/Makefile
5f7b84
+++ b/libio/Makefile
5f7b84
@@ -73,6 +73,9 @@ ifeq (yes,$(build-shared))
5f7b84
 # Add test-fopenloc only if shared library is enabled since it depends on
5f7b84
 # shared localedata objects.
5f7b84
 tests += tst-fopenloc
5f7b84
+# Add tst-bz24228 only if shared library is enabled since it can never meet its
5f7b84
+# objective with static linking because the relevant code just is not there.
5f7b84
+tests += tst-bz24228
5f7b84
 endif
5f7b84
 test-srcs = test-freopen
5f7b84
 
5f7b84
@@ -153,11 +156,14 @@ CFLAGS-oldtmpfile.c += -fexceptions
5f7b84
 
5f7b84
 CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
5f7b84
 
5f7b84
+LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
5f7b84
+
5f7b84
 tst_wprintf2-ARGS = "Some Text"
5f7b84
 
5f7b84
 test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
5f7b84
 tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
5f7b84
 tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
5f7b84
+tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace
5f7b84
 
5f7b84
 generated += test-fmemopen.mtrace test-fmemopen.check
5f7b84
 generated += tst-fopenloc.mtrace tst-fopenloc.check
5f7b84
@@ -166,6 +172,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check
5f7b84
 aux	:= fileops genops stdfiles stdio strops
5f7b84
 
5f7b84
 ifeq ($(build-shared),yes)
5f7b84
+generated += tst-bz24228.mtrace tst-bz24228.check
5f7b84
 aux	+= oldfileops oldstdfiles
5f7b84
 endif
5f7b84
 
5f7b84
@@ -180,7 +187,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \
5f7b84
 ifeq (yes,$(build-shared))
5f7b84
 # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
5f7b84
 # library is enabled since they depend on tst-fopenloc.out.
5f7b84
-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
5f7b84
+tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
5f7b84
+		 $(objpfx)tst-bz24228-mem.out
5f7b84
 endif
5f7b84
 endif
5f7b84
 
5f7b84
@@ -232,3 +240,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out
5f7b84
 $(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out
5f7b84
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \
5f7b84
 	$(evaluate-test)
5f7b84
+
5f7b84
+$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out
5f7b84
+	$(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \
5f7b84
+	$(evaluate-test)
5f7b84
diff --git a/libio/genops.c b/libio/genops.c
5f7b84
index 2fec221b99729718..a8241dd26640bbcb 100644
5f7b84
--- a/libio/genops.c
5f7b84
+++ b/libio/genops.c
5f7b84
@@ -789,9 +789,16 @@ _IO_unbuffer_all (void)
5f7b84
 
5f7b84
   for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain)
5f7b84
     {
5f7b84
+      int legacy = 0;
5f7b84
+
5f7b84
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
5f7b84
+      if (__glibc_unlikely (_IO_vtable_offset (fp) != 0))
5f7b84
+	legacy = 1;
5f7b84
+#endif
5f7b84
+
5f7b84
       if (! (fp->_flags & _IO_UNBUFFERED)
5f7b84
 	  /* Iff stream is un-orientated, it wasn't used. */
5f7b84
-	  && fp->_mode != 0)
5f7b84
+	  && (legacy || fp->_mode != 0))
5f7b84
 	{
5f7b84
 #ifdef _IO_MTSAFE_IO
5f7b84
 	  int cnt;
5f7b84
@@ -805,7 +812,7 @@ _IO_unbuffer_all (void)
5f7b84
 	      __sched_yield ();
5f7b84
 #endif
5f7b84
 
5f7b84
-	  if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
5f7b84
+	  if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
5f7b84
 	    {
5f7b84
 	      fp->_flags |= _IO_USER_BUF;
5f7b84
 
5f7b84
@@ -816,7 +823,7 @@ _IO_unbuffer_all (void)
5f7b84
 
5f7b84
 	  _IO_SETBUF (fp, NULL, 0);
5f7b84
 
5f7b84
-	  if (fp->_mode > 0)
5f7b84
+	  if (! legacy && fp->_mode > 0)
5f7b84
 	    _IO_wsetb (fp, NULL, NULL, 0);
5f7b84
 
5f7b84
 #ifdef _IO_MTSAFE_IO
5f7b84
@@ -827,7 +834,8 @@ _IO_unbuffer_all (void)
5f7b84
 
5f7b84
       /* Make sure that never again the wide char functions can be
5f7b84
 	 used.  */
5f7b84
-      fp->_mode = -1;
5f7b84
+      if (! legacy)
5f7b84
+	fp->_mode = -1;
5f7b84
     }
5f7b84
 
5f7b84
 #ifdef _IO_MTSAFE_IO
5f7b84
diff --git a/libio/tst-bz24228.c b/libio/tst-bz24228.c
5f7b84
new file mode 100644
5f7b84
index 0000000000000000..6a74500d473ceeab
5f7b84
--- /dev/null
5f7b84
+++ b/libio/tst-bz24228.c
5f7b84
@@ -0,0 +1,29 @@
5f7b84
+/* BZ #24228 check for memory corruption in legacy libio
5f7b84
+   Copyright (C) 2019 Free Software Foundation, Inc.
5f7b84
+   This file is part of the GNU C Library.
5f7b84
+
5f7b84
+   The GNU C Library is free software; you can redistribute it and/or
5f7b84
+   modify it under the terms of the GNU Lesser General Public
5f7b84
+   License as published by the Free Software Foundation; either
5f7b84
+   version 2.1 of the License, or (at your option) any later version.
5f7b84
+
5f7b84
+   The GNU C Library is distributed in the hope that it will be useful,
5f7b84
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
5f7b84
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
5f7b84
+   Lesser General Public License for more details.
5f7b84
+
5f7b84
+   You should have received a copy of the GNU Lesser General Public
5f7b84
+   License along with the GNU C Library; if not, see
5f7b84
+   <https://www.gnu.org/licenses/>.  */
5f7b84
+
5f7b84
+#include <mcheck.h>
5f7b84
+#include <support/test-driver.h>
5f7b84
+
5f7b84
+static int
5f7b84
+do_test (void)
5f7b84
+{
5f7b84
+  mtrace ();
5f7b84
+  return 0;
5f7b84
+}
5f7b84
+
5f7b84
+#include <support/test-driver.c>
5f7b84
diff --git a/libio/tst-bz24228.map b/libio/tst-bz24228.map
5f7b84
new file mode 100644
5f7b84
index 0000000000000000..4383e0817d7f5583
5f7b84
--- /dev/null
5f7b84
+++ b/libio/tst-bz24228.map
5f7b84
@@ -0,0 +1,5 @@
5f7b84
+# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c
5f7b84
+# implementation when it is available for the architecture.
5f7b84
+{
5f7b84
+  local: _IO_stdin_used;
5f7b84
+};