blob: f7789f4a38eb90c6f7d90d3810cd9431cfd57789 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
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//
Allie Woodeb9e6d82015-04-17 13:55:30 -070016
Alex Deymo39910dc2015-11-09 17:04:30 -080017#include "update_engine/payload_consumer/filesystem_verifier_action.h"
Allie Woodeb9e6d82015-04-17 13:55:30 -070018
Amin Hassanid3f4bea2018-04-30 14:52:40 -070019#include <memory>
Allie Woodeb9e6d82015-04-17 13:55:30 -070020#include <string>
Amin Hassanid3f4bea2018-04-30 14:52:40 -070021#include <utility>
Allie Woodeb9e6d82015-04-17 13:55:30 -070022
Alex Deymo20c99202015-07-09 16:14:16 -070023#include <base/bind.h>
Allie Woodeb9e6d82015-04-17 13:55:30 -070024#include <base/posix/eintr_wrapper.h>
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070025#include <brillo/message_loops/fake_message_loop.h>
26#include <brillo/message_loops/message_loop_utils.h>
Sen Jiang57f91802017-11-14 17:42:13 -080027#include <brillo/secure_blob.h>
Allie Woodeb9e6d82015-04-17 13:55:30 -070028#include <gtest/gtest.h>
29
Alex Deymo39910dc2015-11-09 17:04:30 -080030#include "update_engine/common/hash_calculator.h"
31#include "update_engine/common/test_utils.h"
32#include "update_engine/common/utils.h"
Allie Woodeb9e6d82015-04-17 13:55:30 -070033
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070034using brillo::MessageLoop;
Allie Woodeb9e6d82015-04-17 13:55:30 -070035using std::string;
Allie Woodeb9e6d82015-04-17 13:55:30 -070036
37namespace chromeos_update_engine {
38
39class FilesystemVerifierActionTest : public ::testing::Test {
40 protected:
Alex Deymo20c99202015-07-09 16:14:16 -070041 void SetUp() override {
42 loop_.SetAsCurrent();
43 }
44
45 void TearDown() override {
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070046 EXPECT_EQ(0, brillo::MessageLoopRunMaxIterations(&loop_, 1));
Alex Deymo20c99202015-07-09 16:14:16 -070047 }
48
Allie Woodeb9e6d82015-04-17 13:55:30 -070049 // Returns true iff test has completed successfully.
Sen Jiangfef85fd2016-03-25 15:32:49 -070050 bool DoTest(bool terminate_early, bool hash_fail);
Allie Woodeb9e6d82015-04-17 13:55:30 -070051
Sen Jiang3eeaf7d2018-10-11 13:55:32 -070052 void BuildActions(const InstallPlan& install_plan);
53
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070054 brillo::FakeMessageLoop loop_{nullptr};
Sen Jiang57f91802017-11-14 17:42:13 -080055 ActionProcessor processor_;
Allie Woodeb9e6d82015-04-17 13:55:30 -070056};
57
58class FilesystemVerifierActionTestDelegate : public ActionProcessorDelegate {
59 public:
Amin Hassaniabe4a772018-07-26 11:19:10 -070060 FilesystemVerifierActionTestDelegate()
61 : ran_(false), code_(ErrorCode::kError) {}
62
Allie Woodeb9e6d82015-04-17 13:55:30 -070063 void ProcessingDone(const ActionProcessor* processor, ErrorCode code) {
Amin Hassaniabe4a772018-07-26 11:19:10 -070064 MessageLoop::current()->BreakLoop();
Allie Woodeb9e6d82015-04-17 13:55:30 -070065 }
66 void ProcessingStopped(const ActionProcessor* processor) {
Amin Hassaniabe4a772018-07-26 11:19:10 -070067 MessageLoop::current()->BreakLoop();
Allie Woodeb9e6d82015-04-17 13:55:30 -070068 }
69 void ActionCompleted(ActionProcessor* processor,
70 AbstractAction* action,
71 ErrorCode code) {
72 if (action->Type() == FilesystemVerifierAction::StaticType()) {
73 ran_ = true;
74 code_ = code;
Amin Hassaniabe4a772018-07-26 11:19:10 -070075 EXPECT_FALSE(static_cast<FilesystemVerifierAction*>(action)->src_stream_);
Amin Hassanid3f4bea2018-04-30 14:52:40 -070076 } else if (action->Type() ==
77 ObjectCollectorAction<InstallPlan>::StaticType()) {
78 auto collector_action =
79 static_cast<ObjectCollectorAction<InstallPlan>*>(action);
80 install_plan_.reset(new InstallPlan(collector_action->object()));
Allie Woodeb9e6d82015-04-17 13:55:30 -070081 }
82 }
83 bool ran() const { return ran_; }
84 ErrorCode code() const { return code_; }
85
Amin Hassanid3f4bea2018-04-30 14:52:40 -070086 std::unique_ptr<InstallPlan> install_plan_;
87
Allie Woodeb9e6d82015-04-17 13:55:30 -070088 private:
Allie Woodeb9e6d82015-04-17 13:55:30 -070089 bool ran_;
90 ErrorCode code_;
91};
92
Allie Woodeb9e6d82015-04-17 13:55:30 -070093bool FilesystemVerifierActionTest::DoTest(bool terminate_early,
Sen Jiangfef85fd2016-03-25 15:32:49 -070094 bool hash_fail) {
Sen Jiang0779a152018-07-02 17:34:56 -070095 test_utils::ScopedTempFile a_loop_file("a_loop_file.XXXXXX");
Allie Woodeb9e6d82015-04-17 13:55:30 -070096
Alex Deymo20c99202015-07-09 16:14:16 -070097 // Make random data for a.
Allie Woodeb9e6d82015-04-17 13:55:30 -070098 const size_t kLoopFileSize = 10 * 1024 * 1024 + 512;
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070099 brillo::Blob a_loop_data(kLoopFileSize);
Allie Woodeb9e6d82015-04-17 13:55:30 -0700100 test_utils::FillWithData(&a_loop_data);
101
Allie Woodeb9e6d82015-04-17 13:55:30 -0700102 // Write data to disk
Sen Jiang0779a152018-07-02 17:34:56 -0700103 if (!(test_utils::WriteFileVector(a_loop_file.path(), a_loop_data))) {
Allie Woodeb9e6d82015-04-17 13:55:30 -0700104 ADD_FAILURE();
105 return false;
106 }
107
108 // Attach loop devices to the files
109 string a_dev;
Alex Deymocbc22742016-03-04 17:53:02 -0800110 test_utils::ScopedLoopbackDeviceBinder a_dev_releaser(
Sen Jiang0779a152018-07-02 17:34:56 -0700111 a_loop_file.path(), false, &a_dev);
Allie Woodeb9e6d82015-04-17 13:55:30 -0700112 if (!(a_dev_releaser.is_bound())) {
113 ADD_FAILURE();
114 return false;
115 }
116
Sen Jiang0779a152018-07-02 17:34:56 -0700117 LOG(INFO) << "verifying: " << a_loop_file.path() << " (" << a_dev << ")";
Allie Woodeb9e6d82015-04-17 13:55:30 -0700118
119 bool success = true;
120
121 // Set up the action objects
122 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700123 install_plan.source_slot = 0;
124 install_plan.target_slot = 1;
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700125 InstallPlan::Partition part;
126 part.name = "part";
Sen Jiangfef85fd2016-03-25 15:32:49 -0700127 part.target_size = kLoopFileSize - (hash_fail ? 1 : 0);
128 part.target_path = a_dev;
Sen Jiangfef85fd2016-03-25 15:32:49 -0700129 if (!HashCalculator::RawHashOfData(a_loop_data, &part.target_hash)) {
130 ADD_FAILURE();
131 success = false;
Sen Jiangf9874812015-12-08 16:11:48 -0800132 }
133 part.source_size = kLoopFileSize;
134 part.source_path = a_dev;
Sen Jiangf9874812015-12-08 16:11:48 -0800135 if (!HashCalculator::RawHashOfData(a_loop_data, &part.source_hash)) {
136 ADD_FAILURE();
137 success = false;
Allie Woodeb9e6d82015-04-17 13:55:30 -0700138 }
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700139 install_plan.partitions = {part};
Allie Woodeb9e6d82015-04-17 13:55:30 -0700140
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700141 BuildActions(install_plan);
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700142
Amin Hassaniabe4a772018-07-26 11:19:10 -0700143 FilesystemVerifierActionTestDelegate delegate;
Sen Jiang57f91802017-11-14 17:42:13 -0800144 processor_.set_delegate(&delegate);
Allie Woodeb9e6d82015-04-17 13:55:30 -0700145
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700146 loop_.PostTask(FROM_HERE,
147 base::Bind(
148 [](ActionProcessor* processor, bool terminate_early) {
149 processor->StartProcessing();
150 if (terminate_early) {
151 processor->StopProcessing();
152 }
153 },
Sen Jiang57f91802017-11-14 17:42:13 -0800154 base::Unretained(&processor_),
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700155 terminate_early));
Alex Deymo20c99202015-07-09 16:14:16 -0700156 loop_.Run();
Allie Woodeb9e6d82015-04-17 13:55:30 -0700157
158 if (!terminate_early) {
159 bool is_delegate_ran = delegate.ran();
160 EXPECT_TRUE(is_delegate_ran);
161 success = success && is_delegate_ran;
162 } else {
163 EXPECT_EQ(ErrorCode::kError, delegate.code());
164 return (ErrorCode::kError == delegate.code());
165 }
166 if (hash_fail) {
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700167 ErrorCode expected_exit_code = ErrorCode::kNewRootfsVerificationError;
Allie Woodeb9e6d82015-04-17 13:55:30 -0700168 EXPECT_EQ(expected_exit_code, delegate.code());
169 return (expected_exit_code == delegate.code());
170 }
171 EXPECT_EQ(ErrorCode::kSuccess, delegate.code());
172
173 // Make sure everything in the out_image is there
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700174 brillo::Blob a_out;
Allie Woodeb9e6d82015-04-17 13:55:30 -0700175 if (!utils::ReadFile(a_dev, &a_out)) {
176 ADD_FAILURE();
177 return false;
178 }
179 const bool is_a_file_reading_eq =
180 test_utils::ExpectVectorsEq(a_loop_data, a_out);
181 EXPECT_TRUE(is_a_file_reading_eq);
182 success = success && is_a_file_reading_eq;
183
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700184 bool is_install_plan_eq = (*delegate.install_plan_ == install_plan);
Allie Woodeb9e6d82015-04-17 13:55:30 -0700185 EXPECT_TRUE(is_install_plan_eq);
186 success = success && is_install_plan_eq;
Allie Woodeb9e6d82015-04-17 13:55:30 -0700187 return success;
188}
189
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700190void FilesystemVerifierActionTest::BuildActions(
191 const InstallPlan& install_plan) {
192 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
193 auto verifier_action = std::make_unique<FilesystemVerifierAction>();
194 auto collector_action =
195 std::make_unique<ObjectCollectorAction<InstallPlan>>();
196
197 feeder_action->set_obj(install_plan);
198
199 BondActions(feeder_action.get(), verifier_action.get());
200 BondActions(verifier_action.get(), collector_action.get());
201
202 processor_.EnqueueAction(std::move(feeder_action));
203 processor_.EnqueueAction(std::move(verifier_action));
204 processor_.EnqueueAction(std::move(collector_action));
205}
206
Allie Woodeb9e6d82015-04-17 13:55:30 -0700207class FilesystemVerifierActionTest2Delegate : public ActionProcessorDelegate {
208 public:
209 void ActionCompleted(ActionProcessor* processor,
210 AbstractAction* action,
211 ErrorCode code) {
212 if (action->Type() == FilesystemVerifierAction::StaticType()) {
213 ran_ = true;
214 code_ = code;
215 }
216 }
Allie Woodeb9e6d82015-04-17 13:55:30 -0700217 bool ran_;
218 ErrorCode code_;
219};
220
221TEST_F(FilesystemVerifierActionTest, MissingInputObjectTest) {
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700222 auto copier_action = std::make_unique<FilesystemVerifierAction>();
223 auto collector_action =
224 std::make_unique<ObjectCollectorAction<InstallPlan>>();
Allie Woodeb9e6d82015-04-17 13:55:30 -0700225
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700226 BondActions(copier_action.get(), collector_action.get());
Allie Woodeb9e6d82015-04-17 13:55:30 -0700227
Sen Jiang57f91802017-11-14 17:42:13 -0800228 processor_.EnqueueAction(std::move(copier_action));
229 processor_.EnqueueAction(std::move(collector_action));
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700230
231 FilesystemVerifierActionTest2Delegate delegate;
232 processor_.set_delegate(&delegate);
233
Sen Jiang57f91802017-11-14 17:42:13 -0800234 processor_.StartProcessing();
235 EXPECT_FALSE(processor_.IsRunning());
Allie Woodeb9e6d82015-04-17 13:55:30 -0700236 EXPECT_TRUE(delegate.ran_);
237 EXPECT_EQ(ErrorCode::kError, delegate.code_);
238}
239
240TEST_F(FilesystemVerifierActionTest, NonExistentDriveTest) {
Alex Deymo64d98782016-02-05 18:03:48 -0800241 InstallPlan install_plan;
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700242 InstallPlan::Partition part;
243 part.name = "nope";
244 part.source_path = "/no/such/file";
245 part.target_path = "/no/such/file";
246 install_plan.partitions = {part};
247
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700248 BuildActions(install_plan);
Allie Woodeb9e6d82015-04-17 13:55:30 -0700249
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700250 FilesystemVerifierActionTest2Delegate delegate;
251 processor_.set_delegate(&delegate);
Allie Woodeb9e6d82015-04-17 13:55:30 -0700252
Sen Jiang57f91802017-11-14 17:42:13 -0800253 processor_.StartProcessing();
254 EXPECT_FALSE(processor_.IsRunning());
Allie Woodeb9e6d82015-04-17 13:55:30 -0700255 EXPECT_TRUE(delegate.ran_);
Sen Jiang57f91802017-11-14 17:42:13 -0800256 EXPECT_EQ(ErrorCode::kFilesystemVerifierError, delegate.code_);
Allie Woodeb9e6d82015-04-17 13:55:30 -0700257}
258
259TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashTest) {
Alex Deymo80f70ff2016-02-10 16:08:11 -0800260 ASSERT_EQ(0U, getuid());
Sen Jiangfef85fd2016-03-25 15:32:49 -0700261 EXPECT_TRUE(DoTest(false, false));
Allie Woodeb9e6d82015-04-17 13:55:30 -0700262}
263
264TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashFailTest) {
Alex Deymo80f70ff2016-02-10 16:08:11 -0800265 ASSERT_EQ(0U, getuid());
Sen Jiangfef85fd2016-03-25 15:32:49 -0700266 EXPECT_TRUE(DoTest(false, true));
Allie Woodeb9e6d82015-04-17 13:55:30 -0700267}
268
269TEST_F(FilesystemVerifierActionTest, RunAsRootTerminateEarlyTest) {
Alex Deymo80f70ff2016-02-10 16:08:11 -0800270 ASSERT_EQ(0U, getuid());
Sen Jiangfef85fd2016-03-25 15:32:49 -0700271 EXPECT_TRUE(DoTest(true, false));
Alex Deymob9e8e262015-08-03 20:23:03 -0700272 // TerminateEarlyTest may leak some null callbacks from the Stream class.
273 while (loop_.RunOnce(false)) {}
Allie Woodeb9e6d82015-04-17 13:55:30 -0700274}
275
Sen Jiang57f91802017-11-14 17:42:13 -0800276#ifdef __ANDROID__
Amin Hassani2e4eda52019-01-07 14:01:17 -0800277TEST_F(FilesystemVerifierActionTest, RunAsRootWriteVerityTest) {
Sen Jiang57f91802017-11-14 17:42:13 -0800278 test_utils::ScopedTempFile part_file("part_file.XXXXXX");
279 constexpr size_t filesystem_size = 200 * 4096;
280 constexpr size_t part_size = 256 * 4096;
281 brillo::Blob part_data(filesystem_size, 0x1);
282 part_data.resize(part_size);
283 ASSERT_TRUE(test_utils::WriteFileVector(part_file.path(), part_data));
284 string target_path;
285 test_utils::ScopedLoopbackDeviceBinder target_device(
286 part_file.path(), true, &target_path);
287
288 InstallPlan install_plan;
289 InstallPlan::Partition part;
290 part.name = "part";
291 part.target_path = target_path;
292 part.target_size = part_size;
293 part.block_size = 4096;
294 part.hash_tree_algorithm = "sha1";
295 part.hash_tree_data_offset = 0;
296 part.hash_tree_data_size = filesystem_size;
297 part.hash_tree_offset = filesystem_size;
298 part.hash_tree_size = 3 * 4096;
Sen Jianga778e5b2018-09-13 11:42:56 -0700299 part.fec_data_offset = 0;
300 part.fec_data_size = filesystem_size + part.hash_tree_size;
301 part.fec_offset = part.fec_data_size;
302 part.fec_size = 2 * 4096;
303 part.fec_roots = 2;
Sen Jiang57f91802017-11-14 17:42:13 -0800304 // for i in {1..$((200 * 4096))}; do echo -n -e '\x1' >> part; done
305 // avbtool add_hashtree_footer --image part --partition_size $((256 * 4096))
Sen Jianga778e5b2018-09-13 11:42:56 -0700306 // --partition_name part --do_not_append_vbmeta_image
307 // --output_vbmeta_image vbmeta
Sen Jiang57f91802017-11-14 17:42:13 -0800308 // truncate -s $((256 * 4096)) part
309 // sha256sum part | xxd -r -p | hexdump -v -e '/1 "0x%02x, "'
Sen Jianga778e5b2018-09-13 11:42:56 -0700310 part.target_hash = {0x28, 0xd4, 0x96, 0x75, 0x4c, 0xf5, 0x8a, 0x3e,
311 0x31, 0x85, 0x08, 0x92, 0x85, 0x62, 0xf0, 0x37,
312 0xbc, 0x8d, 0x7e, 0xa4, 0xcb, 0x24, 0x18, 0x7b,
313 0xf3, 0xeb, 0xb5, 0x8d, 0x6f, 0xc8, 0xd8, 0x1a};
Sen Jiang57f91802017-11-14 17:42:13 -0800314 // avbtool info_image --image vbmeta | grep Salt | cut -d':' -f 2 |
315 // xxd -r -p | hexdump -v -e '/1 "0x%02x, "'
316 part.hash_tree_salt = {0x9e, 0xcb, 0xf8, 0xd5, 0x0b, 0xb4, 0x43,
317 0x0a, 0x7a, 0x10, 0xad, 0x96, 0xd7, 0x15,
318 0x70, 0xba, 0xed, 0x27, 0xe2, 0xae};
319 install_plan.partitions = {part};
320
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700321 BuildActions(install_plan);
Sen Jiang57f91802017-11-14 17:42:13 -0800322
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700323 FilesystemVerifierActionTestDelegate delegate;
324 processor_.set_delegate(&delegate);
Sen Jiang57f91802017-11-14 17:42:13 -0800325
326 loop_.PostTask(
327 FROM_HERE,
328 base::Bind(
329 [](ActionProcessor* processor) { processor->StartProcessing(); },
330 base::Unretained(&processor_)));
331 loop_.Run();
332
333 EXPECT_FALSE(processor_.IsRunning());
334 EXPECT_TRUE(delegate.ran());
335 EXPECT_EQ(ErrorCode::kSuccess, delegate.code());
336}
337#endif // __ANDROID__
338
Amin Hassani2e4eda52019-01-07 14:01:17 -0800339TEST_F(FilesystemVerifierActionTest, RunAsRootSkipWriteVerityTest) {
Sen Jiang3eeaf7d2018-10-11 13:55:32 -0700340 test_utils::ScopedTempFile part_file("part_file.XXXXXX");
341 constexpr size_t filesystem_size = 200 * 4096;
342 constexpr size_t part_size = 256 * 4096;
343 brillo::Blob part_data(part_size);
344 test_utils::FillWithData(&part_data);
345 ASSERT_TRUE(test_utils::WriteFileVector(part_file.path(), part_data));
346 string target_path;
347 test_utils::ScopedLoopbackDeviceBinder target_device(
348 part_file.path(), true, &target_path);
349
350 InstallPlan install_plan;
351 install_plan.write_verity = false;
352 InstallPlan::Partition part;
353 part.name = "part";
354 part.target_path = target_path;
355 part.target_size = part_size;
356 part.block_size = 4096;
357 part.hash_tree_data_offset = 0;
358 part.hash_tree_data_size = filesystem_size;
359 part.hash_tree_offset = filesystem_size;
360 part.hash_tree_size = 3 * 4096;
361 part.fec_data_offset = 0;
362 part.fec_data_size = filesystem_size + part.hash_tree_size;
363 part.fec_offset = part.fec_data_size;
364 part.fec_size = 2 * 4096;
365 EXPECT_TRUE(HashCalculator::RawHashOfData(part_data, &part.target_hash));
366 install_plan.partitions = {part};
367
368 BuildActions(install_plan);
369
370 FilesystemVerifierActionTestDelegate delegate;
371 processor_.set_delegate(&delegate);
372
373 loop_.PostTask(
374 FROM_HERE,
375 base::Bind(
376 [](ActionProcessor* processor) { processor->StartProcessing(); },
377 base::Unretained(&processor_)));
378 loop_.Run();
379
380 EXPECT_FALSE(processor_.IsRunning());
381 EXPECT_TRUE(delegate.ran());
382 EXPECT_EQ(ErrorCode::kSuccess, delegate.code());
383}
Allie Woodeb9e6d82015-04-17 13:55:30 -0700384} // namespace chromeos_update_engine