Skip to content

[Bug] Heap Buffer Overflow in WasmBinaryReader::readExpression #8089

@oneafter

Description

@oneafter

Desciprtion

We discovered a Heap Buffer Overflow vulnerability in wasm-opt. The crash occurs within the WasmBinaryReader::readExpression function when parsing a malformed WebAssembly binary.

The issue appears to be an Out-of-Bounds Read where the parser attempts to read a byte past the end of the input buffer, specifically while processing Data Segments.

Environment

  • OS: Linux x86_64
  • Complier: Clang with -fsanitize=address
  • Tools: AddressSanitizer

Vulnerability Details

  • Target: wasm-opt
  • Vulnerability Type: Heap Buffer Overflow
  • Location: src/wasm/wasm-binary.cpp:4736

The ASAN report indicates the crash happens immediately after a memory allocation for the file content, suggesting the parser reaches the EOF unexpectedly but tries to consume more bytes.

Reproduce

./wasm-opt repro -o /dev/null

Download Link: repro

ASAN report

==27855==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x512000000450 at pc 0x7fcc583639f6 bp 0x7ffe4a441f50 sp 0x7ffe4a441f48
READ of size 1 at 0x512000000450 thread T0
    #0 0x7fcc583639f5 in wasm::WasmBinaryReader::readExpression() /src/binaryen/src/wasm/wasm-binary.cpp:4736:10
    #1 0x7fcc58326082 in wasm::WasmBinaryReader::readDataSegments() /src/binaryen/src/wasm/wasm-binary.cpp:4865:22
    #2 0x7fcc58306962 in wasm::WasmBinaryReader::read() /src/binaryen/src/wasm/wasm-binary.cpp:2092:9
    #3 0x7fcc583bd63c in wasm::ModuleReader::readBinaryData(std::vector<char, std::allocator<char>>&, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) /src/binaryen/src/wasm/wasm-io.cpp:67:10
    #4 0x7fcc583bddc7 in wasm::ModuleReader::readBinary(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) /src/binaryen/src/wasm/wasm-io.cpp:78:3
    #5 0x7fcc583bf68d in wasm::ModuleReader::read(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) /src/binaryen/src/wasm/wasm-io.cpp:101:5
    #6 0x55b42ff0568c in main /src/binaryen/src/tools/wasm-opt.cpp:319:14
    #7 0x7fcc5503f1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #8 0x7fcc5503f28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #9 0x55b42fb7a164 in _start (/src/binaryen/build/bin/wasm-opt+0x7a164) (BuildId: 0854baef848e0e3aca2fa54cd3656fe250c93259)

0x512000000450 is located 0 bytes after 272-byte region [0x512000000340,0x512000000450)
allocated by thread T0 here:
    #0 0x55b42fc5b611 in operator new(unsigned long) (/src/binaryen/build/bin/wasm-opt+0x15b611) (BuildId: 0854baef848e0e3aca2fa54cd3656fe250c93259)
    #1 0x7fcc5811c2fd in std::__new_allocator<char>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27
    #2 0x7fcc5811c2fd in std::allocator_traits<std::allocator<char>>::allocate(std::allocator<char>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20
    #3 0x7fcc5811c2fd in std::_Vector_base<char, std::allocator<char>>::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20
    #4 0x7fcc5811c2fd in std::_Vector_base<char, std::allocator<char>>::_M_create_storage(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:398:33
    #5 0x7fcc5811c2fd in std::_Vector_base<char, std::allocator<char>>::_Vector_base(unsigned long, std::allocator<char> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:335:9
    #6 0x7fcc5811c2fd in std::vector<char, std::allocator<char>>::vector(unsigned long, char const&, std::allocator<char> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:571:9
    #7 0x7fcc5811c2fd in std::vector<char, std::allocator<char>> wasm::read_file<std::vector<char, std::allocator<char>>>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, wasm::Flags::BinaryOption) /src/binaryen/src/support/file.cpp:75:5
    #8 0x7fcc583bdbbb in wasm::ModuleReader::readBinary(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) /src/binaryen/src/wasm/wasm-io.cpp:77:14
    #9 0x7fcc583bf68d in wasm::ModuleReader::read(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) /src/binaryen/src/wasm/wasm-io.cpp:101:5
    #10 0x55b42ff0568c in main /src/binaryen/src/tools/wasm-opt.cpp:319:14
    #11 0x7fcc5503f1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #12 0x7fcc5503f28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #13 0x55b42fb7a164 in _start (/src/binaryen/build/bin/wasm-opt+0x7a164) (BuildId: 0854baef848e0e3aca2fa54cd3656fe250c93259)

SUMMARY: AddressSanitizer: heap-buffer-overflow /src/binaryen/src/wasm/wasm-binary.cpp:4736:10 in wasm::WasmBinaryReader::readExpression()
Shadow bytes around the buggy address:
  0x512000000180: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x512000000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x512000000280: 00 00 00 00 00 00 00 00 00 00 00 00 05 fa fa fa
  0x512000000300: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x512000000380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x512000000400: 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa
  0x512000000480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x512000000500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x512000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x512000000600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x512000000680: 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
==27855==ABORTING

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions