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