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.
MakeBrokerPolicyMemory()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
IsInheritableHandle(HANDLE handle)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
PolicyBase()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
~PolicyBase()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
AddRef()158 void PolicyBase::AddRef() {
159 ::InterlockedIncrement(&ref_count);
160 }
161
Release()162 void PolicyBase::Release() {
163 if (0 == ::InterlockedDecrement(&ref_count))
164 delete this;
165 }
166
SetTokenLevel(TokenLevel initial,TokenLevel lockdown)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
GetInitialTokenLevel() const176 TokenLevel PolicyBase::GetInitialTokenLevel() const {
177 return initial_level_;
178 }
179
GetLockdownTokenLevel() const180 TokenLevel PolicyBase::GetLockdownTokenLevel() const{
181 return lockdown_level_;
182 }
183
SetJobLevel(JobLevel job_level,uint32 ui_exceptions)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
SetJobMemoryLimit(size_t memory_limit)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
SetAlternateDesktop(bool alternate_winstation)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
GetAlternateDesktop() const207 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
CreateAlternateDesktop(bool alternate_winstation)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
DestroyAlternateDesktop()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
SetIntegrityLevel(IntegrityLevel integrity_level)294 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
295 integrity_level_ = integrity_level;
296 return SBOX_ALL_OK;
297 }
298
GetIntegrityLevel() const299 IntegrityLevel PolicyBase::GetIntegrityLevel() const {
300 return integrity_level_;
301 }
302
SetDelayedIntegrityLevel(IntegrityLevel integrity_level)303 ResultCode PolicyBase::SetDelayedIntegrityLevel(
304 IntegrityLevel integrity_level) {
305 delayed_integrity_level_ = integrity_level;
306 return SBOX_ALL_OK;
307 }
308
SetAppContainer(const wchar_t * sid)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
SetCapability(const wchar_t * sid)329 ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
330 capabilities_.push_back(sid);
331 return SBOX_ALL_OK;
332 }
333
SetProcessMitigations(MitigationFlags flags)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
GetProcessMitigations()342 MitigationFlags PolicyBase::GetProcessMitigations() {
343 return mitigations_;
344 }
345
SetDelayedProcessMitigations(MitigationFlags flags)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
GetDelayedProcessMitigations() const354 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
355 return delayed_mitigations_;
356 }
357
SetStrictInterceptions()358 void PolicyBase::SetStrictInterceptions() {
359 relaxed_interceptions_ = false;
360 }
361
SetStdoutHandle(HANDLE handle)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
SetStderrHandle(HANDLE handle)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
AddRule(SubSystem subsystem,Semantics semantics,const wchar_t * pattern)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
AddDllToUnload(const wchar_t * dll_name)388 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
389 blacklisted_dlls_.push_back(dll_name);
390 return SBOX_ALL_OK;
391 }
392
AddKernelObjectToClose(const base::char16 * handle_type,const base::char16 * handle_name)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.
OnMessageReady(IPCParams * ipc,CallbackGeneric * callback)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.
SetupService(InterceptionManager * manager,int service)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
MakeJobObject(HANDLE * job)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
MakeTokens(HANDLE * initial,HANDLE * lockdown)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
GetAppContainer()501 const AppContainerAttributes* PolicyBase::GetAppContainer() {
502 if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
503 return NULL;
504
505 return appcontainer_list_.get();
506 }
507
AddTarget(TargetProcess * target)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
OnJobEmpty(HANDLE job)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
EvalPolicy(int service,CountedParameterSetBase * params)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
GetStdoutHandle()597 HANDLE PolicyBase::GetStdoutHandle() {
598 return stdout_handle_;
599 }
600
GetStderrHandle()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.
Ping(IPCInfo * ipc,void * arg1)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
GetDispatcher(int ipc_tag)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
SetupAllInterceptions(TargetProcess * target)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
SetupHandleCloser(TargetProcess * target)665 bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
666 return handle_closer_.InitializeTargetHandles(target);
667 }
668
AddRuleInternal(SubSystem subsystem,Semantics semantics,const wchar_t * pattern)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