зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1340719 - Throw an exception if accessing Xray from wrong docgroup (r=bholley)
MozReview-Commit-ID: BBrRsk3KvGb
This commit is contained in:
Родитель
ea4ae58e28
Коммит
fcdb251c4b
|
@ -93,6 +93,12 @@ public:
|
|||
mTabGroup->ValidateAccess();
|
||||
}
|
||||
|
||||
// Like ValidateAccess, but it returns a bool rather than asserting.
|
||||
bool AccessAllowed() const
|
||||
{
|
||||
return mTabGroup->AccessAllowed();
|
||||
}
|
||||
|
||||
// Return a pointer that can be continually checked to see if access to this
|
||||
// DocGroup is valid. This pointer should live at least as long as the
|
||||
// DocGroup.
|
||||
|
|
|
@ -1717,6 +1717,7 @@ nsMessageManagerScriptExecutor::InitChildGlobalInternal(
|
|||
// Set the location information for the new global, so that tools like
|
||||
// about:memory may use that information.
|
||||
xpc::SetLocationForGlobal(global, aID);
|
||||
xpc::SetDocGroupValidation(global);
|
||||
|
||||
DidCreateGlobal();
|
||||
return true;
|
||||
|
|
|
@ -9,6 +9,7 @@ support-files =
|
|||
file_bug1303838.html
|
||||
file_bug1303838_target.html
|
||||
file_bug1303838_with_iframe.html
|
||||
file_docgroup_forbid.html
|
||||
file_messagemanager_unload.html
|
||||
file_pluginAudio.html
|
||||
file_use_counter_outer.html
|
||||
|
@ -26,6 +27,8 @@ support-files =
|
|||
tags = mcb
|
||||
[browser_bug1011748.js]
|
||||
[browser_bug1058164.js]
|
||||
[browser_docgroup_forbid.js]
|
||||
skip-if = !e10s
|
||||
[browser_messagemanager_loadprocessscript.js]
|
||||
[browser_messagemanager_targetframeloader.js]
|
||||
[browser_messagemanager_unload.js]
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
const url = "https://example.com/browser/dom/base/test/file_docgroup_forbid.html";
|
||||
|
||||
function frameScript() {
|
||||
let e = Services.ww.getWindowEnumerator();
|
||||
let exception = false;
|
||||
while (e.hasMoreElements()) {
|
||||
try {
|
||||
/*
|
||||
* If this is a window we're not supposed to touch, we'll get an
|
||||
* error very early here (during the QI).
|
||||
*/
|
||||
var window = e.getNext().QueryInterface(Components.interfaces.nsIDOMWindow);
|
||||
var doc = window.document;
|
||||
} catch (e) {
|
||||
if (/accessing object in wrong DocGroup/.test(e.toString())) {
|
||||
exception = true;
|
||||
break;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do some stuff that will trigger the DocGroup assertions if we
|
||||
* didn't throw.
|
||||
*/
|
||||
|
||||
let elt = doc.createElement("div");
|
||||
elt.innerHTML = "hello!";
|
||||
doc.body.appendChild(elt);
|
||||
|
||||
let evt = new window.CustomEvent("foopy");
|
||||
doc.dispatchEvent(evt);
|
||||
}
|
||||
sendAsyncMessage("DocGroupTest:Done", exception);
|
||||
}
|
||||
|
||||
function promiseMessage(messageManager, message) {
|
||||
return new Promise(resolve => {
|
||||
let listener = (msg) => {
|
||||
messageManager.removeMessageListener(message, listener);
|
||||
resolve(msg);
|
||||
};
|
||||
|
||||
messageManager.addMessageListener(message, listener);
|
||||
})
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
// This pref is normally disabled during tests, but we want to test
|
||||
// it here, so we enable it.
|
||||
yield new Promise(go => {
|
||||
SpecialPowers.pushPrefEnv({set: [["extensions.throw_on_docgroup_mismatch.enabled", true]]}, go)
|
||||
});
|
||||
|
||||
let url1 = url + "?tab=1";
|
||||
let url2 = url + "?tab=2";
|
||||
|
||||
let browser1 = gBrowser.selectedBrowser;
|
||||
|
||||
let tab2 = gBrowser.addTab(url2, {sameProcessAsFrameLoader: browser1.frameLoader});
|
||||
let browser2 = tab2.linkedBrowser;
|
||||
yield BrowserTestUtils.browserLoaded(browser2, false, url2);
|
||||
|
||||
browser1.loadURI(url1);
|
||||
yield BrowserTestUtils.browserLoaded(browser1, false, url1);
|
||||
|
||||
browser1.messageManager.loadFrameScript(`data:,(${frameScript})();`, false);
|
||||
|
||||
let exception = yield promiseMessage(browser1.messageManager, "DocGroupTest:Done");
|
||||
|
||||
ok(exception, "Touching two windows threw an exception (that's good!)");
|
||||
|
||||
gBrowser.removeTab(tab2);
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
<script>
|
||||
document.addEventListener("foopy", function() { dump("ran event handler\n"); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -97,6 +97,7 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
|
|||
mNext(nullptr),
|
||||
mGlobalJSObject(aGlobal),
|
||||
mHasCallInterpositions(false),
|
||||
mDocGroupValidation(false),
|
||||
mIsContentXBLScope(false),
|
||||
mIsAddonScope(false)
|
||||
{
|
||||
|
@ -167,6 +168,9 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
|
|||
if (addonId) {
|
||||
// We forbid CPOWs unless they're specifically allowed.
|
||||
priv->allowCPOWs = gAllowCPOWAddonSet ? gAllowCPOWAddonSet->has(addonId) : false;
|
||||
|
||||
// Automatically opt into DocGroup validation for add-on compartments.
|
||||
mDocGroupValidation = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1373,6 +1373,12 @@ AllowCPOWsInAddon(const nsACString& addonIdStr, bool allow)
|
|||
return XPCWrappedNativeScope::AllowCPOWsInAddon(jsapi.cx(), addonId, allow);
|
||||
}
|
||||
|
||||
void
|
||||
SetDocGroupValidation(JSObject* global)
|
||||
{
|
||||
CompartmentPrivate::Get(global)->scope->SetDocGroupValidation();
|
||||
}
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -866,6 +866,9 @@ public:
|
|||
|
||||
bool AttachComponentsObject(JSContext* aCx);
|
||||
|
||||
void SetDocGroupValidation() { mDocGroupValidation = true; }
|
||||
bool HasDocGroupValidation() const { return mDocGroupValidation; }
|
||||
|
||||
// Returns the JS object reflection of the Components object.
|
||||
bool
|
||||
GetComponentsJSObject(JS::MutableHandleObject obj);
|
||||
|
@ -1067,6 +1070,12 @@ private:
|
|||
// from this scope if the caller scope has mInterposition set.
|
||||
bool mHasCallInterpositions;
|
||||
|
||||
// If this flag is set, Xray wrappers from this compartment to content
|
||||
// compartments will be DocGroupValidationWrappers of some
|
||||
// sort. Consequently, this compartment will throw instead of asserting for
|
||||
// DocGroup mismatches.
|
||||
bool mDocGroupValidation;
|
||||
|
||||
nsAutoPtr<DOMExpandoSet> mDOMExpandoSet;
|
||||
|
||||
JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;
|
||||
|
|
|
@ -415,6 +415,8 @@ void NukeAllWrappersForCompartment(JSContext* cx, JSCompartment* compartment,
|
|||
void SetLocationForGlobal(JSObject* global, const nsACString& location);
|
||||
void SetLocationForGlobal(JSObject* global, nsIURI* locationURI);
|
||||
|
||||
void SetDocGroupValidation(JSObject* global);
|
||||
|
||||
// ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
|
||||
// of JS::ZoneStats.
|
||||
class ZoneStatsExtras {
|
||||
|
|
|
@ -0,0 +1,274 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DocGroupValidationWrapper.h"
|
||||
#include "AddonWrapper.h"
|
||||
#include "WaiveXrayWrapper.h"
|
||||
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
||||
using namespace xpc;
|
||||
|
||||
static bool
|
||||
AccessAllowed(JSContext* cx, JS::Handle<JSObject*> wrapper)
|
||||
{
|
||||
RootedObject unwrapped(cx, UncheckedUnwrap(wrapper));
|
||||
RefPtr<nsGlobalWindow> window = WindowGlobalOrNull(unwrapped);
|
||||
if (!window) {
|
||||
// Access to non-windows is always kosher.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (window->GetDocGroup()->AccessAllowed())
|
||||
return true;
|
||||
|
||||
static bool sThrowOnMismatch;
|
||||
static bool sPrefInitialized;
|
||||
if (!sPrefInitialized) {
|
||||
sPrefInitialized = true;
|
||||
Preferences::AddBoolVarCache(&sThrowOnMismatch,
|
||||
"extensions.throw_on_docgroup_mismatch.enabled");
|
||||
}
|
||||
|
||||
// If DocGroup validation is disabled, don't throw.
|
||||
if (!sThrowOnMismatch)
|
||||
return true;
|
||||
|
||||
JS_ReportErrorASCII(cx, "accessing object in wrong DocGroup");
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::getOwnPropertyDescriptor(cx, wrapper, id, desc);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
Handle<PropertyDescriptor> desc,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::defineProperty(cx, wrapper, id, desc, result);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::ownPropertyKeys(JSContext* cx, HandleObject wrapper,
|
||||
AutoIdVector& props) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::ownPropertyKeys(cx, wrapper, props);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::delete_(cx, wrapper, id, result);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::enumerate(JSContext* cx, HandleObject wrapper, MutableHandleObject objp) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::enumerate(cx, wrapper, objp);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::getPrototype(JSContext* cx, HandleObject proxy,
|
||||
MutableHandleObject protop) const
|
||||
{
|
||||
return AccessAllowed(cx, proxy) &&
|
||||
Base::getPrototype(cx, proxy, protop);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
return AccessAllowed(cx, proxy) &&
|
||||
Base::setPrototype(cx, proxy, proto, result);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
|
||||
MutableHandleObject protop) const
|
||||
{
|
||||
return AccessAllowed(cx, proxy) &&
|
||||
Base::getPrototypeIfOrdinary(cx, proxy, isOrdinary, protop);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::setImmutablePrototype(JSContext* cx, HandleObject proxy,
|
||||
bool* succeeded) const
|
||||
{
|
||||
return AccessAllowed(cx, proxy) &&
|
||||
Base::setImmutablePrototype(cx, proxy, succeeded);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::preventExtensions(JSContext* cx, HandleObject wrapper,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::preventExtensions(cx, wrapper, result);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::isExtensible(cx, wrapper, extensible);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::has(cx, wrapper, id, bp);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
|
||||
HandleId id, MutableHandleValue vp) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::get(cx, wrapper, receiver, id, vp);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult& result) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::set(cx, wrapper, id, v, receiver, result);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::call(cx, wrapper, args);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::construct(cx, wrapper, args);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::getPropertyDescriptor(cx, wrapper, id, desc);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::hasOwn(cx, wrapper, id, bp);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
|
||||
AutoIdVector& props) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::getOwnEnumerablePropertyKeys(cx, wrapper, props);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
|
||||
bool* bp) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper) &&
|
||||
Base::hasInstance(cx, wrapper, v, bp);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
const char*
|
||||
DocGroupValidationWrapper<Base>::className(JSContext* cx, HandleObject proxy) const
|
||||
{
|
||||
return AccessAllowed(cx, proxy)
|
||||
? Base::className(cx, proxy)
|
||||
: "forbidden";
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
JSString*
|
||||
DocGroupValidationWrapper<Base>::fun_toString(JSContext* cx, HandleObject wrapper,
|
||||
unsigned indent) const
|
||||
{
|
||||
return AccessAllowed(cx, wrapper)
|
||||
? Base::fun_toString(cx, wrapper, indent)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandle<RegExpShared*> g) const
|
||||
{
|
||||
return AccessAllowed(cx, proxy) &&
|
||||
Base::regexp_toShared(cx, proxy, g);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
DocGroupValidationWrapper<Base>::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
|
||||
{
|
||||
return AccessAllowed(cx, proxy) &&
|
||||
Base::boxedValue_unbox(cx, proxy, vp);
|
||||
}
|
||||
|
||||
namespace xpc {
|
||||
|
||||
template<typename Base>
|
||||
const DocGroupValidationWrapper<Base> DocGroupValidationWrapper<Base>::singleton(0);
|
||||
|
||||
#define DEFINE_SINGLETON(Base) \
|
||||
template class DocGroupValidationWrapper<Base>
|
||||
|
||||
DEFINE_SINGLETON(CrossCompartmentWrapper);
|
||||
DEFINE_SINGLETON(PermissiveXrayXPCWN);
|
||||
DEFINE_SINGLETON(PermissiveXrayDOM);
|
||||
DEFINE_SINGLETON(PermissiveXrayJS);
|
||||
|
||||
DEFINE_SINGLETON(AddonWrapper<CrossCompartmentWrapper>);
|
||||
DEFINE_SINGLETON(AddonWrapper<PermissiveXrayXPCWN>);
|
||||
DEFINE_SINGLETON(AddonWrapper<PermissiveXrayDOM>);
|
||||
|
||||
DEFINE_SINGLETON(WaiveXrayWrapper);
|
||||
|
||||
} // namespace xpc
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef xpc_DocGroupValidationWrapper_h
|
||||
#define xpc_DocGroupValidationWrapper_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "jswrapper.h"
|
||||
#include "WaiveXrayWrapper.h"
|
||||
#include "XrayWrapper.h"
|
||||
|
||||
namespace xpc {
|
||||
|
||||
template<typename Base>
|
||||
class DocGroupValidationWrapper : public Base {
|
||||
public:
|
||||
explicit constexpr DocGroupValidationWrapper(unsigned flags) : Base(flags) { }
|
||||
|
||||
/* Standard internal methods. */
|
||||
virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const override;
|
||||
virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
Handle<PropertyDescriptor> desc,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual bool enumerate(JSContext* cx, HandleObject wrapper, MutableHandleObject objp) const override;
|
||||
virtual bool getPrototype(JSContext* cx, HandleObject proxy,
|
||||
MutableHandleObject protop) const override;
|
||||
virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
|
||||
ObjectOpResult& result) const override;
|
||||
|
||||
virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
|
||||
MutableHandleObject protop) const override;
|
||||
virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
|
||||
bool* succeeded) const override;
|
||||
virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
|
||||
virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
|
||||
virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
|
||||
HandleId id, MutableHandleValue vp) const override;
|
||||
virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult& result) const override;
|
||||
virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
|
||||
virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
|
||||
|
||||
/* SpiderMonkey extensions. */
|
||||
virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const override;
|
||||
virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
|
||||
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
|
||||
bool* bp) const override;
|
||||
virtual const char* className(JSContext* cx, HandleObject proxy) const override;
|
||||
virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
|
||||
unsigned indent) const override;
|
||||
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandle<RegExpShared*> g) const override;
|
||||
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
|
||||
|
||||
static const DocGroupValidationWrapper singleton;
|
||||
};
|
||||
|
||||
#define DECLARE_SINGLETON(Base) \
|
||||
extern template class DocGroupValidationWrapper<Base>
|
||||
|
||||
DECLARE_SINGLETON(CrossCompartmentWrapper);
|
||||
DECLARE_SINGLETON(PermissiveXrayXPCWN);
|
||||
DECLARE_SINGLETON(PermissiveXrayDOM);
|
||||
DECLARE_SINGLETON(PermissiveXrayJS);
|
||||
|
||||
DECLARE_SINGLETON(AddonWrapper<CrossCompartmentWrapper>);
|
||||
DECLARE_SINGLETON(AddonWrapper<PermissiveXrayXPCWN>);
|
||||
DECLARE_SINGLETON(AddonWrapper<PermissiveXrayDOM>);
|
||||
|
||||
DECLARE_SINGLETON(WaiveXrayWrapper);
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
#endif // xpc_DocGroupValidationWrapper_h
|
|
@ -7,6 +7,7 @@
|
|||
#include "WaiveXrayWrapper.h"
|
||||
#include "FilteringWrapper.h"
|
||||
#include "AddonWrapper.h"
|
||||
#include "DocGroupValidationWrapper.h"
|
||||
#include "XrayWrapper.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "XPCWrapper.h"
|
||||
|
@ -447,6 +448,66 @@ SelectAddonWrapper(JSContext* cx, HandleObject obj, const Wrapper* wrapper)
|
|||
return wrapper;
|
||||
}
|
||||
|
||||
static bool
|
||||
NeedsDocGroupValidationWrapper(JSContext* cx, HandleObject obj,
|
||||
JSCompartment* origin, JSCompartment* target,
|
||||
CompartmentPrivate* targetCompartmentPrivate)
|
||||
{
|
||||
// We do DocGroup validation in the following circumstances:
|
||||
// - Only if the target compartment has the DocGroupValidation()
|
||||
// flag set (which includes any add-on compartments).
|
||||
// - Only if we're in the content process.
|
||||
// - Only if the origin compartment is not system principled and is not a sandbox.
|
||||
// - Only if the target compartment is system principled.
|
||||
|
||||
if (!targetCompartmentPrivate->scope->HasDocGroupValidation())
|
||||
return false;
|
||||
|
||||
if (!XRE_IsContentProcess())
|
||||
return false;
|
||||
|
||||
if (!AccessCheck::isChrome(target))
|
||||
return false;
|
||||
|
||||
if (AccessCheck::isChrome(origin) ||
|
||||
IsSandbox(js::GetGlobalForObjectCrossCompartment(obj)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const Wrapper*
|
||||
SelectDocGroupValidationWrapper(JSContext* cx, HandleObject obj, const Wrapper* wrapper)
|
||||
{
|
||||
// Validation wrappers only supports certain wrapper types, so we check if
|
||||
// we would have used one of the supported ones.
|
||||
if (wrapper == &CrossCompartmentWrapper::singleton)
|
||||
return &DocGroupValidationWrapper<CrossCompartmentWrapper>::singleton;
|
||||
else if (wrapper == &PermissiveXrayXPCWN::singleton)
|
||||
return &DocGroupValidationWrapper<PermissiveXrayXPCWN>::singleton;
|
||||
else if (wrapper == &PermissiveXrayDOM::singleton)
|
||||
return &DocGroupValidationWrapper<PermissiveXrayDOM>::singleton;
|
||||
else if (wrapper == &PermissiveXrayJS::singleton)
|
||||
return &DocGroupValidationWrapper<PermissiveXrayJS>::singleton;
|
||||
else if (wrapper == &AddonWrapper<CrossCompartmentWrapper>::singleton)
|
||||
return &DocGroupValidationWrapper<AddonWrapper<CrossCompartmentWrapper>>::singleton;
|
||||
else if (wrapper == &AddonWrapper<PermissiveXrayXPCWN>::singleton)
|
||||
return &DocGroupValidationWrapper<AddonWrapper<PermissiveXrayXPCWN>>::singleton;
|
||||
else if (wrapper == &AddonWrapper<PermissiveXrayDOM>::singleton)
|
||||
return &DocGroupValidationWrapper<AddonWrapper<PermissiveXrayDOM>>::singleton;
|
||||
else if (wrapper == &WaiveXrayWrapper::singleton)
|
||||
return &DocGroupValidationWrapper<WaiveXrayWrapper>::singleton;
|
||||
|
||||
// If NeedsDocGroupValidationWrapper is true, then securityWrapper should be false
|
||||
// and xrayType should never be NotXray (since the target always subsumes the origin
|
||||
// and the origin never subsumes the target).
|
||||
MOZ_ASSERT(wrapper == &WaiveXrayWrapper::singleton ||
|
||||
wrapper == &(PermissiveXrayOpaque::singleton));
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
|
||||
{
|
||||
|
@ -556,6 +617,13 @@ WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
|
|||
// then we try to "upgrade" the wrapper to an interposing one.
|
||||
if (targetCompartmentPrivate->scope->HasInterposition())
|
||||
wrapper = SelectAddonWrapper(cx, obj, wrapper);
|
||||
|
||||
// Now try another "upgrade" to a DocGroupValidationWrapper.
|
||||
if (NeedsDocGroupValidationWrapper(cx, obj, origin, target,
|
||||
targetCompartmentPrivate))
|
||||
{
|
||||
wrapper = SelectDocGroupValidationWrapper(cx, obj, wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetSubsumesOrigin) {
|
||||
|
|
|
@ -12,6 +12,7 @@ UNIFIED_SOURCES += [
|
|||
'AccessCheck.cpp',
|
||||
'AddonWrapper.cpp',
|
||||
'ChromeObjectWrapper.cpp',
|
||||
'DocGroupValidationWrapper.cpp',
|
||||
'FilteringWrapper.cpp',
|
||||
'WaiveXrayWrapper.cpp',
|
||||
'WrapperFactory.cpp',
|
||||
|
|
|
@ -5658,3 +5658,7 @@ pref("layers.advanced.boxshadow-outer-layers", 2);
|
|||
pref("layers.advanced.caret-layers", 2);
|
||||
pref("layers.advanced.displaybuttonborder-layers", 2);
|
||||
pref("layers.advanced.outline-layers", 2);
|
||||
|
||||
// Determines whether we throw an exception when a frame script
|
||||
// accesses the wrong DocGroup. The alternative is to crash.
|
||||
user_pref("extensions.throw_on_docgroup_mismatch.enabled", true);
|
||||
|
|
|
@ -370,3 +370,5 @@ user_pref("browser.formautofill.experimental", true);
|
|||
// The prefs recommended by Marionette are typically geared towards
|
||||
// consumer automation; not vendor testing.
|
||||
user_pref("marionette.prefs.recommended", false);
|
||||
|
||||
user_pref("extensions.throw_on_docgroup_mismatch.enabled", false);
|
||||
|
|
|
@ -77,10 +77,16 @@ public:
|
|||
ValidatingDispatcher* mPrevRunningDispatcher;
|
||||
};
|
||||
|
||||
// Ensure that it's valid to access the TabGroup at this time.
|
||||
// Return true if it's valid to access the TabGroup at this time.
|
||||
bool AccessAllowed() const
|
||||
{
|
||||
return !sRunningDispatcher || mAccessValid;
|
||||
}
|
||||
|
||||
// Like AccessAllowed(), but asserts.
|
||||
void ValidateAccess() const
|
||||
{
|
||||
MOZ_ASSERT(!sRunningDispatcher || mAccessValid);
|
||||
MOZ_ASSERT(AccessAllowed());
|
||||
}
|
||||
|
||||
class Runnable;
|
||||
|
|
Загрузка…
Ссылка в новой задаче