summaryrefslogtreecommitdiffstats
path: root/sandbox/win
diff options
context:
space:
mode:
authorliamjm <liamjm@chromium.org>2016-02-09 14:45:28 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-09 22:47:30 +0000
commit80958824392b9ea4ec1932f02e2bd98b814591ad (patch)
tree75745e39e7105baf1dee2580cd46fe929fa993eb /sandbox/win
parent9835e5e163f789ea43e6aedb7495d5173c431958 (diff)
downloadchromium_src-80958824392b9ea4ec1932f02e2bd98b814591ad.zip
chromium_src-80958824392b9ea4ec1932f02e2bd98b814591ad.tar.gz
chromium_src-80958824392b9ea4ec1932f02e2bd98b814591ad.tar.bz2
Intercept CreateThread inside renderer and proxy out to CreateRemoteThread in browser.
summary: * Create new interception * Create new IPC (IPC_CREATETHREAD_TAG) * new tests in process_policy_test.cc * Interception is installed, but passes call through by default. Proxy is only done for tests, when ALPC ports are closed. Note: the IPC uses VOIDPTR_TYPE for a size_t param. These are not guaranteed to be the same (http://stackoverflow.com/questions/1464174/size-t-vs-intptr-t). Should we create a size_t IPC type? BUG=464430 Review URL: https://codereview.chromium.org/1225183003 Cr-Commit-Position: refs/heads/master@{#374510}
Diffstat (limited to 'sandbox/win')
-rw-r--r--sandbox/win/src/interceptors.h1
-rw-r--r--sandbox/win/src/interceptors_64.cc14
-rw-r--r--sandbox/win/src/interceptors_64.h9
-rw-r--r--sandbox/win/src/ipc_tags.h1
-rw-r--r--sandbox/win/src/policy_broker.cc14
-rw-r--r--sandbox/win/src/policy_broker.h3
-rw-r--r--sandbox/win/src/process_policy_test.cc105
-rw-r--r--sandbox/win/src/process_thread_dispatcher.cc31
-rw-r--r--sandbox/win/src/process_thread_dispatcher.h7
-rw-r--r--sandbox/win/src/process_thread_interception.cc79
-rw-r--r--sandbox/win/src/process_thread_interception.h14
-rw-r--r--sandbox/win/src/process_thread_policy.cc22
-rw-r--r--sandbox/win/src/process_thread_policy.h10
-rw-r--r--sandbox/win/src/sandbox_policy.h18
-rw-r--r--sandbox/win/src/sandbox_policy_base.cc10
-rw-r--r--sandbox/win/src/sandbox_policy_base.h2
-rw-r--r--sandbox/win/src/top_level_dispatcher.cc1
-rw-r--r--sandbox/win/tests/common/controller.cc8
18 files changed, 326 insertions, 23 deletions
diff --git a/sandbox/win/src/interceptors.h b/sandbox/win/src/interceptors.h
index 5ee6fd3..2391957 100644
--- a/sandbox/win/src/interceptors.h
+++ b/sandbox/win/src/interceptors.h
@@ -34,6 +34,7 @@ enum InterceptorId {
// Process-thread dispatcher:
CREATE_PROCESSW_ID,
CREATE_PROCESSA_ID,
+ CREATE_THREAD_ID,
// Registry dispatcher:
CREATE_KEY_ID,
OPEN_KEY_ID,
diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc
index cdef943..a9b38b6 100644
--- a/sandbox/win/src/interceptors_64.cc
+++ b/sandbox/win/src/interceptors_64.cc
@@ -201,6 +201,20 @@ SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessA64(
process_information);
}
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateThread64(LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ PVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id) {
+ CreateThreadFunction orig_fn =
+ reinterpret_cast<CreateThreadFunction>(g_originals[CREATE_THREAD_ID]);
+ return TargetCreateThread(orig_fn, thread_attributes, stack_size,
+ start_address, parameter, creation_flags,
+ thread_id);
+}
+
// -----------------------------------------------------------------------
SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateKey64(
diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h
index 7368ceb..16d1c9f 100644
--- a/sandbox/win/src/interceptors_64.h
+++ b/sandbox/win/src/interceptors_64.h
@@ -122,6 +122,15 @@ SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessA64(
LPVOID environment, LPCSTR current_directory, LPSTARTUPINFOA startup_info,
LPPROCESS_INFORMATION process_information);
+// Interception of CreateThread in kernel32.dll.
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateThread64(LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ PVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id);
+
// -----------------------------------------------------------------------
// Interceptors handled by the registry dispatcher.
diff --git a/sandbox/win/src/ipc_tags.h b/sandbox/win/src/ipc_tags.h
index d680411..3a1724b 100644
--- a/sandbox/win/src/ipc_tags.h
+++ b/sandbox/win/src/ipc_tags.h
@@ -32,6 +32,7 @@ enum {
IPC_GDI_GDIDLLINITIALIZE_TAG,
IPC_GDI_GETSTOCKOBJECT_TAG,
IPC_USER_REGISTERCLASSW_TAG,
+ IPC_CREATETHREAD_TAG,
IPC_LAST_TAG
};
diff --git a/sandbox/win/src/policy_broker.cc b/sandbox/win/src/policy_broker.cc
index e6c2b26..74a93f0 100644
--- a/sandbox/win/src/policy_broker.cc
+++ b/sandbox/win/src/policy_broker.cc
@@ -96,7 +96,8 @@ bool SetupNtdllImports(TargetProcess *child) {
#undef INIT_GLOBAL_NT
#undef INIT_GLOBAL_RTL
-bool SetupBasicInterceptions(InterceptionManager* manager) {
+bool SetupBasicInterceptions(InterceptionManager* manager,
+ bool is_csrss_connected) {
// Interceptions provided by process_thread_policy, without actual policy.
if (!INTERCEPT_NT(manager, NtOpenThread, OPEN_THREAD_ID, 20) ||
!INTERCEPT_NT(manager, NtOpenProcess, OPEN_PROCESS_ID, 20) ||
@@ -116,8 +117,15 @@ bool SetupBasicInterceptions(InterceptionManager* manager) {
20))
return false;
- return INTERCEPT_NT(manager, NtOpenThreadTokenEx, OPEN_THREAD_TOKEN_EX_ID,
- 24);
+ if (!INTERCEPT_NT(manager, NtOpenThreadTokenEx, OPEN_THREAD_TOKEN_EX_ID,
+ 24))
+ return false;
+ }
+
+ if (!is_csrss_connected) {
+ if (!INTERCEPT_EAT(manager, kKerneldllName, CreateThread, CREATE_THREAD_ID,
+ 28))
+ return false;
}
return true;
diff --git a/sandbox/win/src/policy_broker.h b/sandbox/win/src/policy_broker.h
index 15d3b21..a8d819d 100644
--- a/sandbox/win/src/policy_broker.h
+++ b/sandbox/win/src/policy_broker.h
@@ -15,7 +15,8 @@ class TargetProcess;
bool InitGlobalNt();
// Sets up interceptions not controlled by explicit policies.
-bool SetupBasicInterceptions(InterceptionManager* manager);
+bool SetupBasicInterceptions(InterceptionManager* manager,
+ bool is_csrss_connected);
// Sets up imports from NTDLL for the given target process so the interceptions
// can work.
diff --git a/sandbox/win/src/process_policy_test.cc b/sandbox/win/src/process_policy_test.cc
index 4dcefd9..0498d3c 100644
--- a/sandbox/win/src/process_policy_test.cc
+++ b/sandbox/win/src/process_policy_test.cc
@@ -11,6 +11,7 @@
#include "base/win/scoped_handle.h"
#include "base/win/scoped_process_information.h"
#include "base/win/windows_version.h"
+#include "sandbox/win/src/process_thread_interception.h"
#include "sandbox/win/src/sandbox.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "sandbox/win/src/sandbox_policy.h"
@@ -269,6 +270,74 @@ SBOX_TESTS_COMMAND int Process_OpenToken(int argc, wchar_t **argv) {
return SBOX_TEST_FAILED;
}
+// Generate a event name, used to test thread creation.
+std::wstring GenerateEventName(DWORD pid) {
+ wchar_t buff[30] = {0};
+ int res = swprintf_s(buff, sizeof(buff) / sizeof(buff[0]),
+ L"ProcessPolicyTest_%08x", pid);
+ if (-1 != res) {
+ return std::wstring(buff);
+ }
+ return std::wstring();
+}
+
+// This is the function that is called when testing thread creation.
+// It is expected to set an event that the caller is waiting on.
+DWORD TestThreadFunc(LPVOID lpdwThreadParam) {
+ std::wstring event_name =
+ GenerateEventName(reinterpret_cast<DWORD>(lpdwThreadParam));
+ if (!event_name.length()) {
+ return 1;
+ }
+ HANDLE event = ::OpenEvent(EVENT_ALL_ACCESS | EVENT_MODIFY_STATE, FALSE,
+ event_name.c_str());
+ if (!event) {
+ return 1;
+ }
+ if (!SetEvent(event)) {
+ return 1;
+ }
+ return 0;
+}
+
+SBOX_TESTS_COMMAND int Process_CreateThread(int argc, wchar_t** argv) {
+ DWORD pid = ::GetCurrentProcessId();
+ std::wstring event_name = GenerateEventName(pid);
+ if (!event_name.length()) {
+ return SBOX_TEST_FIRST_ERROR;
+ }
+ HANDLE event = ::CreateEvent(NULL, TRUE, FALSE, event_name.c_str());
+ if (!event) {
+ return SBOX_TEST_SECOND_ERROR;
+ }
+
+ DWORD thread_id = 0;
+ HANDLE thread = NULL;
+ thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&TestThreadFunc,
+ (LPVOID)pid, 0, &thread_id);
+
+ if (!thread) {
+ return SBOX_TEST_THIRD_ERROR;
+ }
+ if (!thread_id) {
+ return SBOX_TEST_FOURTH_ERROR;
+ }
+ if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
+ return SBOX_TEST_FIFTH_ERROR;
+ }
+ DWORD exit_code = 0;
+ if (!GetExitCodeThread(thread, &exit_code)) {
+ return SBOX_TEST_SIXTH_ERROR;
+ }
+ if (exit_code) {
+ return SBOX_TEST_SEVENTH_ERROR;
+ }
+ if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) {
+ return SBOX_TEST_FAILED;
+ }
+ return SBOX_TEST_SUCCEEDED;
+}
+
TEST(ProcessPolicyTest, TestAllAccess) {
// Check if the "all access" rule fails to be added when the token is too
// powerful.
@@ -397,7 +466,6 @@ TEST(ProcessPolicyTest, TestCreateProcessA) {
sandbox::TargetPolicy* policy = runner.GetPolicy();
policy->SetJobLevel(JOB_NONE, 0);
policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
-
base::string16 exe_path = MakePathToSys(L"calc.exe", false);
ASSERT_TRUE(!exe_path.empty());
EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
@@ -406,4 +474,37 @@ TEST(ProcessPolicyTest, TestCreateProcessA) {
runner.RunTest(L"Process_CreateProcessA calc.exe"));
}
-} // namespace sandbox
+// This tests that the CreateThread works with CSRSS not locked down.
+// In other words, that the interception passes through OK.
+TEST(ProcessPolicyTest, TestCreateThreadWithCsrss) {
+ TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
+ runner.SetDisableCsrss(false);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_CreateThread"));
+}
+
+// This tests that the CreateThread works with CSRSS locked down.
+// In other words, that the interception correctly works.
+TEST(ProcessPolicyTest, TestCreateThreadWithoutCsrss) {
+ TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_CreateThread"));
+}
+
+// This tests that our CreateThread interceptors works when called directly.
+TEST(ProcessPolicyTest, TestCreateThreadOutsideSandbox) {
+ DWORD pid = ::GetCurrentProcessId();
+ std::wstring event_name = GenerateEventName(pid);
+ ASSERT_STRNE(NULL, event_name.c_str());
+ HANDLE event = ::CreateEvent(NULL, TRUE, FALSE, event_name.c_str());
+ EXPECT_NE(static_cast<HANDLE>(NULL), event);
+
+ DWORD thread_id = 0;
+ HANDLE thread = NULL;
+ thread = TargetCreateThread(::CreateThread, NULL, 0,
+ (LPTHREAD_START_ROUTINE)&TestThreadFunc,
+ (LPVOID)pid, 0, &thread_id);
+ EXPECT_NE(static_cast<HANDLE>(NULL), thread);
+ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(thread, INFINITE));
+ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(event, INFINITE));
+}
+
+} // namespace sandbox \ No newline at end of file
diff --git a/sandbox/win/src/process_thread_dispatcher.cc b/sandbox/win/src/process_thread_dispatcher.cc
index 8debd1e..886017c 100644
--- a/sandbox/win/src/process_thread_dispatcher.cc
+++ b/sandbox/win/src/process_thread_dispatcher.cc
@@ -124,11 +124,22 @@ ThreadProcessDispatcher::ThreadProcessDispatcher(PolicyBase* policy_base)
reinterpret_cast<CallbackGeneric>(
&ThreadProcessDispatcher::CreateProcessW)};
+ // NOTE(liamjm): 2nd param is size_t: Using VOIDPTR_TYPE as they are
+ // the same size on windows.
+ static_assert(sizeof(size_t) == sizeof(void*),
+ "VOIDPTR_TYPE not same size as size_t");
+ static const IPCCall create_thread_params = {
+ {IPC_CREATETHREAD_TAG,
+ {VOIDPTR_TYPE, VOIDPTR_TYPE, VOIDPTR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ThreadProcessDispatcher::CreateThread)};
+
ipc_calls_.push_back(open_thread);
ipc_calls_.push_back(open_process);
ipc_calls_.push_back(process_token);
ipc_calls_.push_back(process_tokenex);
ipc_calls_.push_back(create_params);
+ ipc_calls_.push_back(create_thread_params);
}
bool ThreadProcessDispatcher::SetupService(InterceptionManager* manager,
@@ -138,6 +149,7 @@ bool ThreadProcessDispatcher::SetupService(InterceptionManager* manager,
case IPC_NTOPENPROCESS_TAG:
case IPC_NTOPENPROCESSTOKEN_TAG:
case IPC_NTOPENPROCESSTOKENEX_TAG:
+ case IPC_CREATETHREAD_TAG:
// There is no explicit policy for these services.
NOTREACHED();
return false;
@@ -244,4 +256,23 @@ bool ThreadProcessDispatcher::CreateProcessW(IPCInfo* ipc, base::string16* name,
return true;
}
+bool ThreadProcessDispatcher::CreateThread(IPCInfo* ipc,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags) {
+ if (!start_address) {
+ return false;
+ }
+
+ HANDLE handle;
+ DWORD ret = ProcessPolicy::CreateThreadAction(*ipc->client_info, stack_size,
+ start_address, parameter,
+ creation_flags, NULL, &handle);
+
+ ipc->return_info.nt_status = ret;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
} // namespace sandbox
diff --git a/sandbox/win/src/process_thread_dispatcher.h b/sandbox/win/src/process_thread_dispatcher.h
index 008385f..d39ac65 100644
--- a/sandbox/win/src/process_thread_dispatcher.h
+++ b/sandbox/win/src/process_thread_dispatcher.h
@@ -50,6 +50,13 @@ class ThreadProcessDispatcher : public Dispatcher {
base::string16* cur_dir,
CountedBuffer* info);
+ // Processes IPC requests coming from calls to CreateThread() in the target.
+ bool CreateThread(IPCInfo* ipc,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags);
+
PolicyBase* policy_base_;
DISALLOW_COPY_AND_ASSIGN(ThreadProcessDispatcher);
};
diff --git a/sandbox/win/src/process_thread_interception.cc b/sandbox/win/src/process_thread_interception.cc
index f8a144f..9cb20b9 100644
--- a/sandbox/win/src/process_thread_interception.cc
+++ b/sandbox/win/src/process_thread_interception.cc
@@ -5,7 +5,7 @@
#include "sandbox/win/src/process_thread_interception.h"
#include <stdint.h>
-
+#include "base/win/windows_version.h"
#include "sandbox/win/src/crosscall_client.h"
#include "sandbox/win/src/ipc_tags.h"
#include "sandbox/win/src/policy_params.h"
@@ -408,4 +408,81 @@ BOOL WINAPI TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,
return FALSE;
}
+HANDLE WINAPI TargetCreateThread(CreateThreadFunction orig_CreateThread,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id) {
+ HANDLE hThread = NULL;
+
+ TargetServices* target_services = SandboxFactory::GetTargetServices();
+ if (NULL == target_services ||
+ target_services->GetState()->IsCsrssConnected()) {
+ hThread = orig_CreateThread(thread_attributes, stack_size, start_address,
+ parameter, creation_flags, thread_id);
+ if (hThread) {
+ return hThread;
+ }
+ }
+
+ DWORD original_error = ::GetLastError();
+ do {
+ if (NULL == target_services)
+ break;
+
+ // We don't trust that the IPC can work this early.
+ if (!target_services->GetState()->InitCalled())
+ break;
+
+ __try {
+ if (NULL != thread_id &&
+ !ValidParameter(thread_id, sizeof(*thread_id), WRITE))
+ break;
+
+ if (nullptr == start_address)
+ break;
+ // We don't support thread_attributes not being null.
+ if (nullptr != thread_attributes)
+ break;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ void* memory = GetGlobalIPCMemory();
+ if (nullptr == memory)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+
+ // NOTE: we don't pass the thread_attributes through. This matches the
+ // approach in CreateProcess and in CreateThreadInternal().
+ ResultCode code = CrossCall(ipc, IPC_CREATETHREAD_TAG,
+ reinterpret_cast<LPVOID>(stack_size),
+ reinterpret_cast<LPVOID>(start_address),
+ parameter, creation_flags, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ ::SetLastError(answer.win32_result);
+ if (ERROR_SUCCESS != answer.win32_result) {
+ return NULL;
+ }
+
+ __try {
+ if (thread_id != NULL) {
+ *thread_id = ::GetThreadId(answer.handle);
+ }
+ return answer.handle;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ } while (false);
+
+ ::SetLastError(original_error);
+ return NULL;
+}
+
} // namespace sandbox
diff --git a/sandbox/win/src/process_thread_interception.h b/sandbox/win/src/process_thread_interception.h
index 31dc231..aff1f6d 100644
--- a/sandbox/win/src/process_thread_interception.h
+++ b/sandbox/win/src/process_thread_interception.h
@@ -36,11 +36,11 @@ typedef BOOL (WINAPI *CreateProcessAFunction)(
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation);
-typedef HANDLE (WINAPI *CreateThreadFunction)(
+typedef HANDLE(WINAPI* CreateThreadFunction)(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
- PVOID lpParameter,
+ LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
@@ -83,6 +83,16 @@ SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessA(
LPVOID environment, LPCSTR current_directory, LPSTARTUPINFOA startup_info,
LPPROCESS_INFORMATION process_information);
+// Interception of CreateThread in kernel32.dll.
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateThread(CreateThreadFunction orig_CreateThread,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id);
+
} // extern "C"
} // namespace sandbox
diff --git a/sandbox/win/src/process_thread_policy.cc b/sandbox/win/src/process_thread_policy.cc
index b4976c0b..11928c8 100644
--- a/sandbox/win/src/process_thread_policy.cc
+++ b/sandbox/win/src/process_thread_policy.cc
@@ -238,4 +238,26 @@ DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result,
return ERROR_SUCCESS;
}
+DWORD ProcessPolicy::CreateThreadAction(
+ const ClientInfo& client_info,
+ const SIZE_T stack_size,
+ const LPTHREAD_START_ROUTINE start_address,
+ const LPVOID parameter,
+ const DWORD creation_flags,
+ LPDWORD thread_id,
+ HANDLE* handle) {
+ HANDLE local_handle =
+ ::CreateRemoteThread(client_info.process, nullptr, stack_size,
+ start_address, parameter, creation_flags, thread_id);
+ if (!local_handle) {
+ return ::GetLastError();
+ }
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return ERROR_ACCESS_DENIED;
+ }
+ return ERROR_SUCCESS;
+}
+
} // namespace sandbox
diff --git a/sandbox/win/src/process_thread_policy.h b/sandbox/win/src/process_thread_policy.h
index a66b52e..0cfa451 100644
--- a/sandbox/win/src/process_thread_policy.h
+++ b/sandbox/win/src/process_thread_policy.h
@@ -76,6 +76,16 @@ class ProcessPolicy {
const base::string16 &app_name,
const base::string16 &command_line,
PROCESS_INFORMATION* process_info);
+
+ // Processes a 'CreateThread()' request from the target.
+ // 'client_info' : the target process that is making the request.
+ static DWORD CreateThreadAction(const ClientInfo& client_info,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ PVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id,
+ HANDLE* handle);
};
} // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index 43b272b..909066f 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -48,17 +48,17 @@ class TargetPolicy {
// over the resulting process and thread handles.
// No other parameters besides the command line are
// passed to the child process.
- PROCESS_ALL_EXEC, // Allows the creation of a process and return fill
+ PROCESS_ALL_EXEC, // Allows the creation of a process and return full
// access on the returned handles.
// This flag can be used only when the main token of
// the sandboxed application is at least INTERACTIVE.
EVENTS_ALLOW_ANY, // Allows the creation of an event with full access.
- EVENTS_ALLOW_READONLY, // Allows opening an even with synchronize access.
- REG_ALLOW_READONLY, // Allows readonly access to a registry key.
- REG_ALLOW_ANY, // Allows read and write access to a registry key.
- FAKE_USER_GDI_INIT // Fakes user32 and gdi32 initialization. This can
- // be used to allow the DLLs to load and initialize
- // even if the process cannot access that subsystem.
+ EVENTS_ALLOW_READONLY, // Allows opening an even with synchronize access.
+ REG_ALLOW_READONLY, // Allows readonly access to a registry key.
+ REG_ALLOW_ANY, // Allows read and write access to a registry key.
+ FAKE_USER_GDI_INIT // Fakes user32 and gdi32 initialization. This can
+ // be used to allow the DLLs to load and initialize
+ // even if the process cannot access that subsystem.
};
// Increments the reference count of this object. The reference count must
@@ -209,6 +209,10 @@ class TargetPolicy {
// Returns the currently set delayed mitigation flags.
virtual MitigationFlags GetDelayedProcessMitigations() const = 0;
+ // Disconnect the target from CSRSS when TargetServices::LowerToken() is
+ // called inside the target.
+ virtual void SetDisconnectCsrss() = 0;
+
// Sets the interceptions to operate in strict mode. By default, interceptions
// are performed in "relaxed" mode, where if something inside NTDLL.DLL is
// already patched we attempt to intercept it anyway. Setting interceptions
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index dc3ed1f..f7002bf 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -133,6 +133,7 @@ PolicyBase::PolicyBase()
delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
mitigations_(0),
delayed_mitigations_(0),
+ is_csrss_connected_(true),
policy_maker_(NULL),
policy_(NULL),
lowbox_sid_(NULL) {
@@ -625,6 +626,13 @@ bool PolicyBase::OnJobEmpty(HANDLE job) {
return true;
}
+void PolicyBase::SetDisconnectCsrss() {
+ if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ is_csrss_connected_ = false;
+ AddKernelObjectToClose(L"ALPC Port", NULL);
+ }
+}
+
EvalResult PolicyBase::EvalPolicy(int service,
CountedParameterSetBase* params) {
if (NULL != policy_) {
@@ -677,7 +685,7 @@ bool PolicyBase::SetupAllInterceptions(TargetProcess* target) {
}
}
- if (!SetupBasicInterceptions(&manager))
+ if (!SetupBasicInterceptions(&manager, is_csrss_connected_))
return false;
if (!manager.InitializeInterceptions())
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 6520915..cd30eba 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -61,6 +61,7 @@ class PolicyBase final : public TargetPolicy {
MitigationFlags GetProcessMitigations() override;
ResultCode SetDelayedProcessMitigations(MitigationFlags flags) override;
MitigationFlags GetDelayedProcessMitigations() const override;
+ void SetDisconnectCsrss() override;
void SetStrictInterceptions() override;
ResultCode SetStdoutHandle(HANDLE handle) override;
ResultCode SetStderrHandle(HANDLE handle) override;
@@ -145,6 +146,7 @@ class PolicyBase final : public TargetPolicy {
IntegrityLevel delayed_integrity_level_;
MitigationFlags mitigations_;
MitigationFlags delayed_mitigations_;
+ bool is_csrss_connected_;
// Object in charge of generating the low level policy.
LowLevelPolicy* policy_maker_;
// Memory structure that stores the low level policy.
diff --git a/sandbox/win/src/top_level_dispatcher.cc b/sandbox/win/src/top_level_dispatcher.cc
index e6e224b..1880c62 100644
--- a/sandbox/win/src/top_level_dispatcher.cc
+++ b/sandbox/win/src/top_level_dispatcher.cc
@@ -47,6 +47,7 @@ TopLevelDispatcher::TopLevelDispatcher(PolicyBase* policy) : policy_(policy) {
ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher;
ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher;
ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher;
+ ipc_targets_[IPC_CREATETHREAD_TAG] = dispatcher;
thread_process_dispatcher_.reset(dispatcher);
dispatcher = new SyncDispatcher(policy_);
diff --git a/sandbox/win/tests/common/controller.cc b/sandbox/win/tests/common/controller.cc
index c9c63ae..3b710578 100644
--- a/sandbox/win/tests/common/controller.cc
+++ b/sandbox/win/tests/common/controller.cc
@@ -213,12 +213,8 @@ int TestRunner::InternalRunTest(const wchar_t* command) {
target_process_id_ = 0;
}
- if (disable_csrss_) {
- // Close all ALPC ports to disable CSRSS.
- if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
- policy_->AddKernelObjectToClose(L"ALPC Port", NULL);
- }
- }
+ if (disable_csrss_)
+ policy_->SetDisconnectCsrss();
// Get the path to the sandboxed process.
wchar_t prog_name[MAX_PATH];