• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "sandbox/win/src/process_thread_interception.h"
6 
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"
15 
16 namespace sandbox {
17 
18 SANDBOX_INTERCEPT NtExports g_nt;
19 
20 // Hooks NtOpenThread and proxy the call to the broker if it's trying to
21 // open a thread in the same process.
TargetNtOpenThread(NtOpenThreadFunction orig_OpenThread,PHANDLE thread,ACCESS_MASK desired_access,POBJECT_ATTRIBUTES object_attributes,PCLIENT_ID client_id)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;
30 
31   do {
32     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
33       break;
34     if (!client_id)
35       break;
36 
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;
43 
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;
52         }
53       }
54 
55       thread_id = static_cast<uint32>(
56                       reinterpret_cast<ULONG_PTR>(client_id->UniqueThread));
57     } __except(EXCEPTION_EXECUTE_HANDLER) {
58       break;
59     }
60 
61     if (should_break)
62       break;
63 
64     if (!ValidParameter(thread, sizeof(HANDLE), WRITE))
65       break;
66 
67     void* memory = GetGlobalIPCMemory();
68     if (NULL == memory)
69       break;
70 
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;
77 
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;
88 
89     __try {
90       // Write the output parameters.
91       *thread = answer.handle;
92     } __except(EXCEPTION_EXECUTE_HANDLER) {
93       break;
94     }
95 
96     return answer.nt_status;
97   } while (false);
98 
99   return status;
100 }
101 
102 // Hooks NtOpenProcess and proxy the call to the broker if it's trying to
103 // open the current process.
TargetNtOpenProcess(NtOpenProcessFunction orig_OpenProcess,PHANDLE process,ACCESS_MASK desired_access,POBJECT_ATTRIBUTES object_attributes,PCLIENT_ID client_id)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;
112 
113   do {
114     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
115       break;
116     if (!client_id)
117       break;
118 
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;
130         }
131       }
132 
133       process_id = static_cast<uint32>(
134                       reinterpret_cast<ULONG_PTR>(client_id->UniqueProcess));
135     } __except(EXCEPTION_EXECUTE_HANDLER) {
136       break;
137     }
138 
139     if (should_break)
140       break;
141 
142     if (!ValidParameter(process, sizeof(HANDLE), WRITE))
143       break;
144 
145     void* memory = GetGlobalIPCMemory();
146     if (NULL == memory)
147       break;
148 
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;
155 
156     if (!NT_SUCCESS(answer.nt_status))
157       return answer.nt_status;
158 
159     __try {
160       // Write the output parameters.
161       *process = answer.handle;
162     } __except(EXCEPTION_EXECUTE_HANDLER) {
163       break;
164     }
165 
166     return answer.nt_status;
167   } while (false);
168 
169   return status;
170 }
171 
172 
TargetNtOpenProcessToken(NtOpenProcessTokenFunction orig_OpenProcessToken,HANDLE process,ACCESS_MASK desired_access,PHANDLE token)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;
179 
180   do {
181     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
182       break;
183 
184     if (CURRENT_PROCESS != process)
185       break;
186 
187     if (!ValidParameter(token, sizeof(HANDLE), WRITE))
188       break;
189 
190     void* memory = GetGlobalIPCMemory();
191     if (NULL == memory)
192       break;
193 
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;
200 
201     if (!NT_SUCCESS(answer.nt_status))
202       return answer.nt_status;
203 
204     __try {
205       // Write the output parameters.
206       *token = answer.handle;
207     } __except(EXCEPTION_EXECUTE_HANDLER) {
208       break;
209     }
210 
211     return answer.nt_status;
212   } while (false);
213 
214   return status;
215 }
216 
TargetNtOpenProcessTokenEx(NtOpenProcessTokenExFunction orig_OpenProcessTokenEx,HANDLE process,ACCESS_MASK desired_access,ULONG handle_attributes,PHANDLE token)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;
224 
225   do {
226     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
227       break;
228 
229     if (CURRENT_PROCESS != process)
230       break;
231 
232     if (!ValidParameter(token, sizeof(HANDLE), WRITE))
233       break;
234 
235     void* memory = GetGlobalIPCMemory();
236     if (NULL == memory)
237       break;
238 
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;
245 
246     if (!NT_SUCCESS(answer.nt_status))
247       return answer.nt_status;
248 
249     __try {
250       // Write the output parameters.
251       *token = answer.handle;
252     } __except(EXCEPTION_EXECUTE_HANDLER) {
253       break;
254     }
255 
256     return answer.nt_status;
257   } while (false);
258 
259   return status;
260 }
261 
TargetCreateProcessW(CreateProcessWFunction orig_CreateProcessW,LPCWSTR application_name,LPWSTR command_line,LPSECURITY_ATTRIBUTES process_attributes,LPSECURITY_ATTRIBUTES thread_attributes,BOOL inherit_handles,DWORD flags,LPVOID environment,LPCWSTR current_directory,LPSTARTUPINFOW startup_info,LPPROCESS_INFORMATION process_information)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;
275   }
276 
277   // We don't trust that the IPC can work this early.
278   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
279     return FALSE;
280 
281   DWORD original_error = ::GetLastError();
282 
283   do {
284     if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
285                         WRITE))
286       break;
287 
288     void* memory = GetGlobalIPCMemory();
289     if (NULL == memory)
290       break;
291 
292     const wchar_t* cur_dir = NULL;
293 
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;
298 
299     SharedMemIPCClient ipc(memory);
300     CrossCallReturn answer = {0};
301 
302     InOutCountedBuffer proc_info(process_information,
303                                  sizeof(PROCESS_INFORMATION));
304 
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;
309 
310     ::SetLastError(answer.win32_result);
311     if (ERROR_SUCCESS != answer.win32_result)
312       return FALSE;
313 
314     return TRUE;
315   } while (false);
316 
317   ::SetLastError(original_error);
318   return FALSE;
319 }
320 
TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,LPCSTR application_name,LPSTR command_line,LPSECURITY_ATTRIBUTES process_attributes,LPSECURITY_ATTRIBUTES thread_attributes,BOOL inherit_handles,DWORD flags,LPVOID environment,LPCSTR current_directory,LPSTARTUPINFOA startup_info,LPPROCESS_INFORMATION process_information)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;
334   }
335 
336   // We don't trust that the IPC can work this early.
337   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
338     return FALSE;
339 
340   DWORD original_error = ::GetLastError();
341 
342   do {
343     if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
344                         WRITE))
345       break;
346 
347     void* memory = GetGlobalIPCMemory();
348     if (NULL == memory)
349       break;
350 
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;
358     }
359 
360     if (application_name) {
361       app_unicode = AnsiToUnicode(application_name);
362       if (!app_unicode) {
363         operator delete(cmd_unicode, NT_ALLOC);
364         break;
365       }
366     }
367 
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;
371 
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;
376 
377     SharedMemIPCClient ipc(memory);
378     CrossCallReturn answer = {0};
379 
380     InOutCountedBuffer proc_info(process_information,
381                                  sizeof(PROCESS_INFORMATION));
382 
383     ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, app_name,
384                                 cmd_line, cur_dir, proc_info, &answer);
385 
386     operator delete(cmd_unicode, NT_ALLOC);
387     operator delete(app_unicode, NT_ALLOC);
388 
389     if (SBOX_ALL_OK != code)
390       break;
391 
392     ::SetLastError(answer.win32_result);
393     if (ERROR_SUCCESS != answer.win32_result)
394       return FALSE;
395 
396     return TRUE;
397   } while (false);
398 
399   ::SetLastError(original_error);
400   return FALSE;
401 }
402 
403 }  // namespace sandbox
404