# HG changeset patch # Parent 5fa70bd90a8b2bcbafd14a936c3b3edd0bdf26d6 # User Jesper Kristensen Bug 792479 - Allow UI resources to opt-in to be used by web content diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -21,6 +21,7 @@ #include "nsIContentSecurityPolicy.h" #include "nsCxPusher.h" #include "jswrapper.h" +#include "nsIResProtocolHandler.h" #include "mozilla/Preferences.h" #include "mozilla/HashFunctions.h" @@ -359,6 +360,28 @@ nsPrincipal::CheckMayLoad(nsIURI* aURI, return NS_OK; } + // If the target URI is a nested URI, get the base URI + nsCOMPtr targetBaseURI = NS_GetInnermostURI(aURI); + + //-- get the target scheme + nsAutoCString targetScheme; + nsresult rv = targetBaseURI->GetScheme(targetScheme); + if (NS_FAILED(rv)) return rv; + + // If a resource: URI is marked as public, web content has full read access to + // it even though it is not same-origin. + if (targetScheme.EqualsLiteral("resource")) { + nsCOMPtr resHandler(do_GetService( + NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource")); + if (resHandler) { + bool isPublic = false; + resHandler->IsPublicResource(targetBaseURI, &isPublic); + if (isPublic) { + return NS_OK; + } + } + } + if (aReport) { nsScriptSecurityManager::ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI); } diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -54,6 +54,7 @@ #include "nsIURIFixup.h" #include "nsCDefaultURIFixup.h" #include "nsIChromeRegistry.h" +#include "nsIResProtocolHandler.h" #include "nsIContentSecurityPolicy.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "mozilla/Preferences.h" @@ -757,6 +758,20 @@ nsScriptSecurityManager::CheckLoadURIWit } } + // If a resource: URI is marked as public, web content may load it + // in contexts that don't use ALLOW_CHROME (e.g. iframes) + if (targetScheme.EqualsLiteral("resource")) { + nsCOMPtr resHandler(do_GetService( + NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource")); + if (resHandler) { + bool isPublic = false; + resHandler->IsPublicResource(targetBaseURI, &isPublic); + if (isPublic) { + return NS_OK; + } + } + } + // resource: and chrome: are equivalent, securitywise // That's bogus!! Fix this. But watch out for // the view-source stylesheet? diff --git a/netwerk/protocol/res/nsIResProtocolHandler.idl b/netwerk/protocol/res/nsIResProtocolHandler.idl --- a/netwerk/protocol/res/nsIResProtocolHandler.idl +++ b/netwerk/protocol/res/nsIResProtocolHandler.idl @@ -8,7 +8,7 @@ /** * Protocol handler interface for the resource:// protocol */ -[scriptable, uuid(067ca872-e947-4bd6-8946-a479cb6ba5dd)] +[scriptable, uuid(240df3df-5d39-4521-9a9c-fc87aa63c8b3)] interface nsIResProtocolHandler : nsIProtocolHandler { /** @@ -42,4 +42,20 @@ interface nsIResProtocolHandler : nsIPro * @throws NS_ERROR_NOT_AVAILABLE if resURI.host() is an unknown root key. */ AUTF8String resolveURI(in nsIURI resURI); + + /** + * Marks a substitution as public or not. + * + * A public substitution can be accessed from web content using an iframe or XHR. + * + * @param root The same root key as given to setSubstitution. + * @param public If true, marks the given root key as public. + If false, clears the marking of the root key. + */ + void setPublicSubstitution(in ACString root, in boolean isPublic); + + /** + * Checks if a resource URI is marked as public or not. + */ + boolean isPublicResource(in nsIURI resURI); }; diff --git a/netwerk/protocol/res/nsResProtocolHandler.cpp b/netwerk/protocol/res/nsResProtocolHandler.cpp --- a/netwerk/protocol/res/nsResProtocolHandler.cpp +++ b/netwerk/protocol/res/nsResProtocolHandler.cpp @@ -336,6 +336,18 @@ nsResProtocolHandler::SetSubstitution(co } NS_IMETHODIMP +nsResProtocolHandler::SetPublicSubstitution(const nsACString& root, bool isPublic) +{ + if (!isPublic) { + mPublicSubstitutions.RemoveEntry(root); + return NS_OK; + } + + mPublicSubstitutions.PutEntry(root); + return NS_OK; +} + +NS_IMETHODIMP nsResProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result) { NS_ENSURE_ARG_POINTER(result); @@ -417,3 +429,17 @@ nsResProtocolHandler::ResolveURI(nsIURI #endif return rv; } + +NS_IMETHODIMP +nsResProtocolHandler::IsPublicResource(nsIURI *uri, bool *result) +{ + NS_ENSURE_ARG_POINTER(result); + nsresult rv; + nsAutoCString host; + + rv = uri->GetAsciiHost(host); + if (NS_FAILED(rv)) return rv; + + *result = mPublicSubstitutions.GetEntry(host); + return NS_OK; +} diff --git a/netwerk/protocol/res/nsResProtocolHandler.h b/netwerk/protocol/res/nsResProtocolHandler.h --- a/netwerk/protocol/res/nsResProtocolHandler.h +++ b/netwerk/protocol/res/nsResProtocolHandler.h @@ -42,6 +42,7 @@ private: nsresult Init(nsIFile *aOmniJar); nsresult AddSpecialDir(const char* aSpecialDir, const nsACString& aSubstitution); nsInterfaceHashtable mSubstitutions; + nsTHashtable mPublicSubstitutions; nsCOMPtr mIOService; friend class nsResURL; diff --git a/netwerk/test/mochitests/data.js b/netwerk/test/mochitests/data.js new file mode 100644 --- /dev/null +++ b/netwerk/test/mochitests/data.js @@ -0,0 +1,1 @@ +var x = 1; \ No newline at end of file diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini --- a/netwerk/test/mochitests/mochitest.ini +++ b/netwerk/test/mochitests/mochitest.ini @@ -5,7 +5,9 @@ support-files = partial_content.sjs user_agent.sjs user_agent_update.sjs + data.js +[test_ui_resource_protocol.html] [test_partially_cached_content.html] [test_uri_scheme.html] [test_user_agent_overrides.html] diff --git a/netwerk/test/mochitests/test_ui_resource_protocol.html b/netwerk/test/mochitests/test_ui_resource_protocol.html new file mode 100644 --- /dev/null +++ b/netwerk/test/mochitests/test_ui_resource_protocol.html @@ -0,0 +1,94 @@ + + + + + + Test for Bug 792479 + + + + + +Mozilla Bug 792479 + + + + + +