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