Commit 6b485048 authored by Patrick Thier's avatar Patrick Thier Committed by V8 LUCI CQ

[sandbox] Add shared external pointer table for strings

To be able to share external strings, we need to share the external
pointer table in sandbox builds.
To avoid branches at runtime all pointers for external strings are
stored in the shared external pointer table.

Bug: v8:12957
Change-Id: Iaa6be7839a2f5e50f80fd58c5b33fb9c6af61057
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3695263Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarSamuel Groß <saelo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81324}
parent 809f10e8
......@@ -309,8 +309,12 @@ enum ExternalPointerTag : uint64_t {
kExternalPointerNullTag = MAKE_TAG(0b0000000000000000),
kExternalPointerFreeEntryTag = MAKE_TAG(0b0111111100000000),
kWaiterQueueNodeTag = MAKE_TAG(0b1000000111111111),
// Begin shared external object tags
// Update kSharedExternalObjectMask and kSharedExternalObjectTag when new
// tags are shared.
kExternalStringResourceTag = MAKE_TAG(0b1000001011111111),
kExternalStringResourceDataTag = MAKE_TAG(0b1000001101111111),
// End shared external object tags
kForeignForeignAddressTag = MAKE_TAG(0b1000001110111111),
kNativeContextMicrotaskQueueTag = MAKE_TAG(0b1000001111011111),
kEmbedderDataSlotPayloadTag = MAKE_TAG(0b1000001111101111),
......@@ -323,8 +327,22 @@ enum ExternalPointerTag : uint64_t {
kAccessorInfoSetterTag = MAKE_TAG(0b1000010110111111),
};
// clang-format on
// Shared external pointers can be access from shared isolates. They are stored
// in a shared external pointer table.
constexpr uint64_t kSharedExternalObjectMask = MAKE_TAG(0b1111111001111111);
constexpr uint64_t kSharedExternalObjectTag = MAKE_TAG(0b1000001001111111);
#undef MAKE_TAG
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
// True if the external resource can be accessed from shared isolates.
V8_INLINE static constexpr bool IsExternalPointerTagShareable(
ExternalPointerTag tag) {
return (tag & kSharedExternalObjectMask) == kSharedExternalObjectTag;
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
// {obj} must be the raw tagged pointer representation of a HeapObject
// that's guaranteed to never be in ReadOnlySpace.
V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
......@@ -406,8 +424,10 @@ class Internals {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
static const int kIsolateExternalPointerTableOffset =
kIsolateLongTaskStatsCounterOffset + kApiSizetSize;
static const int kIsolateRootsOffset =
static const int kIsolateSharedExternalPointerTableAddressOffset =
kIsolateExternalPointerTableOffset + kExternalPointerTableSize;
static const int kIsolateRootsOffset =
kIsolateSharedExternalPointerTableAddressOffset + kApiSystemPointerSize;
#else
static const int kIsolateRootsOffset =
kIsolateLongTaskStatsCounterOffset + kApiSizetSize;
......@@ -569,6 +589,15 @@ class Internals {
kExternalPointerTableBufferOffset;
return *reinterpret_cast<internal::Address**>(addr);
}
V8_INLINE static internal::Address* GetSharedExternalPointerTableBase(
v8::Isolate* isolate) {
internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
kIsolateSharedExternalPointerTableAddressOffset;
addr = *reinterpret_cast<internal::Address*>(addr);
addr += kExternalPointerTableBufferOffset;
return *reinterpret_cast<internal::Address**>(addr);
}
#endif
template <typename T>
......@@ -627,7 +656,9 @@ class Internals {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
// See src/sandbox/external-pointer-table-inl.h. Logic duplicated here so it
// can be inlined in embedder code and doesn't require an additional call.
internal::Address* table = GetExternalPointerTableBase(isolate);
internal::Address* table = IsExternalPointerTagShareable(tag)
? GetSharedExternalPointerTableBase(isolate)
: GetExternalPointerTableBase(isolate);
internal::ExternalPointer_t encoded_value =
ReadRawField<ExternalPointer_t>(heap_object_ptr, offset);
uint32_t index = encoded_value >> kExternalPointerIndexShift;
......
......@@ -3165,6 +3165,7 @@ void TurboAssembler::LoadExternalPointerField(Register destination,
ASM_CODE_COMMENT(this);
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
DCHECK_NE(kExternalPointerNullTag, tag);
DCHECK(!IsExternalPointerTagShareable(tag));
UseScratchRegisterScope temps(this);
Register external_table = temps.AcquireX();
if (isolate_root == no_reg) {
......
......@@ -1561,13 +1561,27 @@ TNode<Uint32T> CodeStubAssembler::ChangeExternalPointerToIndex(
TNode<Uint32T> shifted_index = ReinterpretCast<Uint32T>(external_pointer);
return Word32Shr(shifted_index, Uint32Constant(kExternalPointerIndexShift));
}
TNode<RawPtrT> CodeStubAssembler::ExternalPointerTableAddress(
ExternalPointerTag external_pointer_tag) {
if (IsExternalPointerTagShareable(external_pointer_tag)) {
TNode<ExternalReference> table_address_address = ExternalConstant(
ExternalReference::shared_external_pointer_table_address_address(
isolate()));
return UncheckedCast<RawPtrT>(
Load(MachineType::Pointer(), table_address_address));
}
return ExternalConstant(
ExternalReference::external_pointer_table_address(isolate()));
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
void CodeStubAssembler::InitializeExternalPointerField(TNode<HeapObject> object,
TNode<IntPtrT> offset) {
TNode<IntPtrT> offset,
ExternalPointerTag tag) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
TNode<ExternalReference> external_pointer_table_address = ExternalConstant(
ExternalReference::external_pointer_table_address(isolate()));
TNode<RawPtrT> external_pointer_table_address =
ExternalPointerTableAddress(tag);
// We could implement the fast path for allocating from the freelist here,
// however, this logic needs to be atomic and so requires CSA to expose
......@@ -1593,8 +1607,8 @@ TNode<RawPtrT> CodeStubAssembler::LoadExternalPointerFromObject(
TNode<HeapObject> object, TNode<IntPtrT> offset,
ExternalPointerTag external_pointer_tag) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
TNode<ExternalReference> external_pointer_table_address = ExternalConstant(
ExternalReference::external_pointer_table_address(isolate()));
TNode<RawPtrT> external_pointer_table_address =
ExternalPointerTableAddress(external_pointer_tag);
TNode<RawPtrT> table = UncheckedCast<RawPtrT>(
Load(MachineType::Pointer(), external_pointer_table_address,
UintPtrConstant(Internals::kExternalPointerTableBufferOffset)));
......@@ -1622,8 +1636,8 @@ void CodeStubAssembler::StoreExternalPointerToObject(
TNode<HeapObject> object, TNode<IntPtrT> offset, TNode<RawPtrT> pointer,
ExternalPointerTag external_pointer_tag) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
TNode<ExternalReference> external_pointer_table_address = ExternalConstant(
ExternalReference::external_pointer_table_address(isolate()));
TNode<RawPtrT> external_pointer_table_address =
ExternalPointerTableAddress(external_pointer_tag);
TNode<RawPtrT> table = UncheckedCast<RawPtrT>(
Load(MachineType::Pointer(), external_pointer_table_address,
UintPtrConstant(Internals::kExternalPointerTableBufferOffset)));
......
......@@ -1103,14 +1103,17 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
TNode<ExternalPointerT> ChangeIndexToExternalPointer(TNode<Uint32T> index);
TNode<Uint32T> ChangeExternalPointerToIndex(TNode<ExternalPointerT> pointer);
TNode<RawPtrT> ExternalPointerTableAddress(ExternalPointerTag tag);
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
// Initialize an external pointer field in an object.
void InitializeExternalPointerField(TNode<HeapObject> object, int offset) {
InitializeExternalPointerField(object, IntPtrConstant(offset));
void InitializeExternalPointerField(TNode<HeapObject> object, int offset,
ExternalPointerTag tag) {
InitializeExternalPointerField(object, IntPtrConstant(offset), tag);
}
void InitializeExternalPointerField(TNode<HeapObject> object,
TNode<IntPtrT> offset);
TNode<IntPtrT> offset,
ExternalPointerTag tag);
// Initialize an external pointer field in an object with given value.
void InitializeExternalPointerField(TNode<HeapObject> object, int offset,
......@@ -1124,7 +1127,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<IntPtrT> offset,
TNode<RawPtrT> pointer,
ExternalPointerTag tag) {
InitializeExternalPointerField(object, offset);
InitializeExternalPointerField(object, offset, tag);
StoreExternalPointerToObject(object, offset, pointer, tag);
}
......
......@@ -241,6 +241,14 @@ ExternalReference ExternalReference::external_pointer_table_address(
Isolate* isolate) {
return ExternalReference(isolate->external_pointer_table_address());
}
ExternalReference
ExternalReference::shared_external_pointer_table_address_address(
Isolate* isolate) {
return ExternalReference(
isolate->shared_external_pointer_table_address_address());
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
ExternalReference ExternalReference::interpreter_dispatch_table_address(
......
......@@ -85,6 +85,9 @@ class StatsCounter;
#define EXTERNAL_REFERENCE_LIST_WITH_ISOLATE_SANDBOXED_EXTERNAL_POINTERS(V) \
V(external_pointer_table_address, \
"Isolate::external_pointer_table_address(" \
")") \
V(shared_external_pointer_table_address_address, \
"Isolate::shared_external_pointer_table_address_address(" \
")")
#else
#define EXTERNAL_REFERENCE_LIST_WITH_ISOLATE_SANDBOXED_EXTERNAL_POINTERS(V)
......
......@@ -417,6 +417,7 @@ void TurboAssembler::LoadExternalPointerField(
DCHECK(!AreAliased(destination, scratch));
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
DCHECK_NE(kExternalPointerNullTag, tag);
DCHECK(!IsExternalPointerTagShareable(tag));
DCHECK(!field_operand.AddressUsesRegister(scratch));
if (isolateRootLocation == IsolateRootLocation::kInRootRegister) {
DCHECK(root_array_available_);
......
......@@ -13,7 +13,7 @@
#include "src/compiler/node.h"
#include "src/compiler/simplified-operator.h"
#include "src/roots/roots-inl.h"
#include "src/sandbox/external-pointer.h"
#include "src/sandbox/external-pointer-inl.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-linkage.h"
......@@ -437,7 +437,16 @@ Node* MemoryLowering::DecodeExternalPointer(
// the generated code is never executed under a different Isolate, as that
// would allow access to external objects from different Isolates. It also
// would break if the code is serialized/deserialized at some point.
Node* table_address = __ ExternalConstant(
Node* table_address =
IsExternalPointerTagShareable(external_pointer_tag)
? __
Load(MachineType::Pointer(),
__ ExternalConstant(
ExternalReference::
shared_external_pointer_table_address_address(
isolate())),
__ IntPtrConstant(0))
: __ ExternalConstant(
ExternalReference::external_pointer_table_address(isolate()));
Node* table = __ Load(MachineType::Pointer(), table_address,
Internals::kExternalPointerTableBufferOffset);
......
......@@ -2890,6 +2890,7 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t table_index,
Node* WasmGraphBuilder::BuildLoadExternalPointerFromObject(
Node* object, int offset, ExternalPointerTag tag) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
DCHECK(!IsExternalPointerTagShareable(tag));
Node* external_pointer = gasm_->LoadFromObject(
MachineType::Uint32(), object, wasm::ObjectAccess::ToTagged(offset));
static_assert(kExternalPointerIndexShift > kSystemPointerSizeLog2);
......
......@@ -58,7 +58,9 @@ class Isolate;
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
#define ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V) \
V(kExternalPointerTableOffset, ExternalPointerTable::kSize, \
external_pointer_table)
external_pointer_table) \
V(kSharedExternalPointerTableOffset, kSystemPointerSize, \
shared_external_pointer_table)
#else
#define ISOLATE_DATA_FIELDS_SANDBOXED_EXTERNAL_POINTERS(V)
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
......@@ -196,6 +198,7 @@ class IsolateData final {
// Table containing pointers to external objects.
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
ExternalPointerTable external_pointer_table_;
ExternalPointerTable* shared_external_pointer_table_;
#endif
RootsTable roots_table_;
......
......@@ -3559,6 +3559,11 @@ void Isolate::Deinit() {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
external_pointer_table().TearDown();
if (OwnsStringTables()) {
shared_external_pointer_table().TearDown();
delete isolate_data_.shared_external_pointer_table_;
isolate_data_.shared_external_pointer_table_ = nullptr;
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
{
......@@ -4115,6 +4120,14 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data,
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
external_pointer_table().Init(this);
if (OwnsStringTables()) {
isolate_data_.shared_external_pointer_table_ = new ExternalPointerTable();
shared_external_pointer_table().Init(this);
} else {
DCHECK_NOT_NULL(shared_isolate());
isolate_data_.shared_external_pointer_table_ =
shared_isolate()->isolate_data_.shared_external_pointer_table_;
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
#if V8_ENABLE_WEBASSEMBLY
......
......@@ -1964,6 +1964,19 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
return reinterpret_cast<Address>(&isolate_data_.external_pointer_table_);
}
ExternalPointerTable& shared_external_pointer_table() {
return *isolate_data_.shared_external_pointer_table_;
}
const ExternalPointerTable& shared_external_pointer_table() const {
return *isolate_data_.shared_external_pointer_table_;
}
Address shared_external_pointer_table_address_address() {
return reinterpret_cast<Address>(
&isolate_data_.shared_external_pointer_table_);
}
Maybe<ExternalPointer_t> GetWaiterQueueNodeExternalPointer() const {
return waiter_queue_node_external_pointer_;
}
......
......@@ -2092,6 +2092,7 @@ void MarkCompactCollector::MarkObjectsFromClientHeaps() {
// Custom marking for the external pointer table entry used to hold
// client Isolates' WaiterQueueNode, which is used by JS mutexes and
// condition variables.
DCHECK(!IsExternalPointerTagShareable(kWaiterQueueNodeTag));
ExternalPointer_t waiter_queue_ext;
if (client->GetWaiterQueueNodeExternalPointer().To(&waiter_queue_ext)) {
uint32_t index = waiter_queue_ext >> kExternalPointerIndexShift;
......@@ -2757,6 +2758,9 @@ void MarkCompactCollector::ClearNonLiveReferences() {
TRACE_GC(heap()->tracer(),
GCTracer::Scope::MC_SWEEP_EXTERNAL_POINTER_TABLE);
isolate()->external_pointer_table().Sweep(isolate());
if (isolate()->OwnsStringTables()) {
isolate()->shared_external_pointer_table().Sweep(isolate());
}
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
......
......@@ -13,6 +13,7 @@
#include "src/heap/spaces.h"
#include "src/objects/objects.h"
#include "src/objects/smi.h"
#include "src/sandbox/external-pointer-inl.h"
namespace v8 {
namespace internal {
......@@ -140,6 +141,19 @@ void MarkingVisitorBase<ConcreteVisitor, MarkingState>::VisitCodeTarget(
concrete_visitor()->RecordRelocSlot(host, rinfo, target);
}
template <typename ConcreteVisitor, typename MarkingState>
void MarkingVisitorBase<ConcreteVisitor, MarkingState>::VisitExternalPointer(
HeapObject host, ExternalPointerSlot slot, ExternalPointerTag tag) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
uint32_t index = slot.load_raw() >> kExternalPointerIndexShift;
if (IsExternalPointerTagShareable(tag)) {
shared_external_pointer_table_->Mark(index);
} else {
external_pointer_table_->Mark(index);
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
}
// ===========================================================================
// Object participating in bytecode flushing =================================
// ===========================================================================
......
......@@ -157,7 +157,9 @@ class MarkingVisitorBase : public HeapVisitor<int, ConcreteVisitor> {
is_shared_heap_(heap->IsShared())
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
,
external_pointer_table_(&heap->isolate()->external_pointer_table())
external_pointer_table_(&heap->isolate()->external_pointer_table()),
shared_external_pointer_table_(
&heap->isolate()->shared_external_pointer_table())
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
{
}
......@@ -210,12 +212,7 @@ class MarkingVisitorBase : public HeapVisitor<int, ConcreteVisitor> {
}
V8_INLINE void VisitExternalPointer(HeapObject host, ExternalPointerSlot slot,
ExternalPointerTag tag) final {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
uint32_t index = slot.load_raw() >> kExternalPointerIndexShift;
external_pointer_table_->Mark(index);
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
}
ExternalPointerTag tag) final;
protected:
ConcreteVisitor* concrete_visitor() {
......@@ -286,6 +283,7 @@ class MarkingVisitorBase : public HeapVisitor<int, ConcreteVisitor> {
const bool is_shared_heap_;
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
ExternalPointerTable* const external_pointer_table_;
ExternalPointerTable* const shared_external_pointer_table_;
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
};
......
......@@ -19,7 +19,11 @@ V8_INLINE Address DecodeExternalPointer(const Isolate* isolate,
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
static_assert(kExternalPointerSize == kInt32Size);
uint32_t index = encoded_pointer >> kExternalPointerIndexShift;
return isolate->external_pointer_table().Get(index, tag);
const ExternalPointerTable& table =
IsExternalPointerTagShareable(tag)
? isolate->shared_external_pointer_table()
: isolate->external_pointer_table();
return table.Get(index, tag);
#else
static_assert(kExternalPointerSize == kSystemPointerSize);
return encoded_pointer;
......@@ -32,7 +36,10 @@ V8_INLINE Address DecodeAndClearExternalPointer(
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
static_assert(kExternalPointerSize == kInt32Size);
uint32_t index = encoded_pointer >> kExternalPointerIndexShift;
return isolate->external_pointer_table().Exchange(index, kNullAddress, tag);
ExternalPointerTable& table = IsExternalPointerTagShareable(tag)
? isolate->shared_external_pointer_table()
: isolate->external_pointer_table();
return table.Exchange(index, kNullAddress, tag);
#else
// There is nothing to clear when external pointers are not sandboxed since
// there is no double indirection.
......@@ -49,8 +56,11 @@ V8_INLINE void InitExternalPointerField(Address field_address, Isolate* isolate,
V8_INLINE void InitExternalPointerField(Address field_address, Isolate* isolate,
Address value, ExternalPointerTag tag) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
ExternalPointer_t index = isolate->external_pointer_table().Allocate();
isolate->external_pointer_table().Set(index, value, tag);
ExternalPointerTable& table = IsExternalPointerTagShareable(tag)
? isolate->shared_external_pointer_table()
: isolate->external_pointer_table();
ExternalPointer_t index = table.Allocate();
table.Set(index, value, tag);
index <<= kExternalPointerIndexShift;
base::Memory<ExternalPointer_t>(field_address) = index;
#else
......@@ -102,7 +112,10 @@ V8_INLINE void WriteExternalPointerField(Address field_address,
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
ExternalPointer_t index = base::Memory<ExternalPointer_t>(field_address);
index >>= kExternalPointerIndexShift;
isolate->external_pointer_table().Set(index, value, tag);
ExternalPointerTable& table = IsExternalPointerTagShareable(tag)
? isolate->shared_external_pointer_table()
: isolate->external_pointer_table();
table.Set(index, value, tag);
#else
// Pointer compression causes types larger than kTaggedSize to be unaligned.
constexpr bool v8_pointer_compression_unaligned =
......
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