• 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/filesystem_verifier_action.h"
18 
19 #include <fcntl.h>
20 
21 #include <set>
22 #include <string>
23 #include <vector>
24 
25 #include <base/bind.h>
26 #include <base/posix/eintr_wrapper.h>
27 #include <base/strings/string_util.h>
28 #include <base/strings/stringprintf.h>
29 #include <brillo/bind_lambda.h>
30 #include <brillo/message_loops/fake_message_loop.h>
31 #include <brillo/message_loops/message_loop_utils.h>
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34 
35 #include "update_engine/common/hash_calculator.h"
36 #include "update_engine/common/test_utils.h"
37 #include "update_engine/common/utils.h"
38 #include "update_engine/payload_consumer/payload_constants.h"
39 
40 using brillo::MessageLoop;
41 using std::set;
42 using std::string;
43 using std::vector;
44 
45 namespace chromeos_update_engine {
46 
47 class FilesystemVerifierActionTest : public ::testing::Test {
48  protected:
SetUp()49   void SetUp() override {
50     loop_.SetAsCurrent();
51   }
52 
TearDown()53   void TearDown() override {
54     EXPECT_EQ(0, brillo::MessageLoopRunMaxIterations(&loop_, 1));
55   }
56 
57   // Returns true iff test has completed successfully.
58   bool DoTest(bool terminate_early, bool hash_fail);
59 
60   brillo::FakeMessageLoop loop_{nullptr};
61 };
62 
63 class FilesystemVerifierActionTestDelegate : public ActionProcessorDelegate {
64  public:
FilesystemVerifierActionTestDelegate(FilesystemVerifierAction * action)65   explicit FilesystemVerifierActionTestDelegate(
66       FilesystemVerifierAction* action)
67       : action_(action), ran_(false), code_(ErrorCode::kError) {}
ExitMainLoop()68   void ExitMainLoop() {
69     // We need to wait for the Action to call Cleanup.
70     if (action_->IsCleanupPending()) {
71       LOG(INFO) << "Waiting for Cleanup() to be called.";
72       MessageLoop::current()->PostDelayedTask(
73           FROM_HERE,
74           base::Bind(&FilesystemVerifierActionTestDelegate::ExitMainLoop,
75                      base::Unretained(this)),
76           base::TimeDelta::FromMilliseconds(100));
77     } else {
78       MessageLoop::current()->BreakLoop();
79     }
80   }
ProcessingDone(const ActionProcessor * processor,ErrorCode code)81   void ProcessingDone(const ActionProcessor* processor, ErrorCode code) {
82     ExitMainLoop();
83   }
ProcessingStopped(const ActionProcessor * processor)84   void ProcessingStopped(const ActionProcessor* processor) {
85     ExitMainLoop();
86   }
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)87   void ActionCompleted(ActionProcessor* processor,
88                        AbstractAction* action,
89                        ErrorCode code) {
90     if (action->Type() == FilesystemVerifierAction::StaticType()) {
91       ran_ = true;
92       code_ = code;
93     }
94   }
ran() const95   bool ran() const { return ran_; }
code() const96   ErrorCode code() const { return code_; }
97 
98  private:
99   FilesystemVerifierAction* action_;
100   bool ran_;
101   ErrorCode code_;
102 };
103 
StartProcessorInRunLoop(ActionProcessor * processor,FilesystemVerifierAction * filesystem_copier_action,bool terminate_early)104 void StartProcessorInRunLoop(ActionProcessor* processor,
105                              FilesystemVerifierAction* filesystem_copier_action,
106                              bool terminate_early) {
107   processor->StartProcessing();
108   if (terminate_early) {
109     EXPECT_NE(nullptr, filesystem_copier_action);
110     processor->StopProcessing();
111   }
112 }
113 
DoTest(bool terminate_early,bool hash_fail)114 bool FilesystemVerifierActionTest::DoTest(bool terminate_early,
115                                           bool hash_fail) {
116   string a_loop_file;
117 
118   if (!(utils::MakeTempFile("a_loop_file.XXXXXX", &a_loop_file, nullptr))) {
119     ADD_FAILURE();
120     return false;
121   }
122   ScopedPathUnlinker a_loop_file_unlinker(a_loop_file);
123 
124   // Make random data for a.
125   const size_t kLoopFileSize = 10 * 1024 * 1024 + 512;
126   brillo::Blob a_loop_data(kLoopFileSize);
127   test_utils::FillWithData(&a_loop_data);
128 
129   // Write data to disk
130   if (!(test_utils::WriteFileVector(a_loop_file, a_loop_data))) {
131     ADD_FAILURE();
132     return false;
133   }
134 
135   // Attach loop devices to the files
136   string a_dev;
137   test_utils::ScopedLoopbackDeviceBinder a_dev_releaser(
138       a_loop_file, false, &a_dev);
139   if (!(a_dev_releaser.is_bound())) {
140     ADD_FAILURE();
141     return false;
142   }
143 
144   LOG(INFO) << "verifying: "  << a_loop_file << " (" << a_dev << ")";
145 
146   bool success = true;
147 
148   // Set up the action objects
149   InstallPlan install_plan;
150   install_plan.source_slot = 0;
151   install_plan.target_slot = 1;
152   InstallPlan::Partition part;
153   part.name = "part";
154   part.target_size = kLoopFileSize - (hash_fail ? 1 : 0);
155   part.target_path = a_dev;
156   if (!HashCalculator::RawHashOfData(a_loop_data, &part.target_hash)) {
157     ADD_FAILURE();
158     success = false;
159   }
160   part.source_size = kLoopFileSize;
161   part.source_path = a_dev;
162   if (!HashCalculator::RawHashOfData(a_loop_data, &part.source_hash)) {
163     ADD_FAILURE();
164     success = false;
165   }
166   install_plan.partitions = {part};
167 
168   ActionProcessor processor;
169 
170   ObjectFeederAction<InstallPlan> feeder_action;
171   FilesystemVerifierAction copier_action;
172   ObjectCollectorAction<InstallPlan> collector_action;
173 
174   BondActions(&feeder_action, &copier_action);
175   BondActions(&copier_action, &collector_action);
176 
177   FilesystemVerifierActionTestDelegate delegate(&copier_action);
178   processor.set_delegate(&delegate);
179   processor.EnqueueAction(&feeder_action);
180   processor.EnqueueAction(&copier_action);
181   processor.EnqueueAction(&collector_action);
182 
183   feeder_action.set_obj(install_plan);
184 
185   loop_.PostTask(FROM_HERE, base::Bind(&StartProcessorInRunLoop,
186                                        &processor,
187                                        &copier_action,
188                                        terminate_early));
189   loop_.Run();
190 
191   if (!terminate_early) {
192     bool is_delegate_ran = delegate.ran();
193     EXPECT_TRUE(is_delegate_ran);
194     success = success && is_delegate_ran;
195   } else {
196     EXPECT_EQ(ErrorCode::kError, delegate.code());
197     return (ErrorCode::kError == delegate.code());
198   }
199   if (hash_fail) {
200     ErrorCode expected_exit_code = ErrorCode::kNewRootfsVerificationError;
201     EXPECT_EQ(expected_exit_code, delegate.code());
202     return (expected_exit_code == delegate.code());
203   }
204   EXPECT_EQ(ErrorCode::kSuccess, delegate.code());
205 
206   // Make sure everything in the out_image is there
207   brillo::Blob a_out;
208   if (!utils::ReadFile(a_dev, &a_out)) {
209     ADD_FAILURE();
210     return false;
211   }
212   const bool is_a_file_reading_eq =
213       test_utils::ExpectVectorsEq(a_loop_data, a_out);
214   EXPECT_TRUE(is_a_file_reading_eq);
215   success = success && is_a_file_reading_eq;
216 
217   bool is_install_plan_eq = (collector_action.object() == install_plan);
218   EXPECT_TRUE(is_install_plan_eq);
219   success = success && is_install_plan_eq;
220   return success;
221 }
222 
223 class FilesystemVerifierActionTest2Delegate : public ActionProcessorDelegate {
224  public:
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)225   void ActionCompleted(ActionProcessor* processor,
226                        AbstractAction* action,
227                        ErrorCode code) {
228     if (action->Type() == FilesystemVerifierAction::StaticType()) {
229       ran_ = true;
230       code_ = code;
231     }
232   }
233   bool ran_;
234   ErrorCode code_;
235 };
236 
TEST_F(FilesystemVerifierActionTest,MissingInputObjectTest)237 TEST_F(FilesystemVerifierActionTest, MissingInputObjectTest) {
238   ActionProcessor processor;
239   FilesystemVerifierActionTest2Delegate delegate;
240 
241   processor.set_delegate(&delegate);
242 
243   FilesystemVerifierAction copier_action;
244   ObjectCollectorAction<InstallPlan> collector_action;
245 
246   BondActions(&copier_action, &collector_action);
247 
248   processor.EnqueueAction(&copier_action);
249   processor.EnqueueAction(&collector_action);
250   processor.StartProcessing();
251   EXPECT_FALSE(processor.IsRunning());
252   EXPECT_TRUE(delegate.ran_);
253   EXPECT_EQ(ErrorCode::kError, delegate.code_);
254 }
255 
TEST_F(FilesystemVerifierActionTest,NonExistentDriveTest)256 TEST_F(FilesystemVerifierActionTest, NonExistentDriveTest) {
257   ActionProcessor processor;
258   FilesystemVerifierActionTest2Delegate delegate;
259 
260   processor.set_delegate(&delegate);
261 
262   ObjectFeederAction<InstallPlan> feeder_action;
263   InstallPlan install_plan;
264   InstallPlan::Partition part;
265   part.name = "nope";
266   part.source_path = "/no/such/file";
267   part.target_path = "/no/such/file";
268   install_plan.partitions = {part};
269 
270   feeder_action.set_obj(install_plan);
271   FilesystemVerifierAction verifier_action;
272   ObjectCollectorAction<InstallPlan> collector_action;
273 
274   BondActions(&verifier_action, &collector_action);
275 
276   processor.EnqueueAction(&feeder_action);
277   processor.EnqueueAction(&verifier_action);
278   processor.EnqueueAction(&collector_action);
279   processor.StartProcessing();
280   EXPECT_FALSE(processor.IsRunning());
281   EXPECT_TRUE(delegate.ran_);
282   EXPECT_EQ(ErrorCode::kError, delegate.code_);
283 }
284 
TEST_F(FilesystemVerifierActionTest,RunAsRootVerifyHashTest)285 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashTest) {
286   ASSERT_EQ(0U, getuid());
287   EXPECT_TRUE(DoTest(false, false));
288 }
289 
TEST_F(FilesystemVerifierActionTest,RunAsRootVerifyHashFailTest)290 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashFailTest) {
291   ASSERT_EQ(0U, getuid());
292   EXPECT_TRUE(DoTest(false, true));
293 }
294 
TEST_F(FilesystemVerifierActionTest,RunAsRootTerminateEarlyTest)295 TEST_F(FilesystemVerifierActionTest, RunAsRootTerminateEarlyTest) {
296   ASSERT_EQ(0U, getuid());
297   EXPECT_TRUE(DoTest(true, false));
298   // TerminateEarlyTest may leak some null callbacks from the Stream class.
299   while (loop_.RunOnce(false)) {}
300 }
301 
302 }  // namespace chromeos_update_engine
303