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