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