Skip to content

[Segmentation fault] Out-of-bounds read in wasm::FunctionValidator::visitBlock #6847

@sofiaaberegg

Description

@sofiaaberegg

Hi,

I identified an out-of-bounds data read bug when fuzzing the wasm-opt tool. This bug is triggered when attempting to validate a malformed WAST file containing a BLOCK instruction with no defined functions.

Steps to reproduce:

Test file: wast-oob-read.zip
Command: ./wasm-opt ./wast-oob-read.wast

GDB:

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

Reading symbols from ./wasm-opt...
(gdb) run
Starting program: /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/bin/wasm-opt ./wast-oob-read.wast
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7600640 (LWP 904392)]
[New Thread 0x7ffff6c00640 (LWP 904393)]
[New Thread 0x7ffff6200640 (LWP 904394)]
[New Thread 0x7ffff5800640 (LWP 904395)]
[New Thread 0x7ffff4e00640 (LWP 904396)]
[New Thread 0x7ffff4400640 (LWP 904397)]
[New Thread 0x7ffff3a00640 (LWP 904398)]
[New Thread 0x7ffff3000640 (LWP 904399)]
[New Thread 0x7ffff2600640 (LWP 904400)]
[New Thread 0x7ffff1c00640 (LWP 904401)]
[New Thread 0x7ffff1200640 (LWP 904402)]
[New Thread 0x7ffff0800640 (LWP 904403)]
[New Thread 0x7fffefe00640 (LWP 904404)]
[New Thread 0x7fffef400640 (LWP 904405)]
[New Thread 0x7fffeea00640 (LWP 904406)]
[New Thread 0x7fffee000640 (LWP 904407)]
[New Thread 0x7fffed600640 (LWP 904408)]
[New Thread 0x7fffecc00640 (LWP 904409)]
[New Thread 0x7fffec200640 (LWP 904410)]
[New Thread 0x7fffeb800640 (LWP 904411)]
[New Thread 0x7fffeae00640 (LWP 904412)]
[New Thread 0x7fffea400640 (LWP 904413)]
[New Thread 0x7fffe9a00640 (LWP 904414)]
[New Thread 0x7fffe9000640 (LWP 904415)]

