v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
trusted-object.h
Go to the documentation of this file.
1// Copyright 2023 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_OBJECTS_TRUSTED_OBJECT_H_
6#define V8_OBJECTS_TRUSTED_OBJECT_H_
7
9
10// Has to be the last include (doesn't have include guards):
12
13namespace v8 {
14namespace internal {
15
16#include "torque-generated/src/objects/trusted-object-tq.inc"
17
18// An object that is trusted to not have been modified in a malicious way.
19//
20// Typical examples of trusted objects are containers for bytecode or code
21// metadata, which often allow an attacker to corrupt (for example) stack
22// memory when manipulated. When the sandbox is enabled, trusted objects are
23// located outside of the sandbox (in one of the trusted heap spaces) so that
24// attackers cannot corrupt these objects and use them to escape from the
25// sandbox. When the sandbox is disabled, trusted objects are treated like any
26// other objects since in that case, many other types of objects (for example
27// ArrayBuffers) can be used to corrupt memory outside of V8's heaps as well.
28//
29// Trusted objects cannot directly be referenced from untrusted objects as this
30// would be unsafe: an attacker could corrupt any (direct) pointer to these
31// objects stored inside the sandbox. However, ExposedTrustedObject can be
32// referenced via indirect pointers, which guarantee memory-safe access.
33class TrustedObject : public HeapObject {
34 public:
36
37 // Protected pointers.
38 //
39 // These are pointers for which it is guaranteed that neither the pointer-to
40 // object nor the pointer itself can be modified by an attacker. In practice,
41 // this means that they must be pointers between objects in trusted space,
42 // outside of the sandbox, where they are protected from an attacker. As
43 // such, the slot accessors for these slots only exist on TrustedObjects but
44 // not on other HeapObjects.
47 AcquireLoadTag) const;
48 inline void WriteProtectedPointerField(int offset,
50 inline void WriteProtectedPointerField(int offset,
53 inline bool IsProtectedPointerFieldEmpty(int offset) const;
55 inline void ClearProtectedPointerField(int offset);
57
58 inline ProtectedPointerSlot RawProtectedPointerField(int byte_offset) const;
60 int byte_offset) const;
61
62#ifdef VERIFY_HEAP
63 inline void VerifyProtectedPointerField(Isolate* isolate, int offset);
64#endif
65
66 static constexpr int kHeaderSize = HeapObject::kHeaderSize;
67
69};
70
75
76// A trusted object that can safely be referenced from untrusted objects.
77//
78// These objects live in trusted space but are "exposed" to untrusted objects
79// living inside the sandbox. They still cannot be referenced through "direct"
80// pointers (these can be corrupted by an attacker), but instead they must be
81// referenced through "indirect pointers": an index into a pointer table that
82// contains the actual pointer as well as a type tag. This mechanism then
83// guarantees memory-safe access.
84//
85// We want to have one pointer table entry per referenced object, *not* per
86// reference. As such, there must be a way to obtain an existing table entry
87// for a given (exposed) object. This base class provides that table entry in
88// the form of the 'self' indirect pointer.
89//
90// The need to inherit from this base class to make a trusted object accessible
91// means that it is not possible to expose existing utility objects such as
92// hash tables or fixed arrays. Instead, those would need to be "wrapped" by
93// another ExposedTrustedObject. This limitation is by design: if we were to
94// create such an exposed utility object, it would likely weaken the
95// type-safety mechanism of indirect pointers because indirect pointers are
96// (effectively) tagged with the target's instance type. As such, if the same
97// object type is used in different contexts, they would both use the same type
98// tag, allowing an attacker to perform a "substitution attack". As a concrete
99// example, consider the case of a trusted, exposed byte array. If such a byte
100// array is used (a) to hold some sort of bytecode for an interpreter and (b)
101// some sort of trusted metadata, then an attacker can take a trusted byte
102// array from context (a) and use it in context (b) or vice versa. This would
103// effectively result in a type confusion and likely lead to an escape from the
104// sandbox. This problem goes away if (a) and (b) each use a dedicated object
105// with a unique instance type. It is of course still possible to build new
106// utility objects on top of this class, but hopefully this comment serves to
107// document the potential pitfalls when doing so.
109 public:
110 // Initializes this object by creating its pointer table entry.
111 inline void init_self_indirect_pointer(Isolate* isolate);
112 inline void init_self_indirect_pointer(LocalIsolate* isolate);
113
114 // Returns the 'self' indirect pointer of this object.
115 // This indirect pointer references a pointer table entry (either in the
116 // trusted pointer table or the code pointer table for Code objects) through
117 // which this object can be referenced from inside the sandbox.
119
121
122#ifdef V8_ENABLE_SANDBOX
123 // The 'self' indirect pointer is only available when the sandbox is enabled.
124 // Otherwise, these objects are referenced through direct pointers.
125#define FIELD_LIST(V) \
126 V(kSelfIndirectPointerOffset, kIndirectPointerSize) \
127 V(kUnalignedHeaderSize, OBJECT_POINTER_PADDING(kUnalignedHeaderSize)) \
128 V(kHeaderSize, 0) \
129 V(kSize, 0)
130
132#undef FIELD_LIST
133#else // V8_ENABLE_SANDBOX
135#endif // V8_ENABLE_SANDBOX
136
138};
139
140} // namespace internal
141} // namespace v8
142
144
145#endif // V8_OBJECTS_TRUSTED_OBJECT_H_
IndirectPointerHandle self_indirect_pointer_handle() const
OBJECT_CONSTRUCTORS(ExposedTrustedObject, TrustedObject)
void init_self_indirect_pointer(Isolate *isolate)
static constexpr int kHeaderSize
OBJECT_CONSTRUCTORS(TrustedObject, HeapObject)
void ClearProtectedPointerField(int offset)
ProtectedPointerSlot RawProtectedPointerField(int byte_offset) const
void WriteProtectedPointerField(int offset, Tagged< TrustedObject > value)
bool IsProtectedPointerFieldEmpty(int offset) const
Tagged< TrustedObject > ReadProtectedPointerField(int offset) const
ProtectedMaybeObjectSlot RawProtectedMaybeObjectField(int byte_offset) const
static constexpr int kHeaderSize
int32_t offset
#define FIELD_LIST(V)
v8::internal::LoadHandler V8_OBJECT_END
uint32_t IndirectPointerHandle
#define DECL_VERIFIER(Name)
#define V8_OBJECT
#define DEFINE_FIELD_OFFSET_CONSTANTS(StartOffset, LIST_MACRO)
Definition utils.h:242