|
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 <string> |
|
8 |
|
9 #include "base/memory/scoped_ptr.h" |
|
10 #include "sandbox/win/src/ipc_tags.h" |
|
11 #include "sandbox/win/src/nt_internals.h" |
|
12 #include "sandbox/win/src/policy_engine_opcodes.h" |
|
13 #include "sandbox/win/src/policy_params.h" |
|
14 #include "sandbox/win/src/sandbox_types.h" |
|
15 #include "sandbox/win/src/win_utils.h" |
|
16 |
|
17 namespace { |
|
18 |
|
19 // These are the only safe rights that can be given to a sandboxed |
|
20 // process for the process created by the broker. All others are potential |
|
21 // vectors of privilege elevation. |
|
22 const DWORD kProcessRights = SYNCHRONIZE | |
|
23 PROCESS_QUERY_INFORMATION | |
|
24 PROCESS_QUERY_LIMITED_INFORMATION | |
|
25 PROCESS_TERMINATE | |
|
26 PROCESS_SUSPEND_RESUME; |
|
27 |
|
28 const DWORD kThreadRights = SYNCHRONIZE | |
|
29 THREAD_TERMINATE | |
|
30 THREAD_SUSPEND_RESUME | |
|
31 THREAD_QUERY_INFORMATION | |
|
32 THREAD_QUERY_LIMITED_INFORMATION | |
|
33 THREAD_SET_LIMITED_INFORMATION; |
|
34 |
|
35 // Creates a child process and duplicates the handles to 'target_process'. The |
|
36 // remaining parameters are the same as CreateProcess(). |
|
37 BOOL CreateProcessExWHelper(HANDLE target_process, BOOL give_full_access, |
|
38 LPCWSTR lpApplicationName, LPWSTR lpCommandLine, |
|
39 LPSECURITY_ATTRIBUTES lpProcessAttributes, |
|
40 LPSECURITY_ATTRIBUTES lpThreadAttributes, |
|
41 BOOL bInheritHandles, DWORD dwCreationFlags, |
|
42 LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, |
|
43 LPSTARTUPINFOW lpStartupInfo, |
|
44 LPPROCESS_INFORMATION lpProcessInformation) { |
|
45 if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, |
|
46 lpThreadAttributes, bInheritHandles, dwCreationFlags, |
|
47 lpEnvironment, lpCurrentDirectory, lpStartupInfo, |
|
48 lpProcessInformation)) { |
|
49 return FALSE; |
|
50 } |
|
51 |
|
52 DWORD process_access = kProcessRights; |
|
53 DWORD thread_access = kThreadRights; |
|
54 if (give_full_access) { |
|
55 process_access = PROCESS_ALL_ACCESS; |
|
56 thread_access = THREAD_ALL_ACCESS; |
|
57 } |
|
58 if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess, |
|
59 target_process, &lpProcessInformation->hProcess, |
|
60 process_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { |
|
61 ::CloseHandle(lpProcessInformation->hThread); |
|
62 return FALSE; |
|
63 } |
|
64 if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread, |
|
65 target_process, &lpProcessInformation->hThread, |
|
66 thread_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { |
|
67 return FALSE; |
|
68 } |
|
69 return TRUE; |
|
70 } |
|
71 |
|
72 } |
|
73 |
|
74 namespace sandbox { |
|
75 |
|
76 bool ProcessPolicy::GenerateRules(const wchar_t* name, |
|
77 TargetPolicy::Semantics semantics, |
|
78 LowLevelPolicy* policy) { |
|
79 scoped_ptr<PolicyRule> process; |
|
80 switch (semantics) { |
|
81 case TargetPolicy::PROCESS_MIN_EXEC: { |
|
82 process.reset(new PolicyRule(GIVE_READONLY)); |
|
83 break; |
|
84 }; |
|
85 case TargetPolicy::PROCESS_ALL_EXEC: { |
|
86 process.reset(new PolicyRule(GIVE_ALLACCESS)); |
|
87 break; |
|
88 }; |
|
89 default: { |
|
90 return false; |
|
91 }; |
|
92 } |
|
93 |
|
94 if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) { |
|
95 return false; |
|
96 } |
|
97 if (!policy->AddRule(IPC_CREATEPROCESSW_TAG, process.get())) { |
|
98 return false; |
|
99 } |
|
100 return true; |
|
101 } |
|
102 |
|
103 NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info, |
|
104 uint32 desired_access, |
|
105 uint32 thread_id, |
|
106 HANDLE* handle) { |
|
107 *handle = NULL; |
|
108 |
|
109 NtOpenThreadFunction NtOpenThread = NULL; |
|
110 ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread); |
|
111 |
|
112 OBJECT_ATTRIBUTES attributes = {0}; |
|
113 attributes.Length = sizeof(attributes); |
|
114 CLIENT_ID client_id = {0}; |
|
115 client_id.UniqueProcess = reinterpret_cast<PVOID>( |
|
116 static_cast<ULONG_PTR>(client_info.process_id)); |
|
117 client_id.UniqueThread = |
|
118 reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id)); |
|
119 |
|
120 HANDLE local_handle; |
|
121 NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes, |
|
122 &client_id); |
|
123 if (NT_SUCCESS(status)) { |
|
124 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, |
|
125 client_info.process, handle, 0, FALSE, |
|
126 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { |
|
127 ::CloseHandle(local_handle); |
|
128 return STATUS_ACCESS_DENIED; |
|
129 } |
|
130 } |
|
131 |
|
132 return status; |
|
133 } |
|
134 |
|
135 NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info, |
|
136 uint32 desired_access, |
|
137 uint32 process_id, |
|
138 HANDLE* handle) { |
|
139 *handle = NULL; |
|
140 |
|
141 NtOpenProcessFunction NtOpenProcess = NULL; |
|
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 = reinterpret_cast<PVOID>( |
|
151 static_cast<ULONG_PTR>(client_info.process_id)); |
|
152 HANDLE local_handle; |
|
153 NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes, |
|
154 &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 ::CloseHandle(local_handle); |
|
160 return STATUS_ACCESS_DENIED; |
|
161 } |
|
162 } |
|
163 |
|
164 return status; |
|
165 } |
|
166 |
|
167 NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info, |
|
168 HANDLE process, |
|
169 uint32 desired_access, |
|
170 HANDLE* handle) { |
|
171 *handle = NULL; |
|
172 NtOpenProcessTokenFunction NtOpenProcessToken = NULL; |
|
173 ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken); |
|
174 |
|
175 if (CURRENT_PROCESS != process) |
|
176 return STATUS_ACCESS_DENIED; |
|
177 |
|
178 HANDLE local_handle; |
|
179 NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access, |
|
180 &local_handle); |
|
181 if (NT_SUCCESS(status)) { |
|
182 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, |
|
183 client_info.process, handle, 0, FALSE, |
|
184 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { |
|
185 ::CloseHandle(local_handle); |
|
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 desired_access, |
|
195 uint32 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; |
|
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 ::CloseHandle(local_handle); |
|
212 return STATUS_ACCESS_DENIED; |
|
213 } |
|
214 } |
|
215 return status; |
|
216 } |
|
217 |
|
218 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result, |
|
219 const ClientInfo& client_info, |
|
220 const std::wstring &app_name, |
|
221 const std::wstring &command_line, |
|
222 PROCESS_INFORMATION* process_info) { |
|
223 // The only action supported is ASK_BROKER which means create the process. |
|
224 if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) { |
|
225 return ERROR_ACCESS_DENIED; |
|
226 } |
|
227 |
|
228 STARTUPINFO startup_info = {0}; |
|
229 startup_info.cb = sizeof(startup_info); |
|
230 scoped_ptr_malloc<wchar_t> 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 } // namespace sandbox |