Bug 24228 - old x86 applications that use legacy libio crash on exit
Summary: old x86 applications that use legacy libio crash on exit
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: stdio (show other bugs)
Version: 2.23
: P2 normal
Target Milestone: 2.30
Assignee: Dmitry V. Levin
URL: https://bugzilla.altlinux.org/36065
Keywords:
Depends on:
Blocks:
 
Reported: 2019-02-18 12:41 UTC by Dmitry V. Levin
Modified: 2019-09-21 19:50 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dmitry V. Levin 2019-02-18 12:41:44 UTC
According to report in https://bugzilla.altlinux.org/36065,
old x86 applications that use legacy libio crash on exit under valgrind:
$ valgrind ./cat /dev/null
==26578== Memcheck, a memory error detector
==26578== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==26578== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==26578== Command: ./cat /dev/null
==26578==
==26578== Invalid read of size 4
==26578==    at 0x40B0AFA: _IO_wsetb (wgenops.c:96)
==26578==    by 0x40BB681: _IO_unbuffer_all (genops.c:883)
==26578==    by 0x40BB681: _IO_cleanup (genops.c:930)
==26578==    by 0x4076E01: __run_exit_handlers (exit.c:130)
==26578==    by 0x4076E40: exit (exit.c:139)
==26578==    by 0x804991F: ??? (in /usr/src/cat)
==26578==    by 0x8048EB9: ??? (in /usr/src/cat)
==26578==  Address 0x18 is not stack'd, malloc'd or (recently) free'd
==26578==
==26578==
==26578== Process terminating with default action of signal 11 (SIGSEGV)
==26578==  Access not within mapped region at address 0x18
==26578==    at 0x40B0AFA: _IO_wsetb (wgenops.c:96)
==26578==    by 0x40BB681: _IO_unbuffer_all (genops.c:883)
==26578==    by 0x40BB681: _IO_cleanup (genops.c:930)
==26578==    by 0x4076E01: __run_exit_handlers (exit.c:130)
==26578==    by 0x4076E40: exit (exit.c:139)
==26578==    by 0x804991F: ??? (in /usr/src/cat)
==26578==    by 0x8048EB9: ??? (in /usr/src/cat)

I think this happens due to commit glibc-2.23~693 (a601b74d31ca086de38441d316a3dee24c866305) that introduced a regression:
_IO_unbuffer_all() now invokes _IO_wsetb() to free wide buffers of all files, including legacy standard files that are small statically allocated objects that do not have wide buffers.

The proposed fix is to skip _IO_wsetb() invocation for legacy standard files.
Comment 1 Dmitry V. Levin 2019-02-18 12:46:38 UTC
Proposed patch: https://sourceware.org/ml/libc-alpha/2019-02/msg00442.html
Comment 2 Florian Weimer 2019-06-19 12:15:08 UTC
I have a somewhat hacked-together reproducer.  The behavior depends on what is next to _IO_stdout_ etc. in the process image (possibly after interposition).  In most cases, fp->_mode does not appear to be positive, so we do not call _IO_wsetb by accident.
Comment 3 Florian Weimer 2019-06-19 12:23:38 UTC
Patch with a different test case:

https://sourceware.org/ml/libc-alpha/2019-02/msg00476.html
Comment 4 Florian Weimer 2019-06-19 17:40:40 UTC
Note that this also affects OpenJDK 8 binaries for i386, even if they are linked against current glibc because OpenJDK uses a linker script which suppresses output of the _IO_stdin_used variable.
Comment 5 Sourceware Commits 2019-06-20 17:41:45 UTC
The master branch has been updated by Dmitry Levin <ldv@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=21cc130b78a4db9113fb6695e2b951e697662440

commit 21cc130b78a4db9113fb6695e2b951e697662440
Author: Dmitry V. Levin <ldv@altlinux.org>
Date:   Wed Feb 13 01:20:51 2019 +0000

    libio: do not attempt to free wide buffers of legacy streams [BZ #24228]
    
    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.
Comment 6 Dmitry V. Levin 2019-06-20 17:46:08 UTC
Fixed in glibc 2.30.
Comment 7 Sourceware Commits 2019-06-21 08:28:50 UTC
The release/2.27/master branch has been updated by Dmitry Levin <ldv@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=f056ac8363442b0b14d2a7eccc2cd14c5f3b6ce2

commit f056ac8363442b0b14d2a7eccc2cd14c5f3b6ce2
Author: Dmitry V. Levin <ldv@altlinux.org>
Date:   Wed Feb 13 01:20:51 2019 +0000

    libio: do not attempt to free wide buffers of legacy streams [BZ #24228]
    
    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)
Comment 8 Sourceware Commits 2019-06-21 08:28:56 UTC
The release/2.28/master branch has been updated by Dmitry Levin <ldv@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=91b02c5b4d17d60015af24d277eb31348fc0bc34

commit 91b02c5b4d17d60015af24d277eb31348fc0bc34
Author: Dmitry V. Levin <ldv@altlinux.org>
Date:   Wed Feb 13 01:20:51 2019 +0000

    libio: do not attempt to free wide buffers of legacy streams [BZ #24228]
    
    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)
Comment 9 Sourceware Commits 2019-06-21 08:29:02 UTC
The release/2.29/master branch has been updated by Dmitry Levin <ldv@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4

commit 34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4
Author: Dmitry V. Levin <ldv@altlinux.org>
Date:   Wed Feb 13 01:20:51 2019 +0000

    libio: do not attempt to free wide buffers of legacy streams [BZ #24228]
    
    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)
Comment 10 John Paul Adrian Glaubitz 2019-09-11 15:35:49 UTC
This particular fix comes with a test that seems to be executed on all architectures even though it seems to be x86-specific.

Is this intentional?

It fails on sparc64:

----------
FAIL: libio/tst-bz24228
original exit status 138
----------

Full log: https://buildd.debian.org/status/fetch.php?pkg=glibc&arch=sparc64&ver=2.29-1&stamp=1568193377&raw=0
Comment 11 Florian Weimer 2019-09-11 15:47:21 UTC
(In reply to John Paul Adrian Glaubitz from comment #10)
> This particular fix comes with a test that seems to be executed on all
> architectures even though it seems to be x86-specific.
> 
> Is this intentional?

Yes, it affects some MIPS architectures as well.

> It fails on sparc64:
> 
> ----------
> FAIL: libio/tst-bz24228
> original exit status 138
> ----------
> 
> Full log:
> https://buildd.debian.org/status/fetch.php?pkg=glibc&arch=sparc64&ver=2.29-
> 1&stamp=1568193377&raw=0

Please open a separate bug for that and provide a build log with -O, so that make attributes error message to the right commands.  Thanks.  (Enabling -O by default should be safe for Debian glibc builds, given that make is current, and it is advertised as not affecting performance, but the build log will be slightly larger.)
Comment 12 John Paul Adrian Glaubitz 2019-09-21 19:50:08 UTC
(In reply to Florian Weimer from comment #11)
> Please open a separate bug for that and provide a build log with -O, so that
> make attributes error message to the right commands.  Thanks.  (Enabling -O
> by default should be safe for Debian glibc builds, given that make is
> current, and it is advertised as not affecting performance, but the build
> log will be slightly larger.)

Okay, working on it.