author | Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com> |
Tue, 22 Aug 2017 10:07:03 +0200 | |
changeset 376154 | 46d5697dc9e0b8ce53d5d02f7c5f228a5dab4914 |
parent 376153 | 7e6cd9dc49d54e193186c28fbe000da3630ca7e9 |
child 376155 | 2e4748827cda73771b02c8e9316e257505518a36 |
push id | 32376 |
push user | kwierso@gmail.com |
push date | Wed, 23 Aug 2017 00:07:40 +0000 |
treeherder | mozilla-central@64a45ee1731c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug, tooru |
bugs | 1370843 |
milestone | 57.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/docshell/base/nsDocShellTreeOwner.cpp +++ b/docshell/base/nsDocShellTreeOwner.cpp @@ -987,17 +987,16 @@ 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) { - // Bug 1370843 - Explicitly pass triggeringPrincipal nsresult rv = tabChild->RemoteDropLinks(linksCount, links); for (uint32_t i = 0; i < linksCount; i++) { NS_RELEASE(links[i]); } free(links); return rv; } }
--- a/dom/base/contentAreaDropListener.js +++ b/dom/base/contentAreaDropListener.js @@ -233,16 +233,25 @@ ContentAreaDropListener.prototype = } } if (aCount) aCount.value = links.length; return links; }, + queryLinks: function(aDataTransfer, aCount) + { + let links = this._getDropLinks(aDataTransfer); + if (aCount) { + aCount.value = links.length; + } + return links; + }, + _eventTargetIsDisabled: function(aEvent) { let ownerDoc = aEvent.originalTarget.ownerDocument; if (!ownerDoc || !ownerDoc.defaultView) return false; return ownerDoc.defaultView .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
--- a/dom/base/nsIDroppedLinkHandler.idl +++ b/dom/base/nsIDroppedLinkHandler.idl @@ -1,15 +1,16 @@ /* 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" #include "nsIPrincipal.idl" +interface nsIDOMDataTransfer; interface nsIDOMDragEvent; [scriptable, uuid(69E14F91-2E09-4CA6-A511-A715C99A2804)] interface nsIDroppedLinkItem : nsISupports { /** * Returns the URL of the link. */ @@ -75,13 +76,23 @@ interface nsIDroppedLinkHandler : nsISup * current document's security context (URI_INHERITS_SECURITY_CONTEXT). */ void dropLinks(in nsIDOMDragEvent aEvent, [optional] in boolean aDisallowInherit, [optional] out unsigned long aCount, [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks); /** + * Given a dataTransfer, allows caller to determine and verify links being + * dragged. Since drag/drop performs a roundtrip of parent, child, parent, + * it allows the parent to verify that the child did not modify links + * being dropped. + */ + void queryLinks(in nsIDOMDataTransfer aDataTransfer, + [optional] out unsigned long aCount, + [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks); + + /** * Given a drop event aEvent, determines the triggering principal for the * event and returns it. */ nsIPrincipal getTriggeringPrincipal(in nsIDOMDragEvent aEvent); };
--- 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 @@ -22,17 +23,18 @@ interface nsIBrowser : nsISupports * 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/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -11,16 +11,17 @@ #ifdef ACCESSIBILITY #include "mozilla/a11y/DocAccessibleParent.h" #include "nsAccessibilityService.h" #endif #include "mozilla/BrowserElementParent.h" #include "mozilla/dom/ContentBridgeParent.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/DataTransfer.h" +#include "mozilla/dom/DataTransferItemList.h" #include "mozilla/dom/Event.h" #include "mozilla/dom/indexedDB/ActorsParent.h" #include "mozilla/dom/IPCBlobUtils.h" #include "mozilla/dom/PaymentRequestParent.h" #include "mozilla/EventStateManager.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/gfx/GPUProcessManager.h" @@ -96,16 +97,17 @@ #include "ImageOps.h" #include "UnitTransforms.h" #include <algorithm> #include "mozilla/WebBrowserPersistDocumentParent.h" #include "nsIGroupedSHistory.h" #include "PartialSHistory.h" #include "ProcessPriorityManager.h" #include "nsString.h" +#include "NullPrincipal.h" #ifdef XP_WIN #include "mozilla/plugins/PluginWidgetParent.h" #endif #if defined(XP_WIN) && defined(ACCESSIBILITY) #include "mozilla/a11y/AccessibleWrap.h" #include "mozilla/a11y/nsWinUtils.h" @@ -533,22 +535,42 @@ TabParent::RecvSizeShellTo(const uint32_ return IPC_OK(); } mozilla::ipc::IPCResult TabParent::RecvDropLinks(nsTArray<nsString>&& aLinks) { nsCOMPtr<nsIBrowser> browser = do_QueryInterface(mFrameElement); if (browser) { + // Verify that links have not been modified by the child. If links have + // not been modified then it's safe to load those links using the + // SystemPrincipal. If they have been modified by web content, then + // we use a NullPrincipal which still allows to load web links. + bool loadUsingSystemPrincipal = true; + if (aLinks.Length() != mVerifyDropLinks.Length()) { + loadUsingSystemPrincipal = false; + } UniquePtr<const char16_t*[]> links; links = MakeUnique<const char16_t*[]>(aLinks.Length()); for (uint32_t i = 0; i < aLinks.Length(); i++) { + if (loadUsingSystemPrincipal) { + if (!aLinks[i].Equals(mVerifyDropLinks[i])) { + loadUsingSystemPrincipal = false; + } + } links[i] = aLinks[i].get(); } - browser->DropLinks(aLinks.Length(), links.get()); + mVerifyDropLinks.Clear(); + nsCOMPtr<nsIPrincipal> triggeringPrincipal; + if (loadUsingSystemPrincipal) { + triggeringPrincipal = nsContentUtils::GetSystemPrincipal(); + } else { + triggeringPrincipal = NullPrincipal::Create(); + } + 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); @@ -1169,24 +1191,101 @@ TabParent::GetLayoutDeviceToCSSScale() nsIDocument* doc = (content ? content->OwnerDoc() : nullptr); nsIPresShell* shell = (doc ? doc->GetShell() : nullptr); nsPresContext* ctx = (shell ? shell->GetPresContext() : nullptr); return LayoutDeviceToCSSScale(ctx ? (float)ctx->AppUnitsPerDevPixel() / nsPresContext::AppUnitsPerCSSPixel() : 0.0f); } +bool +TabParent::QueryDropLinksForVerification() +{ + // Before sending the dragEvent, we query the links being dragged and + // store them on the parent, to make sure the child can not modify links. + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); + if (!dragSession) { + NS_WARNING("No dragSession to query links for verification"); + return false; + } + + nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer; + dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer)); + if (!initialDataTransfer) { + NS_WARNING("No initialDataTransfer to query links for verification"); + return false; + } + + nsCOMPtr<nsIDroppedLinkHandler> dropHandler = + do_GetService("@mozilla.org/content/dropped-link-handler;1"); + if (!dropHandler) { + NS_WARNING("No dropHandler to query links for verification"); + return false; + } + + // No more than one drop event can happen simultaneously; reset the link + // verification array and store all links that are being dragged. + mVerifyDropLinks.Clear(); + + uint32_t linksCount = 0; + nsIDroppedLinkItem** droppedLinkedItems = nullptr; + dropHandler->QueryLinks(initialDataTransfer, + &linksCount, &droppedLinkedItems); + + // Since the entire event is cancelled if one of the links is invalid, + // we can store all links on the parent side without any prior + // validation checks. + nsresult rv = NS_OK; + for (uint32_t i = 0; i < linksCount; i++) { + nsString tmp; + rv = droppedLinkedItems[i]->GetUrl(tmp); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to query url for verification"); + break; + } + mVerifyDropLinks.AppendElement(tmp); + + rv = droppedLinkedItems[i]->GetName(tmp); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to query name for verification"); + break; + } + mVerifyDropLinks.AppendElement(tmp); + + rv = droppedLinkedItems[i]->GetType(tmp); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to query type for verification"); + break; + } + mVerifyDropLinks.AppendElement(tmp); + } + for (uint32_t i = 0; i < linksCount; i++) { + NS_IF_RELEASE(droppedLinkedItems[i]); + } + free(droppedLinkedItems); + if (NS_FAILED(rv)) { + mVerifyDropLinks.Clear(); + return false; + } + return true; +} + void TabParent::SendRealDragEvent(WidgetDragEvent& aEvent, uint32_t aDragAction, uint32_t aDropEffect) { if (mIsDestroyed || !mIsReadyToHandleInputEvents) { return; } aEvent.mRefPoint += GetChildProcessOffset(); + if (aEvent.mMessage == eDrop) { + if (!QueryDropLinksForVerification()) { + return; + } + } DebugOnly<bool> ret = PBrowserParent::SendRealDragEvent(aEvent, aDragAction, aDropEffect); NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed"); MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess()); } LayoutDevicePoint TabParent::AdjustTapToChildWidget(const LayoutDevicePoint& aPoint)
--- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -748,16 +748,22 @@ private: uint32_t mCustomCursorHotspotX, mCustomCursorHotspotY; // True if the cursor changes from the TabChild should change the widget // cursor. This happens whenever the cursor is in the tab's region. bool mTabSetsCursor; bool mHasContentOpener; + // When dropping links we perform a roundtrip from + // Parent (SendRealDragEvent) -> Child -> Parent (RecvDropLinks) + // and have to ensure that the child did not modify links to be loaded. + bool QueryDropLinksForVerification(); + nsTArray<nsString> mVerifyDropLinks; + #ifdef DEBUG int32_t mActiveSupressDisplayportCount; #endif ShowInfo GetShowInfo(); private: // This is used when APZ needs to find the TabParent associated with a layer
--- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -1579,29 +1579,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[