blob: 4460db0dc0027c7df0211bdc81a15652a8c1b04f [file] [log] [blame]
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_SANDBOX_INDIRECT_POINTER_INL_H_
#define V8_SANDBOX_INDIRECT_POINTER_INL_H_
#include "include/v8-internal.h"
#include "src/base/atomic-utils.h"
#include "src/sandbox/code-pointer-table-inl.h"
#include "src/sandbox/indirect-pointer.h"
#include "src/sandbox/isolate-inl.h"
#include "src/sandbox/trusted-pointer-table-inl.h"
namespace v8 {
namespace internal {
V8_INLINE void InitSelfIndirectPointerField(Address field_address,
IsolateForSandbox isolate,
Tagged<HeapObject> host,
IndirectPointerTag tag) {
#ifdef V8_ENABLE_SANDBOX
DCHECK_NE(tag, kUnknownIndirectPointerTag);
// TODO(saelo): in the future, we might want to CHECK here or in
// AllocateAndInitializeEntry that the host lives in trusted space.
IndirectPointerHandle handle;
if (tag == kCodeIndirectPointerTag) {
CodePointerTable::Space* space =
isolate.GetCodePointerTableSpaceFor(field_address);
handle = GetProcessWideCodePointerTable()->AllocateAndInitializeEntry(
space, host.address(), kNullAddress, kDefaultCodeEntrypointTag);
} else {
TrustedPointerTable::Space* space = isolate.GetTrustedPointerTableSpace();
handle = isolate.GetTrustedPointerTable().AllocateAndInitializeEntry(
space, host.ptr(), tag);
}
// Use a Release_Store to ensure that the store of the pointer into the table
// is not reordered after the store of the handle. Otherwise, other threads
// may access an uninitialized table entry and crash.
auto location = reinterpret_cast<IndirectPointerHandle*>(field_address);
base::AsAtomic32::Release_Store(location, handle);
#else
UNREACHABLE();
#endif
}
namespace {
#ifdef V8_ENABLE_SANDBOX
template <IndirectPointerTag tag>
V8_INLINE Tagged<Object> ResolveTrustedPointerHandle(
IndirectPointerHandle handle, IsolateForSandbox isolate) {
const TrustedPointerTable& table = isolate.GetTrustedPointerTable();
return Tagged<Object>(table.Get(handle, tag));
}
V8_INLINE Tagged<Object> ResolveCodePointerHandle(
IndirectPointerHandle handle) {
CodePointerTable* table = GetProcessWideCodePointerTable();
return Tagged<Object>(table->GetCodeObject(handle));
}
#endif // V8_ENABLE_SANDBOX
} // namespace
template <IndirectPointerTag tag>
V8_INLINE Tagged<Object> ReadIndirectPointerField(Address field_address,
IsolateForSandbox isolate) {
#ifdef V8_ENABLE_SANDBOX
// Load the indirect pointer handle from the object.
auto location = reinterpret_cast<IndirectPointerHandle*>(field_address);
IndirectPointerHandle handle = base::AsAtomic32::Relaxed_Load(location);
DCHECK_NE(handle, kNullIndirectPointerHandle);
// Resolve the handle. The tag implies the pointer table to use.
// Here we generally assume that the load from the table cannot be reordered
// before the load of the code object pointer due to the data dependency
// between the two loads and therefore use relaxed memory ordering, but
// technically we should use memory_order_consume here.
if constexpr (tag == kUnknownIndirectPointerTag) {
// In this case we need to check if the handle is a code pointer handle and
// select the appropriate table based on that.
if (handle & kCodePointerHandleMarker) {
return ResolveCodePointerHandle(handle);
} else {
// TODO(saelo): once we have type tagging for entries in the trusted
// pointer table, we could ASSUME that the top bits of the tag match the
// instance type, which might allow the compiler to optimize subsequent
// instance type checks.
return ResolveTrustedPointerHandle<tag>(handle, isolate);
}
} else if constexpr (tag == kCodeIndirectPointerTag) {
return ResolveCodePointerHandle(handle);
} else {
return ResolveTrustedPointerHandle<tag>(handle, isolate);
}
#else
UNREACHABLE();
#endif
}
template <IndirectPointerTag tag>
V8_INLINE void WriteIndirectPointerField(Address field_address,
Tagged<ExposedTrustedObject> value) {
#ifdef V8_ENABLE_SANDBOX
static_assert(tag != kIndirectPointerNullTag);
IndirectPointerHandle handle = value->self_indirect_pointer_handle();
DCHECK_NE(handle, kNullIndirectPointerHandle);
auto location = reinterpret_cast<IndirectPointerHandle*>(field_address);
base::AsAtomic32::Release_Store(location, handle);
#else
UNREACHABLE();
#endif
}
} // namespace internal
} // namespace v8
#endif // V8_SANDBOX_INDIRECT_POINTER_INL_H_