Index: sandbox/win/src/broker_services.cc |
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc |
index 54d87c44750e6d4e3b8b7474c90dfe807be036dc..2350342cf4534ddc3082a485eed6c48cd2f40f76 100644 |
--- a/sandbox/win/src/broker_services.cc |
+++ b/sandbox/win/src/broker_services.cc |
@@ -4,6 +4,8 @@ |
#include "sandbox/win/src/broker_services.h" |
+#include <AclAPI.h> |
+ |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/threading/platform_thread.h" |
@@ -80,6 +82,29 @@ void DeregisterPeerTracker(PeerTracker* peer) { |
} |
} |
+// Utility function to pack token values into a key for the cache map. |
+uint32_t GenerateTokenCacheKey(const sandbox::PolicyBase* policy) { |
+ const size_t kTokenShift = 3; |
+ uint32_t key; |
+ |
+ // Make sure our token values aren't too large to pack into the key. |
+ static_assert(sandbox::USER_LAST <= (1 << kTokenShift), |
+ "TokenLevel too large"); |
+ static_assert(sandbox::INTEGRITY_LEVEL_LAST <= (1 << kTokenShift), |
+ "IntegrityLevel too large"); |
+ static_assert(sizeof(key) < (kTokenShift * 3), |
+ "Token key type too small"); |
+ |
+ // The key is the enum values shifted to avoid overlap and OR'd together. |
+ key = policy->GetInitialTokenLevel(); |
+ key <<= kTokenShift; |
+ key |= policy->GetLockdownTokenLevel(); |
+ key <<= kTokenShift; |
+ key |= policy->GetIntegrityLevel(); |
+ |
+ return key; |
+} |
+ |
} // namespace |
namespace sandbox { |
@@ -153,6 +178,13 @@ BrokerServicesBase::~BrokerServicesBase() { |
// If job_port_ isn't NULL, assumes that the lock has been initialized. |
if (job_port_) |
::DeleteCriticalSection(&lock_); |
+ |
+ // Close any token in the cache. |
+ for (TokenCacheMap::iterator it = token_cache_.begin(); |
+ it != token_cache_.end(); ++it) { |
+ ::CloseHandle(it->second.first); |
+ ::CloseHandle(it->second.second); |
+ } |
} |
TargetPolicy* BrokerServicesBase::CreatePolicy() { |
@@ -299,10 +331,35 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, |
// with the soon to be created target process. |
HANDLE initial_token_temp; |
HANDLE lockdown_token_temp; |
- ResultCode result = policy_base->MakeTokens(&initial_token_temp, |
- &lockdown_token_temp); |
- if (SBOX_ALL_OK != result) |
- return result; |
+ ResultCode result = SBOX_ALL_OK; |
+ |
+ // Create the master tokens only once and save them in a cache. That way |
+ // can just duplicate them to avoid hammering LSASS on every sandboxed |
+ // process launch. |
+ uint32_t token_key = GenerateTokenCacheKey(policy_base); |
+ TokenCacheMap::iterator it = token_cache_.find(token_key); |
+ if (it != token_cache_.end()) { |
+ initial_token_temp = it->second.first; |
+ lockdown_token_temp = it->second.second; |
+ } else { |
+ result = policy_base->MakeTokens(&initial_token_temp, |
+ &lockdown_token_temp); |
+ if (SBOX_ALL_OK != result) |
+ return result; |
+ token_cache_[token_key] = |
+ std::pair<HANDLE, HANDLE>(initial_token_temp, lockdown_token_temp); |
+ } |
+ |
+ if (!::DuplicateToken(initial_token_temp, SecurityImpersonation, |
+ &initial_token_temp)) { |
+ return SBOX_ERROR_GENERIC; |
+ } |
+ |
+ if (!::DuplicateTokenEx(lockdown_token_temp, TOKEN_ALL_ACCESS, 0, |
+ SecurityIdentification, TokenPrimary, |
+ &lockdown_token_temp)) { |
+ return SBOX_ERROR_GENERIC; |
+ } |
base::win::ScopedHandle initial_token(initial_token_temp); |
base::win::ScopedHandle lockdown_token(lockdown_token_temp); |