Bug 863246 - Content can only load resource:// URIs declared content-accessible in manifests draft
authorChung-Sheng Fu <cfu@mozilla.com>
Thu, 08 Jun 2017 17:42:44 +0800
changeset 609603 fdfe3920d6d6fb6efe3da56fba7c3eb8f7ac604e
parent 609596 aff336ac161daa3ea350e59a288963edbd58ed39
child 609604 49a4f8eac0ce0852e03277c70c99f38bbea8792f
push id68598
push userbmo:cfu@mozilla.com
push dateMon, 17 Jul 2017 03:04:40 +0000
bugs863246
milestone56.0a1
Bug 863246 - Content can only load resource:// URIs declared content-accessible in manifests MozReview-Commit-ID: C1bXwxfr2se
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
--- a/chrome/RegistryMessageUtils.h
+++ b/chrome/RegistryMessageUtils.h
@@ -39,22 +39,24 @@ struct ChromePackage
   }
 };
 
 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;
   }
 };
 
 struct OverrideMapping
 {
   SerializedURI originalURI;
   SerializedURI overrideURI;
 
@@ -140,29 +142,33 @@ struct ParamTraits<SubstitutionMapping>
 {
   typedef SubstitutionMapping paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     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;
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     aLog->append(StringPrintf(L"[%s://%s, %s, %u]",
--- a/chrome/nsChromeRegistry.h
+++ b/chrome/nsChromeRegistry.h
@@ -144,16 +144,19 @@ public:
     // Content script may access files in this package
     CONTENT_ACCESSIBLE = 1 << 2,
 
     // Package may be loaded remotely
     REMOTE_ALLOWED = 1 << 3,
 
     // Package must be loaded remotely
     REMOTE_REQUIRED = 1 << 4,
+
+    // Content is excplicitly disallowed from accessing package/resource
+    CONTENT_INACCESSIBLE = 1 << 5,
   };
 
   bool mInitialized;
 
   // "Override" table (chrome URI string -> real URI)
   nsInterfaceHashtable<nsURIHashKey, nsIURI> mOverrideTable;
 };
 
--- a/chrome/nsChromeRegistryChrome.cpp
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -922,15 +922,30 @@ nsChromeRegistryChrome::ManifestResource
 
   if (!CanLoadResource(resolved)) {
     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
                           "Warning: cannot register non-local URI '%s' as a resource.",
                           uri);
     return;
   }
 
-  rv = rph->SetSubstitution(host, resolved);
+  bool contentAccessible = false;
+  if ((cx.mType == NS_EXTENSION_LOCATION) || (cx.mType == NS_BOOTSTRAPPED_LOCATION)) {
+    // This is a browser extension. By default, extension resources are
+    // content-accessible unless the manifest opts out.
+    contentAccessible = !(flags & nsChromeRegistry::CONTENT_INACCESSIBLE);
+  } else {
+    // This manifest is part of Firefox. By default, Firefox resources are
+    // not content-accessible unless the manifests opts in.
+    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'.",
                           uri);
   }
 }
--- a/chrome/nsChromeRegistryContent.cpp
+++ b/chrome/nsChromeRegistryContent.cpp
@@ -113,17 +113,17 @@ nsChromeRegistryContent::RegisterSubstit
     rv = NS_NewURI(getter_AddRefs(resolvedURI),
                    aSubstitution.resolvedURI.spec,
                    aSubstitution.resolvedURI.charset.get(),
                    nullptr, io);
     if (NS_FAILED(rv))
       return;
   }
 
-  rv = sph->SetSubstitution(aSubstitution.path, resolvedURI);
+  rv = sph->SetSubstitutionWithFlags(aSubstitution.path, resolvedURI, aSubstitution.flags);
   if (NS_FAILED(rv))
     return;
 }
 
 void
 nsChromeRegistryContent::RegisterOverride(const OverrideMapping& aOverride)
 {
   nsCOMPtr<nsIIOService> io (do_GetIOService());
--- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
+++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
@@ -112,32 +112,33 @@ SubstitutingProtocolHandler::ConstructIn
 //
 // IPC marshalling.
 //
 
 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);
       uri->GetOriginCharset(serialized.charset);
     }
