blob: 6d323053f33395b006980a1f461b6608ec70f2b9 [file] [log] [blame]
// Copyright 2017 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 "chrome_elf/whitelist/whitelist_ime.h"
#include <windows.h>
#include "base/files/file.h"
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
#include "chrome_elf/nt_registry/nt_registry.h"
#include "sandbox/win/src/nt_internals.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace whitelist {
namespace {
constexpr wchar_t kNewGuid[] = L"{12345678-1234-1234-1234-123456789ABC}";
void RegRedirect(nt::ROOT_KEY key,
registry_util::RegistryOverrideManager* rom) {
ASSERT_NE(key, nt::AUTO);
HKEY root = (key == nt::HKCU ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE);
base::string16 temp;
ASSERT_NO_FATAL_FAILURE(rom->OverrideRegistry(root, &temp));
ASSERT_TRUE(nt::SetTestingOverride(key, temp));
}
void CancelRegRedirect(nt::ROOT_KEY key) {
ASSERT_NE(key, nt::AUTO);
ASSERT_TRUE(nt::SetTestingOverride(key, base::string16()));
}
bool GetExistingImeDllPath(std::wstring* path) {
base::win::RegistryKeyIterator ime_iterator(HKEY_LOCAL_MACHINE,
kImeRegistryKey);
// Iterate through IMEs registered on the system until finding one with a
// valid dll path.
for (; ime_iterator.Valid(); ++ime_iterator) {
const wchar_t* guid = ime_iterator.Name();
// Make sure it's a guid.
if (::wcslen(guid) != kGuidLength)
continue;
std::wstring classes_path(kClassesKey);
classes_path.append(guid);
classes_path.push_back(L'\\');
classes_path.append(kClassesSubkey);
base::win::RegKey classes_key(HKEY_LOCAL_MACHINE, classes_path.c_str(),
KEY_QUERY_VALUE);
if (!classes_key.Valid())
continue;
// Grab the default value.
if (classes_key.ReadValue(L"", path) != ERROR_SUCCESS)
continue;
// Make sure the path to a DLL exists. Quite common for it not to.
base::File test(base::FilePath(path->c_str()),
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (test.IsValid())
return true;
}
return false;
}
bool RegisterFakeIme(const wchar_t* new_guid) {
base::win::RegKey parent_key(HKEY_LOCAL_MACHINE, kImeRegistryKey,
KEY_CREATE_SUB_KEY);
if (!parent_key.Valid())
return false;
if (parent_key.CreateKey(new_guid, KEY_WRITE) != ERROR_SUCCESS)
return false;
return true;
}
bool AddClassDllPath(const wchar_t* new_guid, const std::wstring& dll_path) {
base::win::RegKey parent_key(HKEY_LOCAL_MACHINE, kClassesKey,
KEY_CREATE_SUB_KEY);
if (!parent_key.Valid())
return false;
if (parent_key.CreateKey(new_guid, KEY_WRITE) != ERROR_SUCCESS)
return false;
if (parent_key.CreateKey(kClassesSubkey, KEY_WRITE) != ERROR_SUCCESS)
return false;
if (parent_key.WriteValue(L"", dll_path.c_str()) != ERROR_SUCCESS)
return false;
return true;
}
//------------------------------------------------------------------------------
// Whitelist IME tests
//------------------------------------------------------------------------------
// Test initialization with whatever IMEs are on the current machine.
TEST(Whitelist, IMEInitExisting) {
// Init IME!
EXPECT_EQ(InitIMEs(), IMEStatus::kSuccess);
}
// Test initialization with a custom IME to exercise all of the code path for
// non-Microsoft-provided IMEs.
//
// Note: Uses registry test override to protect machine from registry writes.
TEST(Whitelist, IMEInitNonMs) {
// 1. Read in any real registry info needed.
// 2. Enable reg override for test net.
// 3. Write fake registry data.
// 4. InitIMEs()
// 5. Disable reg override.
// 1. Read in any real registry info needed.
// - A dll path to use from an existing MS IME.
std::wstring existing_ime_dll;
ASSERT_TRUE(GetExistingImeDllPath(&existing_ime_dll));
// 2. Enable reg override for test net.
registry_util::RegistryOverrideManager override_manager;
ASSERT_NO_FATAL_FAILURE(RegRedirect(nt::HKLM, &override_manager));
// 3. Add a fake registry IME guid and Class DLL path.
EXPECT_TRUE(RegisterFakeIme(kNewGuid));
EXPECT_TRUE(AddClassDllPath(kNewGuid, existing_ime_dll));
// 4. Init IME!
EXPECT_EQ(InitIMEs(), IMEStatus::kSuccess);
// 5. Disable reg override.
ASSERT_NO_FATAL_FAILURE(CancelRegRedirect(nt::HKLM));
}
} // namespace
} // namespace whitelist