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