Bug 1425975 P13 Check for a different final document principal and reset the ClientSource when it happens. r=asuth
☠☠ backed out by 2e0db1b48499 ☠ ☠
authorBen Kelly <ben@wanderview.com>
Fri, 22 Dec 2017 21:09:20 -0500
changeset 449134 1e657fa97b71a183c521c65e8078d928580bc849
parent 449133 9e1544ec814d46dcf8a771a221f3ac1349663497
child 449135 e6f4a2d1df9a4a50b1b659f87dca99d88a5ef63a
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1425975
milestone59.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 1425975 P13 Check for a different final document principal and reset the ClientSource when it happens. r=asuth
dom/base/nsGlobalWindowInner.cpp
dom/clients/manager/ClientInfo.cpp
dom/clients/manager/ClientInfo.h
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1781,41 +1781,74 @@ nsGlobalWindowInner::EnsureClientSource(
   // In this case we want to inherit this placeholder Client here.
   if (!mClientSource) {
     mClientSource = Move(initialClientSource);
     if (mClientSource) {
       newClientSource = true;
     }
   }
 
+  // Verify the final ClientSource principal matches the final document
+  // principal.  The ClientChannelHelper handles things like network
+  // redirects, but there are other ways the document principal can change.
+  // For example, if something sets the nsIChannel.owner property, then
+  // the final channel principal can be anything.  Unfortunately there is
+  // no good way to detect this until after the channel completes loading.
+  //
+  // For now we handle this just by reseting the ClientSource.  This will
+  // result in a new ClientSource with the correct principal being created.
+  // To APIs like ServiceWorker and Clients API it will look like there was
+  // an initial content page created that was then immediately replaced.
+  // This is pretty close to what we are actually doing.
+  if (mClientSource) {
+    nsCOMPtr<nsIPrincipal> clientPrincipal(mClientSource->Info().GetPrincipal());
+    if (!clientPrincipal || !clientPrincipal->Equals(mDoc->NodePrincipal())) {
+      mClientSource.reset();
+    }
+  }
+
   // If we don't have a reserved client or an initial client, then create
   // one now.  This can happen in certain cases where we avoid preallocating
   // the client in the docshell.  This mainly occurs in situations where
   // the principal is not clearly inherited from the parent; e.g. sandboxed
   // iframes, window.open(), etc.
+  //
+  // We also do this late ClientSource creation if the final document ended
+  // up with a different principal.
+  //
   // TODO: We may not be marking initial about:blank documents created
   //       this way as controlled by a service worker properly.  The
   //       controller should be coming from the same place as the inheritted
   //       principal.  We do this in docshell, but as mentioned we aren't
   //       smart enough to handle all cases yet.  For example, a
   //       window.open() with new URL should inherit the controller from
   //       the opener, but we probably don't handle that yet.
   if (!mClientSource) {
     mClientSource = ClientManager::CreateSource(ClientType::Window,
                                                 EventTargetFor(TaskCategory::Other),
                                                 mDoc->NodePrincipal());
     MOZ_DIAGNOSTIC_ASSERT(mClientSource);
     newClientSource = true;
+
+    // Note, we don't apply the loadinfo controller below if we create
+    // the ClientSource here.
   }
 
   // The load may have started controlling the Client as well.  If
   // so, mark it as controlled immediately here.  The actor may
   // or may not have been notified by the parent side about being
   // controlled yet.
-  if (loadInfo) {
+  //
+  // Note: We should be careful not to control a client that was created late.
+  //       These clients were not seen by the ServiceWorkerManager when it
+  //       marked the LoadInfo controlled and it won't know about them.  Its
+  //       also possible we are creating the client late due to the final
+  //       principal changing and these clients should definitely not be
+  //       controlled by a service worker with a different principal.
+  else if (loadInfo) {
     const Maybe<ServiceWorkerDescriptor> controller = loadInfo->GetController();
     if (controller.isSome()) {
       mClientSource->SetController(controller.ref());
     }
 
     // We also have to handle the case where te initial about:blank is
     // controlled due to inheritting the service worker from its parent,
     // but the actual nsIChannel load is not covered by any service worker.
--- a/dom/clients/manager/ClientInfo.cpp
+++ b/dom/clients/manager/ClientInfo.cpp
@@ -2,21 +2,23 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "ClientInfo.h"
 
 #include "mozilla/dom/ClientIPCTypes.h"
+#include "mozilla/ipc/BackgroundUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::PrincipalInfo;
+using mozilla::ipc::PrincipalInfoToPrincipal;
 
 ClientInfo::ClientInfo(const nsID& aId,
                        ClientType aType,
                        const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
                        const TimeStamp& aCreationTime)
   : mData(MakeUnique<IPCClientInfo>(aId, aType, aPrincipalInfo, aCreationTime,
                                     EmptyCString(),
                                     mozilla::dom::FrameType::None))
@@ -133,10 +135,18 @@ ClientInfo::IsPrivateBrowsing() const
     default:
     {
       // clients should never be expanded principals
       MOZ_CRASH("unexpected principal type!");
     }
   }
 }
 
+nsCOMPtr<nsIPrincipal>
+ClientInfo::GetPrincipal() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIPrincipal> ref = PrincipalInfoToPrincipal(PrincipalInfo());
+  return Move(ref);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientInfo.h
+++ b/dom/clients/manager/ClientInfo.h
@@ -90,14 +90,19 @@ public:
 
   // Convert to the ipdl generated type.
   const IPCClientInfo&
   ToIPC() const;
 
   // Determine if the client is in private browsing mode.
   bool
   IsPrivateBrowsing() const;
+
+  // Get a main-thread nsIPrincipal for the client.  This may return nullptr
+  // if the PrincipalInfo() fails to deserialize for some reason.
+  nsCOMPtr<nsIPrincipal>
+  GetPrincipal() const;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientInfo_h