From 6584da597b9d1f1beb7968b05af03bcbce26f1a7 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Wed, 8 Nov 2017 20:01:41 +0100 Subject: [PATCH] Bug 1407891: Allow view-image to open a data: URI by setting a flag on the loadinfo. r=bz --- browser/base/content/nsContextMenu.js | 3 ++- browser/base/content/utilityOverlay.js | 5 +++++ docshell/base/nsDocShell.cpp | 17 ++++++++++++++++- docshell/base/nsDocShell.h | 1 + docshell/base/nsDocShellLoadInfo.cpp | 15 +++++++++++++++ docshell/base/nsDocShellLoadInfo.h | 1 + docshell/base/nsIDocShell.idl | 3 +++ docshell/base/nsIDocShellLoadInfo.idl | 6 ++++++ docshell/base/nsIWebNavigation.idl | 6 ++++++ dom/security/nsContentSecurityManager.cpp | 4 ++++ ipc/glue/BackgroundUtils.cpp | 2 ++ netwerk/base/LoadInfo.cpp | 22 ++++++++++++++++++++++ netwerk/base/LoadInfo.h | 2 ++ netwerk/base/nsILoadInfo.idl | 5 +++++ netwerk/ipc/NeckoChannelParams.ipdlh | 1 + 15 files changed, 91 insertions(+), 2 deletions(-) diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index f2ca994e9e96..399b40afdeb0 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -951,7 +951,8 @@ nsContextMenu.prototype = { this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); openUILink(this.mediaURL, e, { disallowInheritPrincipal: true, - referrerURI }); + referrerURI, + forceAllowDataURI: true }); } }, diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index ecfd00708a32..2cc27580f2fa 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -207,6 +207,7 @@ function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI openLinkIn(url, where, params); } +/* eslint-disable complexity */ function openLinkIn(url, where, params) { if (!where || !url) return; @@ -222,6 +223,7 @@ function openLinkIn(url, where, params) { params.referrerPolicy : Ci.nsIHttpChannel.REFERRER_POLICY_UNSET); var aRelatedToCurrent = params.relatedToCurrent; var aAllowMixedContent = params.allowMixedContent; + var aForceAllowDataURI = params.forceAllowDataURI; var aInBackground = params.inBackground; var aDisallowInheritPrincipal = params.disallowInheritPrincipal; var aInitiatingDoc = params.initiatingDoc; @@ -433,6 +435,9 @@ function openLinkIn(url, where, params) { if (aIndicateErrorPageLoad) { flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ERROR_LOAD_CHANGES_RV; } + if (aForceAllowDataURI) { + flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI; + } let {URI_INHERITS_SECURITY_CONTEXT} = Ci.nsIProtocolHandler; if (aForceAboutBlankViewerInCurrent && diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 0e24e7462804..5b2bc9675a35 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -1310,6 +1310,7 @@ nsDocShell::LoadURI(nsIURI* aURI, nsCOMPtr shEntry; nsString target; nsAutoString srcdoc; + bool forceAllowDataURI = false; nsCOMPtr sourceDocShell; nsCOMPtr baseURI; @@ -1346,6 +1347,7 @@ nsDocShell::LoadURI(nsIURI* aURI, aLoadInfo->GetSrcdocData(srcdoc); aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell)); aLoadInfo->GetBaseURI(getter_AddRefs(baseURI)); + aLoadInfo->GetForceAllowDataURI(&forceAllowDataURI); } MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, @@ -1609,6 +1611,10 @@ nsDocShell::LoadURI(nsIURI* aURI, flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; } + if (forceAllowDataURI) { + flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI; + } + return InternalLoad(aURI, originalURI, resultPrincipalURI, @@ -4917,6 +4923,9 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI, } nsAutoPopupStatePusher statePusher(popupState); + bool forceAllowDataURI = + aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI; + // Don't pass certain flags that aren't needed and end up confusing // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are // passed to LoadURI though, since it uses them. @@ -4947,6 +4956,7 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI, loadInfo->SetHeadersStream(aHeaderStream); loadInfo->SetBaseURI(aBaseURI); loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal); + loadInfo->SetForceAllowDataURI(forceAllowDataURI); if (fixupInfo) { nsAutoString searchProvider, keyword; @@ -10189,6 +10199,7 @@ nsDocShell::InternalLoad(nsIURI* aURI, // principal to inherit is: it should be aTriggeringPrincipal. loadInfo->SetPrincipalIsExplicit(true); loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(LOAD_LINK)); + loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI); rv = win->Open(NS_ConvertUTF8toUTF16(spec), aWindowTarget, // window name @@ -10866,7 +10877,9 @@ nsDocShell::InternalLoad(nsIURI* aURI, nsCOMPtr req; rv = DoURILoad(aURI, aOriginalURI, aResultPrincipalURI, aLoadReplace, - loadFromExternal, aReferrer, + loadFromExternal, + (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI), + aReferrer, !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), aReferrerPolicy, aTriggeringPrincipal, principalToInherit, aTypeHint, @@ -11004,6 +11017,7 @@ nsDocShell::DoURILoad(nsIURI* aURI, Maybe> const& aResultPrincipalURI, bool aLoadReplace, bool aLoadFromExternal, + bool aForceAllowDataURI, nsIURI* aReferrerURI, bool aSendReferrer, uint32_t aReferrerPolicy, @@ -11184,6 +11198,7 @@ nsDocShell::DoURILoad(nsIURI* aURI, loadInfo->SetPrincipalToInherit(aPrincipalToInherit); } loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal); + loadInfo->SetForceAllowDataURI(aForceAllowDataURI); // We have to do this in case our OriginAttributes are different from the // OriginAttributes of the parent document. Or in case there isn't a diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index ca93a3c7a5bf..c097fcb1f49b 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -452,6 +452,7 @@ protected: mozilla::Maybe> const& aResultPrincipalURI, bool aLoadReplace, bool aLoadFromExternal, + bool aForceAllowDataURI, nsIURI* aReferrer, bool aSendReferrer, uint32_t aReferrerPolicy, diff --git a/docshell/base/nsDocShellLoadInfo.cpp b/docshell/base/nsDocShellLoadInfo.cpp index 40a4b7edd31a..836b629a5db3 100644 --- a/docshell/base/nsDocShellLoadInfo.cpp +++ b/docshell/base/nsDocShellLoadInfo.cpp @@ -67,6 +67,7 @@ nsDocShellLoadInfo::nsDocShellLoadInfo() , mLoadReplace(false) , mInheritPrincipal(false) , mPrincipalIsExplicit(false) + , mForceAllowDataURI(false) , mSendReferrer(true) , mReferrerPolicy(mozilla::net::RP_Unset) , mLoadType(nsIDocShellLoadInfo::loadNormal) @@ -209,6 +210,20 @@ nsDocShellLoadInfo::SetPrincipalIsExplicit(bool aPrincipalIsExplicit) return NS_OK; } +NS_IMETHODIMP +nsDocShellLoadInfo::GetForceAllowDataURI(bool* aForceAllowDataURI) +{ + *aForceAllowDataURI = mForceAllowDataURI; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellLoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI) +{ + mForceAllowDataURI = aForceAllowDataURI; + return NS_OK; +} + NS_IMETHODIMP nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType* aLoadType) { diff --git a/docshell/base/nsDocShellLoadInfo.h b/docshell/base/nsDocShellLoadInfo.h index 58e6fcd734c2..9a080326dbf4 100644 --- a/docshell/base/nsDocShellLoadInfo.h +++ b/docshell/base/nsDocShellLoadInfo.h @@ -39,6 +39,7 @@ protected: bool mLoadReplace; bool mInheritPrincipal; bool mPrincipalIsExplicit; + bool mForceAllowDataURI; bool mSendReferrer; nsDocShellInfoReferrerPolicy mReferrerPolicy; nsDocShellInfoLoadType mLoadType; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 4beac80ff594..2f3572890907 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -127,6 +127,9 @@ interface nsIDocShell : nsIDocShellTreeItem const long INTERNAL_LOAD_FLAGS_NO_OPENER = 0x100; + // Whether a top-level data URI navigation is allowed for that load + const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI = 0x200; + // NB: 0x80 is available. /** diff --git a/docshell/base/nsIDocShellLoadInfo.idl b/docshell/base/nsIDocShellLoadInfo.idl index e66a3a4a6c1c..c8d52c7c5539 100644 --- a/docshell/base/nsIDocShellLoadInfo.idl +++ b/docshell/base/nsIDocShellLoadInfo.idl @@ -65,6 +65,12 @@ interface nsIDocShellLoadInfo : nsISupports */ attribute boolean principalIsExplicit; + /** + * If this attribute is true, then a top-level navigation + * to a data URI will be allowed. + */ + attribute boolean forceAllowDataURI; + /* these are load type enums... */ const long loadNormal = 0; // Normal Load const long loadNormalReplace = 1; // Normal Load but replaces current history slot diff --git a/docshell/base/nsIWebNavigation.idl b/docshell/base/nsIWebNavigation.idl index 78e89a41359f..8fcb21f4a62f 100644 --- a/docshell/base/nsIWebNavigation.idl +++ b/docshell/base/nsIWebNavigation.idl @@ -206,6 +206,12 @@ interface nsIWebNavigation : nsISupports */ const unsigned long LOAD_FLAGS_FIXUP_SCHEME_TYPOS = 0x200000; + /** + * Allows a top-level data: navigation to occur. E.g. view-image + * is an explicit user action which should be allowed. + */ + const unsigned long LOAD_FLAGS_FORCE_ALLOW_DATA_URI = 0x400000; + /** * Loads a given URI. This will give priority to loading the requested URI * in the object implementing this interface. If it can't be loaded here diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 5876db2aeaef..d8db2e063426 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -48,6 +48,10 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel) if (loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) { return true; } + if (loadInfo->GetForceAllowDataURI()) { + // if the loadinfo explicitly allows the data URI navigation, let's allow it now + return true; + } nsCOMPtr uri; nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, true); diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index a0982bfa6f68..6fe9eb3851eb 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -387,6 +387,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo, aLoadInfo->GetUpgradeInsecureRequests(), aLoadInfo->GetVerifySignedContent(), aLoadInfo->GetEnforceSRI(), + aLoadInfo->GetForceAllowDataURI(), aLoadInfo->GetForceInheritPrincipalDropped(), aLoadInfo->GetInnerWindowID(), aLoadInfo->GetOuterWindowID(), @@ -495,6 +496,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs, loadInfoArgs.upgradeInsecureRequests(), loadInfoArgs.verifySignedContent(), loadInfoArgs.enforceSRI(), + loadInfoArgs.forceAllowDataURI(), loadInfoArgs.forceInheritPrincipalDropped(), loadInfoArgs.innerWindowID(), loadInfoArgs.outerWindowID(), diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index dfe324a9d775..3a9f6160a104 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -58,6 +58,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mUpgradeInsecureRequests(false) , mVerifySignedContent(false) , mEnforceSRI(false) + , mForceAllowDataURI(false) , mForceInheritPrincipalDropped(false) , mInnerWindowID(0) , mOuterWindowID(0) @@ -241,6 +242,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow, , mUpgradeInsecureRequests(false) , mVerifySignedContent(false) , mEnforceSRI(false) + , mForceAllowDataURI(false) , mForceInheritPrincipalDropped(false) , mInnerWindowID(0) , mOuterWindowID(0) @@ -309,6 +311,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) , mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests) , mVerifySignedContent(rhs.mVerifySignedContent) , mEnforceSRI(rhs.mEnforceSRI) + , mForceAllowDataURI(rhs.mForceAllowDataURI) , mForceInheritPrincipalDropped(rhs.mForceInheritPrincipalDropped) , mInnerWindowID(rhs.mInnerWindowID) , mOuterWindowID(rhs.mOuterWindowID) @@ -346,6 +349,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, bool aUpgradeInsecureRequests, bool aVerifySignedContent, bool aEnforceSRI, + bool aForceAllowDataURI, bool aForceInheritPrincipalDropped, uint64_t aInnerWindowID, uint64_t aOuterWindowID, @@ -378,6 +382,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mUpgradeInsecureRequests(aUpgradeInsecureRequests) , mVerifySignedContent(aVerifySignedContent) , mEnforceSRI(aEnforceSRI) + , mForceAllowDataURI(aForceAllowDataURI) , mForceInheritPrincipalDropped(aForceInheritPrincipalDropped) , mInnerWindowID(aInnerWindowID) , mOuterWindowID(aOuterWindowID) @@ -751,6 +756,23 @@ LoadInfo::GetEnforceSRI(bool* aResult) return NS_OK; } +NS_IMETHODIMP +LoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI) +{ + MOZ_ASSERT(!mForceAllowDataURI || + mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT, + "can only allow data URI navigation for TYPE_DOCUMENT"); + mForceAllowDataURI = aForceAllowDataURI; + return NS_OK; +} + +NS_IMETHODIMP +LoadInfo::GetForceAllowDataURI(bool* aForceAllowDataURI) +{ + *aForceAllowDataURI = mForceAllowDataURI; + return NS_OK; +} + NS_IMETHODIMP LoadInfo::GetForceInheritPrincipalDropped(bool* aResult) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index bc6911f4d958..9cd3124317e2 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -103,6 +103,7 @@ private: bool aUpgradeInsecureRequests, bool aVerifySignedContent, bool aEnforceSRI, + bool aForceAllowDataURI, bool aForceInheritPrincipalDropped, uint64_t aInnerWindowID, uint64_t aOuterWindowID, @@ -159,6 +160,7 @@ private: bool mUpgradeInsecureRequests; bool mVerifySignedContent; bool mEnforceSRI; + bool mForceAllowDataURI; bool mForceInheritPrincipalDropped; uint64_t mInnerWindowID; uint64_t mOuterWindowID; diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index 03b48011be1d..577c95fe134b 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -506,6 +506,11 @@ interface nsILoadInfo : nsISupports */ [infallible] attribute boolean enforceSRI; + /** + * If true, toplevel data: URI navigation is allowed + */ + [infallible] attribute boolean forceAllowDataURI; + /** * The SEC_FORCE_INHERIT_PRINCIPAL flag may be dropped when a load info * object is created. Specifically, it will be dropped if the SEC_SANDBOXED diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 9da8f0f148ef..882667e2b102 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -47,6 +47,7 @@ struct LoadInfoArgs bool upgradeInsecureRequests; bool verifySignedContent; bool enforceSRI; + bool forceAllowDataURI; bool forceInheritPrincipalDropped; uint64_t innerWindowID; uint64_t outerWindowID;