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/fake_boot_control.h" 36 #include "update_engine/common/hash_calculator.h" 37 #include "update_engine/common/test_utils.h" 38 #include "update_engine/common/utils.h" 39 #include "update_engine/payload_consumer/payload_constants.h" 40 41 using brillo::MessageLoop; 42 using std::set; 43 using std::string; 44 using std::vector; 45 46 namespace chromeos_update_engine { 47 48 class FilesystemVerifierActionTest : public ::testing::Test { 49 protected: 50 void SetUp() override { 51 loop_.SetAsCurrent(); 52 } 53 54 void TearDown() override { 55 EXPECT_EQ(0, brillo::MessageLoopRunMaxIterations(&loop_, 1)); 56 } 57 58 // Returns true iff test has completed successfully. 59 bool DoTest(bool terminate_early, 60 bool hash_fail, 61 VerifierMode verifier_mode); 62 63 brillo::FakeMessageLoop loop_{nullptr}; 64 FakeBootControl fake_boot_control_; 65 }; 66 67 class FilesystemVerifierActionTestDelegate : public ActionProcessorDelegate { 68 public: 69 explicit FilesystemVerifierActionTestDelegate( 70 FilesystemVerifierAction* action) 71 : action_(action), ran_(false), code_(ErrorCode::kError) {} 72 void ExitMainLoop() { 73 // We need to wait for the Action to call Cleanup. 74 if (action_->IsCleanupPending()) { 75 LOG(INFO) << "Waiting for Cleanup() to be called."; 76 MessageLoop::current()->PostDelayedTask( 77 FROM_HERE, 78 base::Bind(&FilesystemVerifierActionTestDelegate::ExitMainLoop, 79 base::Unretained(this)), 80 base::TimeDelta::FromMilliseconds(100)); 81 } else { 82 MessageLoop::current()->BreakLoop(); 83 } 84 } 85 void ProcessingDone(const ActionProcessor* processor, ErrorCode code) { 86 ExitMainLoop(); 87 } 88 void ProcessingStopped(const ActionProcessor* processor) { 89 ExitMainLoop(); 90 } 91 void ActionCompleted(ActionProcessor* processor, 92 AbstractAction* action, 93 ErrorCode code) { 94 if (action->Type() == FilesystemVerifierAction::StaticType()) { 95 ran_ = true; 96 code_ = code; 97 } 98 } 99 bool ran() const { return ran_; } 100 ErrorCode code() const { return code_; } 101 102 private: 103 FilesystemVerifierAction* action_; 104 bool ran_; 105 ErrorCode code_; 106 }; 107 108 void StartProcessorInRunLoop(ActionProcessor* processor, 109 FilesystemVerifierAction* filesystem_copier_action, 110 bool terminate_early) { 111 processor->StartProcessing(); 112 if (terminate_early) { 113 EXPECT_NE(nullptr, filesystem_copier_action); 114 processor->StopProcessing(); 115 } 116 } 117 118 // TODO(garnold) Temporarily disabling this test, see chromium-os:31082 for 119 // details; still trying to track down the root cause for these rare write 120 // failures and whether or not they are due to the test setup or an inherent 121 // issue with the chroot environment, library versions we use, etc. 122 TEST_F(FilesystemVerifierActionTest, DISABLED_RunAsRootSimpleTest) { 123 ASSERT_EQ(0U, getuid()); 124 bool test = DoTest(false, false, VerifierMode::kComputeSourceHash); 125 EXPECT_TRUE(test); 126 if (!test) 127 return; 128 test = DoTest(false, false, VerifierMode::kVerifyTargetHash); 129 EXPECT_TRUE(test); 130 } 131 132 bool FilesystemVerifierActionTest::DoTest(bool terminate_early, 133 bool hash_fail, 134 VerifierMode verifier_mode) { 135 string a_loop_file; 136 137 if (!(utils::MakeTempFile("a_loop_file.XXXXXX", &a_loop_file, nullptr))) { 138 ADD_FAILURE(); 139 return false; 140 } 141 ScopedPathUnlinker a_loop_file_unlinker(a_loop_file); 142 143 // Make random data for a. 144 const size_t kLoopFileSize = 10 * 1024 * 1024 + 512; 145 brillo::Blob a_loop_data(kLoopFileSize); 146 test_utils::FillWithData(&a_loop_data); 147 148 // Write data to disk 149 if (!(test_utils::WriteFileVector(a_loop_file, a_loop_data))) { 150 ADD_FAILURE(); 151 return false; 152 } 153 154 // Attach loop devices to the files 155 string a_dev; 156 test_utils::ScopedLoopbackDeviceBinder a_dev_releaser( 157 a_loop_file, false, &a_dev); 158 if (!(a_dev_releaser.is_bound())) { 159 ADD_FAILURE(); 160 return false; 161 } 162 163 LOG(INFO) << "verifying: " << a_loop_file << " (" << a_dev << ")"; 164 165 bool success = true; 166 167 // Set up the action objects 168 InstallPlan install_plan; 169 install_plan.source_slot = 0; 170 install_plan.target_slot = 1; 171 InstallPlan::Partition part; 172 part.name = "part"; 173 if (verifier_mode == VerifierMode::kVerifyTargetHash) { 174 part.target_size = kLoopFileSize - (hash_fail ? 1 : 0); 175 part.target_path = a_dev; 176 fake_boot_control_.SetPartitionDevice( 177 part.name, install_plan.target_slot, a_dev); 178 if (!HashCalculator::RawHashOfData(a_loop_data, &part.target_hash)) { 179 ADD_FAILURE(); 180 success = false; 181 } 182 } 183 part.source_size = kLoopFileSize; 184 part.source_path = a_dev; 185 fake_boot_control_.SetPartitionDevice( 186 part.name, install_plan.source_slot, a_dev); 187 if (!HashCalculator::RawHashOfData(a_loop_data, &part.source_hash)) { 188 ADD_FAILURE(); 189 success = false; 190 } 191 install_plan.partitions = {part}; 192 193 ActionProcessor processor; 194 195 ObjectFeederAction<InstallPlan> feeder_action; 196 FilesystemVerifierAction copier_action(&fake_boot_control_, verifier_mode); 197 ObjectCollectorAction<InstallPlan> collector_action; 198 199 BondActions(&feeder_action, &copier_action); 200 BondActions(&copier_action, &collector_action); 201 202 FilesystemVerifierActionTestDelegate delegate(&copier_action); 203 processor.set_delegate(&delegate); 204 processor.EnqueueAction(&feeder_action); 205 processor.EnqueueAction(&copier_action); 206 processor.EnqueueAction(&collector_action); 207 208 feeder_action.set_obj(install_plan); 209 210 loop_.PostTask(FROM_HERE, base::Bind(&StartProcessorInRunLoop, 211 &processor, 212 &copier_action, 213 terminate_early)); 214 loop_.Run(); 215 216 if (!terminate_early) { 217 bool is_delegate_ran = delegate.ran(); 218 EXPECT_TRUE(is_delegate_ran); 219 success = success && is_delegate_ran; 220 } else { 221 EXPECT_EQ(ErrorCode::kError, delegate.code()); 222 return (ErrorCode::kError == delegate.code()); 223 } 224 if (hash_fail) { 225 ErrorCode expected_exit_code = ErrorCode::kNewRootfsVerificationError; 226 EXPECT_EQ(expected_exit_code, delegate.code()); 227 return (expected_exit_code == delegate.code()); 228 } 229 EXPECT_EQ(ErrorCode::kSuccess, delegate.code()); 230 231 // Make sure everything in the out_image is there 232 brillo::Blob a_out; 233 if (!utils::ReadFile(a_dev, &a_out)) { 234 ADD_FAILURE(); 235 return false; 236 } 237 const bool is_a_file_reading_eq = 238 test_utils::ExpectVectorsEq(a_loop_data, a_out); 239 EXPECT_TRUE(is_a_file_reading_eq); 240 success = success && is_a_file_reading_eq; 241 242 bool is_install_plan_eq = (collector_action.object() == install_plan); 243 EXPECT_TRUE(is_install_plan_eq); 244 success = success && is_install_plan_eq; 245 return success; 246 } 247 248 class FilesystemVerifierActionTest2Delegate : public ActionProcessorDelegate { 249 public: 250 void ActionCompleted(ActionProcessor* processor, 251 AbstractAction* action, 252 ErrorCode code) { 253 if (action->Type() == FilesystemVerifierAction::StaticType()) { 254 ran_ = true; 255 code_ = code; 256 } 257 } 258 bool ran_; 259 ErrorCode code_; 260 }; 261 262 TEST_F(FilesystemVerifierActionTest, MissingInputObjectTest) { 263 ActionProcessor processor; 264 FilesystemVerifierActionTest2Delegate delegate; 265 266 processor.set_delegate(&delegate); 267 268 FilesystemVerifierAction copier_action(&fake_boot_control_, 269 VerifierMode::kVerifyTargetHash); 270 ObjectCollectorAction<InstallPlan> collector_action; 271 272 BondActions(&copier_action, &collector_action); 273 274 processor.EnqueueAction(&copier_action); 275 processor.EnqueueAction(&collector_action); 276 processor.StartProcessing(); 277 EXPECT_FALSE(processor.IsRunning()); 278 EXPECT_TRUE(delegate.ran_); 279 EXPECT_EQ(ErrorCode::kError, delegate.code_); 280 } 281 282 TEST_F(FilesystemVerifierActionTest, NonExistentDriveTest) { 283 ActionProcessor processor; 284 FilesystemVerifierActionTest2Delegate delegate; 285 286 processor.set_delegate(&delegate); 287 288 ObjectFeederAction<InstallPlan> feeder_action; 289 InstallPlan install_plan; 290 InstallPlan::Partition part; 291 part.name = "nope"; 292 part.source_path = "/no/such/file"; 293 part.target_path = "/no/such/file"; 294 install_plan.partitions = {part}; 295 296 feeder_action.set_obj(install_plan); 297 FilesystemVerifierAction verifier_action(&fake_boot_control_, 298 VerifierMode::kVerifyTargetHash); 299 ObjectCollectorAction<InstallPlan> collector_action; 300 301 BondActions(&verifier_action, &collector_action); 302 303 processor.EnqueueAction(&feeder_action); 304 processor.EnqueueAction(&verifier_action); 305 processor.EnqueueAction(&collector_action); 306 processor.StartProcessing(); 307 EXPECT_FALSE(processor.IsRunning()); 308 EXPECT_TRUE(delegate.ran_); 309 EXPECT_EQ(ErrorCode::kError, delegate.code_); 310 } 311 312 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashTest) { 313 ASSERT_EQ(0U, getuid()); 314 EXPECT_TRUE(DoTest(false, false, VerifierMode::kVerifyTargetHash)); 315 EXPECT_TRUE(DoTest(false, false, VerifierMode::kComputeSourceHash)); 316 } 317 318 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashFailTest) { 319 ASSERT_EQ(0U, getuid()); 320 EXPECT_TRUE(DoTest(false, true, VerifierMode::kVerifyTargetHash)); 321 } 322 323 TEST_F(FilesystemVerifierActionTest, RunAsRootTerminateEarlyTest) { 324 ASSERT_EQ(0U, getuid()); 325 EXPECT_TRUE(DoTest(true, false, VerifierMode::kVerifyTargetHash)); 326 // TerminateEarlyTest may leak some null callbacks from the Stream class. 327 while (loop_.RunOnce(false)) {} 328 } 329 330 // Disabled as we switched to minor version 3, so this test is obsolete, will be 331 // deleted when we delete the corresponding code in PerformAction(). 332 // Test that the rootfs and kernel size used for hashing in delta payloads for 333 // major version 1 is properly read. 334 TEST_F(FilesystemVerifierActionTest, 335 DISABLED_RunAsRootDetermineLegacySizeTest) { 336 string img; 337 EXPECT_TRUE(utils::MakeTempFile("img.XXXXXX", &img, nullptr)); 338 ScopedPathUnlinker img_unlinker(img); 339 test_utils::CreateExtImageAtPath(img, nullptr); 340 // Extend the "partition" holding the file system from 10MiB to 20MiB. 341 EXPECT_EQ(0, truncate(img.c_str(), 20 * 1024 * 1024)); 342 343 InstallPlan install_plan; 344 install_plan.source_slot = 1; 345 346 fake_boot_control_.SetPartitionDevice( 347 kLegacyPartitionNameRoot, install_plan.source_slot, img); 348 fake_boot_control_.SetPartitionDevice( 349 kLegacyPartitionNameKernel, install_plan.source_slot, img); 350 FilesystemVerifierAction action(&fake_boot_control_, 351 VerifierMode::kComputeSourceHash); 352 353 ObjectFeederAction<InstallPlan> feeder_action; 354 feeder_action.set_obj(install_plan); 355 356 ObjectCollectorAction<InstallPlan> collector_action; 357 358 BondActions(&feeder_action, &action); 359 BondActions(&action, &collector_action); 360 ActionProcessor processor; 361 processor.EnqueueAction(&feeder_action); 362 processor.EnqueueAction(&action); 363 processor.EnqueueAction(&collector_action); 364 365 loop_.PostTask(FROM_HERE, 366 base::Bind([&processor]{ processor.StartProcessing(); })); 367 loop_.Run(); 368 install_plan = collector_action.object(); 369 370 ASSERT_EQ(2U, install_plan.partitions.size()); 371 // When computing the size of the rootfs on legacy delta updates we use the 372 // size of the filesystem, but when updating the kernel we use the whole 373 // partition. 374 EXPECT_EQ(10U << 20, install_plan.partitions[0].source_size); 375 EXPECT_EQ(kLegacyPartitionNameRoot, install_plan.partitions[0].name); 376 EXPECT_EQ(20U << 20, install_plan.partitions[1].source_size); 377 EXPECT_EQ(kLegacyPartitionNameKernel, install_plan.partitions[1].name); 378 } 379 380 } // namespace chromeos_update_engine 381