This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug stdio/20938] New: In variable-width charsets, _IO_wfile_sync passes a negative buffer size to __codecvt_do_length on certain inputs to fgetws resulting in SIGSEGV


https://sourceware.org/bugzilla/show_bug.cgi?id=20938

            Bug ID: 20938
           Summary: In variable-width charsets, _IO_wfile_sync passes a
                    negative buffer size to __codecvt_do_length on certain
                    inputs to fgetws resulting in SIGSEGV
           Product: glibc
           Version: 2.24
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: stdio
          Assignee: unassigned at sourceware dot org
          Reporter: catqueen2 at protonmail dot ch
  Target Milestone: ---

/* 

See this Stack Overflow question: https://stackoverflow.com/questions/40975450

The following code demonstrates the problem: 

*/ 

#include <locale.h>
#include <wchar.h>
#include <stdlib.h>
#include <stdio.h>

int main(const int argc, const char* const * const argv) {
  (void) argc;

  setlocale(LC_ALL, argv[1]);

  const size_t len = (size_t) atoi(argv[2]);

  wchar_t *buf = (wchar_t *) malloc(sizeof (wchar_t) * len),
         *stat = fgetws(buf, (int) len, stdin);

  wprintf(L"[%ls], [%ls]\n", stat, buf);

  free(buf);

  wprintf(L"we are still: %ls\n", L"alive");

  return EXIT_SUCCESS;
}

/* 

compile it like: `gcc -std=c11 main.c -o main` (-std=c++ >= 11 has the same
behaviour)
Then, try running it like: `./main C 3`, and give it 10 bytes of input. The
program works and ends normally, and Valgrind reports no memory errors.

On the other hand, if it is run with a variable-width (UTF) locale: `./main
en_US.utf8 3` and given 10 bytes of STDIN the program behaves normally, but
crashes on exiting main. Valgrind reports the following:

==2639== Invalid read of size 8
==2639==    at 0x4EAF575: _IO_wfile_sync (wfileops.c:534)
==2639==    by 0x4EB6DB1: _IO_default_setbuf (genops.c:523)
==2639==    by 0x4EB2FC8: _IO_file_setbuf@@GLIBC_2.2.5 (fileops.c:459)
==2639==    by 0x4EB79B5: _IO_unbuffer_all (genops.c:921)
==2639==    by 0x4EB79B5: _IO_cleanup (genops.c:966)
==2639==    by 0x4E73282: __run_exit_handlers (exit.c:96)
==2639==    by 0x4E73339: exit (exit.c:105)
==2639==    by 0x4E593F7: (below main) (libc-start.c:325)
==2639==  Address 0x18 is not stack'd, malloc'd or (recently) free'd

The aforementioned Stack Overflow question and answer came to the conclusion
that:

Inside _IO_wfile_sync, fp->_wide_data->_IO_read_end points to the end of the
input string L"5555555555\n", while fp->_wide_data->_IO_read_ptr is at the
third character (after reading two), and the difference is -9.

__codecvt_do_length expects an argument _IO_size_t max for a buffer size and
receives (_IO_ssize_t) -9 which is turned into, presumably, 2^word_size - 9.
Among the first lines in this function is the declaration wchar_t to_buf[max];.

This results in *increasing* the stack pointer instead of decreasing it, and
data that should have been safely stored there (among them the pointer fp of
_IO_wfile_sync(), as it ends up stored in a register rbx) is overwritten at the
first opportunity.

After the return from the function, fp is overwritten with something that does
not make sense (NULL, in this case), even though it has never been exposed to
it, and dereferencing it on line 534 of wfileops.c causes a SIGSEGV, as the
backtrace tells us.

I don't know the exact build date as I have not built libc from source (I do
not know how to tell GCC to use a completely different libc).

The GLibC version is 2.24-3ubuntu1, but it does not seem this exists only in
Ubuntu repositories as it is here, too:
https://code.woboq.org/userspace/glibc/libio/wfileops.c.html#500

*/

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]