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 
49 using brillo::MessageLoop;
50 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
51 using std::string;
52 
53 namespace chromeos_update_engine {
54 
55 class PostinstActionProcessorDelegate : public ActionProcessorDelegate {
56  public:
57   PostinstActionProcessorDelegate() = default;
ProcessingDone(const ActionProcessor * processor,ErrorCode code)58   void ProcessingDone(const ActionProcessor* processor,
59                       ErrorCode code) override {
60     MessageLoop::current()->BreakLoop();
61     processing_done_called_ = true;
62   }
ProcessingStopped(const ActionProcessor * processor)63   void ProcessingStopped(const ActionProcessor* processor) override {
64     MessageLoop::current()->BreakLoop();
65     processing_stopped_called_ = true;
66   }
67 
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)68   void ActionCompleted(ActionProcessor* processor,
69                        AbstractAction* action,
70                        ErrorCode code) override {
71     if (action->Type() == PostinstallRunnerAction::StaticType()) {
72       code_ = code;
73       code_set_ = true;
74     }
75   }
76 
77   ErrorCode code_{ErrorCode::kError};
78   bool code_set_{false};
79   bool processing_done_called_{false};
80   bool processing_stopped_called_{false};
81 };
82 
83 class MockPostinstallRunnerActionDelegate
84     : public PostinstallRunnerAction::DelegateInterface {
85  public:
86   MOCK_METHOD1(ProgressUpdate, void(double progress));
87 };
88 
89 class PostinstallRunnerActionTest : public ::testing::Test {
90  protected:
SetUp()91   void SetUp() override {
92     loop_.SetAsCurrent();
93     async_signal_handler_.Init();
94     subprocess_.Init(&async_signal_handler_);
95     // These tests use the postinstall files generated by "generate_images.sh"
96     // stored in the "disk_ext2_unittest.img" image.
97     postinstall_image_ =
98         test_utils::GetBuildArtifactsPath("gen/disk_ext2_unittest.img");
99   }
100 
101   // Setup an action processor and run the PostinstallRunnerAction with a single
102   // partition |device_path|, running the |postinstall_program| command from
103   // there.
104   void RunPostinstallAction(const string& device_path,
105                             const string& postinstall_program,
106                             bool powerwash_required,
107                             bool is_rollback,
108                             bool save_rollback_data);
109 
110   void RunPostinstallActionWithInstallPlan(const InstallPlan& install_plan);
111 
112  public:
ResumeRunningAction()113   void ResumeRunningAction() {
114     ASSERT_NE(nullptr, postinstall_action_);
115     postinstall_action_->ResumeAction();
116   }
117 
SuspendRunningAction()118   void SuspendRunningAction() {
119     if (!postinstall_action_ || !postinstall_action_->current_command_ ||
120         test_utils::Readlink(base::StringPrintf(
121             "/proc/%d/fd/0", postinstall_action_->current_command_)) !=
122             "/dev/zero") {
123       // We need to wait for the postinstall command to start and flag that it
124       // is ready by redirecting its input to /dev/zero.
125       loop_.PostDelayedTask(
126           FROM_HERE,
127           base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
128                      base::Unretained(this)),
129           base::TimeDelta::FromMilliseconds(100));
130     } else {
131       postinstall_action_->SuspendAction();
132       // Schedule to be resumed in a little bit.
133       loop_.PostDelayedTask(
134           FROM_HERE,
135           base::Bind(&PostinstallRunnerActionTest::ResumeRunningAction,
136                      base::Unretained(this)),
137           base::TimeDelta::FromMilliseconds(100));
138     }
139   }
140 
CancelWhenStarted()141   void CancelWhenStarted() {
142     if (!postinstall_action_ || !postinstall_action_->current_command_) {
143       // Wait for the postinstall command to run.
144       loop_.PostDelayedTask(
145           FROM_HERE,
146           base::Bind(&PostinstallRunnerActionTest::CancelWhenStarted,
147                      base::Unretained(this)),
148           base::TimeDelta::FromMilliseconds(10));
149     } else {
150       CHECK(processor_);
151       // Must |PostDelayedTask()| here to be safe that |FileDescriptorWatcher|
152       // doesn't leak memory, do not directly call |StopProcessing()|.
153       loop_.PostDelayedTask(
154           FROM_HERE,
155           base::Bind(
156               [](ActionProcessor* processor) { processor->StopProcessing(); },
157               base::Unretained(processor_)),
158           base::TimeDelta::FromMilliseconds(100));
159     }
160   }
161 
162  protected:
163 #if BASE_VER < 780000  // Android
164   base::MessageLoopForIO base_loop_;
165   brillo::BaseMessageLoop loop_{&base_loop_};
166 #else   // CrOS
167   base::SingleThreadTaskExecutor base_loop_{base::MessagePumpType::IO};
168   brillo::BaseMessageLoop loop_{base_loop_.task_runner()};
169 #endif  // BASE_VER < 780000
170   brillo::AsynchronousSignalHandler async_signal_handler_;
171   Subprocess subprocess_;
172 
173   // The path to the postinstall sample image.
174   string postinstall_image_;
175 
176   FakeBootControl fake_boot_control_;
177   FakeHardware fake_hardware_;
178   PostinstActionProcessorDelegate processor_delegate_;
179 
180   // The PostinstallRunnerAction delegate receiving the progress updates.
181   PostinstallRunnerAction::DelegateInterface* setup_action_delegate_{nullptr};
182 
183   // A pointer to the posinstall_runner action and the processor.
184   PostinstallRunnerAction* postinstall_action_{nullptr};
185   ActionProcessor* processor_{nullptr};
186 };
187 
RunPostinstallAction(const string & device_path,const string & postinstall_program,bool powerwash_required,bool is_rollback,bool save_rollback_data)188 void PostinstallRunnerActionTest::RunPostinstallAction(
189     const string& device_path,
190     const string& postinstall_program,
191     bool powerwash_required,
192     bool is_rollback,
193     bool save_rollback_data) {
194   InstallPlan::Partition part;
195   part.name = "part";
196   part.target_path = device_path;
197   part.readonly_target_path = device_path;
198   part.run_postinstall = true;
199   part.postinstall_path = postinstall_program;
200   InstallPlan install_plan;
201   install_plan.partitions = {part};
202   install_plan.download_url = "http://127.0.0.1:8080/update";
203   install_plan.powerwash_required = powerwash_required;
204   install_plan.is_rollback = is_rollback;
205   install_plan.rollback_data_save_requested = save_rollback_data;
206   RunPostinstallActionWithInstallPlan(install_plan);
207 }
208 
RunPostinstallActionWithInstallPlan(const chromeos_update_engine::InstallPlan & install_plan)209 void PostinstallRunnerActionTest::RunPostinstallActionWithInstallPlan(
210     const chromeos_update_engine::InstallPlan& install_plan) {
211   ActionProcessor processor;
212   processor_ = &processor;
213   auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
214   feeder_action->set_obj(install_plan);
215   auto runner_action = std::make_unique<PostinstallRunnerAction>(
216       &fake_boot_control_, &fake_hardware_);
217   postinstall_action_ = runner_action.get();
218   base::FilePath temp_dir;
219   TEST_AND_RETURN(base::CreateNewTempDirectory("postinstall", &temp_dir));
220   postinstall_action_->SetMountDir(temp_dir.value());
221   runner_action->set_delegate(setup_action_delegate_);
222   BondActions(feeder_action.get(), runner_action.get());
223   auto collector_action =
224       std::make_unique<ObjectCollectorAction<InstallPlan>>();
225   BondActions(runner_action.get(), collector_action.get());
226   processor.EnqueueAction(std::move(feeder_action));
227   processor.EnqueueAction(std::move(runner_action));
228   processor.EnqueueAction(std::move(collector_action));
229   processor.set_delegate(&processor_delegate_);
230 
231   loop_.PostTask(
232       FROM_HERE,
233       base::Bind(
234           [](ActionProcessor* processor) { processor->StartProcessing(); },
235           base::Unretained(&processor)));
236   loop_.Run();
237   ASSERT_FALSE(processor.IsRunning());
238   postinstall_action_ = nullptr;
239   processor_ = nullptr;
240   EXPECT_TRUE(processor_delegate_.processing_stopped_called_ ||
241               processor_delegate_.processing_done_called_);
242   if (processor_delegate_.processing_done_called_) {
243     // Validation check that the code was set when the processor finishes.
244     EXPECT_TRUE(processor_delegate_.code_set_);
245   }
246 }
247 
TEST_F(PostinstallRunnerActionTest,ProcessProgressLineTest)248 TEST_F(PostinstallRunnerActionTest, ProcessProgressLineTest) {
249   PostinstallRunnerAction action(&fake_boot_control_, &fake_hardware_);
250   testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_;
251   action.set_delegate(&mock_delegate_);
252 
253   action.current_partition_ = 1;
254   action.partition_weight_ = {1, 2, 5};
255   action.accumulated_weight_ = 1;
256   action.total_weight_ = 8;
257 
258   // 50% of the second action is 2/8 = 0.25 of the total.
259   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.25));
260   action.ProcessProgressLine("global_progress 0.5");
261   testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
262 
263   // 1.5 should be read as 100%, to catch rounding error cases like 1.000001.
264   // 100% of the second is 3/8 of the total.
265   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.375));
266   action.ProcessProgressLine("global_progress 1.5");
267   testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
268 
269   // None of these should trigger a progress update.
270   action.ProcessProgressLine("foo_bar");
271   action.ProcessProgressLine("global_progress");
272   action.ProcessProgressLine("global_progress ");
273   action.ProcessProgressLine("global_progress NaN");
274   action.ProcessProgressLine("global_progress Exception in ... :)");
275 }
276 
277 // Test that postinstall succeeds in the simple case of running the default
278 // /postinst command which only exits 0.
TEST_F(PostinstallRunnerActionTest,RunAsRootSimpleTest)279 TEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) {
280   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
281 
282   RunPostinstallAction(
283       loop.dev(), kPostinstallDefaultScript, false, false, false);
284   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
285   EXPECT_TRUE(processor_delegate_.processing_done_called_);
286 
287   // Since powerwash_required was false, this should not trigger a powerwash.
288   EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
289   EXPECT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
290 }
291 
TEST_F(PostinstallRunnerActionTest,RunAsRootRunSymlinkFileTest)292 TEST_F(PostinstallRunnerActionTest, RunAsRootRunSymlinkFileTest) {
293   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
294   RunPostinstallAction(loop.dev(), "bin/postinst_link", false, false, false);
295   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
296 }
297 
TEST_F(PostinstallRunnerActionTest,RunAsRootPowerwashRequiredTest)298 TEST_F(PostinstallRunnerActionTest, RunAsRootPowerwashRequiredTest) {
299   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
300   // Run a simple postinstall program but requiring a powerwash.
301   RunPostinstallAction(loop.dev(),
302                        "bin/postinst_example",
303                        /*powerwash_required=*/true,
304                        false,
305                        false);
306   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
307 
308   // Check that powerwash was scheduled.
309   EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
310   EXPECT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
311 }
312 
TEST_F(PostinstallRunnerActionTest,RunAsRootRollbackTestNoDataSave)313 TEST_F(PostinstallRunnerActionTest, RunAsRootRollbackTestNoDataSave) {
314   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
315 
316   // Run a simple postinstall program, rollback happened.
317   RunPostinstallAction(loop.dev(),
318                        "bin/postinst_example",
319                        false,
320                        /*is_rollback=*/true,
321                        /*save_rollback_data=*/false);
322   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
323 
324   // Check that powerwash was scheduled and that it's NOT a rollback powerwash.
325   EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
326   EXPECT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
327 }
328 
TEST_F(PostinstallRunnerActionTest,RunAsRootRollbackTestWithDataSave)329 TEST_F(PostinstallRunnerActionTest, RunAsRootRollbackTestWithDataSave) {
330   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
331 
332   // Run a simple postinstall program, rollback happened.
333   RunPostinstallAction(loop.dev(),
334                        "bin/postinst_example",
335                        false,
336                        /*is_rollback=*/true,
337                        /*save_rollback_data=*/true);
338   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
339 
340   // Check that powerwash was scheduled and that it's a rollback powerwash.
341   EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
342   EXPECT_TRUE(fake_hardware_.GetIsRollbackPowerwashScheduled());
343 }
344 
345 // Runs postinstall from a partition file that doesn't mount, so it should
346 // fail.
TEST_F(PostinstallRunnerActionTest,RunAsRootCantMountTest)347 TEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) {
348   RunPostinstallAction(
349       "/dev/null", kPostinstallDefaultScript, false, false, false);
350   EXPECT_EQ(ErrorCode::kPostInstallMountError, processor_delegate_.code_);
351 
352   // In case of failure, Postinstall should not signal a powerwash even if it
353   // was requested.
354   EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
355   EXPECT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
356 }
357 
TEST_F(PostinstallRunnerActionTest,RunAsRootSkipOptionalPostinstallTest)358 TEST_F(PostinstallRunnerActionTest, RunAsRootSkipOptionalPostinstallTest) {
359   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
360   InstallPlan::Partition part;
361   part.name = "part";
362   part.target_path = "/dev/null";
363   part.readonly_target_path = loop.dev();
364   part.run_postinstall = true;
365   part.postinstall_path = "non_existent_path";
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