Bug 706057: Fix use-after-free in getOwnPropertyDescriptor.

getOwnPropertyDescriptor should create the descriptor object by
using [[DefineOwnProperty]], and not by looking through the prototype
chain where it may invoke getters and setters on the Object.prototype.

If there exists an Object.prototype.get property with a setter, that method is
invoked when it shouldn't. A malicious getter here can delete the property
currently being processed in getOwnPropertyDescriptor, and we'll end up
with a use-after-free bug.

Avoid this problem by following the spec and use js_defproperty rather than
js_setproperty to define own properties in getOwnPropertyDescriptor and
related functions.
This commit is contained in:
Tor Andersson
2022-11-07 12:52:05 +01:00
parent bf4ac94207
commit edb50ad66f

View File

@@ -134,25 +134,25 @@ static void O_getOwnPropertyDescriptor(js_State *J)
js_newobject(J); js_newobject(J);
if (!ref->getter && !ref->setter) { if (!ref->getter && !ref->setter) {
js_pushvalue(J, ref->value); js_pushvalue(J, ref->value);
js_setproperty(J, -2, "value"); js_defproperty(J, -2, "value", 0);
js_pushboolean(J, !(ref->atts & JS_READONLY)); js_pushboolean(J, !(ref->atts & JS_READONLY));
js_setproperty(J, -2, "writable"); js_defproperty(J, -2, "writable", 0);
} else { } else {
if (ref->getter) if (ref->getter)
js_pushobject(J, ref->getter); js_pushobject(J, ref->getter);
else else
js_pushundefined(J); js_pushundefined(J);
js_setproperty(J, -2, "get"); js_defproperty(J, -2, "get", 0);
if (ref->setter) if (ref->setter)
js_pushobject(J, ref->setter); js_pushobject(J, ref->setter);
else else
js_pushundefined(J); js_pushundefined(J);
js_setproperty(J, -2, "set"); js_defproperty(J, -2, "set", 0);
} }
js_pushboolean(J, !(ref->atts & JS_DONTENUM)); js_pushboolean(J, !(ref->atts & JS_DONTENUM));
js_setproperty(J, -2, "enumerable"); js_defproperty(J, -2, "enumerable", 0);
js_pushboolean(J, !(ref->atts & JS_DONTCONF)); js_pushboolean(J, !(ref->atts & JS_DONTCONF));
js_setproperty(J, -2, "configurable"); js_defproperty(J, -2, "configurable", 0);
} }
} }
@@ -248,7 +248,7 @@ static void ToPropertyDescriptor(js_State *J, js_Object *obj, const char *name,
} }
if (js_hasproperty(J, -1, "value")) { if (js_hasproperty(J, -1, "value")) {
hasvalue = 1; hasvalue = 1;
js_setproperty(J, -3, name); js_defproperty(J, -3, name, 0);
} }
if (!writable) atts |= JS_READONLY; if (!writable) atts |= JS_READONLY;