Skip to content

Fix out of bounds write in scanner RPG rule#77

Open
Alearner12 wants to merge 1 commit into
lipnitsk:masterfrom
Alearner12:master
Open

Fix out of bounds write in scanner RPG rule#77
Alearner12 wants to merge 1 commit into
lipnitsk:masterfrom
Alearner12:master

Conversation

@Alearner12

Copy link
Copy Markdown

Bug

yylex (cue_scanner.l:128) contains an off-by-one error when parsing REM REPLAYGAIN_* fields that causes a 1-byte out-of-bounds write. When the scanner enters the <RPG> state, it copies the matched characters into the global yy_buffer (which is defined as PARSER_BUFFER / 1024 bytes).

The code currently bounds the strncpy by sizeof(yy_buffer), but then sets the null terminator at index sizeof(yy_buffer):
yylval.sval[(yyleng > sizeof(yy_buffer) ? sizeof(yy_buffer) : yyleng)] = '\0';

If the input string is exactly 1024 characters or longer, this writes \0 to yylval.sval[1024], which is 1 byte past the end of the 1024-byte yy_buffer. Because yy_buffer is a global array, this triggers a global buffer overflow, corrupting the adjacent yytext variable in memory. ASan catches this cleanly.

Reproduction

Create a minimal .cue file with a ReplayGain tag containing a value of 1024 bytes or more.
Build libcue with gcc -O1 -g -fsanitize=address and run a small harness that calls cue_parse_string() on the payload:

PERFORMER "Test"
FILE "test.wav" WAVE
  TRACK 01 AUDIO
    INDEX 01 00:00:00
REM REPLAYGAIN_ALBUM_GAIN <1024 'A's>

Running this under ASan predictably traps:

==204862==ERROR: AddressSanitizer: global-buffer-overflow on address 0x55e0511aa500
WRITE of size 1 at 0x55e0511aa500 thread T0
    #0 yylex cue_scanner.l:128
    #1 yyparse cue_parser.c:1196
    #2 cue_parse_string cue_parser.y:390

0x55e0511aa500 is located 0 bytes to the right of global variable 'yy_buffer' defined in 'cue_scanner.l:14:6' of size 1024

Fix

The fix is to just use the exact same truncation logic that the <NAME> rule (around line 46) already uses. By changing the string copy length and null termination index to sizeof(yy_buffer) - 1, we ensure there's always space for the null byte. This safely truncates any overly long ReplayGain values to fit within the buffer limits.

Verification

Tested the exact same 1024-byte and 1025-byte PoC payloads against the patched code with ASan enabled:

  • 1024-byte value: OK (no ASan trip)
  • 1025-byte value: OK (no ASan trip)
  • Normal input: OK (no ASan trip)

All previously-OOB lengths are now safely truncated, and in-bounds values are processed just like before. No other existing logic or parsing rules are affected since the change is isolated to the RPG state handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant