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

[sandbox] Fix serialization of NativeContext

When a NativeContext is being serialized, the NativeContext's
microtask_queue is set to nullptr as it is not included in the snapshot.
However, when the sandbox is enabled, this will only set the pointer in
the external pointer table to nullptr, but not the handle stored in the
object. This then causes the deserialized object to briefly be invalid,
before it's microtask queue handle is (re-)initialized. If a GC runs
during that timeframe, it will see an invalid external pointer handle,
which may cause DCHECK failures.
To fix this, this CL now introduces a generic mechanism for clearing and
restoring external pointer slots for serialization.

Bug: v8:13218
Change-Id: I03c8779bbec0a42a0b66687e76c951b1887e6122
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/+/3850294Reviewed-by: 's avatarJakob Linke <jgruber@chromium.org>
Commit-Queue: Samuel Groß <saelo@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82677}
parent 074e015a
......@@ -217,6 +217,29 @@ void ExternalPointerSlot::store(Isolate* isolate, Address value,
WriteMaybeUnalignedValue<Address>(address(), value);
}
ExternalPointerSlot::RawContent
ExternalPointerSlot::GetAndClearContentForSerialization(
const DisallowGarbageCollection& no_gc) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
ExternalPointerHandle content = Relaxed_LoadHandle();
Relaxed_StoreHandle(kNullExternalPointerHandle);
#else
Address content = ReadMaybeUnalignedValue<Address>(address());
WriteMaybeUnalignedValue<Address>(address(), kNullAddress);
#endif
return content;
}
void ExternalPointerSlot::RestoreContentAfterSerialization(
ExternalPointerSlot::RawContent content,
const DisallowGarbageCollection& no_gc) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
return Relaxed_StoreHandle(content);
#else
return WriteMaybeUnalignedValue<Address>(address(), content);
#endif
}
#ifdef V8_ENABLE_SANDBOX
const ExternalPointerTable& ExternalPointerSlot::GetExternalPointerTableForTag(
const Isolate* isolate, ExternalPointerTag tag) {
......
......@@ -6,6 +6,7 @@
#define V8_OBJECTS_SLOTS_H_
#include "src/base/memory.h"
#include "src/common/assert-scope.h"
#include "src/common/globals.h"
#include "src/sandbox/external-pointer-table.h"
......@@ -309,6 +310,20 @@ class ExternalPointerSlot
inline Address load(const Isolate* isolate, ExternalPointerTag tag);
inline void store(Isolate* isolate, Address value, ExternalPointerTag tag);
// ExternalPointerSlot serialization support.
// These methods can be used to clear an external pointer slot prior to
// serialization and restore it afterwards. This is useful in cases where the
// external pointer is not contained in the snapshot but will instead be
// reconstructed during deserialization.
// Note that GC must be disallowed while an object's external slot is cleared
// as otherwise the corresponding entry in the external pointer table may not
// be marked as alive.
using RawContent = ExternalPointer_t;
inline RawContent GetAndClearContentForSerialization(
const DisallowGarbageCollection& no_gc);
inline void RestoreContentAfterSerialization(
RawContent content, const DisallowGarbageCollection& no_gc);
private:
#ifdef V8_ENABLE_SANDBOX
inline const ExternalPointerTable& GetExternalPointerTableForTag(
......
......@@ -25,42 +25,48 @@ class V8_NODISCARD SanitizeNativeContextScope final {
SanitizeNativeContextScope(Isolate* isolate, NativeContext native_context,
bool allow_active_isolate_for_testing,
const DisallowGarbageCollection& no_gc)
: isolate_(isolate),
native_context_(native_context),
microtask_queue_(native_context.microtask_queue()),
: native_context_(native_context),
optimized_code_list_(native_context.OptimizedCodeListHead()),
deoptimized_code_list_(native_context.DeoptimizedCodeListHead()) {
deoptimized_code_list_(native_context.DeoptimizedCodeListHead()),
no_gc_(no_gc) {
#ifdef DEBUG
if (!allow_active_isolate_for_testing) {
// Microtasks.
DCHECK_EQ(0, microtask_queue_->size());
DCHECK(!microtask_queue_->HasMicrotasksSuppressions());
DCHECK_EQ(0, microtask_queue_->GetMicrotasksScopeDepth());
DCHECK(microtask_queue_->DebugMicrotasksScopeDepthIsZero());
MicrotaskQueue* microtask_queue = native_context_.microtask_queue();
DCHECK_EQ(0, microtask_queue->size());
DCHECK(!microtask_queue->HasMicrotasksSuppressions());
DCHECK_EQ(0, microtask_queue->GetMicrotasksScopeDepth());
DCHECK(microtask_queue->DebugMicrotasksScopeDepthIsZero());
// Code lists.
DCHECK(optimized_code_list_.IsUndefined(isolate));
DCHECK(deoptimized_code_list_.IsUndefined(isolate));
}
#endif
microtask_queue_external_pointer_ =
native_context
.RawExternalPointerField(NativeContext::kMicrotaskQueueOffset)
.GetAndClearContentForSerialization(no_gc);
Object undefined = ReadOnlyRoots(isolate).undefined_value();
native_context.set_microtask_queue(isolate, nullptr);
native_context.SetOptimizedCodeListHead(undefined);
native_context.SetDeoptimizedCodeListHead(undefined);
}
~SanitizeNativeContextScope() {
// Restore saved fields.
native_context_.SetDeoptimizedCodeListHead(optimized_code_list_);
native_context_.SetOptimizedCodeListHead(deoptimized_code_list_);
native_context_.set_microtask_queue(isolate_, microtask_queue_);
native_context_.SetOptimizedCodeListHead(optimized_code_list_);
native_context_.SetDeoptimizedCodeListHead(deoptimized_code_list_);
native_context_
.RawExternalPointerField(NativeContext::kMicrotaskQueueOffset)
.RestoreContentAfterSerialization(microtask_queue_external_pointer_,
no_gc_);
}
private:
Isolate* isolate_;
NativeContext native_context_;
MicrotaskQueue* const microtask_queue_;
ExternalPointerSlot::RawContent microtask_queue_external_pointer_;
const Object optimized_code_list_;
const Object deoptimized_code_list_;
const DisallowGarbageCollection& no_gc_;
};
} // namespace
......
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