A Use-after-free problem was discovered in wasm::WasmBinaryBuilder::visitCall(wasm::Call*) function in wasm-binary.cpp. 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. UAF.zip
$ 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.
The ASAN dumps the stack trace as follows:
=================================================================
==12717==ERROR: AddressSanitizer: heap-use-after-free on address 0x615000000c38 at pc 0x000000877201 bp 0x7ffcfa43cb50 sp 0x7ffcfa43cb48
READ of size 8 at 0x615000000c38 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 0x86c092 in wasm::WasmBinaryBuilder::skipUnreachableCode() /binaryen/src/wasm/wasm-binary.cpp:1409:16
#3 0x861fc8 in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1384:9
#4 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#5 0x87192e in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1863:18
#6 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#7 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#8 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#9 0x87192e in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1863:18
#10 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#11 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#12 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#13 0x871a00 in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1865:21
#14 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#15 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#16 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#17 0x871a00 in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1865:21
#18 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#19 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#20 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#21 0x871a00 in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1865:21
#22 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#23 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#24 0x87031d in wasm::WasmBinaryBuilder::visitBlock(wasm::Block*) /binaryen/src/wasm/wasm-binary.cpp:1822:5
#25 0x86598a in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1679:38
#26 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#27 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#28 0x83237a in wasm::WasmBinaryBuilder::readFunctions() /binaryen/src/wasm/wasm-binary.cpp:1121:20
#29 0x8139b7 in wasm::WasmBinaryBuilder::read() /binaryen/src/wasm/wasm-binary.cpp:678:41
#30 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
#31 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
#32 0x60aa08 in main /binaryen/src/tools/wasm-merge.cpp:617:16
#33 0x7f56b3d4a82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#34 0x508d58 in _start (/binaryen/build/bin/wasm-merge+0x508d58)
0x615000000c38 is located 440 bytes inside of 512-byte region [0x615000000a80,0x615000000c80)
freed by thread T0 here:
#0 0x601fc8 in operator delete(void*) /home/wencheng/Documents/CLib/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_new_delete.cc:149
#1 0x79bed4 in __gnu_cxx::new_allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task>::deallocate(wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/ext/new_allocator.h:125:2
#2 0x79bed4 in std::allocator_traits<std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::deallocate(std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task>&, wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/alloc_traits.h:462
#3 0x79bed4 in std::_Vector_base<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task, std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::_M_deallocate(wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_vector.h:180
#4 0x79bed4 in std::_Vector_base<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task, std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::~_Vector_base() /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_vector.h:162
#5 0x79bed4 in std::vector<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task, std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::~vector() /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_vector.h:435
#6 0x79bed4 in wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::~Walker() /binaryen/src/wasm-traversal.h:276
#7 0x79bed4 in wasm::BranchUtils::BranchSeeker::hasNamed(wasm::Expression*, wasm::Name) /binaryen/src/ir/branch-utils.h:208
#8 0x79bed4 in wasm::handleUnreachable(wasm::Block*, bool, bool) /binaryen/src/wasm/wasm.cpp:198
#9 0x85c506 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1847:10
#10 0x87192e in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1863:18
#11 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#12 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#13 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#14 0x87192e in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1863:18
#15 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#16 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#17 0x87031d in wasm::WasmBinaryBuilder::visitBlock(wasm::Block*) /binaryen/src/wasm/wasm-binary.cpp:1822:5
#18 0x86598a in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1679:38
#19 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#20 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#21 0x83237a in wasm::WasmBinaryBuilder::readFunctions() /binaryen/src/wasm/wasm-binary.cpp:1121:20
#22 0x8139b7 in wasm::WasmBinaryBuilder::read() /binaryen/src/wasm/wasm-binary.cpp:678:41
#23 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
#24 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
#25 0x60aa08 in main /binaryen/src/tools/wasm-merge.cpp:617:16
#26 0x7f56b3d4a82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
previously allocated by thread T0 here:
#0 0x601250 in operator new(unsigned long) /home/wencheng/Documents/CLib/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_new_delete.cc:92
#1 0x7dcff4 in __gnu_cxx::new_allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/ext/new_allocator.h:111:27
#2 0x7dcff4 in std::allocator_traits<std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::allocate(std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/alloc_traits.h:436
#3 0x7dcff4 in std::_Vector_base<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task, std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_vector.h:172
#4 0x7dcff4 in void std::vector<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task, std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::_M_realloc_insert<void (*&)(wasm::BranchUtils::BranchSeeker*, wasm::Expression**), wasm::Expression**&>(__gnu_cxx::__normal_iterator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task*, std::vector<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task, std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> > >, void (*&)(wasm::BranchUtils::BranchSeeker*, wasm::Expression**), wasm::Expression**&) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/vector.tcc:406
#5 0x7d020a in void std::vector<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task, std::allocator<wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::Task> >::emplace_back<void (*&)(wasm::BranchUtils::BranchSeeker*, wasm::Expression**), wasm::Expression**&>(void (*&)(wasm::BranchUtils::BranchSeeker*, wasm::Expression**), wasm::Expression**&) /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/vector.tcc:105:4
#6 0x7d020a in wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::pushTask(void (*)(wasm::BranchUtils::BranchSeeker*, wasm::Expression**), wasm::Expression**) /binaryen/src/wasm-traversal.h:396
#7 0x7d020a in wasm::PostWalker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::scan(wasm::BranchUtils::BranchSeeker*, wasm::Expression**) /binaryen/src/wasm-traversal.h:487
#8 0x7ca3c1 in wasm::Walker<wasm::BranchUtils::BranchSeeker, wasm::Visitor<wasm::BranchUtils::BranchSeeker, void> >::walk(wasm::Expression*&) /binaryen/src/wasm-traversal.h:416:7
#9 0x79be62 in wasm::BranchUtils::BranchSeeker::hasNamed(wasm::Expression*, wasm::Name) /binaryen/src/ir/branch-utils.h:206:12
#10 0x79be62 in wasm::handleUnreachable(wasm::Block*, bool, bool) /binaryen/src/wasm/wasm.cpp:198
#11 0x85c506 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1847:10
#12 0x87192e in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1863:18
#13 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#14 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#15 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#16 0x87192e in wasm::WasmBinaryBuilder::visitIf(wasm::If*) /binaryen/src/wasm/wasm-binary.cpp:1863:18
#17 0x866693 in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1680:38
#18 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#19 0x87031d in wasm::WasmBinaryBuilder::visitBlock(wasm::Block*) /binaryen/src/wasm/wasm-binary.cpp:1822:5
#20 0x86598a in wasm::WasmBinaryBuilder::readExpression(wasm::Expression*&) /binaryen/src/wasm/wasm-binary.cpp:1679:38
#21 0x86135e in wasm::WasmBinaryBuilder::processExpressions() /binaryen/src/wasm/wasm-binary.cpp:1359:16
#22 0x85c0b2 in wasm::WasmBinaryBuilder::getBlockOrSingleton(wasm::Type) /binaryen/src/wasm/wasm-binary.cpp:1838:3
#23 0x83237a in wasm::WasmBinaryBuilder::readFunctions() /binaryen/src/wasm/wasm-binary.cpp:1121:20
#24 0x8139b7 in wasm::WasmBinaryBuilder::read() /binaryen/src/wasm/wasm-binary.cpp:678:41
#25 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
#26 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
#27 0x60aa08 in main /binaryen/src/tools/wasm-merge.cpp:617:16
#28 0x7f56b3d4a82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
SUMMARY: AddressSanitizer: heap-use-after-free /binaryen/src/wasm/wasm-binary.cpp:1954:12 in wasm::WasmBinaryBuilder::visitCall(wasm::Call*)
Shadow bytes around the buggy address:
0x0c2a7fff8130: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2a7fff8140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c2a7fff8150: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2a7fff8160: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2a7fff8170: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c2a7fff8180: fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd
0x0c2a7fff8190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c2a7fff81a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2a7fff81b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2a7fff81c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2a7fff81d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
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
==12717==ABORTING
The text was updated successfully, but these errors were encountered:
Hi, there.
A Use-after-free problem was discovered in wasm::WasmBinaryBuilder::visitCall(wasm::Call*) function in wasm-binary.cpp. 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.
UAF.zip
$ git log
The ASAN dumps the stack trace as follows:
The text was updated successfully, but these errors were encountered: