Bug 969559 - Set delayed restricted integrity in child process to block off pipe and file access after LowerToken call. r=aklotz
authorBrian R. Bondy <netzen@gmail.com>
Fri, 14 Feb 2014 11:07:16 -0500
changeset 186009 20152316a6087d037828d35807339584f582d39e
parent 186008 65ab71e423474803dd2c57127be4cad9d6301691
child 186010 b18f669df651e557e49e1bff36dea42325eb9b12
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaklotz
bugs969559
milestone30.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 969559 - Set delayed restricted integrity in child process to block off pipe and file access after LowerToken call. r=aklotz
dom/ipc/ContentChild.cpp
ipc/app/MozillaRuntimeMain.cpp
security/sandbox/moz.build
security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
security/sandbox/win/src/sandboxbroker/sandboxBroker.h
security/sandbox/win/src/sandboxtarget/moz.build
security/sandbox/win/src/sandboxtarget/sandboxTarget.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -25,19 +25,26 @@
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
-#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_UNIX) && !defined(XP_MACOSX)
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#if defined(XP_WIN)
+#define TARGET_SANDBOX_EXPORTS
+#include "mozilla/sandboxTarget.h"
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
 #include "mozilla/Sandbox.h"
 #endif
+#endif
+
 #include "mozilla/unused.h"
 
 #include "nsIConsoleListener.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
@@ -588,23 +595,28 @@ ContentChild::AllocPImageBridgeChild(moz
 bool
 ContentChild::RecvSetProcessPrivileges(const ChildPrivileges& aPrivs)
 {
   ChildPrivileges privs = (aPrivs == PRIVILEGES_DEFAULT) ?
                           GeckoChildProcessHost::DefaultChildPrivileges() :
                           aPrivs;
   // If this fails, we die.
   SetCurrentProcessPrivileges(privs);
-#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_UNIX) && !defined(XP_MACOSX)
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#if defined(XP_WIN)
+  mozilla::SandboxTarget::Instance()->StartSandbox();
+#else if defined(XP_UNIX) && !defined(XP_MACOSX)
   // SetCurrentProcessSandbox should be moved close to process initialization
   // time if/when possible. SetCurrentProcessPrivileges should probably be
   // moved as well. Right now this is set ONLY if we receive the
   // RecvSetProcessPrivileges message. See bug 880808.
   SetCurrentProcessSandbox();
 #endif
+#endif
   return true;
 }
 
 bool
 ContentChild::RecvSpeakerManagerNotify()
 {
 #ifdef MOZ_WIDGET_GONK
   nsRefPtr<SpeakerManagerService> service =
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/app/MozillaRuntimeMain.cpp
@@ -20,16 +20,17 @@
 #include "nsWindowsWMain.cpp"
 #include "nsSetDllDirectory.h"
 #endif
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
 #include "sandbox/chromium/base/basictypes.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
+#include "mozilla/sandboxTarget.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 # include <sys/time.h>
 # include <sys/resource.h> 
 
 # include <binder/ProcessState.h>
 
@@ -62,24 +63,37 @@ InitializeBinder(void *aDummy) {
     int err = setpriority(PRIO_PROCESS, 0, 0);
     MOZ_ASSERT(!err);
     LOGE_IF(err, "setpriority failed. Current process needs root permission.");
     android::ProcessState::self()->startThreadPool();
     setpriority(PRIO_PROCESS, 0, curPrio);
 }
 #endif
 
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+static bool gIsSandboxEnabled = false;
+void StartSandboxCallback()
+{
+    if (gIsSandboxEnabled) {
+        sandbox::TargetServices* target_service =
+            sandbox::SandboxFactory::GetTargetServices();
+        target_service->LowerToken();
+    }
+}
+#endif
+
 int
 main(int argc, char* argv[])
 {
     bool isNuwa = false;
-    bool isSandboxEnabled = false;
     for (int i = 1; i < argc; i++) {
         isNuwa |= strcmp(argv[i], "-nuwa") == 0;
-        isSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+        gIsSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
+#endif
     }
 
 #ifdef MOZ_NUWA_PROCESS
     if (isNuwa) {
         PrepareNuwaProcess();
     }
 #endif
 
@@ -95,47 +109,45 @@ main(int argc, char* argv[])
     } else {
         NuwaAddFinalConstructor(&InitializeBinder, nullptr);
     }
 #else
     InitializeBinder(nullptr);
 #endif
 #endif
 
-#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
-    if (isSandboxEnabled) {
-        sandbox::TargetServices* target_service =
-            sandbox::SandboxFactory::GetTargetServices();
-        if (!target_service) {
-            return 1;
-        }
-
-        sandbox::ResultCode result = target_service->Init();
-        if (result != sandbox::SBOX_ALL_OK) {
-            return 2;
-        }
-
-        // Initialization is finished, switch to the lowered token
-        target_service->LowerToken();
-    }
-#endif
-
     // Check for the absolute minimum number of args we need to move
     // forward here. We expect the last arg to be the child process type.
     if (argc < 1)
       return 3;
     GeckoProcessType proctype = XRE_StringToChildProcessType(argv[--argc]);
 
 #ifdef XP_WIN
     // For plugins, this is done in PluginProcessChild::Init, as we need to
     // avoid it for unsupported plugins.  See PluginProcessChild::Init for
     // the details.
     if (proctype != GeckoProcessType_Plugin) {
         mozilla::SanitizeEnvironmentVariables();
         SetDllDirectory(L"");
     }
+
+#ifdef MOZ_CONTENT_SANDBOX
+    if (gIsSandboxEnabled) {
+        sandbox::TargetServices* target_service =
+            sandbox::SandboxFactory::GetTargetServices();
+        if (!target_service) {
+            return 1;
+        }
+
+        sandbox::ResultCode result = target_service->Init();
+        if (result != sandbox::SBOX_ALL_OK) {
+           return 2;
+        }
+        mozilla::SandboxTarget::Instance()->SetStartSandboxCallback(StartSandboxCallback);
+    }
+#endif
 #endif
 
     nsresult rv = XRE_InitChildProcess(argc, argv, proctype);
     NS_ENSURE_SUCCESS(rv, 1);
 
     return 0;
 }
--- a/security/sandbox/moz.build
+++ b/security/sandbox/moz.build
@@ -8,17 +8,20 @@ if CONFIG['OS_ARCH'] == 'Linux':
 
     DIRS += ['linux']
 
 elif CONFIG['OS_ARCH'] == 'WINNT':
     LIBRARY_NAME = 'sandbox_s'
     EXPORT_LIBRARY = True
     FORCE_STATIC_LIB = True
 
-    DIRS += ['win/src/sandboxbroker']
+    DIRS += [
+        'win/src/sandboxbroker',
+        'win/src/sandboxtarget',
+    ]
 
     SOURCES += [
         'chromium/base/at_exit.cc',
         'chromium/base/base_switches.cc',
         'chromium/base/callback_internal.cc',
         'chromium/base/cpu.cc',
         'chromium/base/debug/alias.cc',
         'chromium/base/debug/profiler.cc',
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -18,54 +18,65 @@ SandboxBroker::SandboxBroker()
   if (!sBrokerService) {
     sBrokerService = sandbox::SandboxFactory::GetBrokerServices();
     if (sBrokerService) {
       sandbox::ResultCode result = sBrokerService->Init();
       if (result != sandbox::SBOX_ALL_OK) {
         sBrokerService = nullptr;
       }
     }
+
+    // We'll start to increase the restrictions over time.
+    mPolicy = sBrokerService->CreatePolicy();
   }
 }
 
 bool
+SandboxBroker::AllowPipe(const wchar_t *aPath)
+{
+  return mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
+                          sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, aPath);
+}
+
+bool
 SandboxBroker::LaunchApp(const wchar_t *aPath,
                            const wchar_t *aArguments,
                            void **aProcessHandle)
 {
   // If the broker service isn't already initialized, do it now
-  if (!sBrokerService) {
+  if (!sBrokerService || !mPolicy) {
     return false;
   }
 
   // Setup the sandbox policy, this is initially:
   // Medium integrity, unrestricted, in the same window station, within the
   // same desktop, and has no job object.
   // We'll start to increase the restrictions over time.
-  sandbox::TargetPolicy *policy = sBrokerService->CreatePolicy();
-  policy->SetJobLevel(sandbox::JOB_NONE, 0);
-  policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
-                        sandbox::USER_RESTRICTED_SAME_ACCESS);
-  policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_MEDIUM);
+  mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
+  mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                         sandbox::USER_RESTRICTED_SAME_ACCESS);
+  mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
 
   // Ceate the sandboxed process
   PROCESS_INFORMATION targetInfo;
   sandbox::ResultCode result;
