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