Thread 1 "wasm-opt" received signal SIGSEGV, Segmentation fault.
wasm::FunctionValidator::visitBlock (this=0x7fffffffb9a0, curr=0x555556f8ba60) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm/wasm-validator.cpp:699
699	  switch (getFunction()->profile) {
(gdb) bt
#0  wasm::FunctionValidator::visitBlock (this=0x7fffffffb9a0, curr=0x555556f8ba60) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm/wasm-validator.cpp:699
#1  0x00005555561b7a9b in wasm::Walker<wasm::FunctionValidator, wasm::Visitor<wasm::FunctionValidator, void> >::doVisitBlock (self=0x7fffffffb9a0, currp=0x7fffffffb920)
    at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm-delegations.def:18
#2  0x00005555561adcc4 in wasm::Walker<wasm::FunctionValidator, wasm::Visitor<wasm::FunctionValidator, void> >::walk (this=0x7fffffffb9f8, root=@0x7fffffffb920: 0x555556f8ba60)
    at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm-traversal.h:307
#3  0x00005555561ac979 in wasm::FunctionValidator::validate (this=0x7fffffffb9a0, curr=0x555556f8ba60) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm/wasm-validator.cpp:261
#4  0x00005555561a0483 in operator() (__closure=0x7fffffffbc40, curr=0x555556f5d2e0) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm/wasm-validator.cpp:3781
#5  0x00005555561a3c5d in wasm::ModuleUtils::iterDefinedGlobals<wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&)::<lambda(wasm::Global*)> >(wasm::Module &, struct {...}) (wasm=..., visitor=...)
    at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/ir/module-utils.h:158
#6  0x00005555561a0741 in wasm::validateGlobals (module=..., info=...) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm/wasm-validator.cpp:3763
#7  0x00005555561a2f0f in wasm::WasmValidator::validate (this=0x7fffffffc300, module=..., flags=2) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm/wasm-validator.cpp:4159
#8  0x00005555561a32bd in wasm::WasmValidator::validate (this=0x7fffffffc300, module=..., options=...) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/wasm/wasm-validator.cpp:4192
#9  0x000055555565bdf3 in main (argc=2, argv=0x7fffffffe038) at /home/sofi/fuzzing/binaryen/executables/Debug/binaryen/src/tools/wasm-opt.cpp:298

Valgrind:

valgrind ./wasm-opt ./wast-oob-read.wast
==904527== Memcheck, a memory error detector
==904527== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==904527== Using Valgrind-3.24.0.GIT and LibVEX; rerun with -h for copyright info
==904527== Command: ./wasm-opt ./wast-oob-read.wast
==904527== 
==904527== Invalid read of size 4
==904527==    at 0xD4812F: wasm::FunctionValidator::visitBlock(wasm::Block*) (wasm-validator.cpp:699)
==904527==    by 0xD6BA9A: wasm::Walker<wasm::FunctionValidator, wasm::Visitor<wasm::FunctionValidator, void> >::doVisitBlock(wasm::FunctionValidator*, wasm::Expression**) (wasm-delegations.def:18)
==904527==    by 0xD61CC3: wasm::Walker<wasm::FunctionValidator, wasm::Visitor<wasm::FunctionValidator, void> >::walk(wasm::Expression*&) (wasm-traversal.h:307)
==904527==    by 0xD60978: wasm::FunctionValidator::validate(wasm::Expression*) (wasm-validator.cpp:261)
==904527==    by 0xD54482: wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&)::{lambda(wasm::Global*)#1}::operator()(wasm::Global*) const (wasm-validator.cpp:3781)
==904527==    by 0xD57C5C: void wasm::ModuleUtils::iterDefinedGlobals<wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&)::{lambda(wasm::Global*)#1}>(wasm::Module&, wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&)::{lambda(wasm::Global*)#1}) (module-utils.h:158)
==904527==    by 0xD54740: wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&) (wasm-validator.cpp:3763)
==904527==    by 0xD56F0E: wasm::WasmValidator::validate(wasm::Module&, unsigned int) (wasm-validator.cpp:4159)
==904527==    by 0xD572BC: wasm::WasmValidator::validate(wasm::Module&, wasm::PassOptions const&) (wasm-validator.cpp:4192)
==904527==    by 0x20FDF2: main (wasm-opt.cpp:298)
==904527==  Address 0x40 is not stack'd, malloc'd or (recently) free'd
==904527== 
==904527== 
==904527== Process terminating with default action of signal 11 (SIGSEGV)
==904527==  Access not within mapped region at address 0x40
==904527==    at 0xD4812F: wasm::FunctionValidator::visitBlock(wasm::Block*) (wasm-validator.cpp:699)
==904527==    by 0xD6BA9A: wasm::Walker<wasm::FunctionValidator, wasm::Visitor<wasm::FunctionValidator, void> >::doVisitBlock(wasm::FunctionValidator*, wasm::Expression**) (wasm-delegations.def:18)
==904527==    by 0xD61CC3: wasm::Walker<wasm::FunctionValidator, wasm::Visitor<wasm::FunctionValidator, void> >::walk(wasm::Expression*&) (wasm-traversal.h:307)
==904527==    by 0xD60978: wasm::FunctionValidator::validate(wasm::Expression*) (wasm-validator.cpp:261)
==904527==    by 0xD54482: wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&)::{lambda(wasm::Global*)#1}::operator()(wasm::Global*) const (wasm-validator.cpp:3781)
==904527==    by 0xD57C5C: void wasm::ModuleUtils::iterDefinedGlobals<wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&)::{lambda(wasm::Global*)#1}>(wasm::Module&, wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&)::{lambda(wasm::Global*)#1}) (module-utils.h:158)
==904527==    by 0xD54740: wasm::validateGlobals(wasm::Module&, wasm::ValidationInfo&) (wasm-validator.cpp:3763)
==904527==    by 0xD56F0E: wasm::WasmValidator::validate(wasm::Module&, unsigned int) (wasm-validator.cpp:4159)
==904527==    by 0xD572BC: wasm::WasmValidator::validate(wasm::Module&, wasm::PassOptions const&) (wasm-validator.cpp:4192)
==904527==    by 0x20FDF2: main (wasm-opt.cpp:298)
==904527==  If you believe this happened as a result of a stack
==904527==  overflow in your program's main thread (unlikely but
==904527==  possible), you can try to increase the size of the
==904527==  main thread stack using the --main-stacksize= flag.
==904527==  The main thread stack size used in this run was 8388608.
==904527== 
==904527== HEAP SUMMARY:
==904527==     in use at exit: 260,524 bytes in 2,043 blocks
==904527==   total heap usage: 3,606 allocs, 1,563 frees, 407,734 bytes allocated
==904527== 
==904527== LEAK SUMMARY:
==904527==    definitely lost: 0 bytes in 0 blocks
==904527==    indirectly lost: 0 bytes in 0 blocks
==904527==      possibly lost: 7,296 bytes in 24 blocks
==904527==    still reachable: 253,228 bytes in 2,019 blocks
==904527==         suppressed: 0 bytes in 0 blocks
==904527== Rerun with --leak-check=full to see details of leaked memory
==904527== 
==904527== For lists of detected and suppressed errors, rerun with: -s
==904527== 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