mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 843829 - Wrap unwaived content JS objects in opaque wrappers for XBL scopes. r=mrbkap
This commit is contained in:
parent
d77249c1d5
commit
6e2393b436
@ -71,6 +71,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821850
|
||||
return "method:" + arg;
|
||||
</body>
|
||||
</method>
|
||||
<method name="passMeAJSObject">
|
||||
<parameter name="arg" />
|
||||
<body>
|
||||
is(typeof arg.prop, 'undefined', "No properties");
|
||||
is(Object.getOwnPropertyNames(arg).length, 0, "Should have no own properties");
|
||||
try {
|
||||
arg.foo = 2;
|
||||
ok(true, "Stuff fails silently");
|
||||
} catch (e) {
|
||||
ok(false, "Stuff should fail silently");
|
||||
}
|
||||
is(typeof arg.foo, 'undefined', "Shouldn't place props");
|
||||
</body>
|
||||
</method>
|
||||
<property name="prop">
|
||||
<getter>return this._prop;</getter>
|
||||
<setter>this._prop = "set:" + val;</setter>
|
||||
@ -120,11 +134,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821850
|
||||
bound.prop = "someOtherVal";
|
||||
is(bound.prop, "set:someOtherVal", "Can set properties from content");
|
||||
|
||||
// Make sure we can't pass JS objects to the XBL scope.
|
||||
var proto = bound.__proto__;
|
||||
proto.passMeAJSObject({prop: 2});
|
||||
|
||||
//
|
||||
// Try sticking a bunch of stuff on the prototype object.
|
||||
//
|
||||
|
||||
var proto = bound.__proto__;
|
||||
proto.someExpando = 201;
|
||||
is(bound.someExpando, 201, "Can stick non-XBL properties on the proto");
|
||||
|
||||
|
@ -53,6 +53,30 @@ struct Opaque : public Policy {
|
||||
}
|
||||
};
|
||||
|
||||
// This policy is designed to protect privileged callers from untrusted non-
|
||||
// Xrayable objects. Nothing is allowed, and nothing throws.
|
||||
struct GentlyOpaque : public Policy {
|
||||
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
|
||||
return false;
|
||||
}
|
||||
static bool deny(js::Wrapper::Action act) {
|
||||
return true;
|
||||
}
|
||||
static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl)
|
||||
{
|
||||
// We allow nativeCall here because the alternative is throwing (which
|
||||
// happens in SecurityWrapper::nativeCall), which we don't want. There's
|
||||
// unlikely to be too much harm to letting this through, because this
|
||||
// wrapper is only used to wrap less-privileged objects in more-privileged
|
||||
// scopes, so unwrapping here only drops privileges.
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isSafeToUnwrap() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// This policy only permits access to the object if the subject can touch
|
||||
// system objects.
|
||||
struct OnlyIfSubjectIsSystem : public Policy {
|
||||
|
@ -143,6 +143,30 @@ FilteringWrapper<Base, Policy>::nativeCall(JSContext *cx, JS::IsAcceptableThis t
|
||||
return Base::Restrictive::nativeCall(cx, test, impl, args);
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
JSType hint, MutableHandleValue vp)
|
||||
{
|
||||
return Base::defaultValue(cx, obj, hint, vp);
|
||||
}
|
||||
|
||||
// With our entirely-opaque wrapper, the DefaultValue algorithm throws,
|
||||
// causing spurious exceptions. Manually implement something benign.
|
||||
template<>
|
||||
bool
|
||||
FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
|
||||
::defaultValue(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
JSType hint, MutableHandleValue vp)
|
||||
{
|
||||
JSString *str = JS_NewStringCopyZ(cx, "[Opaque]");
|
||||
if (!str)
|
||||
return false;
|
||||
vp.set(JS::StringValue(str));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::enter(JSContext *cx, JS::Handle<JSObject*> wrapper,
|
||||
@ -179,6 +203,7 @@ FilteringWrapper<Base, Policy>::enter(JSContext *cx, JS::Handle<JSObject*> wrapp
|
||||
#define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
|
||||
#define CW FilteringWrapper<SameCompartmentSecurityWrapper, ComponentsObjectPolicy>
|
||||
#define XCW FilteringWrapper<CrossCompartmentSecurityWrapper, ComponentsObjectPolicy>
|
||||
#define GO FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
|
||||
template<> SOW SOW::singleton(WrapperFactory::SOW_FLAG);
|
||||
template<> SCSOW SCSOW::singleton(WrapperFactory::SOW_FLAG);
|
||||
template<> XOW XOW::singleton(0);
|
||||
@ -188,9 +213,12 @@ template<> NNXOW NNXOW::singleton(0);
|
||||
template<> CW CW::singleton(0);
|
||||
template<> XCW XCW::singleton(0);
|
||||
|
||||
template<> GO GO::singleton(0);
|
||||
|
||||
template class SOW;
|
||||
template class XOW;
|
||||
template class DXOW;
|
||||
template class NNXOW;
|
||||
template class ChromeObjectWrapperBase;
|
||||
template class GO;
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ class FilteringWrapper : public Base {
|
||||
virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl,
|
||||
JS::CallArgs args) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool defaultValue(JSContext *cx, JS::Handle<JSObject*> obj, JSType hint, JS::MutableHandleValue vp) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool enter(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
|
||||
js::Wrapper::Action act, bool *bp) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -293,6 +293,10 @@ DEBUG_CheckUnwrapSafety(JSObject *obj, js::Wrapper *handler,
|
||||
} else if (AccessCheck::needsSystemOnlyWrapper(obj)) {
|
||||
// SOWs have a dynamic unwrap check, so we can't really say anything useful
|
||||
// about them here :-(
|
||||
} else if (handler == &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton) {
|
||||
// We explicitly use a SecurityWrapper to protect privileged callers from
|
||||
// less-privileged objects that they should never see. Skip the check in
|
||||
// this case.
|
||||
} else {
|
||||
// Otherwise, it should depend on whether the target subsumes the origin.
|
||||
MOZ_ASSERT(handler->isSafeToUnwrap() == AccessCheck::subsumes(target, origin));
|
||||
@ -361,6 +365,7 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
|
||||
bool targetSubsumesOrigin = AccessCheck::subsumes(target, origin);
|
||||
bool sameOrigin = targetSubsumesOrigin && originSubsumesTarget;
|
||||
XrayType xrayType = GetXrayType(obj);
|
||||
bool waiveXrayFlag = flags & WAIVE_XRAY_WRAPPER_FLAG;
|
||||
|
||||
// By default we use the wrapped proto of the underlying object as the
|
||||
// prototype for our wrapper, but we may select something different below.
|
||||
@ -395,6 +400,20 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
|
||||
OnlyIfSubjectIsSystem>::singleton;
|
||||
}
|
||||
|
||||
// Normally, a non-xrayable non-waived content object that finds itself in
|
||||
// a privileged scope is wrapped with a CrossCompartmentWrapper, even though
|
||||
// the lack of a waiver _really_ should give it an opaque wrapper. This is
|
||||
// a bit too entrenched to change for content-chrome, but we can at least fix
|
||||
// it for XBL scopes.
|
||||
//
|
||||
// See bug 843829.
|
||||
else if (targetSubsumesOrigin && !originSubsumesTarget &&
|
||||
!waiveXrayFlag && xrayType == NotXray &&
|
||||
IsXBLScope(target))
|
||||
{
|
||||
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton;
|
||||
}
|
||||
|
||||
//
|
||||
// Now, handle the regular cases.
|
||||
//
|
||||
@ -417,8 +436,7 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
|
||||
|
||||
// If Xrays are warranted, the caller may waive them for non-security
|
||||
// wrappers.
|
||||
bool waiveXrays = wantXrays && !securityWrapper &&
|
||||
(flags & WAIVE_XRAY_WRAPPER_FLAG);
|
||||
bool waiveXrays = wantXrays && !securityWrapper && waiveXrayFlag;
|
||||
|
||||
wrapper = SelectWrapper(securityWrapper, wantXrays, xrayType, waiveXrays);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user