Bug 1161831 - Implement moz-extension protocol. r=bz,r=billm,sr=mcmanus
authorBobby Holley <bobbyholley@gmail.com>
Sun, 19 Jul 2015 18:42:16 -0700
changeset 285662 9b10ef08bfbe105055f128afd5a1023a6e754011
parent 285661 7b078b5605a1bc51ba7fb87b5b81f46f9e8dfad1
child 285663 8843374b8ac7c8c823c3fad5e44a3295f02b6e20
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, billm, mcmanus
bugs1161831
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1161831 - Implement moz-extension protocol. r=bz,r=billm,sr=mcmanus The heavy lifting all happened in the previous patch, so this is easy now.
caps/nsIAddonPolicyService.idl
caps/nsScriptSecurityManager.cpp
caps/nsScriptSecurityManager.h
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/protocol/res/ExtensionProtocolHandler.cpp
netwerk/protocol/res/ExtensionProtocolHandler.h
netwerk/protocol/res/moz.build
toolkit/components/utils/simpleServices.js
--- a/caps/nsIAddonPolicyService.idl
+++ b/caps/nsIAddonPolicyService.idl
@@ -6,17 +6,22 @@
 
 #include "nsISupports.idl"
 #include "nsIURI.idl"
 
 /**
  * This interface allows the security manager to query custom per-addon security
  * policy.
  */
-[scriptable,uuid(fedf126c-988e-42df-82c9-f2ac99cd65f3)]
+[scriptable,uuid(3ec203f8-2bd0-4f4c-8f99-f9f056221231)]
 interface nsIAddonPolicyService : nsISupports
 {
   /**
    * Returns true if unprivileged code associated with the given addon may load
    * data from |aURI|.
    */
   boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI);
+
+  /**
+   * Returns true if a given extension:// URI is web-accessible.
+   */
+  boolean extensionURILoadableByAnyone(in nsIURI aURI);
 };
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -740,16 +740,26 @@ nsScriptSecurityManager::CheckLoadURIWit
 
     // If the schemes don't match, the policy is specified by the protocol
     // flags on the target URI.  Note that the order of policy checks here is
     // very important!  We start from most restrictive and work our way down.
     // Note that since we're working with the innermost URI, we can just use
     // the methods that work on chains of nested URIs and they will only look
     // at the flags for our one URI.
 
