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