[PATCH 0/2] Fix gconv reference count overflow in swscanf
Frédéric Bérat
fberat@redhat.com
Wed Apr 29 14:59:32 GMT 2026
This series addresses a gconv module reference counter overflow
triggered by the `swscanf` family of functions.
The issue, originally reported by DJ Delorie, occurs because `swscanf`
utilizes a wide-oriented `FILE` stream allocated on the stack via
`_IO_strfile_readw`. When initialized, `_IO_fwide` implicitly clones the
global locale's gconv configuration and increments the gconv module's
reference counter (`__counter`). Because the stream is on the stack, it
cannot be cleaned up via `fclose()` (which would attempt to `free` the
stack pointer). Consequently, `__gconv_release_step` is never called,
leaking the reference counts. Over enough iterations, the 32-bit counter
overflows, resulting in a fatal abort.
Florian Weimer correctly pointed out that if we open the gconv modules
with `RTLD_NODELETE`, we wouldn't need to track references for
`dlclose`. However, upon further investigation of the codebase, removing
the `__counter` tracking entirely is not viable without introducing
catastrophic memory bugs.
The `__counter` member dictates the execution of `gconv_end()`. Several
complex encodings (such as `UTF-16`) dynamically allocate memory during
`gconv_init()` and attach it to `step->__data`. If we remove
`__counter`, we face an unsolvable dilemma during stream teardown: 1. If
we never call `gconv_end()`, we permanently leak `step->__data` memory
every time a dynamic step array is freed (e.g., from the mmap cache). 2.
If we unconditionally call `gconv_end()`, the stack stream destroys the
`step->__data` state that the global locale (and other concurrent
threads) still rely on, leading to immediate use-after-free conditions.
Therefore, reference counting must be maintained to safely manage the
`step->__data` lifecycle.
This patch series follows Adhemerval Zanella Netto's suggestion to
introduce a targeted internal `fclose` equivalent. We introduce
`_IO_wstrfile_fclose_stack()`, which safely releases the gconv reference
counters and finishes the stream without attempting to deallocate the
`FILE` struct. This new function is then hooked into all 13
implementations of `swscanf` across the tree.
Fred.
--
Frédéric Bérat (2):
libio: Fix gconv module reference counter overflow in swscanf
wcsmbs: Add gconv module ref counter overflow test
libio/iofwide.c | 15 ++++++
libio/iovswscanf.c | 4 +-
libio/libioP.h | 1 +
libio/swscanf.c | 2 +-
.../ieee128-isoc23_swscanf.c | 2 +-
.../ieee128-isoc23_vswscanf.c | 4 +-
.../ieee128-isoc99_swscanf.c | 2 +-
.../ieee128-isoc99_vswscanf.c | 4 +-
.../ldbl-128ibm-compat/ieee128-swscanf.c | 2 +-
.../ldbl-128ibm-compat/ieee128-vswscanf.c | 4 +-
sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 12 +++--
wcsmbs/Makefile | 3 +-
wcsmbs/isoc23_swscanf.c | 2 +-
wcsmbs/isoc23_vswscanf.c | 4 +-
wcsmbs/isoc99_swscanf.c | 2 +-
wcsmbs/isoc99_vswscanf.c | 4 +-
wcsmbs/tst-wcsmbs-clone-overflow.c | 50 +++++++++++++++++++
17 files changed, 101 insertions(+), 16 deletions(-)
create mode 100644 wcsmbs/tst-wcsmbs-clone-overflow.c
--
2.54.0
More information about the Libc-alpha
mailing list