Commit bacb343d authored by Penny MacNeil's avatar Penny MacNeil Committed by Commit Bot

[chrome_elf, third-party block support] Change log format.

- Log format changed to pass values instead of hashes.
- Log.path will now be passed untouched, preserving original case from
  section path.  This allows for potentially case-sensitive operations
  later.
- Testing added to ensure the expected case behaviour,
  ThirdPartyTest.PathCaseSensistive.
- Also, reordered arguments for GetFingerprintString, to be more
  intuitively tied to the format string.

R: pmonette@chromium.org
Test: chrome_elf_unittests.exe, ThirdParty*
Bug: 769590
Change-Id: Ib28ec13da7bf27168513031f583bd47e47da0dcc
Reviewed-on: https://chromium-review.googlesource.com/1136660Reviewed-by: default avatarPatrick Monette <pmonette@chromium.org>
Commit-Queue: Penny MacNeil <pennymac@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575033}
parent 71ac0427
......@@ -10,11 +10,15 @@
#include <vector>
#include "base/bind.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/sha1.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_runner_util.h"
#include "base/task_scheduler/post_task.h"
#include "chrome/browser/conflicts/module_blacklist_cache_util_win.h"
#include "chrome_elf/third_party_dlls/logging_api.h"
#include "chrome_elf/third_party_dlls/packed_list_format.h"
namespace {
......@@ -45,14 +49,31 @@ std::vector<third_party_dlls::PackedListModule> DrainLogOnBackgroundTask() {
// get better visibility into all modules that loads into the browser
// process.
if (entry->type == third_party_dlls::LogType::kBlocked) {
// No log path should be empty.
DCHECK(entry->path_len);
blocked_modules.emplace_back();
third_party_dlls::PackedListModule& module = blocked_modules.back();
std::copy(std::begin(entry->basename_hash),
std::end(entry->basename_hash),
std::begin(module.basename_hash));
std::copy(std::begin(entry->code_id_hash), std::end(entry->code_id_hash),
// Fill in a PackedListModule from the log entry.
std::string hash_string =
base::SHA1HashString(third_party_dlls::GetFingerprintString(
entry->time_date_stamp, entry->module_size));
std::copy(std::begin(hash_string), std::end(hash_string),
std::begin(module.code_id_hash));
// |entry->path| is a UTF-8 device path. A hash of the
// lowercase, UTF-8 basename is needed for |module.basename_hash|.
base::FilePath file_path(base::UTF8ToUTF16(entry->path));
std::wstring basename = base::i18n::ToLower(file_path.BaseName().value());
hash_string = base::UTF16ToUTF8(basename);
hash_string = base::SHA1HashString(hash_string);
std::copy(std::begin(hash_string), std::end(hash_string),
std::begin(module.basename_hash));
module.time_date_stamp = now_time_date_stamp;
// TODO(pmonette): |file_path| is ready for
// base::DevicePathToDriveLetterPath() here if needed.
// Consider making these path conversions more efficient
// by caching the local mounted devices and corresponding
// drive paths once.
}
tracker += third_party_dlls::GetLogEntrySize(entry->path_len);
......
......@@ -9,7 +9,6 @@
#include "base/win/windows_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome_elf/chrome_elf_main.h"
#include "chrome_elf/sha1/sha1.h"
#include "chrome_elf/third_party_dlls/logging_api.h"
// This function is a temporary workaround for https://crbug.com/655788. We
......@@ -48,8 +47,8 @@ void SetMetricsClientId(const char* client_id) {}
struct TestLogEntry {
third_party_dlls::LogType log_type;
uint8_t basename_hash[elf_sha1::kSHA1Length];
uint8_t code_id_hash[elf_sha1::kSHA1Length];
uint32_t module_size;
uint32_t time_date_stamp;
};
// This test stub always writes 2 hardcoded entries into the buffer, if the
......@@ -59,20 +58,8 @@ uint32_t DrainLog(uint8_t* buffer,
uint32_t* log_remaining) {
// Alternate between log types.
TestLogEntry kTestLogEntries[] = {
{
third_party_dlls::LogType::kAllowed,
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19},
{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49},
},
{
third_party_dlls::LogType::kBlocked,
{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB},
{0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD},
},
{third_party_dlls::LogType::kAllowed, 0x9901, 0x12345678},
{third_party_dlls::LogType::kBlocked, 0x9902, 0x12345678},
};
// Each entry shares the module path for convenience.
......@@ -94,10 +81,8 @@ uint32_t DrainLog(uint8_t* buffer,
reinterpret_cast<third_party_dlls::LogEntry*>(tracker);
log_entry->type = test_entry.log_type;
::memcpy(log_entry->basename_hash, test_entry.basename_hash,
sizeof(test_entry.basename_hash));
::memcpy(log_entry->code_id_hash, test_entry.code_id_hash,
sizeof(test_entry.code_id_hash));
log_entry->module_size = test_entry.module_size;
log_entry->time_date_stamp = test_entry.time_date_stamp;
log_entry->path_len = kModulePathLength;
::memcpy(log_entry->path, kModulePath, log_entry->path_len + 1);
......
......@@ -148,7 +148,9 @@ bool UTF16ToUTF8(const std::wstring& utf16, std::string* utf8) {
}
// Helper function to contain the data mining for the values needed.
// - All strings returned are lowercase UTF-8.
// - |image_name| and |section_basename| will be lowercased. |section_path|
// will be left untouched, preserved for case-sensitive operations with it.
// - All strings returned are UTF-8. Treat accordingly.
// - This function succeeds if image_name || section_* is found.
// Note: |section_path| contains |section_basename|, if the section name is
// successfully mined.
......@@ -197,12 +199,11 @@ bool GetDataFromImage(PVOID buffer,
*image_name = std::string(name, ::strnlen(name, MAX_PATH));
}
// Lowercase |image_name|.
for (size_t i = 0; i < image_name->size(); i++)
(*image_name)[i] = tolower((*image_name)[i]);
std::wstring temp_section_path = GetSectionName(buffer);
for (size_t i = 0; i < temp_section_path.size(); i++)
temp_section_path[i] = towlower(temp_section_path[i]);
// For now, consider it a success if at least one source results in a name.
// Allow for the rare case of one or the other not being there.
......@@ -223,7 +224,11 @@ bool GetDataFromImage(PVOID buffer,
temp_section_basename = temp_section_path.substr(sep + 1);
}
// Convert strings from UTF-16 to UTF-8.
// Lowercase |section_basename|.
for (size_t i = 0; i < temp_section_basename.size(); i++)
temp_section_basename[i] = towlower(temp_section_basename[i]);
// Convert section strings from UTF-16 to UTF-8.
return UTF16ToUTF8(temp_section_path, section_path) &&
UTF16ToUTF8(temp_section_basename, section_basename);
}
......@@ -288,54 +293,45 @@ NTSTATUS NewNtMapViewOfSectionImpl(
if (!section_basename.empty())
section_basename_hash = elf_sha1::SHA1HashString(section_basename);
std::string fingerprint_hash =
GetFingerprintString(image_size, time_date_stamp);
GetFingerprintString(time_date_stamp, image_size);
fingerprint_hash = elf_sha1::SHA1HashString(fingerprint_hash);
// Check sources for blacklist decision.
bool block = false;
std::string* name_matched = nullptr;
if (!image_name_hash.empty() &&
IsModuleListed(image_name_hash, fingerprint_hash)) {
// 1) Third-party DLL blacklist, check for image name from PE header.
block = true;
name_matched = &image_name_hash;
} else if (!section_basename_hash.empty() &&
section_basename_hash.compare(image_name_hash) != 0 &&
IsModuleListed(section_basename_hash, fingerprint_hash)) {
// 2) Third-party DLL blacklist, check for image name from the section.
block = true;
name_matched = &section_basename_hash;
} else if (!image_name.empty() && blacklist::DllMatch(image_name)) {
// 3) Hard-coded blacklist with name from PE header (deprecated).
block = true;
name_matched = &image_name_hash;
} else if (!section_basename.empty() &&
section_basename.compare(image_name) != 0 &&
blacklist::DllMatch(section_basename)) {
// 4) Hard-coded blacklist with name from the section (deprecated).
block = true;
name_matched = &section_basename_hash;
} else {
// No block.
// Ensure a non-null image name for the log. Prefer the section basename
// (to match the path).
name_matched =
section_basename.empty() ? &image_name_hash : &section_basename_hash;
}
// Else, no block.
// UNMAP the view. This image is being blocked.
if (block) {
assert(name_matched);
assert(g_nt_unmap_view_of_section_func);
g_nt_unmap_view_of_section_func(process, *base);
ret = STATUS_UNSUCCESSFUL;
}
// LOG!
// - If there was a failure getting |section_path|, at least pass image_name.
LogLoadAttempt((block ? third_party_dlls::LogType::kBlocked
: third_party_dlls::LogType::kAllowed),
*name_matched, fingerprint_hash, section_path);
image_size, time_date_stamp,
section_path.empty() ? image_name : section_path);
return ret;
}
......
......@@ -32,15 +32,16 @@ enum LogType : uint8_t {
// (Full path not required for a blacklisted load attempt log.)
struct LogEntry {
LogType type;
uint8_t basename_hash[20];
uint8_t code_id_hash[20];
uint32_t module_size;
uint32_t time_date_stamp;
// Number of characters in |path| string, not including null terminator.
uint32_t path_len;
// UTF-8 full module path, null termination guaranteed.
char path[1];
};
static_assert(sizeof(LogEntry) == 52,
static_assert(sizeof(LogEntry) == 20,
"Ensure expectations for padding and alignment are correct. "
"If this changes, double check GetLogEntrySize() calculation.");
......
......@@ -26,8 +26,8 @@ HANDLE g_notification_event = nullptr;
// This structure will be translated into LogEntry when draining log.
struct LogEntryInternal {
uint8_t basename_hash[elf_sha1::kSHA1Length];
uint8_t code_id_hash[elf_sha1::kSHA1Length];
uint32_t image_size;
uint32_t time_date_stamp;
std::string full_path;
};
......@@ -36,8 +36,8 @@ void TranslateEntry(LogType log_type,
const LogEntryInternal& src,
LogEntry* dst) {
dst->type = log_type;
::memcpy(dst->basename_hash, src.basename_hash, elf_sha1::kSHA1Length);
::memcpy(dst->code_id_hash, src.code_id_hash, elf_sha1::kSHA1Length);
dst->module_size = src.image_size;
dst->time_date_stamp = src.time_date_stamp;
// Sanity check - there should be no LogEntryInternal with a too long path.
// LogLoadAttempt() ensures this.
......@@ -71,8 +71,7 @@ class Log {
void AddEntry(LogEntryInternal&& entry) {
// Sanity checks. If load blocked, do not add duplicate logs.
if (entries_.size() == kMaxLogEntries ||
(log_type_ == LogType::kBlocked &&
ContainsEntry(entry.basename_hash, entry.code_id_hash))) {
(log_type_ == LogType::kBlocked && ContainsEntry(entry))) {
return;
}
entries_.push_back(std::move(entry));
......@@ -114,11 +113,12 @@ class Log {
private:
// Logs are currently unordered, so just loop.
// - Returns true if the given hashes already exist in the log.
bool ContainsEntry(const uint8_t* basename_hash,
const uint8_t* code_id_hash) const {
bool ContainsEntry(const LogEntryInternal& new_entry) const {
for (auto entry : entries_) {
if (!elf_sha1::CompareHashes(basename_hash, entry.basename_hash) &&
!elf_sha1::CompareHashes(code_id_hash, entry.code_id_hash)) {
// Compare strings last, only if everything else matches, for efficiency.
if (new_entry.image_size == entry.image_size &&
new_entry.time_date_stamp == entry.time_date_stamp &&
new_entry.full_path.compare(entry.full_path) == 0) {
return true;
}
}
......@@ -162,22 +162,18 @@ Log& GetAllowedLog() {
// This is called from inside a hook shim, so don't bother with return status.
void LogLoadAttempt(LogType log_type,
const std::string& basename_hash,
const std::string& code_id_hash,
uint32_t image_size,
uint32_t time_date_stamp,
const std::string& full_image_path) {
assert(g_log_mutex);
assert(!basename_hash.empty() && !code_id_hash.empty());
assert(basename_hash.length() == elf_sha1::kSHA1Length &&
code_id_hash.length() == elf_sha1::kSHA1Length);
if (::WaitForSingleObject(g_log_mutex, kMaxMutexWaitMs) != WAIT_OBJECT_0)
return;
// Build the new log entry.
LogEntryInternal entry;
::memcpy(&entry.basename_hash[0], basename_hash.data(),
elf_sha1::kSHA1Length);
::memcpy(&entry.code_id_hash[0], code_id_hash.data(), elf_sha1::kSHA1Length);
entry.image_size = image_size;
entry.time_date_stamp = time_date_stamp;
entry.full_path = full_image_path;
// Edge condition. Ensure the path length is <= max(uint32_t) - 1.
......
......@@ -18,14 +18,13 @@ namespace third_party_dlls {
// Adds a module load attempt to the internal load log.
// - |log_type| indicates the type of logging.
// - |basename_hash| and |code_id_hash| must each point to a buffer of size
// elf_sha1::kSHA1Length, holding a SHA-1 digest (of the module's basename and
// code identifier, respectively).
// - For loads that are allowed, |full_image_path| indicates the full path of
// the loaded image.
// - |image_size| and |time_date_stamp| from the PE headers.
// - |full_image_path| indicates the full path of the loaded image.
// - Note: if there was any failure retrieving the full path, pass at least the
// basename for |full_image_path|.
void LogLoadAttempt(LogType log_type,
const std::string& basename_hash,
const std::string& code_id_hash,
uint32_t image_size,
uint32_t time_date_stamp,
const std::string& full_image_path);
// Initialize internal logs.
......
......@@ -28,36 +28,14 @@ struct NotificationHandlerArguments {
};
struct TestEntry {
uint8_t basename_hash[elf_sha1::kSHA1Length];
uint8_t code_id_hash[elf_sha1::kSHA1Length];
uint32_t image_size;
uint32_t time_date_stamp;
};
// Sample TestEntries - hashes are the same, except for first bytes.
// Sample TestEntries
TestEntry kTestLogs[] = {
{{0x11, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71},
{0x22, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71}},
{{0x33, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71},
{0x44, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71}},
{{0x55, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71},
{0x66, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71}},
{{0x77, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71},
{0x88, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71}},
{{0x99, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71},
{0xaa, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71}},
{{0xbb, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71},
{0xcc, 0xab, 0x9e, 0xa4, 0xbe, 0xf5, 0xf3, 0x6e, 0x7f, 0x20,
0xc3, 0xaf, 0x63, 0x9c, 0x6f, 0x0e, 0xfe, 0x5f, 0x27, 0x71}},
{0x9901, 0x12345678}, {0x9902, 0x12345678}, {0x9903, 0x12345678},
{0x9904, 0x12345678}, {0x9905, 0x12345678}, {0x9906, 0x12345678},
};
// Be sure to test the padding/alignment issues well here.
......@@ -82,12 +60,9 @@ void VerifyBuffer(uint8_t* buffer, uint32_t buffer_size) {
while (tracker < buffer + buffer_size) {
entry = reinterpret_cast<LogEntry*>(tracker);
EXPECT_EQ(elf_sha1::CompareHashes(entry->basename_hash,
kTestLogs[index].basename_hash),
0);
EXPECT_EQ(elf_sha1::CompareHashes(entry->code_id_hash,
kTestLogs[index].code_id_hash),
0);
EXPECT_EQ(entry->module_size, kTestLogs[index].image_size);
EXPECT_EQ(entry->time_date_stamp, kTestLogs[index].time_date_stamp);
if (entry->path_len)
EXPECT_STREQ(entry->path, kTestPaths[index].c_str());
......@@ -151,19 +126,13 @@ TEST(ThirdParty, Logs) {
ASSERT_EQ(InitLogs(), ThirdPartyStatus::kSuccess);
for (size_t i = 0; i < arraysize(kTestLogs); ++i) {
std::string fingerprint_hash(
reinterpret_cast<char*>(kTestLogs[i].code_id_hash),
elf_sha1::kSHA1Length);
std::string name_hash(reinterpret_cast<char*>(kTestLogs[i].basename_hash),
elf_sha1::kSHA1Length);
// Add some blocked entries.
LogLoadAttempt(LogType::kBlocked, name_hash, fingerprint_hash,
std::string());
LogLoadAttempt(LogType::kBlocked, kTestLogs[i].image_size,
kTestLogs[i].time_date_stamp, std::string());
// Add some allowed entries.
LogLoadAttempt(LogType::kAllowed, name_hash, fingerprint_hash,
kTestPaths[i]);
LogLoadAttempt(LogType::kAllowed, kTestLogs[i].image_size,
kTestLogs[i].time_date_stamp, kTestPaths[i]);
}
uint32_t initial_log = 0;
......@@ -206,15 +175,9 @@ TEST(ThirdParty, LogNotifications) {
nullptr, 0, &NotificationHandler, &handler_data, 0, nullptr));
for (size_t i = 0; i < handler_data.logs_expected; ++i) {
std::string fingerprint_hash(
reinterpret_cast<char*>(kTestLogs[i].code_id_hash),
elf_sha1::kSHA1Length);
std::string name_hash(reinterpret_cast<char*>(kTestLogs[i].basename_hash),
elf_sha1::kSHA1Length);
// Add blocked entries - type doesn't matter in this test.
LogLoadAttempt(LogType::kBlocked, name_hash, fingerprint_hash,
std::string());
LogLoadAttempt(LogType::kBlocked, kTestLogs[i].image_size,
kTestLogs[i].time_date_stamp, std::string());
}
EXPECT_EQ(::WaitForSingleObject(thread.Get(), kWaitTimeoutMs * 2),
......
......@@ -98,7 +98,7 @@ PackedListModule GeneratePackedListModule(const std::string& image_name,
assert(!image_name.empty());
// SHA1 hash the two strings, and copy them into the new struct.
std::string code_id = GetFingerprintString(imagesize, timedatestamp);
std::string code_id = GetFingerprintString(timedatestamp, imagesize);
code_id = elf_sha1::SHA1HashString(code_id);
std::string name_hash = elf_sha1::SHA1HashString(image_name);
......@@ -487,6 +487,42 @@ TEST_F(ThirdPartyTest, SHA1SanityCheck) {
0);
}
// Test that full section path is left alone, in terms of case.
TEST_F(ThirdPartyTest, PathCaseSensitive) {
// Rename module to have mixed case.
ASSERT_TRUE(MakeFileCopy(GetExeDir(), kTestDllName2, GetScopedTempDirValue(),
kTestDllName1MixedCase));
// 1) Sanity check that the hook GetDataFromImage() mining leaves the
// section path alone.
TestModuleData module_data = {};
ASSERT_TRUE(GetTestModuleData(kTestDllName1MixedCase, GetScopedTempDirValue(),
&module_data));
// Reminder: this string is actually UTF-8, but this test ensures it is ascii.
// Also, |section_path| will be a device path, so convert to drive letter
// before comparing.
base::FilePath drive;
ASSERT_TRUE(base::DevicePathToDriveLetterPath(
base::FilePath(base::ASCIIToUTF16(module_data.section_path)), &drive));
EXPECT_EQ(drive.value().compare(
MakePath(GetScopedTempDirValue(), kTestDllName1MixedCase)),
0);
// 2) Now check an actual log. Successful DLL load with no blacklist is fine
// for this test.
base::CommandLine cmd_line1 = base::CommandLine::FromString(kTestExeFilename);
cmd_line1.AppendArgNative(GetBlTestFilePath());
cmd_line1.AppendArgNative(
base::IntToString16(main_unittest_exe::kTestSingleDllLoad));
cmd_line1.AppendArgNative(
MakePath(GetScopedTempDirValue(), kTestDllName1MixedCase));
int exit_code = 0;
LaunchChildAndWait(cmd_line1, &exit_code);
ASSERT_EQ(main_unittest_exe::kDllLoadSuccess, exit_code);
}
// Test the status-code passing in registry.
TEST_F(ThirdPartyTest, StatusCodes) {
// 1. Enable reg override for test net.
......
......@@ -10,6 +10,7 @@
#include <shellapi.h>
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/scoped_native_library.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_reg_util_win.h"
......@@ -47,6 +48,23 @@ void RegRedirect(registry_util::RegistryOverrideManager* rom) {
nt::SetTestingOverride(nt::HKCU, temp);
}
// Compare an argument path with a module-load log path.
// - |arg_path| is a UTF-16 drive path.
// - |log.section_path| is UTF-8, and will be a device path, so convert to drive
// letter before comparing.
bool MatchPath(const wchar_t* arg_path, const third_party_dlls::LogEntry& log) {
base::FilePath drive_path;
if (!base::DevicePathToDriveLetterPath(
base::FilePath(base::UTF8ToUTF16(log.path)), &drive_path)) {
return false;
}
if (drive_path.value().compare(arg_path) != 0)
return false;
return true;
}
} // namespace
//------------------------------------------------------------------------------
......@@ -110,7 +128,9 @@ int main() {
case kTestOnlyInitialization:
break;
// Single DLL load.
case kTestSingleDllLoad: {
case kTestSingleDllLoad:
// Single DLL load with log path scrutiny.
case kTestLogPath: {
if (argument_count < 4)
return kMissingArgument;
const wchar_t* dll_name = argv[3];
......@@ -127,6 +147,9 @@ int main() {
bytes = DrainLog(&buffer[0], bytes, nullptr);
third_party_dlls::LogEntry* entry =
reinterpret_cast<third_party_dlls::LogEntry*>(&buffer[0]);
if (!bytes || bytes < third_party_dlls::GetLogEntrySize(entry->path_len))
return kBadLogEntrySize;
if ((code == kDllLoadFailed &&
entry->type != third_party_dlls::kBlocked) ||
(code == kDllLoadSuccess &&
......@@ -134,6 +157,9 @@ int main() {
return kUnexpectedLog;
}
if (test_id == kTestLogPath && !MatchPath(dll_name, *entry))
return kUnexpectedSectionPath;
return code;
}
// Unsupported argument.
......
......@@ -21,11 +21,14 @@ enum ExitCode {
kUnsupportedTestId = -7,
kEmptyLog = -8,
kUnexpectedLog = -9,
kUnexpectedSectionPath = -10,
kBadLogEntrySize = -11,
};
enum TestId {
kTestOnlyInitialization = 1,
kTestSingleDllLoad = 2,
kTestLogPath = 3,
};
} // namespace main_unittest_exe
......
......@@ -204,14 +204,14 @@ TEST_F(ThirdPartyFileTest, Success) {
// Test matching.
for (const auto& test_module : GetTestArray()) {
fingerprint_hash =
GetFingerprintString(test_module.imagesize, test_module.timedatestamp);
GetFingerprintString(test_module.timedatestamp, test_module.imagesize);
fingerprint_hash = elf_sha1::SHA1HashString(fingerprint_hash);
name_hash = elf_sha1::SHA1HashString(test_module.basename);
EXPECT_TRUE(IsModuleListed(name_hash, fingerprint_hash));
}
// Test a failure to match.
fingerprint_hash = GetFingerprintString(1337, 0x12345678);
fingerprint_hash = GetFingerprintString(0x12345678, 1337);
fingerprint_hash = elf_sha1::SHA1HashString(fingerprint_hash);
name_hash = elf_sha1::SHA1HashString("booya.dll");
EXPECT_FALSE(IsModuleListed(name_hash, fingerprint_hash));
......@@ -222,7 +222,7 @@ TEST_F(ThirdPartyFileTest, NoFiles) {
// kFileNotFound is a non-fatal status code.
ASSERT_EQ(InitFromFile(), ThirdPartyStatus::kFileNotFound);
std::string fingerprint_hash = GetFingerprintString(1337, 0x12345678);
std::string fingerprint_hash = GetFingerprintString(0x12345678, 1337);
fingerprint_hash = elf_sha1::SHA1HashString(fingerprint_hash);
std::string name_hash = elf_sha1::SHA1HashString("booya.dll");
EXPECT_FALSE(IsModuleListed(name_hash, fingerprint_hash));
......
......@@ -14,8 +14,8 @@ const wchar_t kThirdPartyRegKeyName[] = L"\\ThirdParty";
// 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) {
std::string GetFingerprintString(uint32_t time_data_stamp,
uint32_t image_size) {
// Max hex 32-bit value is 8 characters long. 2*8+1.
char buffer[17] = {};
::snprintf(buffer, sizeof(buffer), "%08X%x", time_data_stamp, image_size);
......
......@@ -68,7 +68,7 @@ struct PackedListModule {
// and OptionalHeader.SizeOfImage with the formatting string %08X%x.
// - To be used for PackedListModule.code_id_hash, IsModuleListed() and logging
// APIs.
std::string GetFingerprintString(uint32_t image_size, uint32_t time_data_stamp);
std::string GetFingerprintString(uint32_t time_data_stamp, uint32_t image_size);
// These structs are directly written to a storage type. Therefore the padding
// should be consistent across compilations.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment