security/sandbox/win/src/restricted_token.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "sandbox/win/src/restricted_token.h"
michael@0 6
michael@0 7 #include <vector>
michael@0 8
michael@0 9 #include "base/logging.h"
michael@0 10 #include "sandbox/win/src/acl.h"
michael@0 11 #include "sandbox/win/src/win_utils.h"
michael@0 12
michael@0 13
michael@0 14 namespace sandbox {
michael@0 15
michael@0 16 unsigned RestrictedToken::Init(const HANDLE effective_token) {
michael@0 17 DCHECK(!init_);
michael@0 18 if (init_)
michael@0 19 return ERROR_ALREADY_INITIALIZED;
michael@0 20
michael@0 21 if (effective_token) {
michael@0 22 // We duplicate the handle to be able to use it even if the original handle
michael@0 23 // is closed.
michael@0 24 HANDLE effective_token_dup;
michael@0 25 if (::DuplicateHandle(::GetCurrentProcess(),
michael@0 26 effective_token,
michael@0 27 ::GetCurrentProcess(),
michael@0 28 &effective_token_dup,
michael@0 29 0,
michael@0 30 FALSE,
michael@0 31 DUPLICATE_SAME_ACCESS)) {
michael@0 32 effective_token_ = effective_token_dup;
michael@0 33 } else {
michael@0 34 return ::GetLastError();
michael@0 35 }
michael@0 36 } else {
michael@0 37 if (!::OpenProcessToken(::GetCurrentProcess(),
michael@0 38 TOKEN_ALL_ACCESS,
michael@0 39 &effective_token_))
michael@0 40 return ::GetLastError();
michael@0 41 }
michael@0 42
michael@0 43 init_ = true;
michael@0 44 return ERROR_SUCCESS;
michael@0 45 }
michael@0 46
michael@0 47 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
michael@0 48 DCHECK(init_);
michael@0 49 if (!init_)
michael@0 50 return ERROR_NO_TOKEN;
michael@0 51
michael@0 52 size_t deny_size = sids_for_deny_only_.size();
michael@0 53 size_t restrict_size = sids_to_restrict_.size();
michael@0 54 size_t privileges_size = privileges_to_disable_.size();
michael@0 55
michael@0 56 SID_AND_ATTRIBUTES *deny_only_array = NULL;
michael@0 57 if (deny_size) {
michael@0 58 deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
michael@0 59
michael@0 60 for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
michael@0 61 deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
michael@0 62 deny_only_array[i].Sid =
michael@0 63 const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
michael@0 64 }
michael@0 65 }
michael@0 66
michael@0 67 SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
michael@0 68 if (restrict_size) {
michael@0 69 sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
michael@0 70
michael@0 71 for (unsigned int i = 0; i < restrict_size; ++i) {
michael@0 72 sids_to_restrict_array[i].Attributes = 0;
michael@0 73 sids_to_restrict_array[i].Sid =
michael@0 74 const_cast<SID*>(sids_to_restrict_[i].GetPSID());
michael@0 75 }
michael@0 76 }
michael@0 77
michael@0 78 LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
michael@0 79 if (privileges_size) {
michael@0 80 privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
michael@0 81
michael@0 82 for (unsigned int i = 0; i < privileges_size; ++i) {
michael@0 83 privileges_to_disable_array[i].Attributes = 0;
michael@0 84 privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
michael@0 85 }
michael@0 86 }
michael@0 87
michael@0 88 BOOL result = TRUE;
michael@0 89 HANDLE new_token = NULL;
michael@0 90 // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
michael@0 91 // if a token has ben restricted given the limiations of IsTokenRestricted()
michael@0 92 // but it appears that in Windows 7 it hints the AppLocker subsystem to
michael@0 93 // leave us alone.
michael@0 94 if (deny_size || restrict_size || privileges_size) {
michael@0 95 result = ::CreateRestrictedToken(effective_token_,
michael@0 96 SANDBOX_INERT,
michael@0 97 static_cast<DWORD>(deny_size),
michael@0 98 deny_only_array,
michael@0 99 static_cast<DWORD>(privileges_size),
michael@0 100 privileges_to_disable_array,
michael@0 101 static_cast<DWORD>(restrict_size),
michael@0 102 sids_to_restrict_array,
michael@0 103 &new_token);
michael@0 104 } else {
michael@0 105 // Duplicate the token even if it's not modified at this point
michael@0 106 // because any subsequent changes to this token would also affect the
michael@0 107 // current process.
michael@0 108 result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL,
michael@0 109 SecurityIdentification, TokenPrimary,
michael@0 110 &new_token);
michael@0 111 }
michael@0 112
michael@0 113 if (deny_only_array)
michael@0 114 delete[] deny_only_array;
michael@0 115
michael@0 116 if (sids_to_restrict_array)
michael@0 117 delete[] sids_to_restrict_array;
michael@0 118
michael@0 119 if (privileges_to_disable_array)
michael@0 120 delete[] privileges_to_disable_array;
michael@0 121
michael@0 122 if (!result)
michael@0 123 return ::GetLastError();
michael@0 124
michael@0 125 // Modify the default dacl on the token to contain Restricted and the user.
michael@0 126 if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
michael@0 127 return ::GetLastError();
michael@0 128
michael@0 129 if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
michael@0 130 return ::GetLastError();
michael@0 131
michael@0 132 DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
michael@0 133 if (ERROR_SUCCESS != error)
michael@0 134 return error;
michael@0 135
michael@0 136 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
michael@0 137 new_token,
michael@0 138 ::GetCurrentProcess(),
michael@0 139 token_handle,
michael@0 140 TOKEN_ALL_ACCESS,
michael@0 141 FALSE, // Don't inherit.
michael@0 142 0);
michael@0 143
michael@0 144 if (new_token != effective_token_)
michael@0 145 ::CloseHandle(new_token);
michael@0 146
michael@0 147 if (!status)
michael@0 148 return ::GetLastError();
michael@0 149
michael@0 150 return ERROR_SUCCESS;
michael@0 151 }
michael@0 152
michael@0 153 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
michael@0 154 HANDLE *token_handle) const {
michael@0 155 DCHECK(init_);
michael@0 156 if (!init_)
michael@0 157 return ERROR_NO_TOKEN;
michael@0 158
michael@0 159 HANDLE restricted_token_handle;
michael@0 160 unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
michael@0 161 if (ERROR_SUCCESS != err_code)
michael@0 162 return err_code;
michael@0 163
michael@0 164 HANDLE impersonation_token;
michael@0 165 if (!::DuplicateToken(restricted_token_handle,
michael@0 166 SecurityImpersonation,
michael@0 167 &impersonation_token)) {
michael@0 168 ::CloseHandle(restricted_token_handle);
michael@0 169 return ::GetLastError();
michael@0 170 }
michael@0 171
michael@0 172 ::CloseHandle(restricted_token_handle);
michael@0 173
michael@0 174 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
michael@0 175 impersonation_token,
michael@0 176 ::GetCurrentProcess(),
michael@0 177 token_handle,
michael@0 178 TOKEN_ALL_ACCESS,
michael@0 179 FALSE, // Don't inherit.
michael@0 180 0);
michael@0 181
michael@0 182 ::CloseHandle(impersonation_token);
michael@0 183
michael@0 184 if (!status)
michael@0 185 return ::GetLastError();
michael@0 186
michael@0 187 return ERROR_SUCCESS;
michael@0 188 }
michael@0 189
michael@0 190 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
michael@0 191 DCHECK(init_);
michael@0 192 if (!init_)
michael@0 193 return ERROR_NO_TOKEN;
michael@0 194
michael@0 195 TOKEN_GROUPS *token_groups = NULL;
michael@0 196 DWORD size = 0;
michael@0 197
michael@0 198 BOOL result = ::GetTokenInformation(effective_token_,
michael@0 199 TokenGroups,
michael@0 200 NULL, // No buffer.
michael@0 201 0, // Size is 0.
michael@0 202 &size);
michael@0 203 if (!size)
michael@0 204 return ::GetLastError();
michael@0 205
michael@0 206 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
michael@0 207 result = ::GetTokenInformation(effective_token_,
michael@0 208 TokenGroups,
michael@0 209 token_groups,
michael@0 210 size,
michael@0 211 &size);
michael@0 212 if (!result) {
michael@0 213 delete[] reinterpret_cast<BYTE*>(token_groups);
michael@0 214 return ::GetLastError();
michael@0 215 }
michael@0 216
michael@0 217 // Build the list of the deny only group SIDs
michael@0 218 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
michael@0 219 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
michael@0 220 (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
michael@0 221 bool should_ignore = false;
michael@0 222 if (exceptions) {
michael@0 223 for (unsigned int j = 0; j < exceptions->size(); ++j) {
michael@0 224 if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
michael@0 225 token_groups->Groups[i].Sid)) {
michael@0 226 should_ignore = true;
michael@0 227 break;
michael@0 228 }
michael@0 229 }
michael@0 230 }
michael@0 231 if (!should_ignore) {
michael@0 232 sids_for_deny_only_.push_back(
michael@0 233 reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
michael@0 234 }
michael@0 235 }
michael@0 236 }
michael@0 237
michael@0 238 delete[] reinterpret_cast<BYTE*>(token_groups);
michael@0 239
michael@0 240 return ERROR_SUCCESS;
michael@0 241 }
michael@0 242
michael@0 243 unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
michael@0 244 DCHECK(init_);
michael@0 245 if (!init_)
michael@0 246 return ERROR_NO_TOKEN;
michael@0 247
michael@0 248 sids_for_deny_only_.push_back(sid);
michael@0 249 return ERROR_SUCCESS;
michael@0 250 }
michael@0 251
michael@0 252 unsigned RestrictedToken::AddUserSidForDenyOnly() {
michael@0 253 DCHECK(init_);
michael@0 254 if (!init_)
michael@0 255 return ERROR_NO_TOKEN;
michael@0 256
michael@0 257 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
michael@0 258 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
michael@0 259
michael@0 260 BOOL result = ::GetTokenInformation(effective_token_,
michael@0 261 TokenUser,
michael@0 262 token_user,
michael@0 263 size,
michael@0 264 &size);
michael@0 265
michael@0 266 if (!result) {
michael@0 267 delete[] reinterpret_cast<BYTE*>(token_user);
michael@0 268 return ::GetLastError();
michael@0 269 }
michael@0 270
michael@0 271 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
michael@0 272 sids_for_deny_only_.push_back(user);
michael@0 273
michael@0 274 delete[] reinterpret_cast<BYTE*>(token_user);
michael@0 275
michael@0 276 return ERROR_SUCCESS;
michael@0 277 }
michael@0 278
michael@0 279 unsigned RestrictedToken::DeleteAllPrivileges(
michael@0 280 const std::vector<std::wstring> *exceptions) {
michael@0 281 DCHECK(init_);
michael@0 282 if (!init_)
michael@0 283 return ERROR_NO_TOKEN;
michael@0 284
michael@0 285 // Get the list of privileges in the token
michael@0 286 TOKEN_PRIVILEGES *token_privileges = NULL;
michael@0 287 DWORD size = 0;
michael@0 288
michael@0 289 BOOL result = ::GetTokenInformation(effective_token_,
michael@0 290 TokenPrivileges,
michael@0 291 NULL, // No buffer.
michael@0 292 0, // Size is 0.
michael@0 293 &size);
michael@0 294 if (!size)
michael@0 295 return ::GetLastError();
michael@0 296
michael@0 297 token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]);
michael@0 298 result = ::GetTokenInformation(effective_token_,
michael@0 299 TokenPrivileges,
michael@0 300 token_privileges,
michael@0 301 size,
michael@0 302 &size);
michael@0 303 if (!result) {
michael@0 304 delete[] reinterpret_cast<BYTE *>(token_privileges);
michael@0 305 return ::GetLastError();
michael@0 306 }
michael@0 307
michael@0 308
michael@0 309 // Build the list of privileges to disable
michael@0 310 for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
michael@0 311 bool should_ignore = false;
michael@0 312 if (exceptions) {
michael@0 313 for (unsigned int j = 0; j < exceptions->size(); ++j) {
michael@0 314 LUID luid = {0};
michael@0 315 ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
michael@0 316 if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
michael@0 317 token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
michael@0 318 should_ignore = true;
michael@0 319 break;
michael@0 320 }
michael@0 321 }
michael@0 322 }
michael@0 323 if (!should_ignore) {
michael@0 324 privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
michael@0 325 }
michael@0 326 }
michael@0 327
michael@0 328 delete[] reinterpret_cast<BYTE *>(token_privileges);
michael@0 329
michael@0 330 return ERROR_SUCCESS;
michael@0 331 }
michael@0 332
michael@0 333 unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
michael@0 334 DCHECK(init_);
michael@0 335 if (!init_)
michael@0 336 return ERROR_NO_TOKEN;
michael@0 337
michael@0 338 LUID luid = {0};
michael@0 339 if (LookupPrivilegeValue(NULL, privilege, &luid))
michael@0 340 privileges_to_disable_.push_back(luid);
michael@0 341 else
michael@0 342 return ::GetLastError();
michael@0 343
michael@0 344 return ERROR_SUCCESS;
michael@0 345 }
michael@0 346
michael@0 347 unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
michael@0 348 DCHECK(init_);
michael@0 349 if (!init_)
michael@0 350 return ERROR_NO_TOKEN;
michael@0 351
michael@0 352 sids_to_restrict_.push_back(sid); // No attributes
michael@0 353 return ERROR_SUCCESS;
michael@0 354 }
michael@0 355
michael@0 356 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
michael@0 357 DCHECK(init_);
michael@0 358 if (!init_)
michael@0 359 return ERROR_NO_TOKEN;
michael@0 360
michael@0 361 TOKEN_GROUPS *token_groups = NULL;
michael@0 362 DWORD size = 0;
michael@0 363
michael@0 364 BOOL result = ::GetTokenInformation(effective_token_,
michael@0 365 TokenGroups,
michael@0 366 NULL, // No buffer.
michael@0 367 0, // Size is 0.
michael@0 368 &size);
michael@0 369 if (!size)
michael@0 370 return ::GetLastError();
michael@0 371
michael@0 372 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
michael@0 373 result = ::GetTokenInformation(effective_token_,
michael@0 374 TokenGroups,
michael@0 375 token_groups,
michael@0 376 size,
michael@0 377 &size);
michael@0 378 if (!result) {
michael@0 379 delete[] reinterpret_cast<BYTE*>(token_groups);
michael@0 380 return ::GetLastError();
michael@0 381 }
michael@0 382
michael@0 383 SID *logon_sid = NULL;
michael@0 384 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
michael@0 385 if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
michael@0 386 logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
michael@0 387 break;
michael@0 388 }
michael@0 389 }
michael@0 390
michael@0 391 if (logon_sid)
michael@0 392 sids_to_restrict_.push_back(logon_sid);
michael@0 393
michael@0 394 delete[] reinterpret_cast<BYTE*>(token_groups);
michael@0 395
michael@0 396 return ERROR_SUCCESS;
michael@0 397 }
michael@0 398
michael@0 399 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
michael@0 400 DCHECK(init_);
michael@0 401 if (!init_)
michael@0 402 return ERROR_NO_TOKEN;
michael@0 403
michael@0 404 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
michael@0 405 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
michael@0 406
michael@0 407 BOOL result = ::GetTokenInformation(effective_token_,
michael@0 408 TokenUser,
michael@0 409 token_user,
michael@0 410 size,
michael@0 411 &size);
michael@0 412
michael@0 413 if (!result) {
michael@0 414 delete[] reinterpret_cast<BYTE*>(token_user);
michael@0 415 return ::GetLastError();
michael@0 416 }
michael@0 417
michael@0 418 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
michael@0 419 sids_to_restrict_.push_back(user);
michael@0 420
michael@0 421 delete[] reinterpret_cast<BYTE*>(token_user);
michael@0 422
michael@0 423 return ERROR_SUCCESS;
michael@0 424 }
michael@0 425
michael@0 426 unsigned RestrictedToken::AddRestrictingSidAllSids() {
michael@0 427 DCHECK(init_);
michael@0 428 if (!init_)
michael@0 429 return ERROR_NO_TOKEN;
michael@0 430
michael@0 431 // Add the current user to the list.
michael@0 432 unsigned error = AddRestrictingSidCurrentUser();
michael@0 433 if (ERROR_SUCCESS != error)
michael@0 434 return error;
michael@0 435
michael@0 436 TOKEN_GROUPS *token_groups = NULL;
michael@0 437 DWORD size = 0;
michael@0 438
michael@0 439 // Get the buffer size required.
michael@0 440 BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
michael@0 441 &size);
michael@0 442 if (!size)
michael@0 443 return ::GetLastError();
michael@0 444
michael@0 445 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
michael@0 446 result = ::GetTokenInformation(effective_token_,
michael@0 447 TokenGroups,
michael@0 448 token_groups,
michael@0 449 size,
michael@0 450 &size);
michael@0 451 if (!result) {
michael@0 452 delete[] reinterpret_cast<BYTE*>(token_groups);
michael@0 453 return ::GetLastError();
michael@0 454 }
michael@0 455
michael@0 456 // Build the list of restricting sids from all groups.
michael@0 457 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
michael@0 458 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
michael@0 459 AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
michael@0 460 }
michael@0 461
michael@0 462 delete[] reinterpret_cast<BYTE*>(token_groups);
michael@0 463
michael@0 464 return ERROR_SUCCESS;
michael@0 465 }
michael@0 466
michael@0 467 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
michael@0 468 integrity_level_ = integrity_level;
michael@0 469 return ERROR_SUCCESS;
michael@0 470 }
michael@0 471
michael@0 472 } // namespace sandbox

mercurial