Skip to content

Commit 6fb8d85

Browse files
verwaestmibrunin
authored andcommitted
[Backport] CVE-2024-0519: Out of bounds memory access in V8
Manual cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/v8/v8/+/5192447: Merged: [runtime] Drop fast last-property deletion This interacts badly with other optimizations and isn't particularly common. Bug: chromium:1517354 (cherry picked from commit 389ea9be7d68bb189e16da79f6414edbd4f7594f) Change-Id: Ie16aa38e8984c4879491c0d9a0ca9df0e041fd1d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5192447 Auto-Submit: Toon Verwaest <[email protected]> Reviewed-by: Leszek Swirski <[email protected]> Cr-Commit-Position: refs/branch-heads/12.0@{#32} Cr-Branched-From: ed7b4caf1fb8184ad9e24346c84424055d4d430a-refs/heads/12.0.267@{#1} Cr-Branched-From: 210e75b19db4352c9b78dce0bae11c2dc3077df4-refs/heads/main@{#90651} Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/532072 Reviewed-by: Allan Sandfeld Jensen <[email protected]>
1 parent 520c290 commit 6fb8d85

File tree

1 file changed

+0
-160
lines changed

1 file changed

+0
-160
lines changed

chromium/v8/src/runtime/runtime-object.cc

Lines changed: 0 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -92,170 +92,10 @@ MaybeHandle<Object> Runtime::HasProperty(Isolate* isolate,
9292
: ReadOnlyRoots(isolate).false_value_handle();
9393
}
9494

