1 // Copyright 2019 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/chrome_cleaner/engines/broker/engine_requests_impl.h"
6
7 // Windows include must be first for the code to compile.
8 // clang-format off
9 #include <windows.h>
10 #include <sddl.h>
11 // clang-format on
12
13 #include <set>
14 #include <utility>
15
16 #include "base/callback.h"
17 #include "base/task/thread_pool.h"
18 #include "base/task/post_task.h"
19 #include "base/task/task_traits.h"
20 #include "chrome/chrome_cleaner/engines/broker/scanner_sandbox_interface.h"
21 #include "chrome/chrome_cleaner/os/registry.h"
22 #include "mojo/public/cpp/system/platform_handle.h"
23
24 namespace chrome_cleaner {
25
26 namespace {
27
CloseRegistryHandle(HANDLE handle)28 void CloseRegistryHandle(HANDLE handle) {
29 if (IsPredefinedRegistryHandle(handle))
30 return;
31 // Call ::CloseHandle instead of ::RegCloseKey as it's not always possible to
32 // distinguish whether the passed handle was returned by RegOpenKey or by
33 // NtOpenKey.
34 // TODO(veranika): track registry handle types and close them correctly.
35 bool success = ::CloseHandle(handle);
36 PLOG_IF(ERROR, !success) << "Failed to close handle";
37 }
38
ForwardOpenRegistryResult(mojom::EngineRequests::SandboxOpenReadOnlyRegistryCallback result_callback,uint32_t return_code,HKEY handle)39 void ForwardOpenRegistryResult(
40 mojom::EngineRequests::SandboxOpenReadOnlyRegistryCallback result_callback,
41 uint32_t return_code,
42 HKEY handle) {
43 std::move(result_callback).Run(return_code, handle);
44
45 if (return_code == 0) {
46 // Close |handle| only on successful operation, as otherwise it's not set.
47 LSTATUS status = ::RegCloseKey(handle);
48 LOG_IF(ERROR, status != ERROR_SUCCESS)
49 << "Failed to close a registry key: "
50 << logging::SystemErrorCodeToString(status);
51 }
52 }
53
ForwardNtOpenRegistryResult(mojom::EngineRequests::SandboxNtOpenReadOnlyRegistryCallback callback,uint32_t return_code,HANDLE handle)54 void ForwardNtOpenRegistryResult(
55 mojom::EngineRequests::SandboxNtOpenReadOnlyRegistryCallback callback,
56 uint32_t return_code,
57 HANDLE handle) {
58 std::move(callback).Run(return_code, handle);
59 CloseRegistryHandle(handle);
60 }
61
62 } // namespace
63
EngineRequestsImpl(scoped_refptr<MojoTaskRunner> mojo_task_runner,InterfaceMetadataObserver * metadata_observer)64 EngineRequestsImpl::EngineRequestsImpl(
65 scoped_refptr<MojoTaskRunner> mojo_task_runner,
66 InterfaceMetadataObserver* metadata_observer)
67 : mojo_task_runner_(mojo_task_runner),
68 metadata_observer_(metadata_observer) {}
69
70 EngineRequestsImpl::~EngineRequestsImpl() = default;
71
Bind(mojo::PendingAssociatedRemote<mojom::EngineRequests> * remote)72 void EngineRequestsImpl::Bind(
73 mojo::PendingAssociatedRemote<mojom::EngineRequests>* remote) {
74 if (receiver_.is_bound())
75 receiver_.reset();
76
77 receiver_.Bind(remote->InitWithNewEndpointAndPassReceiver());
78 // There's no need to call set_disconnect_handler on this since it's an
79 // associated interface. Any errors will be handled on the main EngineCommands
80 // interface.
81 }
82
SandboxGetFileAttributes(const base::FilePath & file_name,SandboxGetFileAttributesCallback result_callback)83 void EngineRequestsImpl::SandboxGetFileAttributes(
84 const base::FilePath& file_name,
85 SandboxGetFileAttributesCallback result_callback) {
86 base::ThreadPool::PostTask(
87 FROM_HERE, {base::MayBlock()},
88 base::BindOnce(&EngineRequestsImpl::GetFileAttributes,
89 base::Unretained(this), file_name,
90 std::move(result_callback)));
91 }
92
GetFileAttributes(const base::FilePath & file_name,SandboxGetFileAttributesCallback result_callback)93 void EngineRequestsImpl::GetFileAttributes(
94 const base::FilePath& file_name,
95 SandboxGetFileAttributesCallback result_callback) {
96 if (metadata_observer_)
97 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
98 uint32_t attributes = INVALID_FILE_ATTRIBUTES;
99 uint32_t result =
100 chrome_cleaner_sandbox::SandboxGetFileAttributes(file_name, &attributes);
101 mojo_task_runner_->PostTask(
102 FROM_HERE,
103 base::BindOnce(std::move(result_callback), result, attributes));
104 }
105
SandboxGetKnownFolderPath(mojom::KnownFolder folder_id,SandboxGetKnownFolderPathCallback result_callback)106 void EngineRequestsImpl::SandboxGetKnownFolderPath(
107 mojom::KnownFolder folder_id,
108 SandboxGetKnownFolderPathCallback result_callback) {
109 base::ThreadPool::PostTask(
110 FROM_HERE, {base::MayBlock()},
111 base::BindOnce(&EngineRequestsImpl::GetKnownFolderPath,
112 base::Unretained(this), folder_id,
113 std::move(result_callback)));
114 }
115
GetKnownFolderPath(mojom::KnownFolder folder_id,SandboxGetKnownFolderPathCallback result_callback)116 void EngineRequestsImpl::GetKnownFolderPath(
117 mojom::KnownFolder folder_id,
118 SandboxGetKnownFolderPathCallback result_callback) {
119 if (metadata_observer_)
120 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
121 base::FilePath folder_path;
122 bool result = chrome_cleaner_sandbox::SandboxGetKnownFolderPath(folder_id,
123 &folder_path);
124 mojo_task_runner_->PostTask(
125 FROM_HERE,
126 base::BindOnce(std::move(result_callback), result, folder_path));
127 }
128
SandboxGetProcesses(SandboxGetProcessesCallback result_callback)129 void EngineRequestsImpl::SandboxGetProcesses(
130 SandboxGetProcessesCallback result_callback) {
131 base::ThreadPool::PostTask(
132 FROM_HERE, {base::MayBlock()},
133 base::BindOnce(&EngineRequestsImpl::GetProcesses, base::Unretained(this),
134 std::move(result_callback)));
135 }
136
GetProcesses(SandboxGetProcessesCallback result_callback)137 void EngineRequestsImpl::GetProcesses(
138 SandboxGetProcessesCallback result_callback) {
139 if (metadata_observer_)
140 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
141 std::vector<base::ProcessId> processes;
142 bool result = chrome_cleaner_sandbox::SandboxGetProcesses(&processes);
143 mojo_task_runner_->PostTask(
144 FROM_HERE,
145 base::BindOnce(std::move(result_callback), result, std::move(processes)));
146 }
147
SandboxGetTasks(SandboxGetTasksCallback result_callback)148 void EngineRequestsImpl::SandboxGetTasks(
149 SandboxGetTasksCallback result_callback) {
150 base::ThreadPool::PostTask(
151 FROM_HERE, {base::MayBlock()},
152 base::BindOnce(&EngineRequestsImpl::GetTasks, base::Unretained(this),
153 std::move(result_callback)));
154 }
155
GetTasks(SandboxGetTasksCallback result_callback)156 void EngineRequestsImpl::GetTasks(SandboxGetTasksCallback result_callback) {
157 if (metadata_observer_)
158 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
159
160 std::vector<TaskScheduler::TaskInfo> tasks;
161 bool result = chrome_cleaner_sandbox::SandboxGetTasks(&tasks);
162
163 std::vector<mojom::ScheduledTaskPtr> mojo_tasks;
164 for (TaskScheduler::TaskInfo& task : tasks) {
165 std::vector<mojom::ScheduledTaskActionPtr> mojo_actions;
166 for (TaskScheduler::TaskExecAction& action : task.exec_actions) {
167 auto mojo_action = mojom::ScheduledTaskAction::New(
168 std::move(action.application_path), std::move(action.working_dir),
169 std::move(action.arguments));
170 mojo_actions.push_back(std::move(mojo_action));
171 }
172 auto mojo_task = mojom::ScheduledTask::New(std::move(task.name),
173 std::move(task.description),
174 std::move(mojo_actions));
175 mojo_tasks.push_back(std::move(mojo_task));
176 }
177
178 mojo_task_runner_->PostTask(FROM_HERE,
179 base::BindOnce(std::move(result_callback), result,
180 std::move(mojo_tasks)));
181 }
182
SandboxGetProcessImagePath(base::ProcessId pid,SandboxGetProcessImagePathCallback result_callback)183 void EngineRequestsImpl::SandboxGetProcessImagePath(
184 base::ProcessId pid,
185 SandboxGetProcessImagePathCallback result_callback) {
186 base::ThreadPool::PostTask(
187 FROM_HERE, {base::MayBlock()},
188 base::BindOnce(&EngineRequestsImpl::GetProcessImagePath,
189 base::Unretained(this), pid, std::move(result_callback)));
190 }
191
GetProcessImagePath(base::ProcessId pid,SandboxGetProcessImagePathCallback result_callback)192 void EngineRequestsImpl::GetProcessImagePath(
193 base::ProcessId pid,
194 SandboxGetProcessImagePathCallback result_callback) {
195 if (metadata_observer_)
196 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
197 base::FilePath image_path;
198 bool result =
199 chrome_cleaner_sandbox::SandboxGetProcessImagePath(pid, &image_path);
200
201 mojo_task_runner_->PostTask(FROM_HERE,
202 base::BindOnce(std::move(result_callback), result,
203 std::move(image_path)));
204 }
205
SandboxGetLoadedModules(base::ProcessId pid,SandboxGetLoadedModulesCallback result_callback)206 void EngineRequestsImpl::SandboxGetLoadedModules(
207 base::ProcessId pid,
208 SandboxGetLoadedModulesCallback result_callback) {
209 base::ThreadPool::PostTask(
210 FROM_HERE, {base::MayBlock()},
211 base::BindOnce(&EngineRequestsImpl::GetLoadedModules,
212 base::Unretained(this), pid, std::move(result_callback)));
213 }
214
GetLoadedModules(base::ProcessId pid,SandboxGetLoadedModulesCallback result_callback)215 void EngineRequestsImpl::GetLoadedModules(
216 base::ProcessId pid,
217 SandboxGetLoadedModulesCallback result_callback) {
218 if (metadata_observer_)
219 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
220 std::set<std::wstring> modules;
221 bool result = chrome_cleaner_sandbox::SandboxGetLoadedModules(pid, &modules);
222
223 std::vector<std::wstring> modules_list(modules.begin(), modules.end());
224 mojo_task_runner_->PostTask(FROM_HERE,
225 base::BindOnce(std::move(result_callback), result,
226 std::move(modules_list)));
227 }
228
SandboxGetProcessCommandLine(base::ProcessId pid,SandboxGetProcessCommandLineCallback result_callback)229 void EngineRequestsImpl::SandboxGetProcessCommandLine(
230 base::ProcessId pid,
231 SandboxGetProcessCommandLineCallback result_callback) {
232 base::ThreadPool::PostTask(
233 FROM_HERE, {base::MayBlock()},
234 base::BindOnce(&EngineRequestsImpl::GetProcessCommandLine,
235 base::Unretained(this), pid, std::move(result_callback)));
236 }
237
GetProcessCommandLine(base::ProcessId pid,SandboxGetProcessCommandLineCallback result_callback)238 void EngineRequestsImpl::GetProcessCommandLine(
239 base::ProcessId pid,
240 SandboxGetProcessCommandLineCallback result_callback) {
241 if (metadata_observer_)
242 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
243
244 std::wstring command_line;
245 bool result =
246 chrome_cleaner_sandbox::SandboxGetProcessCommandLine(pid, &command_line);
247
248 mojo_task_runner_->PostTask(FROM_HERE,
249 base::BindOnce(std::move(result_callback), result,
250 std::move(command_line)));
251 }
252
SandboxGetUserInfoFromSID(mojom::StringSidPtr string_sid,SandboxGetUserInfoFromSIDCallback result_callback)253 void EngineRequestsImpl::SandboxGetUserInfoFromSID(
254 mojom::StringSidPtr string_sid,
255 SandboxGetUserInfoFromSIDCallback result_callback) {
256 base::ThreadPool::PostTask(
257 FROM_HERE, {base::MayBlock()},
258 base::BindOnce(&EngineRequestsImpl::GetUserInfoFromSID,
259 base::Unretained(this), std::move(string_sid),
260 std::move(result_callback)));
261 }
262
GetUserInfoFromSID(mojom::StringSidPtr string_sid,SandboxGetUserInfoFromSIDCallback result_callback)263 void EngineRequestsImpl::GetUserInfoFromSID(
264 mojom::StringSidPtr string_sid,
265 SandboxGetUserInfoFromSIDCallback result_callback) {
266 if (metadata_observer_)
267 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
268
269 PSID sid = nullptr;
270 if (!::ConvertStringSidToSid(string_sid->value.c_str(), &sid)) {
271 PLOG(ERROR) << "Failed to convert string sid to sid";
272 }
273 mojom::UserInformationPtr user_info = mojom::UserInformation::New();
274 bool result = chrome_cleaner_sandbox::SandboxGetUserInfoFromSID(
275 static_cast<SID*>(sid), user_info.get());
276 ::LocalFree(sid);
277
278 mojo_task_runner_->PostTask(
279 FROM_HERE,
280 base::BindOnce(std::move(result_callback), result, std::move(user_info)));
281 }
282
SandboxOpenReadOnlyRegistry(HANDLE root_key_handle,const std::wstring & sub_key,uint32_t dw_access,SandboxOpenReadOnlyRegistryCallback result_callback)283 void EngineRequestsImpl::SandboxOpenReadOnlyRegistry(
284 HANDLE root_key_handle,
285 const std::wstring& sub_key,
286 uint32_t dw_access,
287 SandboxOpenReadOnlyRegistryCallback result_callback) {
288 base::ThreadPool::PostTask(
289 FROM_HERE, {base::MayBlock()},
290 base::BindOnce(&EngineRequestsImpl::OpenReadOnlyRegistry,
291 base::Unretained(this), root_key_handle, sub_key,
292 dw_access, std::move(result_callback)));
293 }
294
OpenReadOnlyRegistry(HANDLE root_key_handle,const std::wstring & sub_key,uint32_t dw_access,SandboxOpenReadOnlyRegistryCallback result_callback)295 void EngineRequestsImpl::OpenReadOnlyRegistry(
296 HANDLE root_key_handle,
297 const std::wstring& sub_key,
298 uint32_t dw_access,
299 SandboxOpenReadOnlyRegistryCallback result_callback) {
300 if (metadata_observer_)
301 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
302 HKEY handle;
303 uint32_t return_code = chrome_cleaner_sandbox::SandboxOpenReadOnlyRegistry(
304 root_key_handle, sub_key, dw_access, &handle);
305
306 mojo_task_runner_->PostTask(
307 FROM_HERE,
308 base::BindOnce(ForwardOpenRegistryResult, std::move(result_callback),
309 return_code, handle));
310
311 // Close handles as Mojo doesn't own them. ForwardOpenRegistryResult will
312 // close result handle.
313 // TODO(veranika): clearly define ownership and find a better fix.
314 CloseRegistryHandle(root_key_handle);
315 }
316
SandboxNtOpenReadOnlyRegistry(HANDLE root_key_handle,const WStringEmbeddedNulls & sub_key,uint32_t dw_access,SandboxNtOpenReadOnlyRegistryCallback result_callback)317 void EngineRequestsImpl::SandboxNtOpenReadOnlyRegistry(
318 HANDLE root_key_handle,
319 const WStringEmbeddedNulls& sub_key,
320 uint32_t dw_access,
321 SandboxNtOpenReadOnlyRegistryCallback result_callback) {
322 base::ThreadPool::PostTask(
323 FROM_HERE, {base::MayBlock()},
324 base::BindOnce(&EngineRequestsImpl::NtOpenReadOnlyRegistry,
325 base::Unretained(this), root_key_handle, sub_key,
326 dw_access, std::move(result_callback)));
327 }
328
NtOpenReadOnlyRegistry(HANDLE root_key_handle,const WStringEmbeddedNulls & sub_key,uint32_t dw_access,SandboxNtOpenReadOnlyRegistryCallback result_callback)329 void EngineRequestsImpl::NtOpenReadOnlyRegistry(
330 HANDLE root_key_handle,
331 const WStringEmbeddedNulls& sub_key,
332 uint32_t dw_access,
333 SandboxNtOpenReadOnlyRegistryCallback result_callback) {
334 if (metadata_observer_)
335 metadata_observer_->ObserveCall(CURRENT_FILE_AND_METHOD);
336
337 HANDLE handle;
338 uint32_t return_code = chrome_cleaner_sandbox::SandboxNtOpenReadOnlyRegistry(
339 root_key_handle, sub_key, dw_access, &handle);
340
341 mojo_task_runner_->PostTask(
342 FROM_HERE,
343 base::BindOnce(ForwardNtOpenRegistryResult, std::move(result_callback),
344 return_code, handle));
345
346 // Close handles as Mojo doesn't own them. ForwardOpenRegistryResult will
347 // close result handle.
348 // TODO(veranika): clearly define ownership and find a better fix.
349 CloseRegistryHandle(root_key_handle);
350 }
351
352 } // namespace chrome_cleaner
353