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