95-
namespace {
96-
97-
void GeneralizeAllTransitionsToFieldAsMutable(Isolate* isolate, Handle<Map> map,
98-
Handle<Name> name) {
99-
InternalIndex descriptor(map->NumberOfOwnDescriptors());
100-
101-
Handle<Map> target_maps[kPropertyAttributesCombinationsCount];
102-
int target_maps_count = 0;
103-
104-
// Collect all outgoing field transitions.
105-
{
106-
DisallowHeapAllocation no_gc;
107-
TransitionsAccessor transitions(isolate, *map, &no_gc);
108-
transitions.ForEachTransitionTo(
109-
*name,
110-
[&](Map target) {
111-
DCHECK_EQ(descriptor, target.LastAdded());
112-
DCHECK_EQ(*name, target.GetLastDescriptorName(isolate));
113-
PropertyDetails details = target.GetLastDescriptorDetails(isolate);
114-
// Currently, we track constness only for fields.
115-
if (details.kind() == kData &&
116-
details.constness() == PropertyConstness::kConst) {
117-
target_maps[target_maps_count++] = handle(target, isolate);
118-
}
119-
DCHECK_IMPLIES(details.kind() == kAccessor,
120-
details.constness() == PropertyConstness::kConst);
121-
},
122-
&no_gc);
123-
CHECK_LE(target_maps_count, kPropertyAttributesCombinationsCount);
124-
}
125-
126-
for (int i = 0; i < target_maps_count; i++) {
127-
Handle<Map> target = target_maps[i];
128-
PropertyDetails details =
129-
target->instance_descriptors(isolate)
130-
.GetDetails(descriptor);
131-
Handle<FieldType> field_type(
132-
target->instance_descriptors(isolate)
133-
.GetFieldType(descriptor),
134-
isolate);
135-
Map::GeneralizeField(isolate, target, descriptor,
136-
PropertyConstness::kMutable, details.representation(),
137-
field_type);
138-
DCHECK_EQ(PropertyConstness::kMutable,
139-
target->instance_descriptors(isolate)
140-
.GetDetails(descriptor)
141-
.constness());
142-
}
143-
}
144-
145-
bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
146-
Handle<Object> raw_key) {
147-
// This implements a special case for fast property deletion: when the
148-
// last property in an object is deleted, then instead of normalizing
149-
// the properties, we can undo the last map transition, with a few
150-
// prerequisites:
151-
// (1) The receiver must be a regular object and the key a unique name.
152-
Handle<Map> receiver_map(receiver->map(), isolate);
153-
if (receiver_map->IsSpecialReceiverMap()) return false;
154-
DCHECK(receiver_map->IsJSObjectMap());
155-
156-
if (!raw_key->IsUniqueName()) return false;
157-
Handle<Name> key = Handle<Name>::cast(raw_key);
158-
// (2) The property to be deleted must be the last property.
159-
int nof = receiver_map->NumberOfOwnDescriptors();
160-
if (nof == 0) return false;
161-
InternalIndex descriptor(nof - 1);
162-
Handle<DescriptorArray> descriptors(receiver_map->instance_descriptors(),
163-
isolate);
164-
if (descriptors->GetKey(descriptor) != *key) return false;
165-
// (3) The property to be deleted must be deletable.
166-
PropertyDetails details = descriptors->GetDetails(descriptor);
167-
if (!details.IsConfigurable()) return false;
168-
// (4) The map must have a back pointer.
169-
Handle<Object> backpointer(receiver_map->GetBackPointer(), isolate);
170-
if (!backpointer->IsMap()) return false;
171-
Handle<Map> parent_map = Handle<Map>::cast(backpointer);
172-
// (5) The last transition must have been caused by adding a property
173-
// (and not any kind of special transition).
174-
if (parent_map->NumberOfOwnDescriptors() != nof - 1) return false;
175-
176-
// Preconditions successful. No more bailouts after this point.
177-
178-
// Zap the property to avoid keeping objects alive. Zapping is not necessary
179-
// for properties stored in the descriptor array.
180-
if (details.location() == kField) {
181-
DisallowHeapAllocation no_allocation;
182-
183-
// Invalidate slots manually later in case we delete an in-object tagged
184-
// property. In this case we might later store an untagged value in the
185-
// recorded slot.
186-
isolate->heap()->NotifyObjectLayoutChange(*receiver, no_allocation,
187-
InvalidateRecordedSlots::kNo);
188-
FieldIndex index =
189-
FieldIndex::ForPropertyIndex(*receiver_map, details.field_index());
190-
// Special case deleting the last out-of object property.
191-
if (!index.is_inobject() && index.outobject_array_index() == 0) {
192-
DCHECK(!parent_map->HasOutOfObjectProperties());
193-
// Clear out the properties backing store.
194-
receiver->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array());
195-
} else {
196-
Object filler = ReadOnlyRoots(isolate).one_pointer_filler_map();
197-
JSObject::cast(*receiver).RawFastPropertyAtPut(index, filler);
198-
// We must clear any recorded slot for the deleted property, because
199-
// subsequent object modifications might put a raw double there.
200-
// Slot clearing is the reason why this entire function cannot currently
201-
// be implemented in the DeleteProperty stub.
202-
if (index.is_inobject() && !receiver_map->IsUnboxedDoubleField(index)) {
203-
// We need to clear the recorded slot in this case because in-object
204-
// slack tracking might not be finished. This ensures that we don't
205-
// have recorded slots in free space.
206-
isolate->heap()->ClearRecordedSlot(*receiver,
207-
receiver->RawField(index.offset()));
208-
MemoryChunk* chunk = MemoryChunk::FromHeapObject(*receiver);
209-
chunk->InvalidateRecordedSlots(*receiver);
210-
}
211-
}
212-
}
213-
// If the {receiver_map} was marked stable before, then there could be
214-
// optimized code that depends on the assumption that no object that
215-
// reached this {receiver_map} transitions away from it without triggering
216-
// the "deoptimize dependent code" mechanism.
217-
receiver_map->NotifyLeafMapLayoutChange(isolate);
218-
// Finally, perform the map rollback.
219-
receiver->synchronized_set_map(*parent_map);
220-
#if VERIFY_HEAP
221-
receiver->HeapObjectVerify(isolate);
222-
receiver->property_array().PropertyArrayVerify(isolate);
223-
#endif
224-
225-
// If the {descriptor} was "const" so far, we need to update the
226-
// {receiver_map} here, otherwise we could get the constants wrong, i.e.
227-
//
228-
// o.x = 1;
229-
// [change o.x's attributes or reconfigure property kind]
230-
// delete o.x;
231-
// o.x = 2;
232-
//
233-
// could trick V8 into thinking that `o.x` is still 1 even after the second
234-
// assignment.
235-
236-
// Step 1: Migrate object to an up-to-date shape.
237-
if (parent_map->is_deprecated()) {
238-
JSObject::MigrateInstance(isolate, Handle<JSObject>::cast(receiver));
239-
parent_map = handle(receiver->map(), isolate);
240-
}
241-
242-
// Step 2: Mark outgoing transitions from the up-to-date version of the
243-
// parent_map to same property name of any kind or attributes as mutable.
244-
// Also migrate object to the up-to-date map to make the object shapes
245-
// converge sooner.
246-
GeneralizeAllTransitionsToFieldAsMutable(isolate, parent_map, key);
247-
248-
return true;
249-
}
250-
251-
} // namespace
252-
25395
Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
25496
Handle<JSReceiver> receiver,
25597
Handle<Object> key,
25698
LanguageMode language_mode) {
257-
if (DeleteObjectPropertyFast(isolate, receiver, key)) return Just(true);
258-
25999
bool success = false;
260100
LookupIterator::Key lookup_key(isolate, key, &success);
261101
if (!success) return Nothing<bool>();

0 commit comments

Comments
 (0)