summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sandbox/win/src/app_container_test.cc17
-rw-r--r--sandbox/win/src/broker_services.cc4
-rw-r--r--sandbox/win/src/nt_internals.h24
-rw-r--r--sandbox/win/src/policy_target.cc10
-rw-r--r--sandbox/win/src/sandbox_policy.h4
-rw-r--r--sandbox/win/src/sandbox_policy_base.cc57
-rw-r--r--sandbox/win/src/sandbox_policy_base.h4
-rw-r--r--sandbox/win/src/sync_policy_test.cc3
-rw-r--r--sandbox/win/src/target_process.cc72
-rw-r--r--sandbox/win/src/target_process.h3
10 files changed, 173 insertions, 25 deletions
diff --git a/sandbox/win/src/app_container_test.cc b/sandbox/win/src/app_container_test.cc
index 1bfab2c..ced5cbd 100644
--- a/sandbox/win/src/app_container_test.cc
+++ b/sandbox/win/src/app_container_test.cc
@@ -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
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
index 8fa7f0d..8a29f9b 100644
--- a/sandbox/win/src/broker_services.cc
+++ b/sandbox/win/src/broker_services.cc
@@ -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);
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
index 2fe27aa..45511a1 100644
--- a/sandbox/win/src/nt_internals.h
+++ b/sandbox/win/src/nt_internals.h
@@ -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__
diff --git a/sandbox/win/src/policy_target.cc b/sandbox/win/src/policy_target.cc
index 84b7203..fb464cc 100644
--- a/sandbox/win/src/policy_target.cc
+++ b/sandbox/win/src/policy_target.cc
@@ -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);
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index 22a2049..6f096fb 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -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
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index d3c920e..f5ed7e4 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -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();
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 54b0b0b..ea0f3e6 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -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_;
diff --git a/sandbox/win/src/sync_policy_test.cc b/sandbox/win/src/sync_policy_test.cc
index 5368943..9fc08f4 100644
--- a/sandbox/win/src/sync_policy_test.cc
+++ b/sandbox/win/src/sync_policy_test.cc
@@ -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;
diff --git a/sandbox/win/src/target_process.cc b/sandbox/win/src/target_process.cc
index 2c5bf3b..e0284c3 100644
--- a/sandbox/win/src/target_process.cc
+++ b/sandbox/win/src/target_process.cc
@@ -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)) {
diff --git a/sandbox/win/src/target_process.h b/sandbox/win/src/target_process.h
index 9a8dded..cf5ad9f 100644
--- a/sandbox/win/src/target_process.h
+++ b/sandbox/win/src/target_process.h
@@ -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);