diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 15:06:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:48:58 +0000 |
commit | daa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch) | |
tree | 96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/chrome_elf | |
parent | be59a35641616a4cf23c4a13fa0632624b021c1b (diff) | |
download | qtwebengine-chromium-daa093eea7c773db06799a13bd7e4e2e2a9f8f14.tar.gz |
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/chrome_elf')
-rw-r--r-- | chromium/chrome_elf/BUILD.gn | 35 | ||||
-rw-r--r-- | chromium/chrome_elf/DEPS | 6 | ||||
-rw-r--r-- | chromium/chrome_elf/blacklist/blacklist.cc | 10 | ||||
-rw-r--r-- | chromium/chrome_elf/blacklist/blacklist.h | 4 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_main.cc | 4 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_main.h | 5 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_test_stubs.cc | 2 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_x64.def | 38 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_x86.def | 34 | ||||
-rw-r--r-- | chromium/chrome_elf/crash/crash_helper.cc | 22 | ||||
-rw-r--r-- | chromium/chrome_elf/crash/crash_helper.h | 3 | ||||
-rw-r--r-- | chromium/chrome_elf/elf_imports_unittest.cc | 44 | ||||
-rw-r--r-- | chromium/chrome_elf/nt_registry/nt_registry.cc | 161 | ||||
-rw-r--r-- | chromium/chrome_elf/nt_registry/nt_registry.h | 27 | ||||
-rw-r--r-- | chromium/chrome_elf/nt_registry/nt_registry_unittest.cc | 303 | ||||
-rw-r--r-- | chromium/chrome_elf/run_all_unittests.cc | 3 |
16 files changed, 451 insertions, 250 deletions
diff --git a/chromium/chrome_elf/BUILD.gn b/chromium/chrome_elf/BUILD.gn index f8ac4823fa0..1276a06ac02 100644 --- a/chromium/chrome_elf/BUILD.gn +++ b/chromium/chrome_elf/BUILD.gn @@ -28,6 +28,14 @@ windows_manifest("chrome_elf_manifest") { ] } +# Users of chrome_elf exports can depend on this target, which doesn't +# pin them to linking either chrome_elf.dll or test_stubs. +source_set("chrome_elf_main_include") { + sources = [ + "chrome_elf_main.h", + ] +} + # We should move chrome_result_codes.h to another target which does not bring # in the world. shared_library("chrome_elf") { @@ -219,7 +227,6 @@ test("chrome_elf_unittests") { sources = [ "blacklist/test/blacklist_test.cc", "chrome_elf_util_unittest.cc", - "elf_imports_unittest.cc", "hook_util/test/hook_util_test.cc", "nt_registry/nt_registry_unittest.cc", "run_all_unittests.cc", @@ -236,7 +243,6 @@ test("chrome_elf_unittests") { ":security", "//base", "//base/test:test_support", - "//chrome", "//chrome/common:version_header", "//chrome/install_static:install_static_util", "//chrome/install_static/test:test_support", @@ -244,6 +250,28 @@ test("chrome_elf_unittests") { "//sandbox", "//testing/gtest", ] + data_deps = [ + ":blacklist_test_dll_1", + ":blacklist_test_dll_2", + ":blacklist_test_dll_3", + ":chrome_elf", + ] +} + +test("chrome_elf_import_unittests") { + output_name = "chrome_elf_import_unittests" + sources = [ + "elf_imports_unittest.cc", + ] + include_dirs = [ "$target_gen_dir" ] + deps = [ + "//base", + "//base/test:test_support", + "//chrome", + "//chrome/install_static:install_static_util", + "//chrome/install_static/test:test_support", + "//testing/gtest", + ] # It's not easily possible to have //chrome in data_deps without changing # the //chrome target to bundle up both initial/chrome.exe and chrome.exe. @@ -253,9 +281,6 @@ test("chrome_elf_unittests") { "$root_out_dir/chrome.exe", ] data_deps = [ - ":blacklist_test_dll_1", - ":blacklist_test_dll_2", - ":blacklist_test_dll_3", ":chrome_elf", ] diff --git a/chromium/chrome_elf/DEPS b/chromium/chrome_elf/DEPS index 484d1cf8239..978ee2231d3 100644 --- a/chromium/chrome_elf/DEPS +++ b/chromium/chrome_elf/DEPS @@ -1,11 +1,11 @@ include_rules = [ - "+sandbox", - "+breakpad/src/client", "+chrome/app/chrome_crash_reporter_client_win.h", "+chrome/common/chrome_switches.h", "+chrome/common/chrome_version.h", "+chrome/install_static", - "+third_party/crashpad/crashpad/client/crashpad_client.h", "+components/crash/content/app/crashpad.h", "+components/crash/core/common/crash_keys.h", + "+sandbox", + "+third_party/breakpad/breakpad/src/client", + "+third_party/crashpad/crashpad/client/crashpad_client.h", ] diff --git a/chromium/chrome_elf/blacklist/blacklist.cc b/chromium/chrome_elf/blacklist/blacklist.cc index d7609d4a851..cfcb86cf323 100644 --- a/chromium/chrome_elf/blacklist/blacklist.cc +++ b/chromium/chrome_elf/blacklist/blacklist.cc @@ -194,16 +194,6 @@ bool IsBlacklistInitialized() { return g_blacklist_initialized; } -int GetBlacklistIndex(const wchar_t* dll_name) { - for (int i = 0; - i < static_cast<int>(kTroublesomeDllsMaxCount) && g_troublesome_dlls[i]; - ++i) { - if (_wcsicmp(dll_name, g_troublesome_dlls[i]) == 0) - return i; - } - return -1; -} - bool AddDllToBlacklist(const wchar_t* dll_name) { int blacklist_size = BlacklistSize(); // We need to leave one space at the end for the null pointer. diff --git a/chromium/chrome_elf/blacklist/blacklist.h b/chromium/chrome_elf/blacklist/blacklist.h index 0b6a0a72e1e..1f47dfe4099 100644 --- a/chromium/chrome_elf/blacklist/blacklist.h +++ b/chromium/chrome_elf/blacklist/blacklist.h @@ -42,10 +42,6 @@ extern "C" int BlacklistSize(); // Returns if true if the blacklist has been initialized. extern "C" bool IsBlacklistInitialized(); -// Returns the index of the DLL named |dll_name| on the blacklist, or -1 if not -// found. -extern "C" int GetBlacklistIndex(const wchar_t* dll_name); - // Adds the given dll name to the blacklist. Returns true if the dll name is in // the blacklist when this returns, false on error. Note that this will copy // |dll_name| and will leak it on exit if the string is not subsequently removed diff --git a/chromium/chrome_elf/chrome_elf_main.cc b/chromium/chrome_elf/chrome_elf_main.cc index 2df2f56070d..50912fe157e 100644 --- a/chromium/chrome_elf/chrome_elf_main.cc +++ b/chromium/chrome_elf/chrome_elf_main.cc @@ -69,3 +69,7 @@ BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) { void DumpProcessWithoutCrash() { elf_crash::DumpWithoutCrashing(); } + +void SetMetricsClientId(const char* client_id) { + elf_crash::SetMetricsClientIdImpl(client_id); +} diff --git a/chromium/chrome_elf/chrome_elf_main.h b/chromium/chrome_elf/chrome_elf_main.h index 71eb69b6d60..c313294fe6f 100644 --- a/chromium/chrome_elf/chrome_elf_main.h +++ b/chromium/chrome_elf/chrome_elf_main.h @@ -6,7 +6,7 @@ #define CHROME_ELF_CHROME_ELF_MAIN_H_ // These functions are the cross-module import interface to chrome_elf.dll. -// It is used chrome.exe, chrome.dll and other clients of chrome_elf. +// It is used by chrome.exe, chrome.dll and other clients of chrome_elf. // In tests, these functions are stubbed by implementations in // chrome_elf_test_stubs.cc. extern "C" { @@ -25,6 +25,9 @@ bool GetUserDataDirectoryThunk(wchar_t* user_data_dir, void SignalInitializeCrashReporting(); void SignalChromeElf(); +// Sets the metrics client ID in crash keys. +void SetMetricsClientId(const char* client_id); + } // extern "C" #endif // CHROME_ELF_CHROME_ELF_MAIN_H_ diff --git a/chromium/chrome_elf/chrome_elf_test_stubs.cc b/chromium/chrome_elf/chrome_elf_test_stubs.cc index bec3eea7276..240c6b22931 100644 --- a/chromium/chrome_elf/chrome_elf_test_stubs.cc +++ b/chromium/chrome_elf/chrome_elf_test_stubs.cc @@ -33,3 +33,5 @@ bool GetUserDataDirectoryThunk(wchar_t* user_data_dir, return !user_data_dir_path.empty(); } + +void SetMetricsClientId(const char* client_id) {} diff --git a/chromium/chrome_elf/chrome_elf_x64.def b/chromium/chrome_elf/chrome_elf_x64.def index 184b7989a29..c8b8a249a56 100644 --- a/chromium/chrome_elf/chrome_elf_x64.def +++ b/chromium/chrome_elf/chrome_elf_x64.def @@ -7,21 +7,27 @@ EXPORTS ; When functions are added to this file, they must also be added to ; chrome_elf_x86.def - ; From components/crash/content/app/crashpad.cc - ClearCrashKeyValueImpl - ClearCrashKeyValueImplEx - RequestSingleCrashUploadImpl - SetCrashKeyValueImpl - SetCrashKeyValueImplEx - SetUploadConsentImpl - - ; From components/crash/content/app/crashpad_win.cc - CrashForException - InjectDumpForHungInput - InjectDumpForHungInputNoCrashKeys + ; From components/crash/content/app/crash_export_stubs.cc + ClearCrashKeyValueEx_ExportThunk + ClearCrashKeyValue_ExportThunk + CrashForException_ExportThunk + GetCrashReports_ExportThunk + InjectDumpForHungInputNoCrashKeys_ExportThunk + InjectDumpForHungInput_ExportThunk + RequestSingleCrashUpload_ExportThunk + SetCrashKeyValueEx_ExportThunk + SetCrashKeyValue_ExportThunk + SetUploadConsent_ExportThunk + + ; X64-only exports + RegisterNonABICompliantCodeRange_ExportThunk + UnregisterNonABICompliantCodeRange_ExportThunk + + ; This export is used by SyzyASAN, do not rename or remove without talking + ; to syzygy-team@chromium.org first. + SetCrashKeyValue = SetCrashKeyValue_ExportThunk ; From chrome_elf/crash_helper.cc - GetCrashReportsImpl SetMetricsClientId ; From chrome_elf_main.cc @@ -35,11 +41,5 @@ EXPORTS ; From chrome_elf/blacklist.cc AddDllToBlacklist - GetBlacklistIndex IsBlacklistInitialized SuccessfullyBlocked - - ; X64-only exports - ; From components/crash/content/app/crashpad_win.cc - RegisterNonABICompliantCodeRange - UnregisterNonABICompliantCodeRange diff --git a/chromium/chrome_elf/chrome_elf_x86.def b/chromium/chrome_elf/chrome_elf_x86.def index d49b5e50cca..e51bf1653cb 100644 --- a/chromium/chrome_elf/chrome_elf_x86.def +++ b/chromium/chrome_elf/chrome_elf_x86.def @@ -1,28 +1,29 @@ ; Copyright 2013 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. - LIBRARY "chrome_elf.dll" EXPORTS ; When functions are added to this file, they must also be added to - ; chrome_elf_x64.def - - ; From components/crash/content/app/crashpad.cc - ClearCrashKeyValueImpl - ClearCrashKeyValueImplEx - RequestSingleCrashUploadImpl - SetCrashKeyValueImpl - SetCrashKeyValueImplEx - SetUploadConsentImpl - - ; From components/crash/content/app/crashpad_win.cc - CrashForException - InjectDumpForHungInput - InjectDumpForHungInputNoCrashKeys + ; chrome_elf_x86.def + + ; From components/crash/content/app/crash_export_stubs.cc + ClearCrashKeyValueEx_ExportThunk + ClearCrashKeyValue_ExportThunk + CrashForException_ExportThunk + GetCrashReports_ExportThunk + InjectDumpForHungInputNoCrashKeys_ExportThunk + InjectDumpForHungInput_ExportThunk + RequestSingleCrashUpload_ExportThunk + SetCrashKeyValueEx_ExportThunk + SetCrashKeyValue_ExportThunk + SetUploadConsent_ExportThunk + + ; This export is used by SyzyASAN, do not rename or remove without talking + ; to syzygy-team@chromium.org first. + SetCrashKeyValue = SetCrashKeyValue_ExportThunk ; From chrome_elf/crash_helper.cc - GetCrashReportsImpl SetMetricsClientId ; From chrome_elf_main.cc @@ -36,6 +37,5 @@ EXPORTS ; From chrome_elf/blacklist.cc AddDllToBlacklist - GetBlacklistIndex IsBlacklistInitialized SuccessfullyBlocked diff --git a/chromium/chrome_elf/crash/crash_helper.cc b/chromium/chrome_elf/crash/crash_helper.cc index e1bede4790c..e8e27dc4ebd 100644 --- a/chromium/chrome_elf/crash/crash_helper.cc +++ b/chromium/chrome_elf/crash/crash_helper.cc @@ -118,29 +118,11 @@ void DumpWithoutCrashing() { crash_reporter::DumpWithoutCrashing(); } -} // namespace elf_crash - -//------------------------------------------------------------------------------ -// Exported crash APIs for the rest of the process. -//------------------------------------------------------------------------------ - -// This helper is invoked by code in chrome.dll to retrieve the crash reports. -// See CrashUploadListCrashpad. Note that we do not pass a std::vector here, -// because we do not want to allocate/free in different modules. The returned -// pointer is read-only. -// -// NOTE: Since the returned pointer references read-only memory that will be -// cleaned up when this DLL unloads, be careful not to reference the memory -// beyond that point (e.g. during tests). -extern "C" { - -// This helper is invoked by debugging code in chrome to register the client -// id. -void SetMetricsClientId(const char* client_id) { +void SetMetricsClientIdImpl(const char* client_id) { if (!g_crash_helper_enabled) return; if (client_id) crash_keys::SetMetricsClientIdFromGUID(client_id); } -} // extern "C" +} // namespace elf_crash diff --git a/chromium/chrome_elf/crash/crash_helper.h b/chromium/chrome_elf/crash/crash_helper.h index c1bc1cebd35..b15d67e8595 100644 --- a/chromium/chrome_elf/crash/crash_helper.h +++ b/chromium/chrome_elf/crash/crash_helper.h @@ -31,6 +31,9 @@ int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers); // Generate a crash dump by calling into crashpad. void DumpWithoutCrashing(); +// Set the metrics client ID in crash keys. +void SetMetricsClientIdImpl(const char* client_id); + } // namespace elf_crash #endif // CHROME_ELF_CRASH_CRASH_HELPER_H_ diff --git a/chromium/chrome_elf/elf_imports_unittest.cc b/chromium/chrome_elf/elf_imports_unittest.cc index 96e078c96ca..dfcb9b9fddd 100644 --- a/chromium/chrome_elf/elf_imports_unittest.cc +++ b/chromium/chrome_elf/elf_imports_unittest.cc @@ -9,6 +9,7 @@ #include <vector> #include "base/base_paths.h" +#include "base/bind.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" @@ -17,7 +18,11 @@ #include "base/strings/pattern.h" #include "base/strings/string_util.h" #include "base/test/launcher/test_launcher.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" #include "base/win/pe_image.h" +#include "build/build_config.h" +#include "chrome/install_static/test/scoped_install_details.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -75,8 +80,9 @@ TEST_F(ELFImportsTest, ChromeElfSanityCheck) { GetImports(dll, &elf_imports); // Check that ELF has imports. - ASSERT_LT(0u, elf_imports.size()) << "Ensure the chrome_elf_unittests " - "target was built, instead of chrome_elf_unittests.exe"; + ASSERT_LT(0u, elf_imports.size()) + << "Ensure the chrome_elf_import_unittests " + "target was built, instead of chrome_elf_import_unittests.exe"; static const char* const kValidFilePatterns[] = { "KERNEL32.dll", @@ -141,9 +147,9 @@ TEST_F(ELFImportsTest, DISABLED_ChromeElfLoadSanityTestImpl) { ASSERT_TRUE(PathService::Get(base::DIR_EXE, &dll)); dll = dll.Append(L"chrome_elf.dll"); - // We don't expect user32 to be loaded in chrome_elf_unittests. If this test - // case fails, then it means that a dependency on user32 has crept into the - // chrome_elf_unittests executable, which needs to be removed. + // We don't expect user32 to be loaded in chrome_elf_import_unittests. If this + // test case fails, then it means that a dependency on user32 has crept into + // the chrome_elf_imports_unittests executable, which needs to be removed. // NOTE: it may be a secondary dependency of another system DLL. If so, // try adding a "/DELAYLOAD:<blah>.dll" to the build.gn file. ASSERT_EQ(nullptr, ::GetModuleHandle(L"user32.dll")); @@ -166,13 +172,31 @@ TEST_F(ELFImportsTest, ChromeExeSanityCheck) { GetImports(exe, &exe_imports); // Check that chrome.exe has imports. - ASSERT_LT(0u, exe_imports.size()) << "Ensure the chrome_elf_unittests " - "target was built, instead of chrome_elf_unittests.exe"; + ASSERT_LT(0u, exe_imports.size()) + << "Ensure the chrome_elf_import_unittests " + "target was built, instead of chrome_elf_import_unittests.exe"; // Chrome.exe's first import must be ELF. - EXPECT_EQ("chrome_elf.dll", exe_imports[0]) << - "Illegal import order in chrome.exe (ensure the chrome_elf_unittest " - "target was built, instead of just chrome_elf_unittests.exe)"; + EXPECT_EQ("chrome_elf.dll", exe_imports[0]) + << "Illegal import order in chrome.exe (ensure the " + "chrome_elf_import_unittest " + "target was built, instead of just chrome_elf_import_unittests.exe)"; } } // namespace + +int main(int argc, char** argv) { + // Ensure that the CommandLine instance honors the command line passed in + // instead of the default behavior on Windows which is to use the shell32 + // CommandLineToArgvW API. The chrome_elf_imports_unittests test suite should + // not depend on user32 directly or indirectly (For the curious shell32 + // depends on user32) + base::CommandLine::InitUsingArgvForTesting(argc, argv); + + install_static::ScopedInstallDetails scoped_install_details; + + base::TestSuite test_suite(argc, argv); + return base::LaunchUnitTests( + argc, argv, + base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); +} diff --git a/chromium/chrome_elf/nt_registry/nt_registry.cc b/chromium/chrome_elf/nt_registry/nt_registry.cc index aca2a074da9..69b11c7557e 100644 --- a/chromium/chrome_elf/nt_registry/nt_registry.cc +++ b/chromium/chrome_elf/nt_registry/nt_registry.cc @@ -17,6 +17,8 @@ NtCreateKeyFunction g_nt_create_key = nullptr; NtDeleteKeyFunction g_nt_delete_key = nullptr; NtOpenKeyExFunction g_nt_open_key_ex = nullptr; NtCloseFunction g_nt_close = nullptr; +NtQueryKeyFunction g_nt_query_key = nullptr; +NtEnumerateKeyFunction g_nt_enumerate_key = nullptr; NtQueryValueKeyFunction g_nt_query_value_key = nullptr; NtSetValueKeyFunction g_nt_set_value_key = nullptr; @@ -28,6 +30,10 @@ wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\"; wchar_t g_kRegPathHKCU[nt::g_kRegMaxPathLen + 1] = L""; wchar_t g_current_user_sid_string[nt::g_kRegMaxPathLen + 1] = L""; +// Max number of tries for system API calls when STATUS_BUFFER_TOO_SMALL can be +// returned. +enum { kMaxTries = 5 }; + // For testing only. wchar_t g_HKLM_override[nt::g_kRegMaxPathLen + 1] = L""; wchar_t g_HKCU_override[nt::g_kRegMaxPathLen + 1] = L""; @@ -88,6 +94,12 @@ bool InitNativeRegApi() { g_nt_close = reinterpret_cast<NtCloseFunction>(::GetProcAddress(ntdll, "NtClose")); + g_nt_query_key = reinterpret_cast<NtQueryKeyFunction>( + ::GetProcAddress(ntdll, "NtQueryKey")); + + g_nt_enumerate_key = reinterpret_cast<NtEnumerateKeyFunction>( + ::GetProcAddress(ntdll, "NtEnumerateKey")); + g_nt_query_value_key = reinterpret_cast<NtQueryValueKeyFunction>( ::GetProcAddress(ntdll, "NtQueryValueKey")); @@ -95,8 +107,8 @@ bool InitNativeRegApi() { ::GetProcAddress(ntdll, "NtSetValueKey")); if (!g_rtl_init_unicode_string || !g_nt_create_key || !g_nt_open_key_ex || - !g_nt_delete_key || !g_nt_close || !g_nt_query_value_key || - !g_nt_set_value_key) + !g_nt_delete_key || !g_nt_close || !g_nt_query_key || + !g_nt_enumerate_key || !g_nt_query_value_key || !g_nt_set_value_key) return false; // We need to set HKCU based on the sid of the current user account. @@ -620,8 +632,8 @@ bool CreateRegKey(ROOT_KEY root, ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1) return false; - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return false; if (root == nt::AUTO) root = g_system_install ? nt::HKLM : nt::HKCU; @@ -711,8 +723,8 @@ bool OpenRegKey(ROOT_KEY root, ::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1) return false; - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return false; NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING key_path_uni = {}; @@ -746,17 +758,12 @@ bool OpenRegKey(ROOT_KEY root, } bool DeleteRegKey(HANDLE key) { - if (!g_initialized) - InitNativeRegApi(); - - NTSTATUS status = STATUS_UNSUCCESSFUL; - - status = g_nt_delete_key(key); + if (!g_initialized && !InitNativeRegApi()) + return false; - if (NT_SUCCESS(status)) - return true; + NTSTATUS status = g_nt_delete_key(key); - return false; + return NT_SUCCESS(status); } // wrapper function @@ -791,27 +798,27 @@ bool QueryRegKeyValue(HANDLE key, const wchar_t* value_name, ULONG* out_type, std::vector<BYTE>* out_buffer) { - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return false; - NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; UNICODE_STRING value_uni = {}; g_rtl_init_unicode_string(&value_uni, value_name); - DWORD size_needed = 0; - - // First call to find out how much room we need for the value! - ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, - nullptr, 0, &size_needed); - if (ntstatus != STATUS_BUFFER_TOO_SMALL) - return false; - std::unique_ptr<BYTE[]> buffer(new BYTE[size_needed]); - KEY_VALUE_FULL_INFORMATION* value_info = - reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(buffer.get()); + // Use a loop here, to be a little more tolerant of concurrent registry + // changes. + NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; + int tries = 0; + DWORD size_needed = 1; + std::vector<BYTE> buffer; + KEY_VALUE_FULL_INFORMATION* value_info = nullptr; + do { + buffer.resize(size_needed); + value_info = reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(buffer.data()); + + ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, + value_info, size_needed, &size_needed); + } while (ntstatus == STATUS_BUFFER_TOO_SMALL && ++tries < kMaxTries); - // Second call to get the value. - ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, - value_info, size_needed, &size_needed); if (!NT_SUCCESS(ntstatus)) return false; @@ -967,8 +974,8 @@ bool SetRegKeyValue(HANDLE key, ULONG type, const BYTE* data, DWORD data_size) { - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return false; NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; UNICODE_STRING value_uni = {}; @@ -1093,26 +1100,98 @@ bool SetRegValueMULTISZ(ROOT_KEY root, } //------------------------------------------------------------------------------ +// Enumeration Support +//------------------------------------------------------------------------------ + +bool QueryRegEnumerationInfo(HANDLE key, ULONG* out_subkey_count) { + if (!g_initialized && !InitNativeRegApi()) + return false; + + // Use a loop here, to be a little more tolerant of concurrent registry + // changes. + NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; + int tries = 0; + // Start with sizeof the structure. It's very common for the variable sized + // "Class" element to be of length 0. + DWORD size_needed = sizeof(KEY_FULL_INFORMATION); + std::vector<BYTE> buffer; + KEY_FULL_INFORMATION* key_info = nullptr; + do { + buffer.resize(size_needed); + key_info = reinterpret_cast<KEY_FULL_INFORMATION*>(buffer.data()); + + ntstatus = g_nt_query_key(key, KeyFullInformation, key_info, size_needed, + &size_needed); + } while (ntstatus == STATUS_BUFFER_TOO_SMALL && ++tries < kMaxTries); + + if (!NT_SUCCESS(ntstatus)) + return false; + + // Move desired information to out variables. + *out_subkey_count = key_info->SubKeys; + + return true; +} + +bool QueryRegSubkey(HANDLE key, + ULONG subkey_index, + std::wstring* out_subkey_name) { + if (!g_initialized && !InitNativeRegApi()) + return false; + + // Use a loop here, to be a little more tolerant of concurrent registry + // changes. + NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; + int tries = 0; + // Start with sizeof the structure, plus 12 characters. It's very common for + // key names to be < 12 characters (without being inefficient as an initial + // allocation). + DWORD size_needed = sizeof(KEY_BASIC_INFORMATION) + (12 * sizeof(wchar_t)); + std::vector<BYTE> buffer; + KEY_BASIC_INFORMATION* subkey_info = nullptr; + do { + buffer.resize(size_needed); + subkey_info = reinterpret_cast<KEY_BASIC_INFORMATION*>(buffer.data()); + + ntstatus = g_nt_enumerate_key(key, subkey_index, KeyBasicInformation, + subkey_info, size_needed, &size_needed); + } while (ntstatus == STATUS_BUFFER_TOO_SMALL && ++tries < kMaxTries); + + if (!NT_SUCCESS(ntstatus)) + return false; + + // Move desired information to out variables. + // NOTE: NameLength is size of Name array in bytes. Name array is also + // NOT null terminated! + BYTE* name = reinterpret_cast<BYTE*>(subkey_info->Name); + std::vector<BYTE> content(name, name + subkey_info->NameLength); + EnsureTerminatedSZ(&content, false); + out_subkey_name->assign(reinterpret_cast<wchar_t*>(content.data())); + + return true; +} + +//------------------------------------------------------------------------------ // Utils //------------------------------------------------------------------------------ const wchar_t* GetCurrentUserSidString() { - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return nullptr; return g_current_user_sid_string; } bool IsCurrentProcWow64() { - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return false; return g_wow64_proc; } bool SetTestingOverride(ROOT_KEY root, const std::wstring& new_path) { - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return false; std::wstring sani_new_path = new_path; SanitizeSubkeyPath(&sani_new_path); @@ -1128,8 +1207,8 @@ bool SetTestingOverride(ROOT_KEY root, const std::wstring& new_path) { } std::wstring GetTestingOverride(ROOT_KEY root) { - if (!g_initialized) - InitNativeRegApi(); + if (!g_initialized && !InitNativeRegApi()) + return std::wstring(); if (root == HKCU || (root == AUTO && !g_system_install)) return g_HKCU_override; diff --git a/chromium/chrome_elf/nt_registry/nt_registry.h b/chromium/chrome_elf/nt_registry/nt_registry.h index 5db8771c030..c5d37a3333e 100644 --- a/chromium/chrome_elf/nt_registry/nt_registry.h +++ b/chromium/chrome_elf/nt_registry/nt_registry.h @@ -13,8 +13,10 @@ // Note that this API is currently lazy initialized. Any function that is // NOT merely a wrapper function (i.e. any function that directly interacts with // NTDLL) will immediately check: -// if (!g_initialized) -// InitNativeRegApi(); +// +// if (!g_initialized && !InitNativeRegApi()) +// return false; +// // There is currently no multi-threading lock around the lazy initialization, // as the main client for this API (chrome_elf) does not introduce // a multi-threading concern. This can easily be changed if needed. @@ -73,11 +75,13 @@ bool OpenRegKey(ROOT_KEY root, // Delete a registry key. // - Caller must still call CloseRegKey after the delete. +// - Non-recursive. Must have no subkeys. bool DeleteRegKey(HANDLE key); // Delete a registry key. // - WRAPPER: Function opens and closes the target key for caller. // - Use |wow64_override| to force redirection behaviour, or pass nt::NONE. +// - Non-recursive. Must have no subkeys. bool DeleteRegKey(ROOT_KEY root, WOW64_OVERRIDE wow64_override, const wchar_t* key_path); @@ -223,6 +227,25 @@ bool SetRegValueMULTISZ(ROOT_KEY root, const std::vector<std::wstring>& values); //------------------------------------------------------------------------------ +// Enumeration Support +//------------------------------------------------------------------------------ + +// Query key information for subkey enumeration. +// - Key handle should have been opened with OpenRegKey (with at least +// KEY_ENUMERATE_SUB_KEYS access rights). +// - Currently only returns the number of subkeys. Use |subkey_count| +// in a loop for calling QueryRegSubkey. +bool QueryRegEnumerationInfo(HANDLE key, ULONG* out_subkey_count); + +// Enumerate subkeys by index. +// - Key handle should have been opened with OpenRegKey (with at least +// KEY_ENUMERATE_SUB_KEYS access rights). +// - Get subkey count by calling QueryRegEnumerationInfo. +bool QueryRegSubkey(HANDLE key, + ULONG subkey_index, + std::wstring* out_subkey_name); + +//------------------------------------------------------------------------------ // Utils //------------------------------------------------------------------------------ diff --git a/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc b/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc index ee8f1af0ee8..08728dbcaee 100644 --- a/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc +++ b/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc @@ -8,6 +8,7 @@ #include <rpc.h> #include <stddef.h> +#include "base/callback_helpers.h" #include "base/test/test_reg_util_win.h" #include "testing/gtest/include/gtest/gtest.h" @@ -316,7 +317,7 @@ class NtRegistryTest : public testing::Test { // NT registry API tests //------------------------------------------------------------------------------ -TEST_F(NtRegistryTest, API_DWORD) { +TEST_F(NtRegistryTest, ApiDword) { HANDLE key_handle; const wchar_t* dword_val_name = L"DwordTestValue"; DWORD dword_val = 1234; @@ -326,6 +327,8 @@ TEST_F(NtRegistryTest, API_DWORD) { &key_handle)); ASSERT_NE(key_handle, INVALID_HANDLE_VALUE); ASSERT_NE(key_handle, nullptr); + base::ScopedClosureRunner key_closer( + base::BindOnce(&nt::CloseRegKey, key_handle)); DWORD get_dword = 0; EXPECT_FALSE(nt::QueryRegValueDWORD(key_handle, dword_val_name, &get_dword)); @@ -335,14 +338,12 @@ TEST_F(NtRegistryTest, API_DWORD) { // Get EXPECT_TRUE(nt::QueryRegValueDWORD(key_handle, dword_val_name, &get_dword)); - EXPECT_TRUE(get_dword == dword_val); + EXPECT_EQ(get_dword, dword_val); - // Clean up - EXPECT_TRUE(nt::DeleteRegKey(key_handle)); - nt::CloseRegKey(key_handle); + // Clean up done by NtRegistryTest. } -TEST_F(NtRegistryTest, API_SZ) { +TEST_F(NtRegistryTest, ApiSz) { HANDLE key_handle; const wchar_t* sz_val_name = L"SzTestValue"; std::wstring sz_val = L"blah de blah de blahhhhh."; @@ -363,6 +364,8 @@ TEST_F(NtRegistryTest, API_SZ) { &key_handle)); ASSERT_NE(key_handle, INVALID_HANDLE_VALUE); ASSERT_NE(key_handle, nullptr); + base::ScopedClosureRunner key_closer( + base::BindOnce(&nt::CloseRegKey, key_handle)); std::wstring get_sz; EXPECT_FALSE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz)); @@ -386,44 +389,26 @@ TEST_F(NtRegistryTest, API_SZ) { // Get // ------------------------------ EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz)); - EXPECT_TRUE(get_sz.compare(sz_val) == 0); + EXPECT_EQ(get_sz, sz_val); EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name2, &get_sz)); - EXPECT_TRUE(get_sz.compare(sz_val2) == 0); + EXPECT_EQ(get_sz, sz_val2); EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name3, &get_sz)); // Should be adjusted under the hood to equal sz_val3. - EXPECT_TRUE(get_sz.compare(sz_val3) == 0); + EXPECT_EQ(get_sz, sz_val3); EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name4, &get_sz)); // Should be adjusted under the hood to equal sz_val3. - EXPECT_TRUE(get_sz.compare(sz_val3) == 0); + EXPECT_EQ(get_sz, sz_val3); EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name5, &get_sz)); // Should be adjusted under the hood to an empty string. - EXPECT_TRUE(get_sz.compare(sz_val2) == 0); + EXPECT_EQ(get_sz, sz_val2); - // Clean up - // ------------------------------ - EXPECT_TRUE(nt::DeleteRegKey(key_handle)); - nt::CloseRegKey(key_handle); + // Clean up done by NtRegistryTest. } -TEST_F(NtRegistryTest, API_MULTISZ) { +TEST_F(NtRegistryTest, ApiMultiSz) { HANDLE key_handle; - const wchar_t* multisz_val_name = L"SzmultiTestValue"; - std::vector<std::wstring> multisz_val; - std::wstring multi1 = L"one"; - std::wstring multi2 = L"two"; - std::wstring multi3 = L"three"; - const wchar_t* multisz_val_name2 = L"SzmultiTestValueBad"; - std::wstring multi_empty = L""; - const wchar_t* multisz_val_name3 = L"SzmultiTestValueMalformed"; - const wchar_t* multisz_val_name4 = L"SzmultiTestValueMalformed2"; - const wchar_t* multisz_val_name5 = L"SzmultiTestValueMalformed3"; - const wchar_t* multisz_val_name6 = L"SzmultiTestValueMalformed4"; - std::wstring multisz_val3 = L"malformed"; - BYTE* multisz_val3_byte = reinterpret_cast<BYTE*>(&multisz_val3[0]); - std::vector<BYTE> malform; - for (size_t i = 0; i < (multisz_val3.size() * sizeof(wchar_t)); i++) - malform.push_back(multisz_val3_byte[i]); - const wchar_t* multisz_val_name7 = L"SzmultiTestValueSize0"; + std::vector<std::wstring> multisz_val_set; + std::vector<std::wstring> multisz_val_get; // Create a subkey to play under. // ------------------------------ @@ -431,113 +416,115 @@ TEST_F(NtRegistryTest, API_MULTISZ) { &key_handle)); ASSERT_NE(key_handle, INVALID_HANDLE_VALUE); ASSERT_NE(key_handle, nullptr); + base::ScopedClosureRunner key_closer( + base::BindOnce(&nt::CloseRegKey, key_handle)); - multisz_val.push_back(multi1); - multisz_val.push_back(multi2); - multisz_val.push_back(multi3); - - // Set + // Test 1 - Success // ------------------------------ + const wchar_t* multisz_val_name = L"SzmultiTestValue"; + std::wstring multi1 = L"one"; + std::wstring multi2 = L"two"; + std::wstring multi3 = L"three"; + + multisz_val_set.push_back(multi1); + multisz_val_set.push_back(multi2); + multisz_val_set.push_back(multi3); EXPECT_TRUE( - nt::SetRegValueMULTISZ(key_handle, multisz_val_name, multisz_val)); - multisz_val.clear(); - multisz_val.push_back(multi_empty); + nt::SetRegValueMULTISZ(key_handle, multisz_val_name, multisz_val_set)); EXPECT_TRUE( - nt::SetRegValueMULTISZ(key_handle, multisz_val_name2, multisz_val)); - multisz_val.clear(); + nt::QueryRegValueMULTISZ(key_handle, multisz_val_name, &multisz_val_get)); + EXPECT_EQ(multisz_val_get, multisz_val_set); + multisz_val_set.clear(); + multisz_val_get.clear(); - // No null terminator. + // Test 2 - Bad value + // ------------------------------ + const wchar_t* multisz_val_name2 = L"SzmultiTestValueBad"; + std::wstring multi_empty = L""; + + multisz_val_set.push_back(multi_empty); + EXPECT_TRUE( + nt::SetRegValueMULTISZ(key_handle, multisz_val_name2, multisz_val_set)); + + EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name2, + &multisz_val_get)); + EXPECT_EQ(multisz_val_get.size(), static_cast<DWORD>(0)); + multisz_val_set.clear(); + multisz_val_get.clear(); + + // Test 3 - Malformed + // ------------------------------ + std::wstring multisz_val3 = L"malformed"; + multisz_val_set.push_back(multisz_val3); + BYTE* multisz_val3_byte = reinterpret_cast<BYTE*>(&multisz_val3[0]); + std::vector<BYTE> malform; + for (size_t i = 0; i < (multisz_val3.size() * sizeof(wchar_t)); i++) + malform.push_back(multisz_val3_byte[i]); + + // 3.1: No null terminator. + // ------------------------------ + const wchar_t* multisz_val_name3 = L"SzmultiTestValueMalformed"; EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name3, REG_MULTI_SZ, malform.data(), static_cast<DWORD>(malform.size()))); + EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name3, + &multisz_val_get)); + // Should be adjusted under the hood to equal multisz_val3. + EXPECT_EQ(multisz_val_get, multisz_val_set); + multisz_val_get.clear(); + + // 3.2: Single trailing 0 byte. + // ------------------------------ + const wchar_t* multisz_val_name4 = L"SzmultiTestValueMalformed2"; malform.push_back(0); - // Single trailing 0 byte. EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name4, REG_MULTI_SZ, malform.data(), static_cast<DWORD>(malform.size()))); + EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name4, + &multisz_val_get)); + // Should be adjusted under the hood to equal multisz_val3. + EXPECT_EQ(multisz_val_get, multisz_val_set); + multisz_val_get.clear(); + + // 3.3: Two trailing 0 bytes. + // ------------------------------ + const wchar_t* multisz_val_name5 = L"SzmultiTestValueMalformed3"; malform.push_back(0); - // Two trailing 0 bytes. EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name5, REG_MULTI_SZ, malform.data(), static_cast<DWORD>(malform.size()))); + EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name5, + &multisz_val_get)); + // Should be adjusted under the hood to equal multisz_val3. + EXPECT_EQ(multisz_val_get, multisz_val_set); + multisz_val_get.clear(); + + // 3.4: Three trailing 0 bytes. + // ------------------------------ + const wchar_t* multisz_val_name6 = L"SzmultiTestValueMalformed4"; malform.push_back(0); - // Three trailing 0 bytes. EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name6, REG_MULTI_SZ, malform.data(), static_cast<DWORD>(malform.size()))); - - // Size 0 value. + EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name6, + &multisz_val_get)); + // Should be adjusted under the hood to equal multisz_val3. + EXPECT_EQ(multisz_val_get, multisz_val_set); + multisz_val_set.clear(); + multisz_val_get.clear(); + + // Test 4 - Size zero + // ------------------------------ + const wchar_t* multisz_val_name7 = L"SzmultiTestValueSize0"; EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name7, REG_MULTI_SZ, nullptr, 0)); + EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name7, + &multisz_val_get)); + // Should be empty. + EXPECT_EQ(multisz_val_get, multisz_val_set); - // Get - // ------------------------------ - EXPECT_TRUE( - nt::QueryRegValueMULTISZ(key_handle, multisz_val_name, &multisz_val)); - if (multisz_val.size() == 3) { - EXPECT_TRUE(multi1.compare(multisz_val.at(0)) == 0); - EXPECT_TRUE(multi2.compare(multisz_val.at(1)) == 0); - EXPECT_TRUE(multi3.compare(multisz_val.at(2)) == 0); - } else { - EXPECT_TRUE(false); - } - multisz_val.clear(); - - EXPECT_TRUE( - nt::QueryRegValueMULTISZ(key_handle, multisz_val_name2, &multisz_val)); - EXPECT_EQ(multisz_val.size(), static_cast<DWORD>(0)); - multisz_val.clear(); - - EXPECT_TRUE( - nt::QueryRegValueMULTISZ(key_handle, multisz_val_name3, &multisz_val)); - if (multisz_val.size(), 1) { - // Should be adjusted under the hood to equal sz_val3. - EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0); - } else { - EXPECT_TRUE(false); - } - multisz_val.clear(); - - EXPECT_TRUE( - nt::QueryRegValueMULTISZ(key_handle, multisz_val_name4, &multisz_val)); - if (multisz_val.size(), 1) { - // Should be adjusted under the hood to equal sz_val3. - EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0); - } else { - EXPECT_TRUE(false); - } - multisz_val.clear(); - - EXPECT_TRUE( - nt::QueryRegValueMULTISZ(key_handle, multisz_val_name5, &multisz_val)); - if (multisz_val.size(), 1) { - // Should be adjusted under the hood to equal sz_val3. - EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0); - } else { - EXPECT_TRUE(false); - } - multisz_val.clear(); - - EXPECT_TRUE( - nt::QueryRegValueMULTISZ(key_handle, multisz_val_name6, &multisz_val)); - if (multisz_val.size(), 1) { - // Should be adjusted under the hood to equal sz_val3. - EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0); - } else { - EXPECT_TRUE(false); - } - multisz_val.clear(); - - EXPECT_TRUE( - nt::QueryRegValueMULTISZ(key_handle, multisz_val_name7, &multisz_val)); - // Should be adjusted under the hood to an empty string. - EXPECT_TRUE(multisz_val.empty()); - - // Clean up - // ------------------------------ - EXPECT_TRUE(nt::DeleteRegKey(key_handle)); - nt::CloseRegKey(key_handle); + // Clean up done by NtRegistryTest. } TEST_F(NtRegistryTest, CreateRegKeyRecursion) { @@ -573,6 +560,90 @@ TEST_F(NtRegistryTest, CreateRegKeyRecursion) { ASSERT_NE(key_handle, INVALID_HANDLE_VALUE); ASSERT_NE(key_handle, nullptr); nt::CloseRegKey(key_handle); + + // Clean up done by NtRegistryTest. +} + +TEST_F(NtRegistryTest, ApiEnumeration) { + HANDLE key_handle; + HANDLE subkey_handle; + static constexpr wchar_t key[] = L"NTRegistry\\enum"; + static constexpr wchar_t subkey1[] = L"NTRegistry\\enum\\subkey1"; + static constexpr wchar_t subkey2[] = L"NTRegistry\\enum\\subkey2"; + static constexpr wchar_t subkey3[] = L"NTRegistry\\enum\\subkey3"; + static constexpr const wchar_t* check_names[] = { + L"subkey1", L"subkey2", L"subkey3", + }; + // Test out the "(Default)" value name in this suite. + static constexpr wchar_t subkey_val_name[] = L""; + DWORD subkey_val = 1234; + + // Create a subkey to play under. + // ------------------------------ + ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, key, KEY_ALL_ACCESS, &key_handle)); + ASSERT_NE(key_handle, INVALID_HANDLE_VALUE); + ASSERT_NE(key_handle, nullptr); + base::ScopedClosureRunner key_closer( + base::BindOnce(&nt::CloseRegKey, key_handle)); + + // Set + // ------------------------------ + // Sub-subkey with a default value. + ASSERT_TRUE( + nt::CreateRegKey(nt::HKCU, subkey1, KEY_ALL_ACCESS, &subkey_handle)); + ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE); + ASSERT_NE(subkey_handle, nullptr); + EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val)); + nt::CloseRegKey(subkey_handle); + + // Sub-subkey with a default value. + ASSERT_TRUE( + nt::CreateRegKey(nt::HKCU, subkey2, KEY_ALL_ACCESS, &subkey_handle)); + ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE); + ASSERT_NE(subkey_handle, nullptr); + EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val)); + nt::CloseRegKey(subkey_handle); + + // Sub-subkey with a default value. + ASSERT_TRUE( + nt::CreateRegKey(nt::HKCU, subkey3, KEY_ALL_ACCESS, &subkey_handle)); + ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE); + ASSERT_NE(subkey_handle, nullptr); + EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val)); + nt::CloseRegKey(subkey_handle); + + // Get (via enumeration) + // ------------------------------ + ULONG subkey_count = 0; + EXPECT_TRUE(nt::QueryRegEnumerationInfo(key_handle, &subkey_count)); + ASSERT_EQ(subkey_count, ULONG{3}); + + std::wstring subkey_name; + for (ULONG i = 0; i < subkey_count; i++) { + ASSERT_TRUE(nt::QueryRegSubkey(key_handle, i, &subkey_name)); + + bool found = false; + for (size_t index = 0; index < arraysize(check_names); index++) { + if (0 == subkey_name.compare(check_names[index])) { + found = true; + break; + } + } + ASSERT_TRUE(found); + + // Grab the default DWORD value out of this subkey. + DWORD value = 0; + std::wstring temp(key); + temp.append(L"\\"); + temp.append(subkey_name); + EXPECT_TRUE(nt::QueryRegValueDWORD(nt::HKCU, nt::NONE, temp.c_str(), + subkey_val_name, &value)); + EXPECT_EQ(value, subkey_val); + } + // Also test a known bad index. + EXPECT_FALSE(nt::QueryRegSubkey(key_handle, subkey_count, &subkey_name)); + + // Clean up done by NtRegistryTest. } } // namespace diff --git a/chromium/chrome_elf/run_all_unittests.cc b/chromium/chrome_elf/run_all_unittests.cc index 0f2c930d84a..1f00c731e72 100644 --- a/chromium/chrome_elf/run_all_unittests.cc +++ b/chromium/chrome_elf/run_all_unittests.cc @@ -20,8 +20,7 @@ int main(int argc, char** argv) { install_static::ScopedInstallDetails scoped_install_details; base::TestSuite test_suite(argc, argv); - int ret = base::LaunchUnitTests( + return base::LaunchUnitTests( argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); - return ret; } |