-
Notifications
You must be signed in to change notification settings - Fork 789
Open
Labels
Description
Description
We encountered a Heap-use-after-free (UAF) vulnerability in the wasm-decompile tool of the WABT project. The crash occurs during the decompilation process when wabt::AST::InsertNode attempts to read from a memory region that has already been freed.
Unlike common assertion failures, this issue was reproduced in a Release build (with NDEBUG defined) using AddressSanitizer, indicating a critical memory corruption vulnerability that affects production environments.
Environment
- OS: Linux x86_64
- Complier: Clang
- Build Configuration: Release mode with ASan enabled.
- Build Command:
make clang-release-asan CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=Release -DUSE_ASAN=ON -DCMAKE_CXX_FLAGS_RELEASE=-DNDEBUG"
Vulnerability Details
- Target: wasm-decompile
- Crash Type: Heap-use-after-free (CWE-416)
- Faulting Instruction: READ of size 8
- Location: wabt::AST::InsertNode (wasm-decompile+0x1c0949)
- Root Cause Analysis: The ASan report indicates a use-after-free scenario:
- Allocation: Memory was allocated by operator new via std::_Rb_tree..._M_insert_range_unique (likely inserting into a map/set structure).
- Free: The memory was subsequently freed by operator delete in ProgramMain -> std::_Rb_tree..._M_erase.
- Use: The freed memory was later accessed by wabt::AST::InsertNode during wabt::Decompiler::Decompile.
The stack trace suggests that the AST construction logic is referencing data that has been prematurely destroyed in the main program flow.
Reproduce
./wasm-decompile ./repro
Download Link: repro
ASAN report
==65817==ERROR: AddressSanitizer: heap-use-after-free on address 0x504000000a20 at pc 0x56263508594a bp 0x7ffc2d924fe0 sp 0x7ffc2d924fd8
READ of size 8 at 0x504000000a20 thread T0
#0 0x562635085949 in wabt::AST::InsertNode(wabt::NodeType, wabt::ExprType, wabt::Expr const*, unsigned int) (/src/repro/wabt/bin/wasm-decompile+0x1c0949) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#1 0x56263507c83a in wabt::AST::Construct(wabt::intrusive_list<wabt::Expr> const&, unsigned int, unsigned int, bool) (/src/repro/wabt/bin/wasm-decompile+0x1b783a) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#2 0x5626350774f1 in wabt::Decompiler::Decompile[abi:cxx11]() (/src/repro/wabt/bin/wasm-decompile+0x1b24f1) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#3 0x5626350752a6 in wabt::Decompile[abi:cxx11](wabt::Module const&, wabt::DecompileOptions const&) (/src/repro/wabt/bin/wasm-decompile+0x1b02a6) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#4 0x562635011941 in ProgramMain(int, char**) (/src/repro/wabt/bin/wasm-decompile+0x14c941) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#5 0x7ff08f0ef1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#6 0x7ff08f0ef28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#7 0x562634f35584 in _start (/src/repro/wabt/bin/wasm-decompile+0x70584) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
0x504000000a20 is located 16 bytes inside of 48-byte region [0x504000000a10,0x504000000a40)
freed by thread T0 here:
#0 0x56263500f271 in operator delete(void*) (/src/repro/wabt/bin/wasm-decompile+0x14a271) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#1 0x5626350794ef in std::_Rb_tree<std::basic_string_view<char, std::char_traits<char>>, std::basic_string_view<char, std::char_traits<char>>, std::_Identity<std::basic_string_view<char, std::char_traits<char>>>, std::less<std::basic_string_view<char, std::char_traits<char>>>, std::allocator<std::basic_string_view<char, std::char_traits<char>>>>::_M_erase(std::_Rb_tree_node<std::basic_string_view<char, std::char_traits<char>>>*) (/src/repro/wabt/bin/wasm-decompile+0x1b44ef) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#2 0x562635011919 in ProgramMain(int, char**) (/src/repro/wabt/bin/wasm-decompile+0x14c919) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#3 0x7ff08f0ef1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#4 0x7ff08f0ef28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#5 0x562634f35584 in _start (/src/repro/wabt/bin/wasm-decompile+0x70584) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
previously allocated by thread T0 here:
#0 0x56263500e9f1 in operator new(unsigned long) (/src/repro/wabt/bin/wasm-decompile+0x1499f1) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
#1 0x56263509d8a0 in std::enable_if<__same_value_type<std::basic_string_view<char, std::char_traits<char>> const*>::value, void>::type std::_Rb_tree<std::basic_string_view<char, std::char_traits<char>>, std::basic_string_view<char, std::char_traits<char>>, std::_Identity<std::basic_string_view<char, std::char_traits<char>>>, std::less<std::basic_string_view<char, std::char_traits<char>>>, std::allocator<std::basic_string_view<char, std::char_traits<char>>>>::_M_insert_range_unique<std::basic_string_view<char, std::char_traits<char>> const*>(std::basic_string_view<char, std::char_traits<char>> const*, std::basic_string_view<char, std::char_traits<char>> const*) (/src/repro/wabt/bin/wasm-decompile+0x1d88a0) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
SUMMARY: AddressSanitizer: heap-use-after-free (/src/repro/wabt/bin/wasm-decompile+0x1c0949) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974) in wabt::AST::InsertNode(wabt::NodeType, wabt::ExprType, wabt::Expr const*, unsigned int)
Shadow bytes around the buggy address:
0x504000000780: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
0x504000000800: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
0x504000000880: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
0x504000000900: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
0x504000000980: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
=>0x504000000a00: fa fa fd fd[fd]fd fd fd fa fa 00 00 00 00 00 00
0x504000000a80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x504000000b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x504000000b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x504000000c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x504000000c80: 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
==65817==ABORTING