Index: sandbox/win/src/target_services.cc |
diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc |
index 116f0c929b81ee71ac9d5f7f686593e56a3e78f4..e10f7ca411488e0393d8ec84c9d32266fbff2aaa 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); |