When parsing an %option directive containing a quoted string, if the input file contains a literal null byte (\0) immediately following the opening quote, strlen() evaluates to 0. The subsequent attempt to strip the trailing quote results in an index -1 write, corrupting the memory immediately preceding the nmstr buffer.
Depending on the compiler and memory layout, this null-byte underflow can corrupt adjacent global variables, leading to undefined behavior during C-code generation.
-
Environment
Target: GNU flex commit 13c8018 (HEAD -> master, origin/master, origin/HEAD)
Compiler: clang with AddressSanitizer (-fsanitize=address)
-
Reproduction Steps
I have attached the minimized 14-byte PoC. Because copying and pasting null bytes can be tricky, you can reconstruct it via printf:
# 1. Generate the PoC
printf '\x25\x6f\x70\x74\x69\x6f\x6e\x65\x6d\x69\x74\x22\x00\x22' > poc.l
# 2. Run flex
./src/flex -o /dev/null poc.l
- ASAN Trace Summary
==ERROR: AddressSanitizer: global-buffer-overflow ...
WRITE of size 1 at 0x5f0f489a2e3f thread T0
#0 0x5f0f47f17fd0 in flexscan flex/src/scan.l:490:31
#1 0x5f0f47efb830 in yylex flex/src/yylex.c:51:13
0x5f0f489a2e3f is located 1 bytes before global variable 'nmstr' of size 2048
- Root Cause & Suggested Patch
In src/scan.l (around line 490), the code attempts to strip a trailing character without verifying that the string has a length greater than 0:
nmstr[strlen( nmstr ) - 1] = '\0';
If a null byte is embedded in the token, strlen(nmstr) evaluates to 0, resulting in nmstr[-1] = '\0'.
Suggested Fix:
Add a bounds check to ensure the string is not empty before decrementing:
size_t len = strlen(nmstr);
if (len > 0) {
nmstr[len - 1] = '\0';
}
When parsing an %option directive containing a quoted string, if the input file contains a literal null byte (\0) immediately following the opening quote, strlen() evaluates to 0. The subsequent attempt to strip the trailing quote results in an index -1 write, corrupting the memory immediately preceding the nmstr buffer.
Depending on the compiler and memory layout, this null-byte underflow can corrupt adjacent global variables, leading to undefined behavior during C-code generation.
Environment
Target: GNU flex commit 13c8018 (HEAD -> master, origin/master, origin/HEAD)
Compiler: clang with AddressSanitizer (-fsanitize=address)
Reproduction Steps
I have attached the minimized 14-byte PoC. Because copying and pasting null bytes can be tricky, you can reconstruct it via printf:
In src/scan.l (around line 490), the code attempts to strip a trailing character without verifying that the string has a length greater than 0:
If a null byte is embedded in the token, strlen(nmstr) evaluates to 0, resulting in nmstr[-1] = '\0'.
Suggested Fix:
Add a bounds check to ensure the string is not empty before decrementing: