diff options
author | Michael BrĂ¼ning <michael.bruning@qt.io> | 2020-01-22 17:15:03 +0100 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2020-01-24 17:08:29 +0000 |
commit | f2ad81650e50bc554e57fd4efc05eeb9fc16a201 (patch) | |
tree | e5f7320998b1885ab4f3791559014039ad678041 | |
parent | b94dccc951a1068108ee1bf40076e57460f8e60f (diff) | |
download | qtwebengine-chromium-f2ad81650e50bc554e57fd4efc05eeb9fc16a201.tar.gz |
[Backport] CVE-2019-13735: Out of bounds write in V8
Manual backport of patch:
Merged: Squashed multiple commits.
Merged: Ensure root maps do not have slack in descriptor array
Revision: 31fab144f0652a6aa1f284b60655300ed746b2b6
Merged: Properly share descriptor arrays
Revision: f53c728f55f61deeeacbf669d6aff726244ea5fe
Merged: Fix too restrictive check in Map::MapVerify
Revision: e34e5271d954f7d7e4f87c4c7ab867b3c8e6d891
BUG=chromium:1025468,chromium:1027498,chromium:1028396
NOTRY=true
NOPRESUBMIT=true
NOTREECHECKS=true
R=verwaest@chromium.org
Cr-Branched-From: be181e241c6da9baa49a424b7d91613c8ebf76f8-refs/heads/7.9.317@{#1}
Cr-Branched-From: 0d7889d0b14939fa5c09c39a0a5eb155b74163e4-refs/heads/master@{#64307
Change-Id: I8b1cd3a94ab60fae3a1108726e780110fdc6bc3d
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
-rw-r--r-- | chromium/v8/BUILD.gn | 4 | ||||
-rw-r--r-- | chromium/v8/src/heap/factory.cc | 13 | ||||
-rw-r--r-- | chromium/v8/src/objects-debug.cc | 29 | ||||
-rw-r--r-- | chromium/v8/src/objects.cc | 28 |
4 files changed, 57 insertions, 17 deletions
diff --git a/chromium/v8/BUILD.gn b/chromium/v8/BUILD.gn index 41a50be9373..b4327bf93b8 100644 --- a/chromium/v8/BUILD.gn +++ b/chromium/v8/BUILD.gn @@ -1079,6 +1079,10 @@ template("run_mksnapshot") { args += [ "--no-enable-slow-asserts" ] } } + + if (v8_enable_verify_heap) { + args += [ "--verify-heap" ] + } } } diff --git a/chromium/v8/src/heap/factory.cc b/chromium/v8/src/heap/factory.cc index de29a67cc14..0003d37819d 100644 --- a/chromium/v8/src/heap/factory.cc +++ b/chromium/v8/src/heap/factory.cc @@ -3939,6 +3939,7 @@ Handle<Map> Factory::CreateSloppyFunctionMap( prototype_string(), function_prototype_accessor(), attribs); map->AppendDescriptor(&d); } + DCHECK_EQ(0, map->instance_descriptors()->NumberOfSlackDescriptors()); DCHECK_EQ(inobject_properties_count, field_index); return map; } @@ -3949,10 +3950,15 @@ Handle<Map> Factory::CreateStrictFunctionMap( int header_size = has_prototype ? JSFunction::kSizeWithPrototype : JSFunction::kSizeWithoutPrototype; int inobject_properties_count = 0; - if (IsFunctionModeWithName(function_mode)) ++inobject_properties_count; + // length and prototype accessors or just length accessor. + int descriptors_count = IsFunctionModeWithPrototype(function_mode) ? 2 : 1; + if (IsFunctionModeWithName(function_mode)) { + ++inobject_properties_count; // name property. + } else { + ++descriptors_count; // name accessor. + } if (IsFunctionModeWithHomeObject(function_mode)) ++inobject_properties_count; - int descriptors_count = (IsFunctionModeWithPrototype(function_mode) ? 3 : 2) + - inobject_properties_count; + descriptors_count += inobject_properties_count; Handle<Map> map = NewMap( JS_FUNCTION_TYPE, header_size + inobject_properties_count * kPointerSize, @@ -4016,6 +4022,7 @@ Handle<Map> Factory::CreateStrictFunctionMap( map->AppendDescriptor(&d); } DCHECK_EQ(inobject_properties_count, field_index); + DCHECK_EQ(0, map->instance_descriptors()->NumberOfSlackDescriptors()); return map; } diff --git a/chromium/v8/src/objects-debug.cc b/chromium/v8/src/objects-debug.cc index 8f149c8788c..ba4093ef65f 100644 --- a/chromium/v8/src/objects-debug.cc +++ b/chromium/v8/src/objects-debug.cc @@ -564,8 +564,33 @@ void Map::MapVerify(Isolate* isolate) { CHECK(instance_size() == kVariableSizeSentinel || (kPointerSize <= instance_size() && static_cast<size_t>(instance_size()) < heap->Capacity())); - CHECK(GetBackPointer()->IsUndefined(heap->isolate()) || - !Map::cast(GetBackPointer())->is_stable()); + if (GetBackPointer()->IsUndefined(heap->isolate())) { + // Root maps must not have descriptors in the descriptor array that do not + // belong to the map. + CHECK_EQ(NumberOfOwnDescriptors(), + instance_descriptors()->number_of_descriptors()); + } else { + // If there is a parent map it must be non-stable. + Map* parent = Map::cast(GetBackPointer()); + CHECK(!parent->is_stable()); + DescriptorArray* descriptors = instance_descriptors(); + if (descriptors == parent->instance_descriptors()) { + if (NumberOfOwnDescriptors() == parent->NumberOfOwnDescriptors() + 1) { + // Descriptors sharing through property transitions takes over + // ownership from the parent map. + CHECK(!parent->owns_descriptors()); + } else { + CHECK_EQ(NumberOfOwnDescriptors(), parent->NumberOfOwnDescriptors()); + // Descriptors sharing through special transitions properly takes over + // ownership from the parent map unless it uses the canonical empty + // descriptor array. + if (descriptors != ReadOnlyRoots(isolate).empty_descriptor_array()) { + CHECK_IMPLIES(owns_descriptors(), !parent->owns_descriptors()); + CHECK_IMPLIES(parent->owns_descriptors(), !owns_descriptors()); + } + } + } + } VerifyHeapPointer(isolate, prototype()); VerifyHeapPointer(isolate, instance_descriptors()); SLOW_DCHECK(instance_descriptors()->IsSortedNoDuplicates()); diff --git a/chromium/v8/src/objects.cc b/chromium/v8/src/objects.cc index 60cd27aa95e..9f1b204b4ab 100644 --- a/chromium/v8/src/objects.cc +++ b/chromium/v8/src/objects.cc @@ -4607,9 +4607,8 @@ Map* Map::FindRootMap(Isolate* isolate) const { while (true) { Object* back = result->GetBackPointer(); if (back->IsUndefined(isolate)) { - // Initial map always owns descriptors and doesn't have unused entries - // in the descriptor array. - DCHECK(result->owns_descriptors()); + // Initial map must not contain descriptors in the descriptors array + // that do not belong to the map. DCHECK_EQ(result->NumberOfOwnDescriptors(), result->instance_descriptors()->number_of_descriptors()); return const_cast<Map*>(result); @@ -9389,9 +9388,8 @@ void EnsureInitialMap(Isolate* isolate, Handle<Map> map) { *map == *isolate->async_function_with_home_object_map() || *map == *isolate->async_function_with_name_and_home_object_map()); #endif - // Initial maps must always own their descriptors and it's descriptor array - // does not contain descriptors that do not belong to the map. - DCHECK(map->owns_descriptors()); + // Initial maps must not contain descriptors and in the descriptors array + // that do not belong to the map. DCHECK_EQ(map->NumberOfOwnDescriptors(), map->instance_descriptors()->number_of_descriptors()); } @@ -9409,6 +9407,11 @@ Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map, int instance_size, int inobject_properties, int unused_property_fields) { EnsureInitialMap(isolate, map); + // Initial map must not contain descriptors in the descriptors array + // that do not belong to the map. + DCHECK_EQ(map->NumberOfOwnDescriptors(), + map->instance_descriptors()->number_of_descriptors()); + Handle<Map> result = RawCopy(isolate, map, instance_size, inobject_properties); @@ -9417,9 +9420,10 @@ Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map, int number_of_own_descriptors = map->NumberOfOwnDescriptors(); if (number_of_own_descriptors > 0) { - // The copy will use the same descriptors array. - result->UpdateDescriptors(map->instance_descriptors(), - map->GetLayoutDescriptor()); + // The copy will use the same descriptors array without ownership. + DescriptorArray *descriptors = map->instance_descriptors(); + result->set_owns_descriptors(false); + result->UpdateDescriptors(descriptors, map->GetLayoutDescriptor()); result->SetNumberOfOwnDescriptors(number_of_own_descriptors); DCHECK_EQ(result->NumberOfFields(), @@ -9509,9 +9513,8 @@ void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent, if (!parent->GetBackPointer()->IsUndefined(isolate)) { parent->set_owns_descriptors(false); } else { - // |parent| is initial map and it must keep the ownership, there must be no - // descriptors in the descriptors array that do not belong to the map. - DCHECK(parent->owns_descriptors()); + // |parent| is initial map and it must not contain descriptors in the + // descriptors array that do not belong to the map. DCHECK_EQ(parent->NumberOfOwnDescriptors(), parent->instance_descriptors()->number_of_descriptors()); } @@ -9750,6 +9753,7 @@ Handle<Map> Map::CopyForTransition(Isolate* isolate, Handle<Map> map, // In case the map owned its own descriptors, share the descriptors and // transfer ownership to the new map. // The properties did not change, so reuse descriptors. + map->set_owns_descriptors(false); new_map->InitializeDescriptors(map->instance_descriptors(), map->GetLayoutDescriptor()); } else { |