Bug 1297687 - Use the OriginAttributes associated with a window principal when creating a Sandbox with an expanded principal; r=baku
☠☠ backed out by 63d190efe42e ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 31 Aug 2016 17:58:08 -0400
changeset 312343 1e7eb0625d3e5e7073b3978dcf900cbc83e7ce71
parent 312342 247a05cd82408233e48898c7d1fecd08c6ae897d
child 312344 f8252a5b57fd3bfc0274413173dfcb55059ddb5f
push id20447
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:36:44 +0000
treeherderfx-team@969397f22187 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1297687
milestone51.0a1
Bug 1297687 - Use the OriginAttributes associated with a window principal when creating a Sandbox with an expanded principal; r=baku
caps/nsIScriptSecurityManager.idl
caps/nsPrincipal.cpp
caps/nsPrincipal.h
caps/nsScriptSecurityManager.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/tests/browser/browser.ini
js/xpconnect/tests/browser/browser_expandedPrincipal_originAttributes.js
--- a/caps/nsIScriptSecurityManager.idl
+++ b/caps/nsIScriptSecurityManager.idl
@@ -250,16 +250,24 @@ interface nsIScriptSecurityManager : nsI
 
     /**
      * Get the codebase principal for the channel's URI.
      * aChannel must not be null.
      */
     nsIPrincipal getChannelURIPrincipal(in nsIChannel aChannel);
 
     /**
+     * Get the principal for a sandbox object.
+     *
+     * This function is currently only used in tests.
+     */
+    [implicit_jscontext]
+    nsIPrincipal getSandboxPrincipal(in jsval aSandbox);
+
+    /**
      * Check whether a given principal is a system principal.  This allows us
      * to avoid handing back the system principal to script while allowing
      * script to check whether a given principal is system.
      */
     boolean isSystemPrincipal(in nsIPrincipal aPrincipal);
 %{C++
     bool IsSystemPrincipal(nsIPrincipal* aPrincipal) {
       bool isSystem = false;
--- a/caps/nsPrincipal.cpp
+++ b/caps/nsPrincipal.cpp
@@ -669,17 +669,24 @@ struct OriginComparator
     NS_ENSURE_SUCCESS(rv, false);
     nsAutoCString originB;
     rv = b->GetOrigin(originB);
     NS_ENSURE_SUCCESS(rv, false);
     return a == b;
   }
 };
 
-nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWhiteList)
+nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
+                                         const PrincipalOriginAttributes& aOriginAttributes)
+  : nsExpandedPrincipal(aWhiteList)
+{
+  mOriginAttributes = aOriginAttributes;
+}
+
+nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList)
 {
   // We force the principals to be sorted by origin so that nsExpandedPrincipal
   // origins can have a canonical form.
   OriginComparator c;
   for (size_t i = 0; i < aWhiteList.Length(); ++i) {
     mPrincipals.InsertElementSorted(aWhiteList[i], c);
   }
 }
--- a/caps/nsPrincipal.h
+++ b/caps/nsPrincipal.h
@@ -62,17 +62,19 @@ protected:
 
   bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override;
   bool MayLoadInternal(nsIURI* aURI) override;
 };
 
 class nsExpandedPrincipal : public nsIExpandedPrincipal, public mozilla::BasePrincipal
 {
 public:
-  explicit nsExpandedPrincipal(nsTArray< nsCOMPtr<nsIPrincipal> > &aWhiteList);
+  nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
+                      const mozilla::PrincipalOriginAttributes& aOriginAttributes);
+  explicit nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList);
 
   NS_DECL_NSIEXPANDEDPRINCIPAL
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); };
   NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); };
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -62,16 +62,17 @@
 #include <stdint.h>
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsILoadInfo.h"
 #include "nsXPCOMStrings.h"
+#include "xpcprivate.h"
 
 // This should be probably defined on some other place... but I couldn't find it
 #define WEBAPPS_PERM_NAME "webapps-manage"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
