1 // Copyright (c) 2011 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_policy.h"
6 
7 #include <stdint.h>
8 
9 #include <memory>
10 #include <string>
11 
12 #include "base/memory/free_deleter.h"
13 #include "sandbox/win/src/ipc_tags.h"
14 #include "sandbox/win/src/nt_internals.h"
15 #include "sandbox/win/src/policy_engine_opcodes.h"
16 #include "sandbox/win/src/policy_params.h"
17 #include "sandbox/win/src/sandbox_types.h"
18 #include "sandbox/win/src/win_utils.h"
19 
20 namespace {
21 
22 // These are the only safe rights that can be given to a sandboxed
23 // process for the process created by the broker. All others are potential
24 // vectors of privilege elevation.
25 const DWORD kProcessRights = SYNCHRONIZE | PROCESS_QUERY_INFORMATION |
26                              PROCESS_QUERY_LIMITED_INFORMATION |
27                              PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME;
28 
29 const DWORD kThreadRights = SYNCHRONIZE | THREAD_TERMINATE |
30                             THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION |
31                             THREAD_QUERY_LIMITED_INFORMATION |
32                             THREAD_SET_LIMITED_INFORMATION;
33 
34 // Creates a child process and duplicates the handles to 'target_process'. The
35 // remaining parameters are the same as CreateProcess().
CreateProcessExWHelper(HANDLE target_process,bool give_full_access,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,bool bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)36 bool CreateProcessExWHelper(HANDLE target_process,
37                             bool give_full_access,
38                             LPCWSTR lpApplicationName,
39                             LPWSTR lpCommandLine,
40                             LPSECURITY_ATTRIBUTES lpProcessAttributes,
41                             LPSECURITY_ATTRIBUTES lpThreadAttributes,
42                             bool bInheritHandles,
43                             DWORD dwCreationFlags,
44                             LPVOID lpEnvironment,
45                             LPCWSTR lpCurrentDirectory,
46                             LPSTARTUPINFOW lpStartupInfo,
47                             LPPROCESS_INFORMATION lpProcessInformation) {
48   if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes,
49                         lpThreadAttributes, bInheritHandles, dwCreationFlags,
50                         lpEnvironment, lpCurrentDirectory, lpStartupInfo,
51                         lpProcessInformation)) {
52     return false;
53   }
54 
55   DWORD process_access = kProcessRights;
56   DWORD thread_access = kThreadRights;
57   if (give_full_access) {
58     process_access = PROCESS_ALL_ACCESS;
59     thread_access = THREAD_ALL_ACCESS;
60   }
61   if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess,
62                          target_process, &lpProcessInformation->hProcess,
63                          process_access, false, DUPLICATE_CLOSE_SOURCE)) {
64     ::CloseHandle(lpProcessInformation->hThread);
65     return false;
66   }
67   if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread,
68                          target_process, &lpProcessInformation->hThread,
69                          thread_access, false, DUPLICATE_CLOSE_SOURCE)) {
70     return false;
71   }
72   return true;
73 }
74 
75 }  // namespace
76 
77 namespace sandbox {
78 
GenerateRules(const wchar_t * name,TargetPolicy::Semantics semantics,LowLevelPolicy * policy)79 bool ProcessPolicy::GenerateRules(const wchar_t* name,
80                                   TargetPolicy::Semantics semantics,
81                                   LowLevelPolicy* policy) {
82   std::unique_ptr<PolicyRule> process;
83   switch (semantics) {
84     case TargetPolicy::PROCESS_MIN_EXEC: {
85       process.reset(new PolicyRule(GIVE_READONLY));
86       break;
87     };
88     case TargetPolicy::PROCESS_ALL_EXEC: {
89       process.reset(new PolicyRule(GIVE_ALLACCESS));
90       break;
91     };
92     default: { return false; };
93   }
94 
95   if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) {
96     return false;
97   }
98   if (!policy->AddRule(IpcTag::CREATEPROCESSW, process.get())) {
99     return false;
100   }
101   return true;
102 }
103 
OpenThreadAction(const ClientInfo & client_info,uint32_t desired_access,uint32_t thread_id,HANDLE * handle)104 NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info,
105                                          uint32_t desired_access,
106                                          uint32_t thread_id,
107                                          HANDLE* handle) {
108   *handle = nullptr;
109 
110   NtOpenThreadFunction NtOpenThread = nullptr;
111   ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread);
112 
113   OBJECT_ATTRIBUTES attributes = {0};
114   attributes.Length = sizeof(attributes);
115   CLIENT_ID client_id = {0};
116   client_id.UniqueProcess =
117       reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(client_info.process_id));
118   client_id.UniqueThread =
119       reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id));
120 
121   HANDLE local_handle = nullptr;
122   NTSTATUS status =
123       NtOpenThread(&local_handle, desired_access, &attributes, &client_id);
124   if (NT_SUCCESS(status)) {
125     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
126                            client_info.process, handle, 0, false,
127                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
128       return STATUS_ACCESS_DENIED;
129     }
130   }
131 
132   return status;
133 }
134 
OpenProcessAction(const ClientInfo & client_info,uint32_t desired_access,uint32_t process_id,HANDLE * handle)135 NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info,
136                                           uint32_t desired_access,
137                                           uint32_t process_id,
138                                           HANDLE* handle) {
139   *handle = nullptr;
140 
141   NtOpenProcessFunction NtOpenProcess = nullptr;
142   ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess);
143 
144   if (client_info.process_id != process_id)
145     return STATUS_ACCESS_DENIED;
146 
147   OBJECT_ATTRIBUTES attributes = {0};
148   attributes.Length = sizeof(attributes);
149   CLIENT_ID client_id = {0};
150   client_id.UniqueProcess =
151       reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(client_info.process_id));
152   HANDLE local_handle = nullptr;
153   NTSTATUS status =
154       NtOpenProcess(&local_handle, desired_access, &attributes, &client_id);
155   if (NT_SUCCESS(status)) {
156     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
157                            client_info.process, handle, 0, false,
158                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
159       return STATUS_ACCESS_DENIED;
160     }
161   }
162 
163   return status;
164 }
165 
OpenProcessTokenAction(const ClientInfo & client_info,HANDLE process,uint32_t desired_access,HANDLE * handle)166 NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info,
167                                                HANDLE process,
168                                                uint32_t desired_access,
169                                                HANDLE* handle) {
170   *handle = nullptr;
171   NtOpenProcessTokenFunction NtOpenProcessToken = nullptr;
172   ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken);
173 
174   if (CURRENT_PROCESS != process)
175     return STATUS_ACCESS_DENIED;
176 
177   HANDLE local_handle = nullptr;
178   NTSTATUS status =
179       NtOpenProcessToken(client_info.process, desired_access, &local_handle);
180   if (NT_SUCCESS(status)) {
181     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
182                            client_info.process, handle, 0, false,
183                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
184       return STATUS_ACCESS_DENIED;
185     }
186   }
187   return status;
188 }
189 
OpenProcessTokenExAction(const ClientInfo & client_info,HANDLE process,uint32_t desired_access,uint32_t attributes,HANDLE * handle)190 NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info,
191                                                  HANDLE process,
192                                                  uint32_t desired_access,
193                                                  uint32_t attributes,
194                                                  HANDLE* handle) {
195   *handle = nullptr;
196   NtOpenProcessTokenExFunction NtOpenProcessTokenEx = nullptr;
197   ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx);
198 
199   if (CURRENT_PROCESS != process)
200     return STATUS_ACCESS_DENIED;
201 
202   HANDLE local_handle = nullptr;
203   NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access,
204                                          attributes, &local_handle);
205   if (NT_SUCCESS(status)) {
206     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
207                            client_info.process, handle, 0, false,
208                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
209       return STATUS_ACCESS_DENIED;
210     }
211   }
212   return status;
213 }
214 
CreateProcessWAction(EvalResult eval_result,const ClientInfo & client_info,const std::wstring & app_name,const std::wstring & command_line,const std::wstring & current_dir,PROCESS_INFORMATION * process_info)215 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result,
216                                           const ClientInfo& client_info,
217                                           const std::wstring& app_name,
218                                           const std::wstring& command_line,
219                                           const std::wstring& current_dir,
220                                           PROCESS_INFORMATION* process_info) {
221   // The only action supported is ASK_BROKER which means create the process.
222   if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) {
223     return ERROR_ACCESS_DENIED;
224   }
225 
226   STARTUPINFO startup_info = {0};
227   startup_info.cb = sizeof(startup_info);
228   std::unique_ptr<wchar_t, base::FreeDeleter> cmd_line(
229       _wcsdup(command_line.c_str()));
230 
231   bool should_give_full_access = (GIVE_ALLACCESS == eval_result);
232 
233   const wchar_t* cwd = current_dir.c_str();
234   if (current_dir.empty())
235     cwd = nullptr;
236 
237   if (!CreateProcessExWHelper(client_info.process, should_give_full_access,
238                               app_name.c_str(), cmd_line.get(), nullptr,
239                               nullptr, false, 0, nullptr, cwd, &startup_info,
240                               process_info)) {
241     return ERROR_ACCESS_DENIED;
242   }
243   return ERROR_SUCCESS;
244 }
245 
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)246 DWORD ProcessPolicy::CreateThreadAction(
247     const ClientInfo& client_info,
248     const SIZE_T stack_size,
249     const LPTHREAD_START_ROUTINE start_address,
250     const LPVOID parameter,
251     const DWORD creation_flags,
252     LPDWORD thread_id,
253     HANDLE* handle) {
254   *handle = nullptr;
255   HANDLE local_handle =
256       ::CreateRemoteThread(client_info.process, nullptr, stack_size,
257                            start_address, parameter, creation_flags, thread_id);
258   if (!local_handle) {
259     return ::GetLastError();
260   }
261   if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
262                          client_info.process, handle, 0, false,
263                          DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
264     return ERROR_ACCESS_DENIED;
265   }
266   return ERROR_SUCCESS;
267 }
268 
269 }  // namespace sandbox
270