Bug 1271601 - If a child process fails to duplicate a TransportDescriptor pipe handle then send it anyway and get the target to duplicate. r=gabor, a=ritu
authorBob Owen <bobowencode@gmail.com>
Sat, 21 May 2016 16:16:33 +0100
changeset 333078 053dfc050a5b8ca0e9cf72337a572d4be5f6c94e
parent 333077 c36af26156fa8f0dd20a553f8b9afd8049ec7d72
child 333079 65badb6bff1ea4b79837500e1a8b5969ea7fe489
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgabor, ritu
bugs1271601
milestone48.0a2
Bug 1271601 - If a child process fails to duplicate a TransportDescriptor pipe handle then send it anyway and get the target to duplicate. r=gabor, a=ritu MozReview-Commit-ID: 5CKrQdDxGrg
ipc/glue/Transport_win.cpp
ipc/glue/Transport_win.h
--- a/ipc/glue/Transport_win.cpp
+++ b/ipc/glue/Transport_win.cpp
@@ -60,20 +60,18 @@ TransferHandleToProcess(HANDLE source, b
   if (source == INVALID_HANDLE_VALUE) {
     return source;
   }
   HANDLE handleDup;
   DWORD access = 0;
   DWORD options = DUPLICATE_SAME_ACCESS;
   bool ok = DuplicateHandle(source, pid, &handleDup, access, options);
   if (!ok) {
-    AnnotateSystemError();
-    AnnotateProcessInformation(pid);
+    return nullptr;
   }
-  MOZ_RELEASE_ASSERT(ok);
 
   // Now close our own copy of the handle (we're supposed to be transferring,
   // not copying).
   CloseHandle(source);
 
   return handleDup;
 }
 
--- a/ipc/glue/Transport_win.h
+++ b/ipc/glue/Transport_win.h
@@ -7,17 +7,17 @@
 
 #ifndef mozilla_ipc_Transport_win_h
 #define mozilla_ipc_Transport_win_h 1
 
 #include <string>
 
 #include "base/process.h"
 #include "ipc/IPCMessageUtils.h"
-
+#include "nsWindowsHelpers.h"
 
 namespace mozilla {
 namespace ipc {
 
 struct TransportDescriptor
 {
   std::wstring mPipeName;
   HANDLE mServerPipeHandle;
@@ -36,32 +36,77 @@ namespace IPC {
 template<>
 struct ParamTraits<mozilla::ipc::TransportDescriptor>
 {
   typedef mozilla::ipc::TransportDescriptor paramType;
   static void Write(Message* aMsg, const paramType& aParam)
   {
     HANDLE pipe = mozilla::ipc::TransferHandleToProcess(aParam.mServerPipeHandle,
                                                         aParam.mDestinationProcessId);
+    DWORD duplicateFromProcessId = 0;
+    if (!pipe) {
+      if (XRE_IsParentProcess()) {
+        // If we are the parent and failed to transfer then there is no hope,
+        // just close the handle.
+        ::CloseHandle(aParam.mServerPipeHandle);
+      } else {
+        // We are probably sending to parent so it should be able to duplicate.
+        pipe = aParam.mServerPipeHandle;
+        duplicateFromProcessId = ::GetCurrentProcessId();
+      }
+    }
 
     WriteParam(aMsg, aParam.mPipeName);
     WriteParam(aMsg, pipe);
+    WriteParam(aMsg, duplicateFromProcessId);
     WriteParam(aMsg, aParam.mDestinationProcessId);
   }
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
+    DWORD duplicateFromProcessId;
     bool r = (ReadParam(aMsg, aIter, &aResult->mPipeName) &&
               ReadParam(aMsg, aIter, &aResult->mServerPipeHandle) &&
+              ReadParam(aMsg, aIter, &duplicateFromProcessId) &&
               ReadParam(aMsg, aIter, &aResult->mDestinationProcessId));
     if (!r) {
       return r;
     }
-    if (aResult->mServerPipeHandle != INVALID_HANDLE_VALUE) {
-      MOZ_RELEASE_ASSERT(aResult->mDestinationProcessId == base::GetCurrentProcId());
+
+    MOZ_RELEASE_ASSERT(aResult->mServerPipeHandle,
+                       "Main process failed to duplicate pipe handle to child.");
+
+    // If this is a not the "server" side descriptor, we have finished.
+    if (aResult->mServerPipeHandle == INVALID_HANDLE_VALUE) {
+      return true;
+    }
+
+    MOZ_RELEASE_ASSERT(aResult->mDestinationProcessId == base::GetCurrentProcId());
+
+    // If the pipe has already been duplicated to us, we have finished.
+    if (!duplicateFromProcessId) {
+      return true;
     }
-    return r;
+
+    // Otherwise duplicate the handle to us.
+    nsAutoHandle sourceProcess(::OpenProcess(PROCESS_DUP_HANDLE, FALSE,
+                                             duplicateFromProcessId));
+    if (!sourceProcess) {
+      return false;
+    }
+
+    HANDLE ourHandle;
+    BOOL duped = ::DuplicateHandle(sourceProcess, aResult->mServerPipeHandle,
+                                   ::GetCurrentProcess(), &ourHandle, 0, FALSE,
+                                   DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+    if (!duped) {
+      aResult->mServerPipeHandle = INVALID_HANDLE_VALUE;
+      return false;
+    }
+
+    aResult->mServerPipeHandle = ourHandle;
+    return true;
   }
 };
 
 } // namespace IPC
 
 
 #endif  // mozilla_ipc_Transport_win_h