Skip to content

[Segmentation fault] Out-of-bounds read in wasm::WATParser::makeArrayInitElem #6833

@sofiaaberegg

Description

@sofiaaberegg

Hi,

I identified an out-of-bounds data read bug when fuzzing the wasm-opt tool.

Steps to reproduce:
Test file: wasm-oob-read.zip
Command: ./wasm-opt ./wasm-oob-read.wasm

GDB:

gdb --args ./wasm-opt ./wasm-oob-read.wasm 
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04.2) 12.1

Reading symbols from ./wasm-opt...
(gdb) r
Starting program: /home/sofi/wasm-opt ./wasm-oob-read.wasm
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00005555565cf5c5 in wasm::WATParser::makeArrayInitElem<wasm::WATParser::ParseDefsCtx> (ctx=..., pos=110, annotations=std::vector of length 0, capacity 0) at /home/sofi/fuzzing/binaryen/binaryen/src/parser/parsers.h:2332
2332	  return ctx.makeArrayInitElem(pos, annotations, *type, *elem);
(gdb) bt
#0  0x00005555565cf5c5 in wasm::WATParser::makeArrayInitElem<wasm::WATParser::ParseDefsCtx> (ctx=..., pos=110, annotations=std::vector of length 0, capacity 0) at /home/sofi/fuzzing/binaryen/binaryen/src/parser/parsers.h:2332
#1  0x0000555556598d1b in wasm::WATParser::plaininstr<wasm::WATParser::ParseDefsCtx> (ctx=..., annotations=std::vector of length 0, capacity 0) at /home/sofi/fuzzing/binaryen/binaryen/src/gen-s-parser.inc:75
#2  0x0000555556595eb4 in wasm::WATParser::instr<wasm::WATParser::ParseDefsCtx> (ctx=...) at /home/sofi/fuzzing/binaryen/binaryen/src/parser/parsers.h:938
#3  0x00005555565974e4 in wasm::WATParser::instrs<wasm::WATParser::ParseDefsCtx> (ctx=...) at /home/sofi/fuzzing/binaryen/binaryen/src/parser/parsers.h:1018
#4  0x000055555658f441 in wasm::WATParser::func<wasm::WATParser::ParseDefsCtx> (ctx=...) at /home/sofi/fuzzing/binaryen/binaryen/src/parser/parsers.h:2986
#5  0x000055555657deb1 in wasm::WATParser::parseDefinitions (decls=..., input=..., typeIndices=std::unordered_map with 0 elements, types=std::vector of length 1, capacity 1 = {...}, implicitTypes=std::unordered_map with 2 elements = {...}, 
    typeNames=std::unordered_map with 0 elements) at /home/sofi/fuzzing/binaryen/binaryen/src/parser/parse-5-defs.cpp:51
#6  0x00005555562f6e1c in wasm::WATParser::(anonymous namespace)::doParseModule (wasm=..., input=..., allowExtra=false) at /home/sofi/fuzzing/binaryen/binaryen/src/parser/wat-parser.cpp:113
#7  0x00005555562f7185 in wasm::WATParser::parseModule (wasm=..., in="(func      return", ' ' <repeats 49 times>, "i32.or      i8x16.ge_u   f64.const   5      array.init_elem", ' ' <repeats 15 times>, "0", ' ' <repeats 43 times>, "i64.le_u        "...)
    at /home/sofi/fuzzing/binaryen/binaryen/src/parser/wat-parser.cpp:126
#8  0x00005555560e0c4b in wasm::readTextData (input="(func      return", ' ' <repeats 49 times>, "i32.or      i8x16.ge_u   f64.const   5      array.init_elem", ' ' <repeats 15 times>, "0", ' ' <repeats 43 times>, "i64.le_u        "..., wasm=..., 
    profile=wasm::IRProfile::Normal) at /home/sofi/fuzzing/binaryen/binaryen/src/wasm/wasm-io.cpp:38
