1 //
2 // Copyright (C) 2018 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_generator/boot_img_filesystem.h"
18
19 #include <vector>
20
21 #include <bootimg.h>
22 #include <brillo/secure_blob.h>
23 #include <gtest/gtest.h>
24
25 #include "update_engine/common/test_utils.h"
26 #include "update_engine/common/utils.h"
27
28 namespace chromeos_update_engine {
29
30 using std::unique_ptr;
31 using std::vector;
32
33 class BootImgFilesystemTest : public ::testing::Test {
34 protected:
GetBootImg(const brillo::Blob & kernel,const brillo::Blob & ramdisk,bool header_version3=false)35 brillo::Blob GetBootImg(const brillo::Blob& kernel,
36 const brillo::Blob& ramdisk,
37 bool header_version3 = false) {
38 brillo::Blob boot_img(16 * 1024);
39 constexpr uint32_t page_size = 4096;
40
41 size_t offset = 0;
42 if (header_version3) {
43 boot_img_hdr_v3 hdr_v3{};
44 memcpy(hdr_v3.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
45 hdr_v3.kernel_size = kernel.size();
46 hdr_v3.ramdisk_size = ramdisk.size();
47 hdr_v3.header_version = 3;
48 memcpy(boot_img.data() + offset, &hdr_v3, sizeof(hdr_v3));
49 offset += utils::RoundUp(sizeof(hdr_v3), page_size);
50 } else {
51 boot_img_hdr_v0 hdr_v0{};
52 memcpy(hdr_v0.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
53 hdr_v0.kernel_size = kernel.size();
54 hdr_v0.ramdisk_size = ramdisk.size();
55 hdr_v0.page_size = page_size;
56 hdr_v0.header_version = 0;
57 memcpy(boot_img.data() + offset, &hdr_v0, sizeof(hdr_v0));
58 offset += utils::RoundUp(sizeof(hdr_v0), page_size);
59 }
60 memcpy(boot_img.data() + offset, kernel.data(), kernel.size());
61 offset += utils::RoundUp(kernel.size(), page_size);
62 memcpy(boot_img.data() + offset, ramdisk.data(), ramdisk.size());
63 return boot_img;
64 }
65
66 ScopedTempFile boot_file_;
67 };
68
TEST_F(BootImgFilesystemTest,SimpleTest)69 TEST_F(BootImgFilesystemTest, SimpleTest) {
70 test_utils::WriteFileVector(
71 boot_file_.path(),
72 GetBootImg(brillo::Blob(1234, 'k'), brillo::Blob(5678, 'r')));
73 unique_ptr<BootImgFilesystem> fs =
74 BootImgFilesystem::CreateFromFile(boot_file_.path());
75 EXPECT_NE(nullptr, fs);
76
77 vector<FilesystemInterface::File> files;
78 EXPECT_TRUE(fs->GetFiles(&files));
79 ASSERT_EQ(2u, files.size());
80
81 EXPECT_EQ("<kernel>", files[0].name);
82 EXPECT_EQ(1u, files[0].extents.size());
83 EXPECT_EQ(1u, files[0].extents[0].start_block());
84 EXPECT_EQ(1u, files[0].extents[0].num_blocks());
85 EXPECT_TRUE(files[0].deflates.empty());
86
87 EXPECT_EQ("<ramdisk>", files[1].name);
88 EXPECT_EQ(1u, files[1].extents.size());
89 EXPECT_EQ(2u, files[1].extents[0].start_block());
90 EXPECT_EQ(2u, files[1].extents[0].num_blocks());
91 EXPECT_TRUE(files[1].deflates.empty());
92 }
93
TEST_F(BootImgFilesystemTest,ImageHeaderVersion3)94 TEST_F(BootImgFilesystemTest, ImageHeaderVersion3) {
95 test_utils::WriteFileVector(
96 boot_file_.path(),
97 GetBootImg(brillo::Blob(1000, 'k'), brillo::Blob(5000, 'r'), true));
98 unique_ptr<BootImgFilesystem> fs =
99 BootImgFilesystem::CreateFromFile(boot_file_.path());
100 EXPECT_NE(nullptr, fs);
101
102 vector<FilesystemInterface::File> files;
103 EXPECT_TRUE(fs->GetFiles(&files));
104 ASSERT_EQ(2u, files.size());
105
106 EXPECT_EQ("<kernel>", files[0].name);
107 EXPECT_EQ(1u, files[0].extents.size());
108 EXPECT_EQ(1u, files[0].extents[0].start_block());
109 EXPECT_EQ(1u, files[0].extents[0].num_blocks());
110 EXPECT_TRUE(files[0].deflates.empty());
111
112 EXPECT_EQ("<ramdisk>", files[1].name);
113 EXPECT_EQ(1u, files[1].extents.size());
114 EXPECT_EQ(2u, files[1].extents[0].start_block());
115 EXPECT_EQ(2u, files[1].extents[0].num_blocks());
116 EXPECT_TRUE(files[1].deflates.empty());
117 }
118
TEST_F(BootImgFilesystemTest,BadImageTest)119 TEST_F(BootImgFilesystemTest, BadImageTest) {
120 brillo::Blob boot_img = GetBootImg({}, {});
121 boot_img[7] = '?';
122 test_utils::WriteFileVector(boot_file_.path(), boot_img);
123 unique_ptr<BootImgFilesystem> fs =
124 BootImgFilesystem::CreateFromFile(boot_file_.path());
125 EXPECT_EQ(nullptr, fs);
126 }
127
TEST_F(BootImgFilesystemTest,GZipRamdiskTest)128 TEST_F(BootImgFilesystemTest, GZipRamdiskTest) {
129 // echo ramdisk | gzip | hexdump -v -e '/1 "0x%02x, "'
130 const brillo::Blob ramdisk = {0x1f, 0x8b, 0x08, 0x00, 0x3a, 0x83, 0x35,
131 0x5b, 0x00, 0x03, 0x2b, 0x4a, 0xcc, 0x4d,
132 0xc9, 0x2c, 0xce, 0xe6, 0x02, 0x00, 0x2e,
133 0xf6, 0x0b, 0x08, 0x08, 0x00, 0x00, 0x00};
134 test_utils::WriteFileVector(boot_file_.path(),
135 GetBootImg(brillo::Blob(5678, 'k'), ramdisk));
136 unique_ptr<BootImgFilesystem> fs =
137 BootImgFilesystem::CreateFromFile(boot_file_.path());
138 EXPECT_NE(nullptr, fs);
139
140 vector<FilesystemInterface::File> files;
141 EXPECT_TRUE(fs->GetFiles(&files));
142 ASSERT_EQ(2u, files.size());
143
144 EXPECT_EQ("<kernel>", files[0].name);
145 EXPECT_EQ(1u, files[0].extents.size());
146 EXPECT_EQ(1u, files[0].extents[0].start_block());
147 EXPECT_EQ(2u, files[0].extents[0].num_blocks());
148 EXPECT_TRUE(files[0].deflates.empty());
149
150 EXPECT_EQ("<ramdisk>", files[1].name);
151 EXPECT_EQ(1u, files[1].extents.size());
152 EXPECT_EQ(3u, files[1].extents[0].start_block());
153 EXPECT_EQ(1u, files[1].extents[0].num_blocks());
154 EXPECT_EQ(1u, files[1].deflates.size());
155 }
156
157 } // namespace chromeos_update_engine
158