Bug 1126014 - DomainPolicy support for e10s. r=mrbkap

This commit is contained in:
Gabor Krizsanits 2015-03-24 15:29:16 +01:00
parent dec35f3d87
commit 63fd104813
15 changed files with 600 additions and 18 deletions

View File

@ -5,17 +5,50 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DomainPolicy.h" #include "DomainPolicy.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/unused.h"
#include "nsIMessageManager.h"
#include "nsScriptSecurityManager.h" #include "nsScriptSecurityManager.h"
namespace mozilla { namespace mozilla {
using namespace ipc;
using namespace dom;
NS_IMPL_ISUPPORTS(DomainPolicy, nsIDomainPolicy) NS_IMPL_ISUPPORTS(DomainPolicy, nsIDomainPolicy)
DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet()) static nsresult
, mSuperBlacklist(new DomainSet()) BroadcastDomainSetChange(DomainSetType aSetType, DomainSetChangeType aChangeType,
, mWhitelist(new DomainSet()) nsIURI* aDomain = nullptr)
, mSuperWhitelist(new DomainSet()) {
{} MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default,
"DomainPolicy should only be exposed to the chrome process.");
nsTArray<ContentParent*> parents;
ContentParent::GetAll(parents);
if (!parents.Length()) {
return NS_OK;
}
OptionalURIParams uri;
SerializeURI(aDomain, uri);
for (uint32_t i = 0; i < parents.Length(); i++) {
unused << parents[i]->SendDomainSetChanged(aSetType, aChangeType, uri);
}
return NS_OK;
}
DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet(BLACKLIST))
, mSuperBlacklist(new DomainSet(SUPER_BLACKLIST))
, mWhitelist(new DomainSet(WHITELIST))
, mSuperWhitelist(new DomainSet(SUPER_WHITELIST))
{
if (XRE_GetProcessType() == GeckoProcessType_Default) {
BroadcastDomainSetChange(NO_TYPE, ACTIVATE_POLICY);
}
}
DomainPolicy::~DomainPolicy() DomainPolicy::~DomainPolicy()
{ {
@ -75,10 +108,47 @@ DomainPolicy::Deactivate()
mSuperWhitelist = nullptr; mSuperWhitelist = nullptr;
// Inform the SSM. // Inform the SSM.
nsScriptSecurityManager::GetScriptSecurityManager()->DeactivateDomainPolicy(); nsScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager();
if (ssm) {
ssm->DeactivateDomainPolicy();
}
if (XRE_GetProcessType() == GeckoProcessType_Default) {
BroadcastDomainSetChange(NO_TYPE, DEACTIVATE_POLICY);
}
return NS_OK; return NS_OK;
} }
void
DomainPolicy::CloneDomainPolicy(DomainPolicyClone* aClone)
{
aClone->active() = true;
static_cast<DomainSet*>(mBlacklist.get())->CloneSet(&aClone->blacklist());
static_cast<DomainSet*>(mSuperBlacklist.get())->CloneSet(&aClone->superBlacklist());
static_cast<DomainSet*>(mWhitelist.get())->CloneSet(&aClone->whitelist());
static_cast<DomainSet*>(mSuperWhitelist.get())->CloneSet(&aClone->superWhitelist());
}
static
void
CopyURIs(const InfallibleTArray<URIParams>& aDomains, nsIDomainSet* aSet)
{
for (uint32_t i = 0; i < aDomains.Length(); i++) {
nsCOMPtr<nsIURI> uri = DeserializeURI(aDomains[i]);
aSet->Add(uri);
}
}
void
DomainPolicy::ApplyClone(DomainPolicyClone* aClone)
{
nsCOMPtr<nsIDomainSet> list;
CopyURIs(aClone->blacklist(), mBlacklist);
CopyURIs(aClone->whitelist(), mWhitelist);
CopyURIs(aClone->superBlacklist(), mSuperBlacklist);
CopyURIs(aClone->superWhitelist(), mSuperWhitelist);
}
static already_AddRefed<nsIURI> static already_AddRefed<nsIURI>
GetCanonicalClone(nsIURI* aURI) GetCanonicalClone(nsIURI* aURI)
{ {
@ -100,6 +170,9 @@ DomainSet::Add(nsIURI* aDomain)
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.PutEntry(clone); mHashTable.PutEntry(clone);
if (XRE_GetProcessType() == GeckoProcessType_Default)
return BroadcastDomainSetChange(mType, ADD_DOMAIN, aDomain);
return NS_OK; return NS_OK;
} }
@ -109,6 +182,9 @@ DomainSet::Remove(nsIURI* aDomain)
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.RemoveEntry(clone); mHashTable.RemoveEntry(clone);
if (XRE_GetProcessType() == GeckoProcessType_Default)
return BroadcastDomainSetChange(mType, REMOVE_DOMAIN, aDomain);
return NS_OK; return NS_OK;
} }
@ -116,6 +192,9 @@ NS_IMETHODIMP
DomainSet::Clear() DomainSet::Clear()
{ {
mHashTable.Clear(); mHashTable.Clear();
if (XRE_GetProcessType() == GeckoProcessType_Default)
return BroadcastDomainSetChange(mType, CLEAR_DOMAINS);
return NS_OK; return NS_OK;
} }
@ -160,4 +239,31 @@ DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains)
} }
NS_IMETHODIMP
DomainSet::GetType(uint32_t* aType)
{
*aType = mType;
return NS_OK;
}
static
PLDHashOperator
DomainEnumerator(nsURIHashKey* aEntry, void* aUserArg)
{
InfallibleTArray<URIParams>* uris = static_cast<InfallibleTArray<URIParams>*>(aUserArg);
nsIURI* key = aEntry->GetKey();
URIParams uri;
SerializeURI(key, uri);
uris->AppendElement(uri);
return PL_DHASH_NEXT;
}
void
DomainSet::CloneSet(InfallibleTArray<URIParams>* aDomains)
{
mHashTable.EnumerateEntries(DomainEnumerator, aDomains);
}
} /* namespace mozilla */ } /* namespace mozilla */

View File

@ -13,6 +13,30 @@
namespace mozilla { namespace mozilla {
namespace dom {
class nsIContentParent;
};
namespace ipc {
class URIParams;
};
enum DomainSetChangeType{
ACTIVATE_POLICY,
DEACTIVATE_POLICY,
ADD_DOMAIN,
REMOVE_DOMAIN,
CLEAR_DOMAINS
};
enum DomainSetType{
NO_TYPE,
BLACKLIST,
SUPER_BLACKLIST,
WHITELIST,
SUPER_WHITELIST
};
class DomainPolicy : public nsIDomainPolicy class DomainPolicy : public nsIDomainPolicy
{ {
public: public:
@ -35,11 +59,16 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINSET NS_DECL_NSIDOMAINSET
DomainSet() {} explicit DomainSet(DomainSetType aType)
: mType(aType)
{}
void CloneSet(InfallibleTArray<mozilla::ipc::URIParams>* aDomains);
protected: protected:
virtual ~DomainSet() {} virtual ~DomainSet() {}
nsTHashtable<nsURIHashKey> mHashTable; nsTHashtable<nsURIHashKey> mHashTable;
DomainSetType mType;
}; };
} /* namespace mozilla */ } /* namespace mozilla */

View File

@ -8,6 +8,16 @@
interface nsIURI; interface nsIURI;
interface nsIDomainSet; interface nsIDomainSet;
%{ C++
namespace mozilla {
namespace dom {
class DomainPolicyClone;
}
}
%}
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
/* /*
* When a domain policy is instantiated by invoking activateDomainPolicy() on * When a domain policy is instantiated by invoking activateDomainPolicy() on
* nsIScriptSecurityManager, these domain sets are consulted when each new * nsIScriptSecurityManager, these domain sets are consulted when each new
@ -20,7 +30,7 @@ interface nsIDomainSet;
* When deactivate() is invoked, the domain sets are emptied, and the * When deactivate() is invoked, the domain sets are emptied, and the
* nsIDomainPolicy ceases to have any effect on the system. * nsIDomainPolicy ceases to have any effect on the system.
*/ */
[scriptable, builtinclass, uuid(27b10f54-f34b-42b7-8594-4348d3ad7953)] [scriptable, builtinclass, uuid(82b24a20-6701-4d40-a0f9-f5dc7321b555)]
interface nsIDomainPolicy : nsISupports interface nsIDomainPolicy : nsISupports
{ {
readonly attribute nsIDomainSet blacklist; readonly attribute nsIDomainSet blacklist;
@ -29,11 +39,19 @@ interface nsIDomainPolicy : nsISupports
readonly attribute nsIDomainSet superWhitelist; readonly attribute nsIDomainSet superWhitelist;
void deactivate(); void deactivate();
[noscript, notxpcom] void cloneDomainPolicy(in DomainPolicyClonePtr aClone);
[noscript, notxpcom] void applyClone(in DomainPolicyClonePtr aClone);
}; };
[scriptable, builtinclass, uuid(946a01ff-6525-4007-a2c2-447ebe1875d3)] [scriptable, builtinclass, uuid(665c981b-0a0f-4229-ac06-a826e02d4f69)]
interface nsIDomainSet : nsISupports interface nsIDomainSet : nsISupports
{ {
/*
* The type of the set. See: DomainSetType
*/
[noscript] readonly attribute uint32_t type;
/* /*
* Add a domain to the set. No-op if it already exists. * Add a domain to the set. No-op if it already exists.
*/ */

View File

@ -14,12 +14,19 @@ interface nsILoadContext;
%{ C++ %{ C++
#include "jspubtd.h" #include "jspubtd.h"
namespace mozilla {
namespace dom {
class DomainPolicyClone;
}
}
%} %}
[ptr] native JSContextPtr(JSContext); [ptr] native JSContextPtr(JSContext);
[ptr] native JSObjectPtr(JSObject); [ptr] native JSObjectPtr(JSObject);
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
[scriptable, uuid(f649959d-dae3-4027-83fd-5b7f8c8a8815)] [scriptable, uuid(ba602ca6-dc7a-457e-a57a-ee5b343fd863)]
interface nsIScriptSecurityManager : nsISupports interface nsIScriptSecurityManager : nsISupports
{ {
/** /**
@ -240,6 +247,22 @@ interface nsIScriptSecurityManager : nsISupports
nsIDomainPolicy activateDomainPolicy(); nsIDomainPolicy activateDomainPolicy();
readonly attribute boolean domainPolicyActive; readonly attribute boolean domainPolicyActive;
/**
* Only the parent process can directly access domain policies, child
* processes only have a read-only mirror to the one in the parent.
* For child processes the mirror is updated via messages
* and ContentChild will hold the DomainPolicy by calling
* ActivateDomainPolicyInternal directly. New consumer to this
* function should not be addded.
*/
[noscript] nsIDomainPolicy activateDomainPolicyInternal();
/**
* This function is for internal use only. Every time a child process is spawned, we
* must clone any active domain policies in the parent to the new child.
*/
[noscript, notxpcom] void cloneDomainPolicy(in DomainPolicyClonePtr aClone);
/** /**
* Query mechanism for the above policy. * Query mechanism for the above policy.
* *

View File

@ -1310,9 +1310,14 @@ static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan;
nsScriptSecurityManager::~nsScriptSecurityManager(void) nsScriptSecurityManager::~nsScriptSecurityManager(void)
{ {
Preferences::RemoveObservers(this, kObservedPrefs); Preferences::RemoveObservers(this, kObservedPrefs);
if (mDomainPolicy) if (mDomainPolicy) {
mDomainPolicy->Deactivate(); mDomainPolicy->Deactivate();
MOZ_ASSERT(!mDomainPolicy); }
// ContentChild might hold a reference to the domain policy,
// and it might release it only after the security manager is
// gone. But we can still assert this for the main process.
MOZ_ASSERT_IF(XRE_GetProcessType() == GeckoProcessType_Default,
!mDomainPolicy);
} }
void void
@ -1527,6 +1532,16 @@ nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
NS_IMETHODIMP NS_IMETHODIMP
nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv) nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv)
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
return ActivateDomainPolicyInternal(aRv);
}
NS_IMETHODIMP
nsScriptSecurityManager::ActivateDomainPolicyInternal(nsIDomainPolicy** aRv)
{ {
// We only allow one domain policy at a time. The holder of the previous // We only allow one domain policy at a time. The holder of the previous
// policy must explicitly deactivate it first. // policy must explicitly deactivate it first.
@ -1548,6 +1563,17 @@ nsScriptSecurityManager::DeactivateDomainPolicy()
mDomainPolicy = nullptr; mDomainPolicy = nullptr;
} }
void
nsScriptSecurityManager::CloneDomainPolicy(DomainPolicyClone* aClone)
{
MOZ_ASSERT(aClone);
if (mDomainPolicy) {
mDomainPolicy->CloneDomainPolicy(aClone);
} else {
aClone->active() = false;
}
}
NS_IMETHODIMP NS_IMETHODIMP
nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv) nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
{ {

View File

@ -28,6 +28,7 @@
#include "mozilla/docshell/OfflineCacheUpdateChild.h" #include "mozilla/docshell/OfflineCacheUpdateChild.h"
#include "mozilla/dom/ContentBridgeChild.h" #include "mozilla/dom/ContentBridgeChild.h"
#include "mozilla/dom/ContentBridgeParent.h" #include "mozilla/dom/ContentBridgeParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DOMStorageIPC.h" #include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/ExternalHelperAppChild.h" #include "mozilla/dom/ExternalHelperAppChild.h"
#include "mozilla/dom/PCrashReporterChild.h" #include "mozilla/dom/PCrashReporterChild.h"
@ -110,8 +111,9 @@
#include "mozilla/dom/PMemoryReportRequestChild.h" #include "mozilla/dom/PMemoryReportRequestChild.h"
#include "mozilla/dom/PCycleCollectWithLogsChild.h" #include "mozilla/dom/PCycleCollectWithLogsChild.h"
#ifdef MOZ_PERMISSIONS
#include "nsIScriptSecurityManager.h" #include "nsIScriptSecurityManager.h"
#ifdef MOZ_PERMISSIONS
#include "nsPermission.h" #include "nsPermission.h"
#include "nsPermissionManager.h" #include "nsPermissionManager.h"
#endif #endif
@ -168,6 +170,7 @@
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "nsDeviceStorage.h" #include "nsDeviceStorage.h"
#include "AudioChannelService.h" #include "AudioChannelService.h"
#include "DomainPolicy.h"
#include "mozilla/dom/DataStoreService.h" #include "mozilla/dom/DataStoreService.h"
#include "mozilla/dom/telephony/PTelephonyChild.h" #include "mozilla/dom/telephony/PTelephonyChild.h"
#include "mozilla/dom/time/DateCacheCleaner.h" #include "mozilla/dom/time/DateCacheCleaner.h"
@ -786,9 +789,21 @@ ContentChild::InitXPCOM()
bool isOffline; bool isOffline;
ClipboardCapabilities clipboardCaps; ClipboardCapabilities clipboardCaps;
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries, &clipboardCaps); DomainPolicyClone domainPolicy;
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries, &clipboardCaps, &domainPolicy);
RecvSetOffline(isOffline); RecvSetOffline(isOffline);
if (domainPolicy.active()) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
MOZ_ASSERT(ssm);
ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
if (!mPolicy) {
MOZ_CRASH("Failed to activate domain policy.");
}
mPolicy->ApplyClone(&domainPolicy);
}
nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1")); nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
if (nsCOMPtr<nsIClipboardProxy> clipboardProxy = do_QueryInterface(clipboard)) { if (nsCOMPtr<nsIClipboardProxy> clipboardProxy = do_QueryInterface(clipboard)) {
clipboardProxy->SetCapabilities(clipboardCaps); clipboardProxy->SetCapabilities(clipboardCaps);
@ -2595,9 +2610,83 @@ ContentChild::RecvAssociatePluginId(const uint32_t& aPluginId,
return true; return true;
} }
bool
ContentChild::RecvDomainSetChanged(const uint32_t& aSetType, const uint32_t& aChangeType,
const OptionalURIParams& aDomain)
{
if (aChangeType == ACTIVATE_POLICY) {
if (mPolicy) {
return true;
}
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
MOZ_ASSERT(ssm);
ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
return !!mPolicy;
} else if (!mPolicy) {
MOZ_ASSERT_UNREACHABLE("If the domain policy is not active yet,"
" the first message should be ACTIVATE_POLICY");
return false;
}
NS_ENSURE_TRUE(mPolicy, false);
if (aChangeType == DEACTIVATE_POLICY) {
mPolicy->Deactivate();
mPolicy = nullptr;
return true;
}
nsCOMPtr<nsIDomainSet> set;
switch(aSetType) {
case BLACKLIST:
mPolicy->GetBlacklist(getter_AddRefs(set));
break;
case SUPER_BLACKLIST:
mPolicy->GetSuperBlacklist(getter_AddRefs(set));
break;
case WHITELIST:
mPolicy->GetWhitelist(getter_AddRefs(set));
break;
case SUPER_WHITELIST:
mPolicy->GetSuperWhitelist(getter_AddRefs(set));
break;
default:
NS_NOTREACHED("Unexpected setType");
return false;
}
MOZ_ASSERT(set);
nsCOMPtr<nsIURI> uri = DeserializeURI(aDomain);
switch(aChangeType) {
case ADD_DOMAIN:
NS_ENSURE_TRUE(uri, false);
set->Add(uri);
break;
case REMOVE_DOMAIN:
NS_ENSURE_TRUE(uri, false);
set->Remove(uri);
break;
case CLEAR_DOMAINS:
set->Clear();
break;
default:
NS_NOTREACHED("Unexpected changeType");
return false;
}
return true;
}
bool bool
ContentChild::RecvShutdown() ContentChild::RecvShutdown()
{ {
if (mPolicy) {
mPolicy->Deactivate();
mPolicy = nullptr;
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService(); nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) { if (os) {
os->NotifyObservers(this, "content-child-shutdown", nullptr); os->NotifyObservers(this, "content-child-shutdown", nullptr);

View File

@ -24,6 +24,7 @@ class nsIDOMBlob;
class nsIObserver; class nsIObserver;
struct ResourceMapping; struct ResourceMapping;
struct OverrideMapping; struct OverrideMapping;
class nsIDomainPolicy;
namespace mozilla { namespace mozilla {
class RemoteSpellcheckEngineChild; class RemoteSpellcheckEngineChild;
@ -384,6 +385,8 @@ public:
nsTArray<nsCString>&& aThreadNameFilters) override; nsTArray<nsCString>&& aThreadNameFilters) override;
virtual bool RecvStopProfiler() override; virtual bool RecvStopProfiler() override;
virtual bool RecvGetProfile(nsCString* aProfile) override; virtual bool RecvGetProfile(nsCString* aProfile) override;
virtual bool RecvDomainSetChanged(const uint32_t& aSetType, const uint32_t& aChangeType,
const OptionalURIParams& aDomain) override;
virtual bool RecvShutdown() override; virtual bool RecvShutdown() override;
#ifdef ANDROID #ifdef ANDROID
@ -481,6 +484,8 @@ private:
static ContentChild* sSingleton; static ContentChild* sSingleton;
nsCOMPtr<nsIDomainPolicy> mPolicy;
DISALLOW_EVIL_CONSTRUCTORS(ContentChild); DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
}; };

View File

@ -2782,8 +2782,9 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
bool isOffline; bool isOffline;
InfallibleTArray<nsString> unusedDictionaries; InfallibleTArray<nsString> unusedDictionaries;
ClipboardCapabilities clipboardCaps; ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries, RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries,
&clipboardCaps); &clipboardCaps, &domainPolicy);
mozilla::unused << content->SendSetOffline(isOffline); mozilla::unused << content->SendSetOffline(isOffline);
MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() && MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() &&
!clipboardCaps.supportsFindClipboard(), !clipboardCaps.supportsFindClipboard(),
@ -3119,7 +3120,8 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
bool bool
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline, ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
InfallibleTArray<nsString>* dictionaries, InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps) ClipboardCapabilities* clipboardCaps,
DomainPolicyClone* domainPolicy)
{ {
nsCOMPtr<nsIIOService> io(do_GetIOService()); nsCOMPtr<nsIIOService> io(do_GetIOService());
MOZ_ASSERT(io, "No IO service?"); MOZ_ASSERT(io, "No IO service?");
@ -3140,6 +3142,11 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
rv = clipboard->SupportsFindClipboard(&clipboardCaps->supportsFindClipboard()); rv = clipboard->SupportsFindClipboard(&clipboardCaps->supportsFindClipboard());
MOZ_ASSERT(NS_SUCCEEDED(rv)); MOZ_ASSERT(NS_SUCCEEDED(rv));
// Let's copy the domain policy from the parent to the child (if it's active).
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ENSURE_TRUE(ssm, false);
ssm->CloneDomainPolicy(domainPolicy);
return true; return true;
} }

View File

@ -511,7 +511,8 @@ private:
bool* aIsForBrowser) override; bool* aIsForBrowser) override;
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline, virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
InfallibleTArray<nsString>* dictionaries, InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps) ClipboardCapabilities* clipboardCaps,
DomainPolicyClone* domainPolicy)
override; override;
virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) override; virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) override;

View File

@ -346,6 +346,15 @@ union OptionalContentId
void_t; void_t;
}; };
struct DomainPolicyClone
{
bool active;
URIParams[] blacklist;
URIParams[] whitelist;
URIParams[] superBlacklist;
URIParams[] superWhitelist;
};
prio(normal upto urgent) sync protocol PContent prio(normal upto urgent) sync protocol PContent
{ {
parent spawns PPluginModule; parent spawns PPluginModule;
@ -552,6 +561,8 @@ child:
NuwaFreeze(); NuwaFreeze();
async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, OptionalURIParams aDomain);
/** /**
* Notify the child to shutdown. The child will in turn call FinishShutdown * Notify the child to shutdown. The child will in turn call FinishShutdown
* and let the parent close the channel. * and let the parent close the channel.
@ -586,7 +597,8 @@ parent:
returns (ContentParentId cpId, bool isForApp, bool isForBrowser); returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
sync GetXPCOMProcessAttributes() sync GetXPCOMProcessAttributes()
returns (bool isOffline, nsString[] dictionaries, returns (bool isOffline, nsString[] dictionaries,
ClipboardCapabilities clipboardCaps); ClipboardCapabilities clipboardCaps,
DomainPolicyClone domainPolicy);
sync CreateChildProcess(IPCTabContext context, sync CreateChildProcess(IPCTabContext context,
ProcessPriority priority, ProcessPriority priority,

View File

@ -154,6 +154,7 @@ for var in ('MOZ_PERMISSIONS', 'MOZ_CHILD_PERMISSIONS'):
JAR_MANIFESTS += ['jar.mn'] JAR_MANIFESTS += ['jar.mn']
BROWSER_CHROME_MANIFESTS += ['tests/browser.ini']
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini'] MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] MOCHITEST_MANIFESTS += ['tests/mochitest.ini']

View File

@ -0,0 +1,6 @@
[DEFAULT]
support-files =
file_disableScript.html
file_domainPolicy_base.html
[browser_domainPolicy.js]

View File

@ -0,0 +1,240 @@
var policy; // To make sure we never leave up an activated domain policy after a failed test, let's make this global.
function activateDomainPolicy() {
const ssm = Services.scriptSecurityManager;
policy = ssm.activateDomainPolicy();
}
function deactivateDomainPolicy() {
if (policy) {
policy.deactivate();
policy = null;
}
}
function* test_domainPolicy() {
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
let deferred = Promise.defer();
let currentTask = deferred.promise;
SpecialPowers.pushPrefEnv(
{set: [["dom.ipc.browser_frames.oop_by_default", false],
["browser.pagethumbnails.capturing_disabled", false],
["dom.mozBrowserFramesEnabled", false]]},
() => { return deferred.resolve()});
yield currentTask;
// Create tab
let tab;
// Init test
function initProcess() {
tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
let initPromise = ContentTask.spawn(tab.linkedBrowser, null, function() {
Cu.import("resource://gre/modules/PromiseUtils.jsm");
function loadBase() {
let deferred = PromiseUtils.defer();
let listener = (event) => {
removeEventListener("DOMDocElementInserted", listener, true);
let listener2 = (event) => {
content.removeEventListener('load', listener2);
deferred.resolve();
}
content.addEventListener('load', listener2);
};
addEventListener("DOMDocElementInserted", listener, true);
return deferred.promise;
}
return loadBase();
});
tab.linkedBrowser.loadURI("http://mochi.test:8888/browser/dom/ipc/tests/file_domainPolicy_base.html");
return initPromise;
}
// We use ContentTask for the tests, but we also want to pass some data and some helper functions too.
// To do that, we serialize an input object via JSON |ipcArgs| and some shared helper functions |initUtils|
// and eval them in the content process.
var ipcArgs = {};
function initUtils(obj) {
obj.checkScriptEnabled = function(win, expectEnabled) {
win.wrappedJSObject.gFiredOnclick = false;
win.document.body.dispatchEvent(new win.Event('click'));
return { passed: win.wrappedJSObject.gFiredOnclick == expectEnabled,
msg: `Checking script-enabled for ${win.name} (${win.location})`};
}
obj.navigateFrame = function(ifr, src) {
let deferred = PromiseUtils.defer();
function onload() {
ifr.removeEventListener('load', onload);
deferred.resolve();
}
ifr.addEventListener('load', onload, false);
ifr.setAttribute('src', src);
return deferred.promise;
}
};
function runTest(test) {
return ContentTask.spawn(tab.linkedBrowser,
'ipcArgs = ' + JSON.stringify(ipcArgs) + '; (' + initUtils.toSource() + ')(utils)', test);
}
function checkAndCleanup(result) {
result = [].concat(result);
for (var i in result)
ok(result[i].passed, result[i].msg);
gBrowser.removeTab(tab);
deactivateDomainPolicy();
ipcArgs = {};
}
function testDomain(domain) {
ipcArgs.domain = domain;
return (aUtils) => {
Cu.import("resource://gre/modules/PromiseUtils.jsm");
var ipcArgs;
var utils = {};
eval(aUtils);
let path = '/browser/dom/ipc/tests/file_disableScript.html';
let deferred = PromiseUtils.defer();
var rootFrame = content.document.getElementById('root');
utils.navigateFrame(rootFrame, ipcArgs.domain + path).then(() => {
deferred.resolve(utils.checkScriptEnabled(rootFrame.contentWindow, false));
});
return deferred.promise;
}
}
info("Testing simple blacklist policy");
info("Creating child process first, activating domainPolicy after");
currentTask = initProcess();
yield currentTask;
activateDomainPolicy();
var bl = policy.blacklist;
bl.add(Services.io.newURI('http://example.com', null, null));
currentTask = runTest(testDomain("http://example.com"));
checkAndCleanup(yield currentTask);
info("Activating domainPolicy first, creating child process after");
activateDomainPolicy();
var bl = policy.blacklist;
bl.add(Services.io.newURI('http://example.com', null, null));
currentTask = initProcess();
yield currentTask;
currentTask = runTest(testDomain("http://example.com"));
checkAndCleanup(yield currentTask);
function testList(expectEnabled, list) {
ipcArgs.expectEnabled = expectEnabled;
ipcArgs.list = list;
return (aUtils) => {
Cu.import("resource://gre/modules/PromiseUtils.jsm");
var ipcArgs;
var utils = {};
eval(aUtils);
var results = [];
var testListInternal = function(expectEnabled, list, idx) {
idx = idx || 0;
let deferred = PromiseUtils.defer();
let path = '/browser/dom/ipc/tests/file_disableScript.html';
let target = list[idx] + path;
var rootFrame = content.document.getElementById('root');
utils.navigateFrame(rootFrame, target).then(function() {
results.push(utils.checkScriptEnabled(rootFrame.contentWindow, expectEnabled));
if (idx == list.length - 1)
deferred.resolve(results);
else
testListInternal(expectEnabled, list, idx + 1).then(function(retArg) { deferred.resolve(retArg); });
});
return deferred.promise;
}
return testListInternal(ipcArgs.expectEnabled, ipcArgs.list);
}
}
let testPolicy = {
exceptions: ['http://test1.example.com', 'http://example.com'],
superExceptions: ['http://test2.example.org', 'https://test1.example.com'],
exempt: ['http://test1.example.com', 'http://example.com',
'http://test2.example.org', 'http://sub1.test2.example.org',
'https://sub1.test1.example.com'],
notExempt: ['http://test2.example.com', 'http://sub1.test1.example.com',
'http://www.example.com', 'https://test2.example.com',
'https://example.com', 'http://test1.example.org'],
};
function activate(isBlack, exceptions, superExceptions) {
activateDomainPolicy();
let set = isBlack ? policy.blacklist : policy.whitelist;
let superSet = isBlack ? policy.superBlacklist : policy.superWhitelist;
for (var e of exceptions)
set.add(makeURI(e));
for (var e of superExceptions)
superSet.add(makeURI(e));
};
info("Testing Blacklist-style Domain Policy");
info("Activating domainPolicy first, creating child process after");
activate(true, testPolicy.exceptions, testPolicy.superExceptions);
currentTask = initProcess();
yield currentTask;
let results = [];
currentTask = runTest(testList(true, testPolicy.notExempt));
results = results.concat(yield currentTask);
currentTask = runTest(testList(false, testPolicy.exempt));
results = results.concat(yield currentTask);
checkAndCleanup(results);
info("Creating child process first, activating domainPolicy after");
currentTask = initProcess();
yield currentTask;
activate(true, testPolicy.exceptions, testPolicy.superExceptions);
results = [];
currentTask = runTest(testList(true, testPolicy.notExempt));
results = results.concat(yield currentTask);
currentTask = runTest(testList(false, testPolicy.exempt));
results = results.concat(yield currentTask);
checkAndCleanup(results);
info("Testing Whitelist-style Domain Policy");
deferred = Promise.defer();
currentTask = deferred.promise;
SpecialPowers.pushPrefEnv({set:[["javascript.enabled", false]]}, () => { return deferred.resolve()});
yield currentTask;
info("Activating domainPolicy first, creating child process after");
activate(false, testPolicy.exceptions, testPolicy.superExceptions);
currentTask = initProcess();
yield currentTask;
results = [];
currentTask = runTest(testList(false, testPolicy.notExempt));
results = results.concat(yield currentTask);
currentTask = runTest(testList(true, testPolicy.exempt));
results = results.concat(yield currentTask);
checkAndCleanup(results);
info("Creating child process first, activating domainPolicy after");
currentTask = initProcess();
yield currentTask;
activate(false, testPolicy.exceptions, testPolicy.superExceptions);
results = [];
currentTask = runTest(testList(false, testPolicy.notExempt));
results = results.concat(yield currentTask);
currentTask = runTest(testList(true, testPolicy.exempt));
results = results.concat(yield currentTask);
checkAndCleanup(results);
finish();
}
add_task(test_domainPolicy);
registerCleanupFunction(()=>{
deactivateDomainPolicy();
})

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<script>
var gFiredOnload = false;
var gFiredOnclick = false;
</script>
</head>
<body onload="gFiredOnload = true;" onclick="gFiredOnclick = true;">
</body>
</html>

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<iframe id="root" name="root"/>
</body>
</html>