Skip to content

Commit

Permalink
Use std::array in PackedListModule to contain the SHA1 hash.
Browse files Browse the repository at this point in the history
This allows us to use the hashes as value types with convenient
assignment and comparison operators.

Also add myself as owner of the third_party_dlls subdirectory as
[email protected] no longer works on Chrome.

Change-Id: I66838fd4890637bf53faa22fbcbbfcae6456b583
Reviewed-on: https://chromium-review.googlesource.com/c/1340967
Reviewed-by: Cait Phillips <[email protected]>
Commit-Queue: Patrick Monette <[email protected]>
Cr-Commit-Position: refs/heads/master@{#609374}
  • Loading branch information
plmonette-zz authored and Commit Bot committed Nov 19, 2018
1 parent 84dbdda commit d8b1a10
Show file tree
Hide file tree
Showing 14 changed files with 80 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,13 @@ void PopulatePackedListModule(
base::i18n::ToLower(module_key.module_path.BaseName().value()));
base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_basename.data()),
module_basename.length(),
packed_list_module->basename_hash);
&packed_list_module->basename_hash[0]);

// Hash the code id.
const std::string module_code_id = GenerateCodeId(module_key);
base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_code_id.data()),
module_code_id.length(),
packed_list_module->code_id_hash);
&packed_list_module->code_id_hash[0]);

packed_list_module->time_date_stamp =
CalculateTimeDateStamp(base::Time::Now());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,10 @@ TEST_F(ModuleBlacklistCacheUpdaterTest, RegisteredModules) {
const std::string module_basename = base::UTF16ToUTF8(
base::i18n::ToLower(module_key2.module_path.BaseName().value()));
base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_basename.data()),
module_basename.length(), expected.basename_hash);
module_basename.length(), &expected.basename_hash[0]);
const std::string module_code_id = GenerateCodeId(module_key2);
base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_code_id.data()),
module_code_id.length(), expected.code_id_hash);
module_code_id.length(), &expected.code_id_hash[0]);

EXPECT_TRUE(internal::ModuleEqual()(expected, blacklisted_modules[0]));
}
24 changes: 5 additions & 19 deletions chrome/browser/conflicts/module_blacklist_cache_util_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <functional>
#include <iterator>
#include <string>
#include <tuple>
#include <utility>

#include "base/files/file.h"
Expand Down Expand Up @@ -237,30 +238,15 @@ int64_t CalculateExpectedFileSize(
bool ModuleLess::operator()(
const third_party_dlls::PackedListModule& lhs,
const third_party_dlls::PackedListModule& rhs) const {
auto is_less = [](const auto& lhs, const auto& rhs) {
return std::lexicographical_compare(std::begin(lhs), std::end(lhs),
std::begin(rhs), std::end(rhs));
};

if (is_less(lhs.basename_hash, rhs.basename_hash))
return true;

if (is_less(rhs.basename_hash, lhs.basename_hash))
return false;

return is_less(lhs.code_id_hash, rhs.code_id_hash);
return std::tie(lhs.basename_hash, lhs.code_id_hash) <
std::tie(rhs.basename_hash, rhs.code_id_hash);
}

bool ModuleEqual::operator()(
const third_party_dlls::PackedListModule& lhs,
const third_party_dlls::PackedListModule& rhs) const {
auto are_equal = [](const auto& lhs, const auto& rhs) {
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs),
std::end(rhs));
};

return are_equal(lhs.basename_hash, rhs.basename_hash) &&
are_equal(lhs.code_id_hash, rhs.code_id_hash);
return lhs.basename_hash == rhs.basename_hash &&
lhs.code_id_hash == rhs.code_id_hash;
}

