Commit e10fdbed authored by cbruni's avatar cbruni Committed by Commit bot

[proxies] Limit recursive proxy prototype lookups to 100'000

Creating proto-recursive proxies might lead to instanceof while-looping
endlessly in Object::HasInPrototypeChain (For traps we already have stack
guards in place to prevent stack overflows). We prevent this by limiting
the number of proxies we visit in PrototypeIterator to a magic large number.

LOG=n
BUG=v8:1534

Review URL: https://codereview.chromium.org/1542583003

Cr-Commit-Position: refs/heads/master@{#33007}
parent a878dcfd
...@@ -28,12 +28,15 @@ class PrototypeIterator { ...@@ -28,12 +28,15 @@ class PrototypeIterator {
enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN }; enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN };
const int kProxyPrototypeLimit = 100 * 1000;
PrototypeIterator(Isolate* isolate, Handle<Object> receiver, PrototypeIterator(Isolate* isolate, Handle<Object> receiver,
WhereToStart where_to_start = START_AT_PROTOTYPE) WhereToStart where_to_start = START_AT_PROTOTYPE)
: did_jump_to_prototype_chain_(false), : did_jump_to_prototype_chain_(false),
object_(NULL), object_(NULL),
handle_(receiver), handle_(receiver),
isolate_(isolate) { isolate_(isolate),
seen_proxies_(0) {
CHECK(!handle_.is_null()); CHECK(!handle_.is_null());
if (where_to_start == START_AT_PROTOTYPE) { if (where_to_start == START_AT_PROTOTYPE) {
Advance(); Advance();
...@@ -44,7 +47,8 @@ class PrototypeIterator { ...@@ -44,7 +47,8 @@ class PrototypeIterator {
WhereToStart where_to_start = START_AT_PROTOTYPE) WhereToStart where_to_start = START_AT_PROTOTYPE)
: did_jump_to_prototype_chain_(false), : did_jump_to_prototype_chain_(false),
object_(receiver), object_(receiver),
isolate_(isolate) { isolate_(isolate),
seen_proxies_(0) {
if (where_to_start == START_AT_PROTOTYPE) { if (where_to_start == START_AT_PROTOTYPE) {
Advance(); Advance();
} }
...@@ -127,14 +131,22 @@ class PrototypeIterator { ...@@ -127,14 +131,22 @@ class PrototypeIterator {
handle_ = isolate_->factory()->null_value(); handle_ = isolate_->factory()->null_value();
return true; return true;
} }
if (!handle_.is_null() && handle_->IsJSProxy()) { if (handle_.is_null() || !handle_->IsJSProxy()) {
did_jump_to_prototype_chain_ = true; AdvanceIgnoringProxies();
MaybeHandle<Object> proto = return true;
JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
return proto.ToHandle(&handle_);
} }
AdvanceIgnoringProxies(); // Due to possible __proto__ recursion limit the number of Proxies
return true; // we visit to an arbitrarily chosen large number.
seen_proxies_++;
if (seen_proxies_ > kProxyPrototypeLimit) {
isolate_->Throw(
*isolate_->factory()->NewRangeError(MessageTemplate::kStackOverflow));
return false;
}
did_jump_to_prototype_chain_ = true;
MaybeHandle<Object> proto =
JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
return proto.ToHandle(&handle_);
} }
bool IsAtEnd(WhereToEnd where_to_end = END_AT_NULL) const { bool IsAtEnd(WhereToEnd where_to_end = END_AT_NULL) const {
...@@ -166,6 +178,7 @@ class PrototypeIterator { ...@@ -166,6 +178,7 @@ class PrototypeIterator {
Object* object_; Object* object_;
Handle<Object> handle_; Handle<Object> handle_;
Isolate* isolate_; Isolate* isolate_;
int seen_proxies_;
DISALLOW_COPY_AND_ASSIGN(PrototypeIterator); DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
}; };
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
// Test instanceof with proxies. // Test instanceof with proxies.
function TestInstanceOfWithProxies() { (function TestInstanceOfWithProxies() {
function foo(x) { function foo(x) {
return x instanceof Array; return x instanceof Array;
} }
...@@ -47,6 +47,16 @@ function TestInstanceOfWithProxies() { ...@@ -47,6 +47,16 @@ function TestInstanceOfWithProxies() {
assertTrue(foo_catch(o)); assertTrue(foo_catch(o));
handler.getPrototypeOf = function(target) { return Array.prototype; } handler.getPrototypeOf = function(target) { return Array.prototype; }
assertFalse(foo_catch(o)); assertFalse(foo_catch(o));
} })();
TestInstanceOfWithProxies();
(function testInstanceOfWithRecursiveProxy() {
// Make sure we gracefully deal with recursive proxies.
var proxy = new Proxy({},{});
proxy.__proto__ = proxy;
// instanceof will cause an inifinite prototype walk.
assertThrows(() => { proxy instanceof Object }, RangeError);
var proxy2 = new Proxy({}, {getPrototypeOf() { return proxy2 }});
assertThrows(() => { proxy instanceof Object }, RangeError);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment