1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/restricted_token.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,472 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "sandbox/win/src/restricted_token.h" 1.9 + 1.10 +#include <vector> 1.11 + 1.12 +#include "base/logging.h" 1.13 +#include "sandbox/win/src/acl.h" 1.14 +#include "sandbox/win/src/win_utils.h" 1.15 + 1.16 + 1.17 +namespace sandbox { 1.18 + 1.19 +unsigned RestrictedToken::Init(const HANDLE effective_token) { 1.20 + DCHECK(!init_); 1.21 + if (init_) 1.22 + return ERROR_ALREADY_INITIALIZED; 1.23 + 1.24 + if (effective_token) { 1.25 + // We duplicate the handle to be able to use it even if the original handle 1.26 + // is closed. 1.27 + HANDLE effective_token_dup; 1.28 + if (::DuplicateHandle(::GetCurrentProcess(), 1.29 + effective_token, 1.30 + ::GetCurrentProcess(), 1.31 + &effective_token_dup, 1.32 + 0, 1.33 + FALSE, 1.34 + DUPLICATE_SAME_ACCESS)) { 1.35 + effective_token_ = effective_token_dup; 1.36 + } else { 1.37 + return ::GetLastError(); 1.38 + } 1.39 + } else { 1.40 + if (!::OpenProcessToken(::GetCurrentProcess(), 1.41 + TOKEN_ALL_ACCESS, 1.42 + &effective_token_)) 1.43 + return ::GetLastError(); 1.44 + } 1.45 + 1.46 + init_ = true; 1.47 + return ERROR_SUCCESS; 1.48 +} 1.49 + 1.50 +unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const { 1.51 + DCHECK(init_); 1.52 + if (!init_) 1.53 + return ERROR_NO_TOKEN; 1.54 + 1.55 + size_t deny_size = sids_for_deny_only_.size(); 1.56 + size_t restrict_size = sids_to_restrict_.size(); 1.57 + size_t privileges_size = privileges_to_disable_.size(); 1.58 + 1.59 + SID_AND_ATTRIBUTES *deny_only_array = NULL; 1.60 + if (deny_size) { 1.61 + deny_only_array = new SID_AND_ATTRIBUTES[deny_size]; 1.62 + 1.63 + for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) { 1.64 + deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY; 1.65 + deny_only_array[i].Sid = 1.66 + const_cast<SID*>(sids_for_deny_only_[i].GetPSID()); 1.67 + } 1.68 + } 1.69 + 1.70 + SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL; 1.71 + if (restrict_size) { 1.72 + sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size]; 1.73 + 1.74 + for (unsigned int i = 0; i < restrict_size; ++i) { 1.75 + sids_to_restrict_array[i].Attributes = 0; 1.76 + sids_to_restrict_array[i].Sid = 1.77 + const_cast<SID*>(sids_to_restrict_[i].GetPSID()); 1.78 + } 1.79 + } 1.80 + 1.81 + LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL; 1.82 + if (privileges_size) { 1.83 + privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size]; 1.84 + 1.85 + for (unsigned int i = 0; i < privileges_size; ++i) { 1.86 + privileges_to_disable_array[i].Attributes = 0; 1.87 + privileges_to_disable_array[i].Luid = privileges_to_disable_[i]; 1.88 + } 1.89 + } 1.90 + 1.91 + BOOL result = TRUE; 1.92 + HANDLE new_token = NULL; 1.93 + // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell 1.94 + // if a token has ben restricted given the limiations of IsTokenRestricted() 1.95 + // but it appears that in Windows 7 it hints the AppLocker subsystem to 1.96 + // leave us alone. 1.97 + if (deny_size || restrict_size || privileges_size) { 1.98 + result = ::CreateRestrictedToken(effective_token_, 1.99 + SANDBOX_INERT, 1.100 + static_cast<DWORD>(deny_size), 1.101 + deny_only_array, 1.102 + static_cast<DWORD>(privileges_size), 1.103 + privileges_to_disable_array, 1.104 + static_cast<DWORD>(restrict_size), 1.105 + sids_to_restrict_array, 1.106 + &new_token); 1.107 + } else { 1.108 + // Duplicate the token even if it's not modified at this point 1.109 + // because any subsequent changes to this token would also affect the 1.110 + // current process. 1.111 + result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL, 1.112 + SecurityIdentification, TokenPrimary, 1.113 + &new_token); 1.114 + } 1.115 + 1.116 + if (deny_only_array) 1.117 + delete[] deny_only_array; 1.118 + 1.119 + if (sids_to_restrict_array) 1.120 + delete[] sids_to_restrict_array; 1.121 + 1.122 + if (privileges_to_disable_array) 1.123 + delete[] privileges_to_disable_array; 1.124 + 1.125 + if (!result) 1.126 + return ::GetLastError(); 1.127 + 1.128 + // Modify the default dacl on the token to contain Restricted and the user. 1.129 + if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL)) 1.130 + return ::GetLastError(); 1.131 + 1.132 + if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL)) 1.133 + return ::GetLastError(); 1.134 + 1.135 + DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_); 1.136 + if (ERROR_SUCCESS != error) 1.137 + return error; 1.138 + 1.139 + BOOL status = ::DuplicateHandle(::GetCurrentProcess(), 1.140 + new_token, 1.141 + ::GetCurrentProcess(), 1.142 + token_handle, 1.143 + TOKEN_ALL_ACCESS, 1.144 + FALSE, // Don't inherit. 1.145 + 0); 1.146 + 1.147 + if (new_token != effective_token_) 1.148 + ::CloseHandle(new_token); 1.149 + 1.150 + if (!status) 1.151 + return ::GetLastError(); 1.152 + 1.153 + return ERROR_SUCCESS; 1.154 +} 1.155 + 1.156 +unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation( 1.157 + HANDLE *token_handle) const { 1.158 + DCHECK(init_); 1.159 + if (!init_) 1.160 + return ERROR_NO_TOKEN; 1.161 + 1.162 + HANDLE restricted_token_handle; 1.163 + unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle); 1.164 + if (ERROR_SUCCESS != err_code) 1.165 + return err_code; 1.166 + 1.167 + HANDLE impersonation_token; 1.168 + if (!::DuplicateToken(restricted_token_handle, 1.169 + SecurityImpersonation, 1.170 + &impersonation_token)) { 1.171 + ::CloseHandle(restricted_token_handle); 1.172 + return ::GetLastError(); 1.173 + } 1.174 + 1.175 + ::CloseHandle(restricted_token_handle); 1.176 + 1.177 + BOOL status = ::DuplicateHandle(::GetCurrentProcess(), 1.178 + impersonation_token, 1.179 + ::GetCurrentProcess(), 1.180 + token_handle, 1.181 + TOKEN_ALL_ACCESS, 1.182 + FALSE, // Don't inherit. 1.183 + 0); 1.184 + 1.185 + ::CloseHandle(impersonation_token); 1.186 + 1.187 + if (!status) 1.188 + return ::GetLastError(); 1.189 + 1.190 + return ERROR_SUCCESS; 1.191 +} 1.192 + 1.193 +unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) { 1.194 + DCHECK(init_); 1.195 + if (!init_) 1.196 + return ERROR_NO_TOKEN; 1.197 + 1.198 + TOKEN_GROUPS *token_groups = NULL; 1.199 + DWORD size = 0; 1.200 + 1.201 + BOOL result = ::GetTokenInformation(effective_token_, 1.202 + TokenGroups, 1.203 + NULL, // No buffer. 1.204 + 0, // Size is 0. 1.205 + &size); 1.206 + if (!size) 1.207 + return ::GetLastError(); 1.208 + 1.209 + token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]); 1.210 + result = ::GetTokenInformation(effective_token_, 1.211 + TokenGroups, 1.212 + token_groups, 1.213 + size, 1.214 + &size); 1.215 + if (!result) { 1.216 + delete[] reinterpret_cast<BYTE*>(token_groups); 1.217 + return ::GetLastError(); 1.218 + } 1.219 + 1.220 + // Build the list of the deny only group SIDs 1.221 + for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) { 1.222 + if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 && 1.223 + (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) { 1.224 + bool should_ignore = false; 1.225 + if (exceptions) { 1.226 + for (unsigned int j = 0; j < exceptions->size(); ++j) { 1.227 + if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()), 1.228 + token_groups->Groups[i].Sid)) { 1.229 + should_ignore = true; 1.230 + break; 1.231 + } 1.232 + } 1.233 + } 1.234 + if (!should_ignore) { 1.235 + sids_for_deny_only_.push_back( 1.236 + reinterpret_cast<SID*>(token_groups->Groups[i].Sid)); 1.237 + } 1.238 + } 1.239 + } 1.240 + 1.241 + delete[] reinterpret_cast<BYTE*>(token_groups); 1.242 + 1.243 + return ERROR_SUCCESS; 1.244 +} 1.245 + 1.246 +unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) { 1.247 + DCHECK(init_); 1.248 + if (!init_) 1.249 + return ERROR_NO_TOKEN; 1.250 + 1.251 + sids_for_deny_only_.push_back(sid); 1.252 + return ERROR_SUCCESS; 1.253 +} 1.254 + 1.255 +unsigned RestrictedToken::AddUserSidForDenyOnly() { 1.256 + DCHECK(init_); 1.257 + if (!init_) 1.258 + return ERROR_NO_TOKEN; 1.259 + 1.260 + DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE; 1.261 + TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]); 1.262 + 1.263 + BOOL result = ::GetTokenInformation(effective_token_, 1.264 + TokenUser, 1.265 + token_user, 1.266 + size, 1.267 + &size); 1.268 + 1.269 + if (!result) { 1.270 + delete[] reinterpret_cast<BYTE*>(token_user); 1.271 + return ::GetLastError(); 1.272 + } 1.273 + 1.274 + Sid user = reinterpret_cast<SID*>(token_user->User.Sid); 1.275 + sids_for_deny_only_.push_back(user); 1.276 + 1.277 + delete[] reinterpret_cast<BYTE*>(token_user); 1.278 + 1.279 + return ERROR_SUCCESS; 1.280 +} 1.281 + 1.282 +unsigned RestrictedToken::DeleteAllPrivileges( 1.283 + const std::vector<std::wstring> *exceptions) { 1.284 + DCHECK(init_); 1.285 + if (!init_) 1.286 + return ERROR_NO_TOKEN; 1.287 + 1.288 + // Get the list of privileges in the token 1.289 + TOKEN_PRIVILEGES *token_privileges = NULL; 1.290 + DWORD size = 0; 1.291 + 1.292 + BOOL result = ::GetTokenInformation(effective_token_, 1.293 + TokenPrivileges, 1.294 + NULL, // No buffer. 1.295 + 0, // Size is 0. 1.296 + &size); 1.297 + if (!size) 1.298 + return ::GetLastError(); 1.299 + 1.300 + token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]); 1.301 + result = ::GetTokenInformation(effective_token_, 1.302 + TokenPrivileges, 1.303 + token_privileges, 1.304 + size, 1.305 + &size); 1.306 + if (!result) { 1.307 + delete[] reinterpret_cast<BYTE *>(token_privileges); 1.308 + return ::GetLastError(); 1.309 + } 1.310 + 1.311 + 1.312 + // Build the list of privileges to disable 1.313 + for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) { 1.314 + bool should_ignore = false; 1.315 + if (exceptions) { 1.316 + for (unsigned int j = 0; j < exceptions->size(); ++j) { 1.317 + LUID luid = {0}; 1.318 + ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid); 1.319 + if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart && 1.320 + token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) { 1.321 + should_ignore = true; 1.322 + break; 1.323 + } 1.324 + } 1.325 + } 1.326 + if (!should_ignore) { 1.327 + privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid); 1.328 + } 1.329 + } 1.330 + 1.331 + delete[] reinterpret_cast<BYTE *>(token_privileges); 1.332 + 1.333 + return ERROR_SUCCESS; 1.334 +} 1.335 + 1.336 +unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) { 1.337 + DCHECK(init_); 1.338 + if (!init_) 1.339 + return ERROR_NO_TOKEN; 1.340 + 1.341 + LUID luid = {0}; 1.342 + if (LookupPrivilegeValue(NULL, privilege, &luid)) 1.343 + privileges_to_disable_.push_back(luid); 1.344 + else 1.345 + return ::GetLastError(); 1.346 + 1.347 + return ERROR_SUCCESS; 1.348 +} 1.349 + 1.350 +unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) { 1.351 + DCHECK(init_); 1.352 + if (!init_) 1.353 + return ERROR_NO_TOKEN; 1.354 + 1.355 + sids_to_restrict_.push_back(sid); // No attributes 1.356 + return ERROR_SUCCESS; 1.357 +} 1.358 + 1.359 +unsigned RestrictedToken::AddRestrictingSidLogonSession() { 1.360 + DCHECK(init_); 1.361 + if (!init_) 1.362 + return ERROR_NO_TOKEN; 1.363 + 1.364 + TOKEN_GROUPS *token_groups = NULL; 1.365 + DWORD size = 0; 1.366 + 1.367 + BOOL result = ::GetTokenInformation(effective_token_, 1.368 + TokenGroups, 1.369 + NULL, // No buffer. 1.370 + 0, // Size is 0. 1.371 + &size); 1.372 + if (!size) 1.373 + return ::GetLastError(); 1.374 + 1.375 + token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]); 1.376 + result = ::GetTokenInformation(effective_token_, 1.377 + TokenGroups, 1.378 + token_groups, 1.379 + size, 1.380 + &size); 1.381 + if (!result) { 1.382 + delete[] reinterpret_cast<BYTE*>(token_groups); 1.383 + return ::GetLastError(); 1.384 + } 1.385 + 1.386 + SID *logon_sid = NULL; 1.387 + for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) { 1.388 + if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) { 1.389 + logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid); 1.390 + break; 1.391 + } 1.392 + } 1.393 + 1.394 + if (logon_sid) 1.395 + sids_to_restrict_.push_back(logon_sid); 1.396 + 1.397 + delete[] reinterpret_cast<BYTE*>(token_groups); 1.398 + 1.399 + return ERROR_SUCCESS; 1.400 +} 1.401 + 1.402 +unsigned RestrictedToken::AddRestrictingSidCurrentUser() { 1.403 + DCHECK(init_); 1.404 + if (!init_) 1.405 + return ERROR_NO_TOKEN; 1.406 + 1.407 + DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE; 1.408 + TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]); 1.409 + 1.410 + BOOL result = ::GetTokenInformation(effective_token_, 1.411 + TokenUser, 1.412 + token_user, 1.413 + size, 1.414 + &size); 1.415 + 1.416 + if (!result) { 1.417 + delete[] reinterpret_cast<BYTE*>(token_user); 1.418 + return ::GetLastError(); 1.419 + } 1.420 + 1.421 + Sid user = reinterpret_cast<SID*>(token_user->User.Sid); 1.422 + sids_to_restrict_.push_back(user); 1.423 + 1.424 + delete[] reinterpret_cast<BYTE*>(token_user); 1.425 + 1.426 + return ERROR_SUCCESS; 1.427 +} 1.428 + 1.429 +unsigned RestrictedToken::AddRestrictingSidAllSids() { 1.430 + DCHECK(init_); 1.431 + if (!init_) 1.432 + return ERROR_NO_TOKEN; 1.433 + 1.434 + // Add the current user to the list. 1.435 + unsigned error = AddRestrictingSidCurrentUser(); 1.436 + if (ERROR_SUCCESS != error) 1.437 + return error; 1.438 + 1.439 + TOKEN_GROUPS *token_groups = NULL; 1.440 + DWORD size = 0; 1.441 + 1.442 + // Get the buffer size required. 1.443 + BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0, 1.444 + &size); 1.445 + if (!size) 1.446 + return ::GetLastError(); 1.447 + 1.448 + token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]); 1.449 + result = ::GetTokenInformation(effective_token_, 1.450 + TokenGroups, 1.451 + token_groups, 1.452 + size, 1.453 + &size); 1.454 + if (!result) { 1.455 + delete[] reinterpret_cast<BYTE*>(token_groups); 1.456 + return ::GetLastError(); 1.457 + } 1.458 + 1.459 + // Build the list of restricting sids from all groups. 1.460 + for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) { 1.461 + if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0) 1.462 + AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid)); 1.463 + } 1.464 + 1.465 + delete[] reinterpret_cast<BYTE*>(token_groups); 1.466 + 1.467 + return ERROR_SUCCESS; 1.468 +} 1.469 + 1.470 +unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) { 1.471 + integrity_level_ = integrity_level; 1.472 + return ERROR_SUCCESS; 1.473 +} 1.474 + 1.475 +} // namespace sandbox