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
Родитель 02cb32707b
Коммит 9fe43dfb43
11 изменённых файлов: 119 добавлений и 19 удалений

Просмотреть файл

@ -97,6 +97,8 @@
#include "mozilla/dom/ipc/StructuredCloneData.h" #include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/WebBrowserPersistLocalDocument.h" #include "mozilla/WebBrowserPersistLocalDocument.h"
#include "nsPrincipal.h"
#ifdef MOZ_XUL #ifdef MOZ_XUL
#include "nsXULPopupManager.h" #include "nsXULPopupManager.h"
#endif #endif
@ -278,13 +280,20 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsFrameLoader::SwitchProcessAndLoadURI(nsIURI* aURI) nsFrameLoader::SwitchProcessAndLoadURI(nsIURI* aURI, const nsACString& aPackageId)
{ {
nsCOMPtr<nsIURI> URIToLoad = aURI; nsCOMPtr<nsIURI> URIToLoad = aURI;
RefPtr<TabParent> tp = nullptr; 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; MutableTabContext context;
nsresult rv = GetNewTabContext(&context); nsresult rv = GetNewTabContext(&context, signedPkgOrigin, aPackageId);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Element> ownerElement = mOwnerContent; nsCOMPtr<Element> ownerElement = mOwnerContent;
@ -3031,7 +3040,9 @@ nsFrameLoader::MaybeUpdatePrimaryTabParent(TabParentChange aChange)
} }
nsresult nsresult
nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext) nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
const nsACString& aSignedPkgOriginNoSuffix,
const nsACString& aPackageId)
{ {
nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
nsCOMPtr<mozIApplication> containingApp = GetContainingApp(); nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
@ -3051,7 +3062,11 @@ nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext)
} }
attrs.mAppId = appId; 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); NS_ENSURE_STATE(tabContextUpdated);
return NS_OK; return NS_OK;

Просмотреть файл

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

Просмотреть файл

@ -16,7 +16,7 @@ interface nsIDOMElement;
interface nsITabParent; interface nsITabParent;
interface nsILoadContext; interface nsILoadContext;
[scriptable, builtinclass, uuid(c6e00815-b7a1-4544-b309-a85b86cb1747)] [scriptable, builtinclass, uuid(1645af04-1bc7-4363-8f2c-eb9679220ab1)]
interface nsIFrameLoader : nsISupports interface nsIFrameLoader : nsISupports
{ {
/** /**
@ -52,10 +52,11 @@ interface nsIFrameLoader : nsISupports
/** /**
* Loads the specified URI in this frame but using a different process. * Loads the specified URI in this frame but using a different process.
* Behaves identically to loadURI, except that this method only works * 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. * 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. * Puts the frameloader in prerendering mode.

Просмотреть файл

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

Просмотреть файл

@ -35,6 +35,12 @@ class nsIPrincipal;
namespace mozilla { namespace mozilla {
#if DEUBG
#define LOG(args...) printf_stderr(args)
#else
#define LOG(...)
#endif
#ifdef MOZ_CHILD_PERMISSIONS #ifdef MOZ_CHILD_PERMISSIONS
static bool static bool
@ -118,11 +124,52 @@ AssertAppStatus(PBrowserParent* aActor,
return CheckAppStatusHelper(app, aStatus); 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 bool
AssertAppProcess(TabContext& aContext, AssertAppProcess(TabContext& aContext,
AssertAppProcessType aType, AssertAppProcessType aType,
const char* aCapability) 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(); nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement()); return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement());

Просмотреть файл

@ -37,6 +37,11 @@ struct FrameIPCTabContext
// The ID of the app containing this app/browser frame, if applicable. // The ID of the app containing this app/browser frame, if applicable.
uint32_t frameOwnerAppId; 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 // IPCTabContext is an analog to mozilla::dom::TabContext. Both specify an

Просмотреть файл

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

Просмотреть файл

@ -110,6 +110,12 @@ public:
*/ */
const OriginAttributes& OriginAttributesRef() const; 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: protected:
friend class MaybeInvalidTabContext; friend class MaybeInvalidTabContext;
@ -136,7 +142,8 @@ protected:
*/ */
bool SetTabContext(mozIApplication* aOwnApp, bool SetTabContext(mozIApplication* aOwnApp,
mozIApplication* aAppFrameOwnerApp, mozIApplication* aAppFrameOwnerApp,
const OriginAttributes& aOriginAttributes); const OriginAttributes& aOriginAttributes,
const nsACString& aSignedPkgOriginNoSuffix);
private: private:
/** /**
@ -167,6 +174,13 @@ private:
*/ */
OriginAttributes mOriginAttributes; 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, bool SetTabContext(mozIApplication* aOwnApp,
mozIApplication* aAppFrameOwnerApp, mozIApplication* aAppFrameOwnerApp,
const OriginAttributes& aOriginAttributes) const OriginAttributes& aOriginAttributes,
const nsACString& aSignedPkgOriginNoSuffix = EmptyCString())
{ {
return TabContext::SetTabContext(aOwnApp, return TabContext::SetTabContext(aOwnApp,
aAppFrameOwnerApp, aAppFrameOwnerApp,
aOriginAttributes); aOriginAttributes,
aSignedPkgOriginNoSuffix);
} }
}; };

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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