[wasm] Test code protection in signal handlers
Test that also signal handlers cannot write to code, even if a {CodeSpaceWriteScope} is open when the signal is triggered. R=jkummerow@chromium.org CC=mpdenton@chromium.org Bug: v8:11974 Change-Id: I1e49e4b31ba196948f7f7adfdf88675816e0a58a Cq-Include-Trybots: luci.v8.try:v8_mac_arm64_rel_ng Cq-Include-Trybots: luci.v8.try:v8_mac_arm64_dbg_ng Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3140607 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/main@{#76747}
This commit is contained in:
parent
cd79e83f42
commit
06de35edb6
@ -2,6 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "include/v8config.h"
|
||||
|
||||
// TODO(clemensb): Extend this to other OSes.
|
||||
#if V8_OS_POSIX && !V8_OS_FUCHSIA
|
||||
#include <signal.h>
|
||||
#endif // V8_OS_POSIX && !V8_OS_FUCHSIA
|
||||
|
||||
#include "src/flags/flags.h"
|
||||
#include "src/wasm/code-space-access.h"
|
||||
#include "src/wasm/module-compiler.h"
|
||||
@ -162,6 +169,127 @@ TEST_P(ParameterizedMemoryProtectionTest, CodeNotWritableAfterScope) {
|
||||
ASSERT_DEATH_IF_PROTECTED(WriteToCode());
|
||||
}
|
||||
|
||||
#if V8_OS_POSIX && !V8_OS_FUCHSIA
|
||||
class ParameterizedMemoryProtectionTestWithSignalHandling
|
||||
: public MemoryProtectionTest,
|
||||
public ::testing::WithParamInterface<
|
||||
std::tuple<MemoryProtectionMode, bool, bool>> {
|
||||
public:
|
||||
class SignalHandlerScope {
|
||||
public:
|
||||
SignalHandlerScope() {
|
||||
CHECK_NULL(current_handler_scope_);
|
||||
current_handler_scope_ = this;
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = &HandleSignal;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
|
||||
CHECK_EQ(0, sigaction(SIGPROF, &sa, &old_signal_handler_));
|
||||
}
|
||||
|
||||
~SignalHandlerScope() {
|
||||
CHECK_EQ(current_handler_scope_, this);
|
||||
current_handler_scope_ = nullptr;
|
||||
sigaction(SIGPROF, &old_signal_handler_, nullptr);
|
||||
}
|
||||
|
||||
void SetAddressToWriteToOnSignal(uint8_t* address) {
|
||||
CHECK_NULL(code_address_);
|
||||
CHECK_NOT_NULL(address);
|
||||
code_address_ = address;
|
||||
}
|
||||
|
||||
int num_handled_signals() const { return handled_signals_; }
|
||||
|
||||
private:
|
||||
static void HandleSignal(int signal, siginfo_t*, void*) {
|
||||
if (signal == SIGPROF) {
|
||||
printf("Handled SIGPROF.\n");
|
||||
} else {
|
||||
printf("Handled unknown signal: %d.\n", signal);
|
||||
}
|
||||
CHECK_NOT_NULL(current_handler_scope_);
|
||||
current_handler_scope_->handled_signals_ += 1;
|
||||
if (current_handler_scope_->code_address_ != nullptr) {
|
||||
printf("Writing to %p.\n", current_handler_scope_->code_address_);
|
||||
*current_handler_scope_->code_address_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct sigaction old_signal_handler_;
|
||||
int handled_signals_ = 0;
|
||||
uint8_t* code_address_ = nullptr;
|
||||
|
||||
// These are accessed from the signal handler.
|
||||
static SignalHandlerScope* current_handler_scope_;
|
||||
};
|
||||
|
||||
void SetUp() override { Initialize(std::get<0>(GetParam())); }
|
||||
|
||||
void TestSignalHandler() {
|
||||
const bool write_in_signal_handler = std::get<1>(GetParam());
|
||||
const bool open_write_scope = std::get<2>(GetParam());
|
||||
CompileModule();
|
||||
SignalHandlerScope signal_handler_scope;
|
||||
|
||||
CHECK_EQ(0, signal_handler_scope.num_handled_signals());
|
||||
pthread_kill(pthread_self(), SIGPROF);
|
||||
CHECK_EQ(1, signal_handler_scope.num_handled_signals());
|
||||
|
||||
uint8_t* code_start_ptr = &code()->instructions()[0];
|
||||
uint8_t code_start = *code_start_ptr;
|
||||
CHECK_NE(0, code_start);
|
||||
if (write_in_signal_handler) {
|
||||
signal_handler_scope.SetAddressToWriteToOnSignal(code_start_ptr);
|
||||
}
|
||||
// This will make us crash if code is protected and
|
||||
// {write_in_signal_handler} is set.
|
||||
{
|
||||
base::Optional<CodeSpaceWriteScope> write_scope;
|
||||
if (open_write_scope) write_scope.emplace(native_module());
|
||||
pthread_kill(pthread_self(), SIGPROF);
|
||||
}
|
||||
|
||||
// If we write and code is protected, we never reach here.
|
||||
CHECK(!write_in_signal_handler || !code_is_protected());
|
||||
CHECK_EQ(2, signal_handler_scope.num_handled_signals());
|
||||
CHECK_EQ(write_in_signal_handler ? 0 : code_start, *code_start_ptr);
|
||||
}
|
||||
};
|
||||
|
||||
// static
|
||||
ParameterizedMemoryProtectionTestWithSignalHandling::SignalHandlerScope*
|
||||
ParameterizedMemoryProtectionTestWithSignalHandling::SignalHandlerScope::
|
||||
current_handler_scope_ = nullptr;
|
||||
|
||||
std::string PrintMemoryProtectionAndSignalHandlingTestParam(
|
||||
::testing::TestParamInfo<std::tuple<MemoryProtectionMode, bool, bool>>
|
||||
info) {
|
||||
MemoryProtectionMode protection_mode = std::get<0>(info.param);
|
||||
const bool write_in_signal_handler = std::get<1>(info.param);
|
||||
const bool open_write_scope = std::get<2>(info.param);
|
||||
return std::string{MemoryProtectionModeToString(protection_mode)} + "_" +
|
||||
(write_in_signal_handler ? "Write" : "NoWrite") + "_" +
|
||||
(open_write_scope ? "WithScope" : "NoScope");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
MemoryProtection, ParameterizedMemoryProtectionTestWithSignalHandling,
|
||||
::testing::Combine(::testing::Values(kNoProtection, kPku, kMprotect,
|
||||
kPkuWithMprotectFallback),
|
||||
::testing::Bool(), ::testing::Bool()),
|
||||
PrintMemoryProtectionAndSignalHandlingTestParam);
|
||||
|
||||
TEST_P(ParameterizedMemoryProtectionTestWithSignalHandling, TestSignalHandler) {
|
||||
const bool write_in_signal_handler = std::get<1>(GetParam());
|
||||
if (write_in_signal_handler) {
|
||||
ASSERT_DEATH_IF_PROTECTED(TestSignalHandler());
|
||||
} else {
|
||||
TestSignalHandler();
|
||||
}
|
||||
}
|
||||
#endif // V8_OS_POSIX && !V8_OS_FUCHSIA
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user