Commit f7540af7 authored by shrikant's avatar shrikant Committed by Commit bot

This CL adds a method to create process using LowBox token on Windows. LowBox...

This CL adds a method to create process using LowBox token on Windows. LowBox will help us tackle some of the escapes from Sandbox.

R=cpu,jschuh,rvargas,wfh,forshaw
BUG=455496

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

Cr-Commit-Position: refs/heads/master@{#318648}
parent 611754ae
......@@ -141,4 +141,21 @@ TEST(AppContainerTest, RequiresImpersonation) {
runner.GetPolicy()->SetAppContainer(kAppContainerSid));
}
TEST(AppContainerTest, DenyOpenEventForLowBox) {
if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
return;
TestRunner runner(JOB_UNPROTECTED, USER_UNPROTECTED, USER_UNPROTECTED);
base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, L"test"));
ASSERT_TRUE(event.IsValid());
EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetLowBox(kAppContainerSid));
EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test"));
}
// TODO(shrikant): Please add some tests to prove usage of lowbox token like
// socket connection to local server in lock down mode.
} // namespace sandbox
......@@ -349,6 +349,9 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
// This downcast is safe as long as we control CreatePolicy()
PolicyBase* policy_base = static_cast<PolicyBase*>(policy);
if (policy_base->GetAppContainer() && policy_base->GetLowBoxSid())
return SBOX_ERROR_BAD_PARAMS;
// Construct the tokens and the job object that we are going to associate
// with the soon to be created target process.
HANDLE initial_token_temp;
......@@ -482,6 +485,7 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
thread_pool_);
DWORD win_result = target->Create(exe_path, command_line, inherit_handles,
policy_base->GetLowBoxSid() ? true : false,
startup_info, &process_info);
if (ERROR_SUCCESS != win_result)
return SpawnCleanup(target, win_result);
......
......@@ -656,5 +656,29 @@ typedef NTSTATUS (WINAPI* NtOpenSymbolicLinkObjectFunction) (
#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
#define DIRECTORY_ALL_ACCESS 0x000F
typedef NTSTATUS (WINAPI* NtCreateLowBoxToken)(
OUT PHANDLE token,
IN HANDLE original_handle,
IN ACCESS_MASK access,
IN POBJECT_ATTRIBUTES object_attribute,
IN PSID appcontainer_sid,
IN DWORD capabilityCount,
IN PSID_AND_ATTRIBUTES capabilities,
IN DWORD handle_count,
IN PHANDLE handles);
typedef NTSTATUS(WINAPI *NtSetInformationProcess)(
IN HANDLE process_handle,
IN ULONG info_class,
IN PVOID process_information,
IN ULONG information_length);
struct PROCESS_ACCESS_TOKEN {
HANDLE token;
HANDLE thread;
};
const unsigned int NtProcessInformationAccessToken = 9;
#endif // SANDBOX_WIN_SRC_NT_INTERNALS_H__
......@@ -79,16 +79,6 @@ NTSTATUS WINAPI TargetNtSetInformationThread(
break;
if (ThreadImpersonationToken != thread_info_class)
break;
if (!thread_information)
break;
HANDLE token;
if (sizeof(token) > thread_information_bytes)
break;
NTSTATUS ret = CopyData(&token, thread_information, sizeof(token));
if (!NT_SUCCESS(ret) || NULL != token)
break;
// This is a revert to self.
return STATUS_SUCCESS;
} while (false);
......
......@@ -183,6 +183,10 @@ class TargetPolicy {
// Sets a capability to be enabled for the sandboxed process' AppContainer.
virtual ResultCode SetCapability(const wchar_t* sid) = 0;
// Sets the LowBox token for sandboxed process. This is mutually exclusive
// with SetAppContainer method.
virtual ResultCode SetLowBox(const wchar_t* sid) = 0;
// Sets the mitigations enabled when the process is created. Most of these
// are implemented as attributes passed via STARTUPINFOEX. So they take
// effect before any thread in the target executes. The declaration of
......
......@@ -98,7 +98,8 @@ PolicyBase::PolicyBase()
mitigations_(0),
delayed_mitigations_(0),
policy_maker_(NULL),
policy_(NULL) {
policy_(NULL),
lowbox_sid_(NULL) {
::InitializeCriticalSection(&lock_);
// Initialize the IPC dispatcher array.
memset(&ipc_targets_, NULL, sizeof(ipc_targets_));
......@@ -152,6 +153,10 @@ PolicyBase::~PolicyBase() {
delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG];
delete policy_maker_;
delete policy_;
if (lowbox_sid_)
::LocalFree(lowbox_sid_);
::DeleteCriticalSection(&lock_);
}
......@@ -310,6 +315,10 @@ ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) {
if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
return SBOX_ALL_OK;
// SetLowBox and SetAppContainer are mutually exclusive.
if (lowbox_sid_)
return SBOX_ERROR_UNSUPPORTED;
// Windows refuses to work with an impersonation token for a process inside
// an AppContainer. If the caller wants to use a more privileged initial
// token, or if the lockdown level will prevent the process from starting,
......@@ -331,6 +340,25 @@ ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
return SBOX_ALL_OK;
}
ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
return SBOX_ERROR_UNSUPPORTED;
// SetLowBox and SetAppContainer are mutually exclusive.
if (appcontainer_list_.get())
return SBOX_ERROR_UNSUPPORTED;
DCHECK(sid);
if (lowbox_sid_)
return SBOX_ERROR_BAD_PARAMS;
if (!ConvertStringSidToSid(sid, &lowbox_sid_))
return SBOX_ERROR_GENERIC;
return SBOX_ALL_OK;
}
ResultCode PolicyBase::SetProcessMitigations(
MitigationFlags flags) {
if (!CanSetProcessMitigationsPreStartup(flags))
......@@ -448,6 +476,11 @@ ResultCode PolicyBase::MakeJobObject(HANDLE* job) {
}
ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer() &&
lowbox_sid_) {
return SBOX_ERROR_BAD_PARAMS;
}
// Create the 'naked' token. This will be the permanent token associated
// with the process and therefore with any thread that is not impersonating.
DWORD result = CreateRestrictedToken(lockdown, lockdown_level_,
......@@ -476,6 +509,9 @@ ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
alternate_desktop_integrity_level_label_ = integrity_level_;
}
// We are maintaining two mutually exclusive approaches. One is to start an
// AppContainer process through StartupInfoEx and other is replacing
// existing token with LowBox token after process creation.
if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) {
// Windows refuses to work with an impersonation token. See SetAppContainer
// implementation for more details.
......@@ -484,6 +520,21 @@ ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
*initial = INVALID_HANDLE_VALUE;
return SBOX_ALL_OK;
} else if (lowbox_sid_) {
NtCreateLowBoxToken CreateLowBoxToken = NULL;
ResolveNTFunctionPtr("NtCreateLowBoxToken", &CreateLowBoxToken);
OBJECT_ATTRIBUTES obj_attr;
InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
HANDLE token_lowbox = NULL;
NTSTATUS status = CreateLowBoxToken(&token_lowbox, *lockdown,
TOKEN_ALL_ACCESS, &obj_attr,
lowbox_sid_, 0, NULL, 0, NULL);
if (!NT_SUCCESS(status))
return SBOX_ERROR_GENERIC;
DCHECK(token_lowbox);
::CloseHandle(*lockdown);
*lockdown = token_lowbox;
}
// Create the 'better' token. We use this token as the one that the main
......@@ -505,6 +556,10 @@ const AppContainerAttributes* PolicyBase::GetAppContainer() const {
return appcontainer_list_.get();
}
const PSID PolicyBase::GetLowBoxSid() const {
return lowbox_sid_;
}
bool PolicyBase::AddTarget(TargetProcess* target) {
if (NULL != policy_)
policy_maker_->Done();
......
......@@ -56,6 +56,7 @@ class PolicyBase : public Dispatcher, public TargetPolicy {
IntegrityLevel integrity_level) override;
virtual ResultCode SetAppContainer(const wchar_t* sid) override;
virtual ResultCode SetCapability(const wchar_t* sid) override;
virtual ResultCode SetLowBox(const wchar_t* sid) override;
virtual ResultCode SetProcessMitigations(MitigationFlags flags) override;
virtual MitigationFlags GetProcessMitigations() override;
virtual ResultCode SetDelayedProcessMitigations(
......@@ -86,6 +87,8 @@ class PolicyBase : public Dispatcher, public TargetPolicy {
const AppContainerAttributes* GetAppContainer() const;
const PSID GetLowBoxSid() const;
// Adds a target process to the internal list of targets. Internally a
// call to TargetProcess::Init() is issued.
bool AddTarget(TargetProcess* target);
......@@ -158,6 +161,7 @@ class PolicyBase : public Dispatcher, public TargetPolicy {
HandleCloser handle_closer_;
std::vector<base::string16> capabilities_;
scoped_ptr<AppContainerAttributes> appcontainer_list_;
PSID lowbox_sid_;
static HDESK alternate_desktop_handle_;
static HWINSTA alternate_winstation_handle_;
......
......@@ -29,7 +29,8 @@ SBOX_TESTS_COMMAND int Event_Open(int argc, wchar_t **argv) {
return SBOX_TEST_SUCCEEDED;
if (ERROR_ACCESS_DENIED == error_open ||
ERROR_BAD_PATHNAME == error_open)
ERROR_BAD_PATHNAME == error_open ||
ERROR_FILE_NOT_FOUND == error_open)
return SBOX_TEST_DENIED;
return SBOX_TEST_FAILED;
......
......@@ -14,6 +14,7 @@
#include "sandbox/win/src/policy_low_level.h"
#include "sandbox/win/src/sandbox_types.h"
#include "sandbox/win/src/sharedmem_ipc_server.h"
#include "sandbox/win/src/win_utils.h"
namespace {
......@@ -113,8 +114,15 @@ TargetProcess::~TargetProcess() {
DWORD TargetProcess::Create(const wchar_t* exe_path,
const wchar_t* command_line,
bool inherit_handles,
bool set_lockdown_token_after_create,
const base::win::StartupInformation& startup_info,
base::win::ScopedProcessInformation* target_info) {
if (set_lockdown_token_after_create &&
base::win::GetVersion() < base::win::VERSION_WIN8) {
// We don't allow set_lockdown_token_after_create below Windows 8.
return ERROR_INVALID_PARAMETER;
}
exe_name_.reset(_wcsdup(exe_path));
// the command line needs to be writable by CreateProcess().
......@@ -133,22 +141,40 @@ DWORD TargetProcess::Create(const wchar_t* exe_path,
flags |= CREATE_BREAKAWAY_FROM_JOB;
}
base::win::ScopedHandle scoped_lockdown_token(lockdown_token_.Take());
PROCESS_INFORMATION temp_process_info = {};
if (!::CreateProcessAsUserW(lockdown_token_.Get(),
exe_path,
cmd_line.get(),
NULL, // No security attribute.
NULL, // No thread attribute.
inherit_handles,
flags,
NULL, // Use the environment of the caller.
NULL, // Use current directory of the caller.
startup_info.startup_info(),
&temp_process_info)) {
return ::GetLastError();
if (set_lockdown_token_after_create) {
// First create process with a default token and then replace it later,
// after setting primary thread token. This is required for setting
// an AppContainer token along with an impersonation token.
if (!::CreateProcess(exe_path,
cmd_line.get(),
NULL, // No security attribute.
NULL, // No thread attribute.
inherit_handles,
flags,
NULL, // Use the environment of the caller.
NULL, // Use current directory of the caller.
startup_info.startup_info(),
&temp_process_info)) {
return ::GetLastError();
}
} else {
if (!::CreateProcessAsUserW(scoped_lockdown_token.Get(),
exe_path,
cmd_line.get(),
NULL, // No security attribute.
NULL, // No thread attribute.
inherit_handles,
flags,
NULL, // Use the environment of the caller.
NULL, // Use current directory of the caller.
startup_info.startup_info(),
&temp_process_info)) {
return ::GetLastError();
}
}
base::win::ScopedProcessInformation process_info(temp_process_info);
lockdown_token_.Close();
DWORD win_result = ERROR_SUCCESS;
......@@ -176,6 +202,26 @@ DWORD TargetProcess::Create(const wchar_t* exe_path,
initial_token_.Close();
}
if (set_lockdown_token_after_create) {
PROCESS_ACCESS_TOKEN process_access_token;
process_access_token.thread = process_info.thread_handle();
process_access_token.token = scoped_lockdown_token.Get();
NtSetInformationProcess SetInformationProcess = NULL;
ResolveNTFunctionPtr("NtSetInformationProcess", &SetInformationProcess);
NTSTATUS status = SetInformationProcess(
process_info.process_handle(),
static_cast<PROCESS_INFORMATION_CLASS>(NtProcessInformationAccessToken),
&process_access_token,
sizeof(process_access_token));
if (!NT_SUCCESS(status)) {
win_result = ::GetLastError();
::TerminateProcess(process_info.process_handle(), 0); // exit code
return win_result;
}
}
CONTEXT context;
context.ContextFlags = CONTEXT_ALL;
if (!::GetThreadContext(process_info.thread_handle(), &context)) {
......
......@@ -45,9 +45,12 @@ class TargetProcess {
void Release() {}
// Creates the new target process. The process is created suspended.
// When |set_lockdown_token_after_create| is set, the lockdown token
// is replaced after the process is created
DWORD Create(const wchar_t* exe_path,
const wchar_t* command_line,
bool inherit_handles,
bool set_lockdown_token_after_create,
const base::win::StartupInformation& startup_info,
base::win::ScopedProcessInformation* target_info);
......
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