Bug 1254194: Apply a content security policy to all WebExtension documents. r?gabor draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 14 Apr 2016 16:49:37 -0700
changeset 351737 a2531de05c47931dd2ce4f7b49e60223f937e771
parent 351736 f9fd38f0a756013c53ca754b198cdd003db6ad45
child 351738 6b174c367e1b96ac14f539437657d918ab0af581
push id15524
push usermaglione.k@gmail.com
push dateFri, 15 Apr 2016 01:09:46 +0000
reviewersgabor
bugs1254194
milestone48.0a1
Bug 1254194: Apply a content security policy to all WebExtension documents. r?gabor MozReview-Commit-ID: HsFFbWdq00b
caps/BasePrincipal.cpp
caps/BasePrincipal.h
caps/nsIPrincipal.idl
dom/base/nsDocument.cpp
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -511,16 +511,23 @@ BasePrincipal::GetAppId(uint32_t* aAppId
     return NS_OK;
   }
 
   *aAppId = AppId();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+BasePrincipal::GetAddonId(nsAString& aAddonId)
+{
+  aAddonId.Assign(mOriginAttributes.mAddonId);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 BasePrincipal::GetUserContextId(uint32_t* aUserContextId)
 {
   *aUserContextId = UserContextId();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -210,31 +210,33 @@ public:
   NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
   NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
   NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) final;
   NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final;
   NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
   NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final;
   NS_IMETHOD GetAppId(uint32_t* aAppStatus) final;
+  NS_IMETHOD GetAddonId(nsAString& aAddonId) final;
   NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final;
   NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) final;
   NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
 
   virtual bool IsOnCSSUnprefixingWhitelist() override { return false; }
 
   virtual bool IsCodebasePrincipal() const { return false; };
 
   static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
   static already_AddRefed<BasePrincipal>
   CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttributes& aAttrs);
   static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(const nsACString& aOrigin);
 
   const PrincipalOriginAttributes& OriginAttributesRef() { return mOriginAttributes; }
   uint32_t AppId() const { return mOriginAttributes.mAppId; }
+  inline const nsAString& AddonId() const { return mOriginAttributes.mAddonId; }
   uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
   bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
 
   enum PrincipalKind {
     eNullPrincipal,
     eCodebasePrincipal,
     eExpandedPrincipal,
     eSystemPrincipal
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -291,16 +291,21 @@ interface nsIPrincipal : nsISerializable
      * origin as the app.
      *
      * If you're doing a security check based on appId, you must check
      * appStatus as well.
      */
     [infallible] readonly attribute unsigned long appId;
 
     /**
+     * Gets the ID of the add-on this principal belongs to.
+     */
+    readonly attribute AString addonId;
+
+    /**
      * Gets the id of the user context this principal is inside.  If this
      * principal is inside the default userContext, this returns
      * nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID.
      */
     [infallible] readonly attribute unsigned long userContextId;
 
     /**
      * Returns true iff the principal is inside an isolated mozbrowser element.
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -195,16 +195,17 @@
 #include "mozilla/dom/TouchEvent.h"
 
 #include "mozilla/Preferences.h"
 
 #include "imgILoader.h"
 #include "imgRequestProxy.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsSandboxFlags.h"
+#include "nsIAddonPolicyService.h"
 #include "nsIAppsService.h"
 #include "mozilla/dom/AnimatableBinding.h"
 #include "mozilla/dom/AnonymousContent.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/HTMLBodyElement.h"
@@ -2811,22 +2812,26 @@ nsDocument::InitCSP(nsIChannel* aChannel
       }
       appsService->GetDefaultCSPByLocalId(appId, appDefaultCSP);
       if (!appDefaultCSP.IsEmpty()) {
         applyAppDefaultCSP = true;
       }
     }
   }
 
- // Check if this is part of the Loop/Hello service
- bool applyLoopCSP = IsLoopDocument(aChannel);
+  // Check if this is a document from a WebExtension.
+  bool applyAddonCSP = !BasePrincipal::Cast(principal)->AddonId().IsEmpty();
+
+  // Check if this is part of the Loop/Hello service
+  bool applyLoopCSP = IsLoopDocument(aChannel);
 
   // If there's no CSP to apply, go ahead and return early
   if (!applyAppDefaultCSP &&
       !applyAppManifestCSP &&
+      !applyAddonCSP &&
       !applyLoopCSP &&
       cspHeaderValue.IsEmpty() &&
       cspROHeaderValue.IsEmpty()) {
     if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
       nsCOMPtr<nsIURI> chanURI;
       aChannel->GetURI(getter_AddRefs(chanURI));
       nsAutoCString aspec;
       chanURI->GetAsciiSpec(aspec);
@@ -2874,16 +2879,32 @@ nsDocument::InitCSP(nsIChannel* aChannel
     csp->AppendPolicy(appDefaultCSP, false, false);
   }
 
   // ----- if the doc is an app and specifies a CSP in its manifest, apply it.
   if (applyAppManifestCSP) {
     csp->AppendPolicy(appManifestCSP, false, false);
   }
 
+  // ----- if the doc is an addon, apply its CSP.
+  if (applyAddonCSP) {
+    nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
+
+    nsAutoString addonCSP;
+    rv = aps->GetBaseCSP(addonCSP);
+    if (NS_SUCCEEDED(rv)) {
+      csp->AppendPolicy(addonCSP, false, false);
+    }
+
+    rv = aps->GetAddonCSP(BasePrincipal::Cast(principal)->AddonId(), addonCSP);
+    if (NS_SUCCEEDED(rv)) {
+      csp->AppendPolicy(addonCSP, false, false);
+    }
+  }
+
   // ----- if the doc is part of Loop, apply the loop CSP
   if (applyLoopCSP) {
     nsAdoptingString loopCSP;
     loopCSP = Preferences::GetString("loop.CSP");
     NS_ASSERTION(loopCSP, "Missing loop.CSP preference");
     // If the pref has been removed, we continue without setting a CSP
     if (loopCSP) {
       csp->AppendPolicy(loopCSP, false, false);