OLD | NEW |
| (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/win/src/sandbox_policy_base.h" | |
6 | |
7 #include <sddl.h> | |
8 #include <stddef.h> | |
9 #include <stdint.h> | |
10 | |
11 #include "base/callback.h" | |
12 #include "base/logging.h" | |
13 #include "base/macros.h" | |
14 #include "base/stl_util.h" | |
15 #include "base/strings/stringprintf.h" | |
16 #include "base/win/windows_version.h" | |
17 #include "sandbox/win/src/app_container.h" | |
18 #include "sandbox/win/src/filesystem_policy.h" | |
19 #include "sandbox/win/src/handle_policy.h" | |
20 #include "sandbox/win/src/interception.h" | |
21 #include "sandbox/win/src/job.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.h" | |
27 #include "sandbox/win/src/process_mitigations_win32k_policy.h" | |
28 #include "sandbox/win/src/process_thread_policy.h" | |
29 #include "sandbox/win/src/registry_policy.h" | |
30 #include "sandbox/win/src/restricted_token_utils.h" | |
31 #include "sandbox/win/src/sandbox_policy.h" | |
32 #include "sandbox/win/src/sandbox_utils.h" | |
33 #include "sandbox/win/src/sync_policy.h" | |
34 #include "sandbox/win/src/target_process.h" | |
35 #include "sandbox/win/src/top_level_dispatcher.h" | |
36 #include "sandbox/win/src/window.h" | |
37 | |
38 namespace { | |
39 | |
40 // The standard windows size for one memory page. | |
41 const size_t kOneMemPage = 4096; | |
42 // The IPC and Policy shared memory sizes. | |
43 const size_t kIPCMemSize = kOneMemPage * 2; | |
44 const size_t kPolMemSize = kOneMemPage * 14; | |
45 | |
46 // Helper function to allocate space (on the heap) for policy. | |
47 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() { | |
48 const size_t kTotalPolicySz = kPolMemSize; | |
49 sandbox::PolicyGlobal* policy = static_cast<sandbox::PolicyGlobal*> | |
50 (::operator new(kTotalPolicySz)); | |
51 DCHECK(policy); | |
52 memset(policy, 0, kTotalPolicySz); | |
53 policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal); | |
54 return policy; | |
55 } | |
56 | |
57 bool IsInheritableHandle(HANDLE handle) { | |
58 if (!handle) | |
59 return false; | |
60 if (handle == INVALID_HANDLE_VALUE) | |
61 return false; | |
62 // File handles (FILE_TYPE_DISK) and pipe handles are known to be | |
63 // inheritable. Console handles (FILE_TYPE_CHAR) are not | |
64 // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST. | |
65 DWORD handle_type = GetFileType(handle); | |
66 return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE; | |
67 } | |
68 | |
69 HANDLE CreateLowBoxObjectDirectory(PSID lowbox_sid) { | |
70 DWORD session_id = 0; | |
71 if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) | |
72 return NULL; | |
73 | |
74 LPWSTR sid_string = NULL; | |
75 if (!::ConvertSidToStringSid(lowbox_sid, &sid_string)) | |
76 return NULL; | |
77 | |
78 base::string16 directory_path = base::StringPrintf( | |
79 L"\\Sessions\\%d\\AppContainerNamedObjects\\%ls", | |
80 session_id, sid_string).c_str(); | |
81 ::LocalFree(sid_string); | |
82 | |
83 NtCreateDirectoryObjectFunction CreateObjectDirectory = NULL; | |
84 ResolveNTFunctionPtr("NtCreateDirectoryObject", &CreateObjectDirectory); | |
85 | |
86 OBJECT_ATTRIBUTES obj_attr; | |
87 UNICODE_STRING obj_name; | |
88 sandbox::InitObjectAttribs(directory_path, | |
89 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, | |
90 NULL, | |
91 &obj_attr, | |
92 &obj_name, | |
93 NULL); | |
94 | |
95 HANDLE handle = NULL; | |
96 NTSTATUS status = CreateObjectDirectory(&handle, | |
97 DIRECTORY_ALL_ACCESS, | |
98 &obj_attr); | |
99 | |
100 if (!NT_SUCCESS(status)) | |
101 return NULL; | |
102 | |
103 return handle; | |
104 } | |
105 | |
106 } // namespace | |
107 | |
108 namespace sandbox { | |
109 | |
110 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level; | |
111 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations; | |
112 | |
113 // Initializes static members. | |
114 HWINSTA PolicyBase::alternate_winstation_handle_ = NULL; | |
115 HDESK PolicyBase::alternate_desktop_handle_ = NULL; | |
116 IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ = | |
117 INTEGRITY_LEVEL_SYSTEM; | |
118 | |
119 PolicyBase::PolicyBase() | |
120 : ref_count(1), | |
121 lockdown_level_(USER_LOCKDOWN), | |
122 initial_level_(USER_LOCKDOWN), | |
123 job_level_(JOB_LOCKDOWN), | |
124 ui_exceptions_(0), | |
125 memory_limit_(0), | |
126 use_alternate_desktop_(false), | |
127 use_alternate_winstation_(false), | |
128 file_system_init_(false), | |
129 relaxed_interceptions_(true), | |
130 stdout_handle_(INVALID_HANDLE_VALUE), | |
131 stderr_handle_(INVALID_HANDLE_VALUE), | |
132 integrity_level_(INTEGRITY_LEVEL_LAST), | |
133 delayed_integrity_level_(INTEGRITY_LEVEL_LAST), | |
134 mitigations_(0), | |
135 delayed_mitigations_(0), | |
136 is_csrss_connected_(true), | |
137 policy_maker_(NULL), | |
138 policy_(NULL), | |
139 lowbox_sid_(NULL), | |
140 lockdown_default_dacl_(false) { | |
141 ::InitializeCriticalSection(&lock_); | |
142 dispatcher_.reset(new TopLevelDispatcher(this)); | |
143 } | |
144 | |
145 PolicyBase::~PolicyBase() { | |
146 TargetSet::iterator it; | |
147 for (it = targets_.begin(); it != targets_.end(); ++it) { | |
148 TargetProcess* target = (*it); | |
149 delete target; | |
150 } | |
151 delete policy_maker_; | |
152 delete policy_; | |
153 | |
154 if (lowbox_sid_) | |
155 ::LocalFree(lowbox_sid_); | |
156 | |
157 ::DeleteCriticalSection(&lock_); | |
158 } | |
159 | |
160 void PolicyBase::AddRef() { | |
161 ::InterlockedIncrement(&ref_count); | |
162 } | |
163 | |
164 void PolicyBase::Release() { | |
165 if (0 == ::InterlockedDecrement(&ref_count)) | |
166 delete this; | |
167 } | |
168 | |
169 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) { | |
170 if (initial < lockdown) { | |
171 return SBOX_ERROR_BAD_PARAMS; | |
172 } | |
173 initial_level_ = initial; | |
174 lockdown_level_ = lockdown; | |
175 return SBOX_ALL_OK; | |
176 } | |
177 | |
178 TokenLevel PolicyBase::GetInitialTokenLevel() const { | |
179 return initial_level_; | |
180 } | |
181 | |
182 TokenLevel PolicyBase::GetLockdownTokenLevel() const { | |
183 return lockdown_level_; | |
184 } | |
185 | |
186 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) { | |
187 if (memory_limit_ && job_level == JOB_NONE) { | |
188 return SBOX_ERROR_BAD_PARAMS; | |
189 } | |
190 job_level_ = job_level; | |
191 ui_exceptions_ = ui_exceptions; | |
192 return SBOX_ALL_OK; | |
193 } | |
194 | |
195 JobLevel PolicyBase::GetJobLevel() const { | |
196 return job_level_; | |
197 } | |
198 | |
199 ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) { | |
200 if (memory_limit && job_level_ == JOB_NONE) { | |
201 return SBOX_ERROR_BAD_PARAMS; | |
202 } | |
203 memory_limit_ = memory_limit; | |
204 return SBOX_ALL_OK; | |
205 } | |
206 | |
207 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) { | |
208 use_alternate_desktop_ = true; | |
209 use_alternate_winstation_ = alternate_winstation; | |
210 return CreateAlternateDesktop(alternate_winstation); | |
211 } | |
212 | |
213 base::string16 PolicyBase::GetAlternateDesktop() const { | |
214 // No alternate desktop or winstation. Return an empty string. | |
215 if (!use_alternate_desktop_ && !use_alternate_winstation_) { | |
216 return base::string16(); | |
217 } | |
218 | |
219 // The desktop and winstation should have been created by now. | |
220 // If we hit this scenario, it means that the user ignored the failure | |
221 // during SetAlternateDesktop, so we ignore it here too. | |
222 if (use_alternate_desktop_ && !alternate_desktop_handle_) { | |
223 return base::string16(); | |
224 } | |
225 if (use_alternate_winstation_ && (!alternate_desktop_handle_ || | |
226 !alternate_winstation_handle_)) { | |
227 return base::string16(); | |
228 } | |
229 | |
230 return GetFullDesktopName(alternate_winstation_handle_, | |
231 alternate_desktop_handle_); | |
232 } | |
233 | |
234 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) { | |
235 if (alternate_winstation) { | |
236 // Previously called with alternate_winstation = false? | |
237 if (!alternate_winstation_handle_ && alternate_desktop_handle_) | |
238 return SBOX_ERROR_UNSUPPORTED; | |
239 | |
240 // Check if it's already created. | |
241 if (alternate_winstation_handle_ && alternate_desktop_handle_) | |
242 return SBOX_ALL_OK; | |
243 | |
244 DCHECK(!alternate_winstation_handle_); | |
245 // Create the window station. | |
246 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_); | |
247 if (SBOX_ALL_OK != result) | |
248 return result; | |
249 | |
250 // Verify that everything is fine. | |
251 if (!alternate_winstation_handle_ || | |
252 GetWindowObjectName(alternate_winstation_handle_).empty()) | |
253 return SBOX_ERROR_CANNOT_CREATE_DESKTOP; | |
254 | |
255 // Create the destkop. | |
256 result = CreateAltDesktop(alternate_winstation_handle_, | |
257 &alternate_desktop_handle_); | |
258 if (SBOX_ALL_OK != result) | |
259 return result; | |
260 | |
261 // Verify that everything is fine. | |
262 if (!alternate_desktop_handle_ || | |
263 GetWindowObjectName(alternate_desktop_handle_).empty()) | |
264 return SBOX_ERROR_CANNOT_CREATE_DESKTOP; | |
265 } else { | |
266 // Previously called with alternate_winstation = true? | |
267 if (alternate_winstation_handle_) | |
268 return SBOX_ERROR_UNSUPPORTED; | |
269 | |
270 // Check if it already exists. | |
271 if (alternate_desktop_handle_) | |
272 return SBOX_ALL_OK; | |
273 | |
274 // Create the destkop. | |
275 ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_); | |
276 if (SBOX_ALL_OK != result) | |
277 return result; | |
278 | |
279 // Verify that everything is fine. | |
280 if (!alternate_desktop_handle_ || | |
281 GetWindowObjectName(alternate_desktop_handle_).empty()) | |
282 return SBOX_ERROR_CANNOT_CREATE_DESKTOP; | |
283 } | |
284 | |
285 return SBOX_ALL_OK; | |
286 } | |
287 | |
288 void PolicyBase::DestroyAlternateDesktop() { | |
289 if (alternate_desktop_handle_) { | |
290 ::CloseDesktop(alternate_desktop_handle_); | |
291 alternate_desktop_handle_ = NULL; | |
292 } | |
293 | |
294 if (alternate_winstation_handle_) { | |
295 ::CloseWindowStation(alternate_winstation_handle_); | |
296 alternate_winstation_handle_ = NULL; | |
297 } | |
298 } | |
299 | |
300 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) { | |
301 integrity_level_ = integrity_level; | |
302 return SBOX_ALL_OK; | |
303 } | |
304 | |
305 IntegrityLevel PolicyBase::GetIntegrityLevel() const { | |
306 return integrity_level_; | |
307 } | |
308 | |
309 ResultCode PolicyBase::SetDelayedIntegrityLevel( | |
310 IntegrityLevel integrity_level) { | |
311 delayed_integrity_level_ = integrity_level; | |
312 return SBOX_ALL_OK; | |
313 } | |
314 | |
315 ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) { | |
316 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8) | |
317 return SBOX_ALL_OK; | |
318 | |
319 // SetLowBox and SetAppContainer are mutually exclusive. | |
320 if (lowbox_sid_) | |
321 return SBOX_ERROR_UNSUPPORTED; | |
322 | |
323 // Windows refuses to work with an impersonation token for a process inside | |
324 // an AppContainer. If the caller wants to use a more privileged initial | |
325 // token, or if the lockdown level will prevent the process from starting, | |
326 // we have to fail the operation. | |
327 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_) | |
328 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER; | |
329 | |
330 DCHECK(!appcontainer_list_.get()); | |
331 appcontainer_list_.reset(new AppContainerAttributes); | |
332 ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_); | |
333 if (rv != SBOX_ALL_OK) | |
334 return rv; | |
335 | |
336 return SBOX_ALL_OK; | |
337 } | |
338 | |
339 ResultCode PolicyBase::SetCapability(const wchar_t* sid) { | |
340 capabilities_.push_back(sid); | |
341 return SBOX_ALL_OK; | |
342 } | |
343 | |
344 ResultCode PolicyBase::SetLowBox(const wchar_t* sid) { | |
345 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8) | |
346 return SBOX_ERROR_UNSUPPORTED; | |
347 | |
348 // SetLowBox and SetAppContainer are mutually exclusive. | |
349 if (appcontainer_list_.get()) | |
350 return SBOX_ERROR_UNSUPPORTED; | |
351 | |
352 DCHECK(sid); | |
353 | |
354 if (lowbox_sid_) | |
355 return SBOX_ERROR_BAD_PARAMS; | |
356 | |
357 if (!ConvertStringSidToSid(sid, &lowbox_sid_)) | |
358 return SBOX_ERROR_GENERIC; | |
359 | |
360 return SBOX_ALL_OK; | |
361 } | |
362 | |
363 ResultCode PolicyBase::SetProcessMitigations( | |
364 MitigationFlags flags) { | |
365 if (!CanSetProcessMitigationsPreStartup(flags)) | |
366 return SBOX_ERROR_BAD_PARAMS; | |
367 mitigations_ = flags; | |
368 return SBOX_ALL_OK; | |
369 } | |
370 | |
371 MitigationFlags PolicyBase::GetProcessMitigations() { | |
372 return mitigations_; | |
373 } | |
374 | |
375 ResultCode PolicyBase::SetDelayedProcessMitigations( | |
376 MitigationFlags flags) { | |
377 if (!CanSetProcessMitigationsPostStartup(flags)) | |
378 return SBOX_ERROR_BAD_PARAMS; | |
379 delayed_mitigations_ = flags; | |
380 return SBOX_ALL_OK; | |
381 } | |
382 | |
383 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const { | |
384 return delayed_mitigations_; | |
385 } | |
386 | |
387 void PolicyBase::SetStrictInterceptions() { | |
388 relaxed_interceptions_ = false; | |
389 } | |
390 | |
391 ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) { | |
392 if (!IsInheritableHandle(handle)) | |
393 return SBOX_ERROR_BAD_PARAMS; | |
394 stdout_handle_ = handle; | |
395 return SBOX_ALL_OK; | |
396 } | |
397 | |
398 ResultCode PolicyBase::SetStderrHandle(HANDLE handle) { | |
399 if (!IsInheritableHandle(handle)) | |
400 return SBOX_ERROR_BAD_PARAMS; | |
401 stderr_handle_ = handle; | |
402 return SBOX_ALL_OK; | |
403 } | |
404 | |
405 ResultCode PolicyBase::AddRule(SubSystem subsystem, | |
406 Semantics semantics, | |
407 const wchar_t* pattern) { | |
408 ResultCode result = AddRuleInternal(subsystem, semantics, pattern); | |
409 LOG_IF(ERROR, result != SBOX_ALL_OK) << "Failed to add sandbox rule." | |
410 << " error = " << result | |
411 << ", subsystem = " << subsystem | |
412 << ", semantics = " << semantics | |
413 << ", pattern = '" << pattern << "'"; | |
414 return result; | |
415 } | |
416 | |
417 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) { | |
418 blacklisted_dlls_.push_back(dll_name); | |
419 return SBOX_ALL_OK; | |
420 } | |
421 | |
422 ResultCode PolicyBase::AddKernelObjectToClose(const base::char16* handle_type, | |
423 const base::char16* handle_name) { | |
424 return handle_closer_.AddHandle(handle_type, handle_name); | |
425 } | |
426 | |
427 void PolicyBase::AddHandleToShare(HANDLE handle) { | |
428 CHECK(handle && handle != INVALID_HANDLE_VALUE); | |
429 | |
430 // Ensure the handle can be inherited. | |
431 BOOL result = SetHandleInformation(handle, HANDLE_FLAG_INHERIT, | |
432 HANDLE_FLAG_INHERIT); | |
433 PCHECK(result); | |
434 | |
435 handles_to_share_.push_back(handle); | |
436 } | |
437 | |
438 void PolicyBase::SetLockdownDefaultDacl() { | |
439 lockdown_default_dacl_ = true; | |
440 } | |
441 | |
442 const base::HandlesToInheritVector& PolicyBase::GetHandlesBeingShared() { | |
443 return handles_to_share_; | |
444 } | |
445 | |
446 ResultCode PolicyBase::MakeJobObject(base::win::ScopedHandle* job) { | |
447 if (job_level_ != JOB_NONE) { | |
448 // Create the windows job object. | |
449 Job job_obj; | |
450 DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_, | |
451 memory_limit_); | |
452 if (ERROR_SUCCESS != result) | |
453 return SBOX_ERROR_GENERIC; | |
454 | |
455 *job = job_obj.Take(); | |
456 } else { | |
457 *job = base::win::ScopedHandle(); | |
458 } | |
459 return SBOX_ALL_OK; | |
460 } | |
461 | |
462 ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial, | |
463 base::win::ScopedHandle* lockdown, | |
464 base::win::ScopedHandle* lowbox) { | |
465 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer() && | |
466 lowbox_sid_) { | |
467 return SBOX_ERROR_BAD_PARAMS; | |
468 } | |
469 | |
470 // Create the 'naked' token. This will be the permanent token associated | |
471 // with the process and therefore with any thread that is not impersonating. | |
472 DWORD result = | |
473 CreateRestrictedToken(lockdown_level_, integrity_level_, PRIMARY, | |
474 lockdown_default_dacl_, lockdown); | |
475 if (ERROR_SUCCESS != result) | |
476 return SBOX_ERROR_GENERIC; | |
477 | |
478 // If we're launching on the alternate desktop we need to make sure the | |
479 // integrity label on the object is no higher than the sandboxed process's | |
480 // integrity level. So, we lower the label on the desktop process if it's | |
481 // not already low enough for our process. | |
482 if (alternate_desktop_handle_ && use_alternate_desktop_ && | |
483 integrity_level_ != INTEGRITY_LEVEL_LAST && | |
484 alternate_desktop_integrity_level_label_ < integrity_level_) { | |
485 // Integrity label enum is reversed (higher level is a lower value). | |
486 static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED, | |
487 "Integrity level ordering reversed."); | |
488 result = SetObjectIntegrityLabel(alternate_desktop_handle_, | |
489 SE_WINDOW_OBJECT, | |
490 L"", | |
491 GetIntegrityLevelString(integrity_level_)); | |
492 if (ERROR_SUCCESS != result) | |
493 return SBOX_ERROR_GENERIC; | |
494 | |
495 alternate_desktop_integrity_level_label_ = integrity_level_; | |
496 } | |
497 | |
498 // We are maintaining two mutually exclusive approaches. One is to start an | |
499 // AppContainer process through StartupInfoEx and other is replacing | |
500 // existing token with LowBox token after process creation. | |
501 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) { | |
502 // Windows refuses to work with an impersonation token. See SetAppContainer | |
503 // implementation for more details. | |
504 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_) | |
505 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER; | |
506 | |
507 *initial = base::win::ScopedHandle(); | |
508 return SBOX_ALL_OK; | |
509 } | |
510 | |
511 if (lowbox_sid_) { | |
512 NtCreateLowBoxToken CreateLowBoxToken = NULL; | |
513 ResolveNTFunctionPtr("NtCreateLowBoxToken", &CreateLowBoxToken); | |
514 OBJECT_ATTRIBUTES obj_attr; | |
515 InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL); | |
516 HANDLE token_lowbox = NULL; | |
517 | |
518 if (!lowbox_directory_.IsValid()) | |
519 lowbox_directory_.Set(CreateLowBoxObjectDirectory(lowbox_sid_)); | |
520 DCHECK(lowbox_directory_.IsValid()); | |
521 | |
522 // The order of handles isn't important in the CreateLowBoxToken call. | |
523 // The kernel will maintain a reference to the object directory handle. | |
524 HANDLE saved_handles[1] = {lowbox_directory_.Get()}; | |
525 DWORD saved_handles_count = lowbox_directory_.IsValid() ? 1 : 0; | |
526 | |
527 NTSTATUS status = CreateLowBoxToken(&token_lowbox, lockdown->Get(), | |
528 TOKEN_ALL_ACCESS, &obj_attr, | |
529 lowbox_sid_, 0, NULL, | |
530 saved_handles_count, saved_handles); | |
531 if (!NT_SUCCESS(status)) | |
532 return SBOX_ERROR_GENERIC; | |
533 | |
534 DCHECK(token_lowbox); | |
535 lowbox->Set(token_lowbox); | |
536 } | |
537 | |
538 // Create the 'better' token. We use this token as the one that the main | |
539 // thread uses when booting up the process. It should contain most of | |
540 // what we need (before reaching main( )) | |
541 result = | |
542 CreateRestrictedToken(initial_level_, integrity_level_, IMPERSONATION, | |
543 lockdown_default_dacl_, initial); | |
544 if (ERROR_SUCCESS != result) | |
545 return SBOX_ERROR_GENERIC; | |
546 | |
547 return SBOX_ALL_OK; | |
548 } | |
549 | |
550 const AppContainerAttributes* PolicyBase::GetAppContainer() const { | |
551 if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer()) | |
552 return NULL; | |
553 | |
554 return appcontainer_list_.get(); | |
555 } | |
556 | |
557 PSID PolicyBase::GetLowBoxSid() const { | |
558 return lowbox_sid_; | |
559 } | |
560 | |
561 bool PolicyBase::AddTarget(TargetProcess* target) { | |
562 if (NULL != policy_) | |
563 policy_maker_->Done(); | |
564 | |
565 if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(), | |
566 mitigations_)) { | |
567 return false; | |
568 } | |
569 | |
570 if (!SetupAllInterceptions(target)) | |
571 return false; | |
572 | |
573 if (!SetupHandleCloser(target)) | |
574 return false; | |
575 | |
576 // Initialize the sandbox infrastructure for the target. | |
577 if (ERROR_SUCCESS != | |
578 target->Init(dispatcher_.get(), policy_, kIPCMemSize, kPolMemSize)) | |
579 return false; | |
580 | |
581 g_shared_delayed_integrity_level = delayed_integrity_level_; | |
582 ResultCode ret = target->TransferVariable( | |
583 "g_shared_delayed_integrity_level", | |
584 &g_shared_delayed_integrity_level, | |
585 sizeof(g_shared_delayed_integrity_level)); | |
586 g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST; | |
587 if (SBOX_ALL_OK != ret) | |
588 return false; | |
589 | |
590 // Add in delayed mitigations and pseudo-mitigations enforced at startup. | |
591 g_shared_delayed_mitigations = delayed_mitigations_ | | |
592 FilterPostStartupProcessMitigations(mitigations_); | |
593 if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations)) | |
594 return false; | |
595 | |
596 ret = target->TransferVariable("g_shared_delayed_mitigations", | |
597 &g_shared_delayed_mitigations, | |
598 sizeof(g_shared_delayed_mitigations)); | |
599 g_shared_delayed_mitigations = 0; | |
600 if (SBOX_ALL_OK != ret) | |
601 return false; | |
602 | |
603 AutoLock lock(&lock_); | |
604 targets_.push_back(target); | |
605 return true; | |
606 } | |
607 | |
608 bool PolicyBase::OnJobEmpty(HANDLE job) { | |
609 AutoLock lock(&lock_); | |
610 TargetSet::iterator it; | |
611 for (it = targets_.begin(); it != targets_.end(); ++it) { | |
612 if ((*it)->Job() == job) | |
613 break; | |
614 } | |
615 if (it == targets_.end()) { | |
616 return false; | |
617 } | |
618 TargetProcess* target = *it; | |
619 targets_.erase(it); | |
620 delete target; | |
621 return true; | |
622 } | |
623 | |
624 void PolicyBase::SetDisconnectCsrss() { | |
625 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { | |
626 is_csrss_connected_ = false; | |
627 AddKernelObjectToClose(L"ALPC Port", NULL); | |
628 } | |
629 } | |
630 | |
631 EvalResult PolicyBase::EvalPolicy(int service, | |
632 CountedParameterSetBase* params) { | |
633 if (NULL != policy_) { | |
634 if (NULL == policy_->entry[service]) { | |
635 // There is no policy for this particular service. This is not a big | |
636 // deal. | |
637 return DENY_ACCESS; | |
638 } | |
639 for (int i = 0; i < params->count; i++) { | |
640 if (!params->parameters[i].IsValid()) { | |
641 NOTREACHED(); | |
642 return SIGNAL_ALARM; | |
643 } | |
644 } | |
645 PolicyProcessor pol_evaluator(policy_->entry[service]); | |
646 PolicyResult result = pol_evaluator.Evaluate(kShortEval, | |
647 params->parameters, | |
648 params->count); | |
649 if (POLICY_MATCH == result) { | |
650 return pol_evaluator.GetAction(); | |
651 } | |
652 DCHECK(POLICY_ERROR != result); | |
653 } | |
654 | |
655 return DENY_ACCESS; | |
656 } | |
657 | |
658 HANDLE PolicyBase::GetStdoutHandle() { | |
659 return stdout_handle_; | |
660 } | |
661 | |
662 HANDLE PolicyBase::GetStderrHandle() { | |
663 return stderr_handle_; | |
664 } | |
665 | |
666 bool PolicyBase::SetupAllInterceptions(TargetProcess* target) { | |
667 InterceptionManager manager(target, relaxed_interceptions_); | |
668 | |
669 if (policy_) { | |
670 for (int i = 0; i < IPC_LAST_TAG; i++) { | |
671 if (policy_->entry[i] && !dispatcher_->SetupService(&manager, i)) | |
672 return false; | |
673 } | |
674 } | |
675 | |
676 if (!blacklisted_dlls_.empty()) { | |
677 std::vector<base::string16>::iterator it = blacklisted_dlls_.begin(); | |
678 for (; it != blacklisted_dlls_.end(); ++it) { | |
679 manager.AddToUnloadModules(it->c_str()); | |
680 } | |
681 } | |
682 | |
683 if (!SetupBasicInterceptions(&manager, is_csrss_connected_)) | |
684 return false; | |
685 | |
686 if (!manager.InitializeInterceptions()) | |
687 return false; | |
688 | |
689 // Finally, setup imports on the target so the interceptions can work. | |
690 return SetupNtdllImports(target); | |
691 } | |
692 | |
693 bool PolicyBase::SetupHandleCloser(TargetProcess* target) { | |
694 return handle_closer_.InitializeTargetHandles(target); | |
695 } | |
696 | |
697 ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem, | |
698 Semantics semantics, | |
699 const wchar_t* pattern) { | |
700 if (NULL == policy_) { | |
701 policy_ = MakeBrokerPolicyMemory(); | |
702 DCHECK(policy_); | |
703 policy_maker_ = new LowLevelPolicy(policy_); | |
704 DCHECK(policy_maker_); | |
705 } | |
706 | |
707 switch (subsystem) { | |
708 case SUBSYS_FILES: { | |
709 if (!file_system_init_) { | |
710 if (!FileSystemPolicy::SetInitialRules(policy_maker_)) | |
711 return SBOX_ERROR_BAD_PARAMS; | |
712 file_system_init_ = true; | |
713 } | |
714 if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) { | |
715 NOTREACHED(); | |
716 return SBOX_ERROR_BAD_PARAMS; | |
717 } | |
718 break; | |
719 } | |
720 case SUBSYS_SYNC: { | |
721 if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) { | |
722 NOTREACHED(); | |
723 return SBOX_ERROR_BAD_PARAMS; | |
724 } | |
725 break; | |
726 } | |
727 case SUBSYS_PROCESS: { | |
728 if (lockdown_level_ < USER_INTERACTIVE && | |
729 TargetPolicy::PROCESS_ALL_EXEC == semantics) { | |
730 // This is unsupported. This is a huge security risk to give full access | |
731 // to a process handle. | |
732 return SBOX_ERROR_UNSUPPORTED; | |
733 } | |
734 if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) { | |
735 NOTREACHED(); | |
736 return SBOX_ERROR_BAD_PARAMS; | |
737 } | |
738 break; | |
739 } | |
740 case SUBSYS_NAMED_PIPES: { | |
741 if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) { | |
742 NOTREACHED(); | |
743 return SBOX_ERROR_BAD_PARAMS; | |
744 } | |
745 break; | |
746 } | |
747 case SUBSYS_REGISTRY: { | |
748 if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) { | |
749 NOTREACHED(); | |
750 return SBOX_ERROR_BAD_PARAMS; | |
751 } | |
752 break; | |
753 } | |
754 case SUBSYS_HANDLES: { | |
755 if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) { | |
756 NOTREACHED(); | |
757 return SBOX_ERROR_BAD_PARAMS; | |
758 } | |
759 break; | |
760 } | |
761 | |
762 case SUBSYS_WIN32K_LOCKDOWN: { | |
763 if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules( | |
764 pattern, semantics, policy_maker_)) { | |
765 NOTREACHED(); | |
766 return SBOX_ERROR_BAD_PARAMS; | |
767 } | |
768 break; | |
769 } | |
770 | |
771 default: { return SBOX_ERROR_UNSUPPORTED; } | |
772 } | |
773 | |
774 return SBOX_ALL_OK; | |
775 } | |
776 | |
777 } // namespace sandbox | |
OLD | NEW |