зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1188538: Ensure every protocol handler sets a valid security flag. r=bholley,mixedpuppy
Differential Revision: https://phabricator.services.mozilla.com/D67496 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
287ee18258
Коммит
3e884ce321
|
@ -54,7 +54,7 @@ add_task(async function test_search_favicon() {
|
|||
search_provider: {
|
||||
name: "Bad Icon",
|
||||
search_url: "https://example.net/",
|
||||
favicon_url: "moz-extension://invalid/iDoNotExist.png",
|
||||
favicon_url: "iDoNotExist.png",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -961,38 +961,22 @@ nsresult nsScriptSecurityManager::CheckLoadURIFlags(
|
|||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
// OK, everyone is allowed to load this, since unflagged handlers are
|
||||
// deprecated but treated as URI_LOADABLE_BY_ANYONE. But check whether we
|
||||
// need to warn. At some point we'll want to make this warning into an
|
||||
// error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
|
||||
rv = NS_URIChainHasFlags(
|
||||
aTargetBaseURI, nsIProtocolHandler::URI_LOADABLE_BY_ANYONE, &hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// NB: we also get here if the base URI is URI_LOADABLE_BY_SUBSUMERS,
|
||||
// and none of the rest of the nested chain of URIs for aTargetURI
|
||||
// prohibits the load, so avoid warning in that case:
|
||||
bool hasSubsumersFlag = false;
|
||||
rv = NS_URIChainHasFlags(aTargetBaseURI,
|
||||
nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
|
||||
&hasSubsumersFlag);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!hasFlags && !hasSubsumersFlag) {
|
||||
nsCOMPtr<nsIStringBundle> bundle = BundleHelper::GetOrCreate();
|
||||
if (bundle) {
|
||||
nsAutoString message;
|
||||
AutoTArray<nsString, 1> formatStrings;
|
||||
CopyASCIItoUTF16(targetScheme, *formatStrings.AppendElement());
|
||||
rv = bundle->FormatStringFromName("ProtocolFlagError", formatStrings,
|
||||
message);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIConsoleService> console(
|
||||
do_GetService("@mozilla.org/consoleservice;1"));
|
||||
NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
|
||||
|
||||
console->LogStringMessage(message.get());
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Everyone is allowed to load this. The case URI_LOADABLE_BY_SUBSUMERS
|
||||
// is handled by the caller which is just delegating to us as a helper.
|
||||
bool hasSubsumersFlag = false;
|
||||
NS_URIChainHasFlags(aTargetBaseURI,
|
||||
nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
|
||||
&hasSubsumersFlag);
|
||||
bool hasLoadableByAnyone = false;
|
||||
NS_URIChainHasFlags(aTargetBaseURI,
|
||||
nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
|
||||
&hasLoadableByAnyone);
|
||||
MOZ_ASSERT(hasLoadableByAnyone || hasSubsumersFlag,
|
||||
"why do we get here and do not have any of the two flags set?");
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -841,6 +841,57 @@ nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
|
|||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Every protocol handler must set one of the five security flags
|
||||
* defined in nsIProtocolHandler - if not - deny the load.
|
||||
*/
|
||||
nsresult nsContentSecurityManager::CheckChannelHasProtocolSecurityFlag(
|
||||
nsIChannel* aChannel) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString scheme;
|
||||
rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
rv = ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t flags;
|
||||
rv = handler->DoGetProtocolFlags(uri, &flags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t securityFlagsSet = 0;
|
||||
if (flags & nsIProtocolHandler::URI_LOADABLE_BY_ANYONE) {
|
||||
securityFlagsSet += 1;
|
||||
}
|
||||
if (flags & nsIProtocolHandler::URI_DANGEROUS_TO_LOAD) {
|
||||
securityFlagsSet += 1;
|
||||
}
|
||||
if (flags & nsIProtocolHandler::URI_IS_UI_RESOURCE) {
|
||||
securityFlagsSet += 1;
|
||||
}
|
||||
if (flags & nsIProtocolHandler::URI_IS_LOCAL_FILE) {
|
||||
securityFlagsSet += 1;
|
||||
}
|
||||
if (flags & nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS) {
|
||||
securityFlagsSet += 1;
|
||||
}
|
||||
|
||||
// Ensure that only "1" valid security flags is set.
|
||||
if (securityFlagsSet == 1) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "protocol must use one valid security flag");
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on the security flags provided in the loadInfo of the channel,
|
||||
* doContentSecurityCheck() performs the following content security checks
|
||||
|
@ -870,6 +921,9 @@ nsresult nsContentSecurityManager::doContentSecurityCheck(
|
|||
nsresult rv = CheckAllowLoadInSystemPrivilegedContext(aChannel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = CheckChannelHasProtocolSecurityFlag(aChannel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if dealing with a redirected channel then we have already installed
|
||||
// streamlistener and redirect proxies and so we are done.
|
||||
if (loadInfo->GetInitialSecurityCheckDone()) {
|
||||
|
|
|
@ -42,6 +42,7 @@ class nsContentSecurityManager : public nsIContentSecurityManager,
|
|||
static nsresult CheckChannel(nsIChannel* aChannel);
|
||||
static nsresult CheckFTPSubresourceLoad(nsIChannel* aChannel);
|
||||
static nsresult CheckAllowLoadInSystemPrivilegedContext(nsIChannel* aChannel);
|
||||
static nsresult CheckChannelHasProtocolSecurityFlag(nsIChannel* aChannel);
|
||||
|
||||
virtual ~nsContentSecurityManager() = default;
|
||||
};
|
||||
|
|
|
@ -171,16 +171,18 @@ interface nsIProtocolHandler : nsISupports
|
|||
* | |
|
||||
* +-------------------------------------------------------------------+
|
||||
*
|
||||
* * URI_LOADABLE_BY_ANYONE
|
||||
* * URI_DANGEROUS_TO_LOAD
|
||||
* * URI_IS_UI_RESOURCE
|
||||
* * URI_IS_LOCAL_FILE
|
||||
* * URI_LOADABLE_BY_SUBSUMERS
|
||||
*
|
||||
* These flags are used to determine who is allowed to load URIs for this
|
||||
* protocol. Note that if a URI is nested, only the flags for the
|
||||
* innermost URI matter. See nsINestedURI.
|
||||
*
|
||||
* If none of these five flags are set, the URI must be treated as if it
|
||||
* had the URI_LOADABLE_BY_ANYONE flag set, for compatibility with protocol
|
||||
* handlers written against Gecko 1.8 or earlier. In this case, there may
|
||||
* be run-time warning messages indicating that a "default insecure"
|
||||
* assumption is being made. At some point in the futures (Mozilla 2.0,
|
||||
* most likely), these warnings will become errors.
|
||||
* If none of these five flags are set, the ContentSecurityManager will
|
||||
* deny the load.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -390,6 +390,10 @@ nsresult ExtensionProtocolHandler::GetFlagsForURI(nsIURI* aURI,
|
|||
if (!policy->PrivateBrowsingAllowed()) {
|
||||
flags |= URI_DISALLOW_IN_PRIVATE_CONTEXT;
|
||||
}
|
||||
} else {
|
||||
// In case there is no policy, then default to treating moz-extension URIs
|
||||
// as unsafe and generally only allow chrome: to load such.
|
||||
flags |= URI_DANGEROUS_TO_LOAD;
|
||||
}
|
||||
|
||||
*aFlags = flags;
|
||||
|
|
Загрузка…
Ссылка в новой задаче