diff options
-rw-r--r-- | components/nacl/loader/nacl_main_platform_delegate_win.cc | 3 | ||||
-rw-r--r-- | content/renderer/renderer_main_platform_delegate_win.cc | 3 | ||||
-rw-r--r-- | sandbox/win/BUILD.gn | 1 | ||||
-rw-r--r-- | sandbox/win/sandbox_win.gypi | 1 | ||||
-rw-r--r-- | sandbox/win/src/lpc_policy_test.cc | 156 | ||||
-rw-r--r-- | sandbox/win/src/sandbox_policy.h | 2 | ||||
-rw-r--r-- | sandbox/win/src/sandbox_types.h | 15 | ||||
-rw-r--r-- | sandbox/win/src/target_services.cc | 40 | ||||
-rw-r--r-- | tools/metrics/histograms/histograms.xml | 1 |
9 files changed, 208 insertions, 14 deletions
diff --git a/components/nacl/loader/nacl_main_platform_delegate_win.cc b/components/nacl/loader/nacl_main_platform_delegate_win.cc index e4d0ad5..c0caa5e 100644 --- a/components/nacl/loader/nacl_main_platform_delegate_win.cc +++ b/components/nacl/loader/nacl_main_platform_delegate_win.cc @@ -17,9 +17,6 @@ void NaClMainPlatformDelegate::EnableSandbox( // Cause advapi32 to load before the sandbox is turned on. unsigned int dummy_rand; rand_s(&dummy_rand); - // Warm up language subsystems before the sandbox is turned on. - ::GetUserDefaultLangID(); - ::GetUserDefaultLCID(); // Turn the sandbox on. target_services->LowerToken(); diff --git a/content/renderer/renderer_main_platform_delegate_win.cc b/content/renderer/renderer_main_platform_delegate_win.cc index aae8ea1..675961d 100644 --- a/content/renderer/renderer_main_platform_delegate_win.cc +++ b/content/renderer/renderer_main_platform_delegate_win.cc @@ -87,9 +87,6 @@ bool RendererMainPlatformDelegate::EnableSandbox() { // Cause advapi32 to load before the sandbox is turned on. unsigned int dummy_rand; rand_s(&dummy_rand); - // Warm up language subsystems before the sandbox is turned on. - ::GetUserDefaultLangID(); - ::GetUserDefaultLCID(); target_services->LowerToken(); return true; diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn index 129f065..2250869 100644 --- a/sandbox/win/BUILD.gn +++ b/sandbox/win/BUILD.gn @@ -196,6 +196,7 @@ test("sbox_integration_tests") { "src/handle_policy_test.cc", "src/integrity_level_test.cc", "src/ipc_ping_test.cc", + "src/lpc_policy_test.cc", "src/named_pipe_policy_test.cc", "src/policy_target_test.cc", "src/process_mitigations_test.cc", diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi index 08d512a..ae8b51c 100644 --- a/sandbox/win/sandbox_win.gypi +++ b/sandbox/win/sandbox_win.gypi @@ -219,6 +219,7 @@ 'src/handle_closer_test.cc', 'src/integrity_level_test.cc', 'src/ipc_ping_test.cc', + 'src/lpc_policy_test.cc', 'src/named_pipe_policy_test.cc', 'src/policy_target_test.cc', 'src/process_mitigations_test.cc', diff --git a/sandbox/win/src/lpc_policy_test.cc b/sandbox/win/src/lpc_policy_test.cc new file mode 100644 index 0000000..ac7b39f --- /dev/null +++ b/sandbox/win/src/lpc_policy_test.cc @@ -0,0 +1,156 @@ +// Copyright 2015 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. + +// These tests have been added to specifically tests issues arising from (A)LPC +// lock down. + +#include <algorithm> +#include <cctype> + +#include <windows.h> +#include <winioctl.h> + +#include "base/win/windows_version.h" +#include "sandbox/win/src/sandbox.h" +#include "sandbox/win/src/sandbox_factory.h" +#include "sandbox/win/src/sandbox_policy.h" +#include "sandbox/win/tests/common/controller.h" +#include "sandbox/win/tests/common/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace sandbox { + +// Converts LCID to std::wstring for passing to sbox tests. +std::wstring LcidToWString(LCID lcid) { + wchar_t buff[10] = {0}; + int res = swprintf_s(buff, sizeof(buff) / sizeof(buff[0]), L"%08x", lcid); + if (-1 != res) { + return std::wstring(buff); + } + return std::wstring(); +} + +// Converts LANGID to std::wstring for passing to sbox tests. +std::wstring LangidToWString(LANGID langid) { + wchar_t buff[10] = {0}; + int res = swprintf_s(buff, sizeof(buff) / sizeof(buff[0]), L"%04x", langid); + if (-1 != res) { + return std::wstring(buff); + } + return std::wstring(); +} + +SBOX_TESTS_COMMAND int Lpc_GetUserDefaultLangID(int argc, wchar_t** argv) { + if (argc != 1) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + std::wstring expected_langid_string(argv[0]); + + // This will cause an exception if not warmed up suitably. + LANGID langid = ::GetUserDefaultLangID(); + + std::wstring langid_string = LangidToWString(langid); + if (0 == wcsncmp(langid_string.c_str(), expected_langid_string.c_str(), 4)) { + return SBOX_TEST_SUCCEEDED; + } + return SBOX_TEST_FAILED; +} + +TEST(LpcPolicyTest, GetUserDefaultLangID) { + LANGID langid = ::GetUserDefaultLangID(); + std::wstring cmd = L"Lpc_GetUserDefaultLangID " + LangidToWString(langid); + TestRunner runner; + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd.c_str())); +} + +SBOX_TESTS_COMMAND int Lpc_GetUserDefaultLCID(int argc, wchar_t** argv) { + if (argc != 1) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + std::wstring expected_lcid_string(argv[0]); + + // This will cause an exception if not warmed up suitably. + LCID lcid = ::GetUserDefaultLCID(); + + std::wstring lcid_string = LcidToWString(lcid); + if (0 == wcsncmp(lcid_string.c_str(), expected_lcid_string.c_str(), 8)) { + return SBOX_TEST_SUCCEEDED; + } + return SBOX_TEST_FAILED; +} + +TEST(LpcPolicyTest, GetUserDefaultLCID) { + LCID lcid = ::GetUserDefaultLCID(); + std::wstring cmd = L"Lpc_GetUserDefaultLCID " + LcidToWString(lcid); + TestRunner runner; + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd.c_str())); +} + +// GetUserDefaultLocaleName is not available on WIN XP. So we'll +// load it on-the-fly. +const wchar_t kKernel32DllName[] = L"kernel32.dll"; +typedef int(WINAPI* GetUserDefaultLocaleNameFunction)(LPWSTR lpLocaleName, + int cchLocaleName); + +SBOX_TESTS_COMMAND int Lpc_GetUserDefaultLocaleName(int argc, wchar_t** argv) { + if (argc != 1) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + std::wstring expected_locale_name(argv[0]); + static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func = NULL; + if (!GetUserDefaultLocaleName_func) { + // GetUserDefaultLocaleName is not available on WIN XP. So we'll + // load it on-the-fly. + HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName); + if (!kernel32_dll) { + return SBOX_TEST_FAILED; + } + GetUserDefaultLocaleName_func = + reinterpret_cast<GetUserDefaultLocaleNameFunction>( + GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName")); + if (!GetUserDefaultLocaleName_func) { + return SBOX_TEST_FAILED; + } + } + wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {0}; + // This will cause an exception if not warmed up suitably. + int ret = GetUserDefaultLocaleName_func( + locale_name, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t)); + if (!ret) { + return SBOX_TEST_FAILED; + } + if (!wcsnlen(locale_name, LOCALE_NAME_MAX_LENGTH)) { + return SBOX_TEST_FAILED; + } + if (0 == wcsncmp(locale_name, expected_locale_name.c_str(), + LOCALE_NAME_MAX_LENGTH)) { + return SBOX_TEST_SUCCEEDED; + } + return SBOX_TEST_FAILED; +} + +TEST(LpcPolicyTest, GetUserDefaultLocaleName) { + // GetUserDefaultLocaleName is not available before Vista. + if (base::win::GetVersion() < base::win::VERSION_VISTA) { + return; + } + static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func = NULL; + if (!GetUserDefaultLocaleName_func) { + // GetUserDefaultLocaleName is not available on WIN XP. So we'll + // load it on-the-fly. + HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName); + EXPECT_NE(NULL, int(kernel32_dll)); + GetUserDefaultLocaleName_func = + reinterpret_cast<GetUserDefaultLocaleNameFunction>( + GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName")); + EXPECT_NE(NULL, int(GetUserDefaultLocaleName_func)); + } + wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {0}; + EXPECT_NE(0, GetUserDefaultLocaleName_func( + locale_name, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t))); + EXPECT_NE(0U, wcsnlen(locale_name, LOCALE_NAME_MAX_LENGTH)); + std::wstring cmd = + L"Lpc_GetUserDefaultLocaleName " + std::wstring(locale_name); + TestRunner runner; + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd.c_str())); +} + +} // namespace sandbox diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h index c1af857..0c3e847 100644 --- a/sandbox/win/src/sandbox_policy.h +++ b/sandbox/win/src/sandbox_policy.h @@ -80,7 +80,7 @@ class TargetPolicy { // not compatible with AppContainer, see SetAppContainer. // lockdown: the security level for the token that comes into force after the // process calls TargetServices::LowerToken() or the process calls - // ReverToSelf(). See the explanation of each level in the TokenLevel + // RevertToSelf(). See the explanation of each level in the TokenLevel // definition. // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise. // Returns false if the lockdown value is more permissive than the initial diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h index 3e531be..b749b9c 100644 --- a/sandbox/win/src/sandbox_types.h +++ b/sandbox/win/src/sandbox_types.h @@ -54,13 +54,14 @@ enum ResultCode { // If the sandbox cannot create a secure environment for the target, the // target will be forcibly terminated. These are the process exit codes. enum TerminationCodes { - SBOX_FATAL_INTEGRITY = 7006, // Could not set the integrity level. - 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_MITIGATION = 7011, // Could not set the mitigation policy. - SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit. + SBOX_FATAL_INTEGRITY = 7006, // Could not set the integrity level. + 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_MITIGATION = 7011, // Could not set the mitigation policy. + SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit. + SBOX_FATAL_WARMUP = 7013, // Failed to warmup. SBOX_FATAL_LAST }; diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc index 116f0c9..e10f7ca 100644 --- a/sandbox/win/src/target_services.cc +++ b/sandbox/win/src/target_services.cc @@ -59,6 +59,44 @@ bool CloseOpenHandles(bool* is_csrss_connected) { return true; } +// GetUserDefaultLocaleName is not available on WIN XP. So we'll +// load it on-the-fly. +const wchar_t kKernel32DllName[] = L"kernel32.dll"; +typedef decltype(GetUserDefaultLocaleName)* GetUserDefaultLocaleNameFunction; + +// Warm up language subsystems before the sandbox is turned on. +// Tested on Win8.1 x64: +// This needs to happen after RevertToSelf() is called, because (at least) in +// the case of GetUserDefaultLCID() it checks the TEB to see if the process is +// impersonating (TEB!IsImpersonating). If it is, the cached locale information +// is not used, nor is it set. Therefore, calls after RevertToSelf() will not +// have warmed-up values to use. +bool WarmupWindowsLocales() { + // NOTE(liamjm): When last checked (Win 8.1 x64) it wasn't necessary to + // warmup all of these functions, but let's not assume that. + ::GetUserDefaultLangID(); + ::GetUserDefaultLCID(); + if (base::win::GetVersion() >= base::win::VERSION_VISTA) { + static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func = + NULL; + if (!GetUserDefaultLocaleName_func) { + HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName); + if (!kernel32_dll) { + return false; + } + GetUserDefaultLocaleName_func = + reinterpret_cast<GetUserDefaultLocaleNameFunction>( + GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName")); + if (!GetUserDefaultLocaleName_func) { + return false; + } + } + wchar_t localeName[LOCALE_NAME_MAX_LENGTH] = {0}; + return (0 != GetUserDefaultLocaleName_func( + localeName, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t))); + } + return true; +} // Used as storage for g_target_services, because other allocation facilities // are not available early. We can't use a regular function static because on @@ -97,6 +135,8 @@ void TargetServicesBase::LowerToken() { ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES); if (ERROR_SUCCESS != ::RegDisablePredefinedCache()) ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE); + if (!WarmupWindowsLocales()) + ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_WARMUP); bool is_csrss_connected = true; if (!CloseOpenHandles(&is_csrss_connected)) ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES); diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 470e428..f5d580a 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -57891,6 +57891,7 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries. <int value="7010" label="SBOX_FATAL_CLOSEHANDLES"/> <int value="7011" label="SBOX_FATAL_MITIGATION"/> <int value="7012" label="SBOX_FATAL_MEMORY_EXCEEDED"/> + <int value="7013" label="SBOX_FATAL_WARMUP"/> <int value="529697949" label="CPP_EH_EXCEPTION"/> <int value="533692099" label="STATUS_GUARD_PAGE_VIOLATION"/> <int value="1073740791" label="STATUS_STACK_BUFFER_OVERRUN"/> |