wasm3 / wasm3

🚀 A fast WebAssembly interpreter and the most universal WASM runtime

Home Page:https://twitter.com/wasm3_engine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Segmentation fault due to illegal write access

khagankhan opened this issue · comments

Describe the Bug

While executing a specific WebAssembly file using wasm3 with the _main function specified, a segmentation fault is encountered, leading to an abrupt termination of the program. Possibly stems from op_CopySlot_32

wasm3 --version:
iWasm3 v0.5.0 on x86_64
Build: Feb 20 2024 05:37:25, Ubuntu Clang 14.0.0

uname -a:Linux node0.wasm3.randtest.emulab.net 5.15.0-56-generic #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Steps to reproduce:

  1. Compile the code with ASAN enabled:
     CC=/path/to/clang CXX=/path/to/clang++
    -DCMAKE_C_COMPILER_RANLIB=/usr/bin/ranlib \
    -DCMAKE_CXX_COMPILER_RANLIB=/usr/bin/ranlib \
    -DCMAKE_C_COMPILER_AR=/usr/bin/ar \
    -DCMAKE_CXX_COMPILER_AR=/usr/bin/ar \
    -DCMAKE_C_COMPILER_LAUNCHER=/usr/local/bin/afl-clang-fast \
    -DCMAKE_C_COMPILER_AR=/usr/bin/ar  \
    -DCMAKE_CXX_COMPILER_LAUNCHER=/usr/local/bin/afl-clang-fast++ \
    -DCMAKE_C_FLAGS="-fsanitize=address -g" \
    -DCMAKE_CXX_FLAGS="-fsanitize=address -g"
  1. Save the issue.wat (Remove .txt extension)
  2. Install and build WABT toolkit (wat2wasm from WABT can be used to convert issue.wat into issue.wat using: wat2wasm issue.wat -o issue.wasm. I have also added issue.wasm that obviates the need to use wat2wasm)
  3. Run wasm3 --func _main issue.wasm
  4. Observe the ASAN error.

Files that cause the issue:

issue.wat.txt
issue.wasm.txt

Expected behavior:

wasm3 should execute the WebAssembly file through the _main function without triggering a segmentation fault, ensuring safe and correct handling of memory operations and function calls.

Observed Behavior

AddressSanitizer:DEADLYSIGNAL
=================================================================
==639192==ERROR: AddressSanitizer: SEGV on unknown address 0x63100003b280 (pc 0x563d2989b6e3 bp 0x62d000000930 sp 0x7ffcb66c7e20 T0)
==639192==The signal is caused by a WRITE memory access.
    #0 0x563d2989b6e3 in op_CopySlot_32 /users/khan22/wasmoi/targets/wasm3/source/./m3_exec.h:974:11
    #1 0x563d29870821 in Call /users/khan22/wasmoi/targets/wasm3/source/./m3_exec.h:120:5
    #2 0x563d29870821 in op_CallIndirect /users/khan22/wasmoi/targets/wasm3/source/./m3_exec.h:597:25
    #3 0x563d29870821 in Call /users/khan22/wasmoi/targets/wasm3/source/./m3_exec.h:120:5
    #4 0x563d29870821 in op_CallIndirect /users/khan22/wasmoi/targets/wasm3/source/./m3_exec.h:597:25
    #5 0x563d298addc8 in RunCode /users/khan22/wasmoi/targets/wasm3/source/./m3_exec_defs.h:71:5
    #6 0x563d298addc8 in m3_CallArgv /users/khan22/wasmoi/targets/wasm3/source/m3_env.c:1013:25
    #7 0x563d298559b6 in repl_call /users/khan22/wasmoi/targets/wasm3/platforms/app/main.c:298:14
    #8 0x563d298584b0 in main /users/khan22/wasmoi/targets/wasm3/platforms/app/main.c
    #9 0x7eff3bdd2d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #10 0x7eff3bdd2e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #11 0x563d29796b24 in _start (/users/khan22/wasmoi/targets/wasm3/build/wasm3+0x42b24) (BuildId: b934fcefa2baab6ef334bf12203160c19a890293)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /users/khan22/wasmoi/targets/wasm3/source/./m3_exec.h:974:11 in op_CopySlot_32
==639192==ABORTING

The code whose execution firstly found the issue (cat issue.wat):

(module
  (type (;0;) (func (result i32)))
  (type (;1;) (func (param f32) (result i32)))
  (type (;2;) (func (param i64 f64 i32) (result f32)))
  (func (;0;) (type 0) (result i32)
    (local i32 i64 f32 f64 i32)
    i32.const 0
    i32.const 1
    f32.const 0x1.38d964p+6 (;=78.212296;)
    i32.const 1
    call_indirect (type 1)
    i32.const 1
    local.get 4
    local.tee 0
    local.get 0
    i32.eqz
    select
    i32.rem_u
    local.tee 0
    local.get 0
    i32.eqz
    select
    i32.rem_s
  )
  (func (;1;) (type 2) (param i64 f64 i32) (result f32)
    (local i32 i64 f32 f64)
    f32.const -0x1.2694ecp+110 (;=-1493706800000000000000000000000000;)
    i32.const 1
    if (result f32) ;; label = @1
      f32.const -0x1.cf239cp+93 (;=-17916826000000000000000000000;)
      f32.const 0x1.ead6cp+38 (;=527034220000;)
      i32.const 1
      br_if 0 (;@1;)
      drop
      f32.const 0x1p+0 (;=1;)
      f32.max
    else
      f32.const 0x1p+0 (;=1;)
    end
    f32.sub
  )
  (func (;2;) (type 1) (param f32) (result i32)
    (local i32 i64 f32 f64)
    i32.const 1
    i32.const 0
    i32.const 0
    i32.store16 offset=42 align=1
    i32.const 0
    f32.const -0x1.c43038p-54 (;=-0.00000000000000009805272;)
    i64.const 1
    f64.const -0x1.c6e4f0a4db53bp-402 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017203320082264456;)
    i32.const 0
    i32.const 0
    call_indirect (type 2)
    f32.ne
    i32.add
    i32.store offset=18 align=1
    i32.const 70
    i32.load8_s offset=80
  )
  (table (;0;) 2 funcref)
  (memory (;0;) 1)
  (export "_main" (func 0))
  (elem (;0;) (i32.const 0) func 1 2))

Additional information

A combination of AFL++ and Wasmlike, an Xsmith-based random program generator produced the snippet of code that found the issue. Xsmith Project

This seems to have something to do with branching out of a block where the block result is declared as fewer than what's on the stack. Minimal test case:

(module
  (type (;0;) (func (result i32)))
  (func (;0;) (type 0) (result i32)
    block $3 (result f32)
      f32.const 0x1
      f32.const 0x2
      br $3
    end
    drop
    i32.const 0
  )
  (export "_start" (func 0)))

It works if the block is declared with no results. Strangely, changing to i32 instead of f32 also makes it work.