RESOLVED FIXED 153920
Attributes on the Window instance should be configurable unless [Unforgeable]
https://bugs.webkit.org/show_bug.cgi?id=153920
Summary Attributes on the Window instance should be configurable unless [Unforgeable]
Chris Dumez
Reported 2016-02-05 09:35:16 PST
Attributes on the Window instance should be configurable unless [Unforgeable]: 1. 'constructor' property: http://www.w3.org/TR/WebIDL/#interface-prototype-object 2. Constructor properties (e.g. window.Node): http://www.w3.org/TR/WebIDL/#es-interfaces 3. IDL attributes: http://heycam.github.io/webidl/#es-attributes (configurable unless [Unforgeable], e.g. window.location) Firefox complies with the WebIDL specification but WebKit does not for 1. and 3.
Attachments
WIP Patch (15.11 KB, patch)
2016-02-05 10:22 PST, Chris Dumez
no flags
WIP Patch (23.59 KB, patch)
2016-02-07 12:49 PST, Chris Dumez
no flags
Patch (33.72 KB, patch)
2016-02-07 14:52 PST, Chris Dumez
no flags
Patch (40.11 KB, patch)
2016-02-08 21:12 PST, Chris Dumez
no flags
Patch (58.09 KB, patch)
2016-02-08 22:02 PST, Chris Dumez
no flags
Patch (58.98 KB, patch)
2016-02-09 09:19 PST, Chris Dumez
no flags
Patch (58.75 KB, patch)
2016-02-09 09:21 PST, Chris Dumez
no flags
Patch (58.86 KB, patch)
2016-02-09 09:23 PST, Chris Dumez
darin: review+
Chris Dumez
Comment 1 2016-02-05 10:22:23 PST
Created attachment 270750 [details] WIP Patch
Chris Dumez
Comment 2 2016-02-07 12:49:45 PST
Created attachment 270828 [details] WIP Patch
Chris Dumez
Comment 3 2016-02-07 14:52:22 PST
Darin Adler
Comment 4 2016-02-08 14:57:54 PST
Comment on attachment 270832 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=270832&action=review > Source/JavaScriptCore/runtime/JSObject.cpp:1676 > for (auto iter = hashTable->begin(); iter != hashTable->end(); ++iter) { Modern for loop would be nicer here. > Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:205 > + const HashTableValue* entry = JSDOMWindow::info()->staticPropHashTable->entry(propertyName); auto* would be better, and I’d put the definition inside the if
Gavin Barraclough
Comment 5 2016-02-08 16:40:29 PST
Comment on attachment 270832 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=270832&action=review > Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:210 > } Per conversation, looks like you've changed behavior for (thisObject->staticFunctionsReified() && !allowsAccess) – seems unlikely that this right. Some properties that were previously accessible (with altered attributes) will now be inaccessible. > LayoutTests/js/getOwnPropertyDescriptor-window-attributes.html:61 > +shouldBeTrue("descriptor.configurable"); Should we also be checking descriptor.value? > LayoutTests/js/getOwnPropertyDescriptor-window-attributes.html:69 > +shouldBeTrue("descriptor.configurable"); Should we also be checking descriptor.value?
Chris Dumez
Comment 6 2016-02-08 20:42:56 PST
Comment on attachment 270832 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=270832&action=review >> Source/JavaScriptCore/runtime/JSObject.cpp:1676 >> for (auto iter = hashTable->begin(); iter != hashTable->end(); ++iter) { > > Modern for loop would be nicer here. I will need to tweak HashTable::ConstIterator but OK. >> Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:205 >> + const HashTableValue* entry = JSDOMWindow::info()->staticPropHashTable->entry(propertyName); > > auto* would be better, and I’d put the definition inside the if OK. >> Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:210 >> } > > Per conversation, looks like you've changed behavior for (thisObject->staticFunctionsReified() && !allowsAccess) – seems unlikely that this right. Some properties that were previously accessible (with altered attributes) will now be inaccessible. Good catch. I have checked the behavior of Firefox and Chrome and it seems they keep using the original property getter for cross-origin access, even if that property was deleted / redefined. I propose we do the same. I will also add test coverage for this. >> LayoutTests/js/getOwnPropertyDescriptor-window-attributes.html:61 >> +shouldBeTrue("descriptor.configurable"); > > Should we also be checking descriptor.value? Will do. >> LayoutTests/js/getOwnPropertyDescriptor-window-attributes.html:69 >> +shouldBeTrue("descriptor.configurable"); > > Should we also be checking descriptor.value? Will do.
Chris Dumez
Comment 7 2016-02-08 21:12:54 PST
Chris Dumez
Comment 8 2016-02-08 22:02:45 PST
Radar WebKit Bug Importer
Comment 9 2016-02-08 22:05:05 PST
Gavin Barraclough
Comment 10 2016-02-08 23:22:42 PST
> Good catch. I have checked the behavior of Firefox and Chrome and it seems > they keep using the original property getter for cross-origin access, even > if that property was deleted / redefined. > I propose we do the same. Oh, that makes a lot of sense. As a future refactoring, it's probably cleanest (& therefore less error prone) to just make DOMWindow's getOwnPropertySlot do the cross origin check at the head of the function, separate from the set of real properties for when access is allowed. if (!allowAccess) { // return one of a few hard-coded permitted properties, // else fail. } // real properties for access allowed. In fact, splitting it that way would probably make it clean to return different accessors in the cross-origin cases. If we did it right we can probably do away with dynamic security checks in the accessors for cacheable cases – I'm guessing that we can prove that anywhere we would return the real (access allowed) accessor, it would be safe to cache & never perform a security check, since permission is static.
Gavin Barraclough
Comment 11 2016-02-08 23:46:31 PST
Comment on attachment 270912 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=270912&action=review > Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:208 > + return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); Oh! – I just realized another possible case to check. What if there exists a item on the page that would be accessible via a named property, but that is shadowed by a configurable property in the static table, and that static property is deleted? What I think should happen is, if you try to access that property before deletion you'll get the property from the static table, and after deletion you should get the named property. What I think will happen with your code as-is, is that before deletion you'll correctly get the property from the static table, but after deletion you'll return early here – returning property not found before the named lookup has a chance to run. If I'm right about there being a problem, then I think a fix would be to invert the if: if (!thisObject->staticFunctionsReified() || !allowsAccess) { slot.setCacheableCustom(thisObject, allowsAccess ? entry->attributes() : ReadOnly | DontDelete | DontEnum, entry->propertyGetter()); return true; } (This would all also be easier when we switch to be more spec-compliant & move the named properties onto their own NPO object in the photo chain!)
Chris Dumez
Comment 12 2016-02-09 09:19:33 PST
Chris Dumez
Comment 13 2016-02-09 09:21:18 PST
Chris Dumez
Comment 14 2016-02-09 09:22:24 PST
(In reply to comment #11) > Comment on attachment 270912 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=270912&action=review > > > Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:208 > > + return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); > > Oh! – I just realized another possible case to check. What if there exists a > item on the page that would be accessible via a named property, but that is > shadowed by a configurable property in the static table, and that static > property is deleted? > > What I think should happen is, if you try to access that property before > deletion you'll get the property from the static table, and after deletion > you should get the named property. What I think will happen with your code > as-is, is that before deletion you'll correctly get the property from the > static table, but after deletion you'll return early here – returning > property not found before the named lookup has a chance to run. > > If I'm right about there being a problem, then I think a fix would be to > invert the if: > > if (!thisObject->staticFunctionsReified() || !allowsAccess) { > slot.setCacheableCustom(thisObject, allowsAccess ? > entry->attributes() : ReadOnly | DontDelete | DontEnum, > entry->propertyGetter()); > return true; > } > > (This would all also be easier when we switch to be more spec-compliant & > move the named properties onto their own NPO object in the photo chain!) Yes, you are right that it did not behave as expected in this case. I have added test coverage for this and made the fix.
Chris Dumez
Comment 15 2016-02-09 09:23:31 PST
Darin Adler
Comment 16 2016-02-10 09:31:21 PST
Comment on attachment 270935 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=270935&action=review > Source/JavaScriptCore/runtime/Lookup.h:138 > + const HashTableValue& operator*() { return *value(); } I think this should be a const member, as should value(), key(), and operator->(). > Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:205 > + // When accessing cross-origin known Window properties, we always use the original property getter, > + // even if the property was removed / redefined. This matches Firefox and Chrome's behavior. These comments about matching other browsers often are slightly confusing and a liability long term. If you feel the need to state this in terms of the other browsers’ behavior because no standard makes this clear, then I think you should say "as of early 2016" instead of making it sound timeless.
Chris Dumez
Comment 17 2016-02-10 11:47:12 PST
Note You need to log in before you can comment on or make changes to this bug.