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