author | Kris Maglione <maglione.k@gmail.com> |
Sat, 03 Mar 2018 16:28:18 -0800 (2018-03-04) | |
changeset 407481 | 39e131181d442409a5df2ed945c02aca2b9baca2 |
parent 407480 | f96e8d3c02251534d208bafb046d007970e284a5 |
child 407482 | c291e7dfe010bbaaecac186abfbd8310fba127de |
push id | 33602 |
push user | nerli@mozilla.com |
push date | Sat, 10 Mar 2018 09:59:03 +0000 (2018-03-10) |
treeherder | mozilla-central@0817a733d45a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | aswan, mixedpuppy |
bugs | 1415644 |
milestone | 60.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
|
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5112,16 +5112,17 @@ pref("extensions.webExtensionsMinPlatfor pref("extensions.legacy.enabled", true); pref("extensions.allow-non-mpc-extensions", true); // Other webextensions prefs pref("extensions.webextensions.keepStorageOnUninstall", false); pref("extensions.webextensions.keepUuidOnUninstall", false); // Redirect basedomain used by identity api pref("extensions.webextensions.identity.redirectDomain", "extensions.allizom.org"); +pref("extensions.webextensions.restrictedDomains", "accounts-static.cdn.mozilla.net,accounts.firefox.com,addons.cdn.mozilla.net,addons.mozilla.org,api.accounts.firefox.com,content.cdn.mozilla.net,content.cdn.mozilla.net,discovery.addons.mozilla.org,input.mozilla.org,install.mozilla.org,oauth.accounts.firefox.com,profile.accounts.firefox.com,support.mozilla.org,sync.services.mozilla.com,testpilot.firefox.com"); // Whether or not webextension themes are supported. pref("extensions.webextensions.themes.enabled", false); pref("extensions.webextensions.themes.icons.enabled", false); pref("extensions.webextensions.remote", false); // Whether or not the moz-extension resource loads are remoted. For debugging // purposes only. Setting this to false will break moz-extension URI loading // unless other process sandboxing and extension remoting prefs are changed. pref("extensions.webextensions.protocol.remote", true);
--- a/toolkit/components/extensions/MatchPattern.cpp +++ b/toolkit/components/extensions/MatchPattern.cpp @@ -126,16 +126,25 @@ const nsCString& URLInfo::Host() const { if (mHost.IsVoid()) { Unused << mURI->GetHost(mHost); } return mHost; } +const nsAtom* +URLInfo::HostAtom() const +{ + if (!mHostAtom) { + mHostAtom = NS_Atomize(Host()); + } + return mHostAtom; +} + const nsString& URLInfo::FilePath() const { if (mFilePath.IsEmpty()) { nsCString path; nsCOMPtr<nsIURL> url = do_QueryInterface(mURI); if (url && NS_SUCCEEDED(url->GetFilePath(path))) { AppendUTF8toUTF16(path, mFilePath);
--- a/toolkit/components/extensions/MatchPattern.h +++ b/toolkit/components/extensions/MatchPattern.h @@ -150,31 +150,33 @@ public: URLInfo(const URLInfo& aOther) : URLInfo(aOther.mURI.get()) {} nsIURI* URI() const { return mURI; } nsAtom* Scheme() const; const nsCString& Host() const; + const nsAtom* HostAtom() const; const nsString& Path() const; const nsString& FilePath() const; const nsString& Spec() const; const nsCString& CSpec() const; bool InheritsPrincipal() const; private: nsIURI* URINoRef() const; nsCOMPtr<nsIURI> mURI; mutable nsCOMPtr<nsIURI> mURINoRef; mutable RefPtr<nsAtom> mScheme; mutable nsCString mHost; + mutable RefPtr<nsAtom> mHostAtom; mutable nsString mPath; mutable nsString mFilePath; mutable nsString mSpec; mutable nsCString mCSpec; mutable Maybe<bool> mInheritsPrincipal; };
--- a/toolkit/components/extensions/WebExtensionPolicy.cpp +++ b/toolkit/components/extensions/WebExtensionPolicy.cpp @@ -6,16 +6,17 @@ #include "mozilla/ExtensionPolicyService.h" #include "mozilla/extensions/WebExtensionContentScript.h" #include "mozilla/extensions/WebExtensionPolicy.h" #include "mozilla/AddonManagerWebAPI.h" #include "mozilla/ResultExtensions.h" #include "nsEscape.h" #include "nsIDocShell.h" +#include "nsIObserver.h" #include "nsISubstitutingProtocolHandler.h" #include "nsNetUtil.h" #include "nsPrintfCString.h" namespace mozilla { namespace extensions { using namespace dom; @@ -29,16 +30,19 @@ static const char kBackgroundPageHTMLSta static const char kBackgroundPageHTMLScript[] = "\n\ <script type=\"text/javascript\" src=\"%s\"></script>"; static const char kBackgroundPageHTMLEnd[] = "\n\ <body>\n\ </html>"; +static const char kRestrictedDomainPref[] = + "extensions.webextensions.restrictedDomains"; + static inline ExtensionPolicyService& EPS() { return ExtensionPolicyService::GetSingleton(); } static nsISubstitutingProtocolHandler* Proto() @@ -260,16 +264,116 @@ WebExtensionPolicy::UseRemoteWebExtensio } /* static */ bool WebExtensionPolicy::IsExtensionProcess(GlobalObject& aGlobal) { return EPS().IsExtensionProcess(); } +namespace { + /** + * Maintains a dynamically updated AtomSet based on the comma-separated + * values in the given string pref. + */ + class AtomSetPref : public nsIObserver + , public nsSupportsWeakReference + { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + static already_AddRefed<AtomSetPref> + Create(const char* aPref) + { + RefPtr<AtomSetPref> self = new AtomSetPref(aPref); + Preferences::AddWeakObserver(self, aPref); + return self.forget(); + } + + const AtomSet& Get() const; + + bool Contains(const nsAtom* aAtom) const + { + return Get().Contains(aAtom); + } + + protected: + virtual ~AtomSetPref() = default; + + AtomSetPref(const char* aPref) : mPref(aPref) + {} + + private: + mutable Maybe<AtomSet> mAtomSet; + const char* mPref; + }; + + const AtomSet& + AtomSetPref::Get() const + { + if (mAtomSet.isNothing()) { + nsAutoCString eltsString; + Unused << Preferences::GetCString(mPref, eltsString); + + AutoTArray<nsString, 32> elts; + for (const nsACString& elt : eltsString.Split(',')) { + elts.AppendElement(NS_ConvertUTF8toUTF16(elt)); + elts.LastElement().StripWhitespace(); + } + mAtomSet.emplace(elts); + } + + return mAtomSet.ref(); + } + + NS_IMETHODIMP + AtomSetPref::Observe(nsISupports *aSubject, const char *aTopic, + const char16_t *aData) + { + mAtomSet.reset(); + return NS_OK; + } + + NS_IMPL_ISUPPORTS(AtomSetPref, nsIObserver, nsISupportsWeakReference) +}; + +/* static */ bool +WebExtensionPolicy::IsRestrictedDoc(const DocInfo& aDoc) +{ + // With the exception of top-level about:blank documents with null + // principals, we never match documents that have non-codebase principals, + // including those with null principals or system principals. + if (aDoc.Principal() && !aDoc.Principal()->GetIsCodebasePrincipal()) { + return true; + } + + return IsRestrictedURI(aDoc.PrincipalURL()); +} + +/* static */ bool +WebExtensionPolicy::IsRestrictedURI(const URLInfo &aURI) +{ + static RefPtr<AtomSetPref> domains; + if (!domains) { + domains = AtomSetPref::Create(kRestrictedDomainPref); + ClearOnShutdown(&domains); + } + + if (domains->Contains(aURI.HostAtom())) { + return true; + } + + if (AddonManagerWebAPI::IsValidSite(aURI.URI())) { + return true; + } + + return false; +} + nsCString WebExtensionPolicy::BackgroundPageHTML() const { nsAutoCString result; if (mBackgroundScripts.IsNull()) { result.SetIsVoid(true); return result; @@ -358,17 +462,16 @@ WebExtensionContentScript::WebExtensionC mIncludeGlobs.SetValue().AppendElements(aInit.mIncludeGlobs.Value()); } if (!aInit.mExcludeGlobs.IsNull()) { mExcludeGlobs.SetValue().AppendElements(aInit.mExcludeGlobs.Value()); } } - bool WebExtensionContentScript::Matches(const DocInfo& aDoc) const { if (!mFrameID.IsNull()) { if (aDoc.FrameID() != mFrameID.Value()) { return false; } } else { @@ -385,30 +488,21 @@ WebExtensionContentScript::Matches(const // matchAboutBlank is true and it has the null principal. In all other // cases, we test the URL of the principal that it inherits. if (mMatchAboutBlank && aDoc.IsTopLevel() && aDoc.URL().Spec().EqualsLiteral("about:blank") && aDoc.Principal() && aDoc.Principal()->GetIsNullPrincipal()) { return true; } - // With the exception of top-level about:blank documents with null - // principals, we never match documents that have non-codebase principals, - // including those with null principals or system principals. - if (aDoc.Principal() && !aDoc.Principal()->GetIsCodebasePrincipal()) { + if (mExtension->IsRestrictedDoc(aDoc)) { return false; } - // Content scripts are not allowed on pages that have elevated - // privileges via mozAddonManager (see bug 1280234) - if (AddonManagerWebAPI::IsValidSite(aDoc.PrincipalURL().URI())) { - return false; - } - - URLInfo urlinfo(aDoc.PrincipalURL()); + auto& urlinfo = aDoc.PrincipalURL(); if (mHasActiveTabPermission && aDoc.ShouldMatchActiveTabPermission() && MatchPattern::MatchesAllURLs(urlinfo)) { return true; } return MatchesURI(urlinfo); } @@ -426,17 +520,17 @@ WebExtensionContentScript::MatchesURI(co if (!mIncludeGlobs.IsNull() && !mIncludeGlobs.Value().Matches(aURL.Spec())) { return false; } if (!mExcludeGlobs.IsNull() && mExcludeGlobs.Value().Matches(aURL.Spec())) { return false; } - if (AddonManagerWebAPI::IsValidSite(aURL.URI())) { + if (mExtension->IsRestrictedURI(aURL)) { return false; } return true; } JSObject*
--- a/toolkit/components/extensions/WebExtensionPolicy.h +++ b/toolkit/components/extensions/WebExtensionPolicy.h @@ -20,16 +20,17 @@ #include "nsWrapperCache.h" namespace mozilla { namespace extensions { using dom::WebExtensionInit; using dom::WebExtensionLocalizeCallback; +class DocInfo; class WebExtensionContentScript; class WebExtensionPolicy final : public nsISupports , public nsWrapperCache , public SupportsWeakPtr<WebExtensionPolicy> { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -62,33 +63,37 @@ public: void RegisterContentScript(WebExtensionContentScript& script, ErrorResult& aRv); void UnregisterContentScript(const WebExtensionContentScript& script, ErrorResult& aRv); bool CanAccessURI(const URLInfo& aURI, bool aExplicit = false) const { - return mHostPermissions && mHostPermissions->Matches(aURI, aExplicit); + return (!IsRestrictedURI(aURI) && + mHostPermissions && mHostPermissions->Matches(aURI, aExplicit)); } bool IsPathWebAccessible(const nsAString& aPath) const { return mWebAccessiblePaths.Matches(aPath); } bool HasPermission(const nsAtom* aPermission) const { return mPermissions->Contains(aPermission); } bool HasPermission(const nsAString& aPermission) const { return mPermissions->Contains(aPermission); } + static bool IsRestrictedDoc(const DocInfo& aDoc); + static bool IsRestrictedURI(const URLInfo& aURI); + nsCString BackgroundPageHTML() const; void Localize(const nsAString& aInput, nsString& aResult) const; const nsString& Name() const { return mName; }
--- a/toolkit/components/extensions/webrequest/ChannelWrapper.cpp +++ b/toolkit/components/extensions/webrequest/ChannelWrapper.cpp @@ -370,37 +370,31 @@ ChannelWrapper::IsSystemLoad() const if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) { return IsSystemPrincipal(prin); } } return false; } bool -ChannelWrapper::GetCanModify(ErrorResult& aRv) const +ChannelWrapper::CanModify() const { - nsCOMPtr<nsIURI> uri = FinalURI(); - nsAutoCString spec; - if (uri) { - uri->GetSpec(spec); - } - if (!uri || AddonManagerWebAPI::IsValidSite(uri)) { + if (WebExtensionPolicy::IsRestrictedURI(FinalURLInfo())) { return false; } if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { if (nsIPrincipal* prin = loadInfo->LoadingPrincipal()) { if (IsSystemPrincipal(prin)) { return false; } - if (prin->GetIsCodebasePrincipal() && - (NS_FAILED(prin->GetURI(getter_AddRefs(uri))) || - AddonManagerWebAPI::IsValidSite(uri))) { - return false; + auto* docURI = DocumentURLInfo(); + if (docURI && WebExtensionPolicy::IsRestrictedURI(*docURI)) { + return false; } } } return true; } already_AddRefed<nsIURI> ChannelWrapper::GetOriginURI() const @@ -642,17 +636,17 @@ ChannelWrapper::GetFrameAncestors(nsILoa * Response filtering *****************************************************************************/ void ChannelWrapper::RegisterTraceableChannel(const WebExtensionPolicy& aAddon, nsITabParent* aTabParent) { // We can't attach new listeners after the response has started, so don't // bother registering anything. - if (mResponseStarted) { + if (mResponseStarted || !CanModify()) { return; } mAddonEntries.Put(aAddon.Id(), aTabParent); if (!mChannelEntry) { mChannelEntry = WebRequestService::GetSingleton().RegisterChannel(this); CheckEventListeners(); }
--- a/toolkit/components/extensions/webrequest/ChannelWrapper.h +++ b/toolkit/components/extensions/webrequest/ChannelWrapper.h @@ -204,17 +204,21 @@ public: already_AddRefed<nsIURI> GetDocumentURI() const; already_AddRefed<nsILoadContext> GetLoadContext() const; already_AddRefed<nsIDOMElement> GetBrowserElement() const; - bool GetCanModify(ErrorResult& aRv) const; + bool CanModify() const; + bool GetCanModify(ErrorResult& aRv) const + { + return CanModify(); + } void GetProxyInfo(dom::Nullable<dom::MozProxyInfo>& aRetVal, ErrorResult& aRv) const; void GetRemoteAddress(nsCString& aRetVal) const; void GetRequestHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal, ErrorResult& aRv) const;
--- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -759,17 +759,17 @@ HttpObserverManager = { data.requestHeaders = requestHeaders.toArray(); } if (opts.responseHeaders) { responseHeaders = responseHeaders || new ResponseHeaderChanger(channel); data.responseHeaders = responseHeaders.toArray(); } - if (opts.requestBody) { + if (opts.requestBody && channel.canModify) { requestBody = requestBody || WebRequestUpload.createRequestBody(channel.channel); data.requestBody = requestBody; } try { let result = callback(data); // isProxy is set during onAuth if the auth request is for a proxy.