Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: sandbox/src/restricted_token_utils.cc

Issue 10689170: Move the Windows sandbox to sandbox/win (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase on top of tree (properly this time) Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sandbox/src/restricted_token_utils.h ('k') | sandbox/src/sandbox.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 <aclapi.h>
6 #include <sddl.h>
7 #include <vector>
8
9 #include "sandbox/src/restricted_token_utils.h"
10
11 #include "base/logging.h"
12 #include "base/win/scoped_handle.h"
13 #include "base/win/scoped_process_information.h"
14 #include "base/win/windows_version.h"
15 #include "sandbox/src/job.h"
16 #include "sandbox/src/restricted_token.h"
17 #include "sandbox/src/security_level.h"
18 #include "sandbox/src/sid.h"
19
20 namespace sandbox {
21
22 DWORD CreateRestrictedToken(HANDLE *token_handle,
23 TokenLevel security_level,
24 IntegrityLevel integrity_level,
25 TokenType token_type) {
26 if (!token_handle)
27 return ERROR_BAD_ARGUMENTS;
28
29 RestrictedToken restricted_token;
30 restricted_token.Init(NULL); // Initialized with the current process token
31
32 std::vector<std::wstring> privilege_exceptions;
33 std::vector<Sid> sid_exceptions;
34
35 bool deny_sids = true;
36 bool remove_privileges = true;
37
38 switch (security_level) {
39 case USER_UNPROTECTED: {
40 deny_sids = false;
41 remove_privileges = false;
42 break;
43 }
44 case USER_RESTRICTED_SAME_ACCESS: {
45 deny_sids = false;
46 remove_privileges = false;
47
48 unsigned err_code = restricted_token.AddRestrictingSidAllSids();
49 if (ERROR_SUCCESS != err_code)
50 return err_code;
51
52 break;
53 }
54 case USER_NON_ADMIN: {
55 sid_exceptions.push_back(WinBuiltinUsersSid);
56 sid_exceptions.push_back(WinWorldSid);
57 sid_exceptions.push_back(WinInteractiveSid);
58 sid_exceptions.push_back(WinAuthenticatedUserSid);
59 privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
60 break;
61 }
62 case USER_INTERACTIVE: {
63 sid_exceptions.push_back(WinBuiltinUsersSid);
64 sid_exceptions.push_back(WinWorldSid);
65 sid_exceptions.push_back(WinInteractiveSid);
66 sid_exceptions.push_back(WinAuthenticatedUserSid);
67 privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
68 restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
69 restricted_token.AddRestrictingSid(WinWorldSid);
70 restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
71 restricted_token.AddRestrictingSidCurrentUser();
72 restricted_token.AddRestrictingSidLogonSession();
73 break;
74 }
75 case USER_LIMITED: {
76 sid_exceptions.push_back(WinBuiltinUsersSid);
77 sid_exceptions.push_back(WinWorldSid);
78 sid_exceptions.push_back(WinInteractiveSid);
79 privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
80 restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
81 restricted_token.AddRestrictingSid(WinWorldSid);
82 restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
83
84 // This token has to be able to create objects in BNO.
85 // Unfortunately, on vista, it needs the current logon sid
86 // in the token to achieve this. You should also set the process to be
87 // low integrity level so it can't access object created by other
88 // processes.
89 if (base::win::GetVersion() >= base::win::VERSION_VISTA)
90 restricted_token.AddRestrictingSidLogonSession();
91 break;
92 }
93 case USER_RESTRICTED: {
94 privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
95 restricted_token.AddUserSidForDenyOnly();
96 restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
97 break;
98 }
99 case USER_LOCKDOWN: {
100 restricted_token.AddUserSidForDenyOnly();
101 restricted_token.AddRestrictingSid(WinNullSid);
102 break;
103 }
104 default: {
105 return ERROR_BAD_ARGUMENTS;
106 }
107 }
108
109 DWORD err_code = ERROR_SUCCESS;
110 if (deny_sids) {
111 err_code = restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
112 if (ERROR_SUCCESS != err_code)
113 return err_code;
114 }
115
116 if (remove_privileges) {
117 err_code = restricted_token.DeleteAllPrivileges(&privilege_exceptions);
118 if (ERROR_SUCCESS != err_code)
119 return err_code;
120 }
121
122 restricted_token.SetIntegrityLevel(integrity_level);
123
124 switch (token_type) {
125 case PRIMARY: {
126 err_code = restricted_token.GetRestrictedTokenHandle(token_handle);
127 break;
128 }
129 case IMPERSONATION: {
130 err_code = restricted_token.GetRestrictedTokenHandleForImpersonation(
131 token_handle);
132 break;
133 }
134 default: {
135 err_code = ERROR_BAD_ARGUMENTS;
136 break;
137 }
138 }
139
140 return err_code;
141 }
142
143 DWORD StartRestrictedProcessInJob(wchar_t *command_line,
144 TokenLevel primary_level,
145 TokenLevel impersonation_level,
146 JobLevel job_level,
147 HANDLE *const job_handle_ret) {
148 Job job;
149 DWORD err_code = job.Init(job_level, NULL, 0);
150 if (ERROR_SUCCESS != err_code)
151 return err_code;
152
153 if (JOB_UNPROTECTED != job_level) {
154 // Share the Desktop handle to be able to use MessageBox() in the sandboxed
155 // application.
156 err_code = job.UserHandleGrantAccess(GetDesktopWindow());
157 if (ERROR_SUCCESS != err_code)
158 return err_code;
159 }
160
161 // Create the primary (restricted) token for the process
162 HANDLE primary_token_handle = NULL;
163 err_code = CreateRestrictedToken(&primary_token_handle,
164 primary_level,
165 INTEGRITY_LEVEL_LAST,
166 PRIMARY);
167 if (ERROR_SUCCESS != err_code) {
168 return err_code;
169 }
170 base::win::ScopedHandle primary_token(primary_token_handle);
171
172 // Create the impersonation token (restricted) to be able to start the
173 // process.
174 HANDLE impersonation_token_handle;
175 err_code = CreateRestrictedToken(&impersonation_token_handle,
176 impersonation_level,
177 INTEGRITY_LEVEL_LAST,
178 IMPERSONATION);
179 if (ERROR_SUCCESS != err_code) {
180 return err_code;
181 }
182 base::win::ScopedHandle impersonation_token(impersonation_token_handle);
183
184 // Start the process
185 STARTUPINFO startup_info = {0};
186 base::win::ScopedProcessInformation process_info;
187 DWORD flags = CREATE_SUSPENDED;
188
189 if (base::win::GetVersion() < base::win::VERSION_WIN8) {
190 // Windows 8 implements nested jobs, but for older systems we need to
191 // break out of any job we're in to enforce our restrictions.
192 flags |= CREATE_BREAKAWAY_FROM_JOB;
193 }
194
195 if (!::CreateProcessAsUser(primary_token.Get(),
196 NULL, // No application name.
197 command_line,
198 NULL, // No security attribute.
199 NULL, // No thread attribute.
200 FALSE, // Do not inherit handles.
201 flags,
202 NULL, // Use the environment of the caller.
203 NULL, // Use current directory of the caller.
204 &startup_info,
205 process_info.Receive())) {
206 return ::GetLastError();
207 }
208
209 // Change the token of the main thread of the new process for the
210 // impersonation token with more rights.
211 {
212 HANDLE temp_thread = process_info.thread_handle();
213 if (!::SetThreadToken(&temp_thread, impersonation_token.Get())) {
214 ::TerminateProcess(process_info.process_handle(),
215 0); // exit code
216 return ::GetLastError();
217 }
218 }
219
220 err_code = job.AssignProcessToJob(process_info.process_handle());
221 if (ERROR_SUCCESS != err_code) {
222 ::TerminateProcess(process_info.process_handle(),
223 0); // exit code
224 return ::GetLastError();
225 }
226
227 // Start the application
228 ::ResumeThread(process_info.thread_handle());
229
230 (*job_handle_ret) = job.Detach();
231
232 return ERROR_SUCCESS;
233 }
234
235 DWORD SetObjectIntegrityLabel(HANDLE handle, SE_OBJECT_TYPE type,
236 const wchar_t* ace_access,
237 const wchar_t* integrity_level_sid) {
238 // Build the SDDL string for the label.
239 std::wstring sddl = L"S:("; // SDDL for a SACL.
240 sddl += SDDL_MANDATORY_LABEL; // Ace Type is "Mandatory Label".
241 sddl += L";;"; // No Ace Flags.
242 sddl += ace_access; // Add the ACE access.
243 sddl += L";;;"; // No ObjectType and Inherited Object Type.
244 sddl += integrity_level_sid; // Trustee Sid.
245 sddl += L")";
246
247 DWORD error = ERROR_SUCCESS;
248 PSECURITY_DESCRIPTOR sec_desc = NULL;
249
250 PACL sacl = NULL;
251 BOOL sacl_present = FALSE;
252 BOOL sacl_defaulted = FALSE;
253
254 if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl.c_str(),
255 SDDL_REVISION,
256 &sec_desc, NULL)) {
257 if (::GetSecurityDescriptorSacl(sec_desc, &sacl_present, &sacl,
258 &sacl_defaulted)) {
259 error = ::SetSecurityInfo(handle, type,
260 LABEL_SECURITY_INFORMATION, NULL, NULL, NULL,
261 sacl);
262 } else {
263 error = ::GetLastError();
264 }
265
266 ::LocalFree(sec_desc);
267 } else {
268 return::GetLastError();
269 }
270
271 return error;
272 }
273
274 const wchar_t* GetIntegrityLevelString(IntegrityLevel integrity_level) {
275 switch (integrity_level) {
276 case INTEGRITY_LEVEL_SYSTEM:
277 return L"S-1-16-16384";
278 case INTEGRITY_LEVEL_HIGH:
279 return L"S-1-16-12288";
280 case INTEGRITY_LEVEL_MEDIUM:
281 return L"S-1-16-8192";
282 case INTEGRITY_LEVEL_MEDIUM_LOW:
283 return L"S-1-16-6144";
284 case INTEGRITY_LEVEL_LOW:
285 return L"S-1-16-4096";
286 case INTEGRITY_LEVEL_BELOW_LOW:
287 return L"S-1-16-2048";
288 case INTEGRITY_LEVEL_UNTRUSTED:
289 return L"S-1-16-0";
290 case INTEGRITY_LEVEL_LAST:
291 return NULL;
292 }
293
294 NOTREACHED();
295 return NULL;
296 }
297 DWORD SetTokenIntegrityLevel(HANDLE token, IntegrityLevel integrity_level) {
298 if (base::win::GetVersion() < base::win::VERSION_VISTA)
299 return ERROR_SUCCESS;
300
301 const wchar_t* integrity_level_str = GetIntegrityLevelString(integrity_level);
302 if (!integrity_level_str) {
303 // No mandatory level specified, we don't change it.
304 return ERROR_SUCCESS;
305 }
306
307 PSID integrity_sid = NULL;
308 if (!::ConvertStringSidToSid(integrity_level_str, &integrity_sid))
309 return ::GetLastError();
310
311 TOKEN_MANDATORY_LABEL label = {0};
312 label.Label.Attributes = SE_GROUP_INTEGRITY;
313 label.Label.Sid = integrity_sid;
314
315 DWORD size = sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(integrity_sid);
316 BOOL result = ::SetTokenInformation(token, TokenIntegrityLevel, &label,
317 size);
318 ::LocalFree(integrity_sid);
319
320 return result ? ERROR_SUCCESS : ::GetLastError();
321 }
322
323 DWORD SetProcessIntegrityLevel(IntegrityLevel integrity_level) {
324 if (base::win::GetVersion() < base::win::VERSION_VISTA)
325 return ERROR_SUCCESS;
326
327 // We don't check for an invalid level here because we'll just let it
328 // fail on the SetTokenIntegrityLevel call later on.
329 if (integrity_level == INTEGRITY_LEVEL_LAST) {
330 // No mandatory level specified, we don't change it.
331 return ERROR_SUCCESS;
332 }
333
334 HANDLE token_handle;
335 if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT,
336 &token_handle))
337 return ::GetLastError();
338
339 base::win::ScopedHandle token(token_handle);
340
341 return SetTokenIntegrityLevel(token.Get(), integrity_level);
342 }
343
344 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/src/restricted_token_utils.h ('k') | sandbox/src/sandbox.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698