Bug 1735746 - Block external protocol navigation from sandboxed contexts. r=nika,ckerschb,Gijs,smaug

Differential Revision: https://phabricator.services.mozilla.com/D141131
This commit is contained in:
Paul Zuehlcke
2022-04-20 11:06:50 +00:00
parent e3df4d1993
commit 89b9ce04f7
11 changed files with 78 additions and 14 deletions

View File

@@ -12993,9 +12993,12 @@ nsresult nsDocShell::OnLinkClickSync(nsIContent* aContent,
nsresult rv =
extProtService->IsExposedProtocol(scheme.get(), &isExposed);
if (NS_SUCCEEDED(rv) && !isExposed) {
return extProtService->LoadURI(aLoadState->URI(), triggeringPrincipal,
nullptr, mBrowsingContext,
/* aTriggeredExternally */ false);
return extProtService->LoadURI(
aLoadState->URI(), triggeringPrincipal, nullptr, mBrowsingContext,
/* aTriggeredExternally */
false,
/* aHasValidUserGestureActivation */
aContent->OwnerDoc()->HasValidTransientUserGestureActivation());
}
}
}

View File

@@ -30,3 +30,6 @@ SANDBOX_KEYWORD("allow-presentation", allowpresentation, SANDBOXED_PRESENTATION)
SANDBOX_KEYWORD("allow-storage-access-by-user-activation",
allowstorageaccessbyuseractivatetion, SANDBOXED_STORAGE_ACCESS)
SANDBOX_KEYWORD("allow-downloads", allowdownloads, SANDBOXED_ALLOW_DOWNLOADS)
SANDBOX_KEYWORD("allow-top-navigation-to-custom-protocols",
allowtopnavigationcustomprotocols,
SANDBOXED_TOPLEVEL_NAVIGATION_CUSTOM_PROTOCOLS)

View File

@@ -129,5 +129,10 @@ const unsigned long SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION = 0x20000;
*/
const unsigned long SANDBOXED_ALLOW_DOWNLOADS = 0x10000;
/**
* This flag prevents content from navigating to custom protocols.
*/
const unsigned long SANDBOXED_TOPLEVEL_NAVIGATION_CUSTOM_PROTOCOLS = 0x40000;
const unsigned long SANDBOX_ALL_FLAGS = 0xFFFFF;
#endif

View File

@@ -4547,7 +4547,7 @@ mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aRedirectPrincipal,
const MaybeDiscarded<BrowsingContext>& aContext,
bool aWasExternallyTriggered) {
bool aWasExternallyTriggered, bool aHasValidUserGestureActivation) {
if (aContext.IsDiscarded()) {
return IPC_OK();
}
@@ -4564,7 +4564,8 @@ mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
BrowsingContext* bc = aContext.get();
extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
aWasExternallyTriggered);
aWasExternallyTriggered,
aHasValidUserGestureActivation);
return IPC_OK();
}

View File

@@ -1066,7 +1066,7 @@ class ContentParent final
nsIURI* uri, nsIPrincipal* triggeringPrincipal,
nsIPrincipal* redirectPrincipal,
const MaybeDiscarded<BrowsingContext>& aContext,
bool aWasExternallyTriggered);
bool aWasExternallyTriggered, bool aHasValidUserGestureActivation);
mozilla::ipc::IPCResult RecvExtProtocolChannelConnectParent(
const uint64_t& registrarId);

View File

@@ -1121,7 +1121,8 @@ parent:
nsIPrincipal triggeringPrincipal,
nsIPrincipal redirectPrincipal,
MaybeDiscardedBrowsingContext browsingContext,
bool wasExternallyTriggered);
bool wasExternallyTriggered,
bool hasValidUserGestureActivation);
async ExtProtocolChannelConnectParent(uint64_t registrarId);
// PrefService message

View File

