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
39namespace {
40
41// The standard windows size for one memory page.
42const size_t kOneMemPage = 4096;
43// The IPC and Policy shared memory sizes.
44const size_t kIPCMemSize = kOneMemPage * 2;
45const size_t kPolMemSize = kOneMemPage * 14;
46
47// Helper function to allocate space (on the heap) for policy.
48sandbox::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
58bool 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
72namespace sandbox {
73
74SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
75SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
76
77// Initializes static members.
78HWINSTA PolicyBase::alternate_winstation_handle_ = NULL;
79HDESK PolicyBase::alternate_desktop_handle_ = NULL;
80IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
81    INTEGRITY_LEVEL_SYSTEM;
82
83PolicyBase::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
141PolicyBase::~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
158void PolicyBase::AddRef() {
159  ::InterlockedIncrement(&ref_count);
160}
161
162void PolicyBase::Release() {
163  if (0 == ::InterlockedDecrement(&ref_count))
164    delete this;
165}
166
167ResultCode 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
176TokenLevel PolicyBase::GetInitialTokenLevel() const {
177  return initial_level_;
178}
179
180TokenLevel PolicyBase::GetLockdownTokenLevel() const{
181  return lockdown_level_;
182}
183
184ResultCode 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
193ResultCode 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
201ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
202  use_alternate_desktop_ = true;
203  use_alternate_winstation_ = alternate_winstation;
204  return CreateAlternateDesktop(alternate_winstation);
205}
206
207base::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
228ResultCode 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
282void 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
294ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
295  integrity_level_ = integrity_level;
296  return SBOX_ALL_OK;
297}
298
299IntegrityLevel PolicyBase::GetIntegrityLevel() const {
300  return integrity_level_;
301}
302
303ResultCode PolicyBase::SetDelayedIntegrityLevel(
304    IntegrityLevel integrity_level) {
305  delayed_integrity_level_ = integrity_level;
306  return SBOX_ALL_OK;
307}
308
309ResultCode 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
329ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
330  capabilities_.push_back(sid);
331  return SBOX_ALL_OK;
332}
333
334ResultCode 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
342MitigationFlags PolicyBase::GetProcessMitigations() {
343  return mitigations_;
344}
345
346ResultCode 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
354MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
355  return delayed_mitigations_;
356}
357
358void PolicyBase::SetStrictInterceptions() {
359  relaxed_interceptions_ = false;
360}
361
362ResultCode 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
369ResultCode 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
376ResultCode 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
388ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
389  blacklisted_dlls_.push_back(dll_name);
390  return SBOX_ALL_OK;
391}
392
393ResultCode 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.
401Dispatcher* 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.
422bool 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
434ResultCode 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
450ResultCode 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
501const AppContainerAttributes* PolicyBase::GetAppContainer() {
502  if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
503    return NULL;
504
505  return appcontainer_list_.get();
506}
507
508bool 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
554bool 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
570EvalResult 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
597HANDLE PolicyBase::GetStdoutHandle() {
598  return stdout_handle_;
599}
600
601HANDLE 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.
608bool 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
631Dispatcher* 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
638bool 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
665bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
666  return handle_closer_.InitializeTargetHandles(target);
667}
668
669ResultCode 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