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/payload_generation_config.h"
18
19 #include <brillo/secure_blob.h>
20 #include <gtest/gtest.h>
21
22 #include "update_engine/common/test_utils.h"
23 #include "update_engine/payload_generator/extent_ranges.h"
24 #include "update_engine/payload_generator/extent_utils.h"
25
26 namespace chromeos_update_engine {
27
28 namespace {
29 // dd if=/dev/zero of=part bs=4096 count=2
30 // avbtool add_hashtree_footer --image part --partition_size $((24 * 4096))
31 // --partition_name system
32 constexpr uint64_t kImageSize = 24 * 4096;
33
34 // hexdump -s $((2 * 4096)) -n 64 -v -e '/1 "0x%02x, "' part
35 constexpr uint64_t kHashTreeOffset = 2 * 4096;
36 const uint8_t kHashTree[] = {
37 0x62, 0x4b, 0x5a, 0x4d, 0xa2, 0x97, 0xa0, 0xc8, 0x08, 0x03, 0xa6,
38 0x95, 0x4c, 0x4c, 0x7a, 0x2d, 0xac, 0x50, 0xde, 0x74, 0x00, 0x00,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62,
40 0x4b, 0x5a, 0x4d, 0xa2, 0x97, 0xa0, 0xc8, 0x08, 0x03, 0xa6, 0x95,
41 0x4c, 0x4c, 0x7a, 0x2d, 0xac, 0x50, 0xde, 0x74, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
43
44 // hexdump -s $((3 * 4096)) -n 128 -v -e '/1 "0x%02x, "' part
45 constexpr uint64_t kFECOffset = 3 * 4096;
46 const uint8_t kFEC[] = {
47 0xec, 0x8e, 0x93, 0xd8, 0xf9, 0xa3, 0xd6, 0x9b, 0xa4, 0x06, 0x5f, 0xc8,
48 0x6c, 0xcc, 0x4f, 0x87, 0x07, 0x0f, 0xac, 0xaf, 0x29, 0x8f, 0x97, 0x02,
49 0xb2, 0xfe, 0xb2, 0xfe, 0xe5, 0x9f, 0xf2, 0xdf, 0xe6, 0x4a, 0x36, 0x66,
50 0x04, 0xda, 0xa7, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0xec, 0x8e, 0x93, 0xd8, 0xf9, 0xa3, 0xd6, 0x9b,
53 0xa4, 0x06, 0x5f, 0xc8, 0x6c, 0xcc, 0x4f, 0x87, 0x07, 0x0f, 0xac, 0xaf,
54 0x29, 0x8f, 0x97, 0x02, 0xb2, 0xfe, 0xb2, 0xfe, 0xe5, 0x9f, 0xf2, 0xdf,
55 0xe6, 0x4a, 0x36, 0x66, 0x04, 0xda, 0xa7, 0xd3, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
58
59 // hexdump -s $((5 * 4096)) -n 512 -v -e '/1 "0x%02x, "' part
60 constexpr uint64_t kVBMetaImageOffset = 5 * 4096;
61 const uint8_t kVBMetaImage[] = {
62 0x41, 0x56, 0x42, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x76, 0x62, 0x74,
73 0x6f, 0x6f, 0x6c, 0x20, 0x31, 0x2e, 0x31, 0x2e, 0x30, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x01,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
87 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x20, 0x00, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x1f, 0xab,
99 0x7a, 0x6b, 0xf6, 0xb1, 0x3a, 0x1f, 0xdb, 0x34, 0xa3, 0xfc, 0xc8, 0x73,
100 0x0b, 0x23, 0x61, 0xb3, 0x04, 0xe2, 0x4f, 0x6c, 0xd0, 0x1e, 0x39, 0x9d,
101 0xaa, 0x73, 0x35, 0x53, 0xa7, 0x74, 0x1f, 0x81, 0xd0, 0xa6, 0xa9, 0x5f,
102 0x19, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
105
106 // hexdump -s $((24 * 4096 - 64)) -n 64 -v -e '/1 "0x%02x, "' part
107 constexpr uint64_t kAVBFooterOffset = 24 * 4096 - 64;
108 const uint8_t kAVBFooter[] = {
109 0x41, 0x56, 0x42, 0x66, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
115
116 // avbtool info_image --image part | grep Salt | cut -d':' -f 2 | xxd -r -p |
117 // hexdump -v -e '/1 "0x%02x, "'
118 const uint8_t kHashTreeSalt[] = {0x1f, 0xab, 0x7a, 0x6b, 0xf6, 0xb1, 0x3a,
119 0x1f, 0xdb, 0x34, 0xa3, 0xfc, 0xc8, 0x73,
120 0x0b, 0x23, 0x61, 0xb3, 0x04, 0xe2};
121
GetAVBPartition()122 brillo::Blob GetAVBPartition() {
123 brillo::Blob part(kImageSize);
124 memcpy(part.data() + kHashTreeOffset, kHashTree, sizeof(kHashTree));
125 memcpy(part.data() + kFECOffset, kFEC, sizeof(kFEC));
126 memcpy(part.data() + kVBMetaImageOffset, kVBMetaImage, sizeof(kVBMetaImage));
127 memcpy(part.data() + kAVBFooterOffset, kAVBFooter, sizeof(kAVBFooter));
128 return part;
129 }
130
131 } // namespace
132
133 class PayloadGenerationConfigAndroidTest : public ::testing::Test {
134 protected:
SetUp()135 void SetUp() override {
136 image_config_.partitions.emplace_back("system");
137 image_config_.partitions[0].path = temp_file_.path();
138 }
139
140 ImageConfig image_config_;
141 ScopedTempFile temp_file_{"PayloadGenerationConfigAndroidTest.XXXXXX"};
142 };
143
TEST_F(PayloadGenerationConfigAndroidTest,LoadVerityConfigSimpleTest)144 TEST_F(PayloadGenerationConfigAndroidTest, LoadVerityConfigSimpleTest) {
145 brillo::Blob part = GetAVBPartition();
146 test_utils::WriteFileVector(temp_file_.path(), part);
147 EXPECT_TRUE(image_config_.LoadImageSize());
148 EXPECT_TRUE(image_config_.partitions[0].OpenFilesystem());
149 EXPECT_TRUE(image_config_.LoadVerityConfig());
150 const VerityConfig& verity = image_config_.partitions[0].verity;
151 EXPECT_FALSE(verity.IsEmpty());
152 EXPECT_EQ(ExtentForRange(0, 2), verity.hash_tree_data_extent);
153 EXPECT_EQ(ExtentForRange(2, 1), verity.hash_tree_extent);
154 EXPECT_EQ("sha1", verity.hash_tree_algorithm);
155 brillo::Blob salt(kHashTreeSalt, std::end(kHashTreeSalt));
156 EXPECT_EQ(salt, verity.hash_tree_salt);
157 EXPECT_EQ(ExtentForRange(0, 3), verity.fec_data_extent);
158 EXPECT_EQ(ExtentForRange(3, 2), verity.fec_extent);
159 EXPECT_EQ(2u, verity.fec_roots);
160 }
161
TEST_F(PayloadGenerationConfigAndroidTest,LoadVerityConfigDisableFecTest)162 TEST_F(PayloadGenerationConfigAndroidTest, LoadVerityConfigDisableFecTest) {
163 brillo::Blob part = GetAVBPartition();
164 test_utils::WriteFileVector(temp_file_.path(), part);
165 image_config_.partitions[0].disable_fec_computation = true;
166 EXPECT_TRUE(image_config_.LoadImageSize());
167 EXPECT_TRUE(image_config_.partitions[0].OpenFilesystem());
168 EXPECT_TRUE(image_config_.LoadVerityConfig());
169 const VerityConfig& verity = image_config_.partitions[0].verity;
170 EXPECT_FALSE(verity.IsEmpty());
171 EXPECT_EQ(ExtentForRange(0, 2), verity.hash_tree_data_extent);
172 EXPECT_EQ(ExtentForRange(2, 1), verity.hash_tree_extent);
173 EXPECT_EQ("sha1", verity.hash_tree_algorithm);
174 brillo::Blob salt(kHashTreeSalt, std::end(kHashTreeSalt));
175 EXPECT_EQ(salt, verity.hash_tree_salt);
176 EXPECT_EQ(0u, verity.fec_data_extent.num_blocks());
177 EXPECT_EQ(0u, verity.fec_extent.num_blocks());
178 }
179
TEST_F(PayloadGenerationConfigAndroidTest,LoadVerityConfigInvalidHashTreeTest)180 TEST_F(PayloadGenerationConfigAndroidTest,
181 LoadVerityConfigInvalidHashTreeTest) {
182 brillo::Blob part = GetAVBPartition();
183 part[kHashTreeOffset] ^= 1; // flip one bit
184 test_utils::WriteFileVector(temp_file_.path(), part);
185 EXPECT_TRUE(image_config_.LoadImageSize());
186 EXPECT_TRUE(image_config_.partitions[0].OpenFilesystem());
187 EXPECT_FALSE(image_config_.LoadVerityConfig());
188 }
189
TEST_F(PayloadGenerationConfigAndroidTest,LoadVerityConfigInvalidFECTest)190 TEST_F(PayloadGenerationConfigAndroidTest, LoadVerityConfigInvalidFECTest) {
191 brillo::Blob part = GetAVBPartition();
192 part[kFECOffset] ^= 1; // flip one bit
193 test_utils::WriteFileVector(temp_file_.path(), part);
194 EXPECT_TRUE(image_config_.LoadImageSize());
195 EXPECT_TRUE(image_config_.partitions[0].OpenFilesystem());
196 EXPECT_FALSE(image_config_.LoadVerityConfig());
197 }
198
TEST_F(PayloadGenerationConfigAndroidTest,LoadVerityConfigEmptyImageTest)199 TEST_F(PayloadGenerationConfigAndroidTest, LoadVerityConfigEmptyImageTest) {
200 brillo::Blob part(kImageSize);
201 test_utils::WriteFileVector(temp_file_.path(), part);
202 EXPECT_TRUE(image_config_.LoadImageSize());
203 EXPECT_TRUE(image_config_.LoadVerityConfig());
204 EXPECT_TRUE(image_config_.partitions[0].verity.IsEmpty());
205 }
206
TEST_F(PayloadGenerationConfigAndroidTest,LoadVerityConfigTinyImageTest)207 TEST_F(PayloadGenerationConfigAndroidTest, LoadVerityConfigTinyImageTest) {
208 test_utils::WriteFileString(temp_file_.path(), "tiny");
209 EXPECT_TRUE(image_config_.LoadImageSize());
210 EXPECT_TRUE(image_config_.LoadVerityConfig());
211 EXPECT_TRUE(image_config_.partitions[0].verity.IsEmpty());
212 }
213
214 } // namespace chromeos_update_engine
215