• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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