#9  0x00005555560e0daf in wasm::ModuleReader::readText (this=0x7fffffffc4a0, filename="./wasm-oob-read.wasm", wasm=...) at /home/sofi/fuzzing/binaryen/binaryen/src/wasm/wasm-io.cpp:47
#10 0x00005555560e14ea in wasm::ModuleReader::read (this=0x7fffffffc4a0, filename="./wasm-oob-read.wasm", wasm=..., sourceMapFilename="") at /home/sofi/fuzzing/binaryen/binaryen/src/wasm/wasm-io.cpp:109
#11 0x000055555565aedd in main (argc=2, argv=0x7fffffffe108) at /home/sofi/fuzzing/binaryen/binaryen/src/tools/wasm-opt.cpp:278

Valgrind:

valgrind ./wasm-opt ./wasm-oob-read.wasm 
==3026577== Memcheck, a memory error detector
==3026577== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3026577== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==3026577== Command: ./wasm-opt ./wasm-oob-read.wasm
==3026577== 
==3026577== Invalid read of size 8
==3026577==    at 0x11835C5: wasm::Result<wasm::Ok> wasm::WATParser::makeArrayInitElem<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&, unsigned int, std::vector<wasm::WATParser::Annotation, std::allocator<wasm::WATParser::Annotation> > const&) (parsers.h:2332)
==3026577==    by 0x114CD1A: wasm::MaybeResult<wasm::Ok> wasm::WATParser::plaininstr<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&, std::vector<wasm::WATParser::Annotation, std::allocator<wasm::WATParser::Annotation> > const&) (gen-s-parser.inc:75)
==3026577==    by 0x1149EB3: wasm::MaybeResult<wasm::Ok> wasm::WATParser::instr<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&) (parsers.h:938)
==3026577==    by 0x114B4E3: wasm::Result<wasm::Ok> wasm::WATParser::instrs<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&) (parsers.h:1018)
==3026577==    by 0x1143440: wasm::MaybeResult<wasm::Ok> wasm::WATParser::func<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&) (parsers.h:2986)
==3026577==    by 0x1131EB0: wasm::WATParser::parseDefinitions(wasm::WATParser::ParseDeclsCtx&, wasm::WATParser::Lexer&, std::unordered_map<wasm::Name, unsigned int, std::hash<wasm::Name>, std::equal_to<wasm::Name>, std::allocator<std::pair<wasm::Name const, unsigned int> > >&, std::vector<wasm::HeapType, std::allocator<wasm::HeapType> >&, std::unordered_map<unsigned int, wasm::HeapType, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, wasm::HeapType> > >&, std::unordered_map<wasm::HeapType, std::unordered_map<wasm::Name, unsigned int, std::hash<wasm::Name>, std::equal_to<wasm::Name>, std::allocator<std::pair<wasm::Name const, unsigned int> > >, std::hash<wasm::HeapType>, std::equal_to<wasm::HeapType>, std::allocator<std::pair<wasm::HeapType const, std::unordered_map<wasm::Name, unsigned int, std::hash<wasm::Name>, std::equal_to<wasm::Name>, std::allocator<std::pair<wasm::Name const, unsigned int> > > > > >&) (parse-5-defs.cpp:51)
==3026577==    by 0xEAAE1B: wasm::WATParser::(anonymous namespace)::doParseModule(wasm::Module&, wasm::WATParser::Lexer&, bool) (wat-parser.cpp:113)
==3026577==    by 0xEAB184: wasm::WATParser::parseModule(wasm::Module&, std::basic_string_view<char, std::char_traits<char> >) (wat-parser.cpp:126)
==3026577==    by 0xC94C4A: wasm::readTextData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, wasm::Module&, wasm::IRProfile) (wasm-io.cpp:38)
==3026577==    by 0xC94DAE: wasm::ModuleReader::readText(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, wasm::Module&) (wasm-io.cpp:47)
==3026577==    by 0xC954E9: 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> >) (wasm-io.cpp:109)
==3026577==    by 0x20EEDC: main (wasm-opt.cpp:278)
==3026577==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
==3026577== 
==3026577== 
==3026577== Process terminating with default action of signal 11 (SIGSEGV)
==3026577==  Access not within mapped region at address 0x8
==3026577==    at 0x11835C5: wasm::Result<wasm::Ok> wasm::WATParser::makeArrayInitElem<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&, unsigned int, std::vector<wasm::WATParser::Annotation, std::allocator<wasm::WATParser::Annotation> > const&) (parsers.h:2332)
==3026577==    by 0x114CD1A: wasm::MaybeResult<wasm::Ok> wasm::WATParser::plaininstr<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&, std::vector<wasm::WATParser::Annotation, std::allocator<wasm::WATParser::Annotation> > const&) (gen-s-parser.inc:75)
==3026577==    by 0x1149EB3: wasm::MaybeResult<wasm::Ok> wasm::WATParser::instr<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&) (parsers.h:938)
==3026577==    by 0x114B4E3: wasm::Result<wasm::Ok> wasm::WATParser::instrs<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&) (parsers.h:1018)
==3026577==    by 0x1143440: wasm::MaybeResult<wasm::Ok> wasm::WATParser::func<wasm::WATParser::ParseDefsCtx>(wasm::WATParser::ParseDefsCtx&) (parsers.h:2986)
==3026577==    by 0x1131EB0: wasm::WATParser::parseDefinitions(wasm::WATParser::ParseDeclsCtx&, wasm::WATParser::Lexer&, std::unordered_map<wasm::Name, unsigned int, std::hash<wasm::Name>, std::equal_to<wasm::Name>, std::allocator<std::pair<wasm::Name const, unsigned int> > >&, std::vector<wasm::HeapType, std::allocator<wasm::HeapType> >&, std::unordered_map<unsigned int, wasm::HeapType, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, wasm::HeapType> > >&, std::unordered_map<wasm::HeapType, std::unordered_map<wasm::Name, unsigned int, std::hash<wasm::Name>, std::equal_to<wasm::Name>, std::allocator<std::pair<wasm::Name const, unsigned int> > >, std::hash<wasm::HeapType>, std::equal_to<wasm::HeapType>, std::allocator<std::pair<wasm::HeapType const, std::unordered_map<wasm::Name, unsigned int, std::hash<wasm::Name>, std::equal_to<wasm::Name>, std::allocator<std::pair<wasm::Name const, unsigned int> > > > > >&) (parse-5-defs.cpp:51)
==3026577==    by 0xEAAE1B: wasm::WATParser::(anonymous namespace)::doParseModule(wasm::Module&, wasm::WATParser::Lexer&, bool) (wat-parser.cpp:113)
==3026577==    by 0xEAB184: wasm::WATParser::parseModule(wasm::Module&, std::basic_string_view<char, std::char_traits<char> >) (wat-parser.cpp:126)
==3026577==    by 0xC94C4A: wasm::readTextData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, wasm::Module&, wasm::IRProfile) (wasm-io.cpp:38)
==3026577==    by 0xC94DAE: wasm::ModuleReader::readText(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, wasm::Module&) (wasm-io.cpp:47)
==3026577==    by 0xC954E9: 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> >) (wasm-io.cpp:109)
==3026577==    by 0x20EEDC: main (wasm-opt.cpp:278)
==3026577==  If you believe this happened as a result of a stack
==3026577==  overflow in your program's main thread (unlikely but
==3026577==  possible), you can try to increase the size of the
==3026577==  main thread stack using the --main-stacksize= flag.
==3026577==  The main thread stack size used in this run was 8388608.
==3026577== 
==3026577== HEAP SUMMARY:
==3026577==     in use at exit: 249,343 bytes in 1,953 blocks
==3026577==   total heap usage: 3,346 allocs, 1,393 frees, 387,559 bytes allocated
==3026577== 
==3026577== LEAK SUMMARY:
==3026577==    definitely lost: 0 bytes in 0 blocks
==3026577==    indirectly lost: 0 bytes in 0 blocks
==3026577==      possibly lost: 0 bytes in 0 blocks
==3026577==    still reachable: 249,343 bytes in 1,953 blocks
==3026577==         suppressed: 0 bytes in 0 blocks
==3026577== Rerun with --leak-check=full to see details of leaked memory
==3026577== 
==3026577== For lists of detected and suppressed errors, rerun with: -s
==3026577== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault

Metadata

Metadata

Assignees

No one assigned

    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