GBDev RGBDS v0.7.0 was discovered to contain a stack overflow via the readInterpolation
function in the rgbasm tool. During a WRITE operation, indicating an attempt to write beyond the allocated stack buffer for the symName
variable, tested against commit a37285e.
==1041978==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffff0d20 at pc 0x0000004e6099 bp 0x7fffffff0bf0 sp 0x7fffffff0be8
WRITE of size 1 at 0x7fffffff0d20 thread T0
#0 0x4e6098 in readInterpolation(unsigned long) /tmp/rgbds/src/asm/lexer.cpp:1377:15
#1 0x4e2ddd in peek() /tmp/rgbds/src/asm/lexer.cpp:907:21
#2 0x4df09e in nextChar() /tmp/rgbds/src/asm/lexer.cpp:963:10
#3 0x4df09e in yylex_NORMAL() /tmp/rgbds/src/asm/lexer.cpp:1771:11
#4 0x4def25 in yylex() /tmp/rgbds/src/asm/lexer.cpp:2435:14
#5 0x4c9760 in yyparse() /tmp/rgbds/src/asm/parser.cpp:3222:16
#6 0x4ea2e0 in main /tmp/rgbds/src/asm/main.cpp:413:6
#7 0x7ffff7a6d082 in __libc_start_main /build/glibc-wuryBv/glibc-2.31/csu/../csu/libc-start.c:308:16
#8 0x41e7cd in _start (/tmp/rgbds/build/src/rgbasm+0x41e7cd)
Address 0x7fffffff0d20 is located in stack of thread T0 at offset 288 in frame
#0 0x4e5c8f in readInterpolation(unsigned long) /tmp/rgbds/src/asm/lexer.cpp:1342
This frame has 2 object(s):
[32, 288) 'symName' (line 1346) <== Memory access at offset 288 overflows this variable
[352, 400) 'fmt' (line 1348)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /tmp/rgbds/src/asm/lexer.cpp:1377:15 in readInterpolation(unsigned long)
Shadow bytes around the buggy address:
0x10007fff6150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007fff6160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007fff6170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007fff6180: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00
0x10007fff6190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10007fff61a0: 00 00 00 00[f2]f2 f2 f2 f2 f2 f2 f2 00 00 00 00
0x10007fff61b0: 00 00 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
0x10007fff61c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007fff61d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007fff61e0: 00 00 00 00 f1 f1 f1 f1 f8 f8 f8 f8 f8 f8 f2 f2
0x10007fff61f0: f2 f2 f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f8 f2 f8 f2
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==1041978==ABORTING
{0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:
Commit reference: ef0d973
File reference: (src/asm/lexer.cpp
)
@@ -724,7 +724,7 @@ static uint32_t readBracketedMacroArgNum(void)
}
if (i == sizeof(symName)) {
warning(WARNING_LONG_STR, "Bracketed symbol name too long\n");
warning(WARNING_LONG_STR, "Bracketed symbol name too long, got truncated\n");
i--;
}
symName[i] = '\0';
@@ -1371,10 +1371,14 @@ static char const *readInterpolation(size_t depth)
break;
} else if (c == ':' && !fmt_IsFinished(&fmt)) { // Format spec, only once
shiftChar();
if (i == sizeof(symName)) {
warning(WARNING_LONG_STR, "Format spec too long, got truncated\n");
i = sizeof(symName) - 1;
}
symName[i] = '\0';
for (size_t j = 0; j < i; j++)
fmt_UseCharacter(&fmt, symName[j]);
fmt_FinishCharacters(&fmt);
symName[i] = '\0';
if (!fmt_IsValid(&fmt))
error("Invalid format spec '%s'\n", symName);
i = 0; // Now that format has been set, restart at beginning of string
@@ -1386,7 +1390,7 @@ static char const *readInterpolation(size_t depth)
}
if (i == sizeof(symName)) {
warning(WARNING_LONG_STR, "Interpolated symbol name too long\n");
warning(WARNING_LONG_STR, "Interpolated symbol name too long, got truncated\n");
i--;
}
symName[i] = '\0';
The fix now truncates long format spec strings before using them. For example, if the interpolated symbol name itself is too long to fit in the symName
buffer instead of just printing "Interpolated symbol name too long\n"
, it now prints "Interpolated symbol name too long, got truncated\n"
to indicate that the name was truncated.
CVE-2024-27501 was assigned to this.