Skip to content

Global Buffer Underflow (OOB Write) in scan.l via embedded null byte #725

@MarcSchoenefeld

Description

@MarcSchoenefeld

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.

  1. Environment
    Target: GNU flex commit 13c8018 (HEAD -> master, origin/master, origin/HEAD)
    Compiler: clang with AddressSanitizer (-fsanitize=address)

  2. 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
  1. 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
  1. 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';
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions