Bug 1172165 - check all nested URI schemes in CAPS. Make view-source dangerous to load, and about: URIs use per-URI flags so they keep working, r=bz

Also, add an opt-out for crashtest/reftest for the view-source thing so they don't all break, r=bz
This commit is contained in:
Gijs Kruitbosch 2015-12-11 08:06:41 -05:00
parent eab0e329eb
commit 5364db3fb3
8 changed files with 126 additions and 7 deletions

View File

@ -629,6 +629,42 @@ EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase)
}
}
static bool
AllSchemesMatch(nsIURI* aURI, nsIURI* aOtherURI)
{
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
nsCOMPtr<nsINestedURI> nestedOtherURI = do_QueryInterface(aOtherURI);
auto stringComparator = nsCaseInsensitiveCStringComparator();
if (!nestedURI && !nestedOtherURI) {
// Neither of the URIs is nested, compare their schemes directly:
nsAutoCString scheme, otherScheme;
aURI->GetScheme(scheme);
aOtherURI->GetScheme(otherScheme);
return scheme.Equals(otherScheme, stringComparator);
}
while (nestedURI && nestedOtherURI) {
nsCOMPtr<nsIURI> currentURI = do_QueryInterface(nestedURI);
nsCOMPtr<nsIURI> currentOtherURI = do_QueryInterface(nestedOtherURI);
nsAutoCString scheme, otherScheme;
currentURI->GetScheme(scheme);
currentOtherURI->GetScheme(otherScheme);
if (!scheme.Equals(otherScheme, stringComparator)) {
return false;
}
nestedURI->GetInnerURI(getter_AddRefs(currentURI));
nestedOtherURI->GetInnerURI(getter_AddRefs(currentOtherURI));
nestedURI = do_QueryInterface(currentURI);
nestedOtherURI = do_QueryInterface(currentOtherURI);
}
if (!!nestedURI != !!nestedOtherURI) {
// If only one of the scheme chains runs out at one point, clearly the chains
// aren't of the same length, so we bail:
return false;
}
return true;
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
nsIURI *aTargetURI,
@ -729,14 +765,30 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
rv = sourceBaseURI->GetScheme(sourceScheme);
if (NS_FAILED(rv)) return rv;
// When comparing schemes, if the relevant pref is set, view-source URIs
// are reachable from same-protocol (so e.g. file: can link to
// view-source:file). This is required for reftests.
static bool sViewSourceReachableFromInner = false;
static bool sCachedViewSourcePref = false;
if (!sCachedViewSourcePref) {
sCachedViewSourcePref = true;
mozilla::Preferences::AddBoolVarCache(&sViewSourceReachableFromInner,
"security.view-source.reachable-from-inner-protocol");
}
bool targetIsViewSource = false;
if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
// A null principal can target its own URI.
if (sourceURI == aTargetURI) {
return NS_OK;
}
}
else if (targetScheme.Equals(sourceScheme,
nsCaseInsensitiveCStringComparator()))
else if (AllSchemesMatch(sourceURI, aTargetURI) ||
(sViewSourceReachableFromInner &&
sourceScheme.EqualsIgnoreCase(targetScheme.get()) &&
NS_SUCCEEDED(aTargetURI->SchemeIs("view-source", &targetIsViewSource)) &&
targetIsViewSource))
{
// every scheme can access another URI from the same scheme,
// as long as they don't represent null principals...
@ -785,7 +837,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
// at the flags for our one URI.
// Check for system target URI
rv = DenyAccessIfURIHasFlags(targetBaseURI,
rv = DenyAccessIfURIHasFlags(aTargetURI,
nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
if (NS_FAILED(rv)) {
// Deny access, since the origin principal is not system
@ -853,7 +905,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
}
// Check for target URI pointing to a file
rv = NS_URIChainHasFlags(targetBaseURI,
rv = NS_URIChainHasFlags(aTargetURI,
nsIProtocolHandler::URI_IS_LOCAL_FILE,
&hasFlags);
NS_ENSURE_SUCCESS(rv, rv);
@ -1639,3 +1691,4 @@ nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
return NS_OK;
}

View File

@ -64,3 +64,7 @@
// Allow XUL and XBL files to be opened from file:// URIs
branch.setBoolPref("dom.allow_XUL_XBL_for_file", true);
// Allow view-source URIs to be opened from URIs that share
// their protocol with the inner URI of the view-source URI
branch.setBoolPref("security.view-source.reachable-from-inner-protocol", true);

View File

@ -2025,6 +2025,10 @@ pref("security.cert_pinning.enforcement_level", 0);
// for tests.
pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
// If set to true, allow view-source URIs to be opened from URIs that share
// their protocol with the inner URI of the view-source URI
pref("security.view-source.reachable-from-inner-protocol", false);
// Modifier key prefs: default to Windows settings,
// menu access key = alt, accelerator key = control.
// Use 17 for Ctrl, 18 for Alt, 224 for Meta, 91 for Win, 0 for none. Mac settings in macprefs.js

View File

@ -39,7 +39,8 @@ static bool IsSafeToLinkForUntrustedContent(nsIAboutModule *aModule, nsIURI *aUR
}
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS(nsAboutProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference)
NS_IMPL_ISUPPORTS(nsAboutProtocolHandler, nsIProtocolHandler,
nsIProtocolHandlerWithDynamicFlags, nsISupportsWeakReference)
////////////////////////////////////////////////////////////////////////////////
// nsIProtocolHandler methods:
@ -65,6 +66,33 @@ nsAboutProtocolHandler::GetProtocolFlags(uint32_t *result)
return NS_OK;
}
NS_IMETHODIMP
nsAboutProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aFlags)
{
// First use the default (which is "unsafe for content"):
GetProtocolFlags(aFlags);
// Now try to see if this URI overrides the default:
nsCOMPtr<nsIAboutModule> aboutMod;
nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(aboutMod));
if (NS_FAILED(rv)) {
// Swallow this and just tell the consumer the default:
return NS_OK;
}
uint32_t aboutModuleFlags = 0;
rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags);
// This should never happen, so pass back the error:
NS_ENSURE_SUCCESS(rv, rv);
// If marked as safe, and not marked unlinkable, pass 'safe' flags.
if ((aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) &&
!(aboutModuleFlags & nsIAboutModule::MAKE_UNLINKABLE)) {
*aFlags = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE |
URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
}
return NS_OK;
}
NS_IMETHODIMP
nsAboutProtocolHandler::NewURI(const nsACString &aSpec,
const char *aCharset, // ignore charset info

View File

@ -13,7 +13,8 @@
class nsIURI;
class nsAboutProtocolHandler : public nsIProtocolHandler
class nsAboutProtocolHandler : public nsIProtocolHandlerWithDynamicFlags
, public nsIProtocolHandler
, public nsSupportsWeakReference
{
public:
@ -21,6 +22,7 @@ public:
// nsIProtocolHandler methods:
NS_DECL_NSIPROTOCOLHANDLER
NS_DECL_NSIPROTOCOLHANDLERWITHDYNAMICFLAGS
// nsAboutProtocolHandler methods:
nsAboutProtocolHandler() {}

View File

@ -35,7 +35,7 @@ nsViewSourceHandler::GetDefaultPort(int32_t *result)
NS_IMETHODIMP
nsViewSourceHandler::GetProtocolFlags(uint32_t *result)
{
*result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE |
*result = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD |
URI_NON_PERSISTABLE;
return NS_OK;
}

View File

@ -25,6 +25,7 @@ skip-if = e10s
[test_user_agent_updates.html]
skip-if = e10s
[test_user_agent_updates_reset.html]
[test_viewsource_unlinkable.html]
[test_xhr_method_case.html]
[test_signed_web_packaged_app.html]
skip-if = e10s || buildapp != 'browser'

View File

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<!--
-->
<head>
<title>Test for view-source linkability</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
function runTest() {
SimpleTest.doesThrow(function() {
window.open('view-source:' + location.href, "_blank");
}, "Trying to access view-source URL from unprivileged code should throw.");
SimpleTest.finish();
}
</script>
</head>
<body onload="runTest();">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>