From e66562aa8b7bed7f194355eb3953ead052e2aa48 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 30 Apr 2018 21:00:21 +0200 Subject: Bug 1182569: Use AsyncOpen2 for docshell loads --- dom/jsurl/nsJSProtocolHandler.cpp | 49 ++++++++++++++------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) (limited to 'dom') diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index cdb63f890..90171db10 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -36,7 +36,6 @@ #include "nsIContentViewer.h" #include "nsIXPConnect.h" #include "nsContentUtils.h" -#include "nsNullPrincipal.h" #include "nsJSUtils.h" #include "nsThreadUtils.h" #include "nsIScriptChannel.h" @@ -336,7 +335,7 @@ public: NS_FORWARD_SAFE_NSIPROPERTYBAG(mPropertyBag) NS_FORWARD_SAFE_NSIPROPERTYBAG2(mPropertyBag) - nsresult Init(nsIURI *aURI); + nsresult Init(nsIURI *aURI, nsILoadInfo* aLoadInfo); // Actually evaluate the script. void EvaluateScript(); @@ -354,17 +353,16 @@ protected: nsCOMPtr mStreamChannel; nsCOMPtr mPropertyBag; nsCOMPtr mListener; // Our final listener - nsCOMPtr mContext; // The context passed to AsyncOpen nsCOMPtr mOriginalInnerWindow; // The inner window our load // started against. - // If we blocked onload on a document in AsyncOpen, this is the document we + // If we blocked onload on a document in AsyncOpen2, this is the document we // did it on. nsCOMPtr mDocumentOnloadBlockedOn; nsresult mStatus; // Our status nsLoadFlags mLoadFlags; - nsLoadFlags mActualLoadFlags; // See AsyncOpen + nsLoadFlags mActualLoadFlags; // See AsyncOpen2 RefPtr mIOThunk; PopupControlState mPopupState; @@ -404,7 +402,7 @@ nsresult nsJSChannel::StopAll() return rv; } -nsresult nsJSChannel::Init(nsIURI *aURI) +nsresult nsJSChannel::Init(nsIURI* aURI, nsILoadInfo* aLoadInfo) { RefPtr jsURI; nsresult rv = aURI->QueryInterface(kJSURICID, @@ -418,21 +416,13 @@ nsresult nsJSChannel::Init(nsIURI *aURI) // Remember, until AsyncOpen is called, the script will not be evaluated // and the underlying Input Stream will not be created... nsCOMPtr channel; - - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); - - // If the resultant script evaluation actually does return a value, we - // treat it as html. - // The following channel is never openend, so it does not matter what - // securityFlags we pass; let's follow the principle of least privilege. - rv = NS_NewInputStreamChannel(getter_AddRefs(channel), - aURI, - mIOThunk, - nullPrincipal, - nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED, - nsIContentPolicy::TYPE_OTHER, - NS_LITERAL_CSTRING("text/html")); - if (NS_FAILED(rv)) return rv; + rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), + aURI, + mIOThunk, + NS_LITERAL_CSTRING("text/html"), + EmptyCString(), + aLoadInfo); + NS_ENSURE_SUCCESS(rv, rv); rv = mIOThunk->Init(aURI); if (NS_SUCCEEDED(rv)) { @@ -563,6 +553,7 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) "security flags in loadInfo but asyncOpen2() not called"); } #endif + MOZ_RELEASE_ASSERT(!aContext, "please call AsyncOpen2()"); NS_ENSURE_ARG(aListener); @@ -584,7 +575,6 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) } mListener = aListener; - mContext = aContext; mIsActive = true; @@ -655,7 +645,7 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) return mStatus; } - // We're returning success from asyncOpen(), but we didn't open a + // We're returning success from asyncOpen2(), but we didn't open a // stream channel. We'll have to notify ourselves, but make sure to do // it asynchronously. method = &nsJSChannel::NotifyListener; @@ -772,7 +762,7 @@ nsJSChannel::EvaluateScript() return; } - mStatus = mStreamChannel->AsyncOpen(this, mContext); + mStatus = mStreamChannel->AsyncOpen2(this); if (NS_SUCCEEDED(mStatus)) { // mStreamChannel will call OnStartRequest and OnStopRequest on // us, so we'll be sure to call them on our listener. @@ -800,8 +790,8 @@ nsJSChannel::EvaluateScript() void nsJSChannel::NotifyListener() { - mListener->OnStartRequest(this, mContext); - mListener->OnStopRequest(this, mContext, mStatus); + mListener->OnStartRequest(this, nullptr); + mListener->OnStopRequest(this, nullptr, mStatus); CleanupStrongRefs(); } @@ -810,7 +800,6 @@ void nsJSChannel::CleanupStrongRefs() { mListener = nullptr; - mContext = nullptr; mOriginalInnerWindow = nullptr; if (mDocumentOnloadBlockedOn) { mDocumentOnloadBlockedOn->UnblockOnload(false); @@ -1240,11 +1229,7 @@ nsJSProtocolHandler::NewChannel2(nsIURI* uri, return NS_ERROR_OUT_OF_MEMORY; } - rv = channel->Init(uri); - NS_ENSURE_SUCCESS(rv, rv); - - // set the loadInfo on the new channel - rv = channel->SetLoadInfo(aLoadInfo); + rv = channel->Init(uri, aLoadInfo); NS_ENSURE_SUCCESS(rv, rv); if (NS_SUCCEEDED(rv)) { -- cgit v1.2.3 From f799598d65a59660ef67ed965849853c8e5ca1e6 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 30 Apr 2018 21:04:56 +0200 Subject: Bug 1182569: Update ContentSecurityManager to handle docshell loads --- dom/security/nsContentSecurityManager.cpp | 81 ++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 17 deletions(-) (limited to 'dom') diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 0cc4933fe..70e574445 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -10,6 +10,9 @@ #include "nsIStreamListener.h" #include "nsIDocument.h" #include "nsMixedContentBlocker.h" +#include "nsCDefaultURIFixup.h" +#include "nsIURIFixup.h" +#include "nsINestedURI.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/TabChild.h" @@ -244,10 +247,6 @@ DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo, static nsresult DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) { - nsCOMPtr uri; - nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); - nsContentPolicyType contentPolicyType = aLoadInfo->GetExternalContentPolicyType(); nsContentPolicyType internalContentPolicyType = @@ -255,12 +254,24 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) nsCString mimeTypeGuess; nsCOMPtr requestingContext = nullptr; -#ifdef DEBUG - // Don't enforce TYPE_DOCUMENT assertions for loads - // initiated by javascript tests. - bool skipContentTypeCheck = false; - skipContentTypeCheck = Preferences::GetBool("network.loadinfo.skip_type_assertion"); -#endif + nsCOMPtr uri; + nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + + if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT || + contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) { + // TYPE_DOCUMENT and TYPE_SUBDOCUMENT loads might potentially + // be wyciwyg:// channels. Let's fix up the URI so we can + // perform proper security checks. + nsCOMPtr urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv) && urifixup) { + nsCOMPtr fixedURI; + rv = urifixup->CreateExposableURI(uri, getter_AddRefs(fixedURI)); + if (NS_SUCCEEDED(rv)) { + uri = fixedURI; + } + } + } switch(contentPolicyType) { case nsIContentPolicy::TYPE_OTHER: { @@ -294,16 +305,14 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) } case nsIContentPolicy::TYPE_DOCUMENT: { - MOZ_ASSERT(skipContentTypeCheck || false, "contentPolicyType not supported yet"); + mimeTypeGuess = EmptyCString(); + requestingContext = aLoadInfo->LoadingNode(); break; } case nsIContentPolicy::TYPE_SUBDOCUMENT: { mimeTypeGuess = NS_LITERAL_CSTRING("text/html"); requestingContext = aLoadInfo->LoadingNode(); - MOZ_ASSERT(!requestingContext || - requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE, - "type_subdocument requires requestingContext of type Document"); break; } @@ -470,18 +479,32 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) MOZ_ASSERT(false, "can not perform security check without a valid contentType"); } + // For document loads we use the triggeringPrincipal as the originPrincipal. + // Note the the loadingPrincipal for loads of TYPE_DOCUMENT is a nullptr. + nsCOMPtr principal = + (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT || + contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) + ? aLoadInfo->TriggeringPrincipal() + : aLoadInfo->LoadingPrincipal(); + int16_t shouldLoad = nsIContentPolicy::ACCEPT; rv = NS_CheckContentLoadPolicy(internalContentPolicyType, uri, - aLoadInfo->LoadingPrincipal(), + principal, requestingContext, mimeTypeGuess, nullptr, //extra, &shouldLoad, nsContentUtils::GetContentPolicy(), nsContentUtils::GetSecurityManager()); - NS_ENSURE_SUCCESS(rv, rv); - if (NS_CP_REJECTED(shouldLoad)) { + + if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { + if ((NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) && + (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT || + contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT)) { + // for docshell loads we might have to return SHOW_ALT. + return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT; + } return NS_ERROR_CONTENT_BLOCKED; } @@ -629,6 +652,30 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); + nsContentPolicyType contentPolicyType = + loadInfo->GetExternalContentPolicyType(); + + if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT || + contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) { + // query the nested URI for security checks like in the case of view-source + nsCOMPtr nestedURI = do_QueryInterface(uri); + if (nestedURI) { + nestedURI->GetInnerURI(getter_AddRefs(uri)); + } + + // TYPE_DOCUMENT and TYPE_SUBDOCUMENT loads might potentially + // be wyciwyg:// channels. Let's fix up the URI so we can + // perform proper security checks. + nsCOMPtr urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv) && urifixup) { + nsCOMPtr fixedURI; + rv = urifixup->CreateExposableURI(uri, getter_AddRefs(fixedURI)); + if (NS_SUCCEEDED(rv)) { + uri = fixedURI; + } + } + } + // Handle cookie policies uint32_t cookiePolicy = loadInfo->GetCookiePolicy(); if (cookiePolicy == nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) { -- cgit v1.2.3 From d45c25971c084ba4afb38cec530f789969d6a338 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 30 Apr 2018 22:09:55 +0200 Subject: Bug 1182569 - Skip security check for plugins using newstream attribute --- dom/base/nsContentUtils.cpp | 2 +- dom/plugins/base/nsPluginInstanceOwner.cpp | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'dom') diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index bc8cea35a..76463df16 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -5104,7 +5104,7 @@ nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext, handler->OnLinkClick(aContent, aLinkURI, fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(), - fileName, nullptr, nullptr, aIsTrusted); + fileName, nullptr, nullptr, aIsTrusted, aContent->NodePrincipal()); } } diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 291ae576d..d5b1eb9ea 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -535,16 +535,6 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); - if (aDoCheckLoadURIChecks) { - nsCOMPtr secMan( - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); - NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE); - - rv = secMan->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri, - nsIScriptSecurityManager::STANDARD); - NS_ENSURE_SUCCESS(rv, rv); - } - nsCOMPtr headersDataStream; if (aPostStream && aHeadersData) { if (!aHeadersDataLen) @@ -563,8 +553,21 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, Preferences::GetInt("privacy.popups.disable_from_plugins"); nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups); + + // if security checks (in particular CheckLoadURIWithPrincipal) needs + // to be skipped we are creating a codebasePrincipal to make sure + // that security check succeeds. Please note that we do not want to + // fall back to using the systemPrincipal, because that would also + // bypass ContentPolicy checks which should still be enforced. + nsCOMPtr triggeringPrincipal; + if (!aDoCheckLoadURIChecks) { + mozilla::PrincipalOriginAttributes attrs = + BasePrincipal::Cast(content->NodePrincipal())->OriginAttributesRef(); + triggeringPrincipal = BasePrincipal::CreateCodebasePrincipal(uri, attrs); + } + rv = lh->OnLinkClick(content, uri, unitarget.get(), NullString(), - aPostStream, headersDataStream, true); + aPostStream, headersDataStream, true, triggeringPrincipal); return rv; } -- cgit v1.2.3 From b8e6315292839cd8a3263fec9d69555b7202c781 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 30 Apr 2018 22:12:53 +0200 Subject: Bug 1182569: Update tests when converting docshell loads to use AynscOpen2 --- dom/base/test/file_simplecontentpolicy.js | 1 - dom/plugins/test/mochitest/test_bug813906.html | 22 ++++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'dom') diff --git a/dom/base/test/file_simplecontentpolicy.js b/dom/base/test/file_simplecontentpolicy.js index 1f9606c49..2727b9530 100644 --- a/dom/base/test/file_simplecontentpolicy.js +++ b/dom/base/test/file_simplecontentpolicy.js @@ -39,7 +39,6 @@ var policy = { { // Remember last content type seen for the test url if (contentLocation.spec.endsWith(urlSuffix)) { - assert.ok(frame === browserElement, "correct element"); sendAsyncMessage("shouldLoad", {contentType: contentType, isTopLevel: isTopLevel}); return Ci.nsIContentPolicy.REJECT_REQUEST; } diff --git a/dom/plugins/test/mochitest/test_bug813906.html b/dom/plugins/test/mochitest/test_bug813906.html index 04c34daaf..d18dbbff2 100644 --- a/dom/plugins/test/mochitest/test_bug813906.html +++ b/dom/plugins/test/mochitest/test_bug813906.html @@ -18,21 +18,35 @@ function f() {