Bug 1363977 - Have loadTabs() provide the correct triggeringPrincipal. r=gijs,smaug
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Mon, 29 May 2017 21:32:21 +0200
changeset 409373 c95cd85e640081adf0cbe047a41bc45478bbf3d5
parent 409372 316c45d626f1e99d293df942c7f4249957fabfcb
child 409374 99a694a8b9a8654474d93e2a15e70e04eca917d0
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs, smaug
bugs1363977
milestone55.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 1363977 - Have loadTabs() provide the correct triggeringPrincipal. r=gijs,smaug
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/components/places/PlacesUIUtils.jsm
browser/components/syncedtabs/TabListComponent.js
docshell/base/nsDocShellTreeOwner.cpp
dom/interfaces/base/nsIBrowser.idl
dom/interfaces/base/nsITabChild.idl
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
toolkit/content/widgets/browser.xml
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1421,17 +1421,21 @@ var gBrowserInit = {
         for (let i = 0; i < count; i++) {
           let urisstring = uriToLoad.queryElementAt(i, Ci.nsISupportsString);
           specs.push(urisstring.data);
         }
 
         // This function throws for certain malformed URIs, so use exception handling
         // so that we don't disrupt startup
         try {
-          gBrowser.loadTabs(specs, false, true);
+          gBrowser.loadTabs(specs, {
+            inBackground: false,
+            replace: true,
+            // Bug 1365232, provide correct triggeringPrincipal
+          });
         } catch (e) {}
       } else if (uriToLoad instanceof XULElement) {
         // swap the given tab with the default about:blank tab and then close
         // the original tab in the other window.
         let tabToOpen = uriToLoad;
 
         // If this tab was passed as a window argument, clear the
         // reference to it from the arguments array.
@@ -2159,17 +2163,20 @@ function BrowserGoHome(aEvent) {
   switch (where) {
   case "current":
     loadOneOrMoreURIs(homePage);
     break;
   case "tabshifted":
   case "tab":
     urls = homePage.split("|");
     var loadInBackground = getBoolPref("browser.tabs.loadBookmarksInBackground", false);
-    gBrowser.loadTabs(urls, loadInBackground);
+    gBrowser.loadTabs(urls, {
+      inBackground: loadInBackground,
+      triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+    });
     break;
   case "window":
     OpenBrowserWindow();
     break;
   }
 }
 
 function loadOneOrMoreURIs(aURIString) {
@@ -2177,17 +2184,21 @@ function loadOneOrMoreURIs(aURIString) {
   if (window.location.href != getBrowserURL()) {
     window.openDialog(getBrowserURL(), "_blank", "all,dialog=no", aURIString);
     return;
   }
 
   // This function throws for certain malformed URIs, so use exception handling
   // so that we don't disrupt startup
   try {
-    gBrowser.loadTabs(aURIString.split("|"), false, true);
+    gBrowser.loadTabs(aURIString.split("|"), {
+      inBackground: false,
+      replace: true,
+      // Bug 1365232, provide correct triggeringPrincipal
+    });
   } catch (e) {
   }
 }
 
 function focusAndSelectUrlBar() {
   // In customize mode, the url bar is disabled. If a new tab is opened or the
   // user switches to a different tab, this function gets called before we've
   // finished leaving customize mode, and the url bar will still be disabled.
@@ -5824,24 +5835,25 @@ function stripUnsafeProtocolOnPaste(past
                                         () => {
                                                 changed = true;
                                                 return "";
                                               });
   return changed ? pasteDataNoJS : pasteData;
 }
 
 // handleDroppedLink has the following 2 overloads:
-//   handleDroppedLink(event, url, name)
-//   handleDroppedLink(event, links)
-function handleDroppedLink(event, urlOrLinks, name) {
+//   handleDroppedLink(event, url, name, triggeringPrincipal)
+//   handleDroppedLink(event, links, triggeringPrincipal)
+function handleDroppedLink(event, urlOrLinks, nameOrTriggeringPrincipal, triggeringPrincipal) {
   let links;
   if (Array.isArray(urlOrLinks)) {
     links = urlOrLinks;
+    triggeringPrincipal = nameOrTriggeringPrincipal;
   } else {
-    links = [{ url: urlOrLinks, name, type: "" }];
+    links = [{ url: urlOrLinks, nameOrTriggeringPrincipal, type: "" }];
   }
 
   let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
 
   let userContextId = gBrowser.selectedBrowser.getAttribute("usercontextid");
 
   // event is null if links are dropped in content process.
   // inBackground should be false, as it's loading into current browser.
@@ -5862,16 +5874,17 @@ function handleDroppedLink(event, urlOrL
     }
     if (lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
       gBrowser.loadTabs(urls, {
         inBackground,
         replace: true,
         allowThirdPartyFixup: false,
         postDatas,
         userContextId,
+        triggeringPrincipal,
       });
     }
   })();
 
   // If links are dropped in content process, event.preventDefault() should be
   // called in content process.
   if (event) {
     // Keep the event from being handled by the dragDrop listeners
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -6986,23 +6986,31 @@
           if (event.shiftKey)
             inBackground = !inBackground;
 
           let targetTab = this._getDragTargetTab(event, true);
           let userContextId = this.selectedItem.getAttribute("usercontextid");
           let replace = !!targetTab;
           let newIndex = this._getDropIndex(event, true);
           let urls = links.map(link => link.url);
+
+
+          // Bug 1367038: mozSourceNode is null if the drag event originated
+          // in an external application - needs better fallback!
+          let triggeringPrincipal = dt.mozSourceNode
+            ? dt.mozSourceNode.nodePrincipal
+            : Services.scriptSecurityManager.getSystemPrincipal();
           this.tabbrowser.loadTabs(urls, {
             inBackground,
             replace,
             allowThirdPartyFixup: true,
             targetTab,
             newIndex,
             userContextId,
+            triggeringPrincipal,
           });
         }
 
         if (draggedTab) {
           delete draggedTab._dragData;
         }
       ]]></handler>
 
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -948,17 +948,21 @@ this.PlacesUIUtils = {
                                              null, "chrome,dialog=no,all", args);
       return;
     }
 
     var loadInBackground = where == "tabshifted" ? true : false;
     // For consistency, we want all the bookmarks to open in new tabs, instead
     // of having one of them replace the currently focused tab.  Hence we call
     // loadTabs with aReplace set to false.
