File: resources_integrity.cc

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (141 lines) | stat: -rw-r--r-- 5,277 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/resources_integrity.h"

#include <algorithm>
#include <array>

#include "base/files/file.h"
#include "base/functional/bind.h"
#include "base/memory/page_size.h"
#include "base/metrics/histogram_functions.h"
#include "base/path_service.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "build/build_config.h"
#include "chrome/common/chrome_paths.h"
#include "crypto/hash.h"
#include "crypto/secure_util.h"
#include "ui/base/buildflags.h"

#if BUILDFLAG(IS_WIN)
#include <windows.h>

#include "chrome/app/chrome_exe_main_win.h"
#else
#include "chrome/app/packed_resources_integrity.h"  // nogncheck
#endif

namespace {

bool CheckResourceIntegrityInternal(
    const base::FilePath& path,
    base::span<const uint8_t, crypto::hash::kSha256Size> expected_signature) {
  // Open the file for reading; allowing other consumers to also open it for
  // reading and deleting. Do not allow others to write to it.
  base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ |
                            base::File::FLAG_WIN_EXCLUSIVE_WRITE |
                            base::File::FLAG_WIN_SHARE_DELETE);
  if (!file.IsValid())
    return false;

  crypto::hash::Hasher hasher(crypto::hash::HashKind::kSha256);
  std::vector<uint8_t> buffer(base::GetPageSize());

  std::optional<size_t> bytes_read = 0;
  do {
    bytes_read = file.ReadAtCurrentPos(buffer);
    if (!bytes_read.has_value()) {
      return false;
    }
    hasher.Update(base::span(buffer).first(*bytes_read));
  } while (bytes_read.value_or(0) > 0);

  std::array<uint8_t, crypto::hash::kSha256Size> digest;
  hasher.Finish(digest);

  return crypto::SecureMemEqual(digest, expected_signature);
}

void ReportPakIntegrity(const std::string& histogram_name, bool hash_matches) {
  base::UmaHistogramBoolean(histogram_name, hash_matches);
}

}  // namespace

void CheckResourceIntegrity(
    const base::FilePath& path,
    base::span<const uint8_t, crypto::kSHA256Length> expected_signature,
    scoped_refptr<base::SequencedTaskRunner> task_runner,
    base::OnceCallback<void(bool)> callback) {
  task_runner->PostTaskAndReplyWithResult(
      FROM_HERE,
      base::BindOnce(&CheckResourceIntegrityInternal, path, expected_signature),
      std::move(callback));
}

void CheckPakFileIntegrity() {
  base::FilePath resources_pack_path;
  base::PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);

  // On Windows, the hashes cannot be embedded in the chrome.dll target that
  // this file is a part of, because it creates a cyclic build dependency
  // with the Grit resource allow-list generation. Instead, the hashes are
  // embedded in chrome.exe, which provides an exported function to
  // access them.
#if BUILDFLAG(IS_WIN)
  auto get_pak_file_hashes = reinterpret_cast<decltype(&GetPakFileHashes)>(
      ::GetProcAddress(::GetModuleHandle(nullptr), "GetPakFileHashes"));
  if (!get_pak_file_hashes) {
    // This is only exported by chrome.exe and unit_tests.exe, so in
    // other tests, like browser_tests.exe, this export will not be available.
    return;
  }

  const uint8_t *resources_hash_raw = nullptr, *chrome_100_hash_raw = nullptr,
                *chrome_200_hash_raw = nullptr;
  get_pak_file_hashes(&resources_hash_raw, &chrome_100_hash_raw,
                      &chrome_200_hash_raw);

  UNSAFE_BUFFERS(
      // SAFETY: these are compile-time constant data exposed via a C ABI
      // function, which means they can't be directly returned as spans or
      // std::arrays.
      base::span resources_hash(
          resources_hash_raw, base::fixed_extent<crypto::hash::kSha256Size>());
      base::span chrome_100_hash(
          chrome_100_hash_raw, base::fixed_extent<crypto::hash::kSha256Size>());
      base::span chrome_200_hash(
          chrome_200_hash_raw,
          base::fixed_extent<crypto::hash::kSha256Size>());)
#else
  base::span resources_hash = kSha256_resources_pak;
  base::span chrome_100_hash = kSha256_chrome_100_percent_pak;
#if BUILDFLAG(ENABLE_HIDPI)
  base::span chrome_200_hash = kSha256_chrome_200_percent_pak;
#endif
#endif  // BUILDFLAG(IS_WIN)

  scoped_refptr<base::SequencedTaskRunner> task_runner =
      base::ThreadPool::CreateSequencedTaskRunner(
          {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
           base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});

  CheckResourceIntegrity(resources_pack_path, resources_hash, task_runner,
                         base::BindOnce(&ReportPakIntegrity,
                                        "SafeBrowsing.PakIntegrity.Resources"));
  CheckResourceIntegrity(
      resources_pack_path.DirName().AppendASCII("chrome_100_percent.pak"),
      chrome_100_hash, task_runner,
      base::BindOnce(&ReportPakIntegrity,
                     "SafeBrowsing.PakIntegrity.Chrome100"));
#if BUILDFLAG(ENABLE_HIDPI)
  CheckResourceIntegrity(
      resources_pack_path.DirName().AppendASCII("chrome_200_percent.pak"),
      chrome_200_hash, task_runner,
      base::BindOnce(&ReportPakIntegrity,
                     "SafeBrowsing.PakIntegrity.Chrome200"));
#endif
}