author | Jonas Sicking <jonas@sicking.cc> |
Sun, 06 Dec 2015 18:33:14 -0500 (2015-12-06) | |
changeset 275834 | e772b5154e0cc25c61307f812d5185296430a07e |
parent 275833 | 0aa2be7bf89908f74cf1aeaf417e55775857ea34 |
child 275835 | dd7c08e6c57236263743eca64d2a1578eccbe569 |
push id | 29768 |
push user | cbook@mozilla.com |
push date | Mon, 07 Dec 2015 13:16:29 +0000 (2015-12-07) |
treeherder | mozilla-central@59bc3c7a83de [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ckerschb |
bugs | 1226909 |
milestone | 45.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -426,17 +426,16 @@ nsScriptSecurityManager::IsSystemPrincip // nsScriptSecurityManager // ///////////////////////////// //////////////////////////////////// // Methods implementing ISupports // //////////////////////////////////// NS_IMPL_ISUPPORTS(nsScriptSecurityManager, nsIScriptSecurityManager, - nsIChannelEventSink, nsIObserver) /////////////////////////////////////////////////// // Methods implementing nsIScriptSecurityManager // /////////////////////////////////////////////////// ///////////////// Security Checks ///////////////// @@ -1231,51 +1230,16 @@ nsScriptSecurityManager::CanGetService(J nsAutoCString errorMsg("Permission denied to get service. CID="); char cidStr[NSID_LENGTH]; aCID.ToProvidedString(cidStr); errorMsg.Append(cidStr); SetPendingException(cx, errorMsg.get()); return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED; } -///////////////////////////////////////////// -// Method implementing nsIChannelEventSink // -///////////////////////////////////////////// -NS_IMETHODIMP -nsScriptSecurityManager::AsyncOnChannelRedirect(nsIChannel* oldChannel, - nsIChannel* newChannel, - uint32_t redirFlags, - nsIAsyncVerifyRedirectCallback *cb) -{ - nsCOMPtr<nsIPrincipal> oldPrincipal; - GetChannelResultPrincipal(oldChannel, getter_AddRefs(oldPrincipal)); - - nsCOMPtr<nsIURI> newURI; - newChannel->GetURI(getter_AddRefs(newURI)); - nsCOMPtr<nsIURI> newOriginalURI; - newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); - - NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI); - - const uint32_t flags = - nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT | - nsIScriptSecurityManager::DISALLOW_SCRIPT; - nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags); - if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) { - rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags); - } - - if (NS_FAILED(rv)) - return rv; - - cb->OnRedirectVerifyCallback(NS_OK); - return NS_OK; -} - - ///////////////////////////////////// // Method implementing nsIObserver // ///////////////////////////////////// const char sJSEnabledPrefName[] = "javascript.enabled"; const char sFileOriginPolicyPrefName[] = "security.fileuri.strict_origin_policy"; static const char* kObservedPrefs[] = {
--- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -9,17 +9,16 @@ #include "nsIScriptSecurityManager.h" #include "nsIAddonPolicyService.h" #include "mozilla/Maybe.h" #include "nsIAddonPolicyService.h" #include "nsIPrincipal.h" #include "nsCOMPtr.h" -#include "nsIChannelEventSink.h" #include "nsIObserver.h" #include "nsServiceManagerUtils.h" #include "plstr.h" #include "js/TypeDecls.h" #include <stdint.h> class nsCString; @@ -34,27 +33,25 @@ class PrincipalOriginAttributes; ///////////////////////////// // nsScriptSecurityManager // ///////////////////////////// #define NS_SCRIPTSECURITYMANAGER_CID \ { 0x7ee2a4c0, 0x4b93, 0x17d3, \ { 0xba, 0x18, 0x00, 0x60, 0xb0, 0xf1, 0x99, 0xa2 }} class nsScriptSecurityManager final : public nsIScriptSecurityManager, - public nsIChannelEventSink, public nsIObserver { public: static void Shutdown(); NS_DEFINE_STATIC_CID_ACCESSOR(NS_SCRIPTSECURITYMANAGER_CID) NS_DECL_ISUPPORTS NS_DECL_NSISCRIPTSECURITYMANAGER - NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSIOBSERVER static nsScriptSecurityManager* GetScriptSecurityManager(); // Invoked exactly once, by XPConnect. static void InitStatics();
--- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -3,17 +3,19 @@ #include "nsIStreamListener.h" #include "nsILoadInfo.h" #include "nsContentUtils.h" #include "nsCORSListenerProxy.h" #include "nsIStreamListener.h" #include "mozilla/dom/Element.h" -NS_IMPL_ISUPPORTS(nsContentSecurityManager, nsIContentSecurityManager) +NS_IMPL_ISUPPORTS(nsContentSecurityManager, + nsIContentSecurityManager, + nsIChannelEventSink) static nsresult ValidateSecurityFlags(nsILoadInfo* aLoadInfo) { nsSecurityFlags securityMode = aLoadInfo->GetSecurityMode(); if (securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS && securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED && @@ -337,83 +339,145 @@ nsContentSecurityManager::doContentSecur NS_ENSURE_ARG(aChannel); nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); if (!loadInfo) { MOZ_ASSERT(false, "channel needs to have loadInfo to perform security checks"); return NS_ERROR_UNEXPECTED; } + // if dealing with a redirected channel then we have already installed + // streamlistener and redirect proxies and so we are done. + if (loadInfo->GetInitialSecurityCheckDone()) { + return NS_OK; + } + // make sure that only one of the five security flags is set in the loadinfo // e.g. do not require same origin and allow cross origin at the same time nsresult rv = ValidateSecurityFlags(loadInfo); NS_ENSURE_SUCCESS(rv, rv); - // lets store the initialSecurityCheckDone flag which indicates whether the channel - // was initialy evaluated by the contentSecurityManager. Once the inital - // asyncOpen() of the channel went through the contentSecurityManager then - // redirects do not have perform all the security checks, e.g. no reason - // to setup CORS again. - bool initialSecurityCheckDone = loadInfo->GetInitialSecurityCheckDone(); - - // now lets set the initalSecurityFlag for subsequent calls - rv = loadInfo->SetInitialSecurityCheckDone(true); - NS_ENSURE_SUCCESS(rv, rv); - // since aChannel was openend using asyncOpen2() we have to make sure // that redirects of that channel also get openend using asyncOpen2() // please note that some implementations of ::AsyncOpen2 might already // have set that flag to true (e.g. nsViewSourceChannel) in which case // we just set the flag again. rv = loadInfo->SetEnforceSecurity(true); NS_ENSURE_SUCCESS(rv, rv); + if (loadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) { + rv = DoCORSChecks(aChannel, loadInfo, aInAndOutListener); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + rv = CheckChannel(aChannel); + NS_ENSURE_SUCCESS(rv, rv); + } + nsCOMPtr<nsIURI> finalChannelURI; rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalChannelURI)); NS_ENSURE_SUCCESS(rv, rv); + // Perform all ContentPolicy checks (MixedContent, CSP, ...) + rv = DoContentSecurityChecks(finalChannelURI, loadInfo); + NS_ENSURE_SUCCESS(rv, rv); + + // now lets set the initalSecurityFlag for subsequent calls + rv = loadInfo->SetInitialSecurityCheckDone(true); + NS_ENSURE_SUCCESS(rv, rv); + + // all security checks passed - lets allow the load + return NS_OK; +} + +NS_IMETHODIMP +nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel, + nsIChannel* aNewChannel, + uint32_t aRedirFlags, + nsIAsyncVerifyRedirectCallback *aCb) +{ + nsCOMPtr<nsILoadInfo> loadInfo = aOldChannel->GetLoadInfo(); + // Are we enforcing security using LoadInfo? + if (loadInfo && loadInfo->GetEnforceSecurity()) { + nsresult rv = CheckChannel(aNewChannel); + if (NS_FAILED(rv)) { + aOldChannel->Cancel(rv); + return rv; + } + } + + // Also verify that the redirecting server is allowed to redirect to the + // given URI + nsCOMPtr<nsIPrincipal> oldPrincipal; + nsContentUtils::GetSecurityManager()-> + GetChannelResultPrincipal(aOldChannel, getter_AddRefs(oldPrincipal)); + + nsCOMPtr<nsIURI> newURI; + aNewChannel->GetURI(getter_AddRefs(newURI)); + nsCOMPtr<nsIURI> newOriginalURI; + aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); + + NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI); + + const uint32_t flags = + nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT | + nsIScriptSecurityManager::DISALLOW_SCRIPT; + nsresult rv = nsContentUtils::GetSecurityManager()-> + CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags); + if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) { + rv = nsContentUtils::GetSecurityManager()-> + CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags); + } + NS_ENSURE_SUCCESS(rv, rv); + + aCb->OnRedirectVerifyCallback(NS_OK); + return NS_OK; +} + +/* + * Check that this channel passes all security checks. Returns an error code + * if this requesst should not be permitted. + */ +nsresult +nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) +{ + nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); + MOZ_ASSERT(loadInfo); + + // CORS mode is handled by nsCORSListenerProxy nsSecurityFlags securityMode = loadInfo->GetSecurityMode(); + if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) { + return NS_OK; + } + + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + // if none of the REQUIRE_SAME_ORIGIN flags are set, then SOP does not apply if ((securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS) || (securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED)) { - rv = DoSOPChecks(finalChannelURI, loadInfo); + rv = DoSOPChecks(uri, loadInfo); NS_ENSURE_SUCCESS(rv, rv); } - // if dealing with a redirected channel then we only enforce SOP - // and can return at this point. - if (initialSecurityCheckDone) { - return NS_OK; - } - if ((securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS) || (securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL)) { // Please note that DoCheckLoadURIChecks should only be enforced for // cross origin requests. If the flag SEC_REQUIRE_CORS_DATA_INHERITS is set // within the loadInfo, then then CheckLoadURIWithPrincipal is performed // within nsCorsListenerProxy - rv = DoCheckLoadURIChecks(finalChannelURI, loadInfo); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) { - rv = DoCORSChecks(aChannel, loadInfo, aInAndOutListener); + rv = DoCheckLoadURIChecks(uri, loadInfo); NS_ENSURE_SUCCESS(rv, rv); } - // Perform all ContentPolicy checks (MixedContent, CSP, ...) - rv = DoContentSecurityChecks(finalChannelURI, loadInfo); - NS_ENSURE_SUCCESS(rv, rv); - - // all security checks passed - lets allow the load return NS_OK; } - // ==== nsIContentSecurityManager implementation ===== NS_IMETHODIMP nsContentSecurityManager::PerformSecurityCheck(nsIChannel* aChannel, nsIStreamListener* aStreamListener, nsIStreamListener** outStreamListener) { nsCOMPtr<nsIStreamListener> inAndOutListener = aStreamListener;
--- a/dom/security/nsContentSecurityManager.h +++ b/dom/security/nsContentSecurityManager.h @@ -4,34 +4,39 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsContentSecurityManager_h___ #define nsContentSecurityManager_h___ #include "nsIContentSecurityManager.h" #include "nsIChannel.h" +#include "nsIChannelEventSink.h" class nsIStreamListener; #define NS_CONTENTSECURITYMANAGER_CONTRACTID "@mozilla.org/contentsecuritymanager;1" // cdcc1ab8-3cea-4e6c-a294-a651fa35227f #define NS_CONTENTSECURITYMANAGER_CID \ { 0xcdcc1ab8, 0x3cea, 0x4e6c, \ { 0xa2, 0x94, 0xa6, 0x51, 0xfa, 0x35, 0x22, 0x7f } } class nsContentSecurityManager : public nsIContentSecurityManager + , public nsIChannelEventSink { public: NS_DECL_ISUPPORTS NS_DECL_NSICONTENTSECURITYMANAGER + NS_DECL_NSICHANNELEVENTSINK nsContentSecurityManager() {} static nsresult doContentSecurityCheck(nsIChannel* aChannel, nsCOMPtr<nsIStreamListener>& aInAndOutListener); private: + static nsresult CheckChannel(nsIChannel* aChannel); + virtual ~nsContentSecurityManager() {} }; #endif /* nsContentSecurityManager_h___ */
--- a/dom/security/test/csp/file_redirects_main.html +++ b/dom/security/test/csp/file_redirects_main.html @@ -13,17 +13,16 @@ var page = "/tests/dom/security/test/csp var tests = { "font-src": thisSite+page+"?testid=font-src", "frame-src": thisSite+page+"?testid=frame-src", "img-src": thisSite+page+"?testid=img-src", "media-src": thisSite+page+"?testid=media-src", "object-src": thisSite+page+"?testid=object-src", "script-src": thisSite+page+"?testid=script-src", "style-src": thisSite+page+"?testid=style-src", - "worker": thisSite+page+"?testid=worker", "xhr-src": thisSite+page+"?testid=xhr-src", "from-worker": thisSite+page+"?testid=from-worker", "from-blob-worker": thisSite+page+"?testid=from-blob-worker", "img-src-from-css": thisSite+page+"?testid=img-src-from-css", }; var container = document.getElementById("container");
--- a/dom/security/test/csp/file_redirects_page.sjs +++ b/dom/security/test/csp/file_redirects_page.sjs @@ -9,23 +9,18 @@ function handleRequest(request, response }); response.setHeader("Cache-Control", "no-cache", false); response.setHeader("Content-Type", "text/html", false); var resource = "/tests/dom/security/test/csp/file_redirects_resource.sjs"; // CSP header value - var additional = "" - if (query['testid'] == "worker") { - additional = "; script-src 'self' 'unsafe-inline'"; - } response.setHeader("Content-Security-Policy", - "default-src 'self' blob: ; style-src 'self' 'unsafe-inline'" + additional, - false); + "default-src 'self' blob: ; style-src 'self' 'unsafe-inline'", false); // downloadable font that redirects to another site if (query["testid"] == "font-src") { var resp = '<style type="text/css"> @font-face { font-family:' + '"Redirecting Font"; src: url("' + resource + '?res=font&redir=other&id=font-src-redir")} #test{font-family:' + '"Redirecting Font"}</style></head><body>' + '<div id="test">test</div></body>'; @@ -64,22 +59,16 @@ function handleRequest(request, response } // external stylesheet that redirects to another site if (query["testid"] == "style-src") { response.write('<link rel="stylesheet" type="text/css" href="'+resource+'?res=style&redir=other&id=style-src-redir"></link>'); return; } - // worker script resource that redirects to another site - if (query["testid"] == "worker") { - response.write('<script>var worker = new Worker("'+resource+'?res=worker&redir=other&id=worker-redir");</script>'); - return; - } - // script that XHR's to a resource that redirects to another site if (query["testid"] == "xhr-src") { response.write('<script src="'+resource+'?res=xhr"></script>'); return; } // for bug949706 if (query["testid"] == "img-src-from-css") {
--- a/dom/security/test/csp/file_redirects_resource.sjs +++ b/dom/security/test/csp/file_redirects_resource.sjs @@ -80,23 +80,16 @@ function handleRequest(request, response // external stylesheet if (query["res"] == "style") { response.setHeader("Content-Type", "text/css", false); response.write("css data..."); return; } - // web worker resource - if (query["res"] == "worker") { - response.setHeader("Content-Type", "application/javascript", false); - response.write("worker script data..."); - return; - } - // internal stylesheet that loads an image from an external site if (query["res"] == "cssLoader") { let bgURL = thisSite + resource + '?redir=other&res=image&id=' + query["id"]; response.setHeader("Content-Type", "text/css", false); response.write("body { background:url('" + bgURL + "'); }"); return; }
--- a/dom/security/test/csp/test_redirects.html +++ b/dom/security/test/csp/test_redirects.html @@ -77,24 +77,22 @@ var testExpectedResults = { "font-src": "media-src": true, "media-src-redir": false, "object-src": true, "object-src-redir": false, "script-src": true, "script-src-redir": false, "style-src": true, "style-src-redir": false, - "worker": true, - "worker-redir": false, "xhr-src": true, "xhr-src-redir": false, "from-worker": true, - "script-src-redir-from-worker": true, /* redir is allowed since policy isn't inherited */ - "xhr-src-redir-from-worker": true, /* redir is allowed since policy isn't inherited */ - "fetch-src-redir-from-worker": true, /* redir is allowed since policy isn't inherited */ + "script-src-redir-from-worker": true, // redir is allowed since policy isn't inherited + "xhr-src-redir-from-worker": true, // redir is allowed since policy isn't inherited + "fetch-src-redir-from-worker": true, // redir is allowed since policy isn't inherited "from-blob-worker": true, "script-src-redir-from-blob-worker": false, "xhr-src-redir-from-blob-worker": false, "fetch-src-redir-from-blob-worker": false, "img-src-from-css": true, "img-src-redir-from-css": false, };
--- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -1280,17 +1280,16 @@ static const mozilla::Module::ContractID { CSPSERVICE_CONTRACTID, &kCSPSERVICE_CID }, { NS_CSPCONTEXT_CONTRACTID, &kNS_CSPCONTEXT_CID }, { NS_MIXEDCONTENTBLOCKER_CONTRACTID, &kNS_MIXEDCONTENTBLOCKER_CID }, { NS_EVENTLISTENERSERVICE_CONTRACTID, &kNS_EVENTLISTENERSERVICE_CID }, { NS_GLOBALMESSAGEMANAGER_CONTRACTID, &kNS_GLOBALMESSAGEMANAGER_CID }, { NS_PARENTPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_PARENTPROCESSMESSAGEMANAGER_CID }, { NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_CHILDPROCESSMESSAGEMANAGER_CID }, { NS_SCRIPTSECURITYMANAGER_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID }, - { NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID }, { NS_PRINCIPAL_CONTRACTID, &kNS_PRINCIPAL_CID }, { NS_SYSTEMPRINCIPAL_CONTRACTID, &kNS_SYSTEMPRINCIPAL_CID }, { NS_NULLPRINCIPAL_CONTRACTID, &kNS_NULLPRINCIPAL_CID }, { NS_DEVICE_SENSORS_CONTRACTID, &kNS_DEVICE_SENSORS_CID }, #ifndef MOZ_WIDGET_GONK #if defined(ANDROID) { "@mozilla.org/widget/hapticfeedback;1", &kNS_HAPTICFEEDBACK_CID }, #endif
--- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -45,16 +45,17 @@ #include "mozilla/LoadInfo.h" #include "mozilla/net/NeckoCommon.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" #include "mozilla/net/DNS.h" #include "CaptivePortalService.h" #include "ClosingService.h" #include "ReferrerPolicy.h" +#include "nsContentSecurityManager.h" #ifdef MOZ_WIDGET_GONK #include "nsINetworkManager.h" #include "nsINetworkInterface.h" #endif #if defined(XP_WIN) #include "nsNativeConnectionHelper.h" @@ -410,18 +411,21 @@ nsresult nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags, nsAsyncRedirectVerifyHelper *helper) { // If a redirect to a local network address occurs, then chances are we // are in a captive portal, so we trigger a recheck. RecheckCaptivePortalIfLocalRedirect(newChan); + // This is silly. I wish there was a simpler way to get at the global + // reference of the contentSecurityManager. But it lives in the XPCOM + // service registry. nsCOMPtr<nsIChannelEventSink> sink = - do_GetService(NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID); + do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); if (sink) { nsresult rv = helper->DelegateOnChannelRedirect(sink, oldChan, newChan, flags); if (NS_FAILED(rv)) return rv; } // Finally, our category
--- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -1000,25 +1000,16 @@ { 0x86, 0xf8, 0x63, 0xf2, 0x25, 0xb9, 0x40, 0xae } \ } /****************************************************************************** * Contracts that can be implemented by necko users. */ /** - * This contract ID will be gotten as a service and gets the opportunity to look - * at and veto all redirects that are processed by necko. - * - * Must implement nsIChannelEventSink - */ -#define NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID \ - "@mozilla.org/netwerk/global-channel-event-sink;1" - -/** * This contract ID will be gotten as a service implementing nsINetworkLinkService * and monitored by IOService for automatic online/offline management. * * Must implement nsINetworkLinkService */ #define NS_NETWORK_LINK_SERVICE_CONTRACTID \ "@mozilla.org/network/network-link-service;1"