Home | History | Annotate | Download | only in payload_consumer
      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