Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / sandbox / win / src / process_thread_interception.cc
blobe6c8c2e9180c91b96164791b67de1081998b2be4
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sandbox/win/src/process_thread_interception.h"
7 #include "sandbox/win/src/crosscall_client.h"
8 #include "sandbox/win/src/ipc_tags.h"
9 #include "sandbox/win/src/policy_params.h"
10 #include "sandbox/win/src/policy_target.h"
11 #include "sandbox/win/src/sandbox_factory.h"
12 #include "sandbox/win/src/sandbox_nt_util.h"
13 #include "sandbox/win/src/sharedmem_ipc_client.h"
14 #include "sandbox/win/src/target_services.h"
16 namespace sandbox {
18 SANDBOX_INTERCEPT NtExports g_nt;
20 // Hooks NtOpenThread and proxy the call to the broker if it's trying to
21 // open a thread in the same process.
22 NTSTATUS WINAPI TargetNtOpenThread(NtOpenThreadFunction orig_OpenThread,
23 PHANDLE thread, ACCESS_MASK desired_access,
24 POBJECT_ATTRIBUTES object_attributes,
25 PCLIENT_ID client_id) {
26 NTSTATUS status = orig_OpenThread(thread, desired_access, object_attributes,
27 client_id);
28 if (NT_SUCCESS(status))
29 return status;
31 do {
32 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
33 break;
34 if (!client_id)
35 break;
37 uint32 thread_id = 0;
38 bool should_break = false;
39 __try {
40 // We support only the calls for the current process
41 if (NULL != client_id->UniqueProcess)
42 should_break = true;
44 // Object attributes should be NULL or empty.
45 if (!should_break && NULL != object_attributes) {
46 if (0 != object_attributes->Attributes ||
47 NULL != object_attributes->ObjectName ||
48 NULL != object_attributes->RootDirectory ||
49 NULL != object_attributes->SecurityDescriptor ||
50 NULL != object_attributes->SecurityQualityOfService) {
51 should_break = true;
55 thread_id = static_cast<uint32>(
56 reinterpret_cast<ULONG_PTR>(client_id->UniqueThread));
57 } __except(EXCEPTION_EXECUTE_HANDLER) {
58 break;
61 if (should_break)
62 break;
64 if (!ValidParameter(thread, sizeof(HANDLE), WRITE))
65 break;
67 void* memory = GetGlobalIPCMemory();
68 if (NULL == memory)
69 break;
71 SharedMemIPCClient ipc(memory);
72 CrossCallReturn answer = {0};
73 ResultCode code = CrossCall(ipc, IPC_NTOPENTHREAD_TAG, desired_access,
74 thread_id, &answer);
75 if (SBOX_ALL_OK != code)
76 break;
78 if (!NT_SUCCESS(answer.nt_status))
79 // The nt_status here is most likely STATUS_INVALID_CID because
80 // in the broker we set the process id in the CID (client ID) param
81 // to be the current process. If you try to open a thread from another
82 // process you will get this INVALID_CID error. On the other hand, if you
83 // try to open a thread in your own process, it should return success.
84 // We don't want to return STATUS_INVALID_CID here, so we return the
85 // return of the original open thread status, which is most likely
86 // STATUS_ACCESS_DENIED.
87 break;
89 __try {
90 // Write the output parameters.
91 *thread = answer.handle;
92 } __except(EXCEPTION_EXECUTE_HANDLER) {
93 break;
96 return answer.nt_status;
97 } while (false);
99 return status;
102 // Hooks NtOpenProcess and proxy the call to the broker if it's trying to
103 // open the current process.
104 NTSTATUS WINAPI TargetNtOpenProcess(NtOpenProcessFunction orig_OpenProcess,
105 PHANDLE process, ACCESS_MASK desired_access,
106 POBJECT_ATTRIBUTES object_attributes,
107 PCLIENT_ID client_id) {
108 NTSTATUS status = orig_OpenProcess(process, desired_access, object_attributes,
109 client_id);
110 if (NT_SUCCESS(status))
111 return status;
113 do {
114 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
115 break;
116 if (!client_id)
117 break;
119 uint32 process_id = 0;
120 bool should_break = false;
121 __try {
122 // Object attributes should be NULL or empty.
123 if (!should_break && NULL != object_attributes) {
124 if (0 != object_attributes->Attributes ||
125 NULL != object_attributes->ObjectName ||
126 NULL != object_attributes->RootDirectory ||
127 NULL != object_attributes->SecurityDescriptor ||
128 NULL != object_attributes->SecurityQualityOfService) {
129 should_break = true;
133 process_id = static_cast<uint32>(
134 reinterpret_cast<ULONG_PTR>(client_id->UniqueProcess));
135 } __except(EXCEPTION_EXECUTE_HANDLER) {
136 break;
139 if (should_break)
140 break;
142 if (!ValidParameter(process, sizeof(HANDLE), WRITE))
143 break;
145 void* memory = GetGlobalIPCMemory();
146 if (NULL == memory)
147 break;
149 SharedMemIPCClient ipc(memory);
150 CrossCallReturn answer = {0};
151 ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESS_TAG, desired_access,
152 process_id, &answer);
153 if (SBOX_ALL_OK != code)
154 break;
156 if (!NT_SUCCESS(answer.nt_status))
157 return answer.nt_status;
159 __try {
160 // Write the output parameters.
161 *process = answer.handle;
162 } __except(EXCEPTION_EXECUTE_HANDLER) {
163 break;
166 return answer.nt_status;
167 } while (false);
169 return status;
173 NTSTATUS WINAPI TargetNtOpenProcessToken(
174 NtOpenProcessTokenFunction orig_OpenProcessToken, HANDLE process,
175 ACCESS_MASK desired_access, PHANDLE token) {
176 NTSTATUS status = orig_OpenProcessToken(process, desired_access, token);
177 if (NT_SUCCESS(status))
178 return status;
180 do {
181 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
182 break;
184 if (CURRENT_PROCESS != process)
185 break;
187 if (!ValidParameter(token, sizeof(HANDLE), WRITE))
188 break;
190 void* memory = GetGlobalIPCMemory();
191 if (NULL == memory)
192 break;
194 SharedMemIPCClient ipc(memory);
195 CrossCallReturn answer = {0};
196 ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESSTOKEN_TAG, process,
197 desired_access, &answer);
198 if (SBOX_ALL_OK != code)
199 break;
201 if (!NT_SUCCESS(answer.nt_status))
202 return answer.nt_status;
204 __try {
205 // Write the output parameters.
206 *token = answer.handle;
207 } __except(EXCEPTION_EXECUTE_HANDLER) {
208 break;
211 return answer.nt_status;
212 } while (false);
214 return status;
217 NTSTATUS WINAPI TargetNtOpenProcessTokenEx(
218 NtOpenProcessTokenExFunction orig_OpenProcessTokenEx, HANDLE process,
219 ACCESS_MASK desired_access, ULONG handle_attributes, PHANDLE token) {
220 NTSTATUS status = orig_OpenProcessTokenEx(process, desired_access,
221 handle_attributes, token);
222 if (NT_SUCCESS(status))
223 return status;
225 do {
226 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
227 break;
229 if (CURRENT_PROCESS != process)
230 break;
232 if (!ValidParameter(token, sizeof(HANDLE), WRITE))
233 break;
235 void* memory = GetGlobalIPCMemory();
236 if (NULL == memory)
237 break;
239 SharedMemIPCClient ipc(memory);
240 CrossCallReturn answer = {0};
241 ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESSTOKENEX_TAG, process,
242 desired_access, handle_attributes, &answer);
243 if (SBOX_ALL_OK != code)
244 break;
246 if (!NT_SUCCESS(answer.nt_status))
247 return answer.nt_status;
249 __try {
250 // Write the output parameters.
251 *token = answer.handle;
252 } __except(EXCEPTION_EXECUTE_HANDLER) {
253 break;
256 return answer.nt_status;
257 } while (false);
259 return status;
262 BOOL WINAPI TargetCreateProcessW(CreateProcessWFunction orig_CreateProcessW,
263 LPCWSTR application_name, LPWSTR command_line,
264 LPSECURITY_ATTRIBUTES process_attributes,
265 LPSECURITY_ATTRIBUTES thread_attributes,
266 BOOL inherit_handles, DWORD flags,
267 LPVOID environment, LPCWSTR current_directory,
268 LPSTARTUPINFOW startup_info,
269 LPPROCESS_INFORMATION process_information) {
270 if (SandboxFactory::GetTargetServices()->GetState()->IsCsrssConnected() &&
271 orig_CreateProcessW(application_name, command_line, process_attributes,
272 thread_attributes, inherit_handles, flags,
273 environment, current_directory, startup_info,
274 process_information)) {
275 return TRUE;
278 // We don't trust that the IPC can work this early.
279 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
280 return FALSE;
282 DWORD original_error = ::GetLastError();
284 do {
285 if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
286 WRITE))
287 break;
289 void* memory = GetGlobalIPCMemory();
290 if (NULL == memory)
291 break;
293 const wchar_t* cur_dir = NULL;
295 wchar_t current_directory[MAX_PATH];
296 DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
297 if (0 != result && result < MAX_PATH)
298 cur_dir = current_directory;
300 SharedMemIPCClient ipc(memory);
301 CrossCallReturn answer = {0};
303 InOutCountedBuffer proc_info(process_information,
304 sizeof(PROCESS_INFORMATION));
306 ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, application_name,
307 command_line, cur_dir, proc_info, &answer);
308 if (SBOX_ALL_OK != code)
309 break;
311 ::SetLastError(answer.win32_result);
312 if (ERROR_SUCCESS != answer.win32_result)
313 return FALSE;
315 return TRUE;
316 } while (false);
318 ::SetLastError(original_error);
319 return FALSE;
322 BOOL WINAPI TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,
323 LPCSTR application_name, LPSTR command_line,
324 LPSECURITY_ATTRIBUTES process_attributes,
325 LPSECURITY_ATTRIBUTES thread_attributes,
326 BOOL inherit_handles, DWORD flags,
327 LPVOID environment, LPCSTR current_directory,
328 LPSTARTUPINFOA startup_info,
329 LPPROCESS_INFORMATION process_information) {
330 if (orig_CreateProcessA(application_name, command_line, process_attributes,
331 thread_attributes, inherit_handles, flags,
332 environment, current_directory, startup_info,
333 process_information)) {
334 return TRUE;
337 // We don't trust that the IPC can work this early.
338 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
339 return FALSE;
341 DWORD original_error = ::GetLastError();
343 do {
344 if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
345 WRITE))
346 break;
348 void* memory = GetGlobalIPCMemory();
349 if (NULL == memory)
350 break;
352 // Convert the input params to unicode.
353 UNICODE_STRING *cmd_unicode = NULL;
354 UNICODE_STRING *app_unicode = NULL;
355 if (command_line) {
356 cmd_unicode = AnsiToUnicode(command_line);
357 if (!cmd_unicode)
358 break;
361 if (application_name) {
362 app_unicode = AnsiToUnicode(application_name);
363 if (!app_unicode) {
364 operator delete(cmd_unicode, NT_ALLOC);
365 break;
369 const wchar_t* cmd_line = cmd_unicode ? cmd_unicode->Buffer : NULL;
370 const wchar_t* app_name = app_unicode ? app_unicode->Buffer : NULL;
371 const wchar_t* cur_dir = NULL;
373 wchar_t current_directory[MAX_PATH];
374 DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
375 if (0 != result && result < MAX_PATH)
376 cur_dir = current_directory;
378 SharedMemIPCClient ipc(memory);
379 CrossCallReturn answer = {0};
381 InOutCountedBuffer proc_info(process_information,
382 sizeof(PROCESS_INFORMATION));
384 ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, app_name,
385 cmd_line, cur_dir, proc_info, &answer);
387 operator delete(cmd_unicode, NT_ALLOC);
388 operator delete(app_unicode, NT_ALLOC);
390 if (SBOX_ALL_OK != code)
391 break;
393 ::SetLastError(answer.win32_result);
394 if (ERROR_SUCCESS != answer.win32_result)
395 return FALSE;
397 return TRUE;
398 } while (false);
400 ::SetLastError(original_error);
401 return FALSE;
404 } // namespace sandbox