-  result = sBrokerService->SpawnTarget(aPath, aArguments, policy, &targetInfo);
+  result = sBrokerService->SpawnTarget(aPath, aArguments, mPolicy, &targetInfo);
 
   // The sandboxed process is started in a suspended state, resumeit now that
   // we'eve set things up.
   ResumeThread(targetInfo.hThread);
   CloseHandle(targetInfo.hThread);
 
   // Return the process handle to the caller
   *aProcessHandle = targetInfo.hProcess;
 
-  policy->Release();
-
   return true;
 }
 
 SandboxBroker::~SandboxBroker()
 {
+  if (mPolicy) {
+    mPolicy->Release();
+    mPolicy = nullptr;
+  }
 }
 
 }
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
@@ -10,27 +10,30 @@
 #ifdef SANDBOX_EXPORTS
 #define SANDBOX_EXPORT __declspec(dllexport)
 #else
 #define SANDBOX_EXPORT __declspec(dllimport)
 #endif
 
 namespace sandbox {
   class BrokerServices;
+  class TargetPolicy;
 }
 
 namespace mozilla {
 
 class SANDBOX_EXPORT SandboxBroker
 {
 public:
   SandboxBroker();
+  bool AllowPipe(const wchar_t *aPath);
   bool LaunchApp(const wchar_t *aPath, const wchar_t *aArguments,
                  void **aProcessHandle);
   virtual ~SandboxBroker();
 
 private:
   static sandbox::BrokerServices *sBrokerService;
+  sandbox::TargetPolicy *mPolicy;
 };
 
 } // mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/sandboxtarget/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla += [
+    'sandboxTarget.h',
+]
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/sandboxtarget/sandboxTarget.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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/. */
+
+#ifndef __SECURITY_SANDBOX_SANDBOXTARGET_H__
+#define __SECURITY_SANDBOX_SANDBOXTARGET_H__
+
+#ifdef TARGET_SANDBOX_EXPORTS
+#define TARGET_SANDBOX_EXPORT __declspec(dllexport)
+#else
+#define TARGET_SANDBOX_EXPORT __declspec(dllimport)
+#endif
+namespace mozilla {
+
+
+class TARGET_SANDBOX_EXPORT SandboxTarget
+{
+public:
+  typedef void (*StartSandboxPtr)();
+
+  /**
+   * Obtains a pointer to the singleton instance
+   */
+  static SandboxTarget* Instance()
+  {
+    static SandboxTarget sb;
+    return &sb;
+  }
+
+  /**
+   * Called by the application that will lower the sandbox token
+   *
+   * @param aStartSandboxCallback A callback function which will lower privs
+   */
+  void SetStartSandboxCallback(StartSandboxPtr aStartSandboxCallback)
+  {
+    mStartSandboxCallback = aStartSandboxCallback;
+  }
+
+  /**
+   * Called by the library that wants to start the sandbox, which in turn
+   * calls into the previously set StartSandboxCallback.
+   */
+  void StartSandbox()
+  {
+    if (mStartSandboxCallback) {
+      mStartSandboxCallback();
+    }
+  }
+
+protected:
+  SandboxTarget() :
+    mStartSandboxCallback(nullptr)
+  {
+  }
+
+  StartSandboxPtr mStartSandboxCallback;
+};
+
+
+} // mozilla
+
+#endif