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/sandbox_policy_base.h" 6 7 #include <sddl.h> 8 9 #include "base/basictypes.h" 10 #include "base/callback.h" 11 #include "base/logging.h" 12 #include "base/win/windows_version.h" 13 #include "sandbox/win/src/app_container.h" 14 #include "sandbox/win/src/filesystem_dispatcher.h" 15 #include "sandbox/win/src/filesystem_policy.h" 16 #include "sandbox/win/src/handle_dispatcher.h" 17 #include "sandbox/win/src/handle_policy.h" 18 #include "sandbox/win/src/job.h" 19 #include "sandbox/win/src/interception.h" 20 #include "sandbox/win/src/process_mitigations.h" 21 #include "sandbox/win/src/named_pipe_dispatcher.h" 22 #include "sandbox/win/src/named_pipe_policy.h" 23 #include "sandbox/win/src/policy_broker.h" 24 #include "sandbox/win/src/policy_engine_processor.h" 25 #include "sandbox/win/src/policy_low_level.h" 26 #include "sandbox/win/src/process_mitigations_win32k_dispatcher.h" 27 #include "sandbox/win/src/process_mitigations_win32k_policy.h" 28 #include "sandbox/win/src/process_thread_dispatcher.h" 29 #include "sandbox/win/src/process_thread_policy.h" 30 #include "sandbox/win/src/registry_dispatcher.h" 31 #include "sandbox/win/src/registry_policy.h" 32 #include "sandbox/win/src/restricted_token_utils.h" 33 #include "sandbox/win/src/sandbox_policy.h" 34 #include "sandbox/win/src/sync_dispatcher.h" 35 #include "sandbox/win/src/sync_policy.h" 36 #include "sandbox/win/src/target_process.h" 37 #include "sandbox/win/src/window.h" 38 39 namespace { 40 41 // The standard windows size for one memory page. 42 const size_t kOneMemPage = 4096; 43 // The IPC and Policy shared memory sizes. 44 const size_t kIPCMemSize = kOneMemPage * 2; 45 const size_t kPolMemSize = kOneMemPage * 14; 46 47 // Helper function to allocate space (on the heap) for policy. 48 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() { 49 const size_t kTotalPolicySz = kPolMemSize; 50 sandbox::PolicyGlobal* policy = static_cast<sandbox::PolicyGlobal*> 51 (::operator new(kTotalPolicySz)); 52 DCHECK(policy); 53 memset(policy, 0, kTotalPolicySz); 54 policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal); 55 return policy; 56 } 57 58 bool IsInheritableHandle(HANDLE handle) { 59 if (!handle) 60 return false; 61 if (handle == INVALID_HANDLE_VALUE) 62 return false; 63 // File handles (FILE_TYPE_DISK) and pipe handles are known to be 64 // inheritable. Console handles (FILE_TYPE_CHAR) are not 65 // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST. 66 DWORD handle_type = GetFileType(handle); 67 return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE; 68 } 69 70 } 71 72 namespace sandbox { 73 74 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level; 75 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations; 76 77 // Initializes static members. 78 HWINSTA PolicyBase::alternate_winstation_handle_ = NULL; 79 HDESK PolicyBase::alternate_desktop_handle_ = NULL; 80 IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ = 81 INTEGRITY_LEVEL_SYSTEM; 82 83 PolicyBase::PolicyBase() 84 : ref_count(1), 85 lockdown_level_(USER_LOCKDOWN), 86 initial_level_(USER_LOCKDOWN), 87 job_level_(JOB_LOCKDOWN), 88 ui_exceptions_(0), 89 memory_limit_(0), 90 use_alternate_desktop_(false), 91 use_alternate_winstation_(false), 92 file_system_init_(false), 93 relaxed_interceptions_(true), 94 stdout_handle_(INVALID_HANDLE_VALUE), 95 stderr_handle_(INVALID_HANDLE_VALUE), 96 integrity_level_(INTEGRITY_LEVEL_LAST), 97 delayed_integrity_level_(INTEGRITY_LEVEL_LAST), 98 mitigations_(0), 99 delayed_mitigations_(0), 100 policy_maker_(NULL), 101 policy_(NULL) { 102 ::InitializeCriticalSection(&lock_); 103 // Initialize the IPC dispatcher array. 104 memset(&ipc_targets_, NULL, sizeof(ipc_targets_)); 105 Dispatcher* dispatcher = NULL; 106 107 dispatcher = new FilesystemDispatcher(this); 108 ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher; 109 ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher; 110 ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher; 111 ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher; 112 ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher; 113 114 dispatcher = new NamedPipeDispatcher(this); 115 ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher; 116 117 dispatcher = new ThreadProcessDispatcher(this); 118 ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher; 119 ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher; 120 ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher; 121 ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher; 122 ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher; 123 124 dispatcher = new SyncDispatcher(this); 125 ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher; 126 ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher; 127 128 dispatcher = new RegistryDispatcher(this); 129 ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher; 130 ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher; 131 132 dispatcher = new HandleDispatcher(this); 133 ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher; 134 135 dispatcher = new ProcessMitigationsWin32KDispatcher(this); 136 ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher; 137 ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher; 138 ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher; 139 } 140 141 PolicyBase::~PolicyBase() { 142 TargetSet::iterator it; 143 for (it = targets_.begin(); it != targets_.end(); ++it) { 144 TargetProcess* target = (*it); 145 delete target; 146 } 147 delete ipc_targets_[IPC_NTCREATEFILE_TAG]; 148 delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG]; 149 delete ipc_targets_[IPC_NTOPENTHREAD_TAG]; 150 delete ipc_targets_[IPC_CREATEEVENT_TAG]; 151 delete ipc_targets_[IPC_NTCREATEKEY_TAG]; 152 delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG]; 153 delete policy_maker_; 154 delete policy_; 155 ::DeleteCriticalSection(&lock_); 156 } 157 158 void PolicyBase::AddRef() { 159 ::InterlockedIncrement(&ref_count); 160 } 161 162 void PolicyBase::Release() { 163 if (0 == ::InterlockedDecrement(&ref_count)) 164 delete this; 165 } 166 167 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) { 168 if (initial < lockdown) { 169 return SBOX_ERROR_BAD_PARAMS; 170 } 171 initial_level_ = initial; 172 lockdown_level_ = lockdown; 173 return SBOX_ALL_OK; 174 } 175 176 TokenLevel PolicyBase::GetInitialTokenLevel() const { 177 return initial_level_; 178 } 179 180 TokenLevel PolicyBase::GetLockdownTokenLevel() const{ 181 return lockdown_level_; 182 } 183 184 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) { 185 if (memory_limit_ && job_level == JOB_NONE) { 186 return SBOX_ERROR_BAD_PARAMS; 187 } 188 job_level_ = job_level; 189 ui_exceptions_ = ui_exceptions; 190 return SBOX_ALL_OK; 191 } 192 193 ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) { 194 if (memory_limit && job_level_ == JOB_NONE) { 195 return SBOX_ERROR_BAD_PARAMS; 196 } 197 memory_limit_ = memory_limit; 198 return SBOX_ALL_OK; 199 } 200 201 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) { 202 use_alternate_desktop_ = true; 203 use_alternate_winstation_ = alternate_winstation; 204 return CreateAlternateDesktop(alternate_winstation); 205 } 206 207 base::string16 PolicyBase::GetAlternateDesktop() const { 208 // No alternate desktop or winstation. Return an empty string. 209 if (!use_alternate_desktop_ && !use_alternate_winstation_) { 210 return base::string16(); 211 } 212 213 // The desktop and winstation should have been created by now. 214 // If we hit this scenario, it means that the user ignored the failure 215 // during SetAlternateDesktop, so we ignore it here too. 216 if (use_alternate_desktop_ && !alternate_desktop_handle_) { 217 return base::string16(); 218 } 219 if (use_alternate_winstation_ && (!alternate_desktop_handle_ || 220 !alternate_winstation_handle_)) { 221 return base::string16(); 222 } 223 224 return GetFullDesktopName(alternate_winstation_handle_, 225 alternate_desktop_handle_); 226 } 227 228 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) { 229 if (alternate_winstation) { 230 // Previously called with alternate_winstation = false? 231 if (!alternate_winstation_handle_ && alternate_desktop_handle_) 232 return SBOX_ERROR_UNSUPPORTED; 233 234 // Check if it's already created. 235 if (alternate_winstation_handle_ && alternate_desktop_handle_) 236 return SBOX_ALL_OK; 237 238 DCHECK(!alternate_winstation_handle_); 239 // Create the window station. 240 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_); 241 if (SBOX_ALL_OK != result) 242 return result; 243 244 // Verify that everything is fine. 245 if (!alternate_winstation_handle_ || 246 GetWindowObjectName(alternate_winstation_handle_).empty()) 247 return SBOX_ERROR_CANNOT_CREATE_DESKTOP; 248 249 // Create the destkop. 250 result = CreateAltDesktop(alternate_winstation_handle_, 251 &alternate_desktop_handle_); 252 if (SBOX_ALL_OK != result) 253 return result; 254 255 // Verify that everything is fine. 256 if (!alternate_desktop_handle_ || 257 GetWindowObjectName(alternate_desktop_handle_).empty()) 258 return SBOX_ERROR_CANNOT_CREATE_DESKTOP; 259 } else { 260 // Previously called with alternate_winstation = true? 261 if (alternate_winstation_handle_) 262 return SBOX_ERROR_UNSUPPORTED; 263 264 // Check if it already exists. 265 if (alternate_desktop_handle_) 266 return SBOX_ALL_OK; 267 268 // Create the destkop. 269 ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_); 270 if (SBOX_ALL_OK != result) 271 return result; 272 273 // Verify that everything is fine. 274 if (!alternate_desktop_handle_ || 275 GetWindowObjectName(alternate_desktop_handle_).empty()) 276 return SBOX_ERROR_CANNOT_CREATE_DESKTOP; 277 } 278 279 return SBOX_ALL_OK; 280 } 281 282 void PolicyBase::DestroyAlternateDesktop() { 283 if (alternate_desktop_handle_) { 284 ::CloseDesktop(alternate_desktop_handle_); 285 alternate_desktop_handle_ = NULL; 286 } 287 288 if (alternate_winstation_handle_) { 289 ::CloseWindowStation(alternate_winstation_handle_); 290 alternate_winstation_handle_ = NULL; 291 } 292 } 293 294 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) { 295 integrity_level_ = integrity_level; 296 return SBOX_ALL_OK; 297 } 298 299 IntegrityLevel PolicyBase::GetIntegrityLevel() const { 300 return integrity_level_; 301 } 302 303 ResultCode PolicyBase::SetDelayedIntegrityLevel( 304 IntegrityLevel integrity_level) { 305 delayed_integrity_level_ = integrity_level; 306 return SBOX_ALL_OK; 307 } 308 309 ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) { 310 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8) 311 return SBOX_ALL_OK; 312 313 // Windows refuses to work with an impersonation token for a process inside 314 // an AppContainer. If the caller wants to use a more privileged initial 315 // token, or if the lockdown level will prevent the process from starting, 316 // we have to fail the operation. 317 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_) 318 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER; 319 320 DCHECK(!appcontainer_list_.get()); 321 appcontainer_list_.reset(new AppContainerAttributes); 322 ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_); 323 if (rv != SBOX_ALL_OK) 324 return rv; 325 326 return SBOX_ALL_OK; 327 } 328 329 ResultCode PolicyBase::SetCapability(const wchar_t* sid) { 330 capabilities_.push_back(sid); 331 return SBOX_ALL_OK; 332 } 333 334 ResultCode PolicyBase::SetProcessMitigations( 335 MitigationFlags flags) { 336 if (!CanSetProcessMitigationsPreStartup(flags)) 337 return SBOX_ERROR_BAD_PARAMS; 338 mitigations_ = flags; 339 return SBOX_ALL_OK; 340 } 341 342 MitigationFlags PolicyBase::GetProcessMitigations() { 343 return mitigations_; 344 } 345 346 ResultCode PolicyBase::SetDelayedProcessMitigations( 347 MitigationFlags flags) { 348 if (!CanSetProcessMitigationsPostStartup(flags)) 349 return SBOX_ERROR_BAD_PARAMS; 350 delayed_mitigations_ = flags; 351 return SBOX_ALL_OK; 352 } 353 354 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const { 355 return delayed_mitigations_; 356 } 357 358 void PolicyBase::SetStrictInterceptions() { 359 relaxed_interceptions_ = false; 360 } 361 362 ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) { 363 if (!IsInheritableHandle(handle)) 364 return SBOX_ERROR_BAD_PARAMS; 365 stdout_handle_ = handle; 366 return SBOX_ALL_OK; 367 } 368 369 ResultCode PolicyBase::SetStderrHandle(HANDLE handle) { 370 if (!IsInheritableHandle(handle)) 371 return SBOX_ERROR_BAD_PARAMS; 372 stderr_handle_ = handle; 373 return SBOX_ALL_OK; 374 } 375 376 ResultCode PolicyBase::AddRule(SubSystem subsystem, 377 Semantics semantics, 378 const wchar_t* pattern) { 379 ResultCode result = AddRuleInternal(subsystem, semantics, pattern); 380 LOG_IF(ERROR, result != SBOX_ALL_OK) << "Failed to add sandbox rule." 381 << " error = " << result 382 << ", subsystem = " << subsystem 383 << ", semantics = " << semantics 384 << ", pattern = '" << pattern << "'"; 385 return result; 386 } 387 388 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) { 389 blacklisted_dlls_.push_back(dll_name); 390 return SBOX_ALL_OK; 391 } 392 393 ResultCode PolicyBase::AddKernelObjectToClose(const base::char16* handle_type, 394 const base::char16* handle_name) { 395 return handle_closer_.AddHandle(handle_type, handle_name); 396 } 397 398 // When an IPC is ready in any of the targets we get called. We manage an array 399 // of IPC dispatchers which are keyed on the IPC tag so we normally delegate 400 // to the appropriate dispatcher unless we can handle the IPC call ourselves. 401 Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc, 402 CallbackGeneric* callback) { 403 DCHECK(callback); 404 static const IPCParams ping1 = {IPC_PING1_TAG, ULONG_TYPE}; 405 static const IPCParams ping2 = {IPC_PING2_TAG, INOUTPTR_TYPE}; 406 407 if (ping1.Matches(ipc) || ping2.Matches(ipc)) { 408 *callback = reinterpret_cast<CallbackGeneric>( 409 static_cast<Callback1>(&PolicyBase::Ping)); 410 return this; 411 } 412 413 Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag); 414 if (!dispatch) { 415 NOTREACHED(); 416 return NULL; 417 } 418 return dispatch->OnMessageReady(ipc, callback); 419 } 420 421 // Delegate to the appropriate dispatcher. 422 bool PolicyBase::SetupService(InterceptionManager* manager, int service) { 423 if (IPC_PING1_TAG == service || IPC_PING2_TAG == service) 424 return true; 425 426 Dispatcher* dispatch = GetDispatcher(service); 427 if (!dispatch) { 428 NOTREACHED(); 429 return false; 430 } 431 return dispatch->SetupService(manager, service); 432 } 433 434 ResultCode PolicyBase::MakeJobObject(HANDLE* job) { 435 if (job_level_ != JOB_NONE) { 436 // Create the windows job object. 437 Job job_obj; 438 DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_, 439 memory_limit_); 440 if (ERROR_SUCCESS != result) { 441 return SBOX_ERROR_GENERIC; 442 } 443 *job = job_obj.Detach(); 444 } else { 445 *job = NULL; 446 } 447 return SBOX_ALL_OK; 448 } 449 450 ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) { 451 // Create the 'naked' token. This will be the permanent token associated 452 // with the process and therefore with any thread that is not impersonating. 453 DWORD result = CreateRestrictedToken(lockdown, lockdown_level_, 454 integrity_level_, PRIMARY); 455 if (ERROR_SUCCESS != result) 456 return SBOX_ERROR_GENERIC; 457 458 // If we're launching on the alternate desktop we need to make sure the 459 // integrity label on the object is no higher than the sandboxed process's 460 // integrity level. So, we lower the label on the desktop process if it's 461 // not already low enough for our process. 462 if (alternate_desktop_handle_ && use_alternate_desktop_ && 463 integrity_level_ != INTEGRITY_LEVEL_LAST && 464 alternate_desktop_integrity_level_label_ < integrity_level_ && 465 base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) { 466 // Integrity label enum is reversed (higher level is a lower value). 467 static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED, 468 "Integrity level ordering reversed."); 469 result = SetObjectIntegrityLabel(alternate_desktop_handle_, 470 SE_WINDOW_OBJECT, 471 L"", 472 GetIntegrityLevelString(integrity_level_)); 473 if (ERROR_SUCCESS != result) 474 return SBOX_ERROR_GENERIC; 475 476 alternate_desktop_integrity_level_label_ = integrity_level_; 477 } 478 479 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) { 480 // Windows refuses to work with an impersonation token. See SetAppContainer 481 // implementation for more details. 482 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_) 483 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER; 484 485 *initial = INVALID_HANDLE_VALUE; 486 return SBOX_ALL_OK; 487 } 488 489 // Create the 'better' token. We use this token as the one that the main 490 // thread uses when booting up the process. It should contain most of 491 // what we need (before reaching main( )) 492 result = CreateRestrictedToken(initial, initial_level_, 493 integrity_level_, IMPERSONATION); 494 if (ERROR_SUCCESS != result) { 495 ::CloseHandle(*lockdown); 496 return SBOX_ERROR_GENERIC; 497 } 498 return SBOX_ALL_OK; 499 } 500 501 const AppContainerAttributes* PolicyBase::GetAppContainer() { 502 if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer()) 503 return NULL; 504 505 return appcontainer_list_.get(); 506 } 507 508 bool PolicyBase::AddTarget(TargetProcess* target) { 509 if (NULL != policy_) 510 policy_maker_->Done(); 511 512 if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(), 513 mitigations_)) { 514 return false; 515 } 516 517 if (!SetupAllInterceptions(target)) 518 return false; 519 520 if (!SetupHandleCloser(target)) 521 return false; 522 523 // Initialize the sandbox infrastructure for the target. 524 if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize)) 525 return false; 526 527 g_shared_delayed_integrity_level = delayed_integrity_level_; 528 ResultCode ret = target->TransferVariable( 529 "g_shared_delayed_integrity_level", 530 &g_shared_delayed_integrity_level, 531 sizeof(g_shared_delayed_integrity_level)); 532 g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST; 533 if (SBOX_ALL_OK != ret) 534 return false; 535 536 // Add in delayed mitigations and pseudo-mitigations enforced at startup. 537 g_shared_delayed_mitigations = delayed_mitigations_ | 538 FilterPostStartupProcessMitigations(mitigations_); 539 if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations)) 540 return false; 541 542 ret = target->TransferVariable("g_shared_delayed_mitigations", 543 &g_shared_delayed_mitigations, 544 sizeof(g_shared_delayed_mitigations)); 545 g_shared_delayed_mitigations = 0; 546 if (SBOX_ALL_OK != ret) 547 return false; 548 549 AutoLock lock(&lock_); 550 targets_.push_back(target); 551 return true; 552 } 553 554 bool PolicyBase::OnJobEmpty(HANDLE job) { 555 AutoLock lock(&lock_); 556 TargetSet::iterator it; 557 for (it = targets_.begin(); it != targets_.end(); ++it) { 558 if ((*it)->Job() == job) 559 break; 560 } 561 if (it == targets_.end()) { 562 return false; 563 } 564 TargetProcess* target = *it; 565 targets_.erase(it); 566 delete target; 567 return true; 568 } 569 570 EvalResult PolicyBase::EvalPolicy(int service, 571 CountedParameterSetBase* params) { 572 if (NULL != policy_) { 573 if (NULL == policy_->entry[service]) { 574 // There is no policy for this particular service. This is not a big 575 // deal. 576 return DENY_ACCESS; 577 } 578 for (int i = 0; i < params->count; i++) { 579 if (!params->parameters[i].IsValid()) { 580 NOTREACHED(); 581 return SIGNAL_ALARM; 582 } 583 } 584 PolicyProcessor pol_evaluator(policy_->entry[service]); 585 PolicyResult result = pol_evaluator.Evaluate(kShortEval, 586 params->parameters, 587 params->count); 588 if (POLICY_MATCH == result) { 589 return pol_evaluator.GetAction(); 590 } 591 DCHECK(POLICY_ERROR != result); 592 } 593 594 return DENY_ACCESS; 595 } 596 597 HANDLE PolicyBase::GetStdoutHandle() { 598 return stdout_handle_; 599 } 600 601 HANDLE PolicyBase::GetStderrHandle() { 602 return stderr_handle_; 603 } 604 605 // We service IPC_PING_TAG message which is a way to test a round trip of the 606 // IPC subsystem. We receive a integer cookie and we are expected to return the 607 // cookie times two (or three) and the current tick count. 608 bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) { 609 switch (ipc->ipc_tag) { 610 case IPC_PING1_TAG: { 611 IPCInt ipc_int(arg1); 612 uint32 cookie = ipc_int.As32Bit(); 613 ipc->return_info.extended_count = 2; 614 ipc->return_info.extended[0].unsigned_int = ::GetTickCount(); 615 ipc->return_info.extended[1].unsigned_int = 2 * cookie; 616 return true; 617 } 618 case IPC_PING2_TAG: { 619 CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1); 620 if (sizeof(uint32) != io_buffer->Size()) 621 return false; 622 623 uint32* cookie = reinterpret_cast<uint32*>(io_buffer->Buffer()); 624 *cookie = (*cookie) * 3; 625 return true; 626 } 627 default: return false; 628 } 629 } 630 631 Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) { 632 if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG) 633 return NULL; 634 635 return ipc_targets_[ipc_tag]; 636 } 637 638 bool PolicyBase::SetupAllInterceptions(TargetProcess* target) { 639 InterceptionManager manager(target, relaxed_interceptions_); 640 641 if (policy_) { 642 for (int i = 0; i < IPC_LAST_TAG; i++) { 643 if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i)) 644 return false; 645 } 646 } 647 648 if (!blacklisted_dlls_.empty()) { 649 std::vector<base::string16>::iterator it = blacklisted_dlls_.begin(); 650 for (; it != blacklisted_dlls_.end(); ++it) { 651 manager.AddToUnloadModules(it->c_str()); 652 } 653 } 654 655 if (!SetupBasicInterceptions(&manager)) 656 return false; 657 658 if (!manager.InitializeInterceptions()) 659 return false; 660 661 // Finally, setup imports on the target so the interceptions can work. 662 return SetupNtdllImports(target); 663 } 664 665 bool PolicyBase::SetupHandleCloser(TargetProcess* target) { 666 return handle_closer_.InitializeTargetHandles(target); 667 } 668 669 ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem, 670 Semantics semantics, 671 const wchar_t* pattern) { 672 if (NULL == policy_) { 673 policy_ = MakeBrokerPolicyMemory(); 674 DCHECK(policy_); 675 policy_maker_ = new LowLevelPolicy(policy_); 676 DCHECK(policy_maker_); 677 } 678 679 switch (subsystem) { 680 case SUBSYS_FILES: { 681 if (!file_system_init_) { 682 if (!FileSystemPolicy::SetInitialRules(policy_maker_)) 683 return SBOX_ERROR_BAD_PARAMS; 684 file_system_init_ = true; 685 } 686 if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) { 687 NOTREACHED(); 688 return SBOX_ERROR_BAD_PARAMS; 689 } 690 break; 691 } 692 case SUBSYS_SYNC: { 693 if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) { 694 NOTREACHED(); 695 return SBOX_ERROR_BAD_PARAMS; 696 } 697 break; 698 } 699 case SUBSYS_PROCESS: { 700 if (lockdown_level_ < USER_INTERACTIVE && 701 TargetPolicy::PROCESS_ALL_EXEC == semantics) { 702 // This is unsupported. This is a huge security risk to give full access 703 // to a process handle. 704 return SBOX_ERROR_UNSUPPORTED; 705 } 706 if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) { 707 NOTREACHED(); 708 return SBOX_ERROR_BAD_PARAMS; 709 } 710 break; 711 } 712 case SUBSYS_NAMED_PIPES: { 713 if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) { 714 NOTREACHED(); 715 return SBOX_ERROR_BAD_PARAMS; 716 } 717 break; 718 } 719 case SUBSYS_REGISTRY: { 720 if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) { 721 NOTREACHED(); 722 return SBOX_ERROR_BAD_PARAMS; 723 } 724 break; 725 } 726 case SUBSYS_HANDLES: { 727 if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) { 728 NOTREACHED(); 729 return SBOX_ERROR_BAD_PARAMS; 730 } 731 break; 732 } 733 734 case SUBSYS_WIN32K_LOCKDOWN: { 735 if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules( 736 pattern, semantics, policy_maker_)) { 737 NOTREACHED(); 738 return SBOX_ERROR_BAD_PARAMS; 739 } 740 break; 741 } 742 743 default: { return SBOX_ERROR_UNSUPPORTED; } 744 } 745 746 return SBOX_ALL_OK; 747 } 748 749 } // namespace sandbox 750