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 =
|
nsresult rv =
|
||||||
extProtService->IsExposedProtocol(scheme.get(), &isExposed);
|
extProtService->IsExposedProtocol(scheme.get(), &isExposed);
|
||||||
if (NS_SUCCEEDED(rv) && !isExposed) {
|
if (NS_SUCCEEDED(rv) && !isExposed) {
|
||||||
return extProtService->LoadURI(aLoadState->URI(), triggeringPrincipal,
|
return extProtService->LoadURI(
|
||||||
nullptr, mBrowsingContext,
|
aLoadState->URI(), triggeringPrincipal, nullptr, mBrowsingContext,
|
||||||
/* aTriggeredExternally */ false);
|
/* 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",
|
SANDBOX_KEYWORD("allow-storage-access-by-user-activation",
|
||||||
allowstorageaccessbyuseractivatetion, SANDBOXED_STORAGE_ACCESS)
|
allowstorageaccessbyuseractivatetion, SANDBOXED_STORAGE_ACCESS)
|
||||||
SANDBOX_KEYWORD("allow-downloads", allowdownloads, SANDBOXED_ALLOW_DOWNLOADS)
|
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;
|
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;
|
const unsigned long SANDBOX_ALL_FLAGS = 0xFFFFF;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4547,7 +4547,7 @@ mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
|
|||||||
nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
|
nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
|
||||||
nsIPrincipal* aRedirectPrincipal,
|
nsIPrincipal* aRedirectPrincipal,
|
||||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||||
bool aWasExternallyTriggered) {
|
bool aWasExternallyTriggered, bool aHasValidUserGestureActivation) {
|
||||||
if (aContext.IsDiscarded()) {
|
if (aContext.IsDiscarded()) {
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
@@ -4564,7 +4564,8 @@ mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
|
|||||||
|
|
||||||
BrowsingContext* bc = aContext.get();
|
BrowsingContext* bc = aContext.get();
|
||||||
extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
|
extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
|
||||||
aWasExternallyTriggered);
|
aWasExternallyTriggered,
|
||||||
|
aHasValidUserGestureActivation);
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1066,7 +1066,7 @@ class ContentParent final
|
|||||||
nsIURI* uri, nsIPrincipal* triggeringPrincipal,
|
nsIURI* uri, nsIPrincipal* triggeringPrincipal,
|
||||||
nsIPrincipal* redirectPrincipal,
|
nsIPrincipal* redirectPrincipal,
|
||||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||||
bool aWasExternallyTriggered);
|
bool aWasExternallyTriggered, bool aHasValidUserGestureActivation);
|
||||||
mozilla::ipc::IPCResult RecvExtProtocolChannelConnectParent(
|
mozilla::ipc::IPCResult RecvExtProtocolChannelConnectParent(
|
||||||
const uint64_t& registrarId);
|
const uint64_t& registrarId);
|
||||||
|
|
||||||
|
|||||||
@@ -1121,7 +1121,8 @@ parent:
|
|||||||
nsIPrincipal triggeringPrincipal,
|
nsIPrincipal triggeringPrincipal,
|
||||||
nsIPrincipal redirectPrincipal,
|
nsIPrincipal redirectPrincipal,
|
||||||
MaybeDiscardedBrowsingContext browsingContext,
|
MaybeDiscardedBrowsingContext browsingContext,
|
||||||
bool wasExternallyTriggered);
|
bool wasExternallyTriggered,
|
||||||
|
bool hasValidUserGestureActivation);
|
||||||
async ExtProtocolChannelConnectParent(uint64_t registrarId);
|
async ExtProtocolChannelConnectParent(uint64_t registrarId);
|
||||||
|
|
||||||
// PrefService message
|
// PrefService message
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "nsAppDirectoryServiceDefs.h"
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
#include "nsICategoryManager.h"
|
#include "nsICategoryManager.h"
|
||||||
#include "nsDependentSubstring.h"
|
#include "nsDependentSubstring.h"
|
||||||
|
#include "nsSandboxFlags.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsUnicharUtils.h"
|
#include "nsUnicharUtils.h"
|
||||||
#include "nsIStringEnumerator.h"
|
#include "nsIStringEnumerator.h"
|
||||||
@@ -1095,18 +1096,61 @@ nsresult nsExternalHelperAppService::EscapeURI(nsIURI* aURI, nsIURI** aResult) {
|
|||||||
return ios->NewURI(escapedSpec, nullptr, nullptr, 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
|
NS_IMETHODIMP
|
||||||
nsExternalHelperAppService::LoadURI(nsIURI* aURI,
|
nsExternalHelperAppService::LoadURI(nsIURI* aURI,
|
||||||
nsIPrincipal* aTriggeringPrincipal,
|
nsIPrincipal* aTriggeringPrincipal,
|
||||||
nsIPrincipal* aRedirectPrincipal,
|
nsIPrincipal* aRedirectPrincipal,
|
||||||
BrowsingContext* aBrowsingContext,
|
BrowsingContext* aBrowsingContext,
|
||||||
bool aTriggeredExternally) {
|
bool aTriggeredExternally,
|
||||||
|
bool aHasValidUserGestureActivation) {
|
||||||
NS_ENSURE_ARG_POINTER(aURI);
|
NS_ENSURE_ARG_POINTER(aURI);
|
||||||
|
|
||||||
if (XRE_IsContentProcess()) {
|
if (XRE_IsContentProcess()) {
|
||||||
mozilla::dom::ContentChild::GetSingleton()->SendLoadURIExternal(
|
mozilla::dom::ContentChild::GetSingleton()->SendLoadURIExternal(
|
||||||
aURI, aTriggeringPrincipal, aRedirectPrincipal, aBrowsingContext,
|
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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
|
|||||||
NS_IMETHOD LoadURI(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
|
NS_IMETHOD LoadURI(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
|
||||||
nsIPrincipal* aRedirectPrincipal,
|
nsIPrincipal* aRedirectPrincipal,
|
||||||
mozilla::dom::BrowsingContext* aBrowsingContext,
|
mozilla::dom::BrowsingContext* aBrowsingContext,
|
||||||
bool aWasTriggeredExternally) override;
|
bool aWasTriggeredExternally,
|
||||||
|
bool aHasValidUserGestureActivation) override;
|
||||||
NS_IMETHOD SetProtocolHandlerDefaults(nsIHandlerInfo* aHandlerInfo,
|
NS_IMETHOD SetProtocolHandlerDefaults(nsIHandlerInfo* aHandlerInfo,
|
||||||
bool aOSHandlerExists) override;
|
bool aOSHandlerExists) override;
|
||||||
|
|
||||||
|
|||||||
@@ -170,9 +170,9 @@ nsresult nsExtProtocolChannel::OpenURL() {
|
|||||||
mLoadInfo->RedirectChain().LastElement()->GetPrincipal(
|
mLoadInfo->RedirectChain().LastElement()->GetPrincipal(
|
||||||
getter_AddRefs(redirectPrincipal));
|
getter_AddRefs(redirectPrincipal));
|
||||||
}
|
}
|
||||||
rv =
|
rv = extProtService->LoadURI(mUrl, triggeringPrincipal, redirectPrincipal,
|
||||||
extProtService->LoadURI(mUrl, triggeringPrincipal, redirectPrincipal,
|
ctx, mLoadInfo->GetLoadTriggeredFromExternal(),
|
||||||
ctx, mLoadInfo->GetLoadTriggeredFromExternal());
|
mLoadInfo->GetHasValidUserGestureActivation());
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv) && mListener) {
|
if (NS_SUCCEEDED(rv) && mListener) {
|
||||||
mStatus = NS_ERROR_NO_CONTENT;
|
mStatus = NS_ERROR_NO_CONTENT;
|
||||||
|
|||||||
@@ -117,6 +117,10 @@ interface nsIExternalProtocolService : nsISupports
|
|||||||
* @param aWasTriggeredExternally
|
* @param aWasTriggeredExternally
|
||||||
* If true, indicates the load was initiated by an external app.
|
* 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
|
* @note Embedders that do not expose the http protocol should not currently
|
||||||
* use web-based protocol handlers, as handoff won't work correctly
|
* use web-based protocol handlers, as handoff won't work correctly
|
||||||
* (bug 394479).
|
* (bug 394479).
|
||||||
@@ -125,7 +129,8 @@ interface nsIExternalProtocolService : nsISupports
|
|||||||
[optional] in nsIPrincipal aTriggeringPrincipal,
|
[optional] in nsIPrincipal aTriggeringPrincipal,
|
||||||
[optional] in nsIPrincipal aRedirectPrincipal,
|
[optional] in nsIPrincipal aRedirectPrincipal,
|
||||||
[optional] in BrowsingContext aBrowsingContext,
|
[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
|
* Gets a human-readable description for the application responsible for
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ STATIC_ATOMS = [
|
|||||||
Atom("allowscriptstoclose", "allowscriptstoclose"),
|
Atom("allowscriptstoclose", "allowscriptstoclose"),
|
||||||
Atom("allowtopnavigation", "allow-top-navigation"),
|
Atom("allowtopnavigation", "allow-top-navigation"),
|
||||||
Atom("allowtopnavigationbyuseractivation", "allow-top-navigation-by-user-activation"),
|
Atom("allowtopnavigationbyuseractivation", "allow-top-navigation-by-user-activation"),
|
||||||
|
Atom("allowtopnavigationcustomprotocols", "allow-top-navigation-to-custom-protocols"),
|
||||||
Atom("allowuntrusted", "allowuntrusted"),
|
Atom("allowuntrusted", "allowuntrusted"),
|
||||||
Atom("alt", "alt"),
|
Atom("alt", "alt"),
|
||||||
Atom("alternate", "alternate"),
|
Atom("alternate", "alternate"),
|
||||||
|
|||||||
Reference in New Issue
Block a user