summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael BrĂ¼ning <michael.bruning@qt.io>2020-01-22 17:15:03 +0100
committerMichael BrĂ¼ning <michael.bruning@qt.io>2020-01-24 17:08:29 +0000
commitf2ad81650e50bc554e57fd4efc05eeb9fc16a201 (patch)
treee5f7320998b1885ab4f3791559014039ad678041
parentb94dccc951a1068108ee1bf40076e57460f8e60f (diff)
downloadqtwebengine-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.gn4
-rw-r--r--chromium/v8/src/heap/factory.cc13
-rw-r--r--chromium/v8/src/objects-debug.cc29
-rw-r--r--chromium/v8/src/objects.cc28
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 {