public inbox for glibc-bugs@sourceware.org help / color / mirror / Atom feed
From: "ebiggers3 at gmail dot com" <sourceware-bugzilla@sourceware.org> To: glibc-bugs@sourceware.org Subject: [Bug stdio/15362] New: fwrite() may read beyond end of specified buffer Date: Fri, 12 Apr 2013 06:37:00 -0000 [thread overview] Message-ID: <bug-15362-131@http.sourceware.org/bugzilla/> (raw) http://sourceware.org/bugzilla/show_bug.cgi?id=15362 Bug #: 15362 Summary: fwrite() may read beyond end of specified buffer Product: glibc Version: 2.17 Status: NEW Severity: critical Priority: P2 Component: stdio AssignedTo: unassigned@sourceware.org ReportedBy: ebiggers3@gmail.com Classification: Unclassified Created attachment 6979 --> http://sourceware.org/bugzilla/attachment.cgi?id=6979 Program to reproduce bug (only when write fails), and gdb backtrace I have found a bug in glibc's handling of errors in the write() system call, present in the latest version in git, that I was able to bisect down to the following commit: commit 2b766585f9b4ffabeef2f36200c275976b93f2c7 Author: Siddhesh Poyarekar <siddhesh@redhat.com> Date: Fri Nov 16 19:13:11 2012 +0530 printf should return negative value on error [BZ #11741] Fixed bug where printf and family may return a spurious success when printing padded formats. The bug can cause fwrite(), and possibly other functions, to read past the buffer it was passed. It may also be possible that data directly following the passed buffer could be written to the file. For both of these reasons I marked this bug as critical. I initially noticed this bug when fwrite() accessed memory after the buffer it was supposed to access when writing to a full filesystem. This was tested with valgrind and also confirmed by allocating the buffer with mmap() and setting PROT_NONE on the following page with mprotect(). The following describes the cause of the bug as best as I could determine from running the program in gdb and reading the glibc code: 1. fwrite() is called, which calls _IO_new_file_xsputn(), then new_do_write(), then _IO_new_file_write() in libio/fileops.c. 2. On error, _IO_new_file_write() returns -1. This behavior was introduced by commit 2b766585f9b4ffabeef2f36200c275976b93f2c7. The previous behavior was to return a short count (number of bytes written). 3. new_do_write() in libio/fileops.c returns the -1 'count' it got from _IO_new_file_write(). 4. _IO_new_file_xsputn() subtracts 'count' from 'to_do', but 'count' is (size_t)-1, causing 'to_do' to be incremented by 1. 5. Still in _IO_new_file_xsputn(): 'count', which is (size_t)-1, is not less than 'do_write', so execution continues to _IO_default_xsputn(). But the buffer passed to _IO_default_xsputn() is incremented by 'do_write' bytes, even though these bytes probably were NOT written. The buffer may now *start* at the *end* of the data that was supposed to be written, yet the length parameter may be up to 1 more than the original size passed into _IO_new_file_xsputn(). 6. In _IO_default_xsputn(): __mempcpy() attempts to fill the _IO_FILE buffer with data from the input buffer. This data may be past the end of the allowed buffer, causing a memory access violation; alternatively, the memory copy could succeed, which may cause uninitialized memory, or even memory containing sensitive information, to be passed to the underlying write() system call. How to visibly reproduce the bug: A test program 'test.c' is attached. This program simply opens a file in the current directory and writes 32768 bytes to it. The 32768 bytes are taken from a memory mapping (32768 + 4096) bytes in length, the last page of which is set to PROT_NONE to easily see the access violation. So the actual buffer passed to fwrite() is valid for exactly the provided length but no more. To easily cause write() to fail: on Linux, create an empty directory 'tmp', then mount tmpfs on it with a small size limit ('sudo mount tmpfs -t tmpfs tmp -o size=20K'). Then run the test program in this directory, which will segfault, contrary to the expected behavior. Backtrace of this is attached. I did not attach a patch because I am not otherwise highly familiar with the glibc code and am not sure I would be able to correctly fix both this problem and the problem that the problematic commit was trying to fix, but I could try to write one if no one else does. Also given the code path described above, I believe this is purely a glibc bug and does not rely on any particular compiler, kernel version, or architecture. -- Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug.
next reply other threads:[~2013-04-12 6:37 UTC|newest] Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top 2013-04-12 6:37 ebiggers3 at gmail dot com [this message] 2013-04-12 6:41 ` [Bug stdio/15362] " ebiggers3 at gmail dot com 2013-04-12 6:45 ` aj at suse dot de 2013-04-15 11:57 ` siddhesh at redhat dot com 2013-08-05 21:29 ` licquia at linuxfoundation dot org 2013-08-20 18:10 ` norman.shulman@n-dimension.com 2013-10-11 17:09 ` siddhesh at redhat dot com 2014-06-13 13:51 ` fweimer at redhat dot com
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=bug-15362-131@http.sourceware.org/bugzilla/ \ --to=sourceware-bugzilla@sourceware.org \ --cc=glibc-bugs@sourceware.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).