bool ModuleTimeDateStampGreater::operator()(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "base/stl_util.h"
#include "base/time/time.h"
#include "chrome/browser/conflicts/module_list_filter_win.h"
#include "chrome_elf/sha1/sha1.h"
#include "chrome_elf/third_party_dlls/packed_list_format.h"
#include "testing/gtest/include/gtest/gtest.h"

Expand All @@ -42,9 +43,7 @@ std::vector<third_party_dlls::PackedListModule> CreateUniqueModuleEntries(

for (auto& entry : entries) {
// Fill up each bytes for both SHA1 hashes.
for (size_t i = 0;
i < arraysize(third_party_dlls::PackedListModule::basename_hash);
++i) {
for (size_t i = 0; i < elf_sha1::kSHA1Length; ++i) {
entry.basename_hash[i] = byte_distribution(random_engine);
entry.code_id_hash[i] = byte_distribution(random_engine);
}
Expand Down Expand Up @@ -186,10 +185,12 @@ class FakeModuleListFilter : public ModuleListFilter {

void AddWhitelistedModule(const third_party_dlls::PackedListModule& module) {
whitelisted_modules_.emplace(
base::StringPiece(reinterpret_cast<const char*>(module.basename_hash),
base::size(module.basename_hash)),
base::StringPiece(reinterpret_cast<const char*>(module.code_id_hash),
base::size(module.basename_hash)));
base::StringPiece(
reinterpret_cast<const char*>(&module.basename_hash[0]),
base::size(module.basename_hash)),
base::StringPiece(
reinterpret_cast<const char*>(&module.code_id_hash[0]),
base::size(module.basename_hash)));
}

// ModuleListFilter:
Expand Down
1 change: 1 addition & 0 deletions chrome_elf/OWNERS
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[email protected]
[email protected]
[email protected]
[email protected]

# TEAM: [email protected]
Expand Down
23 changes: 4 additions & 19 deletions chrome_elf/sha1/sha1.cc
Original file line number Diff line number Diff line change
Expand Up @@ -205,26 +205,11 @@ void SHA1HashBytes(const unsigned char* data, size_t len, unsigned char* hash) {
//------------------------------------------------------------------------------
// Public functions
//------------------------------------------------------------------------------

int CompareHashes(const uint8_t* first, const uint8_t* second) {
// Compare bytes, high-order to low-order.
for (size_t i = 0; i < kSHA1Length; ++i) {
if (first[i] < second[i])
return -1;
if (first[i] > second[i])
return 1;
// else they are equal, continue;
}

return 0;
}

std::string SHA1HashString(const std::string& str) {
char hash[kSHA1Length] = {};
Digest SHA1HashString(const std::string& str) {
Digest digest;
SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.c_str()),
str.length(), reinterpret_cast<unsigned char*>(hash));

return std::string(hash, kSHA1Length);
str.length(), reinterpret_cast<unsigned char*>(&digest[0]));
return digest;
}

} // namespace elf_sha1
13 changes: 4 additions & 9 deletions chrome_elf/sha1/sha1.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,18 @@

#include <stddef.h>

#include <array>
#include <string>

namespace elf_sha1 {

// Length in bytes of a SHA-1 hash.
constexpr size_t kSHA1Length = 20;

// Compare two hashes.
// - Returns -1 if |first| < |second|
// - Returns 0 if |first| == |second|
// - Returns 1 if |first| > |second|
// Note: Arguments should be kSHA1Length long.
int CompareHashes(const uint8_t* first, const uint8_t* second);
using Digest = std::array<uint8_t, kSHA1Length>;

// Computes the SHA1 hash of the input string |str| and returns the full
// hash. The returned SHA1 will be 20 bytes in length.
std::string SHA1HashString(const std::string& str);
// Returns the computed SHA1 of the input string |str|.
Digest SHA1HashString(const std::string& str);

} // namespace elf_sha1

Expand Down
27 changes: 12 additions & 15 deletions chrome_elf/sha1/sha1_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,34 @@ TEST(SHA1Test, Test1) {
// Example A.1 from FIPS 180-2: one-block message.
std::string input = "abc";

int expected[] = {0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d};
elf_sha1::Digest expected = {0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81,
0x6a, 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50,
0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d};

std::string output = elf_sha1::SHA1HashString(input);
for (size_t i = 0; i < elf_sha1::kSHA1Length; i++)
EXPECT_EQ(expected[i], output[i] & 0xFF);
EXPECT_EQ(elf_sha1::SHA1HashString(input), expected);
}

TEST(SHA1Test, Test2) {
// Example A.2 from FIPS 180-2: multi-block message.
std::string input =
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";

int expected[] = {0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1};
elf_sha1::Digest expected = {0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2,
0x6e, 0xba, 0xae, 0x4a, 0xa1, 0xf9, 0x51,
0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1};

std::string output = elf_sha1::SHA1HashString(input);
for (size_t i = 0; i < elf_sha1::kSHA1Length; i++)
EXPECT_EQ(expected[i], output[i] & 0xFF);
EXPECT_EQ(elf_sha1::SHA1HashString(input), expected);
}

TEST(SHA1Test, Test3) {
// Example A.3 from FIPS 180-2: long message.
std::string input(1000000, 'a');

int expected[] = {0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda, 0xa4, 0xf6, 0x1e,
0xeb, 0x2b, 0xdb, 0xad, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6f};
elf_sha1::Digest expected = {0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda,
0xa4, 0xf6, 0x1e, 0xeb, 0x2b, 0xdb, 0xad,
0x27, 0x31, 0x65, 0x34, 0x01, 0x6f};

std::string output = elf_sha1::SHA1HashString(input);
for (size_t i = 0; i < elf_sha1::kSHA1Length; i++)
EXPECT_EQ(expected[i], output[i] & 0xFF);
EXPECT_EQ(elf_sha1::SHA1HashString(input), expected);
}

} // namespace
15 changes: 7 additions & 8 deletions chrome_elf/third_party_dlls/hook.cc
Original file line number Diff line number Diff line change
Expand Up @@ -294,25 +294,24 @@ NTSTATUS NewNtMapViewOfSectionImpl(
}

// Note that one of either image_name or section_basename can be empty.
std::string image_name_hash;
elf_sha1::Digest image_name_hash;
if (!image_name.empty())
image_name_hash = elf_sha1::SHA1HashString(image_name);
std::string section_basename_hash;
elf_sha1::Digest section_basename_hash;
if (!section_basename.empty())
section_basename_hash = elf_sha1::SHA1HashString(section_basename);
std::string fingerprint_hash =
GetFingerprintString(time_date_stamp, image_size);
fingerprint_hash = elf_sha1::SHA1HashString(fingerprint_hash);
elf_sha1::Digest fingerprint_hash = elf_sha1::SHA1HashString(
GetFingerprintString(time_date_stamp, image_size));

// Check sources for blacklist decision.
bool block = false;

if (!image_name_hash.empty() &&
if (!image_name.empty() &&
IsModuleListed(image_name_hash, fingerprint_hash)) {
// 1) Third-party DLL blacklist, check for image name from PE header.
block = true;
} else if (!section_basename_hash.empty() &&
section_basename_hash.compare(image_name_hash) != 0 &&
} else if (!section_basename.empty() &&
section_basename_hash != image_name_hash &&
IsModuleListed(section_basename_hash, fingerprint_hash)) {
// 2) Third-party DLL blacklist, check for image name from the section.
block = true;
Expand Down
23 changes: 10 additions & 13 deletions chrome_elf/third_party_dlls/main_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <windows.h>

#include <string>

#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
Expand Down Expand Up @@ -98,15 +100,11 @@ PackedListModule GeneratePackedListModule(const std::string& image_name,
// Internally, an empty string should not be passed in here.
assert(!image_name.empty());

// SHA1 hash the two strings, and copy them into the new struct.
std::string code_id = GetFingerprintString(timedatestamp, imagesize);
code_id = elf_sha1::SHA1HashString(code_id);
std::string name_hash = elf_sha1::SHA1HashString(image_name);

// SHA1 hash the two strings into the new struct.
PackedListModule packed_module;
::memcpy(packed_module.code_id_hash, code_id.data(), elf_sha1::kSHA1Length);
::memcpy(packed_module.basename_hash, name_hash.data(),
elf_sha1::kSHA1Length);
packed_module.code_id_hash =
elf_sha1::SHA1HashString(GetFingerprintString(timedatestamp, imagesize));
packed_module.basename_hash = elf_sha1::SHA1HashString(image_name);

return packed_module;
}
Expand Down Expand Up @@ -480,15 +478,14 @@ TEST_F(ThirdPartyTest, SHA1SanityCheck) {
// Get hashes from base_sha1.
const std::string module_basename_hash =
base::SHA1HashString(base::UTF16ToUTF8(kChineseUnicode));
const std::string module_code_id_hash =
base::SHA1HashString(base::StringPrintf(
"%08lX%lx", module_data.timedatestamp, module_data.imagesize));
const std::string module_code_id_hash = base::SHA1HashString(
GetFingerprintString(module_data.timedatestamp, module_data.imagesize));

// Compare the hashes.
EXPECT_EQ(::memcmp(elf_sha1_generated.basename_hash,
EXPECT_EQ(::memcmp(&elf_sha1_generated.basename_hash[0],
module_basename_hash.data(), elf_sha1::kSHA1Length),
0);
EXPECT_EQ(::memcmp(elf_sha1_generated.code_id_hash,
EXPECT_EQ(::memcmp(&elf_sha1_generated.code_id_hash[0],
module_code_id_hash.data(), elf_sha1::kSHA1Length),
0);
}
Expand Down
15 changes: 6 additions & 9 deletions chrome_elf/third_party_dlls/packed_list_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ std::wstring& GetBlFilePath() {
// std::equal_range/std::is_sorted. Must return TRUE if lhs < rhs.
bool HashBinaryPredicate(const PackedListModule& lhs,
const PackedListModule& rhs) {
return elf_sha1::CompareHashes(lhs.basename_hash, rhs.basename_hash) < 0;
return lhs.basename_hash < rhs.basename_hash;
}

// Given a file opened for read, pull in the packed list.
Expand Down Expand Up @@ -172,19 +172,16 @@ ThirdPartyStatus InitInternal() {
// Public defines & functions
//------------------------------------------------------------------------------

bool IsModuleListed(const std::string& basename_hash,
const std::string& fingerprint_hash) {
bool IsModuleListed(const elf_sha1::Digest& basename_hash,
const elf_sha1::Digest& fingerprint_hash) {
assert(g_initialized);
assert(!basename_hash.empty() && !fingerprint_hash.empty());
assert(basename_hash.length() == elf_sha1::kSHA1Length &&
fingerprint_hash.length() == elf_sha1::kSHA1Length);

if (!g_bl_module_array_size)
return false;

PackedListModule target = {};
::memcpy(target.basename_hash, basename_hash.data(), elf_sha1::kSHA1Length);
::memcpy(target.code_id_hash, fingerprint_hash.data(), elf_sha1::kSHA1Length);
target.basename_hash = basename_hash;
target.code_id_hash = fingerprint_hash;

// Binary search for primary hash (basename). There can be more than one
// match.
Expand All @@ -194,7 +191,7 @@ bool IsModuleListed(const std::string& basename_hash,

// Search for secondary hash.
for (PackedListModule* i = pair.first; i != pair.second; ++i) {
if (!elf_sha1::CompareHashes(target.code_id_hash, i->code_id_hash))
if (target.code_id_hash == i->code_id_hash)
return true;
}

Expand Down
5 changes: 3 additions & 2 deletions chrome_elf/third_party_dlls/packed_list_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

#include <string>

#include "chrome_elf/sha1/sha1.h"
#include "chrome_elf/third_party_dlls/status_codes.h"

namespace third_party_dlls {

// Look up a binary based on the required data points.
// - Returns true if match found in the list.
bool IsModuleListed(const std::string& basename_hash,
const std::string& fingerprint_hash);
bool IsModuleListed(const elf_sha1::Digest& basename_hash,
const elf_sha1::Digest& fingerprint_hash);

// Get the full path of the blacklist file used.
std::wstring GetBlFilePathUsed();
Expand Down
Loading

0 comments on commit d8b1a10

Please sign in to comment.