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 // This file contains unit tests for the RestrictedToken.
6 
7 #include "sandbox/win/src/restricted_token.h"
8 
9 #include <vector>
10 
11 #include "base/win/atl.h"
12 #include "base/win/scoped_handle.h"
13 #include "base/win/windows_version.h"
14 #include "sandbox/win/src/acl.h"
15 #include "sandbox/win/src/security_capabilities.h"
16 #include "sandbox/win/src/sid.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace sandbox {
20 
21 namespace {
22 
TestDefaultDalc(bool restricted_required,bool additional_sid_required)23 void TestDefaultDalc(bool restricted_required, bool additional_sid_required) {
24   RestrictedToken token;
25   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
26   if (!restricted_required)
27     token.SetLockdownDefaultDacl();
28   ATL::CSid additional_sid = ATL::Sids::Guests();
29   ATL::CSid additional_sid2 = ATL::Sids::Batch();
30   if (additional_sid_required) {
31     token.AddDefaultDaclSid(Sid(additional_sid.GetPSID()), GRANT_ACCESS,
32                             READ_CONTROL);
33     token.AddDefaultDaclSid(Sid(additional_sid2.GetPSID()), DENY_ACCESS,
34                             GENERIC_ALL);
35   }
36 
37   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
38             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
39 
40   base::win::ScopedHandle handle;
41   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
42             token.GetRestrictedToken(&handle));
43 
44   ATL::CAccessToken restricted_token;
45   restricted_token.Attach(handle.Take());
46 
47   ATL::CDacl dacl;
48   ASSERT_TRUE(restricted_token.GetDefaultDacl(&dacl));
49 
50   ATL::CSid logon_sid;
51   ASSERT_TRUE(restricted_token.GetLogonSid(&logon_sid));
52 
53   bool restricted_found = false;
54   bool logon_sid_found = false;
55   bool additional_sid_found = false;
56   bool additional_sid2_found = false;
57 
58   unsigned int ace_count = dacl.GetAceCount();
59   for (unsigned int i = 0; i < ace_count; ++i) {
60     ATL::CSid sid;
61     ACCESS_MASK mask = 0;
62     BYTE ace_type = 0;
63     dacl.GetAclEntry(i, &sid, &mask, &ace_type);
64     if (sid == ATL::Sids::RestrictedCode() && mask == GENERIC_ALL) {
65       restricted_found = true;
66     } else if (sid == logon_sid) {
67       logon_sid_found = true;
68     } else if (sid == additional_sid && mask == READ_CONTROL &&
69                ace_type == ACCESS_ALLOWED_ACE_TYPE) {
70       additional_sid_found = true;
71     } else if (sid == additional_sid2 && mask == GENERIC_ALL &&
72                ace_type == ACCESS_DENIED_ACE_TYPE) {
73       additional_sid2_found = true;
74     }
75   }
76 
77   ASSERT_EQ(restricted_required, restricted_found);
78   ASSERT_EQ(additional_sid_required, additional_sid_found);
79   ASSERT_EQ(additional_sid_required, additional_sid2_found);
80   if (!restricted_required)
81     ASSERT_FALSE(logon_sid_found);
82 }
83 
GetVariableTokenInformation(HANDLE token,TOKEN_INFORMATION_CLASS information_class,std::vector<char> * information)84 bool GetVariableTokenInformation(HANDLE token,
85                                  TOKEN_INFORMATION_CLASS information_class,
86                                  std::vector<char>* information) {
87   DWORD return_length;
88   if (!::GetTokenInformation(token, information_class, nullptr, 0,
89                              &return_length)) {
90     if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
91       return false;
92     }
93   }
94 
95   information->resize(return_length);
96   return !!::GetTokenInformation(token, information_class, information->data(),
97                                  return_length, &return_length);
98 }
99 
GetVariableTokenInformation(const base::win::ScopedHandle & token,TOKEN_INFORMATION_CLASS information_class,std::vector<char> * information)100 bool GetVariableTokenInformation(const base::win::ScopedHandle& token,
101                                  TOKEN_INFORMATION_CLASS information_class,
102                                  std::vector<char>* information) {
103   return GetVariableTokenInformation(token.Get(), information_class,
104                                      information);
105 }
106 
CheckDaclForPackageSid(const base::win::ScopedHandle & token,PSECURITY_CAPABILITIES security_capabilities,bool package_sid_required)107 void CheckDaclForPackageSid(const base::win::ScopedHandle& token,
108                             PSECURITY_CAPABILITIES security_capabilities,
109                             bool package_sid_required) {
110   DWORD length_needed = 0;
111   ::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION, nullptr, 0,
112                             &length_needed);
113   ASSERT_EQ(::GetLastError(), DWORD{ERROR_INSUFFICIENT_BUFFER});
114 
115   std::vector<char> security_desc_buffer(length_needed);
116   SECURITY_DESCRIPTOR* security_desc =
117       reinterpret_cast<SECURITY_DESCRIPTOR*>(security_desc_buffer.data());
118 
119   ASSERT_TRUE(::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION,
120                                         security_desc, length_needed,
121                                         &length_needed));
122 
123   ATL::CSecurityDesc token_sd(*security_desc);
124   ATL::CDacl dacl;
125   ASSERT_TRUE(token_sd.GetDacl(&dacl));
126 
127   ATL::CSid package_sid(
128       static_cast<SID*>(security_capabilities->AppContainerSid));
129   ATL::CSid all_package_sid(
130       static_cast<SID*>(sandbox::Sid(::WinBuiltinAnyPackageSid).GetPSID()));
131 
132   unsigned int ace_count = dacl.GetAceCount();
133   for (unsigned int i = 0; i < ace_count; ++i) {
134     ATL::CSid sid;
135     ACCESS_MASK mask = 0;
136     BYTE type = 0;
137     dacl.GetAclEntry(i, &sid, &mask, &type);
138     if (mask != TOKEN_ALL_ACCESS || type != ACCESS_ALLOWED_ACE_TYPE)
139       continue;
140     if (sid == package_sid)
141       EXPECT_TRUE(package_sid_required);
142     else if (sid == all_package_sid)
143       EXPECT_FALSE(package_sid_required);
144   }
145 }
146 
CheckLowBoxToken(const base::win::ScopedHandle & token,TOKEN_TYPE token_type,PSECURITY_CAPABILITIES security_capabilities)147 void CheckLowBoxToken(const base::win::ScopedHandle& token,
148                       TOKEN_TYPE token_type,
149                       PSECURITY_CAPABILITIES security_capabilities) {
150   DWORD appcontainer;
151   DWORD return_length;
152   ASSERT_TRUE(::GetTokenInformation(token.Get(), ::TokenIsAppContainer,
153                                     &appcontainer, sizeof(appcontainer),
154                                     &return_length));
155   ASSERT_TRUE(appcontainer);
156   TOKEN_TYPE token_type_real;
157   ASSERT_TRUE(::GetTokenInformation(token.Get(), ::TokenType, &token_type_real,
158                                     sizeof(token_type_real), &return_length));
159   ASSERT_EQ(token_type_real, token_type);
160   if (token_type == ::TokenImpersonation) {
161     SECURITY_IMPERSONATION_LEVEL imp_level;
162     ASSERT_TRUE(::GetTokenInformation(token.Get(), ::TokenImpersonationLevel,
163                                       &imp_level, sizeof(imp_level),
164                                       &return_length));
165     ASSERT_EQ(imp_level, ::SecurityImpersonation);
166   }
167 
168   std::vector<char> package_sid_buf;
169   ASSERT_TRUE(GetVariableTokenInformation(token, ::TokenAppContainerSid,
170                                           &package_sid_buf));
171   PTOKEN_APPCONTAINER_INFORMATION package_sid =
172       reinterpret_cast<PTOKEN_APPCONTAINER_INFORMATION>(package_sid_buf.data());
173   EXPECT_TRUE(::EqualSid(security_capabilities->AppContainerSid,
174                          package_sid->TokenAppContainer));
175 
176   std::vector<char> capabilities_buf;
177   ASSERT_TRUE(GetVariableTokenInformation(token, ::TokenCapabilities,
178                                           &capabilities_buf));
179   PTOKEN_GROUPS capabilities =
180       reinterpret_cast<PTOKEN_GROUPS>(capabilities_buf.data());
181   ASSERT_EQ(capabilities->GroupCount, security_capabilities->CapabilityCount);
182   for (DWORD index = 0; index < capabilities->GroupCount; ++index) {
183     EXPECT_EQ(capabilities->Groups[index].Attributes,
184               security_capabilities->Capabilities[index].Attributes);
185     EXPECT_TRUE(::EqualSid(capabilities->Groups[index].Sid,
186                            security_capabilities->Capabilities[index].Sid));
187   }
188 
189   CheckDaclForPackageSid(token, security_capabilities, true);
190 }
191 
192 // Checks if a sid is in the restricting list of the restricted token.
193 // Asserts if it's not the case. If count is a positive number, the number of
194 // elements in the restricting sids list has to be equal.
CheckRestrictingSid(HANDLE restricted_token,ATL::CSid sid,int count)195 void CheckRestrictingSid(HANDLE restricted_token, ATL::CSid sid, int count) {
196   std::vector<char> memory;
197   ASSERT_TRUE(GetVariableTokenInformation(restricted_token,
198                                           ::TokenRestrictedSids, &memory));
199   PTOKEN_GROUPS groups = reinterpret_cast<PTOKEN_GROUPS>(memory.data());
200   ATL::CTokenGroups atl_groups(*groups);
201 
202   if (count >= 0)
203     ASSERT_EQ(static_cast<unsigned>(count), atl_groups.GetCount());
204 
205   ATL::CSid::CSidArray sids;
206   ATL::CAtlArray<DWORD> attributes;
207   atl_groups.GetSidsAndAttributes(&sids, &attributes);
208 
209   bool present = false;
210   for (unsigned int i = 0; i < sids.GetCount(); ++i) {
211     if (sids[i] == sid) {
212       present = true;
213       break;
214     }
215   }
216 
217   ASSERT_TRUE(present);
218 }
219 
CheckRestrictingSid(const ATL::CAccessToken & restricted_token,ATL::CSid sid,int count)220 void CheckRestrictingSid(const ATL::CAccessToken& restricted_token,
221                          ATL::CSid sid,
222                          int count) {
223   CheckRestrictingSid(restricted_token.GetHandle(), sid, count);
224 }
225 
226 }  // namespace
227 
228 // Tests the initializatioin with an invalid token handle.
TEST(RestrictedTokenTest,InvalidHandle)229 TEST(RestrictedTokenTest, InvalidHandle) {
230   RestrictedToken token;
231   ASSERT_EQ(static_cast<DWORD>(ERROR_INVALID_HANDLE),
232             token.Init(reinterpret_cast<HANDLE>(0x5555)));
233 }
234 
235 // Tests the initialization with nullptr as parameter.
TEST(RestrictedTokenTest,DefaultInit)236 TEST(RestrictedTokenTest, DefaultInit) {
237   // Get the current process token.
238   HANDLE token_handle = INVALID_HANDLE_VALUE;
239   ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
240                                  &token_handle));
241 
242   ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
243 
244   ATL::CAccessToken access_token;
245   access_token.Attach(token_handle);
246 
247   // Create the token using the current token.
248   RestrictedToken token_default;
249   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token_default.Init(nullptr));
250 
251   // Get the handle to the restricted token.
252 
253   base::win::ScopedHandle restricted_token_handle;
254   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
255             token_default.GetRestrictedToken(&restricted_token_handle));
256 
257   ATL::CAccessToken restricted_token;
258   restricted_token.Attach(restricted_token_handle.Take());
259 
260   ATL::CSid sid_user_restricted;
261   ATL::CSid sid_user_default;
262   ATL::CSid sid_owner_restricted;
263   ATL::CSid sid_owner_default;
264   ASSERT_TRUE(restricted_token.GetUser(&sid_user_restricted));
265   ASSERT_TRUE(access_token.GetUser(&sid_user_default));
266   ASSERT_TRUE(restricted_token.GetOwner(&sid_owner_restricted));
267   ASSERT_TRUE(access_token.GetOwner(&sid_owner_default));
268 
269   // Check if both token have the same owner and user.
270   ASSERT_EQ(sid_user_restricted, sid_user_default);
271   ASSERT_EQ(sid_owner_restricted, sid_owner_default);
272 }
273 
274 // Tests the initialization with a custom token as parameter.
TEST(RestrictedTokenTest,CustomInit)275 TEST(RestrictedTokenTest, CustomInit) {
276   // Get the current process token.
277   HANDLE token_handle = INVALID_HANDLE_VALUE;
278   ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
279                                  &token_handle));
280 
281   ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
282 
283   ATL::CAccessToken access_token;
284   access_token.Attach(token_handle);
285 
286   // Change the primary group.
287   access_token.SetPrimaryGroup(ATL::Sids::World());
288 
289   // Create the token using the current token.
290   RestrictedToken token;
291   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
292             token.Init(access_token.GetHandle()));
293 
294   // Get the handle to the restricted token.
295 
296   base::win::ScopedHandle restricted_token_handle;
297   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
298             token.GetRestrictedToken(&restricted_token_handle));
299 
300   ATL::CAccessToken restricted_token;
301   restricted_token.Attach(restricted_token_handle.Take());
302 
303   ATL::CSid sid_restricted;
304   ATL::CSid sid_default;
305   ASSERT_TRUE(restricted_token.GetPrimaryGroup(&sid_restricted));
306   ASSERT_TRUE(access_token.GetPrimaryGroup(&sid_default));
307 
308   // Check if both token have the same owner.
309   ASSERT_EQ(sid_restricted, sid_default);
310 }
311 
312 // Verifies that the token created by the object are valid.
TEST(RestrictedTokenTest,ResultToken)313 TEST(RestrictedTokenTest, ResultToken) {
314   RestrictedToken token;
315   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
316 
317   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
318             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
319 
320   base::win::ScopedHandle restricted_token;
321   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
322             token.GetRestrictedToken(&restricted_token));
323 
324   ASSERT_TRUE(::IsTokenRestricted(restricted_token.Get()));
325 
326   DWORD length = 0;
327   TOKEN_TYPE type;
328   ASSERT_TRUE(::GetTokenInformation(restricted_token.Get(), ::TokenType, &type,
329                                     sizeof(type), &length));
330 
331   ASSERT_EQ(type, TokenPrimary);
332 
333   base::win::ScopedHandle impersonation_token;
334   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
335             token.GetRestrictedTokenForImpersonation(&impersonation_token));
336 
337   ASSERT_TRUE(::IsTokenRestricted(impersonation_token.Get()));
338 
339   ASSERT_TRUE(::GetTokenInformation(impersonation_token.Get(), ::TokenType,
340                                     &type, sizeof(type), &length));
341 
342   ASSERT_EQ(type, TokenImpersonation);
343 }
344 
345 // Verifies that the token created has "Restricted" in its default dacl.
TEST(RestrictedTokenTest,DefaultDacl)346 TEST(RestrictedTokenTest, DefaultDacl) {
347   TestDefaultDalc(true, false);
348 }
349 
350 // Verifies that the token created does not have "Restricted" in its default
351 // dacl.
TEST(RestrictedTokenTest,DefaultDaclLockdown)352 TEST(RestrictedTokenTest, DefaultDaclLockdown) {
353   TestDefaultDalc(false, false);
354 }
355 
356 // Verifies that the token created has an additional SID in its default dacl.
TEST(RestrictedTokenTest,DefaultDaclWithAddition)357 TEST(RestrictedTokenTest, DefaultDaclWithAddition) {
358   TestDefaultDalc(true, true);
359 }
360 
361 // Verifies that the token created does not have "Restricted" in its default
362 // dacl and also has an additional SID.
TEST(RestrictedTokenTest,DefaultDaclLockdownWithAddition)363 TEST(RestrictedTokenTest, DefaultDaclLockdownWithAddition) {
364   TestDefaultDalc(false, true);
365 }
366 
367 // Tests the method "AddSidForDenyOnly".
TEST(RestrictedTokenTest,DenySid)368 TEST(RestrictedTokenTest, DenySid) {
369   RestrictedToken token;
370   base::win::ScopedHandle token_handle;
371 
372   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
373   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
374             token.AddSidForDenyOnly(Sid(WinWorldSid)));
375   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
376             token.GetRestrictedToken(&token_handle));
377 
378   ATL::CAccessToken restricted_token;
379   restricted_token.Attach(token_handle.Take());
380 
381   ATL::CTokenGroups groups;
382   ASSERT_TRUE(restricted_token.GetGroups(&groups));
383 
384   ATL::CSid::CSidArray sids;
385   ATL::CAtlArray<DWORD> attributes;
386   groups.GetSidsAndAttributes(&sids, &attributes);
387 
388   for (unsigned int i = 0; i < sids.GetCount(); i++) {
389     if (ATL::Sids::World() == sids[i]) {
390       ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
391                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
392     }
393   }
394 }
395 
396 // Tests the method "AddAllSidsForDenyOnly".
TEST(RestrictedTokenTest,DenySids)397 TEST(RestrictedTokenTest, DenySids) {
398   RestrictedToken token;
399   base::win::ScopedHandle token_handle;
400 
401   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
402   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
403             token.AddAllSidsForDenyOnly(nullptr));
404   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
405             token.GetRestrictedToken(&token_handle));
406 
407   ATL::CAccessToken restricted_token;
408   restricted_token.Attach(token_handle.Take());
409 
410   ATL::CTokenGroups groups;
411   ASSERT_TRUE(restricted_token.GetGroups(&groups));
412 
413   ATL::CSid::CSidArray sids;
414   ATL::CAtlArray<DWORD> attributes;
415   groups.GetSidsAndAttributes(&sids, &attributes);
416 
417   // Verify that all sids are really gone.
418   for (unsigned int i = 0; i < sids.GetCount(); i++) {
419     if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
420         (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
421       ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
422                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
423     }
424   }
425 }
426 
427 // Tests the method "AddAllSidsForDenyOnly" using an exception list.
TEST(RestrictedTokenTest,DenySidsException)428 TEST(RestrictedTokenTest, DenySidsException) {
429   RestrictedToken token;
430   base::win::ScopedHandle token_handle;
431 
432   std::vector<Sid> sids_exception;
433   sids_exception.push_back(Sid(WinWorldSid));
434 
435   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
436   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
437             token.AddAllSidsForDenyOnly(&sids_exception));
438   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
439             token.GetRestrictedToken(&token_handle));
440 
441   ATL::CAccessToken restricted_token;
442   restricted_token.Attach(token_handle.Take());
443 
444   ATL::CTokenGroups groups;
445   ASSERT_TRUE(restricted_token.GetGroups(&groups));
446 
447   ATL::CSid::CSidArray sids;
448   ATL::CAtlArray<DWORD> attributes;
449   groups.GetSidsAndAttributes(&sids, &attributes);
450 
451   // Verify that all sids are really gone.
452   for (unsigned int i = 0; i < sids.GetCount(); i++) {
453     if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
454         (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
455       if (ATL::Sids::World() == sids[i]) {
456         ASSERT_EQ(0u, attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
457       } else {
458         ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
459                   attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
460       }
461     }
462   }
463 }
464 
465 // Tests test method AddOwnerSidForDenyOnly.
TEST(RestrictedTokenTest,DenyOwnerSid)466 TEST(RestrictedTokenTest, DenyOwnerSid) {
467   RestrictedToken token;
468   base::win::ScopedHandle token_handle;
469 
470   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
471   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.AddUserSidForDenyOnly());
472   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
473             token.GetRestrictedToken(&token_handle));
474 
475   ATL::CAccessToken restricted_token;
476   restricted_token.Attach(token_handle.Take());
477 
478   ATL::CTokenGroups groups;
479   ASSERT_TRUE(restricted_token.GetGroups(&groups));
480 
481   ATL::CSid::CSidArray sids;
482   ATL::CAtlArray<DWORD> attributes;
483   groups.GetSidsAndAttributes(&sids, &attributes);
484 
485   ATL::CSid user_sid;
486   ASSERT_TRUE(restricted_token.GetUser(&user_sid));
487 
488   for (unsigned int i = 0; i < sids.GetCount(); ++i) {
489     if (user_sid == sids[i]) {
490       ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
491                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
492     }
493   }
494 }
495 
496 // Tests test method AddOwnerSidForDenyOnly with a custom effective token.
TEST(RestrictedTokenTest,DenyOwnerSidCustom)497 TEST(RestrictedTokenTest, DenyOwnerSidCustom) {
498   // Get the current process token.
499   HANDLE access_handle = INVALID_HANDLE_VALUE;
500   ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
501                                  &access_handle));
502 
503   ASSERT_NE(INVALID_HANDLE_VALUE, access_handle);
504 
505   ATL::CAccessToken access_token;
506   access_token.Attach(access_handle);
507 
508   RestrictedToken token;
509   base::win::ScopedHandle token_handle;
510   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
511             token.Init(access_token.GetHandle()));
512   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.AddUserSidForDenyOnly());
513   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
514             token.GetRestrictedToken(&token_handle));
515 
516   ATL::CAccessToken restricted_token;
517   restricted_token.Attach(token_handle.Take());
518 
519   ATL::CTokenGroups groups;
520   ASSERT_TRUE(restricted_token.GetGroups(&groups));
521 
522   ATL::CSid::CSidArray sids;
523   ATL::CAtlArray<DWORD> attributes;
524   groups.GetSidsAndAttributes(&sids, &attributes);
525 
526   ATL::CSid user_sid;
527   ASSERT_TRUE(restricted_token.GetUser(&user_sid));
528 
529   for (unsigned int i = 0; i < sids.GetCount(); ++i) {
530     if (user_sid == sids[i]) {
531       ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
532                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
533     }
534   }
535 }
536 
537 // Tests the method DeleteAllPrivileges.
TEST(RestrictedTokenTest,DeleteAllPrivileges)538 TEST(RestrictedTokenTest, DeleteAllPrivileges) {
539   RestrictedToken token;
540   base::win::ScopedHandle token_handle;
541 
542   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
543   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
544             token.DeleteAllPrivileges(nullptr));
545   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
546             token.GetRestrictedToken(&token_handle));
547 
548   ATL::CAccessToken restricted_token;
549   restricted_token.Attach(token_handle.Take());
550 
551   ATL::CTokenPrivileges privileges;
552   ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
553 
554   ASSERT_EQ(0u, privileges.GetCount());
555 }
556 
557 // Tests the method DeleteAllPrivileges with an exception list.
TEST(RestrictedTokenTest,DeleteAllPrivilegesException)558 TEST(RestrictedTokenTest, DeleteAllPrivilegesException) {
559   RestrictedToken token;
560   base::win::ScopedHandle token_handle;
561 
562   std::vector<std::wstring> exceptions;
563   exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
564 
565   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
566   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
567             token.DeleteAllPrivileges(&exceptions));
568   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
569             token.GetRestrictedToken(&token_handle));
570 
571   ATL::CAccessToken restricted_token;
572   restricted_token.Attach(token_handle.Take());
573 
574   ATL::CTokenPrivileges privileges;
575   ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
576 
577   ATL::CTokenPrivileges::CNames privilege_names;
578   ATL::CTokenPrivileges::CAttributes privilege_name_attributes;
579   privileges.GetNamesAndAttributes(&privilege_names,
580                                    &privilege_name_attributes);
581 
582   ASSERT_EQ(1u, privileges.GetCount());
583 
584   for (unsigned int i = 0; i < privileges.GetCount(); ++i) {
585     ASSERT_EQ(privilege_names[i], SE_CHANGE_NOTIFY_NAME);
586   }
587 }
588 
589 // Tests the method DeletePrivilege.
TEST(RestrictedTokenTest,DeletePrivilege)590 TEST(RestrictedTokenTest, DeletePrivilege) {
591   RestrictedToken token;
592   base::win::ScopedHandle token_handle;
593 
594   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
595   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
596             token.DeletePrivilege(SE_CHANGE_NOTIFY_NAME));
597   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
598             token.GetRestrictedToken(&token_handle));
599 
600   ATL::CAccessToken restricted_token;
601   restricted_token.Attach(token_handle.Take());
602 
603   ATL::CTokenPrivileges privileges;
604   ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
605 
606   ATL::CTokenPrivileges::CNames privilege_names;
607   ATL::CTokenPrivileges::CAttributes privilege_name_attributes;
608   privileges.GetNamesAndAttributes(&privilege_names,
609                                    &privilege_name_attributes);
610 
611   for (unsigned int i = 0; i < privileges.GetCount(); ++i) {
612     ASSERT_NE(privilege_names[i], SE_CHANGE_NOTIFY_NAME);
613   }
614 }
615 
616 // Tests the method AddRestrictingSid.
TEST(RestrictedTokenTest,AddRestrictingSid)617 TEST(RestrictedTokenTest, AddRestrictingSid) {
618   RestrictedToken token;
619   base::win::ScopedHandle token_handle;
620 
621   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
622   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
623             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
624   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
625             token.GetRestrictedToken(&token_handle));
626 
627   ATL::CAccessToken restricted_token;
628   restricted_token.Attach(token_handle.Take());
629 
630   CheckRestrictingSid(restricted_token, ATL::Sids::World(), 1);
631 }
632 
633 // Tests the method AddRestrictingSidCurrentUser.
TEST(RestrictedTokenTest,AddRestrictingSidCurrentUser)634 TEST(RestrictedTokenTest, AddRestrictingSidCurrentUser) {
635   RestrictedToken token;
636   base::win::ScopedHandle token_handle;
637 
638   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
639   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
640             token.AddRestrictingSidCurrentUser());
641   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
642             token.GetRestrictedToken(&token_handle));
643 
644   ATL::CAccessToken restricted_token;
645   restricted_token.Attach(token_handle.Take());
646   ATL::CSid user;
647   restricted_token.GetUser(&user);
648 
649   CheckRestrictingSid(restricted_token, user, 1);
650 }
651 
652 // Tests the method AddRestrictingSidCurrentUser with a custom effective token.
TEST(RestrictedTokenTest,AddRestrictingSidCurrentUserCustom)653 TEST(RestrictedTokenTest, AddRestrictingSidCurrentUserCustom) {
654   // Get the current process token.
655   HANDLE access_handle = INVALID_HANDLE_VALUE;
656   ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
657                                  &access_handle));
658 
659   ASSERT_NE(INVALID_HANDLE_VALUE, access_handle);
660 
661   ATL::CAccessToken access_token;
662   access_token.Attach(access_handle);
663 
664   RestrictedToken token;
665   base::win::ScopedHandle token_handle;
666   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
667             token.Init(access_token.GetHandle()));
668   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
669             token.AddRestrictingSidCurrentUser());
670   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
671             token.GetRestrictedToken(&token_handle));
672 
673   ATL::CAccessToken restricted_token;
674   restricted_token.Attach(token_handle.Take());
675   ATL::CSid user;
676   restricted_token.GetUser(&user);
677 
678   CheckRestrictingSid(restricted_token, user, 1);
679 }
680 
681 // Tests the method AddRestrictingSidLogonSession.
TEST(RestrictedTokenTest,AddRestrictingSidLogonSession)682 TEST(RestrictedTokenTest, AddRestrictingSidLogonSession) {
683   RestrictedToken token;
684   base::win::ScopedHandle token_handle;
685 
686   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
687   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
688             token.AddRestrictingSidLogonSession());
689   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
690             token.GetRestrictedToken(&token_handle));
691 
692   ATL::CAccessToken restricted_token;
693   restricted_token.Attach(token_handle.Take());
694   ATL::CSid session;
695   restricted_token.GetLogonSid(&session);
696 
697   CheckRestrictingSid(restricted_token, session, 1);
698 }
699 
700 // Tests adding a lot of restricting sids.
TEST(RestrictedTokenTest,AddMultipleRestrictingSids)701 TEST(RestrictedTokenTest, AddMultipleRestrictingSids) {
702   RestrictedToken token;
703   base::win::ScopedHandle token_handle;
704 
705   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
706   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
707             token.AddRestrictingSidCurrentUser());
708   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
709             token.AddRestrictingSidLogonSession());
710   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
711             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
712   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
713             token.GetRestrictedToken(&token_handle));
714 
715   ATL::CAccessToken restricted_token;
716   restricted_token.Attach(token_handle.Take());
717   ATL::CSid session;
718   restricted_token.GetLogonSid(&session);
719 
720   std::vector<char> memory;
721   ASSERT_TRUE(GetVariableTokenInformation(restricted_token.GetHandle(),
722                                           ::TokenRestrictedSids, &memory));
723   PTOKEN_GROUPS groups = reinterpret_cast<PTOKEN_GROUPS>(memory.data());
724   ATL::CTokenGroups atl_groups(*groups);
725   ASSERT_EQ(3u, atl_groups.GetCount());
726 }
727 
728 // Tests the method "AddRestrictingSidAllSids".
TEST(RestrictedTokenTest,AddAllSidToRestrictingSids)729 TEST(RestrictedTokenTest, AddAllSidToRestrictingSids) {
730   RestrictedToken token;
731   base::win::ScopedHandle token_handle;
732 
733   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
734   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
735             token.AddRestrictingSidAllSids());
736   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
737             token.GetRestrictedToken(&token_handle));
738 
739   ATL::CAccessToken restricted_token;
740   restricted_token.Attach(token_handle.Take());
741 
742   ATL::CTokenGroups groups;
743   ASSERT_TRUE(restricted_token.GetGroups(&groups));
744 
745   ATL::CSid::CSidArray sids;
746   ATL::CAtlArray<DWORD> attributes;
747   groups.GetSidsAndAttributes(&sids, &attributes);
748 
749   // Verify that all group sids are in the restricting sid list.
750   for (unsigned int i = 0; i < sids.GetCount(); i++) {
751     if ((attributes[i] & SE_GROUP_INTEGRITY) == 0) {
752       CheckRestrictingSid(restricted_token, sids[i], -1);
753     }
754   }
755 
756   // Verify that the user is in the restricting sid list.
757   ATL::CSid user;
758   restricted_token.GetUser(&user);
759   CheckRestrictingSid(restricted_token, user, -1);
760 }
761 
762 // Checks the error code when the object is initialized twice.
TEST(RestrictedTokenTest,DoubleInit)763 TEST(RestrictedTokenTest, DoubleInit) {
764   RestrictedToken token;
765   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
766 
767   ASSERT_EQ(static_cast<DWORD>(ERROR_ALREADY_INITIALIZED), token.Init(nullptr));
768 }
769 
TEST(RestrictedTokenTest,LockdownDefaultDaclNoLogonSid)770 TEST(RestrictedTokenTest, LockdownDefaultDaclNoLogonSid) {
771   ATL::CAccessToken anonymous_token;
772   ASSERT_TRUE(::ImpersonateAnonymousToken(::GetCurrentThread()));
773   ASSERT_TRUE(anonymous_token.GetThreadToken(TOKEN_ALL_ACCESS));
774   ::RevertToSelf();
775   ATL::CSid logon_sid;
776   // Verify that the anonymous token doesn't have the logon sid.
777   ASSERT_FALSE(anonymous_token.GetLogonSid(&logon_sid));
778 
779   RestrictedToken token;
780   ASSERT_EQ(DWORD{ERROR_SUCCESS}, token.Init(anonymous_token.GetHandle()));
781   token.SetLockdownDefaultDacl();
782 
783   base::win::ScopedHandle handle;
784   ASSERT_EQ(DWORD{ERROR_SUCCESS}, token.GetRestrictedToken(&handle));
785 }
786 
TEST(RestrictedTokenTest,LowBoxToken)787 TEST(RestrictedTokenTest, LowBoxToken) {
788   if (base::win::GetVersion() < base::win::Version::WIN8)
789     return;
790   base::win::ScopedHandle token;
791 
792   Sid package_sid = Sid::FromSddlString(L"S-1-15-2-1-2-3-4-5-6-7");
793   SecurityCapabilities caps_no_capabilities(package_sid);
794 
795   ASSERT_EQ(DWORD{ERROR_INVALID_PARAMETER},
796             CreateLowBoxToken(nullptr, PRIMARY, &caps_no_capabilities, nullptr,
797                               0, nullptr));
798   ASSERT_EQ(DWORD{ERROR_SUCCESS},
799             CreateLowBoxToken(nullptr, PRIMARY, &caps_no_capabilities, nullptr,
800                               0, &token));
801   ASSERT_TRUE(token.IsValid());
802   CheckLowBoxToken(token, ::TokenPrimary, &caps_no_capabilities);
803 
804   ASSERT_TRUE(ReplacePackageSidInDacl(token.Get(), SE_KERNEL_OBJECT,
805                                       Sid(caps_no_capabilities.AppContainerSid),
806                                       TOKEN_ALL_ACCESS));
807   CheckDaclForPackageSid(token, &caps_no_capabilities, false);
808 
809   ASSERT_EQ(DWORD{ERROR_SUCCESS},
810             CreateLowBoxToken(nullptr, IMPERSONATION, &caps_no_capabilities,
811                               nullptr, 0, &token));
812   ASSERT_TRUE(token.IsValid());
813   CheckLowBoxToken(token, ::TokenImpersonation, &caps_no_capabilities);
814 
815   std::vector<Sid> capabilities;
816   capabilities.push_back(Sid::FromKnownCapability(kInternetClient));
817   capabilities.push_back(Sid::FromKnownCapability(kPrivateNetworkClientServer));
818   SecurityCapabilities caps_with_capabilities(package_sid, capabilities);
819   ASSERT_EQ(DWORD{ERROR_SUCCESS},
820             CreateLowBoxToken(nullptr, PRIMARY, &caps_with_capabilities,
821                               nullptr, 0, &token));
822   ASSERT_TRUE(token.IsValid());
823   CheckLowBoxToken(token, ::TokenPrimary, &caps_with_capabilities);
824 
825   RestrictedToken restricted_token;
826   base::win::ScopedHandle token_handle;
827   ASSERT_EQ(DWORD{ERROR_SUCCESS}, restricted_token.Init(nullptr));
828   ASSERT_EQ(DWORD{ERROR_SUCCESS},
829             restricted_token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
830   ASSERT_EQ(DWORD{ERROR_SUCCESS},
831             restricted_token.GetRestrictedToken(&token_handle));
832 
833   ASSERT_EQ(DWORD{ERROR_SUCCESS},
834             CreateLowBoxToken(token_handle.Get(), PRIMARY,
835                               &caps_with_capabilities, nullptr, 0, &token));
836   ASSERT_TRUE(token.IsValid());
837   CheckLowBoxToken(token, ::TokenPrimary, &caps_with_capabilities);
838   CheckRestrictingSid(token.Get(), ATL::Sids::World(), 1);
839 
840   SecurityCapabilities caps_for_handles(
841       Sid::FromSddlString(L"S-1-15-2-1-2-3-4-5-6-8"));
842   base::win::ScopedHandle object_handle;
843   ASSERT_EQ(DWORD{ERROR_SUCCESS},
844             CreateLowBoxObjectDirectory(caps_for_handles.AppContainerSid, true,
845                                         &object_handle));
846   HANDLE saved_handles[] = {object_handle.Get()};
847 
848   ASSERT_EQ(DWORD{ERROR_SUCCESS},
849             CreateLowBoxToken(token_handle.Get(), PRIMARY, &caps_for_handles,
850                               saved_handles, 1, &token));
851   ASSERT_TRUE(token.IsValid());
852   object_handle.Close();
853   ASSERT_FALSE(object_handle.IsValid());
854   ASSERT_EQ(DWORD{ERROR_ALREADY_EXISTS},
855             CreateLowBoxObjectDirectory(caps_for_handles.AppContainerSid, false,
856                                         &object_handle));
857 }
858 
859 }  // namespace sandbox
860