• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "sandbox/win/src/restricted_token.h"
6 
7 #include <vector>
8 
9 #include "base/logging.h"
10 #include "sandbox/win/src/acl.h"
11 #include "sandbox/win/src/win_utils.h"
12 
13 
14 namespace sandbox {
15 
Init(const HANDLE effective_token)16 unsigned RestrictedToken::Init(const HANDLE effective_token) {
17   DCHECK(!init_);
18   if (init_)
19     return ERROR_ALREADY_INITIALIZED;
20 
21   if (effective_token) {
22     // We duplicate the handle to be able to use it even if the original handle
23     // is closed.
24     HANDLE effective_token_dup;
25     if (::DuplicateHandle(::GetCurrentProcess(),
26                           effective_token,
27                           ::GetCurrentProcess(),
28                           &effective_token_dup,
29                           0,
30                           FALSE,
31                           DUPLICATE_SAME_ACCESS)) {
32       effective_token_ = effective_token_dup;
33     } else {
34       return ::GetLastError();
35     }
36   } else {
37     if (!::OpenProcessToken(::GetCurrentProcess(),
38                             TOKEN_ALL_ACCESS,
39                             &effective_token_))
40       return ::GetLastError();
41   }
42 
43   init_ = true;
44   return ERROR_SUCCESS;
45 }
46 
GetRestrictedTokenHandle(HANDLE * token_handle) const47 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
48   DCHECK(init_);
49   if (!init_)
50     return ERROR_NO_TOKEN;
51 
52   size_t deny_size = sids_for_deny_only_.size();
53   size_t restrict_size = sids_to_restrict_.size();
54   size_t privileges_size = privileges_to_disable_.size();
55 
56   SID_AND_ATTRIBUTES *deny_only_array = NULL;
57   if (deny_size) {
58     deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
59 
60     for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
61       deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
62       deny_only_array[i].Sid =
63           const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
64     }
65   }
66 
67   SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
68   if (restrict_size) {
69     sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
70 
71     for (unsigned int i = 0; i < restrict_size; ++i) {
72       sids_to_restrict_array[i].Attributes = 0;
73       sids_to_restrict_array[i].Sid =
74           const_cast<SID*>(sids_to_restrict_[i].GetPSID());
75     }
76   }
77 
78   LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
79   if (privileges_size) {
80     privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
81 
82     for (unsigned int i = 0; i < privileges_size; ++i) {
83       privileges_to_disable_array[i].Attributes = 0;
84       privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
85     }
86   }
87 
88   BOOL result = TRUE;
89   HANDLE new_token = NULL;
90   // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
91   // if a token has ben restricted given the limiations of IsTokenRestricted()
92   // but it appears that in Windows 7 it hints the AppLocker subsystem to
93   // leave us alone.
94   if (deny_size || restrict_size || privileges_size) {
95     result = ::CreateRestrictedToken(effective_token_,
96                                      SANDBOX_INERT,
97                                      static_cast<DWORD>(deny_size),
98                                      deny_only_array,
99                                      static_cast<DWORD>(privileges_size),
100                                      privileges_to_disable_array,
101                                      static_cast<DWORD>(restrict_size),
102                                      sids_to_restrict_array,
103                                      &new_token);
104   } else {
105     // Duplicate the token even if it's not modified at this point
106     // because any subsequent changes to this token would also affect the
107     // current process.
108     result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL,
109                                 SecurityIdentification, TokenPrimary,
110                                 &new_token);
111   }
112 
113   if (deny_only_array)
114     delete[] deny_only_array;
115 
116   if (sids_to_restrict_array)
117     delete[] sids_to_restrict_array;
118 
119   if (privileges_to_disable_array)
120     delete[] privileges_to_disable_array;
121 
122   if (!result)
123     return ::GetLastError();
124 
125   // Modify the default dacl on the token to contain Restricted and the user.
126   if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
127     return ::GetLastError();
128 
129   if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
130     return ::GetLastError();
131 
132   DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
133   if (ERROR_SUCCESS != error)
134     return error;
135 
136   BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
137                                   new_token,
138                                   ::GetCurrentProcess(),
139                                   token_handle,
140                                   TOKEN_ALL_ACCESS,
141                                   FALSE,  // Don't inherit.
142                                   0);
143 
144   if (new_token != effective_token_)
145     ::CloseHandle(new_token);
146 
147   if (!status)
148     return ::GetLastError();
149 
150   return ERROR_SUCCESS;
151 }
152 
GetRestrictedTokenHandleForImpersonation(HANDLE * token_handle) const153 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
154     HANDLE *token_handle) const {
155   DCHECK(init_);
156   if (!init_)
157     return ERROR_NO_TOKEN;
158 
159   HANDLE restricted_token_handle;
160   unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
161   if (ERROR_SUCCESS != err_code)
162     return err_code;
163 
164   HANDLE impersonation_token;
165   if (!::DuplicateToken(restricted_token_handle,
166                         SecurityImpersonation,
167                         &impersonation_token)) {
168     ::CloseHandle(restricted_token_handle);
169     return ::GetLastError();
170   }
171 
172   ::CloseHandle(restricted_token_handle);
173 
174   BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
175                                   impersonation_token,
176                                   ::GetCurrentProcess(),
177                                   token_handle,
178                                   TOKEN_ALL_ACCESS,
179                                   FALSE,  // Don't inherit.
180                                   0);
181 
182   ::CloseHandle(impersonation_token);
183 
184   if (!status)
185     return ::GetLastError();
186 
187   return ERROR_SUCCESS;
188 }
189 
AddAllSidsForDenyOnly(std::vector<Sid> * exceptions)190 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
191   DCHECK(init_);
192   if (!init_)
193     return ERROR_NO_TOKEN;
194 
195   TOKEN_GROUPS *token_groups = NULL;
196   DWORD size = 0;
197 
198   BOOL result = ::GetTokenInformation(effective_token_,
199                                       TokenGroups,
200                                       NULL,  // No buffer.
201                                       0,  // Size is 0.
202                                       &size);
203   if (!size)
204     return ::GetLastError();
205 
206   token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
207   result = ::GetTokenInformation(effective_token_,
208                                  TokenGroups,
209                                  token_groups,
210                                  size,
211                                  &size);
212   if (!result) {
213     delete[] reinterpret_cast<BYTE*>(token_groups);
214     return ::GetLastError();
215   }
216 
217   // Build the list of the deny only group SIDs
218   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
219     if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
220         (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
221       bool should_ignore = false;
222       if (exceptions) {
223         for (unsigned int j = 0; j < exceptions->size(); ++j) {
224           if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
225                           token_groups->Groups[i].Sid)) {
226             should_ignore = true;
227             break;
228           }
229         }
230       }
231       if (!should_ignore) {
232         sids_for_deny_only_.push_back(
233             reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
234       }
235     }
236   }
237 
238   delete[] reinterpret_cast<BYTE*>(token_groups);
239 
240   return ERROR_SUCCESS;
241 }
242 
AddSidForDenyOnly(const Sid & sid)243 unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
244   DCHECK(init_);
245   if (!init_)
246     return ERROR_NO_TOKEN;
247 
248   sids_for_deny_only_.push_back(sid);
249   return ERROR_SUCCESS;
250 }
251 
AddUserSidForDenyOnly()252 unsigned RestrictedToken::AddUserSidForDenyOnly() {
253   DCHECK(init_);
254   if (!init_)
255     return ERROR_NO_TOKEN;
256 
257   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
258   TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
259 
260   BOOL result = ::GetTokenInformation(effective_token_,
261                                       TokenUser,
262                                       token_user,
263                                       size,
264                                       &size);
265 
266   if (!result) {
267     delete[] reinterpret_cast<BYTE*>(token_user);
268     return ::GetLastError();
269   }
270 
271   Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
272   sids_for_deny_only_.push_back(user);
273 
274   delete[] reinterpret_cast<BYTE*>(token_user);
275 
276   return ERROR_SUCCESS;
277 }
278 
DeleteAllPrivileges(const std::vector<base::string16> * exceptions)279 unsigned RestrictedToken::DeleteAllPrivileges(
280     const std::vector<base::string16> *exceptions) {
281   DCHECK(init_);
282   if (!init_)
283     return ERROR_NO_TOKEN;
284 
285   // Get the list of privileges in the token
286   TOKEN_PRIVILEGES *token_privileges = NULL;
287   DWORD size = 0;
288 
289   BOOL result = ::GetTokenInformation(effective_token_,
290                                       TokenPrivileges,
291                                       NULL,  // No buffer.
292                                       0,  // Size is 0.
293                                       &size);
294   if (!size)
295     return ::GetLastError();
296 
297   token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]);
298   result = ::GetTokenInformation(effective_token_,
299                                  TokenPrivileges,
300                                  token_privileges,
301                                  size,
302                                  &size);
303   if (!result) {
304     delete[] reinterpret_cast<BYTE *>(token_privileges);
305     return ::GetLastError();
306   }
307 
308 
309   // Build the list of privileges to disable
310   for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
311     bool should_ignore = false;
312     if (exceptions) {
313       for (unsigned int j = 0; j < exceptions->size(); ++j) {
314         LUID luid = {0};
315         ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
316         if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
317             token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
318           should_ignore = true;
319           break;
320         }
321       }
322     }
323     if (!should_ignore) {
324         privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
325     }
326   }
327 
328   delete[] reinterpret_cast<BYTE *>(token_privileges);
329 
330   return ERROR_SUCCESS;
331 }
332 
DeletePrivilege(const wchar_t * privilege)333 unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
334   DCHECK(init_);
335   if (!init_)
336     return ERROR_NO_TOKEN;
337 
338   LUID luid = {0};
339   if (LookupPrivilegeValue(NULL, privilege, &luid))
340     privileges_to_disable_.push_back(luid);
341   else
342     return ::GetLastError();
343 
344   return ERROR_SUCCESS;
345 }
346 
AddRestrictingSid(const Sid & sid)347 unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
348   DCHECK(init_);
349   if (!init_)
350     return ERROR_NO_TOKEN;
351 
352   sids_to_restrict_.push_back(sid);  // No attributes
353   return ERROR_SUCCESS;
354 }
355 
AddRestrictingSidLogonSession()356 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
357   DCHECK(init_);
358   if (!init_)
359     return ERROR_NO_TOKEN;
360 
361   TOKEN_GROUPS *token_groups = NULL;
362   DWORD size = 0;
363 
364   BOOL result = ::GetTokenInformation(effective_token_,
365                                       TokenGroups,
366                                       NULL,  // No buffer.
367                                       0,  // Size is 0.
368                                       &size);
369   if (!size)
370     return ::GetLastError();
371 
372   token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
373   result = ::GetTokenInformation(effective_token_,
374                                  TokenGroups,
375                                  token_groups,
376                                  size,
377                                  &size);
378   if (!result) {
379     delete[] reinterpret_cast<BYTE*>(token_groups);
380     return ::GetLastError();
381   }
382 
383   SID *logon_sid = NULL;
384   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
385     if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
386         logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
387         break;
388     }
389   }
390 
391   if (logon_sid)
392     sids_to_restrict_.push_back(logon_sid);
393 
394   delete[] reinterpret_cast<BYTE*>(token_groups);
395 
396   return ERROR_SUCCESS;
397 }
398 
AddRestrictingSidCurrentUser()399 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
400   DCHECK(init_);
401   if (!init_)
402     return ERROR_NO_TOKEN;
403 
404   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
405   TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
406 
407   BOOL result = ::GetTokenInformation(effective_token_,
408                                       TokenUser,
409                                       token_user,
410                                       size,
411                                       &size);
412 
413   if (!result) {
414     delete[] reinterpret_cast<BYTE*>(token_user);
415     return ::GetLastError();
416   }
417 
418   Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
419   sids_to_restrict_.push_back(user);
420 
421   delete[] reinterpret_cast<BYTE*>(token_user);
422 
423   return ERROR_SUCCESS;
424 }
425 
AddRestrictingSidAllSids()426 unsigned RestrictedToken::AddRestrictingSidAllSids() {
427   DCHECK(init_);
428   if (!init_)
429     return ERROR_NO_TOKEN;
430 
431   // Add the current user to the list.
432   unsigned error = AddRestrictingSidCurrentUser();
433   if (ERROR_SUCCESS != error)
434     return error;
435 
436   TOKEN_GROUPS *token_groups = NULL;
437   DWORD size = 0;
438 
439   // Get the buffer size required.
440   BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
441                                       &size);
442   if (!size)
443     return ::GetLastError();
444 
445   token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
446   result = ::GetTokenInformation(effective_token_,
447                                  TokenGroups,
448                                  token_groups,
449                                  size,
450                                  &size);
451   if (!result) {
452     delete[] reinterpret_cast<BYTE*>(token_groups);
453     return ::GetLastError();
454   }
455 
456   // Build the list of restricting sids from all groups.
457   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
458     if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
459       AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
460   }
461 
462   delete[] reinterpret_cast<BYTE*>(token_groups);
463 
464   return ERROR_SUCCESS;
465 }
466 
SetIntegrityLevel(IntegrityLevel integrity_level)467 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
468   integrity_level_ = integrity_level;
469   return ERROR_SUCCESS;
470 }
471 
472 }  // namespace sandbox
473