From 511cc8c18fdcccce5451183bebadd0f89f9c53f5 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sun, 19 Jul 2015 18:42:16 -0700 Subject: [PATCH] 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 | 7 +++- caps/nsScriptSecurityManager.cpp | 10 ++++++ caps/nsScriptSecurityManager.h | 16 +++++++++ netwerk/build/nsNetCID.h | 8 +++++ netwerk/build/nsNetModule.cpp | 5 +++ .../protocol/res/ExtensionProtocolHandler.cpp | 16 +++++++++ .../protocol/res/ExtensionProtocolHandler.h | 35 +++++++++++++++++++ netwerk/protocol/res/moz.build | 1 + toolkit/components/utils/simpleServices.js | 26 ++++++++++++++ 9 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 netwerk/protocol/res/ExtensionProtocolHandler.cpp create mode 100644 netwerk/protocol/res/ExtensionProtocolHandler.h diff --git a/caps/nsIAddonPolicyService.idl b/caps/nsIAddonPolicyService.idl index f858b1484f7..caad17cb32c 100644 --- a/caps/nsIAddonPolicyService.idl +++ b/caps/nsIAddonPolicyService.idl @@ -11,7 +11,7 @@ * 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 { /** @@ -19,4 +19,9 @@ interface nsIAddonPolicyService : nsISupports * 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); }; diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 55d555bbb57..7ab202c36aa 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -745,6 +745,16 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, // 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); diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index e141b6089a7..50b9a8a410b 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -8,10 +8,15 @@ #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" @@ -124,6 +129,17 @@ private: // policy machinery will be removed soon. nsCOMPtr mDomainPolicy; + // Cached addon policy service. We can't generate this in Init() because + // that's too early to get a service. + mozilla::Maybe> 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; diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index dc70366744a..804ad825e22 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -637,6 +637,14 @@ {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, \ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 933c8d27c41..3a5881f7c00 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -272,10 +272,12 @@ namespace net { #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 @@ -760,6 +762,7 @@ 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); @@ -906,6 +909,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { #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 }, @@ -1061,6 +1065,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { #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 }, diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.cpp b/netwerk/protocol/res/ExtensionProtocolHandler.cpp new file mode 100644 index 00000000000..2d6032b9840 --- /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 diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.h b/netwerk/protocol/res/ExtensionProtocolHandler.h new file mode 100644 index 00000000000..7b022b9c740 --- /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___ */ diff --git a/netwerk/protocol/res/moz.build b/netwerk/protocol/res/moz.build index 61771b38e00..665807f4a69 100644 --- a/netwerk/protocol/res/moz.build +++ b/netwerk/protocol/res/moz.build @@ -12,6 +12,7 @@ XPIDL_SOURCES += [ XPIDL_MODULE = 'necko_res' SOURCES += [ + 'ExtensionProtocolHandler.cpp', 'nsResProtocolHandler.cpp', 'SubstitutingProtocolHandler.cpp', ] diff --git a/toolkit/components/utils/simpleServices.js b/toolkit/components/utils/simpleServices.js index c9c3b62df49..8777da4b7f5 100644 --- a/toolkit/components/utils/simpleServices.js +++ b/toolkit/components/utils/simpleServices.js @@ -66,6 +66,21 @@ AddonPolicyService.prototype = { 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 @@ -74,6 +89,17 @@ AddonPolicyService.prototype = { 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]);