@@ -468,16 +469,28 @@ nsScriptSecurityManager::GetChannelURIPr
     rv = MaybeSetAddonIdFromURI(attrs, uri);
     NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
     prin.forget(aPrincipal);
     return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
+nsScriptSecurityManager::GetSandboxPrincipal(JS::HandleValue aSandboxArg,
+                                             JSContext* aCx,
+                                             nsIPrincipal** aPrincipal)
+{
+  if (!aSandboxArg.isObject()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  JS::RootedObject sandbox(aCx, &aSandboxArg.toObject());
+  return xpc::GetSandboxPrincipal(aCx, sandbox, aPrincipal);
+}
+
+NS_IMETHODIMP
 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
                                            bool* aIsSystem)
 {
     *aIsSystem = (aPrincipal == mSystemPrincipal);
     return NS_OK;
 }
 
 /////////////////////////////
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1321,59 +1321,70 @@ GetExpandedPrincipal(JSContext* cx, Hand
         // report error.
         JS_ReportError(cx, "Expected an array of URI strings");
         return false;
     }
 
     nsTArray< nsCOMPtr<nsIPrincipal> > allowedDomains(length);
     allowedDomains.SetLength(length);
 
+    nsCOMPtr<nsIPrincipal> windowPrincipal;
+
     for (uint32_t i = 0; i < length; ++i) {
         RootedValue allowed(cx);
         if (!JS_GetElement(cx, arrayObj, i, &allowed))
             return false;
 
         nsresult rv;
         nsCOMPtr<nsIPrincipal> principal;
         if (allowed.isString()) {
             // In case of string let's try to fetch a codebase principal from it.
             RootedString str(cx, allowed.toString());
 
-            // We use a default originAttributes here because we don't support
+            // We use a default context ID here because we don't support
             // passing a userContextId with an array.
             PrincipalOriginAttributes attrs;
             if (!ParsePrincipal(cx, str, attrs, getter_AddRefs(principal)))
                 return false;
 
         } else if (allowed.isObject()) {
             // In case of object let's see if it's a Principal or a ScriptObjectPrincipal.
             nsCOMPtr<nsISupports> prinOrSop;
             RootedObject obj(cx, &allowed.toObject());
             if (!GetPrincipalOrSOP(cx, obj, getter_AddRefs(prinOrSop)))
                 return false;
 
             nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(prinOrSop));
             principal = do_QueryInterface(prinOrSop);
             if (sop)
                 principal = sop->GetPrincipal();
+
+            // If a Window object has been passed, the expanded principal will inherit
+            // its OriginAttributes.  If more than one Window object has been passed, use
+            // the last one.
+            windowPrincipal = principal;
         }
         NS_ENSURE_TRUE(principal, false);
 
         // We do not allow ExpandedPrincipals to contain any system principals.
         bool isSystem;
         rv = nsXPConnect::SecurityManager()->IsSystemPrincipal(principal, &isSystem);
         NS_ENSURE_SUCCESS(rv, false);
         if (isSystem) {
             JS_ReportError(cx, "System principal is not allowed in an expanded principal");
             return false;
         }
         allowedDomains[i] = principal;
   }
 
-  nsCOMPtr<nsIExpandedPrincipal> result = new nsExpandedPrincipal(allowedDomains);
+  PrincipalOriginAttributes attrs;
+  if (windowPrincipal) {
+      attrs = BasePrincipal::Cast(windowPrincipal)->OriginAttributesRef();
+  }
+  RefPtr<nsExpandedPrincipal> result = new nsExpandedPrincipal(allowedDomains, attrs);
   result.forget(out);
   return true;
 }
 
 /*
  * Helper that tries to get a property from the options object.
  */
 bool
@@ -1734,16 +1745,36 @@ nsXPCComponents_utils_Sandbox::CallOrCon
     if (!options.wantXrays && !xpc::WrapperFactory::WaiveXrayAndWrap(cx, args.rval()))
         return NS_ERROR_UNEXPECTED;
 
     *_retval = true;
     return NS_OK;
 }
 
 nsresult
