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 <memory> 20 #include <string> 21 #include <utility> 22 23 #include <base/bind.h> 24 #include <base/posix/eintr_wrapper.h> 25 #include <brillo/message_loops/fake_message_loop.h> 26 #include <brillo/message_loops/message_loop_utils.h> 27 #include <brillo/secure_blob.h> 28 #include <gtest/gtest.h> 29 30 #include "update_engine/common/hash_calculator.h" 31 #include "update_engine/common/test_utils.h" 32 #include "update_engine/common/utils.h" 33 34 using brillo::MessageLoop; 35 using std::string; 36 37 namespace chromeos_update_engine { 38 39 class FilesystemVerifierActionTest : public ::testing::Test { 40 protected: 41 void SetUp() override { loop_.SetAsCurrent(); } 42 43 void TearDown() override { 44 EXPECT_EQ(0, brillo::MessageLoopRunMaxIterations(&loop_, 1)); 45 } 46 47 // Returns true iff test has completed successfully. 48 bool DoTest(bool terminate_early, bool hash_fail); 49 50 void BuildActions(const InstallPlan& install_plan); 51 52 brillo::FakeMessageLoop loop_{nullptr}; 53 ActionProcessor processor_; 54 }; 55 56 class FilesystemVerifierActionTestDelegate : public ActionProcessorDelegate { 57 public: 58 FilesystemVerifierActionTestDelegate() 59 : ran_(false), code_(ErrorCode::kError) {} 60 61 void ProcessingDone(const ActionProcessor* processor, ErrorCode code) { 62 MessageLoop::current()->BreakLoop(); 63 } 64 void ProcessingStopped(const ActionProcessor* processor) { 65 MessageLoop::current()->BreakLoop(); 66 } 67 void ActionCompleted(ActionProcessor* processor, 68 AbstractAction* action, 69 ErrorCode code) { 70 if (action->Type() == FilesystemVerifierAction::StaticType()) { 71 ran_ = true; 72 code_ = code; 73 EXPECT_FALSE(static_cast<FilesystemVerifierAction*>(action)->src_stream_); 74 } else if (action->Type() == 75 ObjectCollectorAction<InstallPlan>::StaticType()) { 76 auto collector_action = 77 static_cast<ObjectCollectorAction<InstallPlan>*>(action); 78 install_plan_.reset(new InstallPlan(collector_action->object())); 79 } 80 } 81 bool ran() const { return ran_; } 82 ErrorCode code() const { return code_; } 83 84 std::unique_ptr<InstallPlan> install_plan_; 85 86 private: 87 bool ran_; 88 ErrorCode code_; 89 }; 90 91 bool FilesystemVerifierActionTest::DoTest(bool terminate_early, 92 bool hash_fail) { 93 test_utils::ScopedTempFile a_loop_file("a_loop_file.XXXXXX"); 94 95 // Make random data for a. 96 const size_t kLoopFileSize = 10 * 1024 * 1024 + 512; 97 brillo::Blob a_loop_data(kLoopFileSize); 98 test_utils::FillWithData(&a_loop_data); 99 100 // Write data to disk 101 if (!(test_utils::WriteFileVector(a_loop_file.path(), a_loop_data))) { 102 ADD_FAILURE(); 103 return false; 104 } 105 106 // Attach loop devices to the files 107 string a_dev; 108 test_utils::ScopedLoopbackDeviceBinder a_dev_releaser( 109 a_loop_file.path(), false, &a_dev); 110 if (!(a_dev_releaser.is_bound())) { 111 ADD_FAILURE(); 112 return false; 113 } 114 115 LOG(INFO) << "verifying: " << a_loop_file.path() << " (" << a_dev << ")"; 116 117 bool success = true; 118 119 // Set up the action objects 120 InstallPlan install_plan; 121 install_plan.source_slot = 0; 122 install_plan.target_slot = 1; 123 InstallPlan::Partition part; 124 part.name = "part"; 125 part.target_size = kLoopFileSize - (hash_fail ? 1 : 0); 126 part.target_path = a_dev; 127 if (!HashCalculator::RawHashOfData(a_loop_data, &part.target_hash)) { 128 ADD_FAILURE(); 129 success = false; 130 } 131 part.source_size = kLoopFileSize; 132 part.source_path = a_dev; 133 if (!HashCalculator::RawHashOfData(a_loop_data, &part.source_hash)) { 134 ADD_FAILURE(); 135 success = false; 136 } 137 install_plan.partitions = {part}; 138 139 BuildActions(install_plan); 140 141 FilesystemVerifierActionTestDelegate delegate; 142 processor_.set_delegate(&delegate); 143 144 loop_.PostTask(FROM_HERE, 145 base::Bind( 146 [](ActionProcessor* processor, bool terminate_early) { 147 processor->StartProcessing(); 148 if (terminate_early) { 149 processor->StopProcessing(); 150 } 151 }, 152 base::Unretained(&processor_), 153 terminate_early)); 154 loop_.Run(); 155 156 if (!terminate_early) { 157 bool is_delegate_ran = delegate.ran(); 158 EXPECT_TRUE(is_delegate_ran); 159 success = success && is_delegate_ran; 160 } else { 161 EXPECT_EQ(ErrorCode::kError, delegate.code()); 162 return (ErrorCode::kError == delegate.code()); 163 } 164 if (hash_fail) { 165 ErrorCode expected_exit_code = ErrorCode::kNewRootfsVerificationError; 166 EXPECT_EQ(expected_exit_code, delegate.code()); 167 return (expected_exit_code == delegate.code()); 168 } 169 EXPECT_EQ(ErrorCode::kSuccess, delegate.code()); 170 171 // Make sure everything in the out_image is there 172 brillo::Blob a_out; 173 if (!utils::ReadFile(a_dev, &a_out)) { 174 ADD_FAILURE(); 175 return false; 176 } 177 const bool is_a_file_reading_eq = 178 test_utils::ExpectVectorsEq(a_loop_data, a_out); 179 EXPECT_TRUE(is_a_file_reading_eq); 180 success = success && is_a_file_reading_eq; 181 182 bool is_install_plan_eq = (*delegate.install_plan_ == install_plan); 183 EXPECT_TRUE(is_install_plan_eq); 184 success = success && is_install_plan_eq; 185 return success; 186 } 187 188 void FilesystemVerifierActionTest::BuildActions( 189 const InstallPlan& install_plan) { 190 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>(); 191 auto verifier_action = std::make_unique<FilesystemVerifierAction>(); 192 auto collector_action = 193 std::make_unique<ObjectCollectorAction<InstallPlan>>(); 194 195 feeder_action->set_obj(install_plan); 196 197 BondActions(feeder_action.get(), verifier_action.get()); 198 BondActions(verifier_action.get(), collector_action.get()); 199 200 processor_.EnqueueAction(std::move(feeder_action)); 201 processor_.EnqueueAction(std::move(verifier_action)); 202 processor_.EnqueueAction(std::move(collector_action)); 203 } 204 205 class FilesystemVerifierActionTest2Delegate : public ActionProcessorDelegate { 206 public: 207 void ActionCompleted(ActionProcessor* processor, 208 AbstractAction* action, 209 ErrorCode code) { 210 if (action->Type() == FilesystemVerifierAction::StaticType()) { 211 ran_ = true; 212 code_ = code; 213 } 214 } 215 bool ran_; 216 ErrorCode code_; 217 }; 218 219 TEST_F(FilesystemVerifierActionTest, MissingInputObjectTest) { 220 auto copier_action = std::make_unique<FilesystemVerifierAction>(); 221 auto collector_action = 222 std::make_unique<ObjectCollectorAction<InstallPlan>>(); 223 224 BondActions(copier_action.get(), collector_action.get()); 225 226 processor_.EnqueueAction(std::move(copier_action)); 227 processor_.EnqueueAction(std::move(collector_action)); 228 229 FilesystemVerifierActionTest2Delegate delegate; 230 processor_.set_delegate(&delegate); 231 232 processor_.StartProcessing(); 233 EXPECT_FALSE(processor_.IsRunning()); 234 EXPECT_TRUE(delegate.ran_); 235 EXPECT_EQ(ErrorCode::kError, delegate.code_); 236 } 237 238 TEST_F(FilesystemVerifierActionTest, NonExistentDriveTest) { 239 InstallPlan install_plan; 240 InstallPlan::Partition part; 241 part.name = "nope"; 242 part.source_path = "/no/such/file"; 243 part.target_path = "/no/such/file"; 244 install_plan.partitions = {part}; 245 246 BuildActions(install_plan); 247 248 FilesystemVerifierActionTest2Delegate delegate; 249 processor_.set_delegate(&delegate); 250 251 processor_.StartProcessing(); 252 EXPECT_FALSE(processor_.IsRunning()); 253 EXPECT_TRUE(delegate.ran_); 254 EXPECT_EQ(ErrorCode::kFilesystemVerifierError, delegate.code_); 255 } 256 257 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashTest) { 258 ASSERT_EQ(0U, getuid()); 259 EXPECT_TRUE(DoTest(false, false)); 260 } 261 262 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashFailTest) { 263 ASSERT_EQ(0U, getuid()); 264 EXPECT_TRUE(DoTest(false, true)); 265 } 266 267 TEST_F(FilesystemVerifierActionTest, RunAsRootTerminateEarlyTest) { 268 ASSERT_EQ(0U, getuid()); 269 EXPECT_TRUE(DoTest(true, false)); 270 // TerminateEarlyTest may leak some null callbacks from the Stream class. 271 while (loop_.RunOnce(false)) { 272 } 273 } 274 275 #ifdef __ANDROID__ 276 TEST_F(FilesystemVerifierActionTest, RunAsRootWriteVerityTest) { 277 test_utils::ScopedTempFile part_file("part_file.XXXXXX"); 278 constexpr size_t filesystem_size = 200 * 4096; 279 constexpr size_t part_size = 256 * 4096; 280 brillo::Blob part_data(filesystem_size, 0x1); 281 part_data.resize(part_size); 282 ASSERT_TRUE(test_utils::WriteFileVector(part_file.path(), part_data)); 283 string target_path; 284 test_utils::ScopedLoopbackDeviceBinder target_device( 285 part_file.path(), true, &target_path); 286 287 InstallPlan install_plan; 288 InstallPlan::Partition part; 289 part.name = "part"; 290 part.target_path = target_path; 291 part.target_size = part_size; 292 part.block_size = 4096; 293 part.hash_tree_algorithm = "sha1"; 294 part.hash_tree_data_offset = 0; 295 part.hash_tree_data_size = filesystem_size; 296 part.hash_tree_offset = filesystem_size; 297 part.hash_tree_size = 3 * 4096; 298 part.fec_data_offset = 0; 299 part.fec_data_size = filesystem_size + part.hash_tree_size; 300 part.fec_offset = part.fec_data_size; 301 part.fec_size = 2 * 4096; 302 part.fec_roots = 2; 303 // for i in {1..$((200 * 4096))}; do echo -n -e '\x1' >> part; done 304 // avbtool add_hashtree_footer --image part --partition_size $((256 * 4096)) 305 // --partition_name part --do_not_append_vbmeta_image 306 // --output_vbmeta_image vbmeta 307 // truncate -s $((256 * 4096)) part 308 // sha256sum part | xxd -r -p | hexdump -v -e '/1 "0x%02x, "' 309 part.target_hash = {0x28, 0xd4, 0x96, 0x75, 0x4c, 0xf5, 0x8a, 0x3e, 310 0x31, 0x85, 0x08, 0x92, 0x85, 0x62, 0xf0, 0x37, 311 0xbc, 0x8d, 0x7e, 0xa4, 0xcb, 0x24, 0x18, 0x7b, 312 0xf3, 0xeb, 0xb5, 0x8d, 0x6f, 0xc8, 0xd8, 0x1a}; 313 // avbtool info_image --image vbmeta | grep Salt | cut -d':' -f 2 | 314 // xxd -r -p | hexdump -v -e '/1 "0x%02x, "' 315 part.hash_tree_salt = {0x9e, 0xcb, 0xf8, 0xd5, 0x0b, 0xb4, 0x43, 316 0x0a, 0x7a, 0x10, 0xad, 0x96, 0xd7, 0x15, 317 0x70, 0xba, 0xed, 0x27, 0xe2, 0xae}; 318 install_plan.partitions = {part}; 319 320 BuildActions(install_plan); 321 322 FilesystemVerifierActionTestDelegate delegate; 323 processor_.set_delegate(&delegate); 324 325 loop_.PostTask( 326 FROM_HERE, 327 base::Bind( 328 [](ActionProcessor* processor) { processor->StartProcessing(); }, 329 base::Unretained(&processor_))); 330 loop_.Run(); 331 332 EXPECT_FALSE(processor_.IsRunning()); 333 EXPECT_TRUE(delegate.ran()); 334 EXPECT_EQ(ErrorCode::kSuccess, delegate.code()); 335 } 336 #endif // __ANDROID__ 337 338 TEST_F(FilesystemVerifierActionTest, RunAsRootSkipWriteVerityTest) { 339 test_utils::ScopedTempFile part_file("part_file.XXXXXX"); 340 constexpr size_t filesystem_size = 200 * 4096; 341 constexpr size_t part_size = 256 * 4096; 342 brillo::Blob part_data(part_size); 343 test_utils::FillWithData(&part_data); 344 ASSERT_TRUE(test_utils::WriteFileVector(part_file.path(), part_data)); 345 string target_path; 346 test_utils::ScopedLoopbackDeviceBinder target_device( 347 part_file.path(), true, &target_path); 348 349 InstallPlan install_plan; 350 install_plan.write_verity = false; 351 InstallPlan::Partition part; 352 part.name = "part"; 353 part.target_path = target_path; 354 part.target_size = part_size; 355 part.block_size = 4096; 356 part.hash_tree_data_offset = 0; 357 part.hash_tree_data_size = filesystem_size; 358 part.hash_tree_offset = filesystem_size; 359 part.hash_tree_size = 3 * 4096; 360 part.fec_data_offset = 0; 361 part.fec_data_size = filesystem_size + part.hash_tree_size; 362 part.fec_offset = part.fec_data_size; 363 part.fec_size = 2 * 4096; 364 EXPECT_TRUE(HashCalculator::RawHashOfData(part_data, &part.target_hash)); 365 install_plan.partitions = {part}; 366 367 BuildActions(install_plan); 368 369 FilesystemVerifierActionTestDelegate delegate; 370 processor_.set_delegate(&delegate); 371 372 loop_.PostTask( 373 FROM_HERE, 374 base::Bind( 375 [](ActionProcessor* processor) { processor->StartProcessing(); }, 376 base::Unretained(&processor_))); 377 loop_.Run(); 378 379 EXPECT_FALSE(processor_.IsRunning()); 380 EXPECT_TRUE(delegate.ran()); 381 EXPECT_EQ(ErrorCode::kSuccess, delegate.code()); 382 } 383 } // namespace chromeos_update_engine 384