[chrome_elf, third-party block support] Pass file path in registry.
Due to rare case of install_static::GetUserDataDir() path expansion,
this API cannot be used inside DllMain(). The full, expanded path to
the packed blacklist file will be dropped into install_static::GetRegistryPath(),
in the kThirdPartyRegKeyName subkey, in the kBlFilePathRegValue REG_SZ value.
This has no other impact on existing functionality.
- This change includes comments, constants, and tests.
- LogLoadAttempt() will now include the section path for any 'blocked' logs
as well. Friendly reminder that log.AddEntry() will still not add duplicate
'blocked' logs, to protect against spammy logging.
- Removed old bit of uninstaller touching old blacklist.
Test: chrome_elf_unittests.exe, ThirdParty*
Bug: 769590
Change-Id: Id9ada49215aa110db9fb72a4712da9d3fb7ccf31
Reviewed-on: https://chromium-review.googlesource.com/1109600
Reviewed-by: Robert Shield <robertshield@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Penny MacNeil <pennymac@chromium.org>
Cr-Commit-Position: refs/heads/master@{#570849}diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index f8bbe38..b80e2f6b 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -572,12 +572,6 @@
install_static::GetRegistryPath().append(
blacklist::kRegistryBeaconKeyName),
0); // wow64_access
- // The following key is no longer used (https://crbug.com/631771). This
- // cleanup is being left in for a time though.
- InstallUtil::DeleteRegistryKey(
- HKEY_CURRENT_USER,
- install_static::GetRegistryPath().append(L"\\BLFinchList"),
- 0); // wow64_access
}
// Removes the browser's persistent state in the Windows registry for the
diff --git a/chrome_elf/chrome_elf_main.cc b/chrome_elf/chrome_elf_main.cc
index 21242927..0bc157f 100644
--- a/chrome_elf/chrome_elf_main.cc
+++ b/chrome_elf/chrome_elf_main.cc
@@ -47,6 +47,15 @@
return true;
}
+// DllMain
+// -------
+// Warning: The OS loader lock is held during DllMain. Be careful.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971.aspx
+//
+// - Note: Do not use install_static::GetUserDataDir from inside DllMain.
+// This can result in path expansion that triggers secondary DLL loads,
+// that will blow up with the loader lock held.
+// https://bugs.chromium.org/p/chromium/issues/detail?id=748949#c18
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) {
install_static::InitializeProductDetailsForPrimaryModule();
diff --git a/chrome_elf/third_party_dlls/logs.cc b/chrome_elf/third_party_dlls/logs.cc
index 48815e0..d827e61 100644
--- a/chrome_elf/third_party_dlls/logs.cc
+++ b/chrome_elf/third_party_dlls/logs.cc
@@ -179,13 +179,11 @@
elf_sha1::kSHA1Length);
::memcpy(&entry.code_id_hash[0], code_id_hash.data(), elf_sha1::kSHA1Length);
- // Only store full path if the module was allowed to load.
- if (log_type == LogType::kAllowed) {
- entry.full_path = full_image_path;
- // Edge condition. Ensure the path length is <= max(uint32_t) - 1.
- if (entry.full_path.size() > std::numeric_limits<uint32_t>::max() - 1)
- entry.full_path.resize(std::numeric_limits<uint32_t>::max() - 1);
- }
+ // Store the full section path if the module was allowed or blocked.
+ entry.full_path = full_image_path;
+ // Edge condition. Ensure the path length is <= max(uint32_t) - 1.
+ if (entry.full_path.size() > std::numeric_limits<uint32_t>::max() - 1)
+ entry.full_path.resize(std::numeric_limits<uint32_t>::max() - 1);
// Add the new entry.
Log& log =
diff --git a/chrome_elf/third_party_dlls/packed_list_file.cc b/chrome_elf/third_party_dlls/packed_list_file.cc
index 86aadcb37..17a71f7c 100644
--- a/chrome_elf/third_party_dlls/packed_list_file.cc
+++ b/chrome_elf/third_party_dlls/packed_list_file.cc
@@ -12,7 +12,8 @@
#include <algorithm>
#include <limits>
-#include "chrome/install_static/user_data_dir.h"
+#include "chrome/install_static/install_util.h"
+#include "chrome_elf/nt_registry/nt_registry.h"
#include "chrome_elf/third_party_dlls/packed_list_format.h"
namespace third_party_dlls {
@@ -26,7 +27,7 @@
PackedListModule* g_bl_module_array = nullptr;
size_t g_bl_module_array_size = 0;
-// NOTE: this "global" is only initialized once during InitComponent().
+// NOTE: this "global" is only initialized once on first access.
// NOTE: it is wrapped in a function to prevent exit-time dtors.
std::wstring& GetBlFilePath() {
static std::wstring* const file_path = new std::wstring();
@@ -106,20 +107,38 @@
return FileStatus::kSuccess;
}
+// Reads the path to the blacklist file from the registry into |file_path|.
+//
+// - Returns false if the value is not found, is not a REG_SZ, or is empty.
+bool GetFilePathFromRegistry(std::wstring* file_path) {
+ file_path->clear();
+ HANDLE key_handle = nullptr;
+
+ // If the ThirdParty registry key does not exist, it will be created.
+ if (!nt::CreateRegKey(nt::HKCU,
+ install_static::GetRegistryPath()
+ .append(kThirdPartyRegKeyName)
+ .c_str(),
+ KEY_QUERY_VALUE, &key_handle)) {
+ return false;
+ }
+
+ bool found = nt::QueryRegValueSZ(key_handle, kBlFilePathRegValue, file_path);
+ nt::CloseRegKey(key_handle);
+
+ return found && !file_path->empty();
+}
+
// Open a packed data file.
//
-// - Returns kSuccess or kFileNotFound on success.
+// - Returns kSuccess, kFilePathNotFoundInRegistry, or kFileNotFound on success.
FileStatus OpenDataFile(HANDLE* file_handle) {
*file_handle = INVALID_HANDLE_VALUE;
std::wstring& file_path = GetBlFilePath();
// The path may have been overridden for testing.
- if (file_path.empty()) {
- if (!install_static::GetUserDataDirectory(&file_path, nullptr))
- return FileStatus::kUserDataDirFail;
- file_path.append(kFileSubdir);
- file_path.append(kBlFileName);
- }
+ if (file_path.empty() && !GetFilePathFromRegistry(&file_path))
+ return FileStatus::kFilePathNotFoundInRegistry;
// See if file exists. INVALID_HANDLE_VALUE alert!
*file_handle =
@@ -141,17 +160,16 @@
return FileStatus::kSuccess;
}
-// Example file location, relative to user data dir.
-// %localappdata% / Google / Chrome SxS / User Data / ThirdPartyModuleList64 /
-//
-// - NOTE: kFileNotFound and kArraySizeZero are treated as kSuccess.
+// Find the packed blacklist file and read in the array.
+// - NOTE: kFilePathNotFoundInRegistry, kFileNotFound, and kArraySizeZero are
+// treated as kSuccess.
FileStatus InitInternal() {
- // blacklist
- // ---------
HANDLE handle = INVALID_HANDLE_VALUE;
FileStatus status = OpenDataFile(&handle);
- if (status == FileStatus::kFileNotFound)
+ if (status == FileStatus::kFilePathNotFoundInRegistry ||
+ status == FileStatus::kFileNotFound) {
return FileStatus::kSuccess;
+ }
if (status == FileStatus::kSuccess) {
status = ReadInArray(handle, &g_bl_module_array_size, &g_bl_module_array);
::CloseHandle(handle);
diff --git a/chrome_elf/third_party_dlls/packed_list_file.h b/chrome_elf/third_party_dlls/packed_list_file.h
index 9dab05ad..6eebc057 100644
--- a/chrome_elf/third_party_dlls/packed_list_file.h
+++ b/chrome_elf/third_party_dlls/packed_list_file.h
@@ -14,7 +14,7 @@
// "static_cast<int>(FileStatus::value)" to access underlying value.
enum class FileStatus {
kSuccess = 0,
- kUserDataDirFail = 1,
+ kFilePathNotFoundInRegistry = 1,
kFileNotFound = 2,
kFileAccessDenied = 3,
kFileUnexpectedFailure = 4,
diff --git a/chrome_elf/third_party_dlls/packed_list_file_unittest.cc b/chrome_elf/third_party_dlls/packed_list_file_unittest.cc
index c7a7b13..9410ff4 100644
--- a/chrome_elf/third_party_dlls/packed_list_file_unittest.cc
+++ b/chrome_elf/third_party_dlls/packed_list_file_unittest.cc
@@ -14,8 +14,11 @@
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_reg_util_win.h"
#include "base/win/pe_image.h"
+#include "chrome/install_static/install_util.h"
#include "chrome/install_static/user_data_dir.h"
+#include "chrome_elf/nt_registry/nt_registry.h"
#include "chrome_elf/sha1/sha1.h"
#include "chrome_elf/third_party_dlls/packed_list_format.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,6 +29,38 @@
constexpr wchar_t kTestBlFileName[] = L"blfile";
constexpr DWORD kPageSize = 4096;
+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 CreateRegistryKeyValue(const base::string16& full_file_path) {
+ base::win::RegKey key;
+ if (key.Create(HKEY_CURRENT_USER,
+ install_static::GetRegistryPath()
+ .append(kThirdPartyRegKeyName)
+ .c_str(),
+ KEY_WRITE) != ERROR_SUCCESS ||
+ !key.Valid()) {
+ return false;
+ }
+ if (key.WriteValue(kBlFilePathRegValue, full_file_path.c_str()) !=
+ ERROR_SUCCESS)
+ return false;
+
+ return true;
+}
+
struct TestModule {
std::string basename;
DWORD timedatestamp;
@@ -219,5 +254,28 @@
EXPECT_EQ(InitFromFile(), FileStatus::kMetadataReadFail);
}
+// Test successful initialization, getting the file path from registry.
+TEST_F(ThirdPartyFileTest, SuccessFromRegistry) {
+ // 1. Enable reg override for test net.
+ registry_util::RegistryOverrideManager override_manager;
+ ASSERT_NO_FATAL_FAILURE(RegRedirect(nt::HKCU, &override_manager));
+
+ // 2. Add a sample ThirdParty subkey and value, which would be created by
+ // chrome.dll.
+ ASSERT_TRUE(CreateRegistryKeyValue(GetBlTestFilePath()));
+
+ // 3. Drop a blacklist to the expected path.
+ CreateTestFile();
+
+ // Clear override file path so that initialization goes to registry.
+ OverrideFilePathForTesting(L"");
+
+ // 4. Run the test.
+ EXPECT_EQ(InitFromFile(), FileStatus::kSuccess);
+
+ // 5. Disable reg override.
+ ASSERT_NO_FATAL_FAILURE(CancelRegRedirect(nt::HKCU));
+}
+
} // namespace
} // namespace third_party_dlls
diff --git a/chrome_elf/third_party_dlls/packed_list_format.cc b/chrome_elf/third_party_dlls/packed_list_format.cc
index d93898c..c2f8d1c 100644
--- a/chrome_elf/third_party_dlls/packed_list_format.cc
+++ b/chrome_elf/third_party_dlls/packed_list_format.cc
@@ -8,17 +8,11 @@
namespace third_party_dlls {
-// Subdir relative to install_static::GetUserDataDirectory().
-const wchar_t kFileSubdir[] =
- L"\\ThirdPartyModuleList"
-#if defined(_WIN64)
- L"64";
-#else
- L"32";
-#endif
+// Subkey relative to install_static::GetRegistryPath().
+const wchar_t kThirdPartyRegKeyName[] = L"\\ThirdParty";
-// Packed module data cache file.
-const wchar_t kBlFileName[] = L"\\bldata";
+// Subkey value of type REG_SZ to hold a full path to a packed-list file.
+const wchar_t kBlFilePathRegValue[] = L"BlFilePath";
std::string GetFingerprintString(uint32_t image_size,
uint32_t time_data_stamp) {
diff --git a/chrome_elf/third_party_dlls/packed_list_format.h b/chrome_elf/third_party_dlls/packed_list_format.h
index 719a6697..7ede12a 100644
--- a/chrome_elf/third_party_dlls/packed_list_format.h
+++ b/chrome_elf/third_party_dlls/packed_list_format.h
@@ -30,11 +30,11 @@
// second by code_id hash (there can be multiple of the same basename hash).
// -----------------------------------------------------------------------------
-// Subdir relative to install_static::GetUserDataDirectory().
-extern const wchar_t kFileSubdir[];
+// Subkey relative to install_static::GetRegistryPath().
+extern const wchar_t kThirdPartyRegKeyName[];
-// Packed module list cache file.
-extern const wchar_t kBlFileName[];
+// Subkey value of type REG_SZ to hold a full path to a packed-list file.
+extern const wchar_t kBlFilePathRegValue[];
enum PackedListVersion : uint32_t {
kInitialVersion = 1,