Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320)
[chromium-blink-merge.git] / sandbox / win / src / process_thread_interception.cc
blob45926bc5f6358a4b326f3c7bf04483b3dabd434a
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 (orig_CreateProcessW(application_name, command_line, process_attributes,
271 thread_attributes, inherit_handles, flags,
272 environment, current_directory, startup_info,
273 process_information)) {
274 return TRUE;
277 // We don't trust that the IPC can work this early.
278 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
279 return FALSE;
281 DWORD original_error = ::GetLastError();
283 do {
284 if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
285 WRITE))
286 break;
288 void* memory = GetGlobalIPCMemory();
289 if (NULL == memory)
290 break;
292 const wchar_t* cur_dir = NULL;
294 wchar_t current_directory[MAX_PATH];
295 DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
296 if (0 != result && result < MAX_PATH)
297 cur_dir = current_directory;
299 SharedMemIPCClient ipc(memory);
300 CrossCallReturn answer = {0};
302 InOutCountedBuffer proc_info(process_information,
303 sizeof(PROCESS_INFORMATION));
305 ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, application_name,
306 command_line, cur_dir, proc_info, &answer);
307 if (SBOX_ALL_OK != code)
308 break;
310 ::SetLastError(answer.win32_result);
311 if (ERROR_SUCCESS != answer.win32_result)
312 return FALSE;
314 return TRUE;
315 } while (false);
317 ::SetLastError(original_error);
318 return FALSE;
321 BOOL WINAPI TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,
322 LPCSTR application_name, LPSTR command_line,
323 LPSECURITY_ATTRIBUTES process_attributes,
324 LPSECURITY_ATTRIBUTES thread_attributes,
325 BOOL inherit_handles, DWORD flags,
326 LPVOID environment, LPCSTR current_directory,
327 LPSTARTUPINFOA startup_info,
328 LPPROCESS_INFORMATION process_information) {
329 if (orig_CreateProcessA(application_name, command_line, process_attributes,
330 thread_attributes, inherit_handles, flags,
331 environment, current_directory, startup_info,
332 process_information)) {
333 return TRUE;
336 // We don't trust that the IPC can work this early.
337 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
338 return FALSE;
340 DWORD original_error = ::GetLastError();
342 do {
343 if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
344 WRITE))
345 break;
347 void* memory = GetGlobalIPCMemory();
348 if (NULL == memory)
349 break;
351 // Convert the input params to unicode.
352 UNICODE_STRING *cmd_unicode = NULL;
353 UNICODE_STRING *app_unicode = NULL;
354 if (command_line) {
355 cmd_unicode = AnsiToUnicode(command_line);
356 if (!cmd_unicode)
357 break;
360 if (application_name) {
361 app_unicode = AnsiToUnicode(application_name);
362 if (!app_unicode) {
363 operator delete(cmd_unicode, NT_ALLOC);
364 break;
368 const wchar_t* cmd_line = cmd_unicode ? cmd_unicode->Buffer : NULL;
369 const wchar_t* app_name = app_unicode ? app_unicode->Buffer : NULL;
370 const wchar_t* cur_dir = NULL;
372 wchar_t current_directory[MAX_PATH];
373 DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
374 if (0 != result && result < MAX_PATH)
375 cur_dir = current_directory;
377 SharedMemIPCClient ipc(memory);
378 CrossCallReturn answer = {0};
380 InOutCountedBuffer proc_info(process_information,
381 sizeof(PROCESS_INFORMATION));
383 ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, app_name,
384 cmd_line, cur_dir, proc_info, &answer);
386 operator delete(cmd_unicode, NT_ALLOC);
387 operator delete(app_unicode, NT_ALLOC);
389 if (SBOX_ALL_OK != code)
390 break;
392 ::SetLastError(answer.win32_result);
393 if (ERROR_SUCCESS != answer.win32_result)
394 return FALSE;
396 return TRUE;
397 } while (false);
399 ::SetLastError(original_error);
400 return FALSE;
403 } // namespace sandbox