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:
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -1121,7 +1121,8 @@ parent:
|
||||
nsIPrincipal triggeringPrincipal,
|
||||
nsIPrincipal redirectPrincipal,
|
||||
MaybeDiscardedBrowsingContext browsingContext,
|
||||
bool wasExternallyTriggered);
|
||||
bool wasExternallyTriggered,
|
||||
bool hasValidUserGestureActivation);
|
||||
async ExtProtocolChannelConnectParent(uint64_t registrarId);
|
||||
|
||||
// PrefService message
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user