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

mercurial