blob: 366b22d4038b178ee309a6ca00442d168b70a201 [file] [log] [blame]
Greg Kerr019d59c2016-11-17 14:28:49 -08001// Copyright 2016 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Chan045849f2017-12-18 17:27:07 -08005#include "imageloader/component.h"
Greg Kerr019d59c2016-11-17 14:28:49 -08006
7#include <stdint.h>
8
9#include <list>
Eric Carusocbe1c5c2017-03-15 14:21:08 -070010#include <memory>
Greg Kerr019d59c2016-11-17 14:28:49 -080011#include <string>
12#include <vector>
13
Greg Kerr019d59c2016-11-17 14:28:49 -080014#include <base/files/file_path.h>
15#include <base/files/file_util.h>
16#include <base/files/scoped_temp_dir.h>
17#include <base/logging.h>
Greg Kerr019d59c2016-11-17 14:28:49 -080018#include <crypto/secure_hash.h>
19#include <crypto/sha2.h>
20#include <gmock/gmock.h>
21#include <gtest/gtest.h>
22
Ben Chan045849f2017-12-18 17:27:07 -080023#include "imageloader/imageloader_impl.h"
Greg Kerr09f06de2018-02-16 15:32:07 -080024#include "imageloader/mock_helper_process_proxy.h"
Ben Chan045849f2017-12-18 17:27:07 -080025#include "imageloader/test_utilities.h"
Eric Caruso0b79bc82017-03-21 13:44:34 -070026
Greg Kerr019d59c2016-11-17 14:28:49 -080027namespace imageloader {
28
29using testing::_;
30
31class ComponentTest : public testing::Test {
32 public:
33 ComponentTest() {
Eric Caruso0b79bc82017-03-21 13:44:34 -070034 keys_.push_back(std::vector<uint8_t>(std::begin(kDevPublicKey),
35 std::end(kDevPublicKey)));
Greg Kerr019d59c2016-11-17 14:28:49 -080036 CHECK(scoped_temp_dir_.CreateUniqueTempDir());
Eric Carusoa5dfc942018-01-22 15:44:45 -080037 temp_dir_ = scoped_temp_dir_.GetPath();
Greg Kerr019d59c2016-11-17 14:28:49 -080038 CHECK(base::SetPosixFilePermissions(temp_dir_, kComponentDirPerms));
39 }
40
41 bool TestCopyWithCorruptFile(const std::string& component_name,
42 const std::string& file_name) {
43 base::FilePath bad_component_dir = temp_dir_.Append(component_name);
Colin Howesad6271a2018-11-21 15:36:05 -080044 if (!base::CreateDirectory(bad_component_dir))
45 return false;
Greg Kerr019d59c2016-11-17 14:28:49 -080046 if (!base::SetPosixFilePermissions(bad_component_dir, kComponentDirPerms))
47 return false;
48
Eric Carusocbe1c5c2017-03-15 14:21:08 -070049 std::unique_ptr<Component> component =
Eric Caruso0b79bc82017-03-21 13:44:34 -070050 Component::Create(GetTestComponentPath(), keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -070051 if (!component || !component->CopyTo(bad_component_dir))
Greg Kerr019d59c2016-11-17 14:28:49 -080052 return false;
53
Eric Carusocbe1c5c2017-03-15 14:21:08 -070054 std::unique_ptr<Component> bad_component =
Eric Caruso0b79bc82017-03-21 13:44:34 -070055 Component::Create(bad_component_dir, keys_);
Colin Howesad6271a2018-11-21 15:36:05 -080056 if (!bad_component)
57 return false;
Greg Kerr019d59c2016-11-17 14:28:49 -080058
59 base::FilePath file = bad_component_dir.Append(file_name);
60 const char data[] = "c";
Colin Howesad6271a2018-11-21 15:36:05 -080061 if (!base::AppendToFile(file, data, sizeof(data)))
62 return false;
Greg Kerr019d59c2016-11-17 14:28:49 -080063
64 base::FilePath bad_component_dest =
65 temp_dir_.Append(component_name + "invalid");
Colin Howesad6271a2018-11-21 15:36:05 -080066 if (!base::CreateDirectory(bad_component_dest))
67 return false;
Greg Kerr019d59c2016-11-17 14:28:49 -080068
69 if (!base::SetPosixFilePermissions(bad_component_dest, kComponentDirPerms))
70 return false;
Eric Carusocbe1c5c2017-03-15 14:21:08 -070071 return bad_component->CopyTo(bad_component_dest) == false;
Greg Kerr019d59c2016-11-17 14:28:49 -080072 }
73
74 bool TestInitComponentWithCorruptFile(const std::string& component_name,
75 const std::string& file_name) {
76 base::FilePath bad_component_dir = temp_dir_.Append(component_name);
Colin Howesad6271a2018-11-21 15:36:05 -080077 if (!base::CreateDirectory(bad_component_dir))
78 return false;
Greg Kerr019d59c2016-11-17 14:28:49 -080079 if (!base::SetPosixFilePermissions(bad_component_dir, kComponentDirPerms))
80 return false;
81
Eric Carusocbe1c5c2017-03-15 14:21:08 -070082 std::unique_ptr<Component> component =
Eric Caruso0b79bc82017-03-21 13:44:34 -070083 Component::Create(GetTestComponentPath(), keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -070084 if (!component || !component->CopyTo(bad_component_dir))
Greg Kerr019d59c2016-11-17 14:28:49 -080085 return false;
86
87 base::FilePath file = bad_component_dir.Append(file_name);
88 // Read the file out and change the last byte.
89 std::string file_contents;
Colin Howesad6271a2018-11-21 15:36:05 -080090 if (!base::ReadFileToString(file, &file_contents))
91 return false;
Greg Kerr019d59c2016-11-17 14:28:49 -080092 file_contents[file_contents.size() - 1] =
93 ~file_contents[file_contents.size() - 1];
94
95 if (!base::WriteFile(file, file_contents.data(), file_contents.size())) {
96 return false;
97 }
98
Eric Carusocbe1c5c2017-03-15 14:21:08 -070099 std::unique_ptr<Component> bad_component =
Eric Caruso0b79bc82017-03-21 13:44:34 -0700100 Component::Create(bad_component_dir, keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700101 return bad_component == nullptr;
Greg Kerr019d59c2016-11-17 14:28:49 -0800102 }
103
104 bool CompareFileContents(const base::FilePath& src,
105 const base::FilePath& dest,
106 const std::list<std::string>& filenames) {
107 for (const std::string& name : filenames) {
108 std::string source_file_contents;
109 std::string dest_file_contents;
110 if (!base::ReadFileToString(src.Append(name), &source_file_contents))
111 return false;
112 if (!base::ReadFileToString(dest.Append(name), &dest_file_contents))
113 return false;
114 if (source_file_contents != dest_file_contents) {
115 LOG(ERROR) << "File contents does not match for file: " << name;
116 return false;
117 }
118 }
119 return true;
120 }
121
Eric Caruso0b79bc82017-03-21 13:44:34 -0700122 Keys keys_;
Greg Kerr019d59c2016-11-17 14:28:49 -0800123 base::ScopedTempDir scoped_temp_dir_;
124 base::FilePath temp_dir_;
125};
126
127TEST_F(ComponentTest, InitComponentAndCheckManifest) {
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700128 std::unique_ptr<Component> component =
Eric Caruso0b79bc82017-03-21 13:44:34 -0700129 Component::Create(GetTestComponentPath(), keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700130 ASSERT_NE(nullptr, component);
131
Xiaochu Liuc209aab2018-06-19 13:42:15 -0700132 EXPECT_EQ(1, component->manifest().manifest_version());
133 EXPECT_EQ(kTestDataVersion, component->manifest().version());
Greg Kerr019d59c2016-11-17 14:28:49 -0800134 // Don't hardcode the sha256 hashes, but run some sanity checks.
Xiaochu Liuc209aab2018-06-19 13:42:15 -0700135 EXPECT_EQ(crypto::kSHA256Length, component->manifest().image_sha256().size());
136 EXPECT_EQ(crypto::kSHA256Length, component->manifest().table_sha256().size());
137 EXPECT_NE(component->manifest().image_sha256(),
138 component->manifest().table_sha256());
Greg Kerr019d59c2016-11-17 14:28:49 -0800139}
140
Xiaochu Liuc2264342017-08-14 16:37:42 -0700141TEST_F(ComponentTest, TestCopyAndMountComponentExt4) {
142 std::unique_ptr<Component> component =
143 Component::Create(GetTestDataPath("ext4_component"), keys_);
144 ASSERT_NE(nullptr, component);
145
146 const base::FilePath copied_dir = temp_dir_.Append("dest");
147 ASSERT_TRUE(base::CreateDirectory(copied_dir));
148 ASSERT_TRUE(base::SetPosixFilePermissions(copied_dir, kComponentDirPerms));
149
150 ASSERT_TRUE(component->CopyTo(copied_dir));
151
152 std::unique_ptr<Component> copied_component =
153 Component::Create(copied_dir, keys_);
154 ASSERT_NE(nullptr, copied_component);
155
156 const base::FilePath mount_dir = temp_dir_.Append("mount");
157 ASSERT_TRUE(base::CreateDirectory(copied_dir));
158 ASSERT_TRUE(base::SetPosixFilePermissions(copied_dir, kComponentDirPerms));
159
160 // Note: this fails to test the actual mounting process since it is just a
161 // mock here. The platform_ImageLoader autotest tests the real helper
162 // process running as a dbus service.
Greg Kerr09f06de2018-02-16 15:32:07 -0800163 auto helper_mock = std::make_unique<MockHelperProcessProxy>();
Xiaochu Liue61e1d62018-11-12 13:20:09 -0800164 EXPECT_CALL(*helper_mock, SendMountCommand(_, _, FileSystem::kExt4, _))
Xiaochu Liuc2264342017-08-14 16:37:42 -0700165 .Times(1);
166 ON_CALL(*helper_mock, SendMountCommand(_, _, _, _))
167 .WillByDefault(testing::Return(true));
168 ASSERT_TRUE(copied_component->Mount(helper_mock.get(), mount_dir));
169}
170
171TEST_F(ComponentTest, TestCopyAndMountComponentSquashfs) {
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700172 std::unique_ptr<Component> component =
Eric Caruso0b79bc82017-03-21 13:44:34 -0700173 Component::Create(GetTestComponentPath(), keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700174 ASSERT_NE(nullptr, component);
Greg Kerr019d59c2016-11-17 14:28:49 -0800175
176 const base::FilePath copied_dir = temp_dir_.Append("dest");
177 ASSERT_TRUE(base::CreateDirectory(copied_dir));
178 ASSERT_TRUE(base::SetPosixFilePermissions(copied_dir, kComponentDirPerms));
179
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700180 ASSERT_TRUE(component->CopyTo(copied_dir));
Greg Kerr019d59c2016-11-17 14:28:49 -0800181
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700182 std::unique_ptr<Component> copied_component =
Eric Caruso0b79bc82017-03-21 13:44:34 -0700183 Component::Create(copied_dir, keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700184 ASSERT_NE(nullptr, copied_component);
Greg Kerr019d59c2016-11-17 14:28:49 -0800185
186 const base::FilePath mount_dir = temp_dir_.Append("mount");
187 ASSERT_TRUE(base::CreateDirectory(copied_dir));
188 ASSERT_TRUE(base::SetPosixFilePermissions(copied_dir, kComponentDirPerms));
189
Greg Kerr9944e242017-01-26 15:09:31 -0800190 // Note: this fails to test the actual mounting process since it is just a
191 // mock here. The platform_ImageLoader autotest tests the real helper
192 // process running as a dbus service.
Greg Kerr09f06de2018-02-16 15:32:07 -0800193 auto helper_mock = std::make_unique<MockHelperProcessProxy>();
Xiaochu Liue61e1d62018-11-12 13:20:09 -0800194 EXPECT_CALL(*helper_mock, SendMountCommand(_, _, FileSystem::kSquashFS, _))
Xiaochu Liuc2264342017-08-14 16:37:42 -0700195 .Times(1);
196 ON_CALL(*helper_mock, SendMountCommand(_, _, _, _))
Greg Kerr9944e242017-01-26 15:09:31 -0800197 .WillByDefault(testing::Return(true));
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700198 ASSERT_TRUE(copied_component->Mount(helper_mock.get(), mount_dir));
Greg Kerr019d59c2016-11-17 14:28:49 -0800199}
200
201TEST_F(ComponentTest, CheckFilesAfterCopy) {
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700202 std::unique_ptr<Component> component =
Eric Caruso0b79bc82017-03-21 13:44:34 -0700203 Component::Create(GetTestComponentPath(), keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700204 ASSERT_NE(nullptr, component);
Greg Kerr019d59c2016-11-17 14:28:49 -0800205
206 const base::FilePath copied_dir = temp_dir_.Append("dest");
207 ASSERT_TRUE(base::CreateDirectory(copied_dir));
208 ASSERT_TRUE(base::SetPosixFilePermissions(copied_dir, kComponentDirPerms));
209
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700210 ASSERT_TRUE(component->CopyTo(copied_dir));
Greg Kerr019d59c2016-11-17 14:28:49 -0800211
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700212 std::unique_ptr<Component> copied_component =
Eric Caruso0b79bc82017-03-21 13:44:34 -0700213 Component::Create(copied_dir, keys_);
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700214 ASSERT_NE(nullptr, copied_component);
Greg Kerr019d59c2016-11-17 14:28:49 -0800215
216 // Check that all the files are present, except for the manifest.json which
217 // should be discarded.
218 std::list<std::string> original_files;
219 std::list<std::string> copied_files;
220 GetFilesInDir(GetTestComponentPath(), &original_files);
221 GetFilesInDir(copied_dir, &copied_files);
222
223 EXPECT_THAT(original_files,
224 testing::UnorderedElementsAre(
225 "imageloader.json", "imageloader.sig.1", "manifest.json",
226 "table", "image.squash", "manifest.fingerprint"));
227 ASSERT_THAT(copied_files,
228 testing::UnorderedElementsAre(
229 "imageloader.json", "imageloader.sig.1", "table",
230 "image.squash", "manifest.fingerprint"));
231 EXPECT_TRUE(
232 CompareFileContents(GetTestComponentPath(), copied_dir, copied_files));
233}
234
235TEST_F(ComponentTest, IsValidFingerprintFile) {
Greg Kerr019d59c2016-11-17 14:28:49 -0800236 const std::string valid_manifest =
237 "1.3464353b1ed78574e05f3ffe84b52582572b2fe7202f3824a3761e54ace8bb1";
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700238 EXPECT_TRUE(Component::IsValidFingerprintFile(valid_manifest));
Greg Kerr019d59c2016-11-17 14:28:49 -0800239
240 const std::string invalid_unicode_manifest = "Ё Ђ Ѓ Є Ѕ І Ї Ј Љ ";
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700241 EXPECT_FALSE(Component::IsValidFingerprintFile(invalid_unicode_manifest));
Greg Kerr019d59c2016-11-17 14:28:49 -0800242
Eric Carusocbe1c5c2017-03-15 14:21:08 -0700243 EXPECT_FALSE(Component::IsValidFingerprintFile("\x49\x34\x19-43.*+abc"));
Greg Kerr019d59c2016-11-17 14:28:49 -0800244}
245
246TEST_F(ComponentTest, InitComponentWithBadFiles) {
247 EXPECT_TRUE(
248 TestInitComponentWithCorruptFile("bad-component1", "imageloader.json"));
249 EXPECT_TRUE(
250 TestInitComponentWithCorruptFile("bad-component2", "imageloader.sig.1"));
251}
252
253// Now corrupt the manifest of an already initialized component to verify that
254// the copy operation fails.
255TEST_F(ComponentTest, CopyWithBadFiles) {
256 EXPECT_TRUE(TestCopyWithCorruptFile("bad-component1", "image.squash"));
257 EXPECT_TRUE(TestCopyWithCorruptFile("bad-component2", "table"));
258 EXPECT_TRUE(
259 TestCopyWithCorruptFile("bad-component3", "manifest.fingerprint"));
260}
261
262TEST_F(ComponentTest, CopyValidImage) {
263 const int image_size = 4096 * 4;
264
265 base::FilePath image_path = temp_dir_.Append("image");
266 std::vector<char> image(image_size,
267 0xBB); // large enough to test streaming read.
268 ASSERT_EQ(image_size,
269 base::WriteFile(image_path, image.data(), image.size()));
270
271 std::vector<uint8_t> hash(crypto::kSHA256Length);
272
273 std::unique_ptr<crypto::SecureHash> sha256(
274 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
275 sha256->Update(image.data(), image.size());
276 sha256->Finish(hash.data(), hash.size());
277
Eric Caruso089bbff2017-03-21 11:34:15 -0700278 Component component(GetTestComponentPath(), 1);
Greg Kerr019d59c2016-11-17 14:28:49 -0800279 base::FilePath image_dest = temp_dir_.Append("image.copied");
280 ASSERT_TRUE(component.CopyComponentFile(image_path, image_dest, hash));
281
282 // Check if the image file actually exists and has the correct contents.
283 std::string resulting_image;
284 ASSERT_TRUE(base::ReadFileToStringWithMaxSize(image_dest, &resulting_image,
285 image_size));
286
Ben Chana92a9f02017-12-18 17:47:23 -0800287 EXPECT_EQ(0, memcmp(image.data(), resulting_image.data(), image_size));
Greg Kerr019d59c2016-11-17 14:28:49 -0800288}
289
290} // namespace imageloader