diff options
author | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-04-25 15:48:44 +0200 |
---|---|---|
committer | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-04-25 15:48:44 +0200 |
commit | 3ab6c7feee8126bdfc5c9ab9371db41102e12e95 (patch) | |
tree | a309c45826300b888238b6a517051fe7e71d63eb /docshell | |
parent | b18a9cf86ea25bc52d9cfea584e3aa8bfbe81f0a (diff) | |
parent | b069dabc91b7e0f5f8d161cdbe598276a21d6d68 (diff) | |
download | UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar.gz UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar.lz UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar.xz UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.zip |
Merge branch 'master' of https://github.com/MoonchildProductions/UXP into pm_url_1
Diffstat (limited to 'docshell')
-rw-r--r-- | docshell/base/nsDSURIContentListener.cpp | 9 | ||||
-rw-r--r-- | docshell/base/nsDocShell.cpp | 111 | ||||
-rw-r--r-- | docshell/base/nsDocShell.h | 2 | ||||
-rw-r--r-- | docshell/base/nsDocShellLoadInfo.cpp | 15 | ||||
-rw-r--r-- | docshell/base/nsDocShellLoadInfo.h | 1 | ||||
-rw-r--r-- | docshell/base/nsIDocShell.idl | 3 | ||||
-rw-r--r-- | docshell/base/nsIDocShellLoadInfo.idl | 6 | ||||
-rw-r--r-- | docshell/base/nsIWebNavigation.idl | 6 | ||||
-rw-r--r-- | docshell/test/navigation/file_contentpolicy_block_window.html | 5 | ||||
-rw-r--r-- | docshell/test/navigation/mochitest.ini | 2 | ||||
-rw-r--r-- | docshell/test/navigation/test_contentpolicy_block_window.html | 96 |
11 files changed, 223 insertions, 33 deletions
diff --git a/docshell/base/nsDSURIContentListener.cpp b/docshell/base/nsDSURIContentListener.cpp index 93ce3cb26..ee6a4dd62 100644 --- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -17,6 +17,7 @@ #include "nsIHttpChannel.h" #include "nsIScriptSecurityManager.h" #include "nsError.h" +#include "nsContentSecurityManager.h" #include "nsCharSeparatedTokenizer.h" #include "nsIConsoleService.h" #include "nsIScriptError.h" @@ -93,6 +94,14 @@ nsDSURIContentListener::DoContent(const nsACString& aContentType, if (aOpenedChannel) { aOpenedChannel->GetLoadFlags(&loadFlags); + + // block top-level data URI navigations if triggered by the web + if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(aOpenedChannel)) { + // logging to console happens within AllowTopLevelNavigationToDataURI + aRequest->Cancel(NS_ERROR_DOM_BAD_URI); + *aAbortProcess = true; + return NS_OK; + } } if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) { diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 58c182cbb..bd2a8a433 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -42,6 +42,7 @@ #include "nsArray.h" #include "nsArrayUtils.h" +#include "nsContentSecurityManager.h" #include "nsICaptivePortalService.h" #include "nsIDOMStorage.h" #include "nsIContentViewer.h" @@ -138,6 +139,7 @@ #include "nsISiteSecurityService.h" #include "nsStructuredCloneContainer.h" #include "nsIStructuredCloneContainer.h" +#include "nsISupportsPrimitives.h" #ifdef MOZ_PLACES #include "nsIFaviconService.h" #include "mozIPlacesPendingOperation.h" @@ -1272,6 +1274,7 @@ nsDocShell::LoadURI(nsIURI* aURI, nsCOMPtr<nsISHEntry> shEntry; nsXPIDLString target; nsAutoString srcdoc; + bool forceAllowDataURI = false; nsCOMPtr<nsIDocShell> sourceDocShell; nsCOMPtr<nsIURI> baseURI; @@ -1307,6 +1310,7 @@ nsDocShell::LoadURI(nsIURI* aURI, aLoadInfo->GetSrcdocData(srcdoc); aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell)); aLoadInfo->GetBaseURI(getter_AddRefs(baseURI)); + aLoadInfo->GetForceAllowDataURI(&forceAllowDataURI); } #if defined(DEBUG) @@ -1560,6 +1564,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, loadReplace, @@ -4821,6 +4829,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. @@ -4850,6 +4861,7 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI, loadInfo->SetReferrerPolicy(aReferrerPolicy); loadInfo->SetHeadersStream(aHeaderStream); loadInfo->SetBaseURI(aBaseURI); + loadInfo->SetForceAllowDataURI(forceAllowDataURI); if (fixupInfo) { nsAutoString searchProvider, keyword; @@ -9884,49 +9896,49 @@ nsDocShell::InternalLoad(nsIURI* aURI, contentType = nsIContentPolicy::TYPE_DOCUMENT; } - // If there's no targetDocShell, that means we are about to create a new window, - // perform a content policy check before creating the window. - if (!targetDocShell) { - nsCOMPtr<Element> requestingElement; + // If there's no targetDocShell, that means we are about to create a new + // window (or aWindowTarget is empty). Perform a content policy check before + // creating the window. Please note for all other docshell loads + // content policy checks are performed within the contentSecurityManager + // when the channel is about to be openend. + if (!targetDocShell && !aWindowTarget.IsEmpty()) { + MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT, + "opening a new window requires type to be TYPE_DOCUMENT"); + nsISupports* requestingContext = nullptr; - if (contentType == nsIContentPolicy::TYPE_DOCUMENT) { - if (XRE_IsContentProcess()) { - // In e10s the child process doesn't have access to the element that - // contains the browsing context (because that element is in the chrome - // process). So we just pass mScriptGlobal. - requestingContext = ToSupports(mScriptGlobal); - } else { - // This is for loading non-e10s tabs and toplevel windows of various - // sorts. - // For the toplevel window cases, requestingElement will be null. - requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal(); - requestingContext = requestingElement; - } + if (XRE_IsContentProcess()) { + // In e10s the child process doesn't have access to the element that + // contains the browsing context (because that element is in the chrome + // process). So we just pass mScriptGlobal. + requestingContext = ToSupports(mScriptGlobal); } else { - requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal(); + // This is for loading non-e10s tabs and toplevel windows of various + // sorts. + // For the toplevel window cases, requestingElement will be null. + nsCOMPtr<Element> requestingElement = + mScriptGlobal->AsOuter()->GetFrameElementInternal(); requestingContext = requestingElement; - -#ifdef DEBUG - if (requestingElement) { - // Get the docshell type for requestingElement. - nsCOMPtr<nsIDocument> requestingDoc = requestingElement->OwnerDoc(); - nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell(); - - // requestingElement docshell type = current docshell type. - MOZ_ASSERT(mItemType == elementDocShell->ItemType(), - "subframes should have the same docshell type as their parent"); - } -#endif } + // Since Content Policy checks are performed within docShell as well as + // the ContentSecurityManager we need a reliable way to let certain + // nsIContentPolicy consumers ignore duplicate calls. Let's use the 'extra' + // argument to pass a specific identifier. + nsCOMPtr<nsISupportsString> extraStr = + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + NS_NAMED_LITERAL_STRING(msg, "conPolCheckFromDocShell"); + rv = extraStr->SetData(msg); + NS_ENSURE_SUCCESS(rv, rv); + int16_t shouldLoad = nsIContentPolicy::ACCEPT; rv = NS_CheckContentLoadPolicy(contentType, aURI, aTriggeringPrincipal, requestingContext, EmptyCString(), // mime guess - nullptr, // extra + extraStr, // extra &shouldLoad); if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { @@ -10082,6 +10094,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 @@ -10232,8 +10245,11 @@ nsDocShell::InternalLoad(nsIURI* aURI, } } + bool loadFromExternal = false; + // Before going any further vet loads initiated by external programs. if (aLoadType == LOAD_NORMAL_EXTERNAL) { + loadFromExternal = true; // Disallow external chrome: loads targetted at content windows bool isChrome = false; if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) { @@ -10724,7 +10740,9 @@ nsDocShell::InternalLoad(nsIURI* aURI, nsINetworkPredictor::PREDICT_LOAD, this, nullptr); nsCOMPtr<nsIRequest> req; - rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, aReferrer, + rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, loadFromExternal, + (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI), + aReferrer, !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), aReferrerPolicy, aTriggeringPrincipal, principalToInherit, aTypeHint, @@ -10804,6 +10822,8 @@ nsresult nsDocShell::DoURILoad(nsIURI* aURI, nsIURI* aOriginalURI, bool aLoadReplace, + bool aLoadFromExternal, + bool aForceAllowDataURI, nsIURI* aReferrerURI, bool aSendReferrer, uint32_t aReferrerPolicy, @@ -10880,17 +10900,40 @@ nsDocShell::DoURILoad(nsIURI* aURI, nsCOMPtr<nsINode> loadingNode; nsCOMPtr<nsPIDOMWindowOuter> loadingWindow; nsCOMPtr<nsIPrincipal> loadingPrincipal; + nsCOMPtr<nsISupports> topLevelLoadingContext; if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) { loadingNode = nullptr; loadingPrincipal = nullptr; loadingWindow = mScriptGlobal->AsOuter(); + if (XRE_IsContentProcess()) { + // In e10s the child process doesn't have access to the element that + // contains the browsing context (because that element is in the chrome + // process). + nsCOMPtr<nsITabChild> tabChild = GetTabChild(); + topLevelLoadingContext = ToSupports(tabChild); + } else { + // This is for loading non-e10s tabs and toplevel windows of various + // sorts. + // For the toplevel window cases, requestingElement will be null. + nsCOMPtr<Element> requestingElement = + loadingWindow->GetFrameElementInternal(); + topLevelLoadingContext = requestingElement; + } } else { loadingWindow = nullptr; loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal(); if (loadingNode) { // If we have a loading node, then use that as our loadingPrincipal. loadingPrincipal = loadingNode->NodePrincipal(); +#ifdef DEBUG + // Get the docshell type for requestingElement. + nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc(); + nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell(); + // requestingElement docshell type = current docshell type. + MOZ_ASSERT(mItemType == elementDocShell->ItemType(), + "subframes should have the same docshell type as their parent"); +#endif } else { // If this isn't a top-level load and mScriptGlobal's frame element is // null, then the element got removed from the DOM while we were trying @@ -10940,7 +10983,7 @@ nsDocShell::DoURILoad(nsIURI* aURI, nsCOMPtr<nsILoadInfo> loadInfo = (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ? - new LoadInfo(loadingWindow, aTriggeringPrincipal, + new LoadInfo(loadingWindow, aTriggeringPrincipal, topLevelLoadingContext, securityFlags) : new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode, securityFlags, aContentPolicyType); @@ -10948,6 +10991,8 @@ nsDocShell::DoURILoad(nsIURI* aURI, if (aPrincipalToInherit) { 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 3ca9e0b34..63a4e3358 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -369,6 +369,8 @@ protected: nsresult DoURILoad(nsIURI* aURI, nsIURI* aOriginalURI, 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 7d0034b04..b00e8e360 100644 --- a/docshell/base/nsDocShellLoadInfo.cpp +++ b/docshell/base/nsDocShellLoadInfo.cpp @@ -15,6 +15,7 @@ nsDocShellLoadInfo::nsDocShellLoadInfo() : mLoadReplace(false) , mInheritPrincipal(false) , mPrincipalIsExplicit(false) + , mForceAllowDataURI(false) , mSendReferrer(true) , mReferrerPolicy(mozilla::net::RP_Default) , mLoadType(nsIDocShellLoadInfo::loadNormal) @@ -127,6 +128,20 @@ nsDocShellLoadInfo::SetPrincipalIsExplicit(bool aPrincipalIsExplicit) } 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) { NS_ENSURE_ARG_POINTER(aLoadType); diff --git a/docshell/base/nsDocShellLoadInfo.h b/docshell/base/nsDocShellLoadInfo.h index b7eaed832..f3ddcca1e 100644 --- a/docshell/base/nsDocShellLoadInfo.h +++ b/docshell/base/nsDocShellLoadInfo.h @@ -37,6 +37,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 8261c45dc..e34e6adfd 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -116,6 +116,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 113c0a4c1..8804f63a3 100644 --- a/docshell/base/nsIDocShellLoadInfo.idl +++ b/docshell/base/nsIDocShellLoadInfo.idl @@ -55,6 +55,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 042b1c547..241d0731c 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 * however, the URI dispatcher will go through its normal process of content diff --git a/docshell/test/navigation/file_contentpolicy_block_window.html b/docshell/test/navigation/file_contentpolicy_block_window.html new file mode 100644 index 000000000..c51e574e5 --- /dev/null +++ b/docshell/test/navigation/file_contentpolicy_block_window.html @@ -0,0 +1,5 @@ +<html> +<body> +This window should never be openend! +</body> +</html> diff --git a/docshell/test/navigation/mochitest.ini b/docshell/test/navigation/mochitest.ini index 0c35cf352..764e400a8 100644 --- a/docshell/test/navigation/mochitest.ini +++ b/docshell/test/navigation/mochitest.ini @@ -36,6 +36,7 @@ support-files = file_bug1300461_redirect.html file_bug1300461_redirect.html^headers^ file_bug1300461_back.html + file_contentpolicy_block_window.html [test_bug13871.html] [test_bug270414.html] @@ -62,3 +63,4 @@ skip-if = toolkit == 'android' #RANDOM [test_triggeringprincipal_window_open.html] [test_triggeringprincipal_parent_iframe_window_open.html] [test_triggeringprincipal_iframe_iframe_window_open.html] +[test_contentpolicy_block_window.html] diff --git a/docshell/test/navigation/test_contentpolicy_block_window.html b/docshell/test/navigation/test_contentpolicy_block_window.html new file mode 100644 index 000000000..651be825c --- /dev/null +++ b/docshell/test/navigation/test_contentpolicy_block_window.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1329288 +--> +<head> + <title>Test for Bug 1329288</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1329288">Mozilla Bug 1329288</a> + + +<!-- have a testlink which we can use for the test to open a new window --> +<a href="http://test1.example.org/tests/docshell/test/navigation/file_contentpolicy_block_window.html" + target="_blank" + id="testlink">This is a link</a> + +<script class="testbody" type="text/javascript"> +/* + * Description of the test: + * The test tries to open a new window and makes sure that a registered contentPolicy + * gets called with the right (a non null) 'context' for the TYPE_DOCUMENT load. + */ + +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; + +var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); +var componentManager = SpecialPowers.wrap(SpecialPowers.Components).manager + .QueryInterface(Ci.nsIComponentRegistrar); + +// Content policy / factory implementation for the test +var policyID = SpecialPowers.wrap(SpecialPowers.Components).ID("{b80e19d0-878f-d41b-2654-194714a4115c}"); +var policyName = "@mozilla.org/testpolicy;1"; +var policy = { + // nsISupports implementation + QueryInterface: function(iid) { + iid = SpecialPowers.wrap(iid); + if (iid.equals(Ci.nsISupports) || + iid.equals(Ci.nsIFactory) || + iid.equals(Ci.nsIContentPolicy)) + return this; + throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE; + }, + + // nsIFactory implementation + createInstance: function(outer, iid) { + return this.QueryInterface(iid); + }, + + // nsIContentPolicy implementation + shouldLoad: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) { + + if (SpecialPowers.wrap(contentLocation).spec !== document.getElementById("testlink").href) { + // not the URI we are looking for, allow the load + return Ci.nsIContentPolicy.ACCEPT; + } + + is(contentType, Ci.nsIContentPolicy.TYPE_DOCUMENT, + "needs to be type document load"); + ok(context, "context is not allowed to be null"); + ok(context.name.endsWith("test_contentpolicy_block_window.html"), + "context should be the current window"); + + // remove the policy and finish test. + categoryManager.deleteCategoryEntry("content-policy", policyName, false); + + setTimeout(function() { + // Component must be unregistered delayed, otherwise other content + // policy will not be removed from the category correctly + componentManager.unregisterFactory(policyID, policy); + }, 0); + + SimpleTest.finish(); + return Ci.nsIContentPolicy.REJECT_REQUEST; + }, + + shouldProcess: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) { + return Ci.nsIContentPolicy.ACCEPT; + } +} + +policy = SpecialPowers.wrapCallbackObject(policy); +componentManager.registerFactory(policyID, "Test content policy", policyName, policy); +categoryManager.addCategoryEntry("content-policy", policyName, policyName, false, true); + +SimpleTest.waitForExplicitFinish(); + +// now everything is set up, let's start the test +document.getElementById("testlink").click() + +</script> +</body> +</html> |