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:
- 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"
- Save the
issue.wat
(Remove .txt extension) - Install and build WABT toolkit (
wat2wasm
from WABT can be used to convertissue.wat
intoissue.wat
using:wat2wasm issue.wat -o issue.wasm
. I have also addedissue.wasm
that obviates the need to usewat2wasm
) - Run
wasm3 --func _main issue.wasm
- Observe the ASAN error.
Files that cause the issue:
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.