Stack‑Buffer‑Overflow in llvm::ValueSymbolTable::createValueName
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
**Describe the bug**
An AddressSanitizer‑detected **stack‑buffer‑overflow** occurs in LLVM when parsing fuzzer‑generated malformed bitcode. ASan incorrectly attributes the crash to `ValueSymbolTable.cpp:113` due to compiler‑optimized inline function debug‑info mismatch; the real crash occurs inside inlined `llvm::StringMap::insert()` logic.
**To Reproduce**
Steps to reproduce the behavior:
1. Clone the llvm repository and build it refer to oss-fuzz.
```shell
export CC=clang \
CXX=clang++ \
CFLAGS='-fsanitize=address -O0 -g' \
CXXFLAGS='-fsanitize=address -O0 -g' \
LIB_FUZZING_ENGINE='-fsanitize=fuzzer'
```
2. Run the PoC using llvm-opt-fuzzer--x86_64-gvn:
**[Moderator note: binaries are not provided by the LLVM project, use at your own risk]**
`https://github.com/user-attachments/files/28141697/poc.zip`
The PoC is provided as a zip archive. After extracting, run:
```shell
./llvm-opt-fuzzer--x86_64-gvn ./poc
```
**ASAN Report**
```
./fuzzers/llvm-opt-fuzzer: Injected args: -mtriple=x86_64 -passes=gvn
INFO: found LLVMFuzzerCustomMutator (0x5570e1924140). Disabling -len_control by default.
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 148922232
INFO: Loaded 1 modules (658 inline 8-bit counters): 658 [0x5570ecc14f20, 0x5570ecc151b2),
INFO: Loaded 1 PC tables (658 PCs): 658 [0x5570ecc151b8,0x5570ecc17ad8),
./fuzzers/llvm-opt-fuzzer--x86_64-gvn: Running 1 inputs 1 time(s) each.
Running: ./crashes/poc
=================================================================
==242110==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f2e45806058 at pc 0x5570e7f4ab70 bp 0x7ffe81beef90 sp 0x7ffe81beef88
READ of size 4 at 0x7f2e45806058 thread T0
#0 0x5570e7f4ab6f in llvm::ValueSymbolTable::createValueName(llvm::StringRef, llvm::Value*) /home/hexijie/fuzz/project/llvm-project/llvm/lib/IR/ValueSymbolTable.cpp:113:7
#1 0x5570e7f3af4c in llvm::Value::setNameImpl(llvm::Twine const&) /home/hexijie/fuzz/project/llvm-project/llvm/lib/IR/Value.cpp:375:24
#2 0x5570e7f3b678 in llvm::Value::setName(llvm::Twine const&) /home/hexijie/fuzz/project/llvm-project/llvm/lib/IR/Value.cpp:394:3
#3 0x5570e809644b in (anonymous namespace)::BitcodeReader::recordValue(llvm::SmallVectorImpl&, unsigned int, llvm::Triple&) /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:2990:6
#4 0x5570e808768d in (anonymous namespace)::BitcodeReader::parseValueSymbolTable(unsigned long) /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:3150:36
#5 0x5570e806be76 in (anonymous namespace)::BitcodeReader::parseFunctionBody(llvm::Function*) /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:5043:25
#6 0x5570e805d420 in (anonymous namespace)::BitcodeReader::materialize(llvm::GlobalValue*) /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:7077:19
#7 0x5570e805f632 in (anonymous namespace)::BitcodeReader::materializeModule() /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:7172:21
#8 0x5570e7ea5c6c in llvm::Module::materializeAll() /home/hexijie/fuzz/project/llvm-project/llvm/lib/IR/Module.cpp:488:13
#9 0x5570e8046291 in llvm::BitcodeModule::getModuleImpl(llvm::LLVMContext&, bool, bool, bool, llvm::ParserCallbacks) /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:8668:24
#10 0x5570e8052bee in llvm::BitcodeModule::parseModule(llvm::LLVMContext&, llvm::ParserCallbacks) /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:8848:10
#11 0x5570e80530a2 in llvm::parseBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext&, llvm::ParserCallbacks) /home/hexijie/fuzz/project/llvm-project/llvm/lib/Bitcode/Reader/BitcodeReader.cpp:8860:14
#12 0x5570e8037f9c in llvm::parseModule(unsigned char const*, unsigned long, llvm::LLVMContext&) /home/hexijie/fuzz/project/llvm-project/llvm/lib/FuzzMutate/IRMutator.cpp:765:12
#13 0x5570e803885e in llvm::parseAndVerify(unsigned char const*, unsigned long, llvm::LLVMContext&) /home/hexijie/fuzz/project/llvm-project/llvm/lib/FuzzMutate/IRMutator.cpp:787:12
#14 0x5570e1924dc7 in LLVMFuzzerTestOneInput /home/hexijie/fuzz/project/llvm-project/llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp:118:12
#15 0x5570e182d204 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) crtstuff.c
#16 0x5570e1816316 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) crtstuff.c
#17 0x5570e181bdca in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) crtstuff.c
#18 0x5570e18465e6 in main (/home/hexijie/fuzz/fuzzers/llvm-opt-fuzzer--x86_64-gvn+0x90425e6) (BuildId: 1fa97fea3ac0ae5f)
#19 0x7f2e4722a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#20 0x7f2e4722a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#21 0x5570e1810ee4 in _start (/home/hexijie/fuzz/fuzzers/llvm-opt-fuzzer--x86_64-gvn+0x900cee4) (BuildId: 1fa97fea3ac0ae5f)
Address 0x7f2e45806058 is located in stack of thread T0 at offset 88 in frame
#0 0x5570e1924b7f in LLVMFuzzerTestOneInput /home/hexijie/fuzz/project/llvm-project/llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp:107
This frame has 17 object(s):
[32, 40) 'agg.tmp.i'
[64, 72) 'Context' (line 117)
[96, 104) 'M' (line 118) <== Memory access at offset 88 underflows this variable
[128, 184) 'agg.tmp'
[224, 1136) 'ref.tmp' (line 128)
[1264, 3552) 'PB' (line 135)
[3680, 3708) 'agg.tmp20'
[3744, 3896) 'agg.tmp21'
[3968, 3976) 'agg.tmp23'
[4000, 4096) 'LAM' (line 137)
[4128, 4224) 'FAM' (line 138)
[4256, 4352) 'CGAM' (line 139)
[4384, 4408) 'MPM' (line 140)
[4448, 4544) 'MAM' (line 141)
[4576, 4584) 'Err' (line 149)
[4608, 4616) 'agg.tmp31'
[4640, 4736) 'agg.tmp.ensured'
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 /home/hexijie/fuzz/project/llvm-project/llvm/lib/IR/ValueSymbolTable.cpp:113:7 in llvm::ValueSymbolTable::createValueName(llvm::StringRef, llvm::Value*)
Shadow bytes around the buggy address:
0x7f2e45805d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f2e45805e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f2e45805e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f2e45805f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f2e45805f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7f2e45806000: f1 f1 f1 f1 f8 f2 f2 f2 00 f2 f2[f2]00 f2 f2 f2
0x7f2e45806080: 00 00 00 00 00 00 00 f2 f2 f2 f2 f2 f8 f8 f8 f8
0x7f2e45806100: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x7f2e45806180: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x7f2e45806200: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x7f2e45806280: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
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
==242110==ABORTING
```
**Cause**
When parsing malformed bitcode, an out-of-bounds stack write occurs during symbol table insertion. All high-level objects inspected (`this`, `vmap`, input `StringRef Name`) are valid. The crash happens inside optimized inline code, likely due to incorrect stack offset calculation for stack-allocated temporary values during `StringMap` insertion.
- ASan-reported line: `llvm/lib/IR/ValueSymbolTable.cpp:113` (misreported due to compiler optimizations)
- Actual crash location: inlined `StringMap::insert()` at `llvm/include/llvm/ADT/StringMap.h:342`
- Faulty assembly instruction:
```
mov qword ptr [rbx + 0x48], r12
```
- `rbx = 0x7fffffffbe40`
**Screenshots**
- The crashing assembly instruction that causes stack-buffer-overflow
- `rbx = 0x7fffffffbe40` is a valid user-space stack address (confirmed by pwndbg stack layout)
- Program state immediately before the illegal memory write
**Platform (please complete the following information):**
- OS: Ubuntu 22.04 (x86_64)
- Version: commit 3b3a3c2062400d8571d64f57e7fd7bc520824162
Contributor guide
Assessment
This issue has not been assessed yet.