Commit 502857ff authored by jschuh@chromium.org's avatar jschuh@chromium.org

This will make process launch faster and may prevent the LSASS hangs we've seen on XP/Vista.

BUG=347825

Review URL: https://codereview.chromium.org/309593002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275334 0039d316-1c4b-4281-b951-d872f2087c98
parent 044c6f54
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "sandbox/win/src/broker_services.h" #include "sandbox/win/src/broker_services.h"
#include <AclAPI.h>
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
...@@ -80,6 +82,29 @@ void DeregisterPeerTracker(PeerTracker* peer) { ...@@ -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
namespace sandbox { namespace sandbox {
...@@ -153,6 +178,13 @@ BrokerServicesBase::~BrokerServicesBase() { ...@@ -153,6 +178,13 @@ BrokerServicesBase::~BrokerServicesBase() {
// If job_port_ isn't NULL, assumes that the lock has been initialized. // If job_port_ isn't NULL, assumes that the lock has been initialized.
if (job_port_) if (job_port_)
::DeleteCriticalSection(&lock_); ::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() { TargetPolicy* BrokerServicesBase::CreatePolicy() {
...@@ -299,10 +331,35 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, ...@@ -299,10 +331,35 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
// with the soon to be created target process. // with the soon to be created target process.
HANDLE initial_token_temp; HANDLE initial_token_temp;
HANDLE lockdown_token_temp; HANDLE lockdown_token_temp;
ResultCode result = policy_base->MakeTokens(&initial_token_temp, ResultCode result = SBOX_ALL_OK;
&lockdown_token_temp);
if (SBOX_ALL_OK != result) // Create the master tokens only once and save them in a cache. That way
return result; // 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 initial_token(initial_token_temp);
base::win::ScopedHandle lockdown_token(lockdown_token_temp); base::win::ScopedHandle lockdown_token(lockdown_token_temp);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <list> #include <list>
#include <map> #include <map>
#include <set> #include <set>
#include <utility>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
...@@ -105,6 +106,9 @@ class BrokerServicesBase FINAL : public BrokerServices, ...@@ -105,6 +106,9 @@ class BrokerServicesBase FINAL : public BrokerServices,
// job. Consult |jobless_process_handles_| for handles of pocess without job. // job. Consult |jobless_process_handles_| for handles of pocess without job.
std::set<DWORD> child_process_ids_; std::set<DWORD> child_process_ids_;
typedef std::map<uint32_t, std::pair<HANDLE, HANDLE>> TokenCacheMap;
TokenCacheMap token_cache_;
DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase); DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase);
}; };
......
...@@ -87,6 +87,12 @@ class TargetPolicy { ...@@ -87,6 +87,12 @@ class TargetPolicy {
// as possible. // as possible.
virtual ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) = 0; virtual ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) = 0;
// Returns the initial token level.
virtual TokenLevel GetInitialTokenLevel() const = 0;
// Returns the lockdown token level.
virtual TokenLevel GetLockdownTokenLevel() const = 0;
// Sets the security level of the Job Object to which the target process will // Sets the security level of the Job Object to which the target process will
// belong. This setting is permanent and cannot be changed once the target // belong. This setting is permanent and cannot be changed once the target
// process is spawned. The job controls the global security settings which // process is spawned. The job controls the global security settings which
...@@ -144,6 +150,9 @@ class TargetPolicy { ...@@ -144,6 +150,9 @@ class TargetPolicy {
// to start. // to start.
virtual ResultCode SetIntegrityLevel(IntegrityLevel level) = 0; virtual ResultCode SetIntegrityLevel(IntegrityLevel level) = 0;
// Returns the initial integrity level used.
virtual IntegrityLevel GetIntegrityLevel() const = 0;
// Sets the integrity level of the process in the sandbox. The integrity level // Sets the integrity level of the process in the sandbox. The integrity level
// will not take effect before you call LowerToken. User Interface Privilege // will not take effect before you call LowerToken. User Interface Privilege
// Isolation is not affected by this setting and will remain off for the // Isolation is not affected by this setting and will remain off for the
...@@ -179,7 +188,7 @@ class TargetPolicy { ...@@ -179,7 +188,7 @@ class TargetPolicy {
virtual ResultCode SetDelayedProcessMitigations(MitigationFlags flags) = 0; virtual ResultCode SetDelayedProcessMitigations(MitigationFlags flags) = 0;
// Returns the currently set delayed mitigation flags. // Returns the currently set delayed mitigation flags.
virtual MitigationFlags GetDelayedProcessMitigations() = 0; virtual MitigationFlags GetDelayedProcessMitigations() const = 0;
// Sets the interceptions to operate in strict mode. By default, interceptions // Sets the interceptions to operate in strict mode. By default, interceptions
// are performed in "relaxed" mode, where if something inside NTDLL.DLL is // are performed in "relaxed" mode, where if something inside NTDLL.DLL is
......
...@@ -161,6 +161,14 @@ ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) { ...@@ -161,6 +161,14 @@ ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
return SBOX_ALL_OK; return SBOX_ALL_OK;
} }
TokenLevel PolicyBase::GetInitialTokenLevel() const {
return initial_level_;
}
TokenLevel PolicyBase::GetLockdownTokenLevel() const{
return lockdown_level_;
}
ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) { ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
job_level_ = job_level; job_level_ = job_level;
ui_exceptions_ = ui_exceptions; ui_exceptions_ = ui_exceptions;
...@@ -265,6 +273,10 @@ ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) { ...@@ -265,6 +273,10 @@ ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
return SBOX_ALL_OK; return SBOX_ALL_OK;
} }
IntegrityLevel PolicyBase::GetIntegrityLevel() const {
return integrity_level_;
}
ResultCode PolicyBase::SetDelayedIntegrityLevel( ResultCode PolicyBase::SetDelayedIntegrityLevel(
IntegrityLevel integrity_level) { IntegrityLevel integrity_level) {
delayed_integrity_level_ = integrity_level; delayed_integrity_level_ = integrity_level;
...@@ -316,7 +328,7 @@ ResultCode PolicyBase::SetDelayedProcessMitigations( ...@@ -316,7 +328,7 @@ ResultCode PolicyBase::SetDelayedProcessMitigations(
return SBOX_ALL_OK; return SBOX_ALL_OK;
} }
MitigationFlags PolicyBase::GetDelayedProcessMitigations() { MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
return delayed_mitigations_; return delayed_mitigations_;
} }
......
...@@ -41,6 +41,8 @@ class PolicyBase : public Dispatcher, public TargetPolicy { ...@@ -41,6 +41,8 @@ class PolicyBase : public Dispatcher, public TargetPolicy {
virtual void Release() OVERRIDE; virtual void Release() OVERRIDE;
virtual ResultCode SetTokenLevel(TokenLevel initial, virtual ResultCode SetTokenLevel(TokenLevel initial,
TokenLevel lockdown) OVERRIDE; TokenLevel lockdown) OVERRIDE;
virtual TokenLevel GetInitialTokenLevel() const OVERRIDE;
virtual TokenLevel GetLockdownTokenLevel() const OVERRIDE;
virtual ResultCode SetJobLevel(JobLevel job_level, virtual ResultCode SetJobLevel(JobLevel job_level,
uint32 ui_exceptions) OVERRIDE; uint32 ui_exceptions) OVERRIDE;
virtual ResultCode SetAlternateDesktop(bool alternate_winstation) OVERRIDE; virtual ResultCode SetAlternateDesktop(bool alternate_winstation) OVERRIDE;
...@@ -48,6 +50,7 @@ class PolicyBase : public Dispatcher, public TargetPolicy { ...@@ -48,6 +50,7 @@ class PolicyBase : public Dispatcher, public TargetPolicy {
virtual ResultCode CreateAlternateDesktop(bool alternate_winstation) OVERRIDE; virtual ResultCode CreateAlternateDesktop(bool alternate_winstation) OVERRIDE;
virtual void DestroyAlternateDesktop() OVERRIDE; virtual void DestroyAlternateDesktop() OVERRIDE;
virtual ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) OVERRIDE; virtual ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) OVERRIDE;
virtual IntegrityLevel GetIntegrityLevel() const OVERRIDE;
virtual ResultCode SetDelayedIntegrityLevel( virtual ResultCode SetDelayedIntegrityLevel(
IntegrityLevel integrity_level) OVERRIDE; IntegrityLevel integrity_level) OVERRIDE;
virtual ResultCode SetAppContainer(const wchar_t* sid) OVERRIDE; virtual ResultCode SetAppContainer(const wchar_t* sid) OVERRIDE;
...@@ -56,7 +59,7 @@ class PolicyBase : public Dispatcher, public TargetPolicy { ...@@ -56,7 +59,7 @@ class PolicyBase : public Dispatcher, public TargetPolicy {
virtual MitigationFlags GetProcessMitigations() OVERRIDE; virtual MitigationFlags GetProcessMitigations() OVERRIDE;
virtual ResultCode SetDelayedProcessMitigations( virtual ResultCode SetDelayedProcessMitigations(
MitigationFlags flags) OVERRIDE; MitigationFlags flags) OVERRIDE;
virtual MitigationFlags GetDelayedProcessMitigations() OVERRIDE; virtual MitigationFlags GetDelayedProcessMitigations() const OVERRIDE;
virtual void SetStrictInterceptions() OVERRIDE; virtual void SetStrictInterceptions() OVERRIDE;
virtual ResultCode SetStdoutHandle(HANDLE handle) OVERRIDE; virtual ResultCode SetStdoutHandle(HANDLE handle) OVERRIDE;
virtual ResultCode SetStderrHandle(HANDLE handle) OVERRIDE; virtual ResultCode SetStderrHandle(HANDLE handle) OVERRIDE;
......
...@@ -76,7 +76,8 @@ enum TokenLevel { ...@@ -76,7 +76,8 @@ enum TokenLevel {
USER_INTERACTIVE, USER_INTERACTIVE,
USER_NON_ADMIN, USER_NON_ADMIN,
USER_RESTRICTED_SAME_ACCESS, USER_RESTRICTED_SAME_ACCESS,
USER_UNPROTECTED USER_UNPROTECTED,
USER_LAST
}; };
// The Job level specifies a set of decreasing security profiles for the // The Job level specifies a set of decreasing security profiles for the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment