LibJS: Prevent stack overflow if Proxy handler's __proto__ is the Proxy
Fixes #9322.
This commit is contained in:
parent
9998a2c91e
commit
941ff0cf60
Notes:
sideshowbarker
2024-07-18 04:39:55 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/941ff0cf601 Pull-request: https://github.com/SerenityOS/serenity/pull/9842 Reviewed-by: https://github.com/IdanHo ✅
2 changed files with 27 additions and 0 deletions
|
@ -577,6 +577,24 @@ Value ProxyObject::internal_get(PropertyName const& property_name, Value receive
|
|||
// 4. Assert: Type(handler) is Object.
|
||||
// 5. Let target be O.[[ProxyTarget]].
|
||||
|
||||
// NOTE: We need to protect ourselves from a Proxy with the handler's prototype set to the
|
||||
// Proxy itself, which would by default bounce between these functions indefinitely and lead to
|
||||
// a stack overflow when the Proxy's (p) or Proxy handler's (h) Object::get() is called and the
|
||||
// handler doesn't have a `get` trap:
|
||||
//
|
||||
// 1. p -> ProxyObject::internal_get() <- you are here
|
||||
// 2. h -> Value::get_method()
|
||||
// 3. h -> Value::get()
|
||||
// 4. h -> Object::internal_get()
|
||||
// 5. h -> Object::internal_get_prototype_of() (result is p)
|
||||
// 6. goto 1
|
||||
//
|
||||
// In JS code: `h = {}; p = new Proxy({}, h); h.__proto__ = p; p.foo // or h.foo`
|
||||
if (vm.did_reach_stack_space_limit()) {
|
||||
vm.throw_exception<Error>(global_object, ErrorType::CallStackSizeExceeded);
|
||||
return {};
|
||||
}
|
||||
|
||||
// 6. Let trap be ? GetMethod(handler, "get").
|
||||
auto trap = Value(&m_handler).get_method(global_object, vm.names.get);
|
||||
if (vm.exception())
|
||||
|
|
|
@ -107,3 +107,12 @@ describe("[[Get]] invariants", () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("Proxy handler that has the Proxy itself as its prototype", () => {
|
||||
const handler = {};
|
||||
const proxy = new Proxy({}, handler);
|
||||
handler.__proto__ = proxy;
|
||||
expect(() => {
|
||||
proxy.foo;
|
||||
}).toThrowWithMessage(Error, "Call stack size limit exceeded");
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue