1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "update_engine/payload_consumer/filesystem_verifier_action.h"
18
19 #include <fcntl.h>
20
21 #include <set>
22 #include <string>
23 #include <vector>
24
25 #include <base/bind.h>
26 #include <base/posix/eintr_wrapper.h>
27 #include <base/strings/string_util.h>
28 #include <base/strings/stringprintf.h>
29 #include <brillo/bind_lambda.h>
30 #include <brillo/message_loops/fake_message_loop.h>
31 #include <brillo/message_loops/message_loop_utils.h>
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34
35 #include "update_engine/common/hash_calculator.h"
36 #include "update_engine/common/test_utils.h"
37 #include "update_engine/common/utils.h"
38 #include "update_engine/payload_consumer/payload_constants.h"
39
40 using brillo::MessageLoop;
41 using std::set;
42 using std::string;
43 using std::vector;
44
45 namespace chromeos_update_engine {
46
47 class FilesystemVerifierActionTest : public ::testing::Test {
48 protected:
SetUp()49 void SetUp() override {
50 loop_.SetAsCurrent();
51 }
52
TearDown()53 void TearDown() override {
54 EXPECT_EQ(0, brillo::MessageLoopRunMaxIterations(&loop_, 1));
55 }
56
57 // Returns true iff test has completed successfully.
58 bool DoTest(bool terminate_early, bool hash_fail);
59
60 brillo::FakeMessageLoop loop_{nullptr};
61 };
62
63 class FilesystemVerifierActionTestDelegate : public ActionProcessorDelegate {
64 public:
FilesystemVerifierActionTestDelegate(FilesystemVerifierAction * action)65 explicit FilesystemVerifierActionTestDelegate(
66 FilesystemVerifierAction* action)
67 : action_(action), ran_(false), code_(ErrorCode::kError) {}
ExitMainLoop()68 void ExitMainLoop() {
69 // We need to wait for the Action to call Cleanup.
70 if (action_->IsCleanupPending()) {
71 LOG(INFO) << "Waiting for Cleanup() to be called.";
72 MessageLoop::current()->PostDelayedTask(
73 FROM_HERE,
74 base::Bind(&FilesystemVerifierActionTestDelegate::ExitMainLoop,
75 base::Unretained(this)),
76 base::TimeDelta::FromMilliseconds(100));
77 } else {
78 MessageLoop::current()->BreakLoop();
79 }
80 }
ProcessingDone(const ActionProcessor * processor,ErrorCode code)81 void ProcessingDone(const ActionProcessor* processor, ErrorCode code) {
82 ExitMainLoop();
83 }
ProcessingStopped(const ActionProcessor * processor)84 void ProcessingStopped(const ActionProcessor* processor) {
85 ExitMainLoop();
86 }
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)87 void ActionCompleted(ActionProcessor* processor,
88 AbstractAction* action,
89 ErrorCode code) {
90 if (action->Type() == FilesystemVerifierAction::StaticType()) {
91 ran_ = true;
92 code_ = code;
93 }
94 }
ran() const95 bool ran() const { return ran_; }
code() const96 ErrorCode code() const { return code_; }
97
98 private:
99 FilesystemVerifierAction* action_;
100 bool ran_;
101 ErrorCode code_;
102 };
103
StartProcessorInRunLoop(ActionProcessor * processor,FilesystemVerifierAction * filesystem_copier_action,bool terminate_early)104 void StartProcessorInRunLoop(ActionProcessor* processor,
105 FilesystemVerifierAction* filesystem_copier_action,
106 bool terminate_early) {
107 processor->StartProcessing();
108 if (terminate_early) {
109 EXPECT_NE(nullptr, filesystem_copier_action);
110 processor->StopProcessing();
111 }
112 }
113
DoTest(bool terminate_early,bool hash_fail)114 bool FilesystemVerifierActionTest::DoTest(bool terminate_early,
115 bool hash_fail) {
116 string a_loop_file;
117
118 if (!(utils::MakeTempFile("a_loop_file.XXXXXX", &a_loop_file, nullptr))) {
119 ADD_FAILURE();
120 return false;
121 }
122 ScopedPathUnlinker a_loop_file_unlinker(a_loop_file);
123
124 // Make random data for a.
125 const size_t kLoopFileSize = 10 * 1024 * 1024 + 512;
126 brillo::Blob a_loop_data(kLoopFileSize);
127 test_utils::FillWithData(&a_loop_data);
128
129 // Write data to disk
130 if (!(test_utils::WriteFileVector(a_loop_file, a_loop_data))) {
131 ADD_FAILURE();
132 return false;
133 }
134
135 // Attach loop devices to the files
136 string a_dev;
137 test_utils::ScopedLoopbackDeviceBinder a_dev_releaser(
138 a_loop_file, false, &a_dev);
139 if (!(a_dev_releaser.is_bound())) {
140 ADD_FAILURE();
141 return false;
142 }
143
144 LOG(INFO) << "verifying: " << a_loop_file << " (" << a_dev << ")";
145
146 bool success = true;
147
148 // Set up the action objects
149 InstallPlan install_plan;
150 install_plan.source_slot = 0;
151 install_plan.target_slot = 1;
152 InstallPlan::Partition part;
153 part.name = "part";
154 part.target_size = kLoopFileSize - (hash_fail ? 1 : 0);
155 part.target_path = a_dev;
156 if (!HashCalculator::RawHashOfData(a_loop_data, &part.target_hash)) {
157 ADD_FAILURE();
158 success = false;
159 }
160 part.source_size = kLoopFileSize;
161 part.source_path = a_dev;
162 if (!HashCalculator::RawHashOfData(a_loop_data, &part.source_hash)) {
163 ADD_FAILURE();
164 success = false;
165 }
166 install_plan.partitions = {part};
167
168 ActionProcessor processor;
169
170 ObjectFeederAction<InstallPlan> feeder_action;
171 FilesystemVerifierAction copier_action;
172 ObjectCollectorAction<InstallPlan> collector_action;
173
174 BondActions(&feeder_action, &copier_action);
175 BondActions(&copier_action, &collector_action);
176
177 FilesystemVerifierActionTestDelegate delegate(&copier_action);
178 processor.set_delegate(&delegate);
179 processor.EnqueueAction(&feeder_action);
180 processor.EnqueueAction(&copier_action);
181 processor.EnqueueAction(&collector_action);
182
183 feeder_action.set_obj(install_plan);
184
185 loop_.PostTask(FROM_HERE, base::Bind(&StartProcessorInRunLoop,
186 &processor,
187 &copier_action,
188 terminate_early));
189 loop_.Run();
190
191 if (!terminate_early) {
192 bool is_delegate_ran = delegate.ran();
193 EXPECT_TRUE(is_delegate_ran);
194 success = success && is_delegate_ran;
195 } else {
196 EXPECT_EQ(ErrorCode::kError, delegate.code());
197 return (ErrorCode::kError == delegate.code());
198 }
199 if (hash_fail) {
200 ErrorCode expected_exit_code = ErrorCode::kNewRootfsVerificationError;
201 EXPECT_EQ(expected_exit_code, delegate.code());
202 return (expected_exit_code == delegate.code());
203 }
204 EXPECT_EQ(ErrorCode::kSuccess, delegate.code());
205
206 // Make sure everything in the out_image is there
207 brillo::Blob a_out;
208 if (!utils::ReadFile(a_dev, &a_out)) {
209 ADD_FAILURE();
210 return false;
211 }
212 const bool is_a_file_reading_eq =
213 test_utils::ExpectVectorsEq(a_loop_data, a_out);
214 EXPECT_TRUE(is_a_file_reading_eq);
215 success = success && is_a_file_reading_eq;
216
217 bool is_install_plan_eq = (collector_action.object() == install_plan);
218 EXPECT_TRUE(is_install_plan_eq);
219 success = success && is_install_plan_eq;
220 return success;
221 }
222
223 class FilesystemVerifierActionTest2Delegate : public ActionProcessorDelegate {
224 public:
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)225 void ActionCompleted(ActionProcessor* processor,
226 AbstractAction* action,
227 ErrorCode code) {
228 if (action->Type() == FilesystemVerifierAction::StaticType()) {
229 ran_ = true;
230 code_ = code;
231 }
232 }
233 bool ran_;
234 ErrorCode code_;
235 };
236
TEST_F(FilesystemVerifierActionTest,MissingInputObjectTest)237 TEST_F(FilesystemVerifierActionTest, MissingInputObjectTest) {
238 ActionProcessor processor;
239 FilesystemVerifierActionTest2Delegate delegate;
240
241 processor.set_delegate(&delegate);
242
243 FilesystemVerifierAction copier_action;
244 ObjectCollectorAction<InstallPlan> collector_action;
245
246 BondActions(&copier_action, &collector_action);
247
248 processor.EnqueueAction(&copier_action);
249 processor.EnqueueAction(&collector_action);
250 processor.StartProcessing();
251 EXPECT_FALSE(processor.IsRunning());
252 EXPECT_TRUE(delegate.ran_);
253 EXPECT_EQ(ErrorCode::kError, delegate.code_);
254 }
255
TEST_F(FilesystemVerifierActionTest,NonExistentDriveTest)256 TEST_F(FilesystemVerifierActionTest, NonExistentDriveTest) {
257 ActionProcessor processor;
258 FilesystemVerifierActionTest2Delegate delegate;
259
260 processor.set_delegate(&delegate);
261
262 ObjectFeederAction<InstallPlan> feeder_action;
263 InstallPlan install_plan;
264 InstallPlan::Partition part;
265 part.name = "nope";
266 part.source_path = "/no/such/file";
267 part.target_path = "/no/such/file";
268 install_plan.partitions = {part};
269
270 feeder_action.set_obj(install_plan);
271 FilesystemVerifierAction verifier_action;
272 ObjectCollectorAction<InstallPlan> collector_action;
273
274 BondActions(&verifier_action, &collector_action);
275
276 processor.EnqueueAction(&feeder_action);
277 processor.EnqueueAction(&verifier_action);
278 processor.EnqueueAction(&collector_action);
279 processor.StartProcessing();
280 EXPECT_FALSE(processor.IsRunning());
281 EXPECT_TRUE(delegate.ran_);
282 EXPECT_EQ(ErrorCode::kError, delegate.code_);
283 }
284
TEST_F(FilesystemVerifierActionTest,RunAsRootVerifyHashTest)285 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashTest) {
286 ASSERT_EQ(0U, getuid());
287 EXPECT_TRUE(DoTest(false, false));
288 }
289
TEST_F(FilesystemVerifierActionTest,RunAsRootVerifyHashFailTest)290 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashFailTest) {
291 ASSERT_EQ(0U, getuid());
292 EXPECT_TRUE(DoTest(false, true));
293 }
294
TEST_F(FilesystemVerifierActionTest,RunAsRootTerminateEarlyTest)295 TEST_F(FilesystemVerifierActionTest, RunAsRootTerminateEarlyTest) {
296 ASSERT_EQ(0U, getuid());
297 EXPECT_TRUE(DoTest(true, false));
298 // TerminateEarlyTest may leak some null callbacks from the Stream class.
299 while (loop_.RunOnce(false)) {}
300 }
301
302 } // namespace chromeos_update_engine
303