Commit 3974115a authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

[trap-handler] Remove dependencies on macros, globals, flags

This will allow us to refactor those V8 files without being concerned
about potential interference with the security of the trap handler.

This requires the duplication of V8_EXPORT_PRIVATE, the CHECK/DCHECK
macros, and V8_DISABLE_ASAN. The trap-handler specific definitions
are prefixed with "TH_".

R=ahaas@chromium.org

Bug: v8:11755
Change-Id: Iac39b553704ef50e51937375c8db805d57ce2625
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2880218
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74588}
parent 4683d6fe
...@@ -6,19 +6,8 @@ include_rules = [ ...@@ -6,19 +6,8 @@ include_rules = [
"-src", "-src",
"-include", "-include",
"+src/trap-handler", "+src/trap-handler",
] # Use the IMMEDIATE_CRASH() macro for crashing non-recoverably on check failure.
"+src/base/immediate-crash.h",
specific_include_rules = { # Allow include/v8config.h for V8_OS_* macros.
"trap-handler.h": [
"+src/base/build_config.h",
"+src/common/globals.h",
"+src/flags/flags.h",
],
"handler-inside-posix.h": [
# To access V8_OS_LINUX. This file is already included in build_config.h.
"+include/v8config.h", "+include/v8config.h",
], ]
"handler-inside-win.h": [
"+src/base/macros.h",
]
}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define V8_TRAP_HANDLER_HANDLER_INSIDE_POSIX_H_ #define V8_TRAP_HANDLER_HANDLER_INSIDE_POSIX_H_
#include <signal.h> #include <signal.h>
#include "include/v8config.h" #include "include/v8config.h"
namespace v8 { namespace v8 {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include <windows.h> #include <windows.h>
#include "src/base/macros.h" #include "src/trap-handler/trap-handler.h" // For TH_DISABLE_ASAN.
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -18,7 +18,7 @@ LONG WINAPI HandleWasmTrap(EXCEPTION_POINTERS* exception); ...@@ -18,7 +18,7 @@ LONG WINAPI HandleWasmTrap(EXCEPTION_POINTERS* exception);
// On Windows, asan installs its own exception handler which maps shadow // On Windows, asan installs its own exception handler which maps shadow
// memory. Since our exception handler may be executed before the asan exception // memory. Since our exception handler may be executed before the asan exception
// handler, we have to make sure that asan shadow memory is not accessed here. // handler, we have to make sure that asan shadow memory is not accessed here.
DISABLE_ASAN bool TryHandleWasmTrap(EXCEPTION_POINTERS* exception); TH_DISABLE_ASAN bool TryHandleWasmTrap(EXCEPTION_POINTERS* exception);
} // namespace trap_handler } // namespace trap_handler
} // namespace internal } // namespace internal
......
...@@ -50,11 +50,14 @@ bool TryFindLandingPad(uintptr_t fault_addr, uintptr_t* landing_pad) { ...@@ -50,11 +50,14 @@ bool TryFindLandingPad(uintptr_t fault_addr, uintptr_t* landing_pad) {
if (data == nullptr) { if (data == nullptr) {
continue; continue;
} }
const Address base = data->base; const uintptr_t base = data->base;
if (fault_addr >= base && fault_addr < base + data->size) { if (fault_addr >= base && fault_addr < base + data->size) {
// Hurray, we found the code object. Check for protected addresses. // Hurray, we found the code object. Check for protected addresses.
const ptrdiff_t offset = fault_addr - base; const uint32_t offset = static_cast<uint32_t>(fault_addr - base);
// The offset must fit in 32 bit, see comment on
// ProtectedInstructionData::instr_offset.
TH_DCHECK(base + offset == fault_addr);
for (unsigned i = 0; i < data->num_protected_instructions; ++i) { for (unsigned i = 0; i < data->num_protected_instructions; ++i) {
if (data->instructions[i].instr_offset == offset) { if (data->instructions[i].instr_offset == offset) {
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <signal.h> #include <signal.h>
#include <cstdio>
#include "src/trap-handler/handler-inside-posix.h" #include "src/trap-handler/handler-inside-posix.h"
#include "src/trap-handler/trap-handler-internal.h" #include "src/trap-handler/trap-handler-internal.h"
...@@ -39,7 +41,7 @@ bool g_is_default_signal_handler_registered; ...@@ -39,7 +41,7 @@ bool g_is_default_signal_handler_registered;
} // namespace } // namespace
bool RegisterDefaultTrapHandler() { bool RegisterDefaultTrapHandler() {
CHECK(!g_is_default_signal_handler_registered); TH_CHECK(!g_is_default_signal_handler_registered);
struct sigaction action; struct sigaction action;
action.sa_sigaction = HandleSignal; action.sa_sigaction = HandleSignal;
...@@ -61,7 +63,7 @@ bool RegisterDefaultTrapHandler() { ...@@ -61,7 +63,7 @@ bool RegisterDefaultTrapHandler() {
defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \ defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \
defined(UNDEFINED_SANITIZER) defined(UNDEFINED_SANITIZER)
struct sigaction installed_handler; struct sigaction installed_handler;
CHECK_EQ(sigaction(kOobSignal, NULL, &installed_handler), 0); TH_CHECK(sigaction(kOobSignal, NULL, &installed_handler) == 0);
// If the installed handler does not point to HandleSignal, then // If the installed handler does not point to HandleSignal, then
// allow_user_segv_handler is 0. // allow_user_segv_handler is 0.
if (installed_handler.sa_sigaction != HandleSignal) { if (installed_handler.sa_sigaction != HandleSignal) {
......
...@@ -40,7 +40,7 @@ void* g_registered_handler = nullptr; ...@@ -40,7 +40,7 @@ void* g_registered_handler = nullptr;
bool RegisterDefaultTrapHandler() { bool RegisterDefaultTrapHandler() {
constexpr ULONG first = TRUE; constexpr ULONG first = TRUE;
CHECK_NULL(g_registered_handler); TH_CHECK(g_registered_handler == nullptr);
g_registered_handler = AddVectoredExceptionHandler(first, HandleWasmTrap); g_registered_handler = AddVectoredExceptionHandler(first, HandleWasmTrap);
return nullptr != g_registered_handler; return nullptr != g_registered_handler;
......
...@@ -66,7 +66,7 @@ bool IsDisjoint(const CodeProtectionInfo* a, const CodeProtectionInfo* b) { ...@@ -66,7 +66,7 @@ bool IsDisjoint(const CodeProtectionInfo* a, const CodeProtectionInfo* b) {
// registered. // registered.
void VerifyCodeRangeIsDisjoint(const CodeProtectionInfo* code_info) { void VerifyCodeRangeIsDisjoint(const CodeProtectionInfo* code_info) {
for (size_t i = 0; i < gNumCodeObjects; ++i) { for (size_t i = 0; i < gNumCodeObjects; ++i) {
DCHECK(IsDisjoint(code_info, gCodeObjects[i].code_info)); TH_DCHECK(IsDisjoint(code_info, gCodeObjects[i].code_info));
} }
} }
...@@ -79,11 +79,11 @@ void ValidateCodeObjects() { ...@@ -79,11 +79,11 @@ void ValidateCodeObjects() {
// Do some sanity checks on the protected instruction data // Do some sanity checks on the protected instruction data
for (unsigned i = 0; i < data->num_protected_instructions; ++i) { for (unsigned i = 0; i < data->num_protected_instructions; ++i) {
DCHECK_GE(data->instructions[i].instr_offset, 0); TH_DCHECK(data->instructions[i].instr_offset >= 0);
DCHECK_LT(data->instructions[i].instr_offset, data->size); TH_DCHECK(data->instructions[i].instr_offset < data->size);
DCHECK_GE(data->instructions[i].landing_offset, 0); TH_DCHECK(data->instructions[i].landing_offset >= 0);
DCHECK_LT(data->instructions[i].landing_offset, data->size); TH_DCHECK(data->instructions[i].landing_offset < data->size);
DCHECK_GT(data->instructions[i].landing_offset, TH_DCHECK(data->instructions[i].landing_offset >
data->instructions[i].instr_offset); data->instructions[i].instr_offset);
} }
} }
...@@ -92,10 +92,10 @@ void ValidateCodeObjects() { ...@@ -92,10 +92,10 @@ void ValidateCodeObjects() {
size_t free_count = 0; size_t free_count = 0;
for (size_t i = gNextCodeObject; i != gNumCodeObjects; for (size_t i = gNextCodeObject; i != gNumCodeObjects;
i = gCodeObjects[i].next_free) { i = gCodeObjects[i].next_free) {
DCHECK_LT(i, gNumCodeObjects); TH_DCHECK(i < gNumCodeObjects);
++free_count; ++free_count;
// This check will fail if we encounter a cycle. // This check will fail if we encounter a cycle.
DCHECK_LE(free_count, gNumCodeObjects); TH_DCHECK(free_count <= gNumCodeObjects);
} }
// Check that all free entries are reachable via the free list. // Check that all free entries are reachable via the free list.
...@@ -105,12 +105,12 @@ void ValidateCodeObjects() { ...@@ -105,12 +105,12 @@ void ValidateCodeObjects() {
++free_count2; ++free_count2;
} }
} }
DCHECK_EQ(free_count, free_count2); TH_DCHECK(free_count == free_count2);
} }
} // namespace } // namespace
CodeProtectionInfo* CreateHandlerData( CodeProtectionInfo* CreateHandlerData(
Address base, size_t size, size_t num_protected_instructions, uintptr_t base, size_t size, size_t num_protected_instructions,
const ProtectedInstructionData* protected_instructions) { const ProtectedInstructionData* protected_instructions) {
const size_t alloc_size = HandlerDataSize(num_protected_instructions); const size_t alloc_size = HandlerDataSize(num_protected_instructions);
CodeProtectionInfo* data = CodeProtectionInfo* data =
...@@ -131,9 +131,8 @@ CodeProtectionInfo* CreateHandlerData( ...@@ -131,9 +131,8 @@ CodeProtectionInfo* CreateHandlerData(
} }
int RegisterHandlerData( int RegisterHandlerData(
Address base, size_t size, size_t num_protected_instructions, uintptr_t base, size_t size, size_t num_protected_instructions,
const ProtectedInstructionData* protected_instructions) { const ProtectedInstructionData* protected_instructions) {
CodeProtectionInfo* data = CreateHandlerData( CodeProtectionInfo* data = CreateHandlerData(
base, size, num_protected_instructions, protected_instructions); base, size, num_protected_instructions, protected_instructions);
...@@ -188,7 +187,7 @@ int RegisterHandlerData( ...@@ -188,7 +187,7 @@ int RegisterHandlerData(
gNumCodeObjects = new_size; gNumCodeObjects = new_size;
} }
DCHECK(gCodeObjects[i].code_info == nullptr); TH_DCHECK(gCodeObjects[i].code_info == nullptr);
// Find out where the next entry should go. // Find out where the next entry should go.
gNextCodeObject = gCodeObjects[i].next_free; gNextCodeObject = gCodeObjects[i].next_free;
...@@ -211,7 +210,7 @@ void ReleaseHandlerData(int index) { ...@@ -211,7 +210,7 @@ void ReleaseHandlerData(int index) {
if (index == kInvalidIndex) { if (index == kInvalidIndex) {
return; return;
} }
DCHECK_GE(index, 0); TH_DCHECK(index >= 0);
// Remove the data from the global list if it's there. // Remove the data from the global list if it's there.
CodeProtectionInfo* data = nullptr; CodeProtectionInfo* data = nullptr;
...@@ -230,7 +229,7 @@ void ReleaseHandlerData(int index) { ...@@ -230,7 +229,7 @@ void ReleaseHandlerData(int index) {
} }
// TODO(eholk): on debug builds, ensure there are no more copies in // TODO(eholk): on debug builds, ensure there are no more copies in
// the list. // the list.
DCHECK_NOT_NULL(data); // make sure we're releasing legitimate handler data. TH_DCHECK(data); // make sure we're releasing legitimate handler data.
free(data); free(data);
} }
...@@ -259,9 +258,9 @@ bool EnableTrapHandler(bool use_v8_handler) { ...@@ -259,9 +258,9 @@ bool EnableTrapHandler(bool use_v8_handler) {
// trap handlers are disabled. // trap handlers are disabled.
bool can_enable = bool can_enable =
g_can_enable_trap_handler.exchange(false, std::memory_order_relaxed); g_can_enable_trap_handler.exchange(false, std::memory_order_relaxed);
if (!can_enable) { // EnableTrapHandler called twice, or after IsTrapHandlerEnabled.
FATAL("EnableTrapHandler called twice, or after IsTrapHandlerEnabled"); TH_CHECK(can_enable);
}
if (!V8_TRAP_HANDLER_SUPPORTED) { if (!V8_TRAP_HANDLER_SUPPORTED) {
return false; return false;
} }
......
...@@ -22,7 +22,7 @@ namespace trap_handler { ...@@ -22,7 +22,7 @@ namespace trap_handler {
// protected memory access instructions and an offset to a landing pad to handle // protected memory access instructions and an offset to a landing pad to handle
// faults on that instruction. // faults on that instruction.
struct CodeProtectionInfo { struct CodeProtectionInfo {
Address base; uintptr_t base;
size_t size; size_t size;
size_t num_protected_instructions; size_t num_protected_instructions;
ProtectedInstructionData instructions[1]; ProtectedInstructionData instructions[1];
......
...@@ -10,15 +10,13 @@ ...@@ -10,15 +10,13 @@
#include <atomic> #include <atomic>
#include "src/base/build_config.h" #include "include/v8config.h"
#include "src/common/globals.h" #include "src/base/immediate-crash.h"
#include "src/flags/flags.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace trap_handler { namespace trap_handler {
// TODO(eholk): Support trap handlers on other platforms.
#if V8_TARGET_ARCH_X64 && V8_OS_LINUX && !V8_OS_ANDROID #if V8_TARGET_ARCH_X64 && V8_OS_LINUX && !V8_OS_ANDROID
#define V8_TRAP_HANDLER_SUPPORTED true #define V8_TRAP_HANDLER_SUPPORTED true
#elif V8_TARGET_ARCH_X64 && V8_OS_WIN #elif V8_TARGET_ARCH_X64 && V8_OS_WIN
...@@ -33,6 +31,35 @@ namespace trap_handler { ...@@ -33,6 +31,35 @@ namespace trap_handler {
#define V8_TRAP_HANDLER_SUPPORTED false #define V8_TRAP_HANDLER_SUPPORTED false
#endif #endif
// Setup for shared library export.
#if defined(BUILDING_V8_SHARED) && defined(V8_OS_WIN)
#define TH_EXPORT_PRIVATE __declspec(dllexport)
#elif defined(BUILDING_V8_SHARED)
#define TH_EXPORT_PRIVATE __attribute__((visibility("default")))
#elif defined(USING_V8_SHARED) && defined(V8_OS_WIN)
#define TH_EXPORT_PRIVATE __declspec(dllimport)
#else
#define TH_EXPORT_PRIVATE
#endif
#define TH_CHECK(condition) \
if (!(condition)) IMMEDIATE_CRASH();
#ifdef DEBUG
#define TH_DCHECK(condition) TH_CHECK(condition)
#else
#define TH_DCHECK(condition) void(0)
#endif
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define TH_DISABLE_ASAN __attribute__((no_sanitize_address))
#else
#define TH_DISABLE_ASAN
#endif
#else
#define TH_DISABLE_ASAN
#endif
struct ProtectedInstructionData { struct ProtectedInstructionData {
// The offset of this instruction from the start of its code object. // The offset of this instruction from the start of its code object.
// Wasm code never grows larger than 2GB, so uint32_t is sufficient. // Wasm code never grows larger than 2GB, so uint32_t is sufficient.
...@@ -50,14 +77,14 @@ const int kInvalidIndex = -1; ...@@ -50,14 +77,14 @@ const int kInvalidIndex = -1;
/// ///
/// This returns a number that can be used to identify the handler data to /// This returns a number that can be used to identify the handler data to
/// ReleaseHandlerData, or -1 on failure. /// ReleaseHandlerData, or -1 on failure.
int V8_EXPORT_PRIVATE RegisterHandlerData( int TH_EXPORT_PRIVATE RegisterHandlerData(
Address base, size_t size, size_t num_protected_instructions, uintptr_t base, size_t size, size_t num_protected_instructions,
const ProtectedInstructionData* protected_instructions); const ProtectedInstructionData* protected_instructions);
/// Removes the data from the master list and frees any memory, if necessary. /// Removes the data from the master list and frees any memory, if necessary.
/// TODO(mtrofin): We can switch to using size_t for index and not need /// TODO(mtrofin): We can switch to using size_t for index and not need
/// kInvalidIndex. /// kInvalidIndex.
void V8_EXPORT_PRIVATE ReleaseHandlerData(int index); void TH_EXPORT_PRIVATE ReleaseHandlerData(int index);
// Initially false, set to true if when trap handlers are enabled. Never goes // Initially false, set to true if when trap handlers are enabled. Never goes
// back to false then. // back to false then.
...@@ -74,10 +101,10 @@ extern std::atomic<bool> g_can_enable_trap_handler; ...@@ -74,10 +101,10 @@ extern std::atomic<bool> g_can_enable_trap_handler;
// //
// use_v8_handler indicates that V8 should install its own handler // use_v8_handler indicates that V8 should install its own handler
// rather than relying on the embedder to do it. // rather than relying on the embedder to do it.
V8_EXPORT_PRIVATE bool EnableTrapHandler(bool use_v8_handler); TH_EXPORT_PRIVATE bool EnableTrapHandler(bool use_v8_handler);
inline bool IsTrapHandlerEnabled() { inline bool IsTrapHandlerEnabled() {
DCHECK_IMPLIES(g_is_trap_handler_enabled, V8_TRAP_HANDLER_SUPPORTED); TH_DCHECK(!g_is_trap_handler_enabled || V8_TRAP_HANDLER_SUPPORTED);
// Disallow enabling the trap handler after retrieving the current value. // Disallow enabling the trap handler after retrieving the current value.
// Re-enabling them late can produce issues because code or objects might have // Re-enabling them late can produce issues because code or objects might have
// been generated under the assumption that trap handlers are disabled. // been generated under the assumption that trap handlers are disabled.
...@@ -93,29 +120,29 @@ extern thread_local int g_thread_in_wasm_code; ...@@ -93,29 +120,29 @@ extern thread_local int g_thread_in_wasm_code;
// Return the address of the thread-local {g_thread_in_wasm_code} variable. This // Return the address of the thread-local {g_thread_in_wasm_code} variable. This
// pointer can be accessed and modified as long as the thread calling this // pointer can be accessed and modified as long as the thread calling this
// function exists. Only use if from the same thread do avoid race conditions. // function exists. Only use if from the same thread do avoid race conditions.
V8_NOINLINE V8_EXPORT_PRIVATE int* GetThreadInWasmThreadLocalAddress(); V8_NOINLINE TH_EXPORT_PRIVATE int* GetThreadInWasmThreadLocalAddress();
// On Windows, asan installs its own exception handler which maps shadow // On Windows, asan installs its own exception handler which maps shadow
// memory. Since our exception handler may be executed before the asan exception // memory. Since our exception handler may be executed before the asan exception
// handler, we have to make sure that asan shadow memory is not accessed here. // handler, we have to make sure that asan shadow memory is not accessed here.
DISABLE_ASAN inline bool IsThreadInWasm() { return g_thread_in_wasm_code; } TH_DISABLE_ASAN inline bool IsThreadInWasm() { return g_thread_in_wasm_code; }
inline void SetThreadInWasm() { inline void SetThreadInWasm() {
if (IsTrapHandlerEnabled()) { if (IsTrapHandlerEnabled()) {
DCHECK(!IsThreadInWasm()); TH_DCHECK(!IsThreadInWasm());
g_thread_in_wasm_code = true; g_thread_in_wasm_code = true;
} }
} }
inline void ClearThreadInWasm() { inline void ClearThreadInWasm() {
if (IsTrapHandlerEnabled()) { if (IsTrapHandlerEnabled()) {
DCHECK(IsThreadInWasm()); TH_DCHECK(IsThreadInWasm());
g_thread_in_wasm_code = false; g_thread_in_wasm_code = false;
} }
} }
bool RegisterDefaultTrapHandler(); bool RegisterDefaultTrapHandler();
V8_EXPORT_PRIVATE void RemoveTrapHandler(); TH_EXPORT_PRIVATE void RemoveTrapHandler();
size_t GetRecoveredTrapCount(); size_t GetRecoveredTrapCount();
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "include/v8.h" #include "include/v8.h"
#include "src/flags/flags.h"
#include "src/trap-handler/trap-handler.h" #include "src/trap-handler/trap-handler.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment