Skip to content

Commit

Permalink
Bug 840488 - New domain policy API. r=bz
Browse files Browse the repository at this point in the history
Note that this patch changes the semantics of javascript.enabled so that changes
to the pref do not apply to compartments that have already been created. This is
a significant change, but is necessary to support the new domain policy API.
After one cycle or so, we'll rip out the old API.
  • Loading branch information
bholley committed Nov 13, 2013
1 parent d4fcf53 commit 71d1e88
Show file tree
Hide file tree
Showing 10 changed files with 412 additions and 7 deletions.
1 change: 1 addition & 0 deletions caps/idl/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

XPIDL_SOURCES += [
'nsIDomainPolicy.idl',
'nsIPrincipal.idl',
'nsIScriptSecurityManager.idl',
'nsISecurityCheckedComponent.idl',
Expand Down
62 changes: 62 additions & 0 deletions caps/idl/nsIDomainPolicy.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsISupports.idl"

interface nsIURI;
interface nsIDomainSet;

/*
* When a domain policy is instantiated by invoking activateDomainPolicy() on
* nsIScriptSecurityManager, these domain sets are consulted when each new
* global is created (they have no effect on already-created globals).
* If javascript is globally enabled with |javascript.enabled|, the blacklists
* are consulted. If globally disabled, the whitelists are consulted. Lookups
* on blacklist and whitelist happen with contains(), and lookups on
* superBlacklist and superWhitelist happen with containsSuperDomain().
*
* When deactivate() is invoked, the domain sets are emptied, and the
* nsIDomainPolicy ceases to have any effect on the system.
*/
[scriptable, builtinclass, uuid(27b10f54-f34b-42b7-8594-4348d3ad7953)]
interface nsIDomainPolicy : nsISupports
{
readonly attribute nsIDomainSet blacklist;
readonly attribute nsIDomainSet superBlacklist;
readonly attribute nsIDomainSet whitelist;
readonly attribute nsIDomainSet superWhitelist;

void deactivate();
};

[scriptable, builtinclass, uuid(946a01ff-6525-4007-a2c2-447ebe1875d3)]
interface nsIDomainSet : nsISupports
{
/*
* Add a domain to the set. No-op if it already exists.
*/
void add(in nsIURI aDomain);

/*
* Remove a domain from the set. No-op if it doesn't exist.
*/
void remove(in nsIURI aDomain);

/*
* Remove all entries from the set.
*/
void clear();

/*
* Returns true if a given domain is in the set.
*/
bool contains(in nsIURI aDomain);

/*
* Returns true if a given domain is a subdomain of one of the entries in
* the set.
*/
bool containsSuperDomain(in nsIURI aDomain);
};
26 changes: 25 additions & 1 deletion caps/idl/nsIScriptSecurityManager.idl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
interface nsIURI;
interface nsIChannel;
interface nsIDocShell;
interface nsIDomainPolicy;

[scriptable, uuid(36619e6e-6ed3-4fd5-9a16-763f3614e5ed)]
[scriptable, uuid(2911ae60-1b5f-47e6-941e-1bb7b53a167d)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager
{
///////////////// Security Checks //////////////////
Expand Down Expand Up @@ -228,6 +229,29 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
* inMozBrowser has to be true if the app is inside a mozbrowser iframe.
*/
AUTF8String getJarPrefix(in unsigned long appId, in boolean inMozBrowser);

/**
* Per-domain controls to enable and disable script. This system is designed
* to be used by at most one consumer, and enforces this with its semantics.
*
* Initially, domainPolicyActive is false. When activateDomainPolicy() is
* invoked, domainPolicyActive becomes true, and subsequent calls to
* activateDomainPolicy() will fail until deactivate() is invoked on the
* nsIDomainPolicy returned from activateDomainPolicy(). At this point,
* domainPolicyActive becomes false again, and a new consumer may acquire
* control of the system by invoking activateDomainPolicy().
*/
nsIDomainPolicy activateDomainPolicy();
readonly attribute boolean domainPolicyActive;

/**
* Query mechanism for the above policy.
*
* If domainPolicyEnabled is false, this simply returns the current value
* of javascript.enabled. Otherwise, it returns the same value, but taking
* the various blacklist/whitelist exceptions into account.
*/
bool policyAllowsScript(in nsIURI aDomain);
};

%{C++
Expand Down
52 changes: 52 additions & 0 deletions caps/include/DomainPolicy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* 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 DomainPolicy_h__
#define DomainPolicy_h__

#include "nsIDomainPolicy.h"
#include "nsTHashtable.h"
#include "nsURIHashKey.h"

namespace mozilla {

// The name "DomainPolicy" conflicts with some of the old-style policy machinery
// in nsScriptSecurityManager.cpp, which needs to #include this file. So we
// temporarily use a sub-namespace until that machinery goes away in bug 913734.
namespace hotness {

class DomainPolicy : public nsIDomainPolicy
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINPOLICY
DomainPolicy();
virtual ~DomainPolicy();

private:
nsCOMPtr<nsIDomainSet> mBlacklist;
nsCOMPtr<nsIDomainSet> mSuperBlacklist;
nsCOMPtr<nsIDomainSet> mWhitelist;
nsCOMPtr<nsIDomainSet> mSuperWhitelist;
};

class DomainSet : public nsIDomainSet
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINSET

DomainSet() {}
virtual ~DomainSet() {}

protected:
nsTHashtable<nsURIHashKey> mHashTable;
};

} /* namespace hotness */
} /* namespace mozilla */

#endif /* DomainPolicy_h__ */
6 changes: 6 additions & 0 deletions caps/include/nsScriptSecurityManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ class nsScriptSecurityManager : public nsIScriptSecurityManager,
AppAttributesEqual(nsIPrincipal* aFirst,
nsIPrincipal* aSecond);

void DeactivateDomainPolicy();

private:

// GetScriptSecurityManager is the only call that can make one
Expand Down Expand Up @@ -487,6 +489,10 @@ class nsScriptSecurityManager : public nsIScriptSecurityManager,
bool mIsJavaScriptEnabled;
bool mPolicyPrefsChanged;

// This machinery controls new-style domain policies. The old-style
// policy machinery will be removed soon.
nsCOMPtr<nsIDomainPolicy> mDomainPolicy;

static bool sStrictFileOriginPolicy;

static nsIIOService *sIOService;
Expand Down
165 changes: 165 additions & 0 deletions caps/src/DomainPolicy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=4 et sw=4 tw=80: */
/* 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 "DomainPolicy.h"
#include "nsScriptSecurityManager.h"

namespace mozilla {
namespace hotness {

NS_IMPL_ISUPPORTS1(DomainPolicy, nsIDomainPolicy)

DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet())
, mSuperBlacklist(new DomainSet())
, mWhitelist(new DomainSet())
, mSuperWhitelist(new DomainSet())
{}

DomainPolicy::~DomainPolicy()
{
// The SSM holds a strong ref to the DomainPolicy until Deactivate() is
// invoked, so we should never hit the destructor until that happens.
MOZ_ASSERT(!mBlacklist && !mSuperBlacklist &&
!mWhitelist && !mSuperWhitelist);
}


NS_IMETHODIMP
DomainPolicy::GetBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mBlacklist;
set.forget(aSet);
return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::GetSuperBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperBlacklist;
set.forget(aSet);
return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::GetWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mWhitelist;
set.forget(aSet);
return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::GetSuperWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperWhitelist;
set.forget(aSet);
return NS_OK;
}

NS_IMETHODIMP
DomainPolicy::Deactivate()
{
// Clear the hashtables first to free up memory, since script might
// hold the doomed sets alive indefinitely.
mBlacklist->Clear();
mSuperBlacklist->Clear();
mWhitelist->Clear();
mSuperWhitelist->Clear();

// Null them out.
mBlacklist = nullptr;
mSuperBlacklist = nullptr;
mWhitelist = nullptr;
mSuperWhitelist = nullptr;

// Inform the SSM.
nsScriptSecurityManager::GetScriptSecurityManager()->DeactivateDomainPolicy();
return NS_OK;
}

static already_AddRefed<nsIURI>
GetCanonicalClone(nsIURI* aURI)
{
nsCOMPtr<nsIURI> clone;
nsresult rv = aURI->Clone(getter_AddRefs(clone));
NS_ENSURE_SUCCESS(rv, nullptr);
rv = clone->SetUserPass(EmptyCString());
NS_ENSURE_SUCCESS(rv, nullptr);
rv = clone->SetPath(EmptyCString());
NS_ENSURE_SUCCESS(rv, nullptr);
return clone.forget();
}

NS_IMPL_ISUPPORTS1(DomainSet, nsIDomainSet)

NS_IMETHODIMP
DomainSet::Add(nsIURI* aDomain)
{
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.PutEntry(clone);
return NS_OK;
}

NS_IMETHODIMP
DomainSet::Remove(nsIURI* aDomain)
{
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.RemoveEntry(clone);
return NS_OK;
}

NS_IMETHODIMP
DomainSet::Clear()
{
mHashTable.Clear();
return NS_OK;
}

NS_IMETHODIMP
DomainSet::Contains(nsIURI* aDomain, bool* aContains)
{
*aContains = false;
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
*aContains = mHashTable.Contains(clone);
return NS_OK;
}

NS_IMETHODIMP
DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains)
{
*aContains = false;
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
nsAutoCString domain;
nsresult rv = clone->GetHost(domain);
NS_ENSURE_SUCCESS(rv, rv);
while (true) {
// Check the current domain.
if (mHashTable.Contains(clone)) {
*aContains = true;
return NS_OK;
}

// Chop off everything before the first dot, or break if there are no
// dots left.
int32_t index = domain.Find(".");
if (index == kNotFound)
break;
domain.Assign(Substring(domain, index + 1));
rv = clone->SetHost(domain);
NS_ENSURE_SUCCESS(rv, rv);
}

// No match.
return NS_OK;

}

} /* namespace hotness */
} /* namespace mozilla */
1 change: 1 addition & 0 deletions caps/src/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
MODULE = 'caps'

SOURCES += [
'DomainPolicy.cpp',
'nsJSPrincipals.cpp',
'nsNullPrincipal.cpp',
'nsNullPrincipalURI.cpp',
Expand Down
Loading

0 comments on commit 71d1e88

Please sign in to comment.