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/target/sandboxed_test_helpers.h"
6 
7 #include <utility>
8 
9 #include "base/callback_helpers.h"
10 #include "base/task/single_thread_task_executor.h"
11 #include "chrome/chrome_cleaner/engines/common/engine_result_codes.h"
12 #include "chrome/chrome_cleaner/os/early_exit.h"
13 #include "chrome/chrome_cleaner/os/initializer.h"
14 #include "mojo/public/cpp/bindings/pending_receiver.h"
15 #include "mojo/public/cpp/system/message_pipe.h"
16 
17 namespace chrome_cleaner {
18 
19 const int SandboxChildProcess::kConnectionErrorExitCode = 0xDEAD;
20 
21 // FakeEngineDelegate takes a base::Event that it signals once either
22 // Initialize, StartScan, or StartCleanup has been called to indicate when this
23 // class is fully functional (for either scanning or cleaning test). It does not
24 // invoke any actual engine commands.
25 class SandboxChildProcess::FakeEngineDelegate : public EngineDelegate {
26  public:
FakeEngineDelegate(base::WaitableEvent * event)27   explicit FakeEngineDelegate(base::WaitableEvent* event) : event_(event) {}
28 
engine() const29   Engine::Name engine() const override { return Engine::TEST_ONLY; }
30 
Initialize(const base::FilePath & log_directory_path,scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,mojom::EngineCommands::InitializeCallback callback)31   void Initialize(const base::FilePath& log_directory_path,
32                   scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,
33                   mojom::EngineCommands::InitializeCallback callback) override {
34     privileged_file_calls_ = privileged_file_calls;
35     event_->Signal();
36     std::move(callback).Run(EngineResultCode::kSuccess);
37   }
38 
StartScan(const std::vector<UwSId> & enabled_uws,const std::vector<UwS::TraceLocation> & enabled_locations,bool include_details,scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,scoped_refptr<EngineRequestsProxy> privileged_scan_calls,scoped_refptr<EngineScanResultsProxy>)39   uint32_t StartScan(
40       const std::vector<UwSId>& enabled_uws,
41       const std::vector<UwS::TraceLocation>& enabled_locations,
42       bool include_details,
43       scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,
44       scoped_refptr<EngineRequestsProxy> privileged_scan_calls,
45       scoped_refptr<EngineScanResultsProxy> /*report_result_calls*/) override {
46     privileged_file_calls_ = privileged_file_calls;
47     privileged_scan_calls_ = privileged_scan_calls;
48     event_->Signal();
49     return EngineResultCode::kSuccess;
50   }
51 
StartCleanup(const std::vector<UwSId> & enabled_uws,scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,scoped_refptr<EngineRequestsProxy> privileged_scan_calls,scoped_refptr<CleanerEngineRequestsProxy> privileged_removal_calls,scoped_refptr<EngineCleanupResultsProxy>)52   uint32_t StartCleanup(
53       const std::vector<UwSId>& enabled_uws,
54       scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,
55       scoped_refptr<EngineRequestsProxy> privileged_scan_calls,
56       scoped_refptr<CleanerEngineRequestsProxy> privileged_removal_calls,
57       scoped_refptr<EngineCleanupResultsProxy> /*report_result_calls*/)
58       override {
59     privileged_file_calls_ = privileged_file_calls;
60     privileged_scan_calls_ = privileged_scan_calls;
61     privileged_removal_calls_ = privileged_removal_calls;
62     event_->Signal();
63     return EngineResultCode::kSuccess;
64   }
65 
Finalize()66   uint32_t Finalize() override { return EngineResultCode::kSuccess; }
67 
GetFileRequestsProxy()68   scoped_refptr<EngineFileRequestsProxy> GetFileRequestsProxy() {
69     return privileged_file_calls_;
70   }
71 
GetEngineRequestsProxy()72   scoped_refptr<EngineRequestsProxy> GetEngineRequestsProxy() {
73     return privileged_scan_calls_;
74   }
75 
GetCleanerEngineRequestsProxy()76   scoped_refptr<CleanerEngineRequestsProxy> GetCleanerEngineRequestsProxy() {
77     return privileged_removal_calls_;
78   }
79 
UnbindRequestsRemotes()80   void UnbindRequestsRemotes() {
81     if (privileged_scan_calls_) {
82       privileged_scan_calls_->UnbindRequestsRemote();
83     }
84     if (privileged_file_calls_) {
85       privileged_file_calls_->UnbindRequestsRemote();
86     }
87   }
88 
89  private:
90   ~FakeEngineDelegate() override = default;
91 
92   base::WaitableEvent* event_;
93   scoped_refptr<EngineFileRequestsProxy> privileged_file_calls_;
94   scoped_refptr<EngineRequestsProxy> privileged_scan_calls_;
95   scoped_refptr<CleanerEngineRequestsProxy> privileged_removal_calls_;
96 };
97 
SandboxChildProcess(scoped_refptr<MojoTaskRunner> mojo_task_runner)98 SandboxChildProcess::SandboxChildProcess(
99     scoped_refptr<MojoTaskRunner> mojo_task_runner)
100     : ChildProcess(std::move(mojo_task_runner)) {
101   // This must be called before accessing Mojo, because the parent process is
102   // waiting on this and won't respond to Mojo calls.
103   NotifyInitializationDone();
104 
105   mojo::ScopedMessagePipeHandle message_pipe_handle =
106       CreateMessagePipeFromCommandLine();
107   mojo::PendingReceiver<mojom::EngineCommands> engine_commands_receiver(
108       std::move(message_pipe_handle));
109   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
110                             base::WaitableEvent::InitialState::NOT_SIGNALED);
111   mojo_task_runner_->PostTask(
112       FROM_HERE,
113       base::BindOnce(&SandboxChildProcess::BindEngineCommandsReceiver,
114                      base::Unretained(this),
115                      std::move(engine_commands_receiver), &event));
116   event.Wait();
117 }
118 
BindEngineCommandsReceiver(mojo::PendingReceiver<mojom::EngineCommands> receiver,base::WaitableEvent * event)119 void SandboxChildProcess::SandboxChildProcess::BindEngineCommandsReceiver(
120     mojo::PendingReceiver<mojom::EngineCommands> receiver,
121     base::WaitableEvent* event) {
122   fake_engine_delegate_ = base::MakeRefCounted<FakeEngineDelegate>(event);
123   engine_commands_impl_ = std::make_unique<EngineCommandsImpl>(
124       fake_engine_delegate_, std::move(receiver), mojo_task_runner_,
125       /*error_handler=*/base::BindOnce(&EarlyExit, kConnectionErrorExitCode));
126 }
127 
128 scoped_refptr<EngineFileRequestsProxy>
GetFileRequestsProxy()129 SandboxChildProcess::GetFileRequestsProxy() {
130   return fake_engine_delegate_->GetFileRequestsProxy();
131 }
132 
133 scoped_refptr<EngineRequestsProxy>
GetEngineRequestsProxy()134 SandboxChildProcess::GetEngineRequestsProxy() {
135   return fake_engine_delegate_->GetEngineRequestsProxy();
136 }
137 
138 scoped_refptr<CleanerEngineRequestsProxy>
GetCleanerEngineRequestsProxy()139 SandboxChildProcess::GetCleanerEngineRequestsProxy() {
140   return fake_engine_delegate_->GetCleanerEngineRequestsProxy();
141 }
142 
UnbindRequestsRemotes()143 void SandboxChildProcess::UnbindRequestsRemotes() {
144   base::SingleThreadTaskExecutor main_task_executor;
145   base::RunLoop run_loop;
146   if (GetCleanerEngineRequestsProxy()) {
147     mojo_task_runner_->PostTask(
148         FROM_HERE,
149         base::BindOnce(&CleanerEngineRequestsProxy::UnbindRequestsRemote,
150                        GetCleanerEngineRequestsProxy()));
151   }
152 
153   mojo_task_runner_->PostTask(
154       FROM_HERE, base::BindOnce(&FakeEngineDelegate::UnbindRequestsRemotes,
155                                 fake_engine_delegate_));
156 
157   mojo_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
158                                       run_loop.QuitClosure());
159   run_loop.Run();
160 }
161 
~SandboxChildProcess()162 SandboxChildProcess::~SandboxChildProcess() {
163   // |engine_commands_impl_| must be destroyed on the Mojo thread or it will
164   // crash.
165   mojo_task_runner_->PostTask(
166       FROM_HERE, base::BindOnce(
167                      [](std::unique_ptr<EngineCommandsImpl> commands) {
168                        commands.reset();
169                      },
170                      std::move(engine_commands_impl_)));
171 }
172 
173 }  // namespace chrome_cleaner
174