-    browserWindow.gBrowser.loadTabs(urls, loadInBackground, false);
+    browserWindow.gBrowser.loadTabs(urls, {
+      inBackground: loadInBackground,
+      replace: false,
+      triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+    });
   },
 
   openLiveMarkNodesInTabs:
   function PUIU_openLiveMarkNodesInTabs(aNode, aEvent, aView) {
     let window = aView.ownerWindow;
 
     PlacesUtils.livemarks.getLivemark({id: aNode.itemId})
       .then(aLivemark => {
--- a/browser/components/syncedtabs/TabListComponent.js
+++ b/browser/components/syncedtabs/TabListComponent.js
@@ -10,16 +10,18 @@ Cu.import("resource://gre/modules/XPCOMU
 
 let log = Cu.import("resource://gre/modules/Log.jsm", {})
             .Log.repository.getLogger("Sync.RemoteTabs");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
   "resource:///modules/BrowserUITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
   "resource:///modules/PlacesUIUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+  "resource://gre/modules/Services.jsm");
 
 this.EXPORTED_SYMBOLS = [
   "TabListComponent"
 ];
 
 /**
  * TabListComponent
  *
@@ -122,17 +124,21 @@ TabListComponent.prototype = {
     if (!PlacesUIUtils.confirmOpenInTabs(urls.length, this._window)) {
       return;
     }
     if (where == "window") {
       this._window.openDialog(this._window.getBrowserURL(), "_blank",
                               "chrome,dialog=no,all", urls.join("|"));
     } else {
       let loadInBackground = where == "tabshifted" ? true : false;
-      this._getChromeWindow(this._window).gBrowser.loadTabs(urls, loadInBackground, false);
+      this._getChromeWindow(this._window).gBrowser.loadTabs(urls, {
+        inBackground: loadInBackground,
+        replace: false,
+        triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+      });
     }
     BrowserUITelemetry.countSyncedTabEvent("openmultiple", "sidebar");
   },
 
   onCopyTabLocation(url) {
     this._clipboardHelper.copyString(url);
   },
 
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -989,17 +989,30 @@ nsDocShellTreeOwner::HandleEvent(nsIDOME
       nsIDroppedLinkItem** links;
       if (webnav &&
           NS_SUCCEEDED(handler->DropLinks(dragEvent, true, &linksCount, &links))) {
         if (linksCount >= 1) {
           nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
           if (webBrowserChrome) {
             nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(webBrowserChrome);
             if (tabChild) {
-              nsresult rv = tabChild->RemoteDropLinks(linksCount, links);
+              nsCOMPtr<nsIDOMDataTransfer> domDataTransfer;
+              dragEvent->GetDataTransfer(getter_AddRefs(domDataTransfer));
+              NS_ENSURE_TRUE(domDataTransfer, NS_ERROR_UNEXPECTED);
+              nsCOMPtr<nsIDOMNode> domSourceNode;
+              domDataTransfer->GetMozSourceNode(getter_AddRefs(domSourceNode));
+              nsCOMPtr<nsINode> sourceNode = do_QueryInterface(domSourceNode);
+              nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+              if (sourceNode) {
+                triggeringPrincipal = sourceNode->NodePrincipal();
+              } else {
+                triggeringPrincipal = NullPrincipal::Create();
+              }
+              nsresult rv = tabChild->RemoteDropLinks(linksCount, links,
+                                                      triggeringPrincipal);
               for (uint32_t i = 0; i < linksCount; i++) {
                 NS_RELEASE(links[i]);
               }
               free(links);
               return rv;
             }
           }
           nsAutoString url;
--- a/dom/interfaces/base/nsIBrowser.idl
+++ b/dom/interfaces/base/nsIBrowser.idl
@@ -1,14 +1,15 @@
 /* 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 "nsISupports.idl"
 
 interface nsIFrameLoader;
+interface nsIPrincipal;
 
 [scriptable, uuid(14e5a0cb-e223-4202-95e8-fe53275193ea)]
 interface nsIBrowser : nsISupports
 {
   /**
    * Gets an optional frame loader that is "related" to this browser.
    * If this exists, then we should attempt to use the same content parent as
    * this frame loader for any new tab parents.  For example, view source
@@ -18,19 +19,22 @@ interface nsIBrowser : nsISupports
   readonly attribute nsIFrameLoader sameProcessAsFrameLoader;
 
   /*
    * Called by the child to inform the parent that links are dropped into
    * content area.
    *
    * @param linksCount length of links
    * @param links a flat array of url, name, and type for each link
+   * @param triggeringPrincipal a principal that initiated loading
+   *                            of the dropped links
    */
   void dropLinks(in unsigned long linksCount,
-                 [array, size_is(linksCount)] in wstring links);
+                 [array, size_is(linksCount)] in wstring links,
+                 in nsIPrincipal aTriggeringPrincipal);
 
   /**
    * Flags for controlling the behavior of swapBrowsers
    */
 
   /**
    * The default options. This is used for swapping browsers between windows
    */
--- a/dom/interfaces/base/nsITabChild.idl
+++ b/dom/interfaces/base/nsITabChild.idl
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "domstubs.idl"
 #include "nsIDroppedLinkHandler.idl"
 
 interface nsIContentFrameMessageManager;
 interface nsIWebBrowserChrome3;
+interface nsIPrincipal;
 
 native CommandsArray(nsTArray<nsCString>);
 [ref] native CommandsArrayRef(nsTArray<nsCString>);
 
 [scriptable, uuid(1fb79c27-e760-4088-b19c-1ce3673ec24e)]
 interface nsITabChild : nsISupports
 {
   readonly attribute nsIContentFrameMessageManager messageManager;
@@ -26,16 +27,17 @@ interface nsITabChild : nsISupports
   [noscript, notxpcom] void enableDisableCommands(in AString action,
                                                   in CommandsArrayRef enabledCommands,
                                                   in CommandsArrayRef disabledCommands);
 
   [noscript] void remoteSizeShellTo(in int32_t width, in int32_t height,
                                     in int32_t shellItemWidth, in int32_t shellItemHeight);
 
   [noscript] void remoteDropLinks(in unsigned long linksCount,
-                                  [array, size_is(linksCount)] in nsIDroppedLinkItem links);
+                                  [array, size_is(linksCount)] in nsIDroppedLinkItem links,
+                                  in nsIPrincipal triggeringPrincipal);
 
   readonly attribute uint64_t tabId;
 
   [noscript, notxpcom] void beforeUnloadAdded();
   [noscript, notxpcom] void beforeUnloadRemoved();
 };
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -16,16 +16,17 @@ include protocol PRenderFrame;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
 include protocol PIPCBlobInputStream;
 include protocol PPaymentRequest;
 
+include PBackgroundSharedTypes;
 include DOMTypes;
 include IPCBlob;
 include IPCStream;
 include JavaScriptTypes;
 include URIParams;
 include PPrintingTypes;
 include PTabContext;
 
@@ -190,17 +191,17 @@ parent:
                       int32_t aShellItemWidth, int32_t aShellItemHeight);
 
     /**
      * Called by the child to inform the parent that links are dropped into
      * content area.
      *
      * aLinks A flat array of url, name, and type for each link
      */
-    async DropLinks(nsString[] aLinks);
+    async DropLinks(nsString[] aLinks, PrincipalInfo aTriggeringPrincipalInfo);
 
     async Event(RemoteDOMEvent aEvent);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     nested(inside_sync) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -743,17 +743,19 @@ TabChild::RemoteSizeShellTo(int32_t aWid
   }
 
   bool sent = SendSizeShellTo(flags, aWidth, aHeight, aShellItemWidth, aShellItemHeight);
 
   return sent ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
-TabChild::RemoteDropLinks(uint32_t aLinksCount, nsIDroppedLinkItem** aLinks)
+TabChild::RemoteDropLinks(uint32_t aLinksCount,
+                          nsIDroppedLinkItem** aLinks,
+                          nsIPrincipal* aTriggeringPrincipal)
 {
   nsTArray<nsString> linksArray;
   nsresult rv = NS_OK;
   for (uint32_t i = 0; i < aLinksCount; i++) {
     nsString tmp;
     rv = aLinks[i]->GetUrl(tmp);
     if (NS_FAILED(rv)) {
       return rv;
@@ -768,17 +770,19 @@ TabChild::RemoteDropLinks(uint32_t aLink
 
     rv = aLinks[i]->GetType(tmp);
     if (NS_FAILED(rv)) {
       return rv;
     }
     linksArray.AppendElement(tmp);
   }
 
-  bool sent = SendDropLinks(linksArray);
+  PrincipalInfo triggeringPrincipalInfo;
+  PrincipalToPrincipalInfo(aTriggeringPrincipal, &triggeringPrincipalInfo);
+  bool sent = SendDropLinks(linksArray, triggeringPrincipalInfo);
 
   return sent ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 TabChild::SizeBrowserTo(int32_t aWidth, int32_t aHeight)
 {
   NS_WARNING("TabChild::SizeBrowserTo not supported in TabChild");
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -521,26 +521,32 @@ TabParent::RecvSizeShellTo(const uint32_
   nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
   NS_ENSURE_TRUE(xulWin, IPC_OK());
   xulWin->SizeShellToWithLimit(width, height, aShellItemWidth, aShellItemHeight);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-TabParent::RecvDropLinks(nsTArray<nsString>&& aLinks)
+TabParent::RecvDropLinks(nsTArray<nsString>&& aLinks,
+                         const PrincipalInfo& aTriggeringPrincipalInfo)
 {
   nsCOMPtr<nsIBrowser> browser = do_QueryInterface(mFrameElement);
   if (browser) {
     UniquePtr<const char16_t*[]> links;
     links = MakeUnique<const char16_t*[]>(aLinks.Length());
     for (uint32_t i = 0; i < aLinks.Length(); i++) {
       links[i] = aLinks[i].get();
     }
-    browser->DropLinks(aLinks.Length(), links.get());
+    nsCOMPtr<nsIPrincipal> triggeringPrincipal =
+      PrincipalInfoToPrincipal(aTriggeringPrincipalInfo);
+    if (nsContentUtils::IsSystemPrincipal(triggeringPrincipal)) {
+      return IPC_FAIL(this, "Invalid triggeringPrincipal");
+    }
+    browser->DropLinks(aLinks.Length(), links.get(), triggeringPrincipal);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
 {
   nsCOMPtr<nsIDOMEvent> event = do_QueryInterface(aEvent.mEvent);
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -156,17 +156,18 @@ public:
                                                 const bool& aForDocumentNavigation) override;
 
   virtual mozilla::ipc::IPCResult RecvSizeShellTo(const uint32_t& aFlags,
                                                   const int32_t& aWidth,
                                                   const int32_t& aHeight,
                                                   const int32_t& aShellItemWidth,
                                                   const int32_t& aShellItemHeight) override;
 
-  virtual mozilla::ipc::IPCResult RecvDropLinks(nsTArray<nsString>&& aLinks) override;
+  virtual mozilla::ipc::IPCResult RecvDropLinks(nsTArray<nsString>&& aLinks,
+                                                const PrincipalInfo& aTriggeringPrincipalInfo) override;
 
   virtual mozilla::ipc::IPCResult RecvEvent(const RemoteDOMEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult
   RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent) override;
 
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1470,29 +1470,30 @@
                                     aPrintProgressListener);
           ]]>
         </body>
       </method>
 
       <method name="dropLinks">
         <parameter name="aLinksCount"/>
         <parameter name="aLinks"/>
+        <parameter name="aTriggeringPrincipal"/>
         <body><![CDATA[
           if (!this.droppedLinkHandler) {
             return false;
           }
           let links = [];
           for (let i = 0; i < aLinksCount; i += 3) {
             links.push({
               url: aLinks[i],
               name: aLinks[i + 1],
               type: aLinks[i + 2],
             });
           }
-          this.droppedLinkHandler(null, links);
+          this.droppedLinkHandler(null, links, aTriggeringPrincipal);
           return true;
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="keypress" keycode="VK_F7" group="system">
         <![CDATA[
@@ -1584,17 +1585,28 @@
         try {
           // Pass true to prevent the dropping of javascript:/data: URIs
           var links = linkHandler.dropLinks(event, true);
         } catch (ex) {
           return;
         }
 
         if (links.length) {
-          this.droppedLinkHandler(event, links);
+          // Bug 1368481: mozSourceNode is null if the drag event originated
+          // in an external application - needs better fallback!
+          let triggeringPrincipal;
+          let sourceNode = event.dataTransfer.mozSourceNode;
+          if (sourceNode) {
+            triggeringPrincipal = sourceNode.nodePrincipal;
+          } else {
+            var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
+              getService(Components.interfaces.nsIScriptSecurityManager);
+            triggeringPrincipal = secMan.getSystemPrincipal();
+          }
+          this.droppedLinkHandler(event, links, triggeringPrincipal);
         }
       ]]>
       </handler>
     </handlers>
 
   </binding>
 
 </bindings>