Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(725)

Side by Side Diff: sandbox/src/sandbox_policy_base.cc

Issue 10689170: Move the Windows sandbox to sandbox/win (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase on top of tree (properly this time) Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sandbox/src/sandbox_policy_base.h ('k') | sandbox/src/sandbox_types.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/src/sandbox_policy_base.h"
6
7 #include "base/basictypes.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "sandbox/src/filesystem_dispatcher.h"
11 #include "sandbox/src/filesystem_policy.h"
12 #include "sandbox/src/handle_dispatcher.h"
13 #include "sandbox/src/handle_policy.h"
14 #include "sandbox/src/job.h"
15 #include "sandbox/src/interception.h"
16 #include "sandbox/src/named_pipe_dispatcher.h"
17 #include "sandbox/src/named_pipe_policy.h"
18 #include "sandbox/src/policy_broker.h"
19 #include "sandbox/src/policy_engine_processor.h"
20 #include "sandbox/src/policy_low_level.h"
21 #include "sandbox/src/process_thread_dispatcher.h"
22 #include "sandbox/src/process_thread_policy.h"
23 #include "sandbox/src/registry_dispatcher.h"
24 #include "sandbox/src/registry_policy.h"
25 #include "sandbox/src/restricted_token_utils.h"
26 #include "sandbox/src/sandbox_policy.h"
27 #include "sandbox/src/sync_dispatcher.h"
28 #include "sandbox/src/sync_policy.h"
29 #include "sandbox/src/target_process.h"
30 #include "sandbox/src/window.h"
31
32 namespace {
33 // The standard windows size for one memory page.
34 const size_t kOneMemPage = 4096;
35 // The IPC and Policy shared memory sizes.
36 const size_t kIPCMemSize = kOneMemPage * 2;
37 const size_t kPolMemSize = kOneMemPage * 14;
38
39 // Helper function to allocate space (on the heap) for policy.
40 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
41 const size_t kTotalPolicySz = kPolMemSize;
42 char* mem = new char[kTotalPolicySz];
43 DCHECK(mem);
44 memset(mem, 0, kTotalPolicySz);
45 sandbox::PolicyGlobal* policy = reinterpret_cast<sandbox::PolicyGlobal*>(mem);
46 policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
47 return policy;
48 }
49 }
50
51 namespace sandbox {
52
53 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
54
55 // Initializes static members.
56 HWINSTA PolicyBase::alternate_winstation_handle_ = NULL;
57 HDESK PolicyBase::alternate_desktop_handle_ = NULL;
58
59 PolicyBase::PolicyBase()
60 : ref_count(1),
61 lockdown_level_(USER_LOCKDOWN),
62 initial_level_(USER_LOCKDOWN),
63 job_level_(JOB_LOCKDOWN),
64 ui_exceptions_(0),
65 use_alternate_desktop_(false),
66 use_alternate_winstation_(false),
67 file_system_init_(false),
68 relaxed_interceptions_(true),
69 integrity_level_(INTEGRITY_LEVEL_LAST),
70 delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
71 policy_maker_(NULL),
72 policy_(NULL) {
73 ::InitializeCriticalSection(&lock_);
74 // Initialize the IPC dispatcher array.
75 memset(&ipc_targets_, NULL, sizeof(ipc_targets_));
76 Dispatcher* dispatcher = NULL;
77
78 dispatcher = new FilesystemDispatcher(this);
79 ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher;
80 ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher;
81 ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher;
82 ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher;
83 ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher;
84
85 dispatcher = new NamedPipeDispatcher(this);
86 ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher;
87
88 dispatcher = new ThreadProcessDispatcher(this);
89 ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher;
90 ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher;
91 ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher;
92 ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher;
93 ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher;
94
95 dispatcher = new SyncDispatcher(this);
96 ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher;
97 ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
98
99 dispatcher = new RegistryDispatcher(this);
100 ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
101 ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
102
103 dispatcher = new HandleDispatcher(this);
104 ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
105 }
106
107 PolicyBase::~PolicyBase() {
108 TargetSet::iterator it;
109 for (it = targets_.begin(); it != targets_.end(); ++it) {
110 TargetProcess* target = (*it);
111 delete target;
112 }
113 delete ipc_targets_[IPC_NTCREATEFILE_TAG];
114 delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG];
115 delete ipc_targets_[IPC_NTOPENTHREAD_TAG];
116 delete ipc_targets_[IPC_CREATEEVENT_TAG];
117 delete ipc_targets_[IPC_NTCREATEKEY_TAG];
118 delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG];
119 delete policy_maker_;
120 delete policy_;
121 ::DeleteCriticalSection(&lock_);
122 }
123
124 void PolicyBase::AddRef() {
125 ::InterlockedIncrement(&ref_count);
126 }
127
128 void PolicyBase::Release() {
129 if (0 == ::InterlockedDecrement(&ref_count))
130 delete this;
131 }
132
133 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
134 if (initial < lockdown) {
135 return SBOX_ERROR_BAD_PARAMS;
136 }
137 initial_level_ = initial;
138 lockdown_level_ = lockdown;
139 return SBOX_ALL_OK;
140 }
141
142 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
143 job_level_ = job_level;
144 ui_exceptions_ = ui_exceptions;
145 return SBOX_ALL_OK;
146 }
147
148 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
149 use_alternate_desktop_ = true;
150 use_alternate_winstation_ = alternate_winstation;
151 return CreateAlternateDesktop(alternate_winstation);
152 }
153
154 std::wstring PolicyBase::GetAlternateDesktop() const {
155 // No alternate desktop or winstation. Return an empty string.
156 if (!use_alternate_desktop_ && !use_alternate_winstation_) {
157 return std::wstring();
158 }
159
160 // The desktop and winstation should have been created by now.
161 // If we hit this scenario, it means that the user ignored the failure
162 // during SetAlternateDesktop, so we ignore it here too.
163 if (use_alternate_desktop_ && !alternate_desktop_handle_) {
164 return std::wstring();
165 }
166 if (use_alternate_winstation_ && (!alternate_desktop_handle_ ||
167 !alternate_winstation_handle_)) {
168 return std::wstring();
169 }
170
171 return GetFullDesktopName(alternate_winstation_handle_,
172 alternate_desktop_handle_);
173 }
174
175 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
176 if (alternate_winstation) {
177 // Previously called with alternate_winstation = false?
178 if (!alternate_winstation_handle_ && alternate_desktop_handle_)
179 return SBOX_ERROR_UNSUPPORTED;
180
181 // Check if it's already created.
182 if (alternate_winstation_handle_ && alternate_desktop_handle_)
183 return SBOX_ALL_OK;
184
185 DCHECK(!alternate_winstation_handle_);
186 // Create the window station.
187 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
188 if (SBOX_ALL_OK != result)
189 return result;
190
191 // Verify that everything is fine.
192 if (!alternate_winstation_handle_ ||
193 GetWindowObjectName(alternate_winstation_handle_).empty())
194 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
195
196 // Create the destkop.
197 result = CreateAltDesktop(alternate_winstation_handle_,
198 &alternate_desktop_handle_);
199 if (SBOX_ALL_OK != result)
200 return result;
201
202 // Verify that everything is fine.
203 if (!alternate_desktop_handle_ ||
204 GetWindowObjectName(alternate_desktop_handle_).empty())
205 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
206 } else {
207 // Previously called with alternate_winstation = true?
208 if (alternate_winstation_handle_)
209 return SBOX_ERROR_UNSUPPORTED;
210
211 // Check if it already exists.
212 if (alternate_desktop_handle_)
213 return SBOX_ALL_OK;
214
215 // Create the destkop.
216 ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_);
217 if (SBOX_ALL_OK != result)
218 return result;
219
220 // Verify that everything is fine.
221 if (!alternate_desktop_handle_ ||
222 GetWindowObjectName(alternate_desktop_handle_).empty())
223 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
224 }
225
226 return SBOX_ALL_OK;
227 }
228
229 void PolicyBase::DestroyAlternateDesktop() {
230 if (alternate_desktop_handle_) {
231 ::CloseDesktop(alternate_desktop_handle_);
232 alternate_desktop_handle_ = NULL;
233 }
234
235 if (alternate_winstation_handle_) {
236 ::CloseWindowStation(alternate_winstation_handle_);
237 alternate_winstation_handle_ = NULL;
238 }
239 }
240
241 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
242 integrity_level_ = integrity_level;
243 return SBOX_ALL_OK;
244 }
245
246 ResultCode PolicyBase::SetDelayedIntegrityLevel(
247 IntegrityLevel integrity_level) {
248 delayed_integrity_level_ = integrity_level;
249 return SBOX_ALL_OK;
250 }
251
252 void PolicyBase::SetStrictInterceptions() {
253 relaxed_interceptions_ = false;
254 }
255
256 ResultCode PolicyBase::AddRule(SubSystem subsystem, Semantics semantics,
257 const wchar_t* pattern) {
258 if (NULL == policy_) {
259 policy_ = MakeBrokerPolicyMemory();
260 DCHECK(policy_);
261 policy_maker_ = new LowLevelPolicy(policy_);
262 DCHECK(policy_maker_);
263 }
264
265 switch (subsystem) {
266 case SUBSYS_FILES: {
267 if (!file_system_init_) {
268 if (!FileSystemPolicy::SetInitialRules(policy_maker_))
269 return SBOX_ERROR_BAD_PARAMS;
270 file_system_init_ = true;
271 }
272 if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
273 NOTREACHED();
274 return SBOX_ERROR_BAD_PARAMS;
275 }
276 break;
277 }
278 case SUBSYS_SYNC: {
279 if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
280 NOTREACHED();
281 return SBOX_ERROR_BAD_PARAMS;
282 }
283 break;
284 }
285 case SUBSYS_PROCESS: {
286 if (lockdown_level_ < USER_INTERACTIVE &&
287 TargetPolicy::PROCESS_ALL_EXEC == semantics) {
288 // This is unsupported. This is a huge security risk to give full access
289 // to a process handle.
290 return SBOX_ERROR_UNSUPPORTED;
291 }
292 if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
293 NOTREACHED();
294 return SBOX_ERROR_BAD_PARAMS;
295 }
296 break;
297 }
298 case SUBSYS_NAMED_PIPES: {
299 if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
300 NOTREACHED();
301 return SBOX_ERROR_BAD_PARAMS;
302 }
303 break;
304 }
305 case SUBSYS_REGISTRY: {
306 if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
307 NOTREACHED();
308 return SBOX_ERROR_BAD_PARAMS;
309 }
310 break;
311 }
312 case SUBSYS_HANDLES: {
313 if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
314 NOTREACHED();
315 return SBOX_ERROR_BAD_PARAMS;
316 }
317 break;
318 }
319 default: {
320 return SBOX_ERROR_UNSUPPORTED;
321 }
322 }
323
324 return SBOX_ALL_OK;
325 }
326
327 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
328 blacklisted_dlls_.push_back(std::wstring(dll_name));
329 return SBOX_ALL_OK;
330 }
331
332 ResultCode PolicyBase::AddKernelObjectToClose(const char16* handle_type,
333 const char16* handle_name) {
334 return handle_closer_.AddHandle(handle_type, handle_name);
335 }
336
337 // When an IPC is ready in any of the targets we get called. We manage an array
338 // of IPC dispatchers which are keyed on the IPC tag so we normally delegate
339 // to the appropriate dispatcher unless we can handle the IPC call ourselves.
340 Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc,
341 CallbackGeneric* callback) {
342 DCHECK(callback);
343 static const IPCParams ping1 = {IPC_PING1_TAG, ULONG_TYPE};
344 static const IPCParams ping2 = {IPC_PING2_TAG, INOUTPTR_TYPE};
345
346 if (ping1.Matches(ipc) || ping2.Matches(ipc)) {
347 *callback = reinterpret_cast<CallbackGeneric>(
348 static_cast<Callback1>(&PolicyBase::Ping));
349 return this;
350 }
351
352 Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag);
353 if (!dispatch) {
354 NOTREACHED();
355 return NULL;
356 }
357 return dispatch->OnMessageReady(ipc, callback);
358 }
359
360 // Delegate to the appropriate dispatcher.
361 bool PolicyBase::SetupService(InterceptionManager* manager, int service) {
362 if (IPC_PING1_TAG == service || IPC_PING2_TAG == service)
363 return true;
364
365 Dispatcher* dispatch = GetDispatcher(service);
366 if (!dispatch) {
367 NOTREACHED();
368 return false;
369 }
370 return dispatch->SetupService(manager, service);
371 }
372
373 DWORD PolicyBase::MakeJobObject(HANDLE* job) {
374 // Create the windows job object.
375 Job job_obj;
376 DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_);
377 if (ERROR_SUCCESS != result) {
378 return result;
379 }
380 *job = job_obj.Detach();
381 return ERROR_SUCCESS;
382 }
383
384 DWORD PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
385 // Create the 'naked' token. This will be the permanent token associated
386 // with the process and therefore with any thread that is not impersonating.
387 DWORD result = CreateRestrictedToken(lockdown, lockdown_level_,
388 integrity_level_, PRIMARY);
389 if (ERROR_SUCCESS != result) {
390 return result;
391 }
392 // Create the 'better' token. We use this token as the one that the main
393 // thread uses when booting up the process. It should contain most of
394 // what we need (before reaching main( ))
395 result = CreateRestrictedToken(initial, initial_level_,
396 integrity_level_, IMPERSONATION);
397 if (ERROR_SUCCESS != result) {
398 ::CloseHandle(*lockdown);
399 return result;
400 }
401 return SBOX_ALL_OK;
402 }
403
404 bool PolicyBase::AddTarget(TargetProcess* target) {
405 if (NULL != policy_)
406 policy_maker_->Done();
407
408 if (!SetupAllInterceptions(target))
409 return false;
410
411 if (!SetupHandleCloser(target))
412 return false;
413
414 // Initialize the sandbox infrastructure for the target.
415 if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize))
416 return false;
417
418 g_shared_delayed_integrity_level = delayed_integrity_level_;
419 ResultCode ret = target->TransferVariable(
420 "g_shared_delayed_integrity_level",
421 &g_shared_delayed_integrity_level,
422 sizeof(g_shared_delayed_integrity_level));
423 g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
424 if (SBOX_ALL_OK != ret)
425 return false;
426
427 AutoLock lock(&lock_);
428 targets_.push_back(target);
429 return true;
430 }
431
432 bool PolicyBase::OnJobEmpty(HANDLE job) {
433 AutoLock lock(&lock_);
434 TargetSet::iterator it;
435 for (it = targets_.begin(); it != targets_.end(); ++it) {
436 if ((*it)->Job() == job)
437 break;
438 }
439 if (it == targets_.end()) {
440 return false;
441 }
442 TargetProcess* target = *it;
443 targets_.erase(it);
444 delete target;
445 return true;
446 }
447
448 EvalResult PolicyBase::EvalPolicy(int service,
449 CountedParameterSetBase* params) {
450 if (NULL != policy_) {
451 if (NULL == policy_->entry[service]) {
452 // There is no policy for this particular service. This is not a big
453 // deal.
454 return DENY_ACCESS;
455 }
456 for (int i = 0; i < params->count; i++) {
457 if (!params->parameters[i].IsValid()) {
458 NOTREACHED();
459 return SIGNAL_ALARM;
460 }
461 }
462 PolicyProcessor pol_evaluator(policy_->entry[service]);
463 PolicyResult result = pol_evaluator.Evaluate(kShortEval,
464 params->parameters,
465 params->count);
466 if (POLICY_MATCH == result) {
467 return pol_evaluator.GetAction();
468 }
469 DCHECK(POLICY_ERROR != result);
470 }
471
472 return DENY_ACCESS;
473 }
474
475 // We service IPC_PING_TAG message which is a way to test a round trip of the
476 // IPC subsystem. We receive a integer cookie and we are expected to return the
477 // cookie times two (or three) and the current tick count.
478 bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) {
479 switch (ipc->ipc_tag) {
480 case IPC_PING1_TAG: {
481 IPCInt ipc_int(arg1);
482 uint32 cookie = ipc_int.As32Bit();
483 ipc->return_info.extended_count = 2;
484 ipc->return_info.extended[0].unsigned_int = ::GetTickCount();
485 ipc->return_info.extended[1].unsigned_int = 2 * cookie;
486 return true;
487 }
488 case IPC_PING2_TAG: {
489 CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1);
490 if (sizeof(uint32) != io_buffer->Size())
491 return false;
492
493 uint32* cookie = reinterpret_cast<uint32*>(io_buffer->Buffer());
494 *cookie = (*cookie) * 3;
495 return true;
496 }
497 default: return false;
498 }
499 }
500
501 Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) {
502 if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG)
503 return NULL;
504
505 return ipc_targets_[ipc_tag];
506 }
507
508 bool PolicyBase::SetupAllInterceptions(TargetProcess* target) {
509 InterceptionManager manager(target, relaxed_interceptions_);
510
511 if (policy_) {
512 for (int i = 0; i < IPC_LAST_TAG; i++) {
513 if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i))
514 return false;
515 }
516 }
517
518 if (!blacklisted_dlls_.empty()) {
519 std::vector<std::wstring>::iterator it = blacklisted_dlls_.begin();
520 for (; it != blacklisted_dlls_.end(); ++it) {
521 manager.AddToUnloadModules(it->c_str());
522 }
523 }
524
525 if (!handle_closer_.SetupHandleInterceptions(&manager))
526 return false;
527
528 if (!SetupBasicInterceptions(&manager))
529 return false;
530
531 if (!manager.InitializeInterceptions())
532 return false;
533
534 // Finally, setup imports on the target so the interceptions can work.
535 return SetupNtdllImports(target);
536 }
537
538 bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
539 return handle_closer_.InitializeTargetHandles(target);
540 }
541
542 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/src/sandbox_policy_base.h ('k') | sandbox/src/sandbox_types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698