+xpc::GetSandboxPrincipal(JSContext* aCx, HandleObject aSandboxArg,
+                         nsIPrincipal** aPrincipal)
+{
+    JS_AbortIfWrongThread(aCx);
+
+    RootedObject sandbox(aCx, js::CheckedUnwrap(aSandboxArg));
+    if (!sandbox || !IsSandbox(sandbox)) {
+        return NS_ERROR_INVALID_ARG;
+    }
+
+    nsIScriptObjectPrincipal* sop =
+        static_cast<nsIScriptObjectPrincipal*>(xpc_GetJSPrivate(sandbox));
+    MOZ_ASSERT(sop, "Invalid sandbox passed");
+    nsCOMPtr<nsIPrincipal> prin = sop->GetPrincipal();
+    prin.forget(aPrincipal);
+
+    return NS_OK;
+}
+
+nsresult
 xpc::EvalInSandbox(JSContext* cx, HandleObject sandboxArg, const nsAString& source,
                    const nsACString& filename, int32_t lineNo,
                    JSVersion jsVersion, MutableHandleValue rval)
 {
     JS_AbortIfWrongThread(cx);
     rval.set(UndefinedValue());
 
     bool waiveXray = xpc::WrapperFactory::HasWaiveXrayFlag(sandboxArg);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3290,16 +3290,20 @@ GetSandboxAddonId(JSContext* cx, JS::Han
 nsresult
 GetSandboxMetadata(JSContext* cx, JS::HandleObject sandboxArg,
                    JS::MutableHandleValue rval);
 
 nsresult
 SetSandboxMetadata(JSContext* cx, JS::HandleObject sandboxArg,
                    JS::HandleValue metadata);
 
+nsresult
+GetSandboxPrincipal(JSContext* aCx, JS::HandleObject aSandboxArg,
+                    nsIPrincipal** aPrincipal);
+
 bool
 CreateObjectIn(JSContext* cx, JS::HandleValue vobj, CreateObjectInOptions& options,
                JS::MutableHandleValue rval);
 
 bool
 EvalInWindow(JSContext* cx, const nsAString& source, JS::HandleObject scope,
              JS::MutableHandleValue rval);
 
--- a/js/xpconnect/tests/browser/browser.ini
+++ b/js/xpconnect/tests/browser/browser.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 support-files =
   browser_deadObjectOnUnload.html
 [browser_dead_object.js]
+[browser_expandedPrincipal_originAttributes.js]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/browser/browser_expandedPrincipal_originAttributes.js
@@ -0,0 +1,38 @@
+/* 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/.
+ */
+
+add_task(function* test() {
+  let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true});
+
+  yield ContentTask.spawn(privateWin.gBrowser.selectedBrowser, {}, function*() {
+    let tests = [
+      [["https://mozilla.org", content], 1],
+      [["https://mozilla.org", "https://example.com"], 0],
+    ];
+    tests.forEach(item => {
+      let sandbox = Components.utils.Sandbox(item[0]);
+      let principal = Services.scriptSecurityManager
+                              .getSandboxPrincipal(sandbox);
+      is(principal.privateBrowsingId, item[1],
+         "Sandbox principal should have the correct OriginAttributes");
+    });
+  });
+
+  privateWin.close();
+
+  yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
+    let tests = [
+      [["https://mozilla.org", content], 0],
+      [["https://mozilla.org", "https://example.com"], 0],
+    ];
+    tests.forEach(item => {
+      let sandbox = Components.utils.Sandbox(item[0]);
+      let principal = Services.scriptSecurityManager
+                              .getSandboxPrincipal(sandbox);
+      is(principal.privateBrowsingId, item[1],
+         "Sandbox principal should have the correct OriginAttributes");
+    });
+  });
+});