Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: chrome/browser/conflicts/module_event_sink_impl_win.cc

Issue 2576843002: [win] Create ModuleDatabase and ModuleEventSinkImpl. (Closed)
Patch Set: Address sky@'s comments. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/conflicts/module_event_sink_impl_win.h"
6
7 #include <windows.h>
8 #include <psapi.h>
9
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/files/file_path.h"
15 #include "base/macros.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/strings/string_piece.h"
18 #include "chrome/browser/conflicts/module_database_win.h"
19 #include "chrome/common/conflicts/module_watcher_win.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "mojo/public/cpp/bindings/strong_binding.h"
22
23 namespace {
24
25 // Gets the process creation time associated with the given process.
26 bool GetProcessCreationTime(base::ProcessHandle process,
27 uint64_t* creation_time) {
28 FILETIME creation_ft = {};
29 FILETIME exit_ft = {};
30 FILETIME kernel_ft = {};
31 FILETIME user_ft = {};
32 if (!::GetProcessTimes(process, &creation_ft, &exit_ft, &kernel_ft,
33 &user_ft)) {
34 return false;
35 }
36 *creation_time = (static_cast<uint64_t>(creation_ft.dwHighDateTime) << 32) |
37 static_cast<uint64_t>(creation_ft.dwLowDateTime);
38 return true;
39 }
40
41 // Gets the path of the module in the provided remote process. Returns true on
42 // success, false otherwise.
43 bool GetModulePath(base::ProcessHandle process,
44 HMODULE module,
45 base::FilePath* path) {
46 std::vector<wchar_t> temp_path(MAX_PATH);
47 size_t length = 0;
48 while (true) {
49 length = ::GetModuleFileNameEx(process, module, temp_path.data(),
Will Harris 2017/01/11 21:25:38 there's some stuff in the MSDN about PSAPI_VERSION
chrisha 2017/01/11 21:46:22 grt brought this up too. We are currently setting
50 temp_path.size());
51 if (length == 0)
52 return false;
53 if (length < temp_path.size())
54 break;
55 // The entire buffer was consumed, so grow it to ensure the result wasn't
56 // actually truncated.
57 temp_path.resize(2 * temp_path.size());
58 }
59
60 *path = base::FilePath(base::StringPiece16(temp_path.data(), length));
61 return true;
62 }
63
64 // Gets the size of a module in a remote process. Returns true on success, false
65 // otherwise.
66 bool GetModuleSize(base::ProcessHandle process,
67 HMODULE module,
68 uint32_t* size) {
69 MODULEINFO info = {};
70 if (!::GetModuleInformation(process, module, &info, sizeof(info)))
71 return false;
72 *size = info.SizeOfImage;
73 return true;
74 }
75
76 // Reads the typed data from a remote process. Returns true on success, false
77 // otherwise.
78 template <typename T>
79 bool ReadRemoteData(base::ProcessHandle process, uint64_t address, T* data) {
80 const void* typed_address =
81 reinterpret_cast<const void*>(static_cast<uintptr_t>(address));
82 SIZE_T bytes_read = 0;
83 if (!::ReadProcessMemory(process, typed_address, &data, sizeof(data),
84 &bytes_read)) {
85 return false;
86 }
87 if (bytes_read != sizeof(data))
88 return false;
89 return true;
90 }
91
92 // Reads the time date stamp from the module loaded in the provided remote
93 // |process| at the provided remote |load_address|.
94 bool GetModuleTimeDateStamp(base::ProcessHandle process,
95 uint64_t load_address,
96 uint32_t* time_date_stamp) {
97 uint64_t address = load_address + offsetof(IMAGE_DOS_HEADER, e_lfanew);
98 LONG e_lfanew = 0;
99 if (!ReadRemoteData(process, address, &e_lfanew))
100 return false;
101
102 address = load_address + e_lfanew + offsetof(IMAGE_NT_HEADERS, FileHeader) +
103 offsetof(IMAGE_FILE_HEADER, TimeDateStamp);
104 DWORD temp = 0;
105 if (!ReadRemoteData(process, address, &temp))
106 return false;
107
108 *time_date_stamp = temp;
109 return true;
110 }
111
112 } // namespace
113
114 ModuleEventSinkImpl::ModuleEventSinkImpl(base::ProcessHandle process,
115 content::ProcessType process_type,
116 ModuleDatabase* module_database)
117 : process_(process),
118 module_database_(module_database),
119 process_id_(0),
120 creation_time_(0),
121 in_error_(false) {
122 // Failing to get basic process information means this channel should not
123 // continue to forward data, thus it is marked as being in error.
124 process_id_ = ::GetProcessId(process_);
125 if (!GetProcessCreationTime(process_, &creation_time_)) {
126 in_error_ = true;
127 return;
128 }
129 module_database->OnProcessStarted(process_id_, creation_time_, process_type);
130 }
131
132 ModuleEventSinkImpl::~ModuleEventSinkImpl() = default;
133
134 // static
135 void ModuleEventSinkImpl::Create(base::ProcessHandle process,
136 content::ProcessType process_type,
137 ModuleDatabase* module_database,
138 mojom::ModuleEventSinkRequest request) {
139 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
140 auto module_event_sink_impl = base::MakeUnique<ModuleEventSinkImpl>(
141 process, process_type, module_database);
142 base::Closure error_handler = base::Bind(
143 &ModuleDatabase::OnProcessEnded, base::Unretained(module_database),
144 module_event_sink_impl->process_id_,
145 module_event_sink_impl->creation_time_);
146 auto binding = mojo::MakeStrongBinding(std::move(module_event_sink_impl),
147 std::move(request));
148 binding->set_connection_error_handler(error_handler);
149 }
150
151 void ModuleEventSinkImpl::OnModuleEvent(mojom::ModuleEventType event_type,
152 uint64_t load_address) {
153 if (in_error_)
154 return;
155
156 // Mojo takes care of validating |event_type|, so only |load_address| needs to
157 // be checked. Load addresses must be aligned with the allocation granularity
158 // which is at least 64KB on any supported Windows OS.
159 if (load_address == 0 || load_address % (64 * 1024) != 0)
160 return;
161
162 switch (event_type) {
163 case mojom::ModuleEventType::MODULE_ALREADY_LOADED:
164 case mojom::ModuleEventType::MODULE_LOADED:
165 return OnModuleLoad(load_address);
166
167 case mojom::ModuleEventType::MODULE_UNLOADED:
168 return OnModuleUnload(load_address);
169 }
170 }
171
172 void ModuleEventSinkImpl::OnModuleLoad(uint64_t load_address) {
173 if (in_error_)
174 return;
175
176 // The |load_address| is a unique key to a module in a remote process. If
177 // there is a valid module there then the following queries should all pass.
178 // If any of them fail then the load event is silently swallowed. The entire
179 // channel is not marked as being in an error mode, as later events may be
180 // well formed.
181
182 // Convert the |load_address| to a module handle.
183 HMODULE module =
184 reinterpret_cast<HMODULE>(static_cast<uintptr_t>(load_address));
185
186 // Look up the various pieces of module metadata in the remote process.
187
188 base::FilePath module_path;
189 if (!GetModulePath(process_, module, &module_path))
190 return;
191
192 uint32_t module_size = 0;
193 if (!GetModuleSize(process_, module, &module_size))
194 return;
195
196 uint32_t module_time_date_stamp = 0;
197 if (!GetModuleTimeDateStamp(process_, load_address, &module_time_date_stamp))
198 return;
199
200 // Forward this to the module database.
201 module_database_->OnModuleLoad(process_id_, creation_time_, module_path,
202 module_size, module_time_date_stamp,
203 load_address);
204 }
205
206 void ModuleEventSinkImpl::OnModuleUnload(uint64_t load_address) {
207 // Forward this directly to the module database.
208 module_database_->OnModuleUnload(process_id_, creation_time_,
209 static_cast<uintptr_t>(load_address));
210 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698