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

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

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

Powered by Google App Engine
This is Rietveld 408576698