From 7986921c089dbbe2bf1b9f87c522e571a7061c96 Mon Sep 17 00:00:00 2001 From: "jschuh@chromium.org" Date: Thu, 13 Sep 2012 22:29:33 +0000 Subject: Add sandbox support for Windows process mitigations BUG=147752 Review URL: https://codereview.chromium.org/10690058 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156657 0039d316-1c4b-4281-b951-d872f2087c98 --- content/app/startup_helper_win.cc | 13 +- content/common/sandbox_policy.cc | 24 ++- content/public/test/browser_test_base.cc | 1 - content/public/test/test_launcher.cc | 1 - sandbox/win/sandbox_win.gypi | 6 +- sandbox/win/src/broker_services.cc | 37 +++- sandbox/win/src/dep.cc | 89 -------- sandbox/win/src/dep.h | 25 --- sandbox/win/src/dep_test.cc | 158 -------------- sandbox/win/src/nt_internals.h | 16 +- sandbox/win/src/process_mitigations.cc | 321 ++++++++++++++++++++++++++++ sandbox/win/src/process_mitigations.h | 44 ++++ sandbox/win/src/process_mitigations_test.cc | 203 ++++++++++++++++++ sandbox/win/src/sandbox_policy.h | 16 ++ sandbox/win/src/sandbox_policy_base.cc | 46 ++++ sandbox/win/src/sandbox_policy_base.h | 7 + sandbox/win/src/sandbox_types.h | 5 +- sandbox/win/src/security_level.h | 70 ++++++ sandbox/win/src/target_process.cc | 23 -- sandbox/win/src/target_services.cc | 6 + sandbox/win/tests/common/controller.h | 4 + 21 files changed, 797 insertions(+), 318 deletions(-) delete mode 100644 sandbox/win/src/dep.cc delete mode 100644 sandbox/win/src/dep.h delete mode 100644 sandbox/win/src/dep_test.cc create mode 100644 sandbox/win/src/process_mitigations.cc create mode 100644 sandbox/win/src/process_mitigations.h create mode 100644 sandbox/win/src/process_mitigations_test.cc diff --git a/content/app/startup_helper_win.cc b/content/app/startup_helper_win.cc index 9ead36d..17fd323 100644 --- a/content/app/startup_helper_win.cc +++ b/content/app/startup_helper_win.cc @@ -10,7 +10,7 @@ #include "base/base_switches.h" #include "base/command_line.h" #include "base/win/windows_version.h" -#include "sandbox/win/src/dep.h" +#include "sandbox/win/src/process_mitigations.h" #include "sandbox/win/src/sandbox_factory.h" namespace { @@ -37,12 +37,13 @@ namespace content { void InitializeSandboxInfo(sandbox::SandboxInterfaceInfo* info) { info->broker_services = sandbox::SandboxFactory::GetBrokerServices(); - if (!info->broker_services) + if (!info->broker_services) { info->target_services = sandbox::SandboxFactory::GetTargetServices(); - - if (base::win::GetVersion() < base::win::VERSION_VISTA) { - // Enforces strong DEP support. Vista uses the NXCOMPAT flag in the exe. - sandbox::SetCurrentProcessDEP(sandbox::DEP_ENABLED); + } else { + // Ensure the proper mitigations are enforced for the browser process. + sandbox::ApplyProcessMitigationsToCurrentProcess( + sandbox::MITIGATION_DEP | + sandbox::MITIGATION_DEP_NO_ATL_THUNK); } } diff --git a/content/common/sandbox_policy.cc b/content/common/sandbox_policy.cc index b7eba46..6399de2 100644 --- a/content/common/sandbox_policy.cc +++ b/content/common/sandbox_policy.cc @@ -25,6 +25,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/process_type.h" #include "content/public/common/sandbox_init.h" +#include "sandbox/win/src/process_mitigations.h" #include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/sandbox_nt_util.h" #include "sandbox/win/src/win_utils.h" @@ -43,7 +44,6 @@ const wchar_t* const kTroublesomeDlls[] = { L"acpiz.dll", // Unknown. L"avgrsstx.dll", // AVG 8. L"babylonchromepi.dll", // Babylon translator. - L"browsemngr.dll", // Uninstall blocker used by Babylon. L"btkeyind.dll", // Widcomm Bluetooth. L"cmcsyshk.dll", // CMC Internet Security. L"cmsetac.dll", // Unknown (suspected malware). @@ -727,6 +727,28 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, return process; } + // TODO(jschuh): Add all Win8 mitigations. crbug.com/147752 + if (type != content::PROCESS_TYPE_NACL_LOADER) { + if (policy->SetProcessMitigations(MITIGATION_DEP | + MITIGATION_DEP_NO_ATL_THUNK | + MITIGATION_SEHOP | + MITIGATION_BOTTOM_UP_ASLR) + != sandbox::SBOX_ALL_OK) { + return 0; + } + } else { + // TODO(jschuh): Make NaCl work with DEP and SEHOP. crbug.com/147752 + if (policy->SetDelayedProcessMitigations(MITIGATION_DEP | + MITIGATION_DEP_NO_ATL_THUNK) + != sandbox::SBOX_ALL_OK) { + return 0; + } + if (policy->SetProcessMitigations(MITIGATION_BOTTOM_UP_ASLR) + != sandbox::SBOX_ALL_OK) { + return 0; + } + } + if (type == content::PROCESS_TYPE_PLUGIN) { AddGenericDllEvictionPolicy(policy); AddPluginDllEvictionPolicy(policy); diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index 24b0577..1124ada 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc @@ -10,7 +10,6 @@ #include "base/process_util.h" #include "content/public/common/content_switches.h" #include "content/public/common/main_function_params.h" -#include "sandbox/win/src/dep.h" #if defined(OS_MACOSX) #include "base/mac/mac_util.h" diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc index aad3ba3..ab2bdaf 100644 --- a/content/public/test/test_launcher.cc +++ b/content/public/test/test_launcher.cc @@ -34,7 +34,6 @@ #if defined(OS_WIN) #include "base/base_switches.h" #include "content/common/sandbox_policy.h" -#include "sandbox/win/src/dep.h" #include "sandbox/win/src/sandbox_factory.h" #include "sandbox/win/src/sandbox_types.h" #elif defined(OS_MACOSX) diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi index 7160bf7..0b3f590 100644 --- a/sandbox/win/sandbox_win.gypi +++ b/sandbox/win/sandbox_win.gypi @@ -22,8 +22,6 @@ 'src/crosscall_params.h', 'src/crosscall_server.cc', 'src/crosscall_server.h', - 'src/dep.cc', - 'src/dep.h', 'src/eat_resolver.cc', 'src/eat_resolver.h', 'src/filesystem_dispatcher.cc', @@ -73,6 +71,8 @@ 'src/policy_params.h', 'src/policy_target.cc', 'src/policy_target.h', + 'src/process_mitigations.cc', + 'src/process_mitigations.h', 'src/process_thread_dispatcher.cc', 'src/process_thread_dispatcher.h', 'src/process_thread_interception.cc', @@ -232,7 +232,6 @@ ], 'sources': [ 'src/app_container_test.cc', - 'src/dep_test.cc', 'src/file_policy_test.cc', 'src/handle_policy_test.cc', 'tests/integration_tests/integration_tests_test.cc', @@ -241,6 +240,7 @@ 'src/ipc_ping_test.cc', 'src/named_pipe_policy_test.cc', 'src/policy_target_test.cc', + 'src/process_mitigations_test.cc', 'src/process_policy_test.cc', 'src/registry_policy_test.cc', 'src/sync_policy_test.cc', diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc index 497f2f8..0425845 100644 --- a/sandbox/win/src/broker_services.cc +++ b/sandbox/win/src/broker_services.cc @@ -12,6 +12,7 @@ #include "base/win/startup_information.h" #include "base/win/windows_version.h" #include "sandbox/win/src/app_container.h" +#include "sandbox/win/src/process_mitigations.h" #include "sandbox/win/src/sandbox_policy_base.h" #include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/target_process.h" @@ -320,12 +321,36 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, const_cast(desktop.c_str()); } - const AppContainerAttributes* app_container = policy_base->GetAppContainer(); - if (app_container) { - startup_info.InitializeProcThreadAttributeList(1); - result = app_container->ShareForStartup(&startup_info); - if (SBOX_ALL_OK != result) - return result; + if (base::win::GetVersion() >= base::win::VERSION_VISTA) { + int attribute_count = 0; + const AppContainerAttributes* app_container = + policy_base->GetAppContainer(); + if (app_container) + ++attribute_count; + + DWORD64 mitigations; + size_t mitigations_size; + ConvertProcessMitigationsToPolicy(policy->GetProcessMitigations(), + &mitigations, &mitigations_size); + if (mitigations) + ++attribute_count; + + if (!startup_info.InitializeProcThreadAttributeList(attribute_count)) + return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; + + if (app_container) { + result = app_container->ShareForStartup(&startup_info); + if (SBOX_ALL_OK != result) + return result; + } + + if (mitigations) { + if (!startup_info.UpdateProcThreadAttribute( + PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations, + mitigations_size)) { + return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; + } + } } // Construct the thread pool here in case it is expensive. diff --git a/sandbox/win/src/dep.cc b/sandbox/win/src/dep.cc deleted file mode 100644 index 0c42050..0000000 --- a/sandbox/win/src/dep.cc +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "sandbox/win/src/dep.h" - -#include - -#include "base/logging.h" - -namespace sandbox { - -namespace { - -// These values are in the Windows 2008 SDK but not in the previous ones. Define -// the values here until we're sure everyone updated their SDK. -#ifndef PROCESS_DEP_ENABLE -#define PROCESS_DEP_ENABLE 0x00000001 -#endif -#ifndef PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION -#define PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION 0x00000002 -#endif - -// SetProcessDEPPolicy is declared in the Windows 2008 SDK. -typedef BOOL (WINAPI *FnSetProcessDEPPolicy)(DWORD dwFlags); - -enum PROCESS_INFORMATION_CLASS { - ProcessExecuteFlags = 0x22, -}; - -// Flags named as per their usage. -const int MEM_EXECUTE_OPTION_ENABLE = 1; -const int MEM_EXECUTE_OPTION_DISABLE = 2; -const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4; -const int MEM_EXECUTE_OPTION_PERMANENT = 8; - -// Not exactly the right signature but that will suffice. -typedef HRESULT (WINAPI *FnNtSetInformationProcess)( - HANDLE ProcessHandle, - PROCESS_INFORMATION_CLASS ProcessInformationClass, - PVOID ProcessInformation, - ULONG ProcessInformationLength); - -} // namespace - -bool SetCurrentProcessDEP(DepEnforcement enforcement) { -#ifdef _WIN64 - // DEP is always on in x64. - return enforcement != DEP_DISABLED; -#endif - // Only available on Windows XP SP2 and Windows Server 2003 SP1. - // For reference: http://www.uninformed.org/?v=2&a=4 - FnNtSetInformationProcess NtSetInformationProc = - reinterpret_cast( - GetProcAddress(GetModuleHandle(L"ntdll.dll"), - "NtSetInformationProcess")); - - if (!NtSetInformationProc) - return false; - - // Flags being used as per SetProcessDEPPolicy on Vista SP1. - ULONG dep_flags; - switch (enforcement) { - case DEP_DISABLED: - // 2 - dep_flags = MEM_EXECUTE_OPTION_DISABLE; - break; - case DEP_ENABLED: - // 9 - dep_flags = MEM_EXECUTE_OPTION_PERMANENT | MEM_EXECUTE_OPTION_ENABLE; - break; - case DEP_ENABLED_ATL7_COMPAT: - // 0xD - dep_flags = MEM_EXECUTE_OPTION_PERMANENT | MEM_EXECUTE_OPTION_ENABLE | - MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION; - break; - default: - NOTREACHED(); - return false; - } - - HRESULT status = NtSetInformationProc(GetCurrentProcess(), - ProcessExecuteFlags, - &dep_flags, - sizeof(dep_flags)); - return SUCCEEDED(status); -} - -} // namespace sandbox diff --git a/sandbox/win/src/dep.h b/sandbox/win/src/dep.h deleted file mode 100644 index 9016285..0000000 --- a/sandbox/win/src/dep.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SANDBOX_SRC_DEP_H__ -#define SANDBOX_SRC_DEP_H__ - -namespace sandbox { - -enum DepEnforcement { - // DEP is completely disabled. - DEP_DISABLED, - // DEP is permanently enforced. - DEP_ENABLED, - // DEP with support for ATL7 thunking is permanently enforced. - DEP_ENABLED_ATL7_COMPAT, -}; - -// Change the Data Execution Prevention (DEP) status for the current process. -// Once enabled, it cannot be disabled. -bool SetCurrentProcessDEP(DepEnforcement enforcement); - -} // namespace sandbox - -#endif // SANDBOX_SRC_DEP_H__ diff --git a/sandbox/win/src/dep_test.cc b/sandbox/win/src/dep_test.cc deleted file mode 100644 index 2817caa..0000000 --- a/sandbox/win/src/dep_test.cc +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "sandbox/win/src/dep.h" - -#include "sandbox/win/src/sandbox_utils.h" -#include "sandbox/win/tests/common/controller.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace sandbox { - -namespace { - -BYTE kReturnCode[] = { - // ret - 0xC3, -}; - -typedef void (*NullFunction)(); - -// This doesn't fail on Vista Service Pack 0 but it does on XP SP2 and Vista -// SP1. I guess this is a bug in Vista SP0 w.r.t .data PE section. Needs -// investigation to be sure it is a bug and not an error on my part. -bool GenerateDepException() { - bool result = false; - __try { - void* code = kReturnCode; - // Call this code. - reinterpret_cast(code)(); - } __except(EXCEPTION_EXECUTE_HANDLER) { - result = true; - } - return result; -} - -bool GenerateDepAtl7Exception() { - // TODO(maruel): bug 1207762 Somehow test ATL7 - return GenerateDepException(); -} - -SBOX_TESTS_COMMAND int CheckDepLevel(int argc, wchar_t **argv) { - if (1 != argc) - return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; - - int flag = _wtoi(argv[0]); - switch (flag) { - case 1: - // DEP is completely disabled. - if (!SetCurrentProcessDEP(DEP_DISABLED)) { - if (!IsXPSP2OrLater()) - // That's fine. - return SBOX_TEST_SUCCEEDED; - return SBOX_TEST_DENIED; - } - if (GenerateDepException()) - return SBOX_TEST_FAILED; - if (GenerateDepAtl7Exception()) - return SBOX_TEST_FAILED; - return SBOX_TEST_SUCCEEDED; - case 2: - // DEP is enabled with ATL7 thunk support. - if (!SetCurrentProcessDEP(DEP_ENABLED_ATL7_COMPAT)) { - if (!IsXPSP2OrLater()) - // That's fine. - return SBOX_TEST_SUCCEEDED; - return SBOX_TEST_DENIED; - } - if (!GenerateDepException()) - return SBOX_TEST_FAILED; - if (GenerateDepAtl7Exception()) - return SBOX_TEST_FAILED; - return SBOX_TEST_SUCCEEDED; - case 3: - // DEP is enabled. - if (!SetCurrentProcessDEP(DEP_ENABLED)) { - if (!IsXPSP2OrLater()) - // That's fine. - return SBOX_TEST_SUCCEEDED; - return SBOX_TEST_DENIED; - } - if (!GenerateDepException()) - return SBOX_TEST_FAILED; - if (!GenerateDepAtl7Exception()) - return SBOX_TEST_FAILED; - return SBOX_TEST_SUCCEEDED; - case 4: - // DEP can't be disabled. - if (!SetCurrentProcessDEP(DEP_ENABLED)) { - if (!IsXPSP2OrLater()) - // That's fine. - return SBOX_TEST_SUCCEEDED; - } - if (SetCurrentProcessDEP(DEP_DISABLED)) { - return SBOX_TEST_DENIED; - } - // Verify that it is still enabled. - if (!GenerateDepException()) - return SBOX_TEST_FAILED; - if (!GenerateDepAtl7Exception()) - return SBOX_TEST_FAILED; - return SBOX_TEST_SUCCEEDED; - case 5: - // DEP can't be disabled. - if (!SetCurrentProcessDEP(DEP_ENABLED_ATL7_COMPAT)) { - if (!IsXPSP2OrLater()) - // That's fine. - return SBOX_TEST_SUCCEEDED; - } - if (SetCurrentProcessDEP(DEP_DISABLED)) { - return SBOX_TEST_DENIED; - } - // Verify that it is still enabled. - if (!GenerateDepException()) - return SBOX_TEST_FAILED; - if (!GenerateDepAtl7Exception()) - return SBOX_TEST_FAILED; - return SBOX_TEST_SUCCEEDED; - case 6: - // DEP can't be disabled. - if (!SetCurrentProcessDEP(DEP_ENABLED)) { - if (!IsXPSP2OrLater()) - // That's fine. - return SBOX_TEST_SUCCEEDED; - } - if (SetCurrentProcessDEP(DEP_ENABLED_ATL7_COMPAT)) { - return SBOX_TEST_DENIED; - } - // Verify that it is still enabled. - if (!GenerateDepException()) - return SBOX_TEST_FAILED; - if (!GenerateDepAtl7Exception()) - return SBOX_TEST_FAILED; - return SBOX_TEST_SUCCEEDED; - default: - return SBOX_TEST_INVALID_PARAMETER; - } - return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; -} - -} // namespace - -// This test is disabled. See bug 1275842 -TEST(DepTest, DISABLED_TestDepDisable) { - TestRunner runner(JOB_UNPROTECTED, USER_INTERACTIVE, USER_INTERACTIVE); - - runner.SetTimeout(INFINITE); - - EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDepLevel 1")); - // TODO(maruel): bug 1207762 Somehow test ATL7 - // EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDepLevel 2")); - EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDepLevel 3")); - EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDepLevel 4")); - EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDepLevel 5")); - EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDepLevel 6")); -} - -} // namespace sandbox diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h index fe4fcd6..c9aaf92 100644 --- a/sandbox/win/src/nt_internals.h +++ b/sandbox/win/src/nt_internals.h @@ -4,8 +4,8 @@ // This file holds definitions related to the ntdll API. -#ifndef SANDBOX_SRC_NT_INTERNALS_H__ -#define SANDBOX_SRC_NT_INTERNALS_H__ +#ifndef SANDBOX_WIN_SRC_NT_INTERNALS_H__ +#define SANDBOX_WIN_SRC_NT_INTERNALS_H__ #include @@ -292,7 +292,8 @@ typedef NTSTATUS (WINAPI *NtSetInformationThreadFunction) ( // Partial definition only: typedef enum _PROCESSINFOCLASS { - ProcessBasicInformation = 0 + ProcessBasicInformation = 0, + ProcessExecuteFlags = 0x22 } PROCESSINFOCLASS; typedef PVOID PPEB; @@ -314,6 +315,12 @@ typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunction)( IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL); +typedef NTSTATUS (WINAPI *NtSetInformationProcessFunction)( + HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength); + typedef NTSTATUS (WINAPI *NtOpenThreadTokenFunction) ( IN HANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, @@ -608,4 +615,5 @@ typedef VOID (WINAPI *RtlInitUnicodeStringFunction) ( IN OUT PUNICODE_STRING DestinationString, IN PCWSTR SourceString); -#endif // SANDBOX_SRC_NT_INTERNALS_H__ +#endif // SANDBOX_WIN_SRC_NT_INTERNALS_H__ + diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc new file mode 100644 index 0000000..8390c51 --- /dev/null +++ b/sandbox/win/src/process_mitigations.cc @@ -0,0 +1,321 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/win/src/process_mitigations.h" + +#include "base/win/windows_version.h" +#include "sandbox/win/src/nt_internals.h" +#include "sandbox/win/src/sandbox_utils.h" +#include "sandbox/win/src/win_utils.h" + +namespace { + +// Functions for enabling policies. +typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags); + +typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)( + PROCESS_MITIGATION_POLICY mitigation_policy, + PVOID buffer, + SIZE_T length); + +typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)( + DWORD DirectoryFlags); + +} // namespace + +namespace sandbox { + +bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) { + if (!CanSetProcessMitigationsPostStartup(flags)) + return false; + + // We can't apply anything before Win XP, so just return cleanly. + if (!IsXPSP2OrLater()) + return true; + + HMODULE module = ::GetModuleHandleA("kernel32.dll"); + + if (flags & MITIGATION_DLL_SEARCH_ORDER) { + SetDefaultDllDirectoriesFunction set_default_dll_directories = + reinterpret_cast( + ::GetProcAddress(module, "SetDefaultDllDirectories")); + + // Check for SetDefaultDllDirectories since it requires KB2533623. + if (set_default_dll_directories) { + if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + return false; + } + } + + // Set the heap to terminate on corruption + if (flags & MITIGATION_HEAP_TERMINATE) { + if (!::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, + NULL, 0)) + return false; + } + +#if !defined(_WIN64) // DEP is always enabled on 64-bit. + if (flags & MITIGATION_DEP) { + DWORD dep_flags = PROCESS_DEP_ENABLE; + + if (flags & MITIGATION_DEP_NO_ATL_THUNK) + dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION; + + SetProcessDEPPolicyFunction set_process_dep_policy = + reinterpret_cast( + ::GetProcAddress(module, "SetProcessDEPPolicy")); + if (set_process_dep_policy) { + if (!set_process_dep_policy(dep_flags) && + ERROR_ACCESS_DENIED != ::GetLastError()) { + return false; + } + } else { + // We're on XP sp2, so use the less standard approach. + // For reference: http://www.uninformed.org/?v=2&a=4 + const int MEM_EXECUTE_OPTION_ENABLE = 1; + const int MEM_EXECUTE_OPTION_DISABLE = 2; + const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4; + const int MEM_EXECUTE_OPTION_PERMANENT = 8; + + NtSetInformationProcessFunction set_information_process = NULL; + ResolveNTFunctionPtr("NtSetInformationProcess", + &set_information_process); + if (!set_information_process) + return false; + ULONG dep = MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT; + if (!(dep_flags & PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION)) + dep |= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION; + if (!SUCCEEDED(set_information_process(GetCurrentProcess(), + ProcessExecuteFlags, + &dep, sizeof(dep))) && + ERROR_ACCESS_DENIED != ::GetLastError()) { + return false; + } + } + } +#endif + + // This is all we can do in Win7 and below. + base::win::Version version = base::win::GetVersion(); + if (version < base::win::VERSION_WIN8) + return true; + + SetProcessMitigationPolicyFunction set_process_mitigation_policy = + reinterpret_cast( + ::GetProcAddress(module, "SetProcessMitigationPolicy")); + if (!set_process_mitigation_policy) + return false; + + // Enable ASLR policies. + if (flags & MITIGATION_RELOCATE_IMAGE) { + PROCESS_MITIGATION_ASLR_POLICY policy = { 0 }; + policy.EnableForceRelocateImages = true; + policy.DisallowStrippedImages = (flags & + MITIGATION_RELOCATE_IMAGE_REQUIRED) == + MITIGATION_RELOCATE_IMAGE_REQUIRED; + + if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy, + sizeof(policy)) && + ERROR_ACCESS_DENIED != ::GetLastError()) { + return false; + } + } + + // Enable strict handle policies. + if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { + PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 }; + policy.HandleExceptionsPermanentlyEnabled = + policy.RaiseExceptionOnInvalidHandleReference = true; + + if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy, + sizeof(policy)) && + ERROR_ACCESS_DENIED != ::GetLastError()) { + return false; + } + } + + // Enable system call policies. + if (flags & MITIGATION_WIN32K_DISABLE) { + PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 }; + policy.DisallowWin32kSystemCalls = true; + + if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy, + sizeof(policy)) && + ERROR_ACCESS_DENIED != ::GetLastError()) { + return false; + } + } + + // Enable system call policies. + if (flags & MITIGATION_EXTENSION_DLL_DISABLE) { + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 }; + policy.DisableExtensionPoints = true; + + if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy, + &policy, sizeof(policy)) && + ERROR_ACCESS_DENIED != ::GetLastError()) { + return false; + } + } + + return true; +} + +void ConvertProcessMitigationsToPolicy(MitigationFlags flags, + DWORD64* policy_flags, size_t* size) { + base::win::Version version = base::win::GetVersion(); + + *policy_flags = 0; +#if defined(_WIN64) + *size = sizeof(*policy_flags); +#elif defined(_M_IX86) + // A 64-bit flags attribute is illegal on 32-bit Win 7 and below. + if (version < base::win::VERSION_WIN8) + *size = sizeof(DWORD); + else + *size = sizeof(*policy_flags); +#else +#error This platform is not supported. +#endif + + // Nothing for Win XP or Vista. + if (version <= base::win::VERSION_VISTA) + return; + + if (flags & MITIGATION_DEP) { + *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE; + if (!(flags & MITIGATION_DEP_NO_ATL_THUNK)) + *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE; + } + + if (flags & MITIGATION_SEHOP) + *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE; + + // Win 7 + if (version < base::win::VERSION_WIN8) + return; + + if (flags & MITIGATION_RELOCATE_IMAGE) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON; + if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS; + } + } + + if (flags & MITIGATION_HEAP_TERMINATE) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON; + } + + if (flags & MITIGATION_BOTTOM_UP_ASLR) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON; + } + + if (flags & MITIGATION_HIGH_ENTROPY_ASLR) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON; + } + + if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON; + } + + if (flags & MITIGATION_WIN32K_DISABLE) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON; + } + + if (flags & MITIGATION_EXTENSION_DLL_DISABLE) { + *policy_flags |= + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON; + } +} + +MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) { + // Anything prior to XP SP2. + if (!IsXPSP2OrLater()) + return 0; + + base::win::Version version = base::win::GetVersion(); + + // Windows XP SP2+. + if (version < base::win::VERSION_VISTA) { + return flags & (MITIGATION_DEP | + MITIGATION_DEP_NO_ATL_THUNK); + + // Windows Vista + if (version < base::win::VERSION_WIN7) { + return flags & (MITIGATION_DEP | + MITIGATION_DEP_NO_ATL_THUNK | + MITIGATION_BOTTOM_UP_ASLR | + MITIGATION_DLL_SEARCH_ORDER | + MITIGATION_HEAP_TERMINATE); + } + + // Windows 7 and Vista. + } else if (version < base::win::VERSION_WIN8) { + return flags & (MITIGATION_BOTTOM_UP_ASLR | + MITIGATION_DLL_SEARCH_ORDER | + MITIGATION_HEAP_TERMINATE); + } + + // Windows 8 and above. + return flags & (MITIGATION_BOTTOM_UP_ASLR | + MITIGATION_DLL_SEARCH_ORDER); +} + +bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process, + MitigationFlags flags) { +// This is a hack to fake a weak bottom-up ASLR on 32-bit Windows. +#if !defined(_WIN64) + if (flags & MITIGATION_BOTTOM_UP_ASLR) { + unsigned int limit; + rand_s(&limit); + char* ptr = 0; + const size_t kMask64k = 0xFFFF; + // Random range (512k-16.5mb) in 64k steps. + const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k); + while (ptr < end) { + MEMORY_BASIC_INFORMATION memory_info; + if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info))) + break; + size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k, + static_cast(end - ptr)); + if (ptr && memory_info.State == MEM_FREE) + ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS); + ptr += size; + } + } +#endif + + return true; +} + +bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) { + // All of these mitigations can be enabled after startup. + return !(flags & ~(MITIGATION_HEAP_TERMINATE | + MITIGATION_DEP | + MITIGATION_DEP_NO_ATL_THUNK | + MITIGATION_RELOCATE_IMAGE | + MITIGATION_RELOCATE_IMAGE_REQUIRED | + MITIGATION_BOTTOM_UP_ASLR | + MITIGATION_STRICT_HANDLE_CHECKS | + MITIGATION_WIN32K_DISABLE | + MITIGATION_EXTENSION_DLL_DISABLE | + MITIGATION_DLL_SEARCH_ORDER)); +} + +bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) { + // These mitigations cannot be enabled prior to startup. + return !(flags & (MITIGATION_STRICT_HANDLE_CHECKS | + MITIGATION_WIN32K_DISABLE | + MITIGATION_DLL_SEARCH_ORDER)); +} + +} // namespace sandbox + diff --git a/sandbox/win/src/process_mitigations.h b/sandbox/win/src/process_mitigations.h new file mode 100644 index 0000000..9039ad6 --- /dev/null +++ b/sandbox/win/src/process_mitigations.h @@ -0,0 +1,44 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_ +#define SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_ + +#include + +#include "base/basictypes.h" +#include "sandbox/win/src/security_level.h" + +namespace sandbox { + +// Sets the mitigation policy for the current process, ignoring any settings +// that are invalid for the current version of Windows. +bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags); + +// Returns the flags that must be enforced after startup for the current OS +// version. +MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags); + +// Converts sandbox flags to the PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES +// policy flags used by UpdateProcThreadAttribute(). The size field varies +// between a 32-bit and a 64-bit type based on the exact build and version of +// Windows, so the returned size must be passed to UpdateProcThreadAttribute(). +void ConvertProcessMitigationsToPolicy(MitigationFlags flags, + DWORD64* policy_flags, size_t* size); + +// Adds mitigations that need to be performed on the suspended target process +// before execution begins. +bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process, + MitigationFlags flags); + +// Returns true if all the supplied flags can be set after a process starts. +bool CanSetProcessMitigationsPostStartup(MitigationFlags flags); + +// Returns true if all the supplied flags can be set before a process starts. +bool CanSetProcessMitigationsPreStartup(MitigationFlags flags); + +} // namespace sandbox + +#endif // SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_ + diff --git a/sandbox/win/src/process_mitigations_test.cc b/sandbox/win/src/process_mitigations_test.cc new file mode 100644 index 0000000..2456391 --- /dev/null +++ b/sandbox/win/src/process_mitigations_test.cc @@ -0,0 +1,203 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/stringprintf.h" +#include "base/win/scoped_handle.h" + +#include "base/win/windows_version.h" +#include "sandbox/win/src/nt_internals.h" +#include "sandbox/win/src/process_mitigations.h" +#include "sandbox/win/src/sandbox.h" +#include "sandbox/win/src/sandbox_factory.h" +#include "sandbox/win/src/sandbox_utils.h" +#include "sandbox/win/src/target_services.h" +#include "sandbox/win/src/win_utils.h" +#include "sandbox/win/tests/common/controller.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +typedef BOOL (WINAPI *GetProcessDEPPolicyFunction)( + HANDLE process, + LPDWORD flags, + PBOOL permanent); + +typedef BOOL (WINAPI *GetProcessMitigationPolicyFunction)( + HANDLE process, + PROCESS_MITIGATION_POLICY mitigation_policy, + PVOID buffer, + SIZE_T length); + +GetProcessMitigationPolicyFunction get_process_mitigation_policy; + +bool CheckWin8DepPolicy() { + PROCESS_MITIGATION_DEP_POLICY policy; + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDEPPolicy, + &policy, sizeof(policy))) { + return false; + } + return policy.Enable && policy.Permanent; +} + +bool CheckWin8AslrPolicy() { + PROCESS_MITIGATION_ASLR_POLICY policy; + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessASLRPolicy, + &policy, sizeof(policy))) { + return false; + } + return policy.EnableForceRelocateImages && policy.DisallowStrippedImages; +} + +bool CheckWin8StrictHandlePolicy() { + PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy; + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessStrictHandleCheckPolicy, + &policy, sizeof(policy))) { + return false; + } + return policy.RaiseExceptionOnInvalidHandleReference && + policy.HandleExceptionsPermanentlyEnabled; +} + +bool CheckWin8Win32CallPolicy() { + PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy; + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessSystemCallDisablePolicy, + &policy, sizeof(policy))) { + return false; + } + return policy.DisallowWin32kSystemCalls; +} + +bool CheckWin8DllExtensionPolicy() { + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy; + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessExtensionPointDisablePolicy, + &policy, sizeof(policy))) { + return false; + } + return policy.DisableExtensionPoints; +} + +} // namespace + +namespace sandbox { + +SBOX_TESTS_COMMAND int CheckWin8(int argc, wchar_t **argv) { + get_process_mitigation_policy = + reinterpret_cast( + ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), + "GetProcessMitigationPolicy")); + + if (!get_process_mitigation_policy) + return SBOX_TEST_NOT_FOUND; + + if (!CheckWin8DepPolicy()) + return SBOX_TEST_FIRST_ERROR; + + if (!CheckWin8AslrPolicy()) + return SBOX_TEST_SECOND_ERROR; + + if (!CheckWin8StrictHandlePolicy()) + return SBOX_TEST_THIRD_ERROR; + + if (!CheckWin8Win32CallPolicy()) + return SBOX_TEST_FOURTH_ERROR; + + if (!CheckWin8DllExtensionPolicy()) + return SBOX_TEST_FIFTH_ERROR; + + return SBOX_TEST_SUCCEEDED; +} + +TEST(ProcessMitigationsTest, CheckWin8) { + if (base::win::GetVersion() < base::win::VERSION_WIN8) + return; + + TestRunner runner; + sandbox::TargetPolicy* policy = runner.GetPolicy(); + + EXPECT_EQ(policy->SetProcessMitigations( + MITIGATION_DEP | + MITIGATION_DEP_NO_ATL_THUNK | + MITIGATION_RELOCATE_IMAGE | + MITIGATION_RELOCATE_IMAGE_REQUIRED | + MITIGATION_EXTENSION_DLL_DISABLE), + SBOX_ALL_OK); + + EXPECT_EQ(policy->SetDelayedProcessMitigations( + MITIGATION_STRICT_HANDLE_CHECKS | + MITIGATION_WIN32K_DISABLE), + SBOX_ALL_OK); + + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8")); +} + + +SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t **argv) { +#if !defined(_WIN64) // DEP is always enabled on 64-bit. + GetProcessDEPPolicyFunction get_process_dep_policy = + reinterpret_cast( + ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), + "GetProcessDEPPolicy")); + if (get_process_dep_policy) { + BOOL is_permanent = FALSE; + DWORD dep_flags = 0; + + if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags, + &is_permanent)) { + return SBOX_TEST_FIRST_ERROR; + } + + if (!(dep_flags & PROCESS_DEP_ENABLE) || !is_permanent) + return SBOX_TEST_SECOND_ERROR; + + } else { + NtQueryInformationProcessFunction query_information_process = NULL; + ResolveNTFunctionPtr("NtQueryInformationProcess", + &query_information_process); + if (!query_information_process) + return SBOX_TEST_NOT_FOUND; + + ULONG size = 0; + ULONG dep_flags = 0; + if (!SUCCEEDED(query_information_process(::GetCurrentProcess(), + ProcessExecuteFlags, &dep_flags, + sizeof(dep_flags), &size))) { + return SBOX_TEST_THIRD_ERROR; + } + + const int MEM_EXECUTE_OPTION_ENABLE = 1; + const int MEM_EXECUTE_OPTION_DISABLE = 2; + const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4; + const int MEM_EXECUTE_OPTION_PERMANENT = 8; + dep_flags &= 0xff; + + if (dep_flags != (MEM_EXECUTE_OPTION_DISABLE | + MEM_EXECUTE_OPTION_PERMANENT)) { + return SBOX_TEST_FOURTH_ERROR; + } + } +#endif + + return SBOX_TEST_SUCCEEDED; +} + +TEST(ProcessMitigationsTest, CheckDep) { + if (!IsXPSP2OrLater() || base::win::GetVersion() > base::win::VERSION_WIN7) + return; + + TestRunner runner; + sandbox::TargetPolicy* policy = runner.GetPolicy(); + + EXPECT_EQ(policy->SetProcessMitigations( + MITIGATION_DEP | + MITIGATION_DEP_NO_ATL_THUNK | + MITIGATION_SEHOP), + SBOX_ALL_OK); + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDep")); +} + +} // namespace sandbox + diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h index ff487bcc..f0fc2bc 100644 --- a/sandbox/win/src/sandbox_policy.h +++ b/sandbox/win/src/sandbox_policy.h @@ -164,6 +164,22 @@ class TargetPolicy { // Sets a capability to be enabled for the sandboxed process' AppContainer. virtual ResultCode SetCapability(const wchar_t* sid) = 0; + // Sets the mitigations enabled when the process is created. Most of these + // are implemented as attributes passed via STARTUPINFOEX. So they take + // effect before any thread in the target executes. The declaration of + // MitigationFlags is followed by a detailed description of each flag. + virtual ResultCode SetProcessMitigations(MitigationFlags flags) = 0; + + // Returns the currently set mitigation flags. + virtual MitigationFlags GetProcessMitigations() = 0; + + // Sets process mitigation flags that don't take effect before the call to + // LowerToken(). + virtual ResultCode SetDelayedProcessMitigations(MitigationFlags flags) = 0; + + // Returns the currently set delayed mitigation flags. + virtual MitigationFlags GetDelayedProcessMitigations() = 0; + // Sets the interceptions to operate in strict mode. By default, interceptions // are performed in "relaxed" mode, where if something inside NTDLL.DLL is // already patched we attempt to intercept it anyway. Setting interceptions diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc index 3950a0c..f942ff5a 100644 --- a/sandbox/win/src/sandbox_policy_base.cc +++ b/sandbox/win/src/sandbox_policy_base.cc @@ -15,6 +15,7 @@ #include "sandbox/win/src/handle_policy.h" #include "sandbox/win/src/job.h" #include "sandbox/win/src/interception.h" +#include "sandbox/win/src/process_mitigations.h" #include "sandbox/win/src/named_pipe_dispatcher.h" #include "sandbox/win/src/named_pipe_policy.h" #include "sandbox/win/src/policy_broker.h" @@ -53,6 +54,7 @@ sandbox::PolicyGlobal* MakeBrokerPolicyMemory() { namespace sandbox { SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level; +SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations; // Initializes static members. HWINSTA PolicyBase::alternate_winstation_handle_ = NULL; @@ -70,6 +72,8 @@ PolicyBase::PolicyBase() relaxed_interceptions_(true), integrity_level_(INTEGRITY_LEVEL_LAST), delayed_integrity_level_(INTEGRITY_LEVEL_LAST), + mitigations_(0), + delayed_mitigations_(0), policy_maker_(NULL), policy_(NULL) { ::InitializeCriticalSection(&lock_); @@ -276,6 +280,30 @@ ResultCode PolicyBase::SetCapability(const wchar_t* sid) { return SBOX_ALL_OK; } +ResultCode PolicyBase::SetProcessMitigations( + MitigationFlags flags) { + if (!CanSetProcessMitigationsPreStartup(flags)) + return SBOX_ERROR_BAD_PARAMS; + mitigations_ = flags; + return SBOX_ALL_OK; +} + +MitigationFlags PolicyBase::GetProcessMitigations() { + return mitigations_; +} + +ResultCode PolicyBase::SetDelayedProcessMitigations( + MitigationFlags flags) { + if (!CanSetProcessMitigationsPostStartup(flags)) + return SBOX_ERROR_BAD_PARAMS; + delayed_mitigations_ = flags; + return SBOX_ALL_OK; +} + +MitigationFlags PolicyBase::GetDelayedProcessMitigations() { + return delayed_mitigations_; +} + void PolicyBase::SetStrictInterceptions() { relaxed_interceptions_ = false; } @@ -450,6 +478,11 @@ bool PolicyBase::AddTarget(TargetProcess* target) { if (NULL != policy_) policy_maker_->Done(); + if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(), + mitigations_)) { + return false; + } + if (!SetupAllInterceptions(target)) return false; @@ -469,6 +502,19 @@ bool PolicyBase::AddTarget(TargetProcess* target) { if (SBOX_ALL_OK != ret) return false; + // Add in delayed mitigations and pseudo-mitigations enforced at startup. + g_shared_delayed_mitigations = delayed_mitigations_ | + FilterPostStartupProcessMitigations(mitigations_); + if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations)) + return false; + + ret = target->TransferVariable("g_shared_delayed_mitigations", + &g_shared_delayed_mitigations, + sizeof(g_shared_delayed_mitigations)); + g_shared_delayed_mitigations = 0; + if (SBOX_ALL_OK != ret) + return false; + AutoLock lock(&lock_); targets_.push_back(target); return true; diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h index 1334304..efac6a0 100644 --- a/sandbox/win/src/sandbox_policy_base.h +++ b/sandbox/win/src/sandbox_policy_base.h @@ -52,6 +52,11 @@ class PolicyBase : public Dispatcher, public TargetPolicy { IntegrityLevel integrity_level) OVERRIDE; virtual ResultCode SetAppContainer(const wchar_t* sid) OVERRIDE; virtual ResultCode SetCapability(const wchar_t* sid) OVERRIDE; + virtual ResultCode SetProcessMitigations(MitigationFlags flags) OVERRIDE; + virtual MitigationFlags GetProcessMitigations() OVERRIDE; + virtual ResultCode SetDelayedProcessMitigations( + MitigationFlags flags) OVERRIDE; + virtual MitigationFlags GetDelayedProcessMitigations() OVERRIDE; virtual void SetStrictInterceptions() OVERRIDE; virtual ResultCode AddRule(SubSystem subsystem, Semantics semantics, const wchar_t* pattern) OVERRIDE; @@ -120,6 +125,8 @@ class PolicyBase : public Dispatcher, public TargetPolicy { bool relaxed_interceptions_; IntegrityLevel integrity_level_; IntegrityLevel delayed_integrity_level_; + MitigationFlags mitigations_; + MitigationFlags delayed_mitigations_; // The array of objects that will answer IPC calls. Dispatcher* ipc_targets_[IPC_LAST_TAG]; // Object in charge of generating the low level policy. diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h index dcf2042..8e9aef2 100644 --- a/sandbox/win/src/sandbox_types.h +++ b/sandbox/win/src/sandbox_types.h @@ -43,6 +43,8 @@ enum ResultCode { SBOX_ERROR_INVALID_CAPABILITY = 15, // There is a failure initializing the AppContainer. SBOX_ERROR_CANNOT_INIT_APPCONTAINER = 16, + // Initializing or updating ProcThreadAttributes failed. + SBOX_ERROR_PROC_THREAD_ATTRIBUTES = 17, // Placeholder for last item of the enum. SBOX_ERROR_LAST }; @@ -54,7 +56,8 @@ enum TerminationCodes { SBOX_FATAL_DROPTOKEN = 7007, // Could not lower the token. SBOX_FATAL_FLUSHANDLES = 7008, // Failed to flush registry handles. SBOX_FATAL_CACHEDISABLE = 7009, // Failed to forbid HCKU caching. - SBOX_FATAL_CLOSEHANDLES = 7010 // Failed to close pending handles. + SBOX_FATAL_CLOSEHANDLES = 7010, // Failed to close pending handles. + SBOX_FATAL_MITIGATION = 7011 // Could not set the mitigation policy. }; class BrokerServices; diff --git a/sandbox/win/src/security_level.h b/sandbox/win/src/security_level.h index 467f96f..010185a 100644 --- a/sandbox/win/src/security_level.h +++ b/sandbox/win/src/security_level.h @@ -122,6 +122,76 @@ enum JobLevel { JOB_UNPROTECTED }; +// These flags correspond to various process-level mitigations (eg. ASLR and +// DEP). Most are implemented via UpdateProcThreadAttribute() plus flags for +// the PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY attribute argument; documented +// here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686880 +// Some mitigations are implemented directly by the sandbox or emulated to +// the greatest extent possible when not directly supported by the OS. +// Flags that are unsupported for the target OS will be silently ignored. +// Flags that are invalid for their application (pre or post startup) will +// return SBOX_ERROR_BAD_PARAMS. +typedef uint64 MitigationFlags; + +// Permanently enables DEP for the target process. Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE. +const MitigationFlags MITIGATION_DEP = 0x00000001; + +// Permanently Disables ATL thunk emulation when DEP is enabled. Valid +// only when MITIGATION_DEP is passed. Corresponds to not passing +// PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE. +const MitigationFlags MITIGATION_DEP_NO_ATL_THUNK = 0x00000002; + +// Enables Structured exception handling override prevention. Must be +// enabled prior to process start. Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE. +const MitigationFlags MITIGATION_SEHOP = 0x00000004; + +// Forces ASLR on all images in the child process. Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON . +const MitigationFlags MITIGATION_RELOCATE_IMAGE = 0x00000008; + +// Refuses to load DLLs that cannot support ASLR. Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS. +const MitigationFlags MITIGATION_RELOCATE_IMAGE_REQUIRED = 0x00000010; + +// Terminates the process on Windows heap corruption. Coresponds to +// PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON. +const MitigationFlags MITIGATION_HEAP_TERMINATE = 0x00000020; + +// Sets a random lower bound as the minimum user address. Must be +// enabled prior to process start. On 32-bit processes this is +// emulated to a much smaller degree. Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON. +const MitigationFlags MITIGATION_BOTTOM_UP_ASLR = 0x00000040; + +// Increases the randomness range of bottom-up ASLR to up to 1TB. Must be +// enabled prior to process start and with MITIGATION_BOTTOM_UP_ASLR. +// Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON +const MitigationFlags MITIGATION_HIGH_ENTROPY_ASLR = 0x00000080; + +// Immediately raises an exception on a bad handle reference. Must be +// enabled after startup. Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON. +const MitigationFlags MITIGATION_STRICT_HANDLE_CHECKS = 0x00000100; + +// Prevents the process from making Win32k calls. Must be enabled after +// startup. Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON. +const MitigationFlags MITIGATION_WIN32K_DISABLE = 0x00000200; + +// Disables common DLL injection methods (e.g. window hooks and +// App_InitDLLs). Corresponds to +// PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON. +const MitigationFlags MITIGATION_EXTENSION_DLL_DISABLE = 0x00000400; + +// Sets the DLL search order to LOAD_LIBRARY_SEARCH_DEFAULT_DIRS. Additional +// directories can be added via the Windows AddDllDirectory() function. +// http://msdn.microsoft.com/en-us/library/windows/desktop/hh310515 +// Must be enabled after startup. +const MitigationFlags MITIGATION_DLL_SEARCH_ORDER = 0x00000001ULL << 32; + } // namespace sandbox #endif // SANDBOX_SRC_SECURITY_LEVEL_H_ diff --git a/sandbox/win/src/target_process.cc b/sandbox/win/src/target_process.cc index 164b2a9..4eea180 100644 --- a/sandbox/win/src/target_process.cc +++ b/sandbox/win/src/target_process.cc @@ -35,27 +35,6 @@ void CopyPolicyToTarget(const void* source, size_t size, void* dest) { } } -// Reserve a random range at the bottom of the address space in the target -// process to prevent predictable alocations at low addresses. -void PoisonLowerAddressRange(HANDLE process) { - unsigned int limit; - rand_s(&limit); - char* ptr = 0; - const size_t kMask64k = 0xFFFF; - // Random range (512k-16.5mb) in 64k steps. - const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k); - while (ptr < end) { - MEMORY_BASIC_INFORMATION memory_info; - if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info))) - break; - size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k, - static_cast(end - ptr)); - if (ptr && memory_info.State == MEM_FREE) - ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS); - ptr += size; - } -} - } namespace sandbox { @@ -168,8 +147,6 @@ DWORD TargetProcess::Create(const wchar_t* exe_path, } lockdown_token_.Close(); - PoisonLowerAddressRange(process_info.process_handle()); - DWORD win_result = ERROR_SUCCESS; // Assign the suspended target to the windows job object. diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc index 495f108..03813c8 100644 --- a/sandbox/win/src/target_services.cc +++ b/sandbox/win/src/target_services.cc @@ -11,6 +11,7 @@ #include "sandbox/win/src/handle_closer_agent.h" #include "sandbox/win/src/handle_interception.h" #include "sandbox/win/src/ipc_tags.h" +#include "sandbox/win/src/process_mitigations.h" #include "sandbox/win/src/restricted_token_utils.h" #include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/sandbox_types.h" @@ -61,6 +62,7 @@ namespace sandbox { SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST; +SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations = 0; TargetServicesBase::TargetServicesBase() { } @@ -86,6 +88,10 @@ void TargetServicesBase::LowerToken() { ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE); if (!CloseOpenHandles()) ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES); + // Enabling mitigations must happen last otherwise handle closing breaks + if (g_shared_delayed_mitigations && + !ApplyProcessMitigationsToCurrentProcess(g_shared_delayed_mitigations)) + ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_MITIGATION); } ProcessState* TargetServicesBase::GetState() { diff --git a/sandbox/win/tests/common/controller.h b/sandbox/win/tests/common/controller.h index fd7a833..3d42878 100644 --- a/sandbox/win/tests/common/controller.h +++ b/sandbox/win/tests/common/controller.h @@ -31,6 +31,10 @@ enum SboxTestResult { SBOX_TEST_FIRST_ERROR = SBOX_TEST_FIRST_RESULT | SEVERITY_ERROR_FLAGS, SBOX_TEST_SECOND_ERROR, SBOX_TEST_THIRD_ERROR, + SBOX_TEST_FOURTH_ERROR, + SBOX_TEST_FIFTH_ERROR, + SBOX_TEST_SIXTH_ERROR, + SBOX_TEST_SEVENTH_ERROR, SBOX_TEST_INVALID_PARAMETER, SBOX_TEST_FAILED_TO_RUN_TEST, SBOX_TEST_FAILED_TO_EXECUTE_COMMAND, -- cgit v1.1