Commit 679945ff authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[sandbox][x64] Access external pointer in Foreign via bottlenecks

Bug: v8:10391
Change-Id: Ie019eb6253fdd29bfbae6a9f77c8b3396dacb599
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2134141
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67488}
parent 4d2da932
......@@ -145,7 +145,6 @@ class Internals {
1 * kApiTaggedSize + 2 * kApiInt32Size;
static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
static const int kForeignAddressOffset = kApiTaggedSize;
static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
......
......@@ -8707,11 +8707,7 @@ void Isolate::EnqueueMicrotask(Local<Function> v8_function) {
void Isolate::EnqueueMicrotask(MicrotaskCallback callback, void* data) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
i::HandleScope scope(isolate);
i::Handle<i::CallbackTask> microtask = isolate->factory()->NewCallbackTask(
isolate->factory()->NewForeign(reinterpret_cast<i::Address>(callback)),
isolate->factory()->NewForeign(reinterpret_cast<i::Address>(data)));
isolate->default_microtask_queue()->EnqueueMicrotask(*microtask);
isolate->default_microtask_queue()->EnqueueMicrotask(this, callback, data);
}
void Isolate::SetMicrotasksPolicy(MicrotasksPolicy policy) {
......
......@@ -575,7 +575,7 @@ void CallOrConstructBuiltinsAssembler::CallFunctionTemplate(
TNode<Foreign> foreign = LoadObjectField<Foreign>(
call_handler_info, CallHandlerInfo::kJsCallbackOffset);
TNode<RawPtrT> callback =
LoadObjectField<RawPtrT>(foreign, Foreign::kForeignAddressOffset);
DecodeExternalPointer(LoadForeignForeignAddress(foreign));
TNode<Object> call_data =
LoadObjectField<Object>(call_handler_info, CallHandlerInfo::kDataOffset);
TailCallStub(CodeFactory::CallApiCallback(isolate()), context, callback, argc,
......
......@@ -3510,8 +3510,9 @@ void Builtins::Generate_CallApiGetter(MacroAssembler* masm) {
DCHECK(api_function_address != name_arg);
__ LoadTaggedPointerField(
scratch, FieldOperand(callback, AccessorInfo::kJsGetterOffset));
__ movq(api_function_address,
FieldOperand(scratch, Foreign::kForeignAddressOffset));
__ LoadExternalPointerField(
api_function_address,
FieldOperand(scratch, Foreign::kForeignAddressOffset));
// +3 is to skip prolog, return address and name handle.
Operand return_value_operand(
......
......@@ -1294,7 +1294,7 @@ Handle<Foreign> Factory::NewForeign(Address addr) {
HeapObject result = AllocateRawWithImmortalMap(map.instance_size(),
AllocationType::kYoung, map);
Handle<Foreign> foreign(Foreign::cast(result), isolate());
foreign->set_foreign_address(addr);
foreign->set_foreign_address(isolate(), addr);
return foreign;
}
......
......@@ -208,7 +208,7 @@ void AccessorAssembler::HandleLoadAccessor(
TNode<Foreign> foreign = LoadObjectField<Foreign>(
call_handler_info, CallHandlerInfo::kJsCallbackOffset);
TNode<RawPtrT> callback =
LoadObjectField<RawPtrT>(foreign, Foreign::kForeignAddressOffset);
DecodeExternalPointer(LoadForeignForeignAddress(foreign));
TNode<Object> data =
LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
......@@ -1655,7 +1655,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
TNode<Foreign> foreign = LoadObjectField<Foreign>(
call_handler_info, CallHandlerInfo::kJsCallbackOffset);
TNode<RawPtrT> callback =
LoadObjectField<RawPtrT>(foreign, Foreign::kForeignAddressOffset);
DecodeExternalPointer(LoadForeignForeignAddress(foreign));
TNode<Object> data =
LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
......
......@@ -5,8 +5,10 @@
#ifndef V8_OBJECTS_FOREIGN_INL_H_
#define V8_OBJECTS_FOREIGN_INL_H_
#include "src/common/globals.h"
#include "src/objects/foreign.h"
#include "src/common/external-pointer-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/objects-inl.h"
......@@ -26,12 +28,16 @@ bool Foreign::IsNormalized(Object value) {
return Foreign::cast(value).foreign_address() != kNullAddress;
}
Address Foreign::foreign_address() {
return ReadField<Address>(kForeignAddressOffset);
DEF_GETTER(Foreign, foreign_address, Address) {
ExternalPointer_t encoded_value =
ReadField<ExternalPointer_t>(kForeignAddressOffset);
Address value = DecodeExternalPointer(isolate, encoded_value);
return value;
}
void Foreign::set_foreign_address(Address value) {
WriteField<Address>(kForeignAddressOffset, value);
void Foreign::set_foreign_address(Isolate* isolate, Address value) {
ExternalPointer_t encoded_value = EncodeExternalPointer(isolate, value);
WriteField<ExternalPointer_t>(kForeignAddressOffset, encoded_value);
}
} // namespace internal
......
......@@ -18,7 +18,7 @@ namespace internal {
class Foreign : public HeapObject {
public:
// [address]: field containing the address.
inline Address foreign_address();
DECL_GETTER(foreign_address, Address)
static inline bool IsNormalized(Object object);
......@@ -38,11 +38,9 @@ class Foreign : public HeapObject {
// compression is supported) allow unaligned access to full words.
STATIC_ASSERT(IsAligned(kForeignAddressOffset, kTaggedSize));
#else
STATIC_ASSERT(IsAligned(kForeignAddressOffset, kSystemPointerSize));
STATIC_ASSERT(IsAligned(kForeignAddressOffset, kExternalPointerSize));
#endif
STATIC_ASSERT(kForeignAddressOffset == Internals::kForeignAddressOffset);
class BodyDescriptor;
private:
......@@ -50,7 +48,7 @@ class Foreign : public HeapObject {
friend class SerializerDeserializer;
friend class StartupSerializer;
inline void set_foreign_address(Address value);
inline void set_foreign_address(Isolate* isolate, Address value);
OBJECT_CONSTRUCTORS(Foreign, HeapObject);
};
......
......@@ -4,5 +4,5 @@
@apiExposedInstanceTypeValue(0x46)
extern class Foreign extends HeapObject {
foreign_address: RawPtr;
foreign_address: ExternalPointer;
}
......@@ -4,7 +4,9 @@
#include "src/snapshot/deserializer.h"
#include "src/base/logging.h"
#include "src/codegen/assembler-inl.h"
#include "src/common/external-pointer.h"
#include "src/execution/isolate.h"
#include "src/heap/heap-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
......@@ -45,6 +47,15 @@ TSlot Deserializer::WriteAddress(TSlot dest, Address value) {
return dest + (kSystemPointerSize / TSlot::kSlotDataSize);
}
template <typename TSlot>
TSlot Deserializer::WriteExternalPointer(TSlot dest, Address value) {
value = EncodeExternalPointer(isolate(), value);
DCHECK(!allocator()->next_reference_is_weak());
memcpy(dest.ToVoidPtr(), &value, kExternalPointerSize);
STATIC_ASSERT(IsAligned(kExternalPointerSize, TSlot::kSlotDataSize));
return dest + (kExternalPointerSize / TSlot::kSlotDataSize);
}
void Deserializer::Initialize(Isolate* isolate) {
DCHECK_NULL(isolate_);
DCHECK_NOT_NULL(isolate);
......@@ -596,9 +607,15 @@ bool Deserializer::ReadData(TSlot current, TSlot limit,
// Find an external reference and write a pointer to it to the current
// object.
case kSandboxedExternalReference:
case kExternalReference: {
Address address = ReadExternalReferenceCase();
current = WriteAddress(current, address);
if (V8_HEAP_SANDBOX_BOOL && data == kSandboxedExternalReference) {
current = WriteExternalPointer(current, address);
} else {
DCHECK(!V8_HEAP_SANDBOX_BOOL);
current = WriteAddress(current, address);
}
break;
}
......@@ -679,6 +696,7 @@ bool Deserializer::ReadData(TSlot current, TSlot limit,
break;
}
case kSandboxedApiReference:
case kApiReference: {
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
Address address;
......@@ -691,7 +709,12 @@ bool Deserializer::ReadData(TSlot current, TSlot limit,
} else {
address = reinterpret_cast<Address>(NoExternalReferencesCallback);
}
current = WriteAddress(current, address);
if (V8_HEAP_SANDBOX_BOOL && data == kSandboxedApiReference) {
current = WriteExternalPointer(current, address);
} else {
DCHECK(!V8_HEAP_SANDBOX_BOOL);
current = WriteAddress(current, address);
}
break;
}
......
......@@ -132,6 +132,9 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
template <typename TSlot>
inline TSlot WriteAddress(TSlot dest, Address value);
template <typename TSlot>
inline TSlot WriteExternalPointer(TSlot dest, Address value);
// Fills in some heap data in an area from start to end (non-inclusive). The
// space id is used for the write barrier. The object_address is the address
// of the object we are writing into, or nullptr if we are not writing into an
......
......@@ -41,19 +41,19 @@ bool SerializerDeserializer::CanBeDeferred(HeapObject o) {
}
void SerializerDeserializer::RestoreExternalReferenceRedirectors(
const std::vector<AccessorInfo>& accessor_infos) {
Isolate* isolate, const std::vector<AccessorInfo>& accessor_infos) {
// Restore wiped accessor infos.
for (AccessorInfo info : accessor_infos) {
Foreign::cast(info.js_getter())
.set_foreign_address(info.redirected_getter());
.set_foreign_address(isolate, info.redirected_getter());
}
}
void SerializerDeserializer::RestoreExternalReferenceRedirectors(
const std::vector<CallHandlerInfo>& call_handler_infos) {
Isolate* isolate, const std::vector<CallHandlerInfo>& call_handler_infos) {
for (CallHandlerInfo info : call_handler_infos) {
Foreign::cast(info.js_callback())
.set_foreign_address(info.redirected_callback());
.set_foreign_address(isolate, info.redirected_callback());
}
}
......
......@@ -62,9 +62,9 @@ class SerializerDeserializer : public RootVisitor {
static bool CanBeDeferred(HeapObject o);
void RestoreExternalReferenceRedirectors(
const std::vector<AccessorInfo>& accessor_infos);
Isolate* isolate, const std::vector<AccessorInfo>& accessor_infos);
void RestoreExternalReferenceRedirectors(
const std::vector<CallHandlerInfo>& call_handler_infos);
Isolate* isolate, const std::vector<CallHandlerInfo>& call_handler_infos);
static const int kNumberOfPreallocatedSpaces =
static_cast<int>(SnapshotSpace::kNumberOfPreallocatedSpaces);
......@@ -75,8 +75,7 @@ class SerializerDeserializer : public RootVisitor {
// clang-format off
#define UNUSED_SERIALIZER_BYTE_CODES(V) \
V(0x06) V(0x07) V(0x0e) V(0x0f) \
/* Free range 0x26..0x2f */ \
V(0x26) V(0x27) \
/* Free range 0x28..0x2f */ \
V(0x28) V(0x29) V(0x2a) V(0x2b) V(0x2c) V(0x2d) V(0x2e) V(0x2f) \
/* Free range 0x30..0x3f */ \
V(0x30) V(0x31) V(0x32) V(0x33) V(0x34) V(0x35) V(0x36) V(0x37) \
......@@ -136,7 +135,7 @@ class SerializerDeserializer : public RootVisitor {
kBackref = 0x08,
//
// ---------- byte code range 0x10..0x25 ----------
// ---------- byte code range 0x10..0x27 ----------
//
// Object in the startup object cache.
......@@ -174,6 +173,12 @@ class SerializerDeserializer : public RootVisitor {
kApiReference,
// External reference referenced by id.
kExternalReference,
// Same as two bytecodes above but for serializing sandboxed external
// pointer values.
// TODO(v8:10391): Remove them once all ExternalPointer usages are
// sandbox-ready.
kSandboxedApiReference,
kSandboxedExternalReference,
// Internal reference of a code objects in code stream.
kInternalReference,
// In-place weak references.
......
......@@ -719,7 +719,8 @@ void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host,
}
void Serializer::ObjectSerializer::OutputExternalReference(Address target,
int target_size) {
int target_size,
bool sandboxify) {
DCHECK_LE(target_size, sizeof(target)); // Must fit in Address.
ExternalReferenceEncoder::Value encoded_reference;
bool encoded_successfully;
......@@ -744,10 +745,18 @@ void Serializer::ObjectSerializer::OutputExternalReference(Address target,
sink_->PutSection(kFixedRawDataStart + size_in_tagged, "FixedRawData");
sink_->PutRaw(reinterpret_cast<byte*>(&target), target_size, "Bytes");
} else if (encoded_reference.is_from_api()) {
sink_->Put(kApiReference, "ApiRef");
if (V8_HEAP_SANDBOX_BOOL && sandboxify) {
sink_->Put(kSandboxedApiReference, "SandboxedApiRef");
} else {
sink_->Put(kApiReference, "ApiRef");
}
sink_->PutInt(encoded_reference.index(), "reference index");
} else {
sink_->Put(kExternalReference, "ExternalRef");
if (V8_HEAP_SANDBOX_BOOL && sandboxify) {
sink_->Put(kSandboxedExternalReference, "SandboxedExternalRef");
} else {
sink_->Put(kExternalReference, "ExternalRef");
}
sink_->PutInt(encoded_reference.index(), "reference index");
}
bytes_processed_so_far_ += target_size;
......@@ -755,7 +764,8 @@ void Serializer::ObjectSerializer::OutputExternalReference(Address target,
void Serializer::ObjectSerializer::VisitExternalReference(Foreign host,
Address* p) {
OutputExternalReference(host.foreign_address(), kSystemPointerSize);
// "Sandboxify" external reference.
OutputExternalReference(host.foreign_address(), kExternalPointerSize, true);
}
void Serializer::ObjectSerializer::VisitExternalReference(Code host,
......@@ -764,7 +774,8 @@ void Serializer::ObjectSerializer::VisitExternalReference(Code host,
DCHECK_NE(target, kNullAddress); // Code does not reference null.
DCHECK_IMPLIES(serializer_->EncodeExternalReference(target).is_from_api(),
!rinfo->IsCodedSpecially());
OutputExternalReference(target, rinfo->target_address_size());
// Don't "sandboxify" external references embedded in the code.
OutputExternalReference(target, rinfo->target_address_size(), false);
}
void Serializer::ObjectSerializer::VisitInternalReference(Code host,
......
......@@ -343,7 +343,8 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
// This function outputs or skips the raw data between the last pointer and
// up to the current position.
void SerializeContent(Map map, int size);
void OutputExternalReference(Address target, int target_size);
void OutputExternalReference(Address target, int target_size,
bool sandboxify);
void OutputRawData(Address up_to);
void OutputCode(int size);
uint32_t SerializeBackingStore(void* backing_store, int32_t byte_length);
......
......@@ -37,8 +37,8 @@ void StartupDeserializer::DeserializeInto(Isolate* isolate) {
Iterate(isolate, this);
isolate->heap()->IterateWeakRoots(this, VISIT_FOR_SERIALIZATION);
DeserializeDeferredObjects();
RestoreExternalReferenceRedirectors(accessor_infos());
RestoreExternalReferenceRedirectors(call_handler_infos());
RestoreExternalReferenceRedirectors(isolate, accessor_infos());
RestoreExternalReferenceRedirectors(isolate, call_handler_infos());
// Flush the instruction cache for the entire code-space. Must happen after
// builtins deserialization.
......
......@@ -29,8 +29,8 @@ StartupSerializer::StartupSerializer(Isolate* isolate,
}
StartupSerializer::~StartupSerializer() {
RestoreExternalReferenceRedirectors(accessor_infos_);
RestoreExternalReferenceRedirectors(call_handler_infos_);
RestoreExternalReferenceRedirectors(isolate(), accessor_infos_);
RestoreExternalReferenceRedirectors(isolate(), call_handler_infos_);
OutputStatistics("StartupSerializer");
}
......@@ -97,13 +97,17 @@ void StartupSerializer::SerializeObject(HeapObject obj) {
if (use_simulator && obj.IsAccessorInfo()) {
// Wipe external reference redirects in the accessor info.
AccessorInfo info = AccessorInfo::cast(obj);
Address original_address = Foreign::cast(info.getter()).foreign_address();
Foreign::cast(info.js_getter()).set_foreign_address(original_address);
Address original_address =
Foreign::cast(info.getter()).foreign_address(isolate());
Foreign::cast(info.js_getter())
.set_foreign_address(isolate(), original_address);
accessor_infos_.push_back(info);
} else if (use_simulator && obj.IsCallHandlerInfo()) {
CallHandlerInfo info = CallHandlerInfo::cast(obj);
Address original_address = Foreign::cast(info.callback()).foreign_address();
Foreign::cast(info.js_callback()).set_foreign_address(original_address);
Address original_address =
Foreign::cast(info.callback()).foreign_address(isolate());
Foreign::cast(info.js_callback())
.set_foreign_address(isolate(), original_address);
call_handler_infos_.push_back(info);
} else if (obj.IsScript() && Script::cast(obj).IsUserJavaScript()) {
Script::cast(obj).set_context_data(
......
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