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 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 47 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 153 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 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 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 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 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 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 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 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 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 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 467 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) { 468 integrity_level_ = integrity_level; 469 return ERROR_SUCCESS; 470 } 471 472 } // namespace sandbox 473