• 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 <vector>
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/bind_lambda.h>
33 #include <brillo/message_loops/base_message_loop.h>
34 #include <brillo/message_loops/message_loop_utils.h>
35 #include <gmock/gmock.h>
36 #include <gtest/gtest.h>
37 
38 #include "update_engine/common/constants.h"
39 #include "update_engine/common/fake_boot_control.h"
40 #include "update_engine/common/fake_hardware.h"
41 #include "update_engine/common/test_utils.h"
42 #include "update_engine/common/utils.h"
43 
44 using brillo::MessageLoop;
45 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
46 using std::string;
47 using std::vector;
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_ = test_utils::GetBuildArtifactsPath()
94                              .Append("gen/disk_ext2_unittest.img")
95                              .value();
96 
97     ASSERT_EQ(0U, getuid()) << "Run these tests as root.";
98   }
99 
TearDown()100   void TearDown() override {
101     EXPECT_TRUE(base::DeleteFile(base::FilePath(working_dir_), true));
102   }
103 
104   // Setup an action processor and run the PostinstallRunnerAction with a single
105   // partition |device_path|, running the |postinstall_program| command from
106   // there.
107   void RunPosinstallAction(const string& device_path,
108                            const string& postinstall_program,
109                            bool powerwash_required);
110 
111  public:
ResumeRunningAction()112   void ResumeRunningAction() {
113     ASSERT_NE(nullptr, postinstall_action_);
114     postinstall_action_->ResumeAction();
115   }
116 
SuspendRunningAction()117   void SuspendRunningAction() {
118     if (!postinstall_action_ || !postinstall_action_->current_command_ ||
119         test_utils::Readlink(base::StringPrintf(
120             "/proc/%d/fd/0", postinstall_action_->current_command_)) !=
121             "/dev/zero") {
122       // We need to wait for the postinstall command to start and flag that it
123       // is ready by redirecting its input to /dev/zero.
124       loop_.PostDelayedTask(
125           FROM_HERE,
126           base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
127                      base::Unretained(this)),
128           base::TimeDelta::FromMilliseconds(100));
129     } else {
130       postinstall_action_->SuspendAction();
131       // Schedule to be resumed in a little bit.
132       loop_.PostDelayedTask(
133           FROM_HERE,
134           base::Bind(&PostinstallRunnerActionTest::ResumeRunningAction,
135                      base::Unretained(this)),
136           base::TimeDelta::FromMilliseconds(100));
137     }
138   }
139 
CancelWhenStarted()140   void CancelWhenStarted() {
141     if (!postinstall_action_ || !postinstall_action_->current_command_) {
142       // Wait for the postinstall command to run.
143       loop_.PostDelayedTask(
144           FROM_HERE,
145           base::Bind(&PostinstallRunnerActionTest::CancelWhenStarted,
146                      base::Unretained(this)),
147           base::TimeDelta::FromMilliseconds(10));
148     } else {
149       CHECK(processor_);
150       processor_->StopProcessing();
151     }
152   }
153 
154  protected:
155   base::MessageLoopForIO base_loop_;
156   brillo::BaseMessageLoop loop_{&base_loop_};
157   brillo::AsynchronousSignalHandler async_signal_handler_;
158   Subprocess subprocess_;
159 
160   // The path to the postinstall sample image.
161   string postinstall_image_;
162 
163   FakeBootControl fake_boot_control_;
164   FakeHardware fake_hardware_;
165   PostinstActionProcessorDelegate processor_delegate_;
166 
167   // The PostinstallRunnerAction delegate receiving the progress updates.
168   PostinstallRunnerAction::DelegateInterface* setup_action_delegate_{nullptr};
169 
170   // A pointer to the posinstall_runner action and the processor.
171   PostinstallRunnerAction* postinstall_action_{nullptr};
172   ActionProcessor* processor_{nullptr};
173 };
174 
RunPosinstallAction(const string & device_path,const string & postinstall_program,bool powerwash_required)175 void PostinstallRunnerActionTest::RunPosinstallAction(
176     const string& device_path,
177     const string& postinstall_program,
178     bool powerwash_required) {
179   ActionProcessor processor;
180   processor_ = &processor;
181   ObjectFeederAction<InstallPlan> feeder_action;
182   InstallPlan::Partition part;
183   part.name = "part";
184   part.target_path = device_path;
185   part.run_postinstall = true;
186   part.postinstall_path = postinstall_program;
187   InstallPlan install_plan;
188   install_plan.partitions = {part};
189   install_plan.download_url = "http://127.0.0.1:8080/update";
190   install_plan.powerwash_required = powerwash_required;
191   feeder_action.set_obj(install_plan);
192   PostinstallRunnerAction runner_action(&fake_boot_control_, &fake_hardware_);
193   postinstall_action_ = &runner_action;
194   runner_action.set_delegate(setup_action_delegate_);
195   BondActions(&feeder_action, &runner_action);
196   ObjectCollectorAction<InstallPlan> collector_action;
197   BondActions(&runner_action, &collector_action);
198   processor.EnqueueAction(&feeder_action);
199   processor.EnqueueAction(&runner_action);
200   processor.EnqueueAction(&collector_action);
201   processor.set_delegate(&processor_delegate_);
202 
203   loop_.PostTask(FROM_HERE,
204                  base::Bind([&processor] { processor.StartProcessing(); }));
205   loop_.Run();
206   ASSERT_FALSE(processor.IsRunning());
207   postinstall_action_ = nullptr;
208   processor_ = nullptr;
209   EXPECT_TRUE(processor_delegate_.processing_stopped_called_ ||
210               processor_delegate_.processing_done_called_);
211   if (processor_delegate_.processing_done_called_) {
212     // Sanity check that the code was set when the processor finishes.
213     EXPECT_TRUE(processor_delegate_.code_set_);
214   }
215 }
216 
TEST_F(PostinstallRunnerActionTest,ProcessProgressLineTest)217 TEST_F(PostinstallRunnerActionTest, ProcessProgressLineTest) {
218   PostinstallRunnerAction action(&fake_boot_control_, &fake_hardware_);
219   testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_;
220   action.set_delegate(&mock_delegate_);
221 
222   action.current_partition_ = 1;
223   action.partition_weight_ = {1, 2, 5};
224   action.accumulated_weight_ = 1;
225   action.total_weight_ = 8;
226 
227   // 50% of the second actions is 2/8 = 0.25 of the total.
228   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.25));
229   action.ProcessProgressLine("global_progress 0.5");
230   testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
231 
232   // None of these should trigger a progress update.
233   action.ProcessProgressLine("foo_bar");
234   action.ProcessProgressLine("global_progress");
235   action.ProcessProgressLine("global_progress ");
236 }
237 
238 // Test that postinstall succeeds in the simple case of running the default
239 // /postinst command which only exits 0.
TEST_F(PostinstallRunnerActionTest,RunAsRootSimpleTest)240 TEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) {
241   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
242   RunPosinstallAction(loop.dev(), kPostinstallDefaultScript, false);
243   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
244   EXPECT_TRUE(processor_delegate_.processing_done_called_);
245 
246   // Since powerwash_required was false, this should not trigger a powerwash.
247   EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
248 }
249 
TEST_F(PostinstallRunnerActionTest,RunAsRootRunSymlinkFileTest)250 TEST_F(PostinstallRunnerActionTest, RunAsRootRunSymlinkFileTest) {
251   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
252   RunPosinstallAction(loop.dev(), "bin/postinst_link", false);
253   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
254 }
255 
TEST_F(PostinstallRunnerActionTest,RunAsRootPowerwashRequiredTest)256 TEST_F(PostinstallRunnerActionTest, RunAsRootPowerwashRequiredTest) {
257   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
258   // Run a simple postinstall program but requiring a powerwash.
259   RunPosinstallAction(loop.dev(), "bin/postinst_example", true);
260   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
261 
262   // Check that powerwash was scheduled.
263   EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
264 }
265 
266 // Runs postinstall from a partition file that doesn't mount, so it should
267 // fail.
TEST_F(PostinstallRunnerActionTest,RunAsRootCantMountTest)268 TEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) {
269   RunPosinstallAction("/dev/null", kPostinstallDefaultScript, false);
270   EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
271 
272   // In case of failure, Postinstall should not signal a powerwash even if it
273   // was requested.
274   EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
275 }
276 
277 // Check that the failures from the postinstall script cause the action to
278 // fail.
TEST_F(PostinstallRunnerActionTest,RunAsRootErrScriptTest)279 TEST_F(PostinstallRunnerActionTest, RunAsRootErrScriptTest) {
280   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
281   RunPosinstallAction(loop.dev(), "bin/postinst_fail1", false);
282   EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
283 }
284 
285 // The exit code 3 and 4 are a specials cases that would be reported back to
286 // UMA with a different error code. Test those cases are properly detected.
TEST_F(PostinstallRunnerActionTest,RunAsRootFirmwareBErrScriptTest)287 TEST_F(PostinstallRunnerActionTest, RunAsRootFirmwareBErrScriptTest) {
288   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
289   RunPosinstallAction(loop.dev(), "bin/postinst_fail3", false);
290   EXPECT_EQ(ErrorCode::kPostinstallBootedFromFirmwareB,
291             processor_delegate_.code_);
292 }
293 
294 // Check that you can't specify an absolute path.
TEST_F(PostinstallRunnerActionTest,RunAsRootAbsolutePathNotAllowedTest)295 TEST_F(PostinstallRunnerActionTest, RunAsRootAbsolutePathNotAllowedTest) {
296   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
297   RunPosinstallAction(loop.dev(), "/etc/../bin/sh", false);
298   EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
299 }
300 
301 #ifdef __ANDROID__
302 // Check that the postinstall file is relabeled to the postinstall label.
303 // SElinux labels are only set on Android.
TEST_F(PostinstallRunnerActionTest,RunAsRootCheckFileContextsTest)304 TEST_F(PostinstallRunnerActionTest, RunAsRootCheckFileContextsTest) {
305   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
306   RunPosinstallAction(loop.dev(), "bin/self_check_context", false);
307   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
308 }
309 #endif  // __ANDROID__
310 
311 // Check that you can suspend/resume postinstall actions.
TEST_F(PostinstallRunnerActionTest,RunAsRootSuspendResumeActionTest)312 TEST_F(PostinstallRunnerActionTest, RunAsRootSuspendResumeActionTest) {
313   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
314 
315   // We need to wait for the child to run and setup its signal handler.
316   loop_.PostTask(FROM_HERE,
317                  base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
318                             base::Unretained(this)));
319   RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
320   // postinst_suspend returns 0 only if it was suspended at some point.
321   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
322   EXPECT_TRUE(processor_delegate_.processing_done_called_);
323 }
324 
325 // Test that we can cancel a postinstall action while it is running.
TEST_F(PostinstallRunnerActionTest,RunAsRootCancelPostinstallActionTest)326 TEST_F(PostinstallRunnerActionTest, RunAsRootCancelPostinstallActionTest) {
327   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
328 
329   // Wait for the action to start and then cancel it.
330   CancelWhenStarted();
331   RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
332   // When canceling the action, the action never finished and therefore we had
333   // a ProcessingStopped call instead.
334   EXPECT_FALSE(processor_delegate_.code_set_);
335   EXPECT_TRUE(processor_delegate_.processing_stopped_called_);
336 }
337 
338 // Test that we parse and process the progress reports from the progress
339 // file descriptor.
TEST_F(PostinstallRunnerActionTest,RunAsRootProgressUpdatesTest)340 TEST_F(PostinstallRunnerActionTest, RunAsRootProgressUpdatesTest) {
341   testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_;
342   testing::InSequence s;
343   EXPECT_CALL(mock_delegate_, ProgressUpdate(0));
344 
345   // The postinst_progress program will call with 0.25, 0.5 and 1.
346   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.25));
347   EXPECT_CALL(mock_delegate_, ProgressUpdate(0.5));
348   EXPECT_CALL(mock_delegate_, ProgressUpdate(1.));
349 
350   EXPECT_CALL(mock_delegate_, ProgressUpdate(1.));
351 
352   ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
353   setup_action_delegate_ = &mock_delegate_;
354   RunPosinstallAction(loop.dev(), "bin/postinst_progress", false);
355   EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
356 }
357 
358 }  // namespace chromeos_update_engine
359