WebAssembly / WebAssembly/wabt

[Bug] Heap-buffer-overflow in wabt::AST::InsertNode within wasm-decompile

Open
#2,679 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

sanitizer failures wasm-decompile
Dominant language
C++
Stars
8.1k
Forks
827
Avg merge
4d 6h
Merged PRs (30d)
18

Description

Description

We encountered a Heap-buffer-overflow vulnerability in the wasm-decompile tool. The crash occurs in wabt::AST::InsertNode when processing a specific WebAssembly binary.

The AddressSanitizer (ASan) report indicates that the memory being accessed was freed during a std::vector reallocation (_M_realloc_insert). This suggests a Pointer Invalidation issue where a pointer/reference to a vector element is retained and dereferenced after the vector has been resized and its underlying memory freed.

This issue was reproduced in a Release build (with NDEBUG defined), indicating it is a security vulnerability that affects production environments, potentially leading to Denial of Service (DoS) or memory corruption.

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-buffer-overflow (CWE-119 / CWE-416)
  • Faulting Instruction: READ of size 8
  • Location: wabt::AST::InsertNode
  • Root Cause Analysis: The stack trace reveals the following sequence:
  1. A std::vectorwabt::Node undergoes reallocation (expansion) via std::vector::_M_realloc_insert.
  2. The vector frees its old memory buffer (operator delete is called).
  3. wabt::AST::InsertNode subsequently attempts to read from a memory address located in that old, freed buffer.
  4. This implies that InsertNode is using a stale pointer or reference to a node that became invalid when the vector resized.
Reproduce
./wasm-decompile ./repro

Download Link: repro

ASAN report

==65981==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x510000000da0 at pc 0x557e6304794a bp 0x7ffc049d18d0 sp 0x7ffc049d18c8
READ of size 8 at 0x510000000da0 thread T0
    #0 0x557e63047949 in wabt::AST::InsertNode(wabt::NodeType, wabt::ExprType, wabt::Expr const*, unsigned int) (/src/repro/wabt/bin/wasm-decompile+0x1c0949) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #1 0x557e6303fc7a in wabt::AST::Construct(wabt::intrusive_list<wabt::Expr> const&, unsigned int, unsigned int, bool) (/src/repro/wabt/bin/wasm-decompile+0x1b8c7a) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #2 0x557e63047141 in wabt::AST::Construct(wabt::Expr const&) (/src/repro/wabt/bin/wasm-decompile+0x1c0141) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #3 0x557e6303e83a in wabt::AST::Construct(wabt::intrusive_list<wabt::Expr> const&, unsigned int, unsigned int, bool) (/src/repro/wabt/bin/wasm-decompile+0x1b783a) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #4 0x557e630394f1 in wabt::Decompiler::Decompile[abi:cxx11]() (/src/repro/wabt/bin/wasm-decompile+0x1b24f1) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #5 0x557e630372a6 in wabt::Decompile[abi:cxx11](wabt::Module const&, wabt::DecompileOptions const&) (/src/repro/wabt/bin/wasm-decompile+0x1b02a6) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #6 0x557e62fd3941 in ProgramMain(int, char**) (/src/repro/wabt/bin/wasm-decompile+0x14c941) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #7 0x7f3decb4e1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #8 0x7f3decb4e28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #9 0x557e62ef7584 in _start (/src/repro/wabt/bin/wasm-decompile+0x70584) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)

0x510000000da0 is located 2976 bytes after 192-byte region [0x510000000140,0x510000000200)
freed by thread T0 here:
    #0 0x557e62fd1271 in operator delete(void*) (/src/repro/wabt/bin/wasm-decompile+0x14a271) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #1 0x557e6304b23f in void std::vector<wabt::Node, std::allocator<wabt::Node>>::_M_realloc_insert<wabt::Node>(__gnu_cxx::__normal_iterator<wabt::Node*, std::vector<wabt::Node, std::allocator<wabt::Node>>>, wabt::Node&&) (/src/repro/wabt/bin/wasm-decompile+0x1c423f) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)

previously allocated by thread T0 here:
    #0 0x557e62fd09f1 in operator new(unsigned long) (/src/repro/wabt/bin/wasm-decompile+0x1499f1) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)
    #1 0x557e6304acfa in void std::vector<wabt::Node, std::allocator<wabt::Node>>::_M_realloc_insert<wabt::Node>(__gnu_cxx::__normal_iterator<wabt::Node*, std::vector<wabt::Node, std::allocator<wabt::Node>>>, wabt::Node&&) (/src/repro/wabt/bin/wasm-decompile+0x1c3cfa) (BuildId: b44cadef6a2094e740cb6ce71ee9a45cfac22974)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/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:
  0x510000000b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x510000000d80: fa fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa
  0x510000000e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000e80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000f00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000f80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000001000: 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
==65981==ABORTING

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the wasm-decompile entry point and wabt::AST::InsertNode, then reproduce the report using the provided ./wasm-decompile ./repro command and the clang-release-asan build. Trace the reported std::vector reallocation and verify that the supplied repro no longer triggers the ASan heap-buffer-overflow.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, wasm
Domain
compilers, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.