Commit e5e30b34 authored by jgruber's avatar jgruber Committed by Commit Bot

[wasm] Ensure all wasm runtime stubs are PIC

Some builtins, so-called wasm runtime stubs, are copied off-heap to
ensure reachability through near jumps. These builtins must be
individually position-independent. In particular, they may not contain
pc-relative calls to other builtins.

Drive-by: Set hard_abort mode for all wasm runtime stubs to avoid Abort
calls.

Bug: v8:6666
Change-Id: Ie5bc9fc539d6a043dcf7dff66c3b4643baec69ab
Reviewed-on: https://chromium-review.googlesource.com/1183236
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55296}
parent f0409b91
......@@ -167,7 +167,7 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......@@ -283,7 +283,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......
......@@ -1440,6 +1440,18 @@ namespace internal {
V(PromiseRace) \
V(ResolvePromise)
// Convenience macro listing all wasm runtime stubs. Note that the first few
// elements of the list coincide with {compiler::TrapId}, order matters.
#define WASM_RUNTIME_STUB_LIST(V, VTRAP) \
FOREACH_WASM_TRAPREASON(VTRAP) \
V(WasmAllocateHeapNumber) \
V(WasmArgumentsAdaptor) \
V(WasmCallJavaScript) \
V(WasmGrowMemory) \
V(WasmStackGuard) \
V(WasmToNumber) \
V(DoubleToI)
// The exception thrown in the following builtins are caught internally and will
// not be propagated further or re-thrown
#define BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(V) V(PromiseRejectReactionJob)
......
......@@ -354,6 +354,22 @@ bool Builtins::IsIsolateIndependent(int index) {
UNREACHABLE();
}
// static
bool Builtins::IsWasmRuntimeStub(int index) {
DCHECK(IsBuiltinId(index));
switch (index) {
#define CASE_TRAP(Name) case kThrowWasm##Name:
#define CASE(Name) case k##Name:
WASM_RUNTIME_STUB_LIST(CASE, CASE_TRAP)
#undef CASE_TRAP
#undef CASE
return true;
default:
return false;
}
UNREACHABLE();
}
// static
Handle<Code> Builtins::GenerateOffHeapTrampolineFor(Isolate* isolate,
Address off_heap_entry) {
......
......@@ -51,7 +51,7 @@ class Builtins {
static const int32_t kNoBuiltinId = -1;
static bool IsBuiltinId(int maybe_id) {
static constexpr bool IsBuiltinId(int maybe_id) {
return 0 <= maybe_id && maybe_id < builtin_count;
}
......@@ -115,6 +115,11 @@ class Builtins {
// TODO(jgruber,v8:6666): Remove once all builtins have been migrated.
static bool IsIsolateIndependent(int index);
// Wasm runtime stubs are treated specially by wasm. To guarantee reachability
// through near jumps, their code is completely copied into a fresh off-heap
// area.
static bool IsWasmRuntimeStub(int index);
bool is_initialized() const { return initialized_; }
// Used by SetupIsolateDelegate and Deserializer.
......
......@@ -89,7 +89,9 @@ CodeGenerator::CodeGenerator(
Code::Kind code_kind = info_->code_kind();
if (code_kind == Code::WASM_FUNCTION ||
code_kind == Code::WASM_TO_JS_FUNCTION ||
code_kind == Code::WASM_INTERPRETER_ENTRY) {
code_kind == Code::WASM_INTERPRETER_ENTRY ||
(Builtins::IsBuiltinId(builtin_index) &&
Builtins::IsWasmRuntimeStub(builtin_index))) {
tasm_.set_abort_hard(true);
}
tasm_.set_builtin_index(builtin_index);
......
......@@ -1830,7 +1830,7 @@ void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
GenerateDeoptimizationEntries(&masm, kMaxNumberOfEntries, kind);
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
// Allocate the code as immovable since the entry addresses will be used
// directly and there is no support for relocating them.
......
......@@ -36,7 +36,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......@@ -448,7 +448,7 @@ MemMoveFunction CreateMemMoveFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
// TODO(jkummerow): It would be nice to register this code creation event
......
......@@ -542,7 +542,7 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
}
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......@@ -569,7 +569,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......
......@@ -543,7 +543,7 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
}
CodeDesc desc;
masm.GetCode(isolte, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......@@ -570,7 +570,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......
......@@ -14325,11 +14325,11 @@ void Code::CopyFrom(Heap* heap, const CodeDesc& desc) {
}
void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
// copy code
// Copy code.
CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer,
static_cast<size_t>(desc.instr_size));
// copy unwinding info, if any
// Copy unwinding info, if any.
if (desc.unwinding_info) {
DCHECK_GT(desc.unwinding_info_size, 0);
set_unwinding_info_size(desc.unwinding_info_size);
......@@ -14338,20 +14338,15 @@ void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
static_cast<size_t>(desc.unwinding_info_size));
}
// copy reloc info
// Copy reloc info.
CopyBytes(relocation_start(),
desc.buffer + desc.buffer_size - desc.reloc_size,
static_cast<size_t>(desc.reloc_size));
// unbox handles and relocate
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
RelocInfo::kApplyMask;
// Needed to find target_object and runtime_entry on X64
// Unbox handles and relocate.
Assembler* origin = desc.origin;
AllowDeferredHandleDereference embedding_raw_address;
const int mode_mask = RelocInfo::PostCodegenRelocationMask();
for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
......@@ -14359,8 +14354,8 @@ void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
it.rinfo()->set_target_object(heap, *p, UPDATE_WRITE_BARRIER,
SKIP_ICACHE_FLUSH);
} else if (RelocInfo::IsCodeTargetMode(mode)) {
// rewrite code handles to direct pointers to the first instruction in the
// code object
// Rewrite code handles to direct pointers to the first instruction in the
// code object.
Handle<Object> p = it.rinfo()->target_object_handle(origin);
Code* code = Code::cast(*p);
it.rinfo()->set_target_address(code->raw_instruction_start(),
......
......@@ -37,7 +37,8 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(ABI_USES_FUNCTION_DESCRIPTORS || !RelocInfo::RequiresRelocation(desc));
DCHECK(ABI_USES_FUNCTION_DESCRIPTORS ||
!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......
......@@ -376,19 +376,15 @@ void RelocInfo::set_target_address(Address target,
}
}
#ifdef DEBUG
bool RelocInfo::RequiresRelocation(const CodeDesc& desc) {
// Ensure there are no code targets or embedded objects present in the
// deoptimization entries, they would require relocation after code
// generation.
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::kApplyMask;
RelocIterator it(desc, mode_mask);
bool RelocInfo::RequiresRelocationAfterCodegen(const CodeDesc& desc) {
RelocIterator it(desc, RelocInfo::PostCodegenRelocationMask());
return !it.done();
}
bool RelocInfo::RequiresRelocation(Code* code) {
RelocIterator it(code, RelocInfo::kApplyMask);
return !it.done();
}
#endif
#ifdef ENABLE_DISASSEMBLER
const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
......
......@@ -293,11 +293,10 @@ class RelocInfo {
template <typename ObjectVisitor>
inline void Visit(ObjectVisitor* v);
#ifdef DEBUG
// Check whether the given code contains relocation information that
// either is position-relative or movable by the garbage collector.
static bool RequiresRelocation(const CodeDesc& desc);
#endif
static bool RequiresRelocationAfterCodegen(const CodeDesc& desc);
static bool RequiresRelocation(Code* code);
#ifdef ENABLE_DISASSEMBLER
// Printing
......@@ -310,6 +309,16 @@ class RelocInfo {
static const int kApplyMask; // Modes affected by apply. Depends on arch.
// In addition to modes covered by the apply mask (which is applied at GC
// time, among others), this covers all modes that are relocated by
// Code::CopyFromNoFlush after code generation.
static int PostCodegenRelocationMask() {
return ModeMask(RelocInfo::CODE_TARGET) |
ModeMask(RelocInfo::EMBEDDED_OBJECT) |
ModeMask(RelocInfo::RUNTIME_ENTRY) |
ModeMask(RelocInfo::RELATIVE_CODE_TARGET) | kApplyMask;
}
private:
// On ARM/ARM64, note that pc_ is the address of the instruction referencing
// the constant pool and not the address of the constant pool entry.
......
......@@ -34,7 +34,8 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(ABI_USES_FUNCTION_DESCRIPTORS || !RelocInfo::RequiresRelocation(desc));
DCHECK(ABI_USES_FUNCTION_DESCRIPTORS ||
!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......
......@@ -400,6 +400,16 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
saw_unsafe_builtin = true;
fprintf(stderr, "%s is not isolate-independent.\n", Builtins::name(i));
}
if (Builtins::IsWasmRuntimeStub(i) &&
RelocInfo::RequiresRelocation(code)) {
// Wasm additionally requires that its runtime stubs must be
// individually PIC (i.e. we must be able to copy each stub outside the
// embedded area without relocations). In particular, that means
// pc-relative calls to other builtins are disallowed.
saw_unsafe_builtin = true;
fprintf(stderr, "%s is a wasm runtime stub but needs relocation.\n",
Builtins::name(i));
}
if (BuiltinAliasesOffHeapTrampolineRegister(isolate, code)) {
saw_unsafe_builtin = true;
fprintf(stderr, "%s aliases the off-heap trampoline register.\n",
......
......@@ -12,6 +12,7 @@
#include <unordered_set>
#include "src/base/macros.h"
#include "src/builtins/builtins-definitions.h"
#include "src/handles.h"
#include "src/trap-handler/trap-handler.h"
#include "src/vector.h"
......@@ -30,18 +31,6 @@ class NativeModule;
class WasmCodeManager;
struct WasmModule;
// Convenience macro listing all wasm runtime stubs. Note that the first few
// elements of the list coincide with {compiler::TrapId}, order matters.
#define WASM_RUNTIME_STUB_LIST(V, VTRAP) \
FOREACH_WASM_TRAPREASON(VTRAP) \
V(WasmAllocateHeapNumber) \
V(WasmArgumentsAdaptor) \
V(WasmCallJavaScript) \
V(WasmGrowMemory) \
V(WasmStackGuard) \
V(WasmToNumber) \
V(DoubleToI)
struct AddressRange {
Address start;
Address end;
......
......@@ -29,7 +29,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
CodeDesc desc;
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
DCHECK(!RelocInfo::RequiresRelocationAfterCodegen(desc));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
......
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