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