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

Segmentation fault due to illegal write access #465

Open
khagankhan opened this issue Feb 20, 2024 · 1 comment · May be fixed by #491
Open

Segmentation fault due to illegal write access #465

khagankhan opened this issue Feb 20, 2024 · 1 comment · May be fixed by #491

Comments

@khagankhan
Copy link

khagankhan commented Feb 20, 2024

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

@tommie
Copy link

tommie commented May 31, 2024

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.

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

Successfully merging a pull request may close this issue.

2 participants