-    SubstitutionMapping substitution = { mScheme, nsCString(iter.Key()), serialized };
+    SubstitutionMapping substitution = { mScheme, nsCString(iter.Key()), serialized, entry.flags };
     aMappings.AppendElement(substitution);
   }
 
   return NS_OK;
 }
 
 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;
   }
 
   nsTArray<ContentParent*> parents;
   ContentParent::GetAll(parents);
   if (!parents.Length()) {
@@ -147,16 +148,17 @@ SubstitutingProtocolHandler::SendSubstit
   SubstitutionMapping mapping;
   mapping.scheme = mScheme;
   mapping.path = aRoot;
   if (aBaseURI) {
     nsresult rv = aBaseURI->GetSpec(mapping.resolvedURI.spec);
     NS_ENSURE_SUCCESS(rv, rv);
     aBaseURI->GetOriginCharset(mapping.resolvedURI.charset);
   }
+  mapping.flags = aFlags;
 
   for (uint32_t i = 0; i < parents.Length(); i++) {
     Unused << parents[i]->SendRegisterChromeItem(mapping);
   }
 
   return NS_OK;
 }
 
@@ -290,61 +292,91 @@ SubstitutingProtocolHandler::AllowPort(i
 
 //----------------------------------------------------------------------------
 // nsISubstitutingProtocolHandler
 //----------------------------------------------------------------------------
 
 nsresult
 SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI)
 {
+  // Because add-ons use this API to register new substitutions we have to allow it :/
+  return SetSubstitutionWithFlags(root, baseURI, nsISubstitutingProtocolHandler::ALLOW_CONTENT_ACCESS);
+}
+
+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.
   nsAutoCString scheme;
   nsresult rv = baseURI->GetScheme(scheme);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!scheme.Equals(mScheme)) {
     if (mEnforceFileOrJar && !scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar")
         && !scheme.EqualsLiteral("app")) {
       NS_WARNING("Refusing to create substituting URI to non-file:// target");
       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.
   nsAutoCString newBase;
   rv = ResolveURI(baseURI, newBase);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> newBaseURI;
   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
 SubstitutingProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result)
 {
   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
 SubstitutingProtocolHandler::HasSubstitution(const nsACString& root, bool *result)
 {
   NS_ENSURE_ARG_POINTER(result);
   *result = HasSubstitution(root);
   return NS_OK;
--- a/netwerk/protocol/res/SubstitutingProtocolHandler.h
+++ b/netwerk/protocol/res/SubstitutingProtocolHandler.h
@@ -4,19 +4,19 @@
  * 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 SubstitutingProtocolHandler_h___
 #define SubstitutingProtocolHandler_h___
 
 #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"
 
 class nsIIOService;
 
 namespace mozilla {
 namespace net {
@@ -39,23 +39,26 @@ public:
   bool HasSubstitution(const nsACString& aRoot) const { return mSubstitutions.Get(aRoot, nullptr); }
 
   MOZ_MUST_USE nsresult CollectSubstitutions(InfallibleTArray<SubstitutionMapping>& aResources);
 
 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;
   }
 
   // Override this in the subclass to check for special case when resolving URIs
   // _before_ checking substitutions.
   virtual MOZ_MUST_USE bool ResolveSpecialCases(const nsACString& aHost,
                                                 const nsACString& aPath,
                                                 const nsACString& aPathname,
@@ -69,23 +72,38 @@ protected:
   virtual MOZ_MUST_USE nsresult SubstituteChannel(nsIURI* uri, nsILoadInfo* aLoadInfo, nsIChannel** result)
   {
     return NS_OK;
   }
 
   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
   // notified when substitutions are set or unset.
   nsTArray<nsCOMPtr<nsISubstitutionObserver>> mObservers;
 
   // In general, we expect the principal of a document loaded from a
   // substituting URI to be a codebase principal for that URI (rather than
--- a/netwerk/protocol/res/nsIResProtocolHandler.idl
+++ b/netwerk/protocol/res/nsIResProtocolHandler.idl
@@ -6,9 +6,10 @@
 #include "nsISubstitutingProtocolHandler.idl"
 
 /**
  * Protocol handler interface for the resource:// protocol
  */
 [scriptable, uuid(241d34ac-9ed5-46d7-910c-7a9d914aa0c5)]
 interface nsIResProtocolHandler : nsISubstitutingProtocolHandler
 {
+  boolean allowContentToAccess(in nsIURI url);
 };
--- a/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl
+++ b/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl
@@ -10,27 +10,37 @@ interface nsISubstitutionObserver;
 /**
  * Protocol handler superinterface for a protocol which performs substitutions
  * from URIs of its scheme to URIs of another scheme.
  */
 [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)
    *
    * A null baseURI removes the specified substitution.
    *
    * A root key should always be lowercase; however, this may not be
    * enforced.
    */
   [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.
    *
    * @throws NS_ERROR_NOT_AVAILABLE if none exists.
    */
   [must_use] nsIURI getSubstitution(in ACString root);
 
   /**
    * Returns TRUE if the substitution exists and FALSE otherwise.
--- a/netwerk/protocol/res/nsResProtocolHandler.cpp
+++ b/netwerk/protocol/res/nsResProtocolHandler.cpp
@@ -56,26 +56,46 @@ nsResProtocolHandler::Init()
 //----------------------------------------------------------------------------
 
 NS_IMPL_QUERY_INTERFACE(nsResProtocolHandler, nsIResProtocolHandler,
                         nsISubstitutingProtocolHandler, nsIProtocolHandler,
                         nsISupportsWeakReference)
 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
 nsResProtocolHandler::ResolveSpecialCases(const nsACString& aHost,
                                           const nsACString& aPath,
                                           const nsACString& aPathname,
                                           nsACString& aResult)
 {
@@ -93,8 +113,19 @@ nsResProtocolHandler::ResolveSpecialCase
 nsresult
 nsResProtocolHandler::SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI)
 {
     MOZ_ASSERT(!aRoot.Equals(""));
     MOZ_ASSERT(!aRoot.Equals(kAPP));
     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);
+}
--- a/netwerk/protocol/res/nsResProtocolHandler.h
+++ b/netwerk/protocol/res/nsResProtocolHandler.h
@@ -29,16 +29,17 @@ public:
     nsResProtocolHandler()
       : SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE,
                                     /* aEnforceFileOrJar = */ false)
     {}
 
     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
     {
         return mozilla::SubstitutingProtocolHandler::GetSubstitution(aRoot, aResult);
     }
 
     NS_IMETHOD HasSubstitution(const nsACString& aRoot, bool* aResult) override
     {
@@ -56,17 +57,17 @@ public:
     }
 
     NS_IMETHOD RemoveObserver(nsISubstitutionObserver *aObserver) override
     {
         return mozilla::SubstitutingProtocolHandler::RemoveObserver(aObserver);
     }
 
 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,
                                           const nsACString& aPath,
                                           const nsACString& aPathname,
                                           nsACString& aResult) override;
 
 private:
--- a/xpcom/components/ManifestParser.cpp
+++ b/xpcom/components/ManifestParser.cpp
@@ -51,17 +51,17 @@ struct ManifestDirective
 
   // Some directives should only be delivered for APP or EXTENSION locations.
   bool componentonly;
 
   bool ischrome;
 
   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
   // hasn't learned how to initialize unions in a sane way.
   void (nsComponentManagerImpl::*mgrfunc)(
     nsComponentManagerImpl::ManifestProcessingContext& aCx,
     int aLineNo, char* const* aArgv);
   void (nsChromeRegistry::*regfunc)(
@@ -118,17 +118,17 @@ static const ManifestDirective kParsingT
   },
   {
     // NB: note that while skin manifests can use this, they are only allowed
     // to use it for chrome://../skin/ URLs
     "override",         2, false, false, true, true, false,
     nullptr, &nsChromeRegistry::ManifestOverride, nullptr
   },
   {
-    "resource",         2, false, true, true, true, false,
+    "resource",         2, false, true, true, true, true,
     nullptr, &nsChromeRegistry::ManifestResource, nullptr
   }
 };
 
 static const char kWhitespace[] = "\t ";
 
 static bool
 IsNewline(char aChar)
@@ -695,16 +695,18 @@ ParseManifest(NSLocationType aType, File
       }
 #endif
 
       if (directive->contentflags) {
         bool flag;
         if (CheckFlag(kContentAccessible, wtoken, flag)) {
           if (flag)
             flags |= nsChromeRegistry::CONTENT_ACCESSIBLE;
+          else
+            flags |= nsChromeRegistry::CONTENT_INACCESSIBLE;
           continue;
         }
         if (CheckFlag(kRemoteEnabled, wtoken, flag)) {
           if (flag)
             flags |= nsChromeRegistry::REMOTE_ALLOWED;
           continue;
         }
         if (CheckFlag(kRemoteRequired, wtoken, flag)) {