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