Bug 1535704: Part 4 - When sandboxed, mscom::ProcessRuntime must make the MTA thread impersonate using the main thread's token; r=bobowen
authorAaron Klotz <aklotz@mozilla.com>
Tue, 23 Apr 2019 17:54:14 +0000
changeset 471873 496213852ce6d42886a992f729fb125be3fc98f2
parent 471872 d303f2ce387ee0c666aa9173ef3ba841493149c9
child 471874 626ad97710e34569af2ab88d9acb9e06833852e7
push id35941
push userarchaeopteryx@coole-files.de
push dateTue, 30 Apr 2019 11:32:04 +0000
treeherdermozilla-central@ee0dd3b092d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen
bugs1535704
milestone68.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 1535704: Part 4 - When sandboxed, mscom::ProcessRuntime must make the MTA thread impersonate using the main thread's token; r=bobowen Differential Revision: https://phabricator.services.mozilla.com/D27834
ipc/mscom/ProcessRuntime.cpp
ipc/mscom/ProcessRuntime.h
--- a/ipc/mscom/ProcessRuntime.cpp
+++ b/ipc/mscom/ProcessRuntime.cpp
@@ -14,20 +14,21 @@
 #include "mozilla/mscom/ProcessRuntimeShared.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Vector.h"
 #include "mozilla/WindowsVersion.h"
 #include "nsWindowsHelpers.h"
 
-#if defined(MOZILLA_INTERNAL_API)
+#if defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
 #  include "mozilla/mscom/EnsureMTA.h"
+#  include "mozilla/sandboxTarget.h"
 #  include "nsThreadManager.h"
-#endif  // defined(MOZILLA_INTERNAL_API)
+#endif  // defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
 
 #include <accctrl.h>
 #include <aclapi.h>
 #include <objbase.h>
 #include <objidl.h>
 
 // This API from oleaut32.dll is not declared in Windows SDK headers
 extern "C" void __cdecl SetOaNoCache(void);
@@ -38,34 +39,81 @@ namespace mscom {
 ProcessRuntime::ProcessRuntime(GeckoProcessType aProcessType)
     : mInitResult(CO_E_NOTINITIALIZED),
       mIsParentProcess(aProcessType == GeckoProcessType_Default)
 #if defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
       ,
       mActCtxRgn(a11y::Compatibility::GetActCtxResourceId())
 #endif  // defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
 {
-#if defined(MOZILLA_INTERNAL_API)
+#if defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
   // If our process is running under Win32k lockdown, we cannot initialize
   // COM with single-threaded apartments. This is because STAs create a hidden
   // window, which implicitly requires user32 and Win32k, which are blocked.
   // Instead we start a multi-threaded apartment and conduct our process-wide
   // COM initialization on that MTA background thread.
   if (!mIsParentProcess && IsWin32kLockedDown()) {
     // It is possible that we're running so early that we might need to start
     // the thread manager ourselves.
     nsresult rv = nsThreadManager::get().Init();
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
     if (NS_FAILED(rv)) {
       return;
     }
 
-    EnsureMTA([this]() -> void { InitInsideApartment(); });
+    // Use the current thread's impersonation token to initialize COM, as
+    // it might fail otherwise (depending on sandbox policy).
+    HANDLE rawCurThreadImpToken;
+    if (!::OpenThreadToken(::GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY,
+                           FALSE, &rawCurThreadImpToken)) {
+      mInitResult = HRESULT_FROM_WIN32(::GetLastError());
+      return;
+    }
+    nsAutoHandle curThreadImpToken(rawCurThreadImpToken);
+
+#if defined(DEBUG)
+    // Ensure that our current token is still an impersonation token (ie, we
+    // have not yet called RevertToSelf() on this thread).
+    DWORD len;
+    TOKEN_TYPE tokenType;
+    MOZ_ASSERT(::GetTokenInformation(rawCurThreadImpToken, TokenType,
+                                     &tokenType, sizeof(tokenType), &len) &&
+               len == sizeof(tokenType) && tokenType == TokenImpersonation);
+#endif  // defined(DEBUG)
+
+    // Create an impersonation token based on the current thread's token
+    HANDLE rawMtaThreadImpToken = nullptr;
+    if (!::DuplicateToken(rawCurThreadImpToken, SecurityImpersonation,
+                          &rawMtaThreadImpToken)) {
+      mInitResult = HRESULT_FROM_WIN32(::GetLastError());
+      return;
+    }
+    nsAutoHandle mtaThreadImpToken(rawMtaThreadImpToken);
+
+    SandboxTarget::Instance()->RegisterSandboxStartCallback([]() -> void {
+      EnsureMTA([]() -> void {
+        // This is a security risk if it fails, so we release assert
+        MOZ_RELEASE_ASSERT(::RevertToSelf(),
+                           "mscom::ProcessRuntime RevertToSelf failed");
+      }, EnsureMTA::Option::ForceDispatch);
+    });
+
+    // Impersonate and initialize.
+    EnsureMTA([this, rawMtaThreadImpToken]() -> void {
+      if (!::SetThreadToken(nullptr, rawMtaThreadImpToken)) {
+        mInitResult = HRESULT_FROM_WIN32(::GetLastError());
+        return;
+      }
+
+      InitInsideApartment();
+    }, EnsureMTA::Option::ForceDispatch);
+
     return;
   }
+
 #endif  // defined(MOZILLA_INTERNAL_API)
 
   // Otherwise we initialize a single-threaded apartment on the current thread.
   mAptRegion.Init(COINIT_APARTMENTTHREADED);
 
   // We must be the outermost COM initialization on this thread. The COM runtime
   // cannot be configured once we start manipulating objects
   MOZ_ASSERT(mAptRegion.IsValidOutermost());
--- a/ipc/mscom/ProcessRuntime.h
+++ b/ipc/mscom/ProcessRuntime.h
@@ -41,17 +41,17 @@ class MOZ_NON_TEMPORARY_CLASS ProcessRun
    */
   static DWORD GetClientThreadId();
 
  private:
   void InitInsideApartment();
   HRESULT InitializeSecurity();
 
   HRESULT mInitResult;
-  bool mIsParentProcess;
+  const bool mIsParentProcess;
 #if defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
   ActivationContextRegion mActCtxRgn;
 #endif  // defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
   ApartmentRegion mAptRegion;
 };
 
 }  // namespace mscom
 }  // namespace mozilla