Bug 1173523 - Part 1: Expose an nsIPrincipal from nsIPermission rather than a host string, appId, and isInBrowserElement, r=ehsan

This commit is contained in:
Michael Layzell 2015-06-10 12:48:22 -04:00 committed by Ehsan Akhgari
parent 25dfda5b20
commit 56a5f8273e
9 changed files with 241 additions and 135 deletions

View File

@ -53,6 +53,7 @@
#include "mozilla/plugins/PluginModuleParent.h"
#include "mozilla/widget/WidgetMessageUtils.h"
#include "mozilla/media/MediaChild.h"
#include "mozilla/BasePrincipal.h"
#if defined(MOZ_CONTENT_SANDBOX)
#if defined(XP_WIN)
@ -2112,19 +2113,16 @@ ContentChild::RecvAddPermission(const IPC::Permission& permission)
MOZ_ASSERT(permissionManager,
"We have no permissionManager in the Content process !");
nsAutoCString originNoSuffix;
OriginAttributes attrs;
attrs.PopulateFromOrigin(permission.origin, originNoSuffix);
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + nsCString(permission.host));
NS_ENSURE_TRUE(uri, true);
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
MOZ_ASSERT(secMan);
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = secMan->GetAppCodebasePrincipal(uri, permission.appId,
permission.isInBrowserElement,
getter_AddRefs(principal));
nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
NS_ENSURE_SUCCESS(rv, true);
nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
// child processes don't care about modification time.
int64_t modificationTime = 0;

View File

@ -2559,12 +2559,12 @@ ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissio
enumerator->GetNext(getter_AddRefs(supp));
nsCOMPtr<nsIPermission> perm = do_QueryInterface(supp);
nsCString host;
perm->GetHost(host);
uint32_t appId;
perm->GetAppId(&appId);
bool isInBrowserElement;
perm->GetIsInBrowserElement(&isInBrowserElement);
nsCOMPtr<nsIPrincipal> principal;
perm->GetPrincipal(getter_AddRefs(principal));
nsCString origin;
if (principal) {
principal->GetOrigin(origin);
}
nsCString type;
perm->GetType(type);
uint32_t capability;
@ -2574,8 +2574,7 @@ ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissio
int64_t expireTime;
perm->GetExpireTime(&expireTime);
aPermissions->AppendElement(IPC::Permission(host, appId,
isInBrowserElement, type,
aPermissions->AppendElement(IPC::Permission(origin, type,
capability, expireType,
expireTime));
}

View File

@ -196,8 +196,20 @@ DOMStorageObserver::Observe(nsISupports* aSubject,
return NS_OK;
}
nsCOMPtr<nsIPrincipal> principal;
perm->GetPrincipal(getter_AddRefs(principal));
if (!principal) {
return NS_OK;
}
nsCOMPtr<nsIURI> origin;
principal->GetURI(getter_AddRefs(origin));
if (!origin) {
return NS_OK;
}
nsAutoCString host;
perm->GetHost(host);
origin->GetHost(host);
if (host.IsEmpty()) {
return NS_OK;
}

View File

@ -4,48 +4,33 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsPermission.h"
#include "nsContentUtils.h"
#include "nsIClassInfoImpl.h"
#include "nsIEffectiveTLDService.h"
// nsPermission Implementation
NS_IMPL_CLASSINFO(nsPermission, nullptr, 0, {0})
NS_IMPL_ISUPPORTS_CI(nsPermission, nsIPermission)
nsPermission::nsPermission(const nsACString &aHost,
uint32_t aAppId,
bool aIsInBrowserElement,
nsPermission::nsPermission(nsIPrincipal* aPrincipal,
const nsACString &aType,
uint32_t aCapability,
uint32_t aExpireType,
int64_t aExpireTime)
: mHost(aHost)
: mPrincipal(aPrincipal)
, mType(aType)
, mCapability(aCapability)
, mExpireType(aExpireType)
, mExpireTime(aExpireTime)
, mAppId(aAppId)
, mIsInBrowserElement(aIsInBrowserElement)
{
}
NS_IMETHODIMP
nsPermission::GetHost(nsACString &aHost)
nsPermission::GetPrincipal(nsIPrincipal** aPrincipal)
{
aHost = mHost;
return NS_OK;
}
NS_IMETHODIMP
nsPermission::GetAppId(uint32_t* aAppId)
{
*aAppId = mAppId;
return NS_OK;
}
NS_IMETHODIMP
nsPermission::GetIsInBrowserElement(bool* aIsInBrowserElement)
{
*aIsInBrowserElement = mIsInBrowserElement;
nsCOMPtr<nsIPrincipal> copy = mPrincipal;
copy.forget(aPrincipal);
return NS_OK;
}
@ -76,3 +61,97 @@ nsPermission::GetExpireTime(int64_t *aExpireTime)
*aExpireTime = mExpireTime;
return NS_OK;
}
NS_IMETHODIMP
nsPermission::Matches(nsIPrincipal* aPrincipal, bool aExactHost, bool* aMatches)
{
NS_ENSURE_ARG_POINTER(aPrincipal);
NS_ENSURE_ARG_POINTER(aMatches);
*aMatches = false;
// If the principals are equal, then they match.
if (mPrincipal->Equals(aPrincipal)) {
*aMatches = true;
return NS_OK;
}
// Make sure that the OriginAttributes of the two entries are the same
nsAutoCString theirSuffix;
nsresult rv = aPrincipal->GetOriginSuffix(theirSuffix);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString ourSuffix;
rv = mPrincipal->GetOriginSuffix(ourSuffix);
NS_ENSURE_SUCCESS(rv, rv);
if (theirSuffix != ourSuffix) {
return NS_OK;
}
// Right now, we only care about the hosts
nsCOMPtr<nsIURI> theirURI;
rv = aPrincipal->GetURI(getter_AddRefs(theirURI));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> ourURI;
rv = mPrincipal->GetURI(getter_AddRefs(ourURI));
NS_ENSURE_SUCCESS(rv, rv);
// Get the hosts so we can compare them
nsAutoCString theirHost;
rv = theirURI->GetHost(theirHost);
if (NS_FAILED(rv) || theirHost.IsEmpty()) {
return NS_OK;
}
nsAutoCString ourHost;
rv = ourURI->GetHost(ourHost);
if (NS_FAILED(rv) || ourHost.IsEmpty()) {
return NS_OK;
}
if (aExactHost) { // If we only care about the exact host, we compare them and are done
*aMatches = theirHost == ourHost;
return NS_OK;
}
nsCOMPtr<nsIEffectiveTLDService> tldService =
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
if (!tldService) {
NS_ERROR("Should have a tld service!");
return NS_ERROR_FAILURE;
}
// Check if the host or any subdomain of the host matches. This loop will
// not loop forever, as GetNextSubDomain will eventually fail with
// NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS.
while (theirHost != ourHost) {
rv = tldService->GetNextSubDomain(theirHost, theirHost);
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
return NS_OK;
} else {
return rv;
}
}
}
*aMatches = true;
return NS_OK;
}
NS_IMETHODIMP
nsPermission::MatchesURI(nsIURI* aURI, bool aExactHost, bool* aMatches)
{
NS_ENSURE_ARG_POINTER(aURI);
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = secMan->GetNoAppCodebasePrincipal(aURI, getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
return Matches(principal, aExactHost, aMatches);
}

View File

@ -18,9 +18,7 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPERMISSION
nsPermission(const nsACString &aHost,
uint32_t aAppId,
bool aIsInBrowserElement,
nsPermission(nsIPrincipal* aPrincipal,
const nsACString &aType,
uint32_t aCapability,
uint32_t aExpireType,
@ -29,13 +27,11 @@ public:
protected:
virtual ~nsPermission() {};
nsCString mHost;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCString mType;
uint32_t mCapability;
uint32_t mExpireType;
int64_t mExpireTime;
uint32_t mAppId;
bool mIsInBrowserElement;
};
#endif // nsPermission_h__

View File

@ -8,6 +8,7 @@
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/unused.h"
#include "nsPermissionManager.h"
#include "nsPermission.h"
@ -741,6 +742,15 @@ nsPermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal,
return NS_OK;
}
// Null principals can't meaningfully have persisted permissions attached to
// them, so we don't allow adding permissions for them.
bool isNullPrincipal;
nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
if (isNullPrincipal) {
return NS_OK;
}
// Permissions may not be added to expanded principals.
if (IsExpandedPrincipal(aPrincipal)) {
return NS_ERROR_INVALID_ARG;
@ -770,16 +780,12 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
NS_ENSURE_SUCCESS(rv, rv);
if (!IsChildProcess()) {
uint32_t appId;
rv = aPrincipal->GetAppId(&appId);
nsAutoCString origin;
rv = aPrincipal->GetOrigin(origin);
NS_ENSURE_SUCCESS(rv, rv);
bool isInBrowserElement;
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
NS_ENSURE_SUCCESS(rv, rv);
IPC::Permission permission(host, appId, isInBrowserElement, aType,
aPermission, aExpireType, aExpireTime);
IPC::Permission permission(origin, aType, aPermission,
aExpireType, aExpireTime);
nsTArray<ContentParent*> cplist;
ContentParent::GetAll(cplist);
@ -1098,12 +1104,8 @@ nsPermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal,
NS_IMETHODIMP
nsPermissionManager::RemovePermission(nsIPermission* aPerm)
{
nsAutoCString host;
nsresult rv = aPerm->GetHost(host);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> principal;
rv = GetPrincipal(host, getter_AddRefs(principal));
nsresult rv = aPerm->GetPrincipal(getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString type;
@ -1301,9 +1303,14 @@ nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal,
}
PermissionEntry& perm = entry->GetPermissions()[idx];
nsCOMPtr<nsIPermission> r = new nsPermission(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
nsCOMPtr<nsIPrincipal> principal;
rv = GetPrincipal(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPermission> r = new nsPermission(principal,
mTypeArray.ElementAt(perm.mType),
perm.mPermission,
perm.mExpireType,
@ -1444,6 +1451,7 @@ nsPermissionManager::GetPermissionHashKey(const nsACString& aHost,
return GetPermissionHashKey(NS_LITERAL_CSTRING("<file>"), aAppId, aIsInBrowserElement, aType, true);
}
// If aExactHostMatch wasn't true, we can check if the base domain has a permission entry.
if (!aExactHostMatch) {
nsCString domain = GetNextSubDomainForHost(aHost);
if (!domain.IsEmpty()) {
@ -1485,9 +1493,13 @@ AddPermissionsToList(nsPermissionManager::PermissionHashKey* entry, void *arg)
continue;
}
nsPermission *perm = new nsPermission(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
nsCOMPtr<nsIPrincipal> principal;
GetPrincipal(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
getter_AddRefs(principal));
nsPermission *perm = new nsPermission(principal,
data->types->ElementAt(permEntry.mType),
permEntry.mPermission,
permEntry.mExpireType,
@ -1542,9 +1554,13 @@ AddPermissionsModifiedSinceToList(
continue;
}
nsPermission* perm = new nsPermission(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
nsCOMPtr<nsIPrincipal> principal;
GetPrincipal(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
getter_AddRefs(principal));
nsPermission* perm = new nsPermission(principal,
data->types->ElementAt(permEntry.mType),
permEntry.mPermission,
permEntry.mExpireType,
@ -1567,22 +1583,21 @@ nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime)
mPermissionTable.EnumerateEntries(AddPermissionsModifiedSinceToList, &data);
for (int32_t i = 0; i<array.Count(); ++i) {
nsAutoCString host;
bool isInBrowserElement = false;
nsAutoCString type;
uint32_t appId = 0;
array[i]->GetHost(host);
array[i]->GetIsInBrowserElement(&isInBrowserElement);
array[i]->GetType(type);
array[i]->GetAppId(&appId);
nsCOMPtr<nsIPrincipal> principal;
if (NS_FAILED(GetPrincipal(host, appId, isInBrowserElement,
getter_AddRefs(principal)))) {
nsAutoCString type;
nsresult rv = array[i]->GetPrincipal(getter_AddRefs(principal));
if (NS_FAILED(rv)) {
NS_ERROR("GetPrincipal() failed!");
continue;
}
rv = array[i]->GetType(type);
if (NS_FAILED(rv)) {
NS_ERROR("GetType() failed!");
continue;
}
// AddInternal handles removal, so let it do the work...
AddInternal(
principal,
@ -1612,9 +1627,13 @@ nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey
continue;
}
data->permissions.AppendObject(new nsPermission(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
nsCOMPtr<nsIPrincipal> principal;
GetPrincipal(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
getter_AddRefs(principal));
data->permissions.AppendObject(new nsPermission(principal,
gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
permEntry.mPermission,
permEntry.mExpireType,
@ -1658,21 +1677,12 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
mPermissionTable.EnumerateEntries(GetPermissionsForApp, &data);
for (int32_t i=0; i<data.permissions.Count(); ++i) {
nsAutoCString host;
bool isInBrowserElement;
nsCOMPtr<nsIPrincipal> principal;
nsAutoCString type;
data.permissions[i]->GetHost(host);
data.permissions[i]->GetIsInBrowserElement(&isInBrowserElement);
data.permissions[i]->GetPrincipal(getter_AddRefs(principal));
data.permissions[i]->GetType(type);
nsCOMPtr<nsIPrincipal> principal;
if (NS_FAILED(GetPrincipal(host, aAppId, isInBrowserElement,
getter_AddRefs(principal)))) {
NS_ERROR("GetPrincipal() failed!");
continue;
}
AddInternal(principal,
type,
nsIPermissionManager::UNKNOWN_ACTION,
@ -1799,8 +1809,11 @@ nsPermissionManager::NotifyObserversWithPermission(const nsACString &aHost,
int64_t aExpireTime,
const char16_t *aData)
{
nsCOMPtr<nsIPrincipal> principal;
GetPrincipal(aHost, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
nsCOMPtr<nsIPermission> permission =
new nsPermission(aHost, aAppId, aIsInBrowserElement, aType, aPermission,
new nsPermission(principal, aType, aPermission,
aExpireType, aExpireTime);
if (permission)
NotifyObservers(permission, aData);
@ -2293,11 +2306,16 @@ nsPermissionManager::FetchPermissions() {
for (uint32_t i = 0; i < perms.Length(); i++) {
const IPC::Permission &perm = perms[i];
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = GetPrincipal(perm.host, perm.appId,
perm.isInBrowserElement, getter_AddRefs(principal));
nsAutoCString originNoSuffix;
mozilla::OriginAttributes attrs;
attrs.PopulateFromOrigin(perm.origin, originNoSuffix);
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
// The child process doesn't care about modification times - it neither
// reads nor writes, nor removes them based on the date - so 0 (which
// will end up as now()) is fine.

View File

@ -45,4 +45,4 @@ function run_test() {
do_check_eq(pm.testPermissionFromPrincipal(principal, "test/local-files"), pm.ALLOW_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), pm.ALLOW_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(fileInDirPrincipal, "test/local-files"), pm.ALLOW_ACTION);
}
}

View File

@ -6,7 +6,10 @@
#include "nsISupports.idl"
[scriptable, uuid(cfb08e46-193c-4be7-a467-d7775fb2a31e)]
interface nsIPrincipal;
interface nsIURI;
[scriptable, uuid(bb409a51-2371-4fea-9dc9-b7286a458b8c)]
/**
* This interface defines a "permission" object,
* used to specify allowed/blocked objects from
@ -16,19 +19,9 @@
interface nsIPermission : nsISupports
{
/**
* The name of the host for which the permission is set
* The principal for which this permission applies.
*/
readonly attribute AUTF8String host;
/**
* The id of the app for which the permission is set.
*/
readonly attribute unsigned long appId;
/**
* Whether the permission has been set to a page inside a browser element.
*/
readonly attribute boolean isInBrowserElement;
readonly attribute nsIPrincipal principal;
/**
* a case-sensitive ASCII string, indicating the type of permission
@ -56,4 +49,29 @@ interface nsIPermission : nsISupports
* 0:00:00).
*/
readonly attribute int64_t expireTime;
/**
* Test whether a principal would be affected by this permission.
*
* @param principal the principal to test
* @param exactHost If true, only the specific host will be matched,
* @see nsIPermissionManager::testExactPermission.
* If false, subdomains will also be searched,
* @see nsIPermissionManager::testPermission.
*/
boolean matches(in nsIPrincipal principal,
in boolean exactHost);
/**
* Test whether a URI would be affected by this permission.
* This performs a matches with a NO_APP_ID identifier.
*
* @param uri the uri to test
* @param exactHost If true, only the specific host will be matched,
* @see nsIPermissionManager::testExactPermission.
* If false, subdomains will also be searched,
* @see nsIPermissionManager::testPermission.
*/
boolean matchesURI(in nsIURI uri,
in boolean exactHost);
};

View File

@ -20,26 +20,20 @@ namespace IPC {
struct Permission
{
nsCString host, type;
nsCString origin, type;
uint32_t capability, expireType;
int64_t expireTime;
uint32_t appId;
bool isInBrowserElement;
Permission() { }
Permission(const nsCString& aHost,
const uint32_t aAppId,
const bool aIsInBrowserElement,
Permission(const nsCString& aOrigin,
const nsCString& aType,
const uint32_t aCapability,
const uint32_t aExpireType,
const int64_t aExpireTime) : host(aHost),
const int64_t aExpireTime) : origin(aOrigin),
type(aType),
capability(aCapability),
expireType(aExpireType),
expireTime(aExpireTime),
appId(aAppId),
isInBrowserElement(aIsInBrowserElement)
expireTime(aExpireTime)
{}
};
@ -48,34 +42,26 @@ struct ParamTraits<Permission>
{
static void Write(Message* aMsg, const Permission& aParam)
{
WriteParam(aMsg, aParam.host);
WriteParam(aMsg, aParam.origin);
WriteParam(aMsg, aParam.type);
WriteParam(aMsg, aParam.capability);
WriteParam(aMsg, aParam.expireType);
WriteParam(aMsg, aParam.expireTime);
WriteParam(aMsg, aParam.appId);
WriteParam(aMsg, aParam.isInBrowserElement);
}
static bool Read(const Message* aMsg, void** aIter, Permission* aResult)
{
return ReadParam(aMsg, aIter, &aResult->host) &&
return ReadParam(aMsg, aIter, &aResult->origin) &&
ReadParam(aMsg, aIter, &aResult->type) &&
ReadParam(aMsg, aIter, &aResult->capability) &&
ReadParam(aMsg, aIter, &aResult->expireType) &&
ReadParam(aMsg, aIter, &aResult->expireTime) &&
ReadParam(aMsg, aIter, &aResult->appId) &&
ReadParam(aMsg, aIter, &aResult->isInBrowserElement);
ReadParam(aMsg, aIter, &aResult->expireTime);
}
static void Log(const Permission& p, std::wstring* l)
{
l->append(L"(");
LogParam(p.host, l);
l->append(L", ");
LogParam(p.appId, l);
l->append(L", ");
LogParam(p.isInBrowserElement, l);
LogParam(p.origin, l);
l->append(L", ");
LogParam(p.capability, l);
l->append(L", ");