Commit 418b5fc2 authored by Samuel Groß's avatar Samuel Groß Committed by V8 LUCI CQ

[sandbox] Store external pointers in EmbedderDataSlots in shifted form

Similar to other external pointers, the indices into the external
pointer table are stored shifted to the left to guarantee an upper
bound.

Bug: v8:10391
Change-Id: I079dc1568f49ae349c326a8e83fc32c93bdb35cf
Cq-Include-Trybots: luci.v8.try:v8_linux64_heap_sandbox_dbg_ng,v8_linux_arm64_sim_heap_sandbox_dbg_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3455152Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Samuel Groß <saelo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79209}
parent a6ab2ae6
...@@ -368,17 +368,17 @@ Local<Value> Context::GetEmbedderData(int index) { ...@@ -368,17 +368,17 @@ Local<Value> Context::GetEmbedderData(int index) {
} }
void* Context::GetAlignedPointerFromEmbedderData(int index) { void* Context::GetAlignedPointerFromEmbedderData(int index) {
using I = internal::Internals; #if !defined(V8_ENABLE_CHECKS)
static_assert(I::kEmbedderDataSlotSize == internal::kApiSystemPointerSize,
"Enable fast path with sandboxed external pointers enabled "
"once embedder data slots are 32 bits large");
#if !defined(V8_ENABLE_CHECKS) && !defined(V8_SANDBOXED_EXTERNAL_POINTERS)
using A = internal::Address; using A = internal::Address;
using I = internal::Internals;
A ctx = *reinterpret_cast<const A*>(this); A ctx = *reinterpret_cast<const A*>(this);
A embedder_data = A embedder_data =
I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset);
int value_offset = int value_offset =
I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index);
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
value_offset += I::kEmbedderDataSlotRawPayloadOffset;
#endif
internal::Isolate* isolate = I::GetIsolateForSandbox(ctx); internal::Isolate* isolate = I::GetIsolateForSandbox(ctx);
return reinterpret_cast<void*>( return reinterpret_cast<void*>(
I::ReadExternalPointerField(isolate, embedder_data, value_offset, I::ReadExternalPointerField(isolate, embedder_data, value_offset,
......
...@@ -735,18 +735,18 @@ Local<Value> Object::GetInternalField(int index) { ...@@ -735,18 +735,18 @@ Local<Value> Object::GetInternalField(int index) {
} }
void* Object::GetAlignedPointerFromInternalField(int index) { void* Object::GetAlignedPointerFromInternalField(int index) {
using I = internal::Internals; #if !defined(V8_ENABLE_CHECKS)
static_assert(I::kEmbedderDataSlotSize == internal::kApiSystemPointerSize,
"Enable fast path with sandboxed external pointers enabled "
"once embedder data slots are 32 bits large");
#if !defined(V8_ENABLE_CHECKS) && !defined(V8_SANDBOXED_EXTERNAL_POINTERS)
using A = internal::Address; using A = internal::Address;
using I = internal::Internals;
A obj = *reinterpret_cast<A*>(this); A obj = *reinterpret_cast<A*>(this);
// Fast path: If the object is a plain JSObject, which is the common case, we // Fast path: If the object is a plain JSObject, which is the common case, we
// know where to find the internal fields and can return the value directly. // know where to find the internal fields and can return the value directly.
auto instance_type = I::GetInstanceType(obj); auto instance_type = I::GetInstanceType(obj);
if (v8::internal::CanHaveInternalField(instance_type)) { if (v8::internal::CanHaveInternalField(instance_type)) {
int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index);
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
offset += I::kEmbedderDataSlotRawPayloadOffset;
#endif
internal::Isolate* isolate = I::GetIsolateForSandbox(obj); internal::Isolate* isolate = I::GetIsolateForSandbox(obj);
A value = I::ReadExternalPointerField( A value = I::ReadExternalPointerField(
isolate, obj, offset, internal::kEmbedderDataSlotPayloadTag); isolate, obj, offset, internal::kEmbedderDataSlotPayloadTag);
......
...@@ -527,10 +527,6 @@ Handle<EmbedderDataArray> Factory::NewEmbedderDataArray(int length) { ...@@ -527,10 +527,6 @@ Handle<EmbedderDataArray> Factory::NewEmbedderDataArray(int length) {
ObjectSlot end(array.slots_end()); ObjectSlot end(array.slots_end());
size_t slot_count = end - start; size_t slot_count = end - start;
MemsetTagged(start, *undefined_value(), slot_count); MemsetTagged(start, *undefined_value(), slot_count);
for (int i = 0; i < length; i++) {
// TODO(v8:10391, saelo): Handle external pointers in EmbedderDataSlot
EmbedderDataSlot(array, i).AllocateExternalPointerEntry(isolate());
}
} }
return handle(array, isolate()); return handle(array, isolate());
} }
......
...@@ -222,10 +222,11 @@ class MarkingVisitorBase : public HeapVisitor<int, ConcreteVisitor> { ...@@ -222,10 +222,11 @@ class MarkingVisitorBase : public HeapVisitor<int, ConcreteVisitor> {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS #ifdef V8_SANDBOXED_EXTERNAL_POINTERS
// When sandboxed external pointers are enabled, EmbedderDataSlots may // When sandboxed external pointers are enabled, EmbedderDataSlots may
// contain an external pointer, which must be marked as alive. // contain an external pointer, which must be marked as alive.
uint32_t maybe_index = base::Relaxed_Load(reinterpret_cast<base::Atomic32*>( base::Atomic32* ptr = reinterpret_cast<base::Atomic32*>(
slot.address() + EmbedderDataSlot::kRawPayloadOffset)); slot.address() + EmbedderDataSlot::kRawPayloadOffset);
if (external_pointer_table_->IsValidIndex(maybe_index)) { uint32_t index = base::Relaxed_Load(ptr) >> kExternalPointerIndexShift;
external_pointer_table_->Mark(maybe_index); if (external_pointer_table_->IsValidIndex(index)) {
external_pointer_table_->Mark(index);
} }
#endif // V8_SANDBOXED_EXTERNAL_POINTERS #endif // V8_SANDBOXED_EXTERNAL_POINTERS
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "src/objects/embedder-data-slot.h" #include "src/objects/embedder-data-slot.h"
#include "src/objects/js-objects-inl.h" #include "src/objects/js-objects-inl.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/sandbox/external-pointer-inl.h"
// Has to be the last include (doesn't have include guards): // Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h" #include "src/objects/object-macros.h"
...@@ -30,19 +31,6 @@ EmbedderDataSlot::EmbedderDataSlot(JSObject object, int embedder_field_index) ...@@ -30,19 +31,6 @@ EmbedderDataSlot::EmbedderDataSlot(JSObject object, int embedder_field_index)
EmbedderDataSlot::EmbedderDataSlot(const EmbedderDataSlotSnapshot& snapshot) EmbedderDataSlot::EmbedderDataSlot(const EmbedderDataSlotSnapshot& snapshot)
: SlotBase(reinterpret_cast<Address>(&snapshot)) {} : SlotBase(reinterpret_cast<Address>(&snapshot)) {}
void EmbedderDataSlot::AllocateExternalPointerEntry(Isolate* isolate) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
// TODO(v8:10391, saelo): Use InitExternalPointerField() once
// ExternalPointer_t is 4-bytes.
uint32_t index = isolate->external_pointer_table().Allocate();
// Object slots don't support storing raw values, so we just "reinterpret
// cast" the index value to Object.
Object index_as_object(index);
ObjectSlot(address() + kRawPayloadOffset).Relaxed_Store(index_as_object);
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(Smi::zero());
#endif
}
Object EmbedderDataSlot::load_tagged() const { Object EmbedderDataSlot::load_tagged() const {
return ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Load(); return ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Load();
} }
...@@ -89,12 +77,14 @@ bool EmbedderDataSlot::ToAlignedPointer(Isolate* isolate, ...@@ -89,12 +77,14 @@ bool EmbedderDataSlot::ToAlignedPointer(Isolate* isolate,
// are accessed this way only from the main thread via API during "mutator" // are accessed this way only from the main thread via API during "mutator"
// phase which is propely synched with GC (concurrent marker may still look // phase which is propely synched with GC (concurrent marker may still look
// at the tagged part of the embedder slot but read-only access is ok). // at the tagged part of the embedder slot but read-only access is ok).
Address raw_value;
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS #ifdef V8_SANDBOXED_EXTERNAL_POINTERS
uint32_t index = base::Memory<uint32_t>(address() + kRawPayloadOffset); // This might crash if the value is not a valid index.
raw_value = *out_pointer = reinterpret_cast<void*>(ReadExternalPointerField(
isolate->external_pointer_table().Get(index, kEmbedderDataSlotPayloadTag); address() + kRawPayloadOffset, isolate, kEmbedderDataSlotPayloadTag));
// We don't actually care if the pointer is aligned or not...
return true;
#else #else
Address raw_value;
if (COMPRESS_POINTERS_BOOL) { if (COMPRESS_POINTERS_BOOL) {
// TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
// fields (external pointers, doubles and BigInt data) are only kTaggedSize // fields (external pointers, doubles and BigInt data) are only kTaggedSize
...@@ -104,15 +94,17 @@ bool EmbedderDataSlot::ToAlignedPointer(Isolate* isolate, ...@@ -104,15 +94,17 @@ bool EmbedderDataSlot::ToAlignedPointer(Isolate* isolate,
} else { } else {
raw_value = *location(); raw_value = *location();
} }
#endif
*out_pointer = reinterpret_cast<void*>(raw_value); *out_pointer = reinterpret_cast<void*>(raw_value);
return HAS_SMI_TAG(raw_value); return HAS_SMI_TAG(raw_value);
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
} }
bool EmbedderDataSlot::ToAlignedPointerSafe(Isolate* isolate, bool EmbedderDataSlot::ToAlignedPointerSafe(Isolate* isolate,
void** out_pointer) const { void** out_pointer) const {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS #ifdef V8_SANDBOXED_EXTERNAL_POINTERS
uint32_t index = base::Memory<uint32_t>(address() + kRawPayloadOffset); uint32_t index = base::Memory<uint32_t>(address() + kRawPayloadOffset);
if (!HAS_SMI_TAG(index)) return false;
index >>= kExternalPointerIndexShift;
Address raw_value; Address raw_value;
if (isolate->external_pointer_table().IsValidIndex(index)) { if (isolate->external_pointer_table().IsValidIndex(index)) {
raw_value = isolate->external_pointer_table().Get( raw_value = isolate->external_pointer_table().Get(
...@@ -137,22 +129,16 @@ bool EmbedderDataSlot::store_aligned_pointer(Isolate* isolate, void* ptr) { ...@@ -137,22 +129,16 @@ bool EmbedderDataSlot::store_aligned_pointer(Isolate* isolate, void* ptr) {
Address value = reinterpret_cast<Address>(ptr); Address value = reinterpret_cast<Address>(ptr);
if (!HAS_SMI_TAG(value)) return false; if (!HAS_SMI_TAG(value)) return false;
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS #ifdef V8_SANDBOXED_EXTERNAL_POINTERS
if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL) { DCHECK_EQ(0, value & kExternalPointerTagMask);
DCHECK_EQ(0, value & kExternalPointerTagMask); // This also mark the entry as alive until the next GC.
AllocateExternalPointerEntry(isolate); InitExternalPointerField(address() + kRawPayloadOffset, isolate, value,
// Raw payload contains the table index. Object slots don't support loading kEmbedderDataSlotPayloadTag);
// of raw values, so we just "reinterpret cast" Object value to index. ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(Smi::zero());
Object index_as_object = return true;
ObjectSlot(address() + kRawPayloadOffset).Relaxed_Load(); #else
uint32_t index = static_cast<uint32_t>(index_as_object.ptr());
// This also mark the entry as alive until the next GC.
isolate->external_pointer_table().Set(index, value,
kEmbedderDataSlotPayloadTag);
return true;
}
#endif
gc_safe_store(isolate, value); gc_safe_store(isolate, value);
return true; return true;
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
} }
EmbedderDataSlot::RawData EmbedderDataSlot::load_raw( EmbedderDataSlot::RawData EmbedderDataSlot::load_raw(
......
...@@ -62,8 +62,6 @@ class EmbedderDataSlot ...@@ -62,8 +62,6 @@ class EmbedderDataSlot
// Opaque type used for storing raw embedder data. // Opaque type used for storing raw embedder data.
using RawData = Address; using RawData = Address;
V8_INLINE void AllocateExternalPointerEntry(Isolate* isolate);
V8_INLINE Object load_tagged() const; V8_INLINE Object load_tagged() const;
V8_INLINE void store_smi(Smi value); V8_INLINE void store_smi(Smi value);
......
...@@ -308,10 +308,6 @@ int JSObject::GetEmbedderFieldOffset(int index) { ...@@ -308,10 +308,6 @@ int JSObject::GetEmbedderFieldOffset(int index) {
return GetEmbedderFieldsStartOffset() + (kEmbedderDataSlotSize * index); return GetEmbedderFieldsStartOffset() + (kEmbedderDataSlotSize * index);
} }
void JSObject::InitializeEmbedderField(Isolate* isolate, int index) {
EmbedderDataSlot(*this, index).AllocateExternalPointerEntry(isolate);
}
Object JSObject::GetEmbedderField(int index) { Object JSObject::GetEmbedderField(int index) {
return EmbedderDataSlot(*this, index).load_tagged(); return EmbedderDataSlot(*this, index).load_tagged();
} }
......
...@@ -611,7 +611,6 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> { ...@@ -611,7 +611,6 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
static inline int GetEmbedderFieldCount(Map map); static inline int GetEmbedderFieldCount(Map map);
inline int GetEmbedderFieldCount() const; inline int GetEmbedderFieldCount() const;
inline int GetEmbedderFieldOffset(int index); inline int GetEmbedderFieldOffset(int index);
inline void InitializeEmbedderField(Isolate* isolate, int index);
inline Object GetEmbedderField(int index); inline Object GetEmbedderField(int index);
inline void SetEmbedderField(int index, Object value); inline void SetEmbedderField(int index, Object value);
inline void SetEmbedderField(int index, Smi value); inline void SetEmbedderField(int index, Smi value);
......
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