WebAssembly / binaryen

Optimizer and compiler/toolchain library for WebAssembly
Apache License 2.0
7.42k stars 735 forks source link

A Heap-buffer-overflow problem was discovered in function wasm::WasmBinaryBuilder::visitCall(wasm::Call*) in wasm-binary.cpp #1864

Open wcventure opened 5 years ago

wcventure commented 5 years ago

Hi, there.

A Heap-buffer-overflow problem was discovered in function wasm::WasmBinaryBuilder::visitCall(wasm::Call*) in wasm-binary.cpp in wasm. A crafted wasm input can cause segment faults and I have confirmed them with address sanitizer too.

Here are the POC files. Please use "./wasm-merge $POC" to reproduce the error. BOF.zip

The ASAN dumps the stack trace as follows:

=================================================================
==5194==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x606000001858 at pc 0x000000877201 bp 0x7ffd4b516d70 sp 0x7ffd4b516d68
READ of size 8 at 0x606000001858 thread T0
    #0 0x877200 in wasm::WasmBinaryBuilder::visitCall(wasm::Call*) /binaryen/src/wasm/wasm-binary.cpp:1954:12
    #1 0x865f89 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1685:38
    #2 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
    #3 0x86047c in wasm::WasmBinaryBuilder::readExpression() /binaryen/src/wasm/wasm-binary.cpp:1326:3
    #4 0x83aee8 in wasm::WasmBinaryBuilder::readGlobals() /binaryen/src/wasm/wasm-binary.cpp:1344:18
    #5 0x816f37 in wasm::WasmBinaryBuilder::read() /binaryen/src/wasm/wasm-binary.cpp:682:9
    #6 0x912c7d 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> >) /binaryen/src/wasm/wasm-io.cpp:52:10
    #7 0x915750 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> >) /binaryen/src/wasm/wasm-io.cpp:71:5
    #8 0x60aa08 in main /binaryen/src/tools/wasm-merge.cpp:617:16
    #9 0x7fadbeaf082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #10 0x508d58 in _start (/binaryen/build/bin/wasm-merge+0x508d58)

Address 0x606000001858 is a wild pointer.
SUMMARY: AddressSanitizer: heap-buffer-overflow /binaryen/src/wasm/wasm-binary.cpp:1954:12 in wasm::WasmBinaryBuilder::visitCall(wasm::Call*)
Shadow bytes around the buggy address:
  0x0c0c7fff82b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff82c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff82d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff82e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff82f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c0c7fff8300: fa fa fa fa fa fa fa fa fa fa fa[fa]fa fa fa fa
  0x0c0c7fff8310: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8320: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8330: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8340: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8350: 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
==5194==ABORTING

$ git log

commit 45714b5fc6cf14c112bc4f188aca427464ab69d8
Author: Alon Zakai <alonzakai@gmail.com>
Date:   Thu Jan 10 19:31:20 2019 -0800

    Compare binaryen fuzz-exec to JS VMs (#1856)

    The main fuzz_opt.py script compares JS VMs, and separately runs binaryen's fuzz-exec that compares the binaryen interpreter to itself (before and after opts). This PR lets us directly compare binaryen's interpreter output to JS VMs. This found a bunch of minor things we can do better on both sides, giving more fuzz coverage.

    To enable this, a bunch of tiny fixes were needed:

    *    Add --fuzz-exec-before which is like --fuzz-exec but just runs the code before opts are run, instead of before and after.
    *    Normalize double printing (so JS and C++ print comparable things). This includes negative zero in JS, which we never printed properly til now.
    *    Various improvements to how we print fuzz-exec logging - remove unuseful things, and normalize the others across JS and C++.
    *    Properly legalize the wasm when --emit-js-wrapper (i.e., we will run the code from JS), and use that in the JS wrapper code.
kripken commented 5 years ago

Thanks! Fix in #1869.