Bug 1027906 - Set delayed token level for GMP plugin processes to USER_RESTRICTED. Whitelist certain files and registry keys that are required for EME plugins to successfully load. r=bobowen. r=jesup, r=bent, a=lmandel
authorTim Abraldes <tabraldes@mozilla.com>
Fri, 29 Aug 2014 17:34:26 -0700
changeset 216717 0af2575571f3
parent 216716 645d232705b3
child 216718 a128f3f1ce1f
push id3889
push userryanvm@gmail.com
push date2014-09-15 13:57 +0000
treeherdermozilla-beta@0af2575571f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen, jesup, bent, lmandel
bugs1027906
milestone33.0
Bug 1027906 - Set delayed token level for GMP plugin processes to USER_RESTRICTED. Whitelist certain files and registry keys that are required for EME plugins to successfully load. r=bobowen. r=jesup, r=bent, a=lmandel
content/media/gmp/GMPProcessParent.cpp
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/GeckoChildProcessHost.h
security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
security/sandbox/win/src/sandboxbroker/sandboxBroker.h
--- a/content/media/gmp/GMPProcessParent.cpp
+++ b/content/media/gmp/GMPProcessParent.cpp
@@ -4,16 +4,22 @@
  * 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 "GMPProcessParent.h"
 
 #include "base/string_util.h"
 #include "base/process_util.h"
 
+#ifdef XP_WIN
+#include <codecvt>
+#endif
+
+#include <string>
+
 using std::vector;
 using std::string;
 
 using mozilla::gmp::GMPProcessParent;
 using mozilla::ipc::GeckoChildProcessHost;
 using base::ProcessArchitecture;
 
 template<>
@@ -36,16 +42,23 @@ GMPProcessParent::~GMPProcessParent()
 {
 }
 
 bool
 GMPProcessParent::Launch(int32_t aTimeoutMs)
 {
   vector<string> args;
   args.push_back(mGMPPath);
+
+#ifdef XP_WIN
+  std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
+  std::wstring wGMPPath = converter.from_bytes(mGMPPath.c_str());
+  mAllowedFilesRead.push_back(wGMPPath + L"\\*");
+#endif
+
   return SyncLaunch(args, aTimeoutMs, base::GetCurrentProcessArchitecture());
 }
 
 void
 GMPProcessParent::Delete()
 {
   MessageLoop* currentLoop = MessageLoop::current();
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -787,17 +787,26 @@ GeckoChildProcessHost::PerformAsyncLaunc
         shouldSandboxCurrentProcess = true;
       }
       break;
     case GeckoProcessType_Default:
     default:
       MOZ_CRASH("Bad process type in GeckoChildProcessHost");
       break;
   };
-#endif
+
+  if (shouldSandboxCurrentProcess) {
+    for (auto it = mAllowedFilesRead.begin();
+         it != mAllowedFilesRead.end();
+         ++it) {
+      mSandboxBroker.AllowReadFile(it->c_str());
+    }
+  }
+
+#endif // XP_WIN
 
   // Add the application directory path (-appdir path)
   AddAppDirToCommandLine(cmdLine);
 
   // XXX Command line params past this point are expected to be at
   // the end of the command line string, and in a specific order.
   // See XRE_InitChildProcess in nsEmbedFunction.
 
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -161,16 +161,17 @@ protected:
   static int32_t mChildCounter;
 
   void PrepareLaunch();
 
 #ifdef XP_WIN
   void InitWindowsGroupID();
   nsString mGroupId;
   SandboxBroker mSandboxBroker;
+  std::vector<std::wstring> mAllowedFilesRead;
 #endif // XP_WIN
 
 #if defined(OS_POSIX)
   base::file_handle_mapping_vector mFileMap;
 #endif
 
   base::WaitableEventWatcher::Delegate* mDelegate;
 
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -62,65 +62,191 @@ SandboxBroker::LaunchApp(const wchar_t *
 
 bool
 SandboxBroker::SetSecurityLevelForContentProcess()
 {
   if (!mPolicy) {
     return false;
   }
 
-  mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
-  mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
-                         sandbox::USER_RESTRICTED_SAME_ACCESS);
-  mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
-  mPolicy->SetAlternateDesktop(true);
-  return true;
+  auto result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
+  bool ret = (sandbox::SBOX_ALL_OK == result);
+  result =
+    mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                           sandbox::USER_RESTRICTED_SAME_ACCESS);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+  result =
+    mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+  result = mPolicy->SetAlternateDesktop(true);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+  return ret;
 }
 
 bool
 SandboxBroker::SetSecurityLevelForPluginProcess()
 {
   if (!mPolicy) {
     return false;
   }
 
-  mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
-  mPolicy->SetTokenLevel(sandbox::USER_UNPROTECTED,
-                         sandbox::USER_UNPROTECTED);
-  return true;
+  auto result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
+  bool ret = (sandbox::SBOX_ALL_OK == result);
+  result = mPolicy->SetTokenLevel(sandbox::USER_UNPROTECTED,
+                                  sandbox::USER_UNPROTECTED);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+  return ret;
 }
 
 bool
 SandboxBroker::SetSecurityLevelForIPDLUnitTestProcess()
 {
   if (!mPolicy) {
     return false;
   }
 
-  mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
-  mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
-                         sandbox::USER_RESTRICTED_SAME_ACCESS);
-  return true;
+  auto result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
+  bool ret = (sandbox::SBOX_ALL_OK == result);
+  result =
+    mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                           sandbox::USER_RESTRICTED_SAME_ACCESS);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+  return ret;
 }
 
 bool
 SandboxBroker::SetSecurityLevelForGMPlugin()
 {
   if (!mPolicy) {
     return false;
   }
 
-  mPolicy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0);
-  mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
-                         sandbox::USER_RESTRICTED_SAME_ACCESS);
-  mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
-  mPolicy->SetAlternateDesktop(true);
-  return true;
+  auto result = mPolicy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0);
+  bool ret = (sandbox::SBOX_ALL_OK == result);
+  result =
+    mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                           sandbox::USER_RESTRICTED);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result = mPolicy->SetAlternateDesktop(true);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  // We can't use an alternate desktop/window station AND initially
+  // set the process to low integrity. Upstream changes have been
+  // made to allow this and we should uncomment this section once
+  // we've rolled forward.
+  // result =
+  //   mPolicy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
+  // ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result =
+    mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  // Add the policy for the client side of a pipe. It is just a file
+  // in the \pipe\ namespace. We restrict it to pipes that start with
+  // "chrome." so the sandboxed process cannot connect to system services.
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                            sandbox::TargetPolicy::FILES_ALLOW_ANY,
+                            L"\\??\\pipe\\chrome.*");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+#ifdef DEBUG
+  // The plugin process can't create named events, but we'll
+  // make an exception for the events used in logging. Removing
+  // this will break EME in debug builds.
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_SYNC,
+                            sandbox::TargetPolicy::EVENTS_ALLOW_ANY,
+                            L"ChromeIPCLog.*");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+#endif
+
+  // The following rules were added because, during analysis of an EME
+  // plugin during development, these registry keys were accessed when
+  // loading the plugin. Commenting out these policy exceptions caused
+  // plugin loading to fail, so they are necessary for proper functioning
+  // of at least one EME plugin.
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_CURRENT_USER");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_CURRENT_USER\\Control Panel\\Desktop");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_CURRENT_USER\\Control Panel\\Desktop\\LanguageConfiguration");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SideBySide");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+
+  // The following rules were added because, during analysis of an EME
+  // plugin during development, these registry keys were accessed when
+  // loading the plugin. Commenting out these policy exceptions did not
+  // cause anything to break during initial testing, but might cause
+  // unforeseen issues down the road.
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\MUI\\Settings");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Control Panel\\Desktop");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_CURRENT_USER\\Control Panel\\Desktop\\PreferredUILanguages");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                            sandbox::TargetPolicy::REG_ALLOW_READONLY,
+                            L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SideBySide\\PreferExternalManifest");
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  return ret;
 }
 
+bool
+SandboxBroker::AllowReadFile(wchar_t const *file)
+{
+  auto result =
+    mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                     sandbox::TargetPolicy::FILES_ALLOW_READONLY,
+                     file);
+  return (sandbox::SBOX_ALL_OK == result);
+}
+
+bool
+SandboxBroker::AllowReadWriteFile(wchar_t const *file)
+{
+  auto result =
+    mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                     sandbox::TargetPolicy::FILES_ALLOW_ANY,
+                     file);
+  return (sandbox::SBOX_ALL_OK == result);
+}
+
+bool
+SandboxBroker::AllowDirectory(wchar_t const *dir)
+{
+  auto result =
+    mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                     sandbox::TargetPolicy::FILES_ALLOW_DIR_ANY,
+                     dir);
+  return (sandbox::SBOX_ALL_OK == result);
+}
 
 SandboxBroker::~SandboxBroker()
 {
   if (mPolicy) {
     mPolicy->Release();
     mPolicy = nullptr;
   }
 }
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
@@ -30,16 +30,21 @@ public:
   virtual ~SandboxBroker();
 
   // Security levels for different types of processes
   bool SetSecurityLevelForContentProcess();
   bool SetSecurityLevelForPluginProcess();
   bool SetSecurityLevelForIPDLUnitTestProcess();
   bool SetSecurityLevelForGMPlugin();
 
+  // File system permissions
+  bool AllowReadFile(wchar_t const *file);
+  bool AllowReadWriteFile(wchar_t const *file);
+  bool AllowDirectory(wchar_t const *dir);
+
 private:
   static sandbox::BrokerServices *sBrokerService;
   sandbox::TargetPolicy *mPolicy;
 };
 
 } // mozilla
 
 #endif