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