Bug 863246 - Content can only load resource:// URIs declared content-accessible in manifests r=billm,bz

bz:
    caps/nsScriptSecurityManager.cpp

billm:
    browser/extensions/activity-stream/jar.mn
    browser/extensions/onboarding/jar.mn
    chrome/RegistryMessageUtils.h
    chrome/nsChromeRegistry.h
    chrome/nsChromeRegistryChrome.cpp
    chrome/nsChromeRegistryContent.cpp
    netwerk/protocol/res/SubstitutingProtocolHandler.cpp
    netwerk/protocol/res/SubstitutingProtocolHandler.h
    netwerk/protocol/res/nsIResProtocolHandler.idl
    netwerk/protocol/res/nsISubstitutingProtocolHandler.idl
    netwerk/protocol/res/nsResProtocolHandler.cpp
    netwerk/protocol/res/nsResProtocolHandler.h
    xpcom/components/ManifestParser.cpp

MozReview-Commit-ID: 1RXeNn7jdBf

--HG--
extra : rebase_source : 749673b7a5bb0b50192a57496b2ea7962bf6b2d7
This commit is contained in:
Chung-Sheng Fu 2017-06-08 17:44:09 +08:00
Родитель 1a53afbade
Коммит 68b806c637
14 изменённых файлов: 183 добавлений и 37 удалений

