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().
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)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
GenerateRules(const wchar_t * name,TargetPolicy::Semantics semantics,LowLevelPolicy * policy)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
OpenThreadAction(const ClientInfo & client_info,uint32 desired_access,uint32 thread_id,HANDLE * handle)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
OpenProcessAction(const ClientInfo & client_info,uint32 desired_access,uint32 process_id,HANDLE * handle)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
OpenProcessTokenAction(const ClientInfo & client_info,HANDLE process,uint32 desired_access,HANDLE * handle)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
OpenProcessTokenExAction(const ClientInfo & client_info,HANDLE process,uint32 desired_access,uint32 attributes,HANDLE * handle)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
CreateProcessWAction(EvalResult eval_result,const ClientInfo & client_info,const base::string16 & app_name,const base::string16 & command_line,PROCESS_INFORMATION * process_info)218 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result,
219 const ClientInfo& client_info,
220 const base::string16 &app_name,
221 const base::string16 &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<wchar_t, base::FreeDeleter>
231 cmd_line(_wcsdup(command_line.c_str()));
232
233 BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result);
234 if (!CreateProcessExWHelper(client_info.process, should_give_full_access,
235 app_name.c_str(), cmd_line.get(), NULL, NULL,
236 FALSE, 0, NULL, NULL, &startup_info,
237 process_info)) {
238 return ERROR_ACCESS_DENIED;
239 }
240 return ERROR_SUCCESS;
241 }
242
243 } // namespace sandbox
244