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/src/process_thread_policy.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "sandbox/src/ipc_tags.h" | |
11 #include "sandbox/src/nt_internals.h" | |
12 #include "sandbox/src/policy_engine_opcodes.h" | |
13 #include "sandbox/src/policy_params.h" | |
14 #include "sandbox/src/sandbox_types.h" | |
15 #include "sandbox/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 | |
OLD | NEW |