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/postinstall_runner_action.h"
     18 
     19 #include <sys/stat.h>
     20 #include <sys/types.h>
     21 #include <unistd.h>
     22 
     23 #include <memory>
     24 #include <string>
     25 
     26 #include <base/bind.h>
     27 #include <base/files/file_util.h>
     28 #include <base/message_loop/message_loop.h>
     29 #include <base/strings/string_util.h>
     30 #include <base/strings/stringprintf.h>
     31 #include <brillo/message_loops/base_message_loop.h>
     32 #include <brillo/message_loops/message_loop_utils.h>
     33 #include <gmock/gmock.h>
     34 #include <gtest/gtest.h>
     35 
     36 #include "update_engine/common/constants.h"
     37 #include "update_engine/common/fake_boot_control.h"
     38 #include "update_engine/common/fake_hardware.h"
     39 #include "update_engine/common/test_utils.h"
     40 #include "update_engine/common/utils.h"
     41 
     42 using brillo::MessageLoop;
     43 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
     44 using std::string;
     45 
     46 namespace chromeos_update_engine {
     47 
     48 class PostinstActionProcessorDelegate : public ActionProcessorDelegate {
     49  public:
     50   PostinstActionProcessorDelegate() = default;
     51   void ProcessingDone(const ActionProcessor* processor,
     52                       ErrorCode code) override {
     53     MessageLoop::current()->BreakLoop();
     54     processing_done_called_ = true;
     55   }
     56   void ProcessingStopped(const ActionProcessor* processor) override {
     57     MessageLoop::current()->BreakLoop();
     58     processing_stopped_called_ = true;
     59   }
     60 
     61   void ActionCompleted(ActionProcessor* processor,
     62                        AbstractAction* action,
     63                        ErrorCode code) override {
     64     if (action->Type() == PostinstallRunnerAction::StaticType()) {
     65       code_ = code;
     66       code_set_ = true;
     67     }
     68   }
     69 
     70   ErrorCode code_{ErrorCode::kError};
     71   bool code_set_{false};
     72   bool processing_done_called_{false};
     73   bool processing_stopped_called_{false};
     74 };
     75 
     76 class MockPostinstallRunnerActionDelegate
     77     : public PostinstallRunnerAction::DelegateInterface {
     78  public:
     79   MOCK_METHOD1(ProgressUpdate, void(double progress));
     80 };
     81 
     82 class PostinstallRunnerActionTest : public ::testing::Test {
     83  protected:
     84   void SetUp() override {
     85     loop_.SetAsCurrent();
     86     async_signal_handler_.Init();
     87     subprocess_.Init(&async_signal_handler_);
     88     // These tests use the postinstall files generated by "generate_images.sh"
     89     // stored in the "disk_ext2_unittest.img" image.
     90     postinstall_image_ =
     91         test_utils::GetBuildArtifactsPath("gen/disk_ext2_unittest.img");
     92   }
     93 
     94   // Setup an action processor and run the PostinstallRunnerAction with a single
     95   // partition |device_path|, running the |postinstall_program| command from
     96   // there.
     97   void RunPosinstallAction(const string& device_path,
     98                            const string& postinstall_program,
     99                            bool powerwash_required);
    100 
    101  public:
    102   void ResumeRunningAction() {
    103     ASSERT_NE(nullptr, postinstall_action_);
    104     postinstall_action_->ResumeAction();
    105   }
    106 
    107   void SuspendRunningAction() {
    108     if (!postinstall_action_ || !postinstall_action_->current_command_ ||
    109         test_utils::Readlink(base::StringPrintf(
    110             "/proc/%d/fd/0", postinstall_action_->current_command_)) !=
    111             "/dev/zero") {
    112       // We need to wait for the postinstall command to start and flag that it
    113       // is ready by redirecting its input to /dev/zero.
    114       loop_.PostDelayedTask(
    115           FROM_HERE,
    116           base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
    117                      base::Unretained(this)),
    118           base::TimeDelta::FromMilliseconds(100));
    119     } else {
    120       postinstall_action_->SuspendAction();
    121       // Schedule to be resumed in a little bit.
    122       loop_.PostDelayedTask(
    123           FROM_HERE,
    124           base::Bind(&PostinstallRunnerActionTest::ResumeRunningAction,
    125                      base::Unretained(this)),
    126           base::TimeDelta::FromMilliseconds(100));
    127     }
    128   }
    129 
    130   void CancelWhenStarted() {
    131     if (!postinstall_action_ || !postinstall_action_->current_command_) {
    132       // Wait for the postinstall command to run.
    133       loop_.PostDelayedTask(
    134           FROM_HERE,
    135           base::Bind(&PostinstallRunnerActionTest::CancelWhenStarted,
    136                      base::Unretained(this)),
    137           base::TimeDelta::FromMilliseconds(10));
    138     } else {
    139       CHECK(processor_);
    140       processor_->StopProcessing();
    141     }
    142   }
    143 
    144  protected:
    145   base::MessageLoopForIO base_loop_;
    146   brillo::BaseMessageLoop loop_{&base_loop_};
    147   brillo::AsynchronousSignalHandler async_signal_handler_;
    148   Subprocess subprocess_;
    149 
    150   // The path to the postinstall sample image.
    151   string postinstall_image_;
    152 
    153   FakeBootControl fake_boot_control_;
    154   FakeHardware fake_hardware_;
    155   PostinstActionProcessorDelegate processor_delegate_;
    156 
    157   // The PostinstallRunnerAction delegate receiving the progress updates.
    158   PostinstallRunnerAction::DelegateInterface* setup_action_delegate_{nullptr};
    159 
    160   // A pointer to the posinstall_runner action and the processor.
    161   PostinstallRunnerAction* postinstall_action_{nullptr};
    162   ActionProcessor* processor_{nullptr};
    163 };
    164 
    165 void PostinstallRunnerActionTest::RunPosinstallAction(
    166     const string& device_path,
    167     const string& postinstall_program,
    168     bool powerwash_required) {
    169   ActionProcessor processor;
    170   processor_ = &processor;
    171   ObjectFeederAction<InstallPlan> feeder_action;
    172   InstallPlan::Partition part;
    173   part.name = "part";
    174   part.target_path = device_path;
    175   part.run_postinstall = true;
    176   part.postinstall_path = postinstall_program;
    177   InstallPlan install_plan;
    178   install_plan.partitions = {part};
    179   install_plan.download_url = "http://127.0.0.1:8080/update";
    180   install_plan.powerwash_required = powerwash_required;
    181   feeder_action.set_obj(install_plan);
    182   PostinstallRunnerAction runner_action(&fake_boot_control_, &fake_hardware_);
    183   postinstall_action_ = &runner_action;
    184   runner_action.set_delegate(setup_action_delegate_);
    185   BondActions(&feeder_action, &runner_action);
    186   ObjectCollectorAction<InstallPlan> collector_action;
    187   BondActions(&runner_action, &collector_action);
    188   processor.EnqueueAction(&feeder_action);
    189   processor.EnqueueAction(&runner_action);
    190   processor.EnqueueAction(&collector_action);
    191   processor.set_delegate(&processor_delegate_);
    192 
    193   loop_.PostTask(
    194       FROM_HERE,
    195       base::Bind(
    196           [](ActionProcessor* processor) { processor->StartProcessing(); },
    197           base::Unretained(&processor)));
    198   loop_.Run();
    199   ASSERT_FALSE(processor.IsRunning());
    200   postinstall_action_ = nullptr;
    201   processor_ = nullptr;
    202   EXPECT_TRUE(processor_delegate_.processing_stopped_called_ ||
    203               processor_delegate_.processing_done_called_);
    204   if (processor_delegate_.processing_done_called_) {
    205     // Sanity check that the code was set when the processor finishes.
    206     EXPECT_TRUE(processor_delegate_.code_set_);
    207   }
    208 }
    209 
    210 TEST_F(PostinstallRunnerActionTest, ProcessProgressLineTest) {
    211   PostinstallRunnerAction action(&fake_boot_control_, &fake_hardware_);
    212   testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_;
    213   action.set_delegate(&mock_delegate_);
    214 
    215   action.current_partition_ = 1;
    216   action.partition_weight_ = {1, 2, 5};
    217   action.accumulated_weight_ = 1;
    218   action.total_weight_ = 8;
    219 
    220   // 50% of the second action is 2/8 = 0.25 of the total.
    221   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.25));
    222   action.ProcessProgressLine("global_progress 0.5");
    223   testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
    224 
    225   // 1.5 should be read as 100%, to catch rounding error cases like 1.000001.
    226   // 100% of the second is 3/8 of the total.
    227   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.375));
    228   action.ProcessProgressLine("global_progress 1.5");
    229   testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
    230 
    231   // None of these should trigger a progress update.
    232   action.ProcessProgressLine("foo_bar");
    233   action.ProcessProgressLine("global_progress");
    234   action.ProcessProgressLine("global_progress ");
    235   action.ProcessProgressLine("global_progress NaN");
    236   action.ProcessProgressLine("global_progress Exception in ... :)");
    237 }
    238 
    239 // Test that postinstall succeeds in the simple case of running the default
    240 // /postinst command which only exits 0.
    241 TEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) {
    242   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    243   RunPosinstallAction(loop.dev(), kPostinstallDefaultScript, false);
    244   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
    245   EXPECT_TRUE(processor_delegate_.processing_done_called_);
    246 
    247   // Since powerwash_required was false, this should not trigger a powerwash.
    248   EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
    249 }
    250 
    251 TEST_F(PostinstallRunnerActionTest, RunAsRootRunSymlinkFileTest) {
    252   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    253   RunPosinstallAction(loop.dev(), "bin/postinst_link", false);
    254   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
    255 }
    256 
    257 TEST_F(PostinstallRunnerActionTest, RunAsRootPowerwashRequiredTest) {
    258   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    259   // Run a simple postinstall program but requiring a powerwash.
    260   RunPosinstallAction(loop.dev(), "bin/postinst_example", true);
    261   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
    262 
    263   // Check that powerwash was scheduled.
    264   EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
    265 }
    266 
    267 // Runs postinstall from a partition file that doesn't mount, so it should
    268 // fail.
    269 TEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) {
    270   RunPosinstallAction("/dev/null", kPostinstallDefaultScript, false);
    271   EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
    272 
    273   // In case of failure, Postinstall should not signal a powerwash even if it
    274   // was requested.
    275   EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
    276 }
    277 
    278 // Check that the failures from the postinstall script cause the action to
    279 // fail.
    280 TEST_F(PostinstallRunnerActionTest, RunAsRootErrScriptTest) {
    281   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    282   RunPosinstallAction(loop.dev(), "bin/postinst_fail1", false);
    283   EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
    284 }
    285 
    286 // The exit code 3 and 4 are a specials cases that would be reported back to
    287 // UMA with a different error code. Test those cases are properly detected.
    288 TEST_F(PostinstallRunnerActionTest, RunAsRootFirmwareBErrScriptTest) {
    289   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    290   RunPosinstallAction(loop.dev(), "bin/postinst_fail3", false);
    291   EXPECT_EQ(ErrorCode::kPostinstallBootedFromFirmwareB,
    292             processor_delegate_.code_);
    293 }
    294 
    295 // Check that you can't specify an absolute path.
    296 TEST_F(PostinstallRunnerActionTest, RunAsRootAbsolutePathNotAllowedTest) {
    297   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    298   RunPosinstallAction(loop.dev(), "/etc/../bin/sh", false);
    299   EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
    300 }
    301 
    302 #ifdef __ANDROID__
    303 // Check that the postinstall file is relabeled to the postinstall label.
    304 // SElinux labels are only set on Android.
    305 TEST_F(PostinstallRunnerActionTest, RunAsRootCheckFileContextsTest) {
    306   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    307   RunPosinstallAction(loop.dev(), "bin/self_check_context", false);
    308   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
    309 }
    310 #endif  // __ANDROID__
    311 
    312 // Check that you can suspend/resume postinstall actions.
    313 TEST_F(PostinstallRunnerActionTest, RunAsRootSuspendResumeActionTest) {
    314   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    315 
    316   // We need to wait for the child to run and setup its signal handler.
    317   loop_.PostTask(FROM_HERE,
    318                  base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
    319                             base::Unretained(this)));
    320   RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
    321   // postinst_suspend returns 0 only if it was suspended at some point.
    322   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
    323   EXPECT_TRUE(processor_delegate_.processing_done_called_);
    324 }
    325 
    326 // Test that we can cancel a postinstall action while it is running.
    327 TEST_F(PostinstallRunnerActionTest, RunAsRootCancelPostinstallActionTest) {
    328   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    329 
    330   // Wait for the action to start and then cancel it.
    331   CancelWhenStarted();
    332   RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
    333   // When canceling the action, the action never finished and therefore we had
    334   // a ProcessingStopped call instead.
    335   EXPECT_FALSE(processor_delegate_.code_set_);
    336   EXPECT_TRUE(processor_delegate_.processing_stopped_called_);
    337 }
    338 
    339 // Test that we parse and process the progress reports from the progress
    340 // file descriptor.
    341 TEST_F(PostinstallRunnerActionTest, RunAsRootProgressUpdatesTest) {
    342   testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_;
    343   testing::InSequence s;
    344   EXPECT_CALL(mock_delegate_, ProgressUpdate(0));
    345 
    346   // The postinst_progress program will call with 0.25, 0.5 and 1.
    347   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.25));
    348   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.5));
    349   EXPECT_CALL(mock_delegate_, ProgressUpdate(1.));
    350 
    351   EXPECT_CALL(mock_delegate_, ProgressUpdate(1.));
    352 
    353   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
    354   setup_action_delegate_ = &mock_delegate_;
    355   RunPosinstallAction(loop.dev(), "bin/postinst_progress", false);
    356   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
    357 }
    358 
    359 }  // namespace chromeos_update_engine
    360