Просмотреть файл

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[features/activity-stream@mozilla.org] chrome.jar:
% resource activity-stream %content/
% resource activity-stream %content/ contentaccessible=yes
content/lib/ (./lib/*)
content/common/ (./common/*)
content/vendor/Redux.jsm (./vendor/Redux.jsm)

Просмотреть файл

@ -3,7 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[features/onboarding@mozilla.org] chrome.jar:
% resource onboarding %content/
# resource://onboarding/ is referenced in about:home and about:newtab,
# so make it content-accessible.
% resource onboarding %content/ contentaccessible=yes
content/ (content/*)
# Package UITour-lib.js in here rather than under
# /browser/components/uitour to avoid "unreferenced files" error when

Просмотреть файл

@ -7,7 +7,7 @@
lib/ (./lib/*)
data/ (./data/*)
skin/ (skin/*)
% resource shield-recipe-client-content %content/
% resource shield-recipe-client-content %content/ contentaccessible=yes
content/ (./content/*)
% resource shield-recipe-client-vendor %vendor/
% resource shield-recipe-client-vendor %vendor/ contentaccessible=yes
vendor/ (./vendor/*)

Просмотреть файл

@ -53,6 +53,7 @@
#include "nsIURIFixup.h"
#include "nsCDefaultURIFixup.h"
#include "nsIChromeRegistry.h"
#include "nsIResProtocolHandler.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "mozilla/Preferences.h"
@ -915,10 +916,9 @@ nsScriptSecurityManager::CheckLoadURIFlags(nsIURI *aSourceURI,
NS_ENSURE_SUCCESS(rv, rv);
if (hasFlags) {
if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
// For now, don't change behavior for resource:// or moz-icon:// and
// just allow them.
if (!targetScheme.EqualsLiteral("chrome")) {
// For now, don't change behavior for moz-icon:// and just allow it.
if (!targetScheme.EqualsLiteral("chrome")
&& !targetScheme.EqualsLiteral("resource")) {
return NS_OK;
}
@ -939,15 +939,51 @@ nsScriptSecurityManager::CheckLoadURIFlags(nsIURI *aSourceURI,
return NS_OK;
}
// Allow the load only if the chrome package is whitelisted.
nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
NS_CHROMEREGISTRY_CONTRACTID));
if (reg) {
if (targetScheme.EqualsLiteral("resource")) {
// Mochitests that need to load resource:// URIs not declared
// content-accessible in manifests should set the preference
// "security.all_resource_uri_content_accessible" true.
static bool sSecurityPrefCached = false;
static bool sAllResourceUriContentAccessible = false;
if (!sSecurityPrefCached) {
sSecurityPrefCached = true;
Preferences::AddBoolVarCache(
&sAllResourceUriContentAccessible,
"security.all_resource_uri_content_accessible",
false);
}
if (sAllResourceUriContentAccessible) {
return NS_OK;
}
nsCOMPtr<nsIProtocolHandler> ph;
rv = sIOService->GetProtocolHandler("resource", getter_AddRefs(ph));
NS_ENSURE_SUCCESS(rv, rv);
if (!ph) {
return NS_ERROR_DOM_BAD_URI;
}
nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
if (!rph) {
return NS_ERROR_DOM_BAD_URI;
}
bool accessAllowed = false;
reg->AllowContentToAccess(aTargetBaseURI, &accessAllowed);
rph->AllowContentToAccess(aTargetBaseURI, &accessAllowed);
if (accessAllowed) {
return NS_OK;
}
} else {
// Allow the load only if the chrome package is whitelisted.
nsCOMPtr<nsIXULChromeRegistry> reg(
do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
if (reg) {
bool accessAllowed = false;
reg->AllowContentToAccess(aTargetBaseURI, &accessAllowed);
if (accessAllowed) {
return NS_OK;
}
}
}
}

Просмотреть файл

@ -42,12 +42,14 @@ struct SubstitutionMapping
nsCString scheme;
nsCString path;
SerializedURI resolvedURI;
uint32_t flags;
bool operator ==(const SubstitutionMapping& rhs) const
{
return scheme.Equals(rhs.scheme) &&
path.Equals(rhs.path) &&
resolvedURI == rhs.resolvedURI;
resolvedURI == rhs.resolvedURI &&
flags == rhs.flags;
}
};
@ -140,19 +142,23 @@ struct ParamTraits<SubstitutionMapping>
WriteParam(aMsg, aParam.scheme);
WriteParam(aMsg, aParam.path);
WriteParam(aMsg, aParam.resolvedURI);
WriteParam(aMsg, aParam.flags);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
nsCString scheme, path;
SerializedURI resolvedURI;
uint32_t flags;
if (ReadParam(aMsg, aIter, &scheme) &&
ReadParam(aMsg, aIter, &path) &&
ReadParam(aMsg, aIter, &resolvedURI)) {
ReadParam(aMsg, aIter, &resolvedURI) &&
ReadParam(aMsg, aIter, &flags)) {
aResult->scheme = scheme;
aResult->path = path;
aResult->resolvedURI = resolvedURI;
aResult->flags = flags;
return true;
}
return false;

Просмотреть файл

@ -927,7 +927,15 @@ nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int line
return;
}
rv = rph->SetSubstitution(host, resolved);
// By default, Firefox resources are not content-accessible unless the
// manifests opts in.
bool contentAccessible = (flags & nsChromeRegistry::CONTENT_ACCESSIBLE);
uint32_t substitutionFlags = 0;
if (contentAccessible) {
substitutionFlags |= nsIResProtocolHandler::ALLOW_CONTENT_ACCESS;
}
rv = rph->SetSubstitutionWithFlags(host, resolved, substitutionFlags);
if (NS_FAILED(rv)) {
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
"Warning: cannot set substitution for '%s'.",

Просмотреть файл

@ -114,7 +114,7 @@ nsChromeRegistryContent::RegisterSubstitution(const SubstitutionMapping& aSubsti
return;
}
rv = sph->SetSubstitution(aSubstitution.path, resolvedURI);
rv = sph->SetSubstitutionWithFlags(aSubstitution.path, resolvedURI, aSubstitution.flags);
if (NS_FAILED(rv))
return;
}

Просмотреть файл

@ -117,13 +117,14 @@ nsresult
SubstitutingProtocolHandler::CollectSubstitutions(InfallibleTArray<SubstitutionMapping>& aMappings)
{
for (auto iter = mSubstitutions.ConstIter(); !iter.Done(); iter.Next()) {
nsCOMPtr<nsIURI> uri = iter.Data();
SubstitutionEntry& entry = iter.Data();
nsCOMPtr<nsIURI> uri = entry.baseURI;
SerializedURI serialized;
if (uri) {
nsresult rv = uri->GetSpec(serialized.spec);
NS_ENSURE_SUCCESS(rv, rv);
}
SubstitutionMapping substitution = { mScheme, nsCString(iter.Key()), serialized };
SubstitutionMapping substitution = { mScheme, nsCString(iter.Key()), serialized, entry.flags };
aMappings.AppendElement(substitution);
}
@ -131,7 +132,7 @@ SubstitutingProtocolHandler::CollectSubstitutions(InfallibleTArray<SubstitutionM
}
nsresult
SubstitutingProtocolHandler::SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI)
SubstitutingProtocolHandler::SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI, uint32_t aFlags)
{
if (GeckoProcessType_Content == XRE_GetProcessType()) {
return NS_OK;
@ -150,6 +151,7 @@ SubstitutingProtocolHandler::SendSubstitution(const nsACString& aRoot, nsIURI* a
nsresult rv = aBaseURI->GetSpec(mapping.resolvedURI.spec);
NS_ENSURE_SUCCESS(rv, rv);
}
mapping.flags = aFlags;
for (uint32_t i = 0; i < parents.Length(); i++) {
Unused << parents[i]->SendRegisterChromeItem(mapping);
@ -292,11 +294,19 @@ SubstitutingProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_
nsresult
SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI)
{
// Add-ons use this API but they should not be able to make anything
// content-accessible.
return SetSubstitutionWithFlags(root, baseURI, 0);
}
nsresult
SubstitutingProtocolHandler::SetSubstitutionWithFlags(const nsACString& root, nsIURI *baseURI, uint32_t flags)
{
if (!baseURI) {
mSubstitutions.Remove(root);
NotifyObservers(root, baseURI);
return SendSubstitution(root, baseURI);
return SendSubstitution(root, baseURI, flags);
}
// If baseURI isn't a same-scheme URI, we can set the substitution immediately.
@ -310,9 +320,11 @@ SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *bas
return NS_ERROR_INVALID_ARG;
}
mSubstitutions.Put(root, baseURI);
SubstitutionEntry& entry = mSubstitutions.GetOrInsert(root);
entry.baseURI = baseURI;
entry.flags = flags;
NotifyObservers(root, baseURI);
return SendSubstitution(root, baseURI);
return SendSubstitution(root, baseURI, flags);
}
// baseURI is a same-type substituting URI, let's resolve it first.
@ -324,9 +336,11 @@ SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *bas
rv = mIOService->NewURI(newBase, nullptr, nullptr, getter_AddRefs(newBaseURI));
NS_ENSURE_SUCCESS(rv, rv);
mSubstitutions.Put(root, newBaseURI);
SubstitutionEntry& entry = mSubstitutions.GetOrInsert(root);
entry.baseURI = newBaseURI;
entry.flags = flags;
NotifyObservers(root, baseURI);
return SendSubstitution(root, newBaseURI);
return SendSubstitution(root, newBaseURI, flags);
}
nsresult
@ -334,10 +348,29 @@ SubstitutingProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **re
{
NS_ENSURE_ARG_POINTER(result);
if (mSubstitutions.Get(root, result))
SubstitutionEntry entry;
if (mSubstitutions.Get(root, &entry)) {
nsCOMPtr<nsIURI> baseURI = entry.baseURI;
baseURI.forget(result);
return NS_OK;
}
return GetSubstitutionInternal(root, result);
uint32_t flags;
return GetSubstitutionInternal(root, result, &flags);
}
nsresult
SubstitutingProtocolHandler::GetSubstitutionFlags(const nsACString& root, uint32_t* flags)
{
*flags = 0;
SubstitutionEntry entry;
if (mSubstitutions.Get(root, &entry)) {
*flags = entry.flags;
return NS_OK;
}
nsCOMPtr<nsIURI> baseURI;
return GetSubstitutionInternal(root, getter_AddRefs(baseURI), flags);
}
nsresult

Просмотреть файл

@ -9,9 +9,9 @@
#include "nsISubstitutingProtocolHandler.h"
#include "nsInterfaceHashtable.h"
#include "nsIOService.h"
#include "nsISubstitutionObserver.h"
#include "nsDataHashtable.h"
#include "nsStandardURL.h"
#include "mozilla/chrome/RegistryMessageUtils.h"
#include "mozilla/Maybe.h"
@ -44,13 +44,16 @@ protected:
virtual ~SubstitutingProtocolHandler() {}
void ConstructInternal();
MOZ_MUST_USE nsresult SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI);
MOZ_MUST_USE nsresult SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI, uint32_t aFlags);
nsresult GetSubstitutionFlags(const nsACString& root, uint32_t* flags);
// Override this in the subclass to try additional lookups after checking
// mSubstitutions.
virtual MOZ_MUST_USE nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult)
virtual MOZ_MUST_USE nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult, uint32_t* aFlags)
{
*aResult = nullptr;
*aFlags = 0;
return NS_ERROR_NOT_AVAILABLE;
}
@ -74,13 +77,28 @@ protected:
nsIIOService* IOService() { return mIOService; }
private:
struct SubstitutionEntry
{
SubstitutionEntry()
: flags(0)
{
}
~SubstitutionEntry()
{
}
nsCOMPtr<nsIURI> baseURI;
uint32_t flags;
};
// Notifies all observers that a new substitution from |aRoot| to
// |aBaseURI| has been set/installed for this protocol handler.
void NotifyObservers(const nsACString& aRoot, nsIURI* aBaseURI);
nsCString mScheme;
Maybe<uint32_t> mFlags;
nsInterfaceHashtable<nsCStringHashKey,nsIURI> mSubstitutions;
nsDataHashtable<nsCStringHashKey, SubstitutionEntry> mSubstitutions;
nsCOMPtr<nsIIOService> mIOService;
// The list of observers added with AddObserver that will be

Просмотреть файл

@ -11,4 +11,5 @@
[scriptable, uuid(241d34ac-9ed5-46d7-910c-7a9d914aa0c5)]
interface nsIResProtocolHandler : nsISubstitutingProtocolHandler
{
boolean allowContentToAccess(in nsIURI url);
};

Просмотреть файл

@ -14,6 +14,11 @@ interface nsISubstitutionObserver;
[scriptable, uuid(154c64fd-a69e-4105-89f8-bd7dfe621372)]
interface nsISubstitutingProtocolHandler : nsIProtocolHandler
{
/**
* Content script may access files in this package.
*/
const short ALLOW_CONTENT_ACCESS = 1;
/**
* Sets the substitution for the root key:
* resource://root/path ==> baseURI.resolve(path)
@ -25,6 +30,11 @@ interface nsISubstitutingProtocolHandler : nsIProtocolHandler
*/
[must_use] void setSubstitution(in ACString root, in nsIURI baseURI);
/**
* Same as setSubstitution, but with specific flags.
*/
[must_use] void setSubstitutionWithFlags(in ACString root, in nsIURI baseURI, in uint32_t flags);
/**
* Gets the substitution for the root key.
*

Просмотреть файл

@ -61,16 +61,36 @@ NS_IMPL_QUERY_INTERFACE(nsResProtocolHandler, nsIResProtocolHandler,
NS_IMPL_ADDREF_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
NS_IMPL_RELEASE_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
NS_IMETHODIMP
nsResProtocolHandler::AllowContentToAccess(nsIURI *aURI, bool *aResult)
{
*aResult = false;
nsAutoCString host;
nsresult rv = aURI->GetAsciiHost(host);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t flags;
rv = GetSubstitutionFlags(host, &flags);
NS_ENSURE_SUCCESS(rv, rv);
*aResult = flags & nsISubstitutingProtocolHandler::ALLOW_CONTENT_ACCESS;
return NS_OK;
}
nsresult
nsResProtocolHandler::GetSubstitutionInternal(const nsACString& root, nsIURI **result)
nsResProtocolHandler::GetSubstitutionInternal(const nsACString& aRoot,
nsIURI** aResult,
uint32_t* aFlags)
{
nsAutoCString uri;
if (!ResolveSpecialCases(root, NS_LITERAL_CSTRING("/"), NS_LITERAL_CSTRING("/"), uri)) {
if (!ResolveSpecialCases(aRoot, NS_LITERAL_CSTRING("/"), NS_LITERAL_CSTRING("/"), uri)) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_NewURI(result, uri);
*aFlags = 0; // No content access.
return NS_NewURI(aResult, uri);
}
bool
@ -98,3 +118,14 @@ nsResProtocolHandler::SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI)
MOZ_ASSERT(!aRoot.Equals(kGRE));
return SubstitutingProtocolHandler::SetSubstitution(aRoot, aBaseURI);
}
nsresult
nsResProtocolHandler::SetSubstitutionWithFlags(const nsACString& aRoot,
nsIURI* aBaseURI,
uint32_t aFlags)
{
MOZ_ASSERT(!aRoot.Equals(""));
MOZ_ASSERT(!aRoot.Equals(kAPP));
MOZ_ASSERT(!aRoot.Equals(kGRE));
return SubstitutingProtocolHandler::SetSubstitutionWithFlags(aRoot, aBaseURI, aFlags);
}

Просмотреть файл

@ -34,6 +34,7 @@ public:
MOZ_MUST_USE nsresult Init();
NS_IMETHOD SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI) override;
NS_IMETHOD SetSubstitutionWithFlags(const nsACString& aRoot, nsIURI* aBaseURI, uint32_t aFlags) override;
NS_IMETHOD GetSubstitution(const nsACString& aRoot, nsIURI** aResult) override
{
@ -61,7 +62,7 @@ public:
}
protected:
MOZ_MUST_USE nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult) override;
MOZ_MUST_USE nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult, uint32_t* aFlags) override;
virtual ~nsResProtocolHandler() {}
MOZ_MUST_USE bool ResolveSpecialCases(const nsACString& aHost,

Просмотреть файл

@ -56,7 +56,7 @@ struct ManifestDirective
bool allowbootstrap;
// The contentaccessible flags only apply to content directives.
// The contentaccessible flags only apply to content/resource directives.
bool contentflags;
// Function to handle this directive. This isn't a union because C++ still
@ -123,7 +123,7 @@ static const ManifestDirective kParsingTable[] = {
nullptr, &nsChromeRegistry::ManifestOverride, nullptr
},
{
"resource", 2, false, true, true, true, false,
"resource", 2, false, true, true, true, true,
nullptr, &nsChromeRegistry::ManifestResource, nullptr
}
};