diff options
author | Michael BrĂ¼ning <michael.bruning@qt.io> | 2020-01-14 12:58:22 +0100 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2020-01-16 13:08:43 +0000 |
commit | c68e3faa08f985b6c212eac65b9f4de8ed24ca98 (patch) | |
tree | 8050eb6bee799ad87a80ed0f48be206620431a6c | |
parent | 5e753a5b1d72fb30f955ab482196b0f1a533769f (diff) | |
download | qtwebengine-chromium-c68e3faa08f985b6c212eac65b9f4de8ed24ca98.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/diagnostics/objects-debug.cc | 29 | ||||
-rw-r--r-- | chromium/v8/src/heap/factory.cc | 13 | ||||
-rw-r--r-- | chromium/v8/src/objects/map.cc | 28 |
4 files changed, 57 insertions, 17 deletions
diff --git a/chromium/v8/BUILD.gn b/chromium/v8/BUILD.gn index e21400265dd..e8b042d58cb 100644 --- a/chromium/v8/BUILD.gn +++ b/chromium/v8/BUILD.gn @@ -1248,6 +1248,10 @@ template("run_mksnapshot") { args += [ "--no-enable-slow-asserts" ] } } + + if (v8_enable_verify_heap) { + args += [ "--verify-heap" ] + } } } diff --git a/chromium/v8/src/diagnostics/objects-debug.cc b/chromium/v8/src/diagnostics/objects-debug.cc index dc3b3b8091c..07634f3ca79 100644 --- a/chromium/v8/src/diagnostics/objects-debug.cc +++ b/chromium/v8/src/diagnostics/objects-debug.cc @@ -656,8 +656,33 @@ void Map::MapVerify(Isolate* isolate) { CHECK(instance_size() == kVariableSizeSentinel || (kTaggedSize <= instance_size() && static_cast<size_t>(instance_size()) < heap->Capacity())); - CHECK(GetBackPointer().IsUndefined(isolate) || - !Map::cast(GetBackPointer()).is_stable()); + if (GetBackPointer().IsUndefined(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()); + } + } + } + } SLOW_DCHECK(instance_descriptors().IsSortedNoDuplicates()); DisallowHeapAllocation no_gc; SLOW_DCHECK( diff --git a/chromium/v8/src/heap/factory.cc b/chromium/v8/src/heap/factory.cc index 19c36656225..679dc555870 100644 --- a/chromium/v8/src/heap/factory.cc +++ b/chromium/v8/src/heap/factory.cc @@ -4027,6 +4027,7 @@ Handle<Map> Factory::CreateSloppyFunctionMap( map->AppendDescriptor(isolate(), &d); } DCHECK_EQ(inobject_properties_count, field_index); + DCHECK_EQ(0, map->instance_descriptors().number_of_slack_descriptors()); LOG(isolate(), MapDetails(*map)); return map; } @@ -4037,10 +4038,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 * kTaggedSize, @@ -4104,6 +4110,7 @@ Handle<Map> Factory::CreateStrictFunctionMap( map->AppendDescriptor(isolate(), &d); } DCHECK_EQ(inobject_properties_count, field_index); + DCHECK_EQ(0, map->instance_descriptors().number_of_slack_descriptors()); LOG(isolate(), MapDetails(*map)); return map; } diff --git a/chromium/v8/src/objects/map.cc b/chromium/v8/src/objects/map.cc index 7b4f1abd05f..632fbd8a25a 100644 --- a/chromium/v8/src/objects/map.cc +++ b/chromium/v8/src/objects/map.cc @@ -644,9 +644,8 @@ Map Map::FindRootMap(Isolate* isolate) const { while (true) { Object back = result.GetBackPointer(isolate); 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 result; @@ -1575,9 +1574,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 in the descriptors array + // that do not belong to the map. DCHECK_EQ(map->NumberOfOwnDescriptors(), map->instance_descriptors().number_of_descriptors()); } @@ -1595,6 +1593,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); @@ -1603,9 +1606,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(isolate, 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(isolate, descriptors, map->GetLayoutDescriptor(), number_of_own_descriptors); DCHECK_EQ(result->NumberOfFields(), @@ -1685,9 +1689,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()); } @@ -1924,6 +1927,7 @@ Handle<Map> Map::CopyForElementsTransition(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(isolate, map->instance_descriptors(), map->GetLayoutDescriptor()); } else { |