Security Fix: response file (-@) option parsing UAF affecting debug format selection (-F / -g) #189
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hi, this PR addresses a UAF bug here.
Summary
This PR fixes a UAF triggered when NASM parses options from a response file (
-@ <file>) and later resolves the debug format (e.g., viadfmt_find()/strcasecmp()).The issue is reproducible in the newest commit 22a9118.
Output
==1015601==ERROR: AddressSanitizer: heap-use-after-free on address 0x7c4402be0102 at pc 0x000000419be7 bp 0x7fff758ba8c0 sp 0x7fff758ba070 READ of size 1 at 0x7c4402be0102 thread T0 #0 0x000000419be6 in strcasecmp (/data/nasm/build-sanitize/nasm+0x419be6) (BuildId: 0d1cdac1ac1d130f5d6c4f82c13144ff22a7fee3) #1 0x00000053ee53 in dfmt_find /data/nasm/build-sanitize/../output/outform.c:51:14 #2 0x0000004dd8c2 in main /data/nasm/build-sanitize/../asm/nasm.c:517:16 #3 0x7f8403846574 in __libc_start_call_main (/lib64/libc.so.6+0x3574) (BuildId: 48c4b9b1efb1df15da8e787f489128bf31893317) #4 0x7f8403846627 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3627) (BuildId: 48c4b9b1efb1df15da8e787f489128bf31893317) #5 0x000000400824 in _start (/data/nasm/build-sanitize/nasm+0x400824) (BuildId: 0d1cdac1ac1d130f5d6c4f82c13144ff22a7fee3) 0x7c4402be0102 is located 2 bytes inside of 128-byte region [0x7c4402be0100,0x7c4402be0180) freed by thread T0 here: #0 0x0000004a220a in free (/data/nasm/build-sanitize/nasm+0x4a220a) (BuildId: 0d1cdac1ac1d130f5d6c4f82c13144ff22a7fee3) #1 0x000000590ba5 in nasm_free /data/nasm/build-sanitize/../nasmlib/alloc.c:78:9 #2 0x0000004e25ba in process_respfile /data/nasm/build-sanitize/../asm/nasm.c:1370:13 #3 0x0000004e25ba in open_and_process_respfile /data/nasm/build-sanitize/../asm/nasm.c:1444:9 #4 0x0000004e1305 in process_arg /data/nasm/build-sanitize/../asm/nasm.c:956:13 #5 0x0000004dfd19 in parse_cmdline /data/nasm/build-sanitize/../asm/nasm.c:1490:19 #6 0x0000004dd873 in main /data/nasm/build-sanitize/../asm/nasm.c:505:5 #7 0x7f8403846574 in __libc_start_call_main (/lib64/libc.so.6+0x3574) (BuildId: 48c4b9b1efb1df15da8e787f489128bf31893317) #8 0x7f8403846627 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3627) (BuildId: 48c4b9b1efb1df15da8e787f489128bf31893317) #9 0x000000400824 in _start (/data/nasm/build-sanitize/nasm+0x400824) (BuildId: 0d1cdac1ac1d130f5d6c4f82c13144ff22a7fee3) previously allocated by thread T0 here: #0 0x0000004a24a8 in malloc (/data/nasm/build-sanitize/nasm+0x4a24a8) (BuildId: 0d1cdac1ac1d130f5d6c4f82c13144ff22a7fee3) #1 0x000000590a68 in nasm_malloc /data/nasm/build-sanitize/../nasmlib/alloc.c:25:9 #2 0x0000004e228b in process_respfile /data/nasm/build-sanitize/../asm/nasm.c:1345:15 #3 0x0000004e228b in open_and_process_respfile /data/nasm/build-sanitize/../asm/nasm.c:1444:9 #4 0x0000004e1305 in process_arg /data/nasm/build-sanitize/../asm/nasm.c:956:13 #5 0x0000004dfd19 in parse_cmdline /data/nasm/build-sanitize/../asm/nasm.c:1490:19 #6 0x0000004dd873 in main /data/nasm/build-sanitize/../asm/nasm.c:505:5 #7 0x7f8403846574 in __libc_start_call_main (/lib64/libc.so.6+0x3574) (BuildId: 48c4b9b1efb1df15da8e787f489128bf31893317) #8 0x7f8403846627 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3627) (BuildId: 48c4b9b1efb1df15da8e787f489128bf31893317) #9 0x000000400824 in _start (/data/nasm/build-sanitize/nasm+0x400824) (BuildId: 0d1cdac1ac1d130f5d6c4f82c13144ff22a7fee3) SUMMARY: AddressSanitizer: heap-use-after-free (/data/nasm/build-sanitize/nasm+0x419be6) (BuildId: 0d1cdac1ac1d130f5d6c4f82c13144ff22a7fee3) in strcasecmp Shadow bytes around the buggy address: 0x7c4402bdfe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7c4402bdff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7c4402bdff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7c4402be0000: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd 0x7c4402be0080: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa =>0x7c4402be0100:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x7c4402be0180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7c4402be0200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7c4402be0280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7c4402be0300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7c4402be0380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 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 ==1015601==ABORTINGRoot Cause
When options are parsed from a response file, tokens are typically stored in a temporary variable that owns a heap buffer in the parser, which is also assigned to a static pointer
static const char *debug_format, without copying.After the parsing routine returns, it frees the temporary buffer. The stored pointer then becomes dangling and is used later during debug & output format lookup, triggering a UAF.
Reproduce
Create a response file that specifies a debug format, then run:
The input file A is attach here (inside the zip file):
A.zip