@@ -30,6 +30,7 @@
#include "nsAppDirectoryServiceDefs.h"
#include "nsICategoryManager.h"
#include "nsDependentSubstring.h"
#include "nsSandboxFlags.h"
#include "nsString.h"
#include "nsUnicharUtils.h"
#include "nsIStringEnumerator.h"
@@ -1095,18 +1096,61 @@ nsresult nsExternalHelperAppService::EscapeURI(nsIURI* aURI, nsIURI** aResult) {
return ios->NewURI(escapedSpec, nullptr, nullptr, aResult);
}
bool ExternalProtocolIsBlockedBySandbox(
BrowsingContext* aBrowsingContext,
const bool aHasValidUserGestureActivation) {
if (!aBrowsingContext || aBrowsingContext->IsTop()) {
return false;
}
uint32_t sandboxFlags = aBrowsingContext->GetSandboxFlags();
if (sandboxFlags == SANDBOXED_NONE) {
return false;
}
if (!(sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION)) {
return false;
}
if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
return false;
}
if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION_CUSTOM_PROTOCOLS)) {
return false;
}
if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION) &&
aHasValidUserGestureActivation) {
return false;
}
return true;
}
NS_IMETHODIMP
nsExternalHelperAppService::LoadURI(nsIURI* aURI,
nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aRedirectPrincipal,
BrowsingContext* aBrowsingContext,
bool aTriggeredExternally) {
bool aTriggeredExternally,
bool aHasValidUserGestureActivation) {
NS_ENSURE_ARG_POINTER(aURI);
if (XRE_IsContentProcess()) {
mozilla::dom::ContentChild::GetSingleton()->SendLoadURIExternal(
aURI, aTriggeringPrincipal, aRedirectPrincipal, aBrowsingContext,
aTriggeredExternally);
aTriggeredExternally, aHasValidUserGestureActivation);
return NS_OK;
}
// Prevent sandboxed BrowsingContexts from navigating to external protocols.
// This only uses the sandbox flags of the target BrowsingContext of the
// load. The navigating document's CSP sandbox flags do not apply.
if (aBrowsingContext &&
ExternalProtocolIsBlockedBySandbox(aBrowsingContext,
aHasValidUserGestureActivation)) {
return NS_OK;
}

View File

@@ -87,7 +87,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
NS_IMETHOD LoadURI(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aRedirectPrincipal,
mozilla::dom::BrowsingContext* aBrowsingContext,
bool aWasTriggeredExternally) override;
bool aWasTriggeredExternally,
bool aHasValidUserGestureActivation) override;
NS_IMETHOD SetProtocolHandlerDefaults(nsIHandlerInfo* aHandlerInfo,
bool aOSHandlerExists) override;

View File

@@ -170,9 +170,9 @@ nsresult nsExtProtocolChannel::OpenURL() {
mLoadInfo->RedirectChain().LastElement()->GetPrincipal(
getter_AddRefs(redirectPrincipal));
}
rv =
extProtService->LoadURI(mUrl, triggeringPrincipal, redirectPrincipal,
ctx, mLoadInfo->GetLoadTriggeredFromExternal());
rv = extProtService->LoadURI(mUrl, triggeringPrincipal, redirectPrincipal,
ctx, mLoadInfo->GetLoadTriggeredFromExternal(),
mLoadInfo->GetHasValidUserGestureActivation());
if (NS_SUCCEEDED(rv) && mListener) {
mStatus = NS_ERROR_NO_CONTENT;

View File

@@ -117,6 +117,10 @@ interface nsIExternalProtocolService : nsISupports
* @param aWasTriggeredExternally
* If true, indicates the load was initiated by an external app.
*
* @param aHasValidUserGestureActivation
* Whether the document that triggered the load had user activation.
* Used for sandbox checks.
*
* @note Embedders that do not expose the http protocol should not currently
* use web-based protocol handlers, as handoff won't work correctly
* (bug 394479).
@@ -125,7 +129,8 @@ interface nsIExternalProtocolService : nsISupports
[optional] in nsIPrincipal aTriggeringPrincipal,
[optional] in nsIPrincipal aRedirectPrincipal,
[optional] in BrowsingContext aBrowsingContext,
[optional] in bool aWasTriggeredExternally);
[optional] in bool aWasTriggeredExternally,
[optional] in bool aHasValidUserGestureActivation);
/**
* Gets a human-readable description for the application responsible for

View File

@@ -93,6 +93,7 @@ STATIC_ATOMS = [
Atom("allowscriptstoclose", "allowscriptstoclose"),
Atom("allowtopnavigation", "allow-top-navigation"),
Atom("allowtopnavigationbyuseractivation", "allow-top-navigation-by-user-activation"),
Atom("allowtopnavigationcustomprotocols", "allow-top-navigation-to-custom-protocols"),
Atom("allowuntrusted", "allowuntrusted"),
Atom("alt", "alt"),
Atom("alternate", "alternate"),