+    // Special case: moz-extension has a whitelist of URIs that are loadable by
+    // anyone.
+    if (targetScheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) {
+      bool loadable = false;
+      rv = GetAddonPolicyService()->ExtensionURILoadableByAnyone(targetBaseURI, &loadable);
+      if (NS_SUCCEEDED(rv) && loadable) {
+        return NS_OK;
+      }
+    }
+
     // Check for system target URI
     rv = DenyAccessIfURIHasFlags(targetBaseURI,
                                  nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
     if (NS_FAILED(rv)) {
         // Deny access, since the origin principal is not system
         if (reportErrors) {
             ReportError(nullptr, errorTag, sourceURI, aTargetURI);
         }
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -3,20 +3,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 nsScriptSecurityManager_h__
 #define nsScriptSecurityManager_h__
 
 #include "nsIScriptSecurityManager.h"
+
+#include "nsIAddonPolicyService.h"
+#include "mozilla/Maybe.h"
+#include "nsIAddonPolicyService.h"
 #include "nsIPrincipal.h"
 #include "nsCOMPtr.h"
 #include "nsIChannelEventSink.h"
 #include "nsIObserver.h"
+#include "nsServiceManagerUtils.h"
 #include "plstr.h"
 #include "js/TypeDecls.h"
 
 #include <stdint.h>
 
 class nsCString;
 class nsIIOService;
 class nsIStringBundle;
@@ -119,16 +124,27 @@ private:
     bool mPrefInitialized;
     bool mIsJavaScriptEnabled;
     nsTArray<nsCOMPtr<nsIURI>> mFileURIWhitelist;
 
     // This machinery controls new-style domain policies. The old-style
     // policy machinery will be removed soon.
     nsCOMPtr<nsIDomainPolicy> mDomainPolicy;
 
+    // Cached addon policy service. We can't generate this in Init() because
+    // that's too early to get a service.
+    mozilla::Maybe<nsCOMPtr<nsIAddonPolicyService>> mAddonPolicyService;
+    nsIAddonPolicyService* GetAddonPolicyService()
+    {
+        if (mAddonPolicyService.isNothing()) {
+            mAddonPolicyService.emplace(do_GetService("@mozilla.org/addons/policy-service;1"));
+        }
+        return mAddonPolicyService.ref();
+    }
+
     static bool sStrictFileOriginPolicy;
 
     static nsIIOService    *sIOService;
     static nsIStringBundle *sStrBundle;
     static JSRuntime       *sRuntime;
 };
 
 namespace mozilla {
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -632,16 +632,24 @@
 #define NS_RESPROTOCOLHANDLER_CID                    \
 { /* e64f152a-9f07-11d3-8cda-0060b0fc14a3 */         \
     0xe64f152a,                                      \
     0x9f07,                                          \
     0x11d3,                                          \
     {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
 }
 
+#define NS_EXTENSIONPROTOCOLHANDLER_CID              \
+{ /* aea16cd0-f020-4138-b068-0716c4a15b5a */         \
+    0xaea16cd0,                                      \
+    0xf020,                                          \
+    0x4138,                                          \
+    {0xb0, 0x68, 0x07, 0x16, 0xc4, 0xa1, 0x5b, 0x5a} \
+}
+
 #define NS_SUBSTITUTINGURL_CID                       \
 { 0xdea9657c,                                        \
   0x18cf,                                            \
   0x4984,                                            \
   { 0xbd, 0xe9, 0xcc, 0xef, 0x5d, 0x8a, 0xb4, 0x73 } \
 }
 
 /******************************************************************************
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -267,20 +267,22 @@ namespace net {
   NS_GENERIC_FACTORY_CONSTRUCTOR(PackagedAppService)
 } // namespace net
 } // namespace mozilla
 #include "AppProtocolHandler.h"
 
 #ifdef NECKO_PROTOCOL_res
 // resource
 #include "nsResProtocolHandler.h"
+#include "ExtensionProtocolHandler.h"
 #include "SubstitutingProtocolHandler.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsResProtocolHandler, Init)
 
 namespace mozilla {
+NS_GENERIC_FACTORY_CONSTRUCTOR(ExtensionProtocolHandler)
 NS_GENERIC_FACTORY_CONSTRUCTOR(SubstitutingURL)
 } // namespace mozilla
 #endif
 
 #ifdef NECKO_PROTOCOL_device
 #include "nsDeviceProtocolHandler.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceProtocolHandler)
 #endif
@@ -755,16 +757,17 @@ NS_DEFINE_NAMED_CID(NS_HTTPAUTHMANAGER_C
 NS_DEFINE_NAMED_CID(NS_HTTPCHANNELAUTHPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPACTIVITYDISTRIBUTOR_CID);
 #endif // !NECKO_PROTOCOL_http
 #ifdef NECKO_PROTOCOL_ftp
 NS_DEFINE_NAMED_CID(NS_FTPPROTOCOLHANDLER_CID);
 #endif
 #ifdef NECKO_PROTOCOL_res
 NS_DEFINE_NAMED_CID(NS_RESPROTOCOLHANDLER_CID);
+NS_DEFINE_NAMED_CID(NS_EXTENSIONPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_SUBSTITUTINGURL_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_ABOUTPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_SAFEABOUTPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_ABOUT_BLANK_MODULE_CID);
 NS_DEFINE_NAMED_CID(NS_NESTEDABOUTURI_CID);
 #ifdef NECKO_PROTOCOL_about
 #ifdef NS_BUILD_REFCNT_LOGGING
@@ -901,16 +904,17 @@ static const mozilla::Module::CIDEntry k
     { &kNS_HTTPCHANNELAUTHPROVIDER_CID, false, nullptr, mozilla::net::nsHttpChannelAuthProviderConstructor },
     { &kNS_HTTPACTIVITYDISTRIBUTOR_CID, false, nullptr, mozilla::net::nsHttpActivityDistributorConstructor },
 #endif // !NECKO_PROTOCOL_http
 #ifdef NECKO_PROTOCOL_ftp
     { &kNS_FTPPROTOCOLHANDLER_CID, false, nullptr, nsFtpProtocolHandlerConstructor },
 #endif
 #ifdef NECKO_PROTOCOL_res
     { &kNS_RESPROTOCOLHANDLER_CID, false, nullptr, nsResProtocolHandlerConstructor },
+    { &kNS_EXTENSIONPROTOCOLHANDLER_CID, false, nullptr, mozilla::ExtensionProtocolHandlerConstructor },
     { &kNS_SUBSTITUTINGURL_CID, false, nullptr, mozilla::SubstitutingURLConstructor },
 #endif
     { &kNS_ABOUTPROTOCOLHANDLER_CID, false, nullptr, nsAboutProtocolHandlerConstructor },
     { &kNS_SAFEABOUTPROTOCOLHANDLER_CID, false, nullptr, nsSafeAboutProtocolHandlerConstructor },
     { &kNS_ABOUT_BLANK_MODULE_CID, false, nullptr, nsAboutBlank::Create },
     { &kNS_NESTEDABOUTURI_CID, false, nullptr, nsNestedAboutURIConstructor },
 #ifdef NECKO_PROTOCOL_about
 #ifdef NS_BUILD_REFCNT_LOGGING
@@ -1056,16 +1060,17 @@ static const mozilla::Module::ContractID
     { NS_HTTPCHANNELAUTHPROVIDER_CONTRACTID, &kNS_HTTPCHANNELAUTHPROVIDER_CID },
     { NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID, &kNS_HTTPACTIVITYDISTRIBUTOR_CID },
 #endif // !NECKO_PROTOCOL_http
 #ifdef NECKO_PROTOCOL_ftp
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &kNS_FTPPROTOCOLHANDLER_CID },
 #endif
 #ifdef NECKO_PROTOCOL_res
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource", &kNS_RESPROTOCOLHANDLER_CID },
+    { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-extension", &kNS_EXTENSIONPROTOCOLHANDLER_CID },
 #endif
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "about", &kNS_ABOUTPROTOCOLHANDLER_CID },
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-safe-about", &kNS_SAFEABOUTPROTOCOLHANDLER_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "blank", &kNS_ABOUT_BLANK_MODULE_CID },
 #ifdef NECKO_PROTOCOL_about
 #ifdef NS_BUILD_REFCNT_LOGGING
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "bloat", &kNS_ABOUT_BLOAT_MODULE_CID },
 #endif
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
@@ -0,0 +1,16 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#include "ExtensionProtocolHandler.h"
+
+namespace mozilla {
+
+NS_IMPL_QUERY_INTERFACE(ExtensionProtocolHandler, nsISubstitutingProtocolHandler,
+                        nsIProtocolHandler, nsISupportsWeakReference)
+NS_IMPL_ADDREF_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler)
+NS_IMPL_RELEASE_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler)
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 ExtensionProtocolHandler_h___
+#define ExtensionProtocolHandler_h___
+
+#include "SubstitutingProtocolHandler.h"
+#include "nsWeakReference.h"
+
+namespace mozilla {
+
+class ExtensionProtocolHandler final : public nsISubstitutingProtocolHandler,
+                                       public mozilla::SubstitutingProtocolHandler,
+                                       public nsSupportsWeakReference
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
+  NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
+
+  // In general a moz-extension URI is only loadable by chrome, but a whitelisted
+  // subset are web-accessible (see nsIAddonPolicyService).
+  ExtensionProtocolHandler()
+    : SubstitutingProtocolHandler("moz-extension", URI_STD | URI_DANGEROUS_TO_LOAD | URI_IS_LOCAL_RESOURCE)
+  {}
+
+protected:
+  ~ExtensionProtocolHandler() {}
+};
+
+} // namespace mozilla
+
+#endif /* ExtensionProtocolHandler_h___ */
--- a/netwerk/protocol/res/moz.build
+++ b/netwerk/protocol/res/moz.build
@@ -7,16 +7,17 @@
 XPIDL_SOURCES += [
     'nsIResProtocolHandler.idl',
     'nsISubstitutingProtocolHandler.idl',
 ]
 
 XPIDL_MODULE = 'necko_res'
 
 SOURCES += [
+    'ExtensionProtocolHandler.cpp',
     'nsResProtocolHandler.cpp',
     'SubstitutingProtocolHandler.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/toolkit/components/utils/simpleServices.js
+++ b/toolkit/components/utils/simpleServices.js
@@ -62,18 +62,44 @@ AddonPolicyService.prototype = {
    * @see nsIAddonPolicyService.addonMayLoadURI
    */
   addonMayLoadURI(aAddonId, aURI) {
     let cb = this.mayLoadURICallbacks[aAddonId];
     return cb ? cb(aURI) : false;
   },
 
   /*
+   * Invokes a callback (if any) to determine if an extension URI should be
+   * web-accessible.
+   *
+   * @see nsIAddonPolicyService.extensionURILoadableByAnyone
+   */
+  extensionURILoadableByAnyone(aURI) {
+    if (aURI.scheme != "moz-extension") {
+      throw new TypeError("non-extension URI passed");
+    }
+
+    let cb = this.extensionURILoadCallback;
+    return cb ? cb(aURI) : false;
+  },
+
+  /*
    * Sets the callbacks used in addonMayLoadURI above. Not accessible over
    * XPCOM - callers should use .wrappedJSObject on the service to call it
    * directly.
    */
   setAddonLoadURICallback(aAddonId, aCallback) {
     this.mayLoadURICallbacks[aAddonId] = aCallback;
   },
+
+  /*
+   * Sets the callback used in extensionURILoadableByAnyone above. Not
+   * accessible over XPCOM - callers should use .wrappedJSObject on the
+   * service to call it directly.
+   */
+  setExtensionURILoadCallback(aCallback) {
+    var old = this.extensionURILoadCallback;
+    this.extensionURILoadCallback = aCallback;
+    return old;
+  }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RemoteTagServiceService, AddonPolicyService]);