From 5a33d4298982e256a703752cbacf0bb435723d9b Mon Sep 17 00:00:00 2001 From: Congcong Cai Date: Wed, 8 Feb 2023 17:45:49 +0800 Subject: [PATCH 1/4] src: handle wasm out of bound in osx will raise SIGBUS correctly fix: #46559 OSX will raise both SIGBUS and SIGSEGV when out of bound memory visit, This commit set sigaction in OSX for two signals to handle this. --- src/node.cc | 21 +++++++++++++++++- test/fixtures/out-of-bound.wasm | Bin 0 -> 58 bytes test/fixtures/out-of-bound.wat | 16 +++++++++++++ .../parallel/test-wasm-memory-out-of-bound.js | 13 +++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/out-of-bound.wasm create mode 100644 test/fixtures/out-of-bound.wat create mode 100644 test/parallel/test-wasm-memory-out-of-bound.js diff --git a/src/node.cc b/src/node.cc index b29dc57d6011b5..6c98ca9773f704 100644 --- a/src/node.cc +++ b/src/node.cc @@ -365,10 +365,18 @@ static LONG TrapWebAssemblyOrContinue(EXCEPTION_POINTERS* exception) { } #else static std::atomic previous_sigsegv_action; +#if defined(__APPLE__) +static std::atomic previous_sigbus_action; +#endif // __APPLE__ void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) { if (!v8::TryHandleWebAssemblyTrapPosix(signo, info, ucontext)) { +#if defined(__APPLE__) + sigaction_cb prev = signo == SIGBUS ? previous_sigbus_action.load() + : previous_sigsegv_action.load(); +# else sigaction_cb prev = previous_sigsegv_action.load(); +#endif // __APPLE__ if (prev != nullptr) { prev(signo, info, ucontext); } else { @@ -398,6 +406,14 @@ void RegisterSignalHandler(int signal, previous_sigsegv_action.store(handler); return; } +#if defined (__APPLE__) + if (signal == SIGBUS) { + CHECK(previous_sigbus_action.is_lock_free()); + CHECK(!reset_handler); + previous_sigbus_action.store(handler); + return; + } +#endif // __APPLE__ #endif // NODE_USE_V8_WASM_TRAP_HANDLER struct sigaction sa; memset(&sa, 0, sizeof(sa)); @@ -554,7 +570,7 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) { #else // Tell V8 to disable emitting WebAssembly // memory bounds checks. This means that we have - // to catch the SIGSEGV in TrapWebAssemblyOrContinue + // to catch the SIGSEGV/SIGBUS in TrapWebAssemblyOrContinue // and pass the signal context to V8. { struct sigaction sa; @@ -562,6 +578,9 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) { sa.sa_sigaction = TrapWebAssemblyOrContinue; sa.sa_flags = SA_SIGINFO; CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0); +#ifdef __APPLE__ + CHECK_EQ(sigaction(SIGBUS, &sa, nullptr), 0); +#endif } #endif // defined(_WIN32) V8::EnableWebAssemblyTrapHandler(false); diff --git a/test/fixtures/out-of-bound.wasm b/test/fixtures/out-of-bound.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a95761b0f514101b7db446f034699064927513e0 GIT binary patch literal 58 zcmZQbEY4+QU|?WmVN76PU}j=uU}a`xU}WcFWQ#8@Nh~U1VBivE6lSnza6G_}_none (func)) + (memory $0 1) + (export "_start" (func $_start)) + (func $_start + memory.size + i32.const 64 + i32.mul + i32.const 1024 + i32.mul + i32.const 3 + i32.sub + i32.load + drop + ) +) diff --git a/test/parallel/test-wasm-memory-out-of-bound.js b/test/parallel/test-wasm-memory-out-of-bound.js new file mode 100644 index 00000000000000..be9e3c8e4e4727 --- /dev/null +++ b/test/parallel/test-wasm-memory-out-of-bound.js @@ -0,0 +1,13 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); + +const buffer = fixtures.readSync('out-of-bound.wasm'); +WebAssembly.instantiate(buffer, {}).then((results) => { + assert.throws(() => { + results.instance.exports._start(); + }); +}); + From b390df50f53d1ec98a450ceef8b743914b258fad Mon Sep 17 00:00:00 2001 From: Congcong Cai Date: Wed, 8 Feb 2023 22:50:48 +0800 Subject: [PATCH 2/4] format --- src/node.cc | 6 +++--- test/parallel/test-wasm-memory-out-of-bound.js | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/node.cc b/src/node.cc index 6c98ca9773f704..9bb38447e9bd86 100644 --- a/src/node.cc +++ b/src/node.cc @@ -374,7 +374,7 @@ void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) { #if defined(__APPLE__) sigaction_cb prev = signo == SIGBUS ? previous_sigbus_action.load() : previous_sigsegv_action.load(); -# else +#else sigaction_cb prev = previous_sigsegv_action.load(); #endif // __APPLE__ if (prev != nullptr) { @@ -406,7 +406,7 @@ void RegisterSignalHandler(int signal, previous_sigsegv_action.store(handler); return; } -#if defined (__APPLE__) +#if defined(__APPLE__) if (signal == SIGBUS) { CHECK(previous_sigbus_action.is_lock_free()); CHECK(!reset_handler); @@ -578,7 +578,7 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) { sa.sa_sigaction = TrapWebAssemblyOrContinue; sa.sa_flags = SA_SIGINFO; CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0); -#ifdef __APPLE__ +#if defined(__APPLE__) CHECK_EQ(sigaction(SIGBUS, &sa, nullptr), 0); #endif } diff --git a/test/parallel/test-wasm-memory-out-of-bound.js b/test/parallel/test-wasm-memory-out-of-bound.js index be9e3c8e4e4727..ac90c68469ca99 100644 --- a/test/parallel/test-wasm-memory-out-of-bound.js +++ b/test/parallel/test-wasm-memory-out-of-bound.js @@ -8,6 +8,5 @@ const buffer = fixtures.readSync('out-of-bound.wasm'); WebAssembly.instantiate(buffer, {}).then((results) => { assert.throws(() => { results.instance.exports._start(); - }); + }, WebAssembly.RuntimeError('memory access out of bounds')); }); - From c2a7b9c0e3238f94b4c940e47f66345d4a3678a7 Mon Sep 17 00:00:00 2001 From: Congcong Cai Date: Wed, 8 Feb 2023 23:23:11 +0800 Subject: [PATCH 3/4] add TODO mark --- src/node.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/node.cc b/src/node.cc index 9bb38447e9bd86..23646c3bc25088 100644 --- a/src/node.cc +++ b/src/node.cc @@ -365,6 +365,7 @@ static LONG TrapWebAssemblyOrContinue(EXCEPTION_POINTERS* exception) { } #else static std::atomic previous_sigsegv_action; +// TODO(align behavior between macos and other in next major version) #if defined(__APPLE__) static std::atomic previous_sigbus_action; #endif // __APPLE__ @@ -406,6 +407,7 @@ void RegisterSignalHandler(int signal, previous_sigsegv_action.store(handler); return; } +// TODO(align behavior between macos and other in next major version) #if defined(__APPLE__) if (signal == SIGBUS) { CHECK(previous_sigbus_action.is_lock_free()); @@ -578,6 +580,7 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) { sa.sa_sigaction = TrapWebAssemblyOrContinue; sa.sa_flags = SA_SIGINFO; CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0); +// TODO(align behavior between macos and other in next major version) #if defined(__APPLE__) CHECK_EQ(sigaction(SIGBUS, &sa, nullptr), 0); #endif From 456342fd8f3b8f282e32a7d84e1c97fb3f47d630 Mon Sep 17 00:00:00 2001 From: Congcong Cai Date: Sun, 4 Jun 2023 10:01:47 +0200 Subject: [PATCH 4/4] Update test/parallel/test-wasm-memory-out-of-bound.js Co-authored-by: James M Snell --- test/parallel/test-wasm-memory-out-of-bound.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/parallel/test-wasm-memory-out-of-bound.js b/test/parallel/test-wasm-memory-out-of-bound.js index ac90c68469ca99..56ac96beabd33e 100644 --- a/test/parallel/test-wasm-memory-out-of-bound.js +++ b/test/parallel/test-wasm-memory-out-of-bound.js @@ -1,12 +1,12 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const fixtures = require('../common/fixtures'); const buffer = fixtures.readSync('out-of-bound.wasm'); -WebAssembly.instantiate(buffer, {}).then((results) => { +WebAssembly.instantiate(buffer, {}).then(common.mustCall((results) => { assert.throws(() => { results.instance.exports._start(); }, WebAssembly.RuntimeError('memory access out of bounds')); -}); +}));