Bug 1180088 - Use origin-based permission check on parent side for signed packaged web app. r=kanru.

This commit is contained in:
Henry 2015-10-22 05:44:00 +02:00
parent 2f629074a5
commit e8a186056f
11 changed files with 119 additions and 19 deletions

View File

@ -97,6 +97,8 @@
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/WebBrowserPersistLocalDocument.h"
#include "nsPrincipal.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#endif
@ -278,13 +280,20 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
}
NS_IMETHODIMP
nsFrameLoader::SwitchProcessAndLoadURI(nsIURI* aURI)
nsFrameLoader::SwitchProcessAndLoadURI(nsIURI* aURI, const nsACString& aPackageId)
{
nsCOMPtr<nsIURI> URIToLoad = aURI;
RefPtr<TabParent> tp = nullptr;
nsCString signedPkgOrigin;
if (!aPackageId.IsEmpty()) {
// Only when aPackageId is not empty would signed package origin
// be meaningful.
nsPrincipal::GetOriginForURI(aURI, signedPkgOrigin);
}
MutableTabContext context;
nsresult rv = GetNewTabContext(&context);
nsresult rv = GetNewTabContext(&context, signedPkgOrigin, aPackageId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Element> ownerElement = mOwnerContent;
@ -3031,7 +3040,9 @@ nsFrameLoader::MaybeUpdatePrimaryTabParent(TabParentChange aChange)
}
nsresult
nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext)
nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
const nsACString& aSignedPkgOriginNoSuffix,
const nsACString& aPackageId)
{
nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
@ -3051,7 +3062,11 @@ nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext)
}
attrs.mAppId = appId;
bool tabContextUpdated = aTabContext->SetTabContext(ownApp, containingApp, attrs);
// Populate packageId to signedPkg.
attrs.mSignedPkg = NS_ConvertUTF8toUTF16(aPackageId);
bool tabContextUpdated = aTabContext->SetTabContext(ownApp, containingApp,
attrs, aSignedPkgOriginNoSuffix);
NS_ENSURE_STATE(tabContextUpdated);
return NS_OK;

View File

@ -318,7 +318,9 @@ private:
void InitializeBrowserAPI();
nsresult GetNewTabContext(mozilla::dom::MutableTabContext* aTabContext);
nsresult GetNewTabContext(mozilla::dom::MutableTabContext* aTabContext,
const nsACString& aSignedPkgNoSuffix = EmptyCString(),
const nsACString& aPackageId = EmptyCString());
enum TabParentChange {
eTabParentRemoved,

View File

@ -16,7 +16,7 @@ interface nsIDOMElement;
interface nsITabParent;
interface nsILoadContext;
[scriptable, builtinclass, uuid(c6e00815-b7a1-4544-b309-a85b86cb1747)]
[scriptable, builtinclass, uuid(1645af04-1bc7-4363-8f2c-eb9679220ab1)]
interface nsIFrameLoader : nsISupports
{
/**
@ -52,10 +52,11 @@ interface nsIFrameLoader : nsISupports
/**
* Loads the specified URI in this frame but using a different process.
* Behaves identically to loadURI, except that this method only works
* with remote frame.
* with remote frame. For a signed package, we need to specifiy the
* package identifier.
* Throws an exception with non-remote frames.
*/
void switchProcessAndLoadURI(in nsIURI aURI);
void switchProcessAndLoadURI(in nsIURI aURI, in ACString aPackageId);
/**
* Puts the frameloader in prerendering mode.

View File

@ -30,7 +30,7 @@
.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader;
var uri = SpecialPowers.Services.io.newURI(url, null, null);
fl.switchProcessAndLoadURI(uri);
fl.switchProcessAndLoadURI(uri, "");
}
function runTest() {

View File

@ -35,6 +35,12 @@ class nsIPrincipal;
namespace mozilla {
#if DEUBG
#define LOG(args...) printf_stderr(args)
#else
#define LOG(...)
#endif
#ifdef MOZ_CHILD_PERMISSIONS
static bool
@ -118,11 +124,52 @@ AssertAppStatus(PBrowserParent* aActor,
return CheckAppStatusHelper(app, aStatus);
}
// A general purpose helper function to check permission against the origin
// rather than mozIApplication.
static bool
CheckOriginPermission(const nsACString& aOrigin, const char* aPermission)
{
LOG("CheckOriginPermission: %s, %s\n", nsCString(aOrigin).get(), aPermission);
nsIScriptSecurityManager *securityManager =
nsContentUtils::GetSecurityManager();
nsCOMPtr<nsIPrincipal> principal;
securityManager->CreateCodebasePrincipalFromOrigin(aOrigin,
getter_AddRefs(principal));
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
NS_ENSURE_TRUE(permMgr, false);
uint32_t perm;
nsresult rv = permMgr->TestExactPermissionFromPrincipal(principal, aPermission, &perm);
NS_ENSURE_SUCCESS(rv, false);
LOG("Permission %s for %s: %d\n", aPermission, nsCString(aOrigin).get(), perm);
return nsIPermissionManager::ALLOW_ACTION == perm;
}
bool
AssertAppProcess(TabContext& aContext,
AssertAppProcessType aType,
const char* aCapability)
{
const mozilla::OriginAttributes& attr = aContext.OriginAttributesRef();
nsCString suffix;
attr.CreateSuffix(suffix);
if (!aContext.SignedPkgOriginNoSuffix().IsEmpty()) {
LOG("TabContext owning signed package origin: %s, originAttr; %s\n",
nsCString(aContext.SignedPkgOriginNoSuffix()).get(),
suffix.get());
}
// Do a origin-based permission check if the TabContext owns a signed package.
if (!aContext.SignedPkgOriginNoSuffix().IsEmpty() &&
(ASSERT_APP_HAS_PERMISSION == aType || ASSERT_APP_PROCESS_PERMISSION == aType)) {
nsCString origin = aContext.SignedPkgOriginNoSuffix() + suffix;
return CheckOriginPermission(origin, aCapability);
}
nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement());

View File

@ -37,6 +37,11 @@ struct FrameIPCTabContext
// The ID of the app containing this app/browser frame, if applicable.
uint32_t frameOwnerAppId;
// The origin without originAttribute suffix for a signed package.
// This value would be empty if the TabContext doesn't own a signed
// package.
nsCString signedPkgOriginNoSuffix;
};
// IPCTabContext is an analog to mozilla::dom::TabContext. Both specify an

View File

@ -158,11 +158,17 @@ TabContext::OriginAttributesRef() const
return mOriginAttributes;
}
const nsACString&
TabContext::SignedPkgOriginNoSuffix() const
{
return mSignedPkgOriginNoSuffix;
}
bool
TabContext::SetTabContext(mozIApplication* aOwnApp,
mozIApplication* aAppFrameOwnerApp,
const OriginAttributes& aOriginAttributes)
const OriginAttributes& aOriginAttributes,
const nsACString& aSignedPkgOriginNoSuffix)
{
NS_ENSURE_FALSE(mInitialized, false);
@ -192,6 +198,7 @@ TabContext::SetTabContext(mozIApplication* aOwnApp,
mContainingAppId = containingAppId;
mOwnApp = aOwnApp;
mContainingApp = aAppFrameOwnerApp;
mSignedPkgOriginNoSuffix = aSignedPkgOriginNoSuffix;
return true;
}
@ -200,7 +207,9 @@ TabContext::AsIPCTabContext() const
{
nsAutoCString originSuffix;
mOriginAttributes.CreateSuffix(originSuffix);
return IPCTabContext(FrameIPCTabContext(originSuffix, mContainingAppId));
return IPCTabContext(FrameIPCTabContext(originSuffix,
mContainingAppId,
mSignedPkgOriginNoSuffix));
}
static already_AddRefed<mozIApplication>
@ -221,6 +230,7 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
uint32_t containingAppId = NO_APP_ID;
OriginAttributes originAttributes = OriginAttributes();
nsAutoCString originSuffix;
nsAutoCString signedPkgOriginNoSuffix;
const IPCTabContextUnion& contextUnion = aParams.contextUnion();
switch(contextUnion.type()) {
@ -276,6 +286,7 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
contextUnion.get_FrameIPCTabContext();
containingAppId = ipcContext.frameOwnerAppId();
signedPkgOriginNoSuffix = ipcContext.signedPkgOriginNoSuffix();
originSuffix = ipcContext.originSuffix();
originAttributes.PopulateFromSuffix(originSuffix);
break;
@ -305,7 +316,8 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
bool rv;
rv = mTabContext.SetTabContext(ownApp,
containingApp,
originAttributes);
originAttributes,
signedPkgOriginNoSuffix);
if (!rv) {
mInvalidReason = "Couldn't initialize TabContext.";
}

View File

@ -110,6 +110,12 @@ public:
*/
const OriginAttributes& OriginAttributesRef() const;
/**
* Returns the origin associated with the tab (w/o suffix) if this tab owns
* a signed packaged content.
*/
const nsACString& SignedPkgOriginNoSuffix() const;
protected:
friend class MaybeInvalidTabContext;
@ -136,7 +142,8 @@ protected:
*/
bool SetTabContext(mozIApplication* aOwnApp,
mozIApplication* aAppFrameOwnerApp,
const OriginAttributes& aOriginAttributes);
const OriginAttributes& aOriginAttributes,
const nsACString& aSignedPkgOriginNoSuffix);
private:
/**
@ -167,6 +174,13 @@ private:
*/
OriginAttributes mOriginAttributes;
/**
* The signed package origin without suffix. Since the signed packaged
* web content is always loaded in a separate process, it makes sense
* that we store this immutable value in TabContext. If the TabContext
* doesn't own a signed package, this value would be empty.
*/
nsCString mSignedPkgOriginNoSuffix;
};
/**
@ -184,11 +198,13 @@ public:
bool SetTabContext(mozIApplication* aOwnApp,
mozIApplication* aAppFrameOwnerApp,
const OriginAttributes& aOriginAttributes)
const OriginAttributes& aOriginAttributes,
const nsACString& aSignedPkgOriginNoSuffix = EmptyCString())
{
return TabContext::SetTabContext(aOwnApp,
aAppFrameOwnerApp,
aOriginAttributes);
aOriginAttributes,
aSignedPkgOriginNoSuffix);
}
};

View File

@ -518,7 +518,8 @@ TabParent::ShouldSwitchProcess(nsIChannel* aChannel)
}
void
TabParent::OnStartSignedPackageRequest(nsIChannel* aChannel)
TabParent::OnStartSignedPackageRequest(nsIChannel* aChannel,
const nsACString& aPackageId)
{
if (!ShouldSwitchProcess(aChannel)) {
return;
@ -537,7 +538,7 @@ TabParent::OnStartSignedPackageRequest(nsIChannel* aChannel)
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
NS_ENSURE_TRUE_VOID(frameLoader);
nsresult rv = frameLoader->SwitchProcessAndLoadURI(uri);
nsresult rv = frameLoader->SwitchProcessAndLoadURI(uri, aPackageId);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to switch process.");
}

View File

@ -456,7 +456,8 @@ public:
// Called by HttpChannelParent. The function may use a new process to
// reload the URI associated with the given channel.
void OnStartSignedPackageRequest(nsIChannel* aChannel);
void OnStartSignedPackageRequest(nsIChannel* aChannel,
const nsACString& aPackageId);
protected:
bool ReceiveMessage(const nsString& aMessage,

View File

@ -1057,7 +1057,7 @@ NS_IMETHODIMP
HttpChannelParent::OnStartSignedPackageRequest(const nsACString& aPackageId)
{
if (mTabParent) {
mTabParent->OnStartSignedPackageRequest(mChannel);
mTabParent->OnStartSignedPackageRequest(mChannel, aPackageId);
}
return NS_OK;
}