OLD | NEW |
| (Empty) |
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 <string> | |
10 | |
11 #include "base/memory/free_deleter.h" | |
12 #include "base/memory/scoped_ptr.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 | | |
26 PROCESS_QUERY_INFORMATION | | |
27 PROCESS_QUERY_LIMITED_INFORMATION | | |
28 PROCESS_TERMINATE | | |
29 PROCESS_SUSPEND_RESUME; | |
30 | |
31 const DWORD kThreadRights = SYNCHRONIZE | | |
32 THREAD_TERMINATE | | |
33 THREAD_SUSPEND_RESUME | | |
34 THREAD_QUERY_INFORMATION | | |
35 THREAD_QUERY_LIMITED_INFORMATION | | |
36 THREAD_SET_LIMITED_INFORMATION; | |
37 | |
38 // Creates a child process and duplicates the handles to 'target_process'. The | |
39 // remaining parameters are the same as CreateProcess(). | |
40 BOOL CreateProcessExWHelper(HANDLE target_process, BOOL give_full_access, | |
41 LPCWSTR lpApplicationName, LPWSTR lpCommandLine, | |
42 LPSECURITY_ATTRIBUTES lpProcessAttributes, | |
43 LPSECURITY_ATTRIBUTES lpThreadAttributes, | |
44 BOOL bInheritHandles, DWORD dwCreationFlags, | |
45 LPVOID lpEnvironment, 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 } | |
76 | |
77 namespace sandbox { | |
78 | |
79 bool ProcessPolicy::GenerateRules(const wchar_t* name, | |
80 TargetPolicy::Semantics semantics, | |
81 LowLevelPolicy* policy) { | |
82 scoped_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: { | |
93 return false; | |
94 }; | |
95 } | |
96 | |
97 if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) { | |
98 return false; | |
99 } | |
100 if (!policy->AddRule(IPC_CREATEPROCESSW_TAG, process.get())) { | |
101 return false; | |
102 } | |
103 return true; | |
104 } | |
105 | |
106 NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info, | |
107 uint32_t desired_access, | |
108 uint32_t thread_id, | |
109 HANDLE* handle) { | |
110 *handle = NULL; | |
111 | |
112 NtOpenThreadFunction NtOpenThread = NULL; | |
113 ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread); | |
114 | |
115 OBJECT_ATTRIBUTES attributes = {0}; | |
116 attributes.Length = sizeof(attributes); | |
117 CLIENT_ID client_id = {0}; | |
118 client_id.UniqueProcess = reinterpret_cast<PVOID>( | |
119 static_cast<ULONG_PTR>(client_info.process_id)); | |
120 client_id.UniqueThread = | |
121 reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id)); | |
122 | |
123 HANDLE local_handle = NULL; | |
124 NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes, | |
125 &client_id); | |
126 if (NT_SUCCESS(status)) { | |
127 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, | |
128 client_info.process, handle, 0, FALSE, | |
129 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { | |
130 return STATUS_ACCESS_DENIED; | |
131 } | |
132 } | |
133 | |
134 return status; | |
135 } | |
136 | |
137 NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info, | |
138 uint32_t desired_access, | |
139 uint32_t process_id, | |
140 HANDLE* handle) { | |
141 *handle = NULL; | |
142 | |
143 NtOpenProcessFunction NtOpenProcess = NULL; | |
144 ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess); | |
145 | |
146 if (client_info.process_id != process_id) | |
147 return STATUS_ACCESS_DENIED; | |
148 | |
149 OBJECT_ATTRIBUTES attributes = {0}; | |
150 attributes.Length = sizeof(attributes); | |
151 CLIENT_ID client_id = {0}; | |
152 client_id.UniqueProcess = reinterpret_cast<PVOID>( | |
153 static_cast<ULONG_PTR>(client_info.process_id)); | |
154 HANDLE local_handle = NULL; | |
155 NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes, | |
156 &client_id); | |
157 if (NT_SUCCESS(status)) { | |
158 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, | |
159 client_info.process, handle, 0, FALSE, | |
160 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { | |
161 return STATUS_ACCESS_DENIED; | |
162 } | |
163 } | |
164 | |
165 return status; | |
166 } | |
167 | |
168 NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info, | |
169 HANDLE process, | |
170 uint32_t desired_access, | |
171 HANDLE* handle) { | |
172 *handle = NULL; | |
173 NtOpenProcessTokenFunction NtOpenProcessToken = NULL; | |
174 ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken); | |
175 | |
176 if (CURRENT_PROCESS != process) | |
177 return STATUS_ACCESS_DENIED; | |
178 | |
179 HANDLE local_handle = NULL; | |
180 NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access, | |
181 &local_handle); | |
182 if (NT_SUCCESS(status)) { | |
183 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, | |
184 client_info.process, handle, 0, FALSE, | |
185 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { | |
186 return STATUS_ACCESS_DENIED; | |
187 } | |
188 } | |
189 return status; | |
190 } | |
191 | |
192 NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info, | |
193 HANDLE process, | |
194 uint32_t desired_access, | |
195 uint32_t attributes, | |
196 HANDLE* handle) { | |
197 *handle = NULL; | |
198 NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL; | |
199 ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx); | |
200 | |
201 if (CURRENT_PROCESS != process) | |
202 return STATUS_ACCESS_DENIED; | |
203 | |
204 HANDLE local_handle = NULL; | |
205 NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access, | |
206 attributes, &local_handle); | |
207 if (NT_SUCCESS(status)) { | |
208 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, | |
209 client_info.process, handle, 0, FALSE, | |
210 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { | |
211 return STATUS_ACCESS_DENIED; | |
212 } | |
213 } | |
214 return status; | |
215 } | |
216 | |
217 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result, | |
218 const ClientInfo& client_info, | |
219 const base::string16 &app_name, | |
220 const base::string16 &command_line, | |
221 PROCESS_INFORMATION* process_info) { | |
222 // The only action supported is ASK_BROKER which means create the process. | |
223 if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) { | |
224 return ERROR_ACCESS_DENIED; | |
225 } | |
226 | |
227 STARTUPINFO startup_info = {0}; | |
228 startup_info.cb = sizeof(startup_info); | |
229 scoped_ptr<wchar_t, base::FreeDeleter> | |
230 cmd_line(_wcsdup(command_line.c_str())); | |
231 | |
232 BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result); | |
233 if (!CreateProcessExWHelper(client_info.process, should_give_full_access, | |
234 app_name.c_str(), cmd_line.get(), NULL, NULL, | |
235 FALSE, 0, NULL, NULL, &startup_info, | |
236 process_info)) { | |
237 return ERROR_ACCESS_DENIED; | |
238 } | |
239 return ERROR_SUCCESS; | |
240 } | |
241 | |
242 DWORD ProcessPolicy::CreateThreadAction( | |
243 const ClientInfo& client_info, | |
244 const SIZE_T stack_size, | |
245 const LPTHREAD_START_ROUTINE start_address, | |
246 const LPVOID parameter, | |
247 const DWORD creation_flags, | |
248 LPDWORD thread_id, | |
249 HANDLE* handle) { | |
250 HANDLE local_handle = | |
251 ::CreateRemoteThread(client_info.process, nullptr, stack_size, | |
252 start_address, parameter, creation_flags, thread_id); | |
253 if (!local_handle) { | |
254 return ::GetLastError(); | |
255 } | |
256 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, | |
257 client_info.process, handle, 0, FALSE, | |
258 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { | |
259 return ERROR_ACCESS_DENIED; | |
260 } | |
261 return ERROR_SUCCESS; | |
262 } | |
263 | |
264 } // namespace sandbox | |
OLD | NEW |