xref: /aosp_15_r20/system/extras/libfec/test/fec_unittest.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <stdint.h>
18*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
19*288bf522SAndroid Build Coastguard Worker 
20*288bf522SAndroid Build Coastguard Worker #include <string>
21*288bf522SAndroid Build Coastguard Worker #include <vector>
22*288bf522SAndroid Build Coastguard Worker 
23*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
24*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
25*288bf522SAndroid Build Coastguard Worker #include <gtest/gtest.h>
26*288bf522SAndroid Build Coastguard Worker #include <verity/hash_tree_builder.h>
27*288bf522SAndroid Build Coastguard Worker 
28*288bf522SAndroid Build Coastguard Worker #include "../fec_private.h"
29*288bf522SAndroid Build Coastguard Worker #include "fec/io.h"
30*288bf522SAndroid Build Coastguard Worker 
31*288bf522SAndroid Build Coastguard Worker class FecUnitTest : public ::testing::Test {
32*288bf522SAndroid Build Coastguard Worker    protected:
SetUp()33*288bf522SAndroid Build Coastguard Worker     void SetUp() override {
34*288bf522SAndroid Build Coastguard Worker         // Construct a 1 MiB image as file system.
35*288bf522SAndroid Build Coastguard Worker         image_.reserve(1024 * 1024);
36*288bf522SAndroid Build Coastguard Worker         for (unsigned i = 0; i <= 255; i++) {
37*288bf522SAndroid Build Coastguard Worker             std::vector<uint8_t> tmp_vec(4096, i);
38*288bf522SAndroid Build Coastguard Worker             image_.insert(image_.end(), tmp_vec.begin(), tmp_vec.end());
39*288bf522SAndroid Build Coastguard Worker         }
40*288bf522SAndroid Build Coastguard Worker     }
BuildHashtree(const std::string & hash_name)41*288bf522SAndroid Build Coastguard Worker     void BuildHashtree(const std::string &hash_name) {
42*288bf522SAndroid Build Coastguard Worker         // Build the hashtree.
43*288bf522SAndroid Build Coastguard Worker         HashTreeBuilder builder(4096, HashTreeBuilder::HashFunction(hash_name));
44*288bf522SAndroid Build Coastguard Worker         // Use a random salt.
45*288bf522SAndroid Build Coastguard Worker         salt_ = std::vector<uint8_t>(64, 10);
46*288bf522SAndroid Build Coastguard Worker         ASSERT_TRUE(builder.Initialize(image_.size(), salt_));
47*288bf522SAndroid Build Coastguard Worker         ASSERT_TRUE(builder.Update(image_.data(), image_.size()));
48*288bf522SAndroid Build Coastguard Worker         ASSERT_TRUE(builder.BuildHashTree());
49*288bf522SAndroid Build Coastguard Worker         root_hash_ = builder.root_hash();
50*288bf522SAndroid Build Coastguard Worker 
51*288bf522SAndroid Build Coastguard Worker         TemporaryFile temp_file;
52*288bf522SAndroid Build Coastguard Worker         ASSERT_TRUE(builder.WriteHashTreeToFd(temp_file.fd, 0));
53*288bf522SAndroid Build Coastguard Worker         android::base::ReadFileToString(temp_file.path, &hashtree_content_);
54*288bf522SAndroid Build Coastguard Worker     }
55*288bf522SAndroid Build Coastguard Worker 
56*288bf522SAndroid Build Coastguard Worker     // Builds the verity metadata and appends the bytes to the image.
BuildAndAppendsVerityMetadata()57*288bf522SAndroid Build Coastguard Worker     void BuildAndAppendsVerityMetadata() {
58*288bf522SAndroid Build Coastguard Worker         BuildHashtree("sha256");
59*288bf522SAndroid Build Coastguard Worker         // Append the hashtree to the end of image.
60*288bf522SAndroid Build Coastguard Worker         image_.insert(image_.end(), hashtree_content_.begin(),
61*288bf522SAndroid Build Coastguard Worker                       hashtree_content_.end());
62*288bf522SAndroid Build Coastguard Worker 
63*288bf522SAndroid Build Coastguard Worker         // The metadata table has the format: "1 block_device, block_device,
64*288bf522SAndroid Build Coastguard Worker         // BLOCK_SIZE, BLOCK_SIZE, data_blocks, data_blocks, 'sha256',
65*288bf522SAndroid Build Coastguard Worker         // root_hash, salt".
66*288bf522SAndroid Build Coastguard Worker         std::vector<std::string> table = {
67*288bf522SAndroid Build Coastguard Worker             "1",
68*288bf522SAndroid Build Coastguard Worker             "fake_block_device",
69*288bf522SAndroid Build Coastguard Worker             "fake_block_device",
70*288bf522SAndroid Build Coastguard Worker             "4096",
71*288bf522SAndroid Build Coastguard Worker             "4096",
72*288bf522SAndroid Build Coastguard Worker             "256",
73*288bf522SAndroid Build Coastguard Worker             "256",
74*288bf522SAndroid Build Coastguard Worker             "sha256",
75*288bf522SAndroid Build Coastguard Worker             HashTreeBuilder::BytesArrayToString(root_hash_),
76*288bf522SAndroid Build Coastguard Worker             HashTreeBuilder::BytesArrayToString(salt_),
77*288bf522SAndroid Build Coastguard Worker         };
78*288bf522SAndroid Build Coastguard Worker         verity_table_ = android::base::Join(table, ' ');
79*288bf522SAndroid Build Coastguard Worker 
80*288bf522SAndroid Build Coastguard Worker         verity_header_ = {
81*288bf522SAndroid Build Coastguard Worker             0xb001b001, 0, {}, static_cast<unsigned int>(verity_table_.size())
82*288bf522SAndroid Build Coastguard Worker         };
83*288bf522SAndroid Build Coastguard Worker 
84*288bf522SAndroid Build Coastguard Worker         // Construct the verity metadata with header, table, and padding.
85*288bf522SAndroid Build Coastguard Worker         constexpr auto VERITY_META_SIZE = 8 * 4096;
86*288bf522SAndroid Build Coastguard Worker         image_.insert(image_.end(),
87*288bf522SAndroid Build Coastguard Worker                       reinterpret_cast<uint8_t *>(&verity_header_),
88*288bf522SAndroid Build Coastguard Worker                       reinterpret_cast<uint8_t *>(&verity_header_) +
89*288bf522SAndroid Build Coastguard Worker                           sizeof(verity_header_));
90*288bf522SAndroid Build Coastguard Worker         image_.insert(image_.end(), verity_table_.data(),
91*288bf522SAndroid Build Coastguard Worker                       verity_table_.data() + verity_table_.size());
92*288bf522SAndroid Build Coastguard Worker         std::vector<uint8_t> padding(
93*288bf522SAndroid Build Coastguard Worker             VERITY_META_SIZE - sizeof(verity_header_) - verity_table_.size(),
94*288bf522SAndroid Build Coastguard Worker             0);
95*288bf522SAndroid Build Coastguard Worker         image_.insert(image_.end(), padding.begin(), padding.end());
96*288bf522SAndroid Build Coastguard Worker     }
97*288bf522SAndroid Build Coastguard Worker 
BuildAndAppendsEccImage(const std::string & image_name,const std::string & fec_name)98*288bf522SAndroid Build Coastguard Worker     static void BuildAndAppendsEccImage(const std::string &image_name,
99*288bf522SAndroid Build Coastguard Worker                                         const std::string &fec_name) {
100*288bf522SAndroid Build Coastguard Worker         std::vector<std::string> cmd = { "fec", "--encode", "--roots",
101*288bf522SAndroid Build Coastguard Worker                                          "2",   image_name, fec_name };
102*288bf522SAndroid Build Coastguard Worker         ASSERT_EQ(0, std::system(android::base::Join(cmd, ' ').c_str()));
103*288bf522SAndroid Build Coastguard Worker     }
104*288bf522SAndroid Build Coastguard Worker 
AddAvbHashtreeFooter(const std::string & image_name,std::string algorithm="sha256")105*288bf522SAndroid Build Coastguard Worker     void AddAvbHashtreeFooter(const std::string &image_name,
106*288bf522SAndroid Build Coastguard Worker                               std::string algorithm = "sha256") {
107*288bf522SAndroid Build Coastguard Worker         salt_ = std::vector<uint8_t>(64, 10);
108*288bf522SAndroid Build Coastguard Worker         std::vector<std::string> cmd = {
109*288bf522SAndroid Build Coastguard Worker             "avbtool",          "add_hashtree_footer",
110*288bf522SAndroid Build Coastguard Worker             "--salt",           HashTreeBuilder::BytesArrayToString(salt_),
111*288bf522SAndroid Build Coastguard Worker             "--hash_algorithm", algorithm,
112*288bf522SAndroid Build Coastguard Worker             "--image",          image_name,
113*288bf522SAndroid Build Coastguard Worker         };
114*288bf522SAndroid Build Coastguard Worker         ASSERT_EQ(0, std::system(android::base::Join(cmd, ' ').c_str()));
115*288bf522SAndroid Build Coastguard Worker 
116*288bf522SAndroid Build Coastguard Worker         BuildHashtree(algorithm);
117*288bf522SAndroid Build Coastguard Worker     }
118*288bf522SAndroid Build Coastguard Worker 
119*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> image_;
120*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> salt_;
121*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> root_hash_;
122*288bf522SAndroid Build Coastguard Worker     std::string hashtree_content_;
123*288bf522SAndroid Build Coastguard Worker     verity_header verity_header_;
124*288bf522SAndroid Build Coastguard Worker     std::string verity_table_;
125*288bf522SAndroid Build Coastguard Worker };
126*288bf522SAndroid Build Coastguard Worker 
TEST_F(FecUnitTest,LoadVerityImage_ParseVerity)127*288bf522SAndroid Build Coastguard Worker TEST_F(FecUnitTest, LoadVerityImage_ParseVerity) {
128*288bf522SAndroid Build Coastguard Worker     TemporaryFile verity_image;
129*288bf522SAndroid Build Coastguard Worker     BuildAndAppendsVerityMetadata();
130*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteFully(verity_image.fd, image_.data(),
131*288bf522SAndroid Build Coastguard Worker                                           image_.size()));
132*288bf522SAndroid Build Coastguard Worker 
133*288bf522SAndroid Build Coastguard Worker     struct fec_handle *handle = nullptr;
134*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_open(&handle, verity_image.path, O_RDONLY, FEC_FS_EXT4, 2));
135*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<fec_handle> guard(handle);
136*288bf522SAndroid Build Coastguard Worker 
137*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(image_.size(), handle->size);
138*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024, handle->data_size);  // filesystem size
139*288bf522SAndroid Build Coastguard Worker 
140*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024 + hashtree_content_.size(),
141*288bf522SAndroid Build Coastguard Worker               handle->verity.metadata_start);
142*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(verity_header_.length, handle->verity.header.length);
143*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(verity_table_, handle->verity.table);
144*288bf522SAndroid Build Coastguard Worker 
145*288bf522SAndroid Build Coastguard Worker     // check the hashtree.
146*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(salt_, handle->hashtree().salt);
147*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024, handle->hashtree().hash_start);
148*288bf522SAndroid Build Coastguard Worker     // the fec hashtree only stores the hash of the lowest level.
149*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(std::vector<uint8_t>(hashtree_content_.begin() + 4096,
150*288bf522SAndroid Build Coastguard Worker                                    hashtree_content_.end()),
151*288bf522SAndroid Build Coastguard Worker               handle->hashtree().hash_data);
152*288bf522SAndroid Build Coastguard Worker 
153*288bf522SAndroid Build Coastguard Worker     uint64_t hash_size =
154*288bf522SAndroid Build Coastguard Worker         verity_get_size(handle->hashtree().data_blocks * FEC_BLOCKSIZE, nullptr,
155*288bf522SAndroid Build Coastguard Worker                         nullptr, SHA256_DIGEST_LENGTH);
156*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(hashtree_content_.size(), hash_size);
157*288bf522SAndroid Build Coastguard Worker }
158*288bf522SAndroid Build Coastguard Worker 
TEST_F(FecUnitTest,LoadVerityImage_ParseEcc)159*288bf522SAndroid Build Coastguard Worker TEST_F(FecUnitTest, LoadVerityImage_ParseEcc) {
160*288bf522SAndroid Build Coastguard Worker     TemporaryFile verity_image;
161*288bf522SAndroid Build Coastguard Worker     BuildAndAppendsVerityMetadata();
162*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteFully(verity_image.fd, image_.data(),
163*288bf522SAndroid Build Coastguard Worker                                           image_.size()));
164*288bf522SAndroid Build Coastguard Worker     TemporaryFile ecc_image;
165*288bf522SAndroid Build Coastguard Worker     BuildAndAppendsEccImage(verity_image.path, ecc_image.path);
166*288bf522SAndroid Build Coastguard Worker     std::string ecc_content;
167*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::ReadFileToString(ecc_image.path, &ecc_content));
168*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteStringToFd(ecc_content, verity_image.fd));
169*288bf522SAndroid Build Coastguard Worker     struct fec_handle *handle = nullptr;
170*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_open(&handle, verity_image.path, O_RDONLY, FEC_FS_EXT4, 2));
171*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<fec_handle> guard(handle);
172*288bf522SAndroid Build Coastguard Worker 
173*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024, handle->data_size);  // filesystem size
174*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024 + hashtree_content_.size(),
175*288bf522SAndroid Build Coastguard Worker               handle->verity.metadata_start);
176*288bf522SAndroid Build Coastguard Worker 
177*288bf522SAndroid Build Coastguard Worker     fec_verity_metadata verity_metadata{};
178*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_verity_get_metadata(handle, &verity_metadata));
179*288bf522SAndroid Build Coastguard Worker     ASSERT_FALSE(verity_metadata.disabled);
180*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024, verity_metadata.data_size);
181*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(verity_table_, verity_metadata.table);
182*288bf522SAndroid Build Coastguard Worker 
183*288bf522SAndroid Build Coastguard Worker     fec_ecc_metadata ecc_metadata{};
184*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_ecc_get_metadata(handle, &ecc_metadata));
185*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(ecc_metadata.valid);
186*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(handle->verity.metadata_start + 8 * 4096, ecc_metadata.start);
187*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(2, ecc_metadata.roots);
188*288bf522SAndroid Build Coastguard Worker     // 256 (data) + 3 (hashtree) + 8 (verity meta)
189*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(267, ecc_metadata.blocks);
190*288bf522SAndroid Build Coastguard Worker }
191*288bf522SAndroid Build Coastguard Worker 
TEST_F(FecUnitTest,VerityImage_FecRead)192*288bf522SAndroid Build Coastguard Worker TEST_F(FecUnitTest, VerityImage_FecRead) {
193*288bf522SAndroid Build Coastguard Worker     TemporaryFile verity_image;
194*288bf522SAndroid Build Coastguard Worker     BuildAndAppendsVerityMetadata();
195*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteFully(verity_image.fd, image_.data(),
196*288bf522SAndroid Build Coastguard Worker                                           image_.size()));
197*288bf522SAndroid Build Coastguard Worker     TemporaryFile ecc_image;
198*288bf522SAndroid Build Coastguard Worker     BuildAndAppendsEccImage(verity_image.path, ecc_image.path);
199*288bf522SAndroid Build Coastguard Worker     std::string ecc_content;
200*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::ReadFileToString(ecc_image.path, &ecc_content));
201*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteStringToFd(ecc_content, verity_image.fd));
202*288bf522SAndroid Build Coastguard Worker 
203*288bf522SAndroid Build Coastguard Worker     // Corrupt the last block
204*288bf522SAndroid Build Coastguard Worker     uint64_t corrupt_offset = 4096 * 255;
205*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(corrupt_offset, lseek64(verity_image.fd, corrupt_offset, 0));
206*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> corruption(100, 10);
207*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteFully(verity_image.fd, corruption.data(),
208*288bf522SAndroid Build Coastguard Worker                                           corruption.size()));
209*288bf522SAndroid Build Coastguard Worker 
210*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> read_data(1024, 0);
211*288bf522SAndroid Build Coastguard Worker     struct fec_handle *handle = nullptr;
212*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0,
213*288bf522SAndroid Build Coastguard Worker               fec_open(&handle, verity_image.path, O_RDONLY, FEC_FS_EXT4, 2));
214*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<fec_handle> guard(handle);
215*288bf522SAndroid Build Coastguard Worker 
216*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024, fec_pread(handle, read_data.data(), 1024, corrupt_offset));
217*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(std::vector<uint8_t>(1024, 255), read_data);
218*288bf522SAndroid Build Coastguard Worker 
219*288bf522SAndroid Build Coastguard Worker     // Unaligned read that spans two blocks
220*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(678, fec_pread(handle, read_data.data(), 678, corrupt_offset - 123));
221*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(std::vector<uint8_t>(123, 254),
222*288bf522SAndroid Build Coastguard Worker               std::vector<uint8_t>(read_data.begin(), read_data.begin() + 123));
223*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(std::vector<uint8_t>(555, 255),
224*288bf522SAndroid Build Coastguard Worker               std::vector<uint8_t>(read_data.begin() + 123, read_data.begin() + 678));
225*288bf522SAndroid Build Coastguard Worker 
226*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> large_data(53388, 0);
227*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(53388, fec_pread(handle, large_data.data(), 53388, 385132));
228*288bf522SAndroid Build Coastguard Worker }
229*288bf522SAndroid Build Coastguard Worker 
TEST_F(FecUnitTest,LoadAvbImage_HashtreeFooter)230*288bf522SAndroid Build Coastguard Worker TEST_F(FecUnitTest, LoadAvbImage_HashtreeFooter) {
231*288bf522SAndroid Build Coastguard Worker     TemporaryFile avb_image;
232*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(
233*288bf522SAndroid Build Coastguard Worker         android::base::WriteFully(avb_image.fd, image_.data(), image_.size()));
234*288bf522SAndroid Build Coastguard Worker     AddAvbHashtreeFooter(avb_image.path);
235*288bf522SAndroid Build Coastguard Worker 
236*288bf522SAndroid Build Coastguard Worker     struct fec_handle *handle = nullptr;
237*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_open(&handle, avb_image.path, O_RDWR, FEC_FS_EXT4, 2));
238*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<fec_handle> guard(handle);
239*288bf522SAndroid Build Coastguard Worker 
240*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024, handle->data_size);  // filesystem size
241*288bf522SAndroid Build Coastguard Worker 
242*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(handle->avb.valid);
243*288bf522SAndroid Build Coastguard Worker 
244*288bf522SAndroid Build Coastguard Worker     // check the hashtree.
245*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(salt_, handle->hashtree().salt);
246*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024, handle->hashtree().hash_start);
247*288bf522SAndroid Build Coastguard Worker     // the fec hashtree only stores the hash of the lowest level.
248*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(std::vector<uint8_t>(hashtree_content_.begin() + 4096,
249*288bf522SAndroid Build Coastguard Worker                                    hashtree_content_.end()),
250*288bf522SAndroid Build Coastguard Worker               handle->hashtree().hash_data);
251*288bf522SAndroid Build Coastguard Worker     uint64_t hash_size =
252*288bf522SAndroid Build Coastguard Worker         verity_get_size(handle->hashtree().data_blocks * FEC_BLOCKSIZE, nullptr,
253*288bf522SAndroid Build Coastguard Worker                         nullptr, SHA256_DIGEST_LENGTH);
254*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(hashtree_content_.size(), hash_size);
255*288bf522SAndroid Build Coastguard Worker 
256*288bf522SAndroid Build Coastguard Worker     fec_ecc_metadata ecc_metadata{};
257*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_ecc_get_metadata(handle, &ecc_metadata));
258*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(ecc_metadata.valid);
259*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024 + hash_size, ecc_metadata.start);
260*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(259, ecc_metadata.blocks);
261*288bf522SAndroid Build Coastguard Worker }
262*288bf522SAndroid Build Coastguard Worker 
TEST_F(FecUnitTest,LoadAvbImage_CorrectHashtree)263*288bf522SAndroid Build Coastguard Worker TEST_F(FecUnitTest, LoadAvbImage_CorrectHashtree) {
264*288bf522SAndroid Build Coastguard Worker     TemporaryFile avb_image;
265*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(
266*288bf522SAndroid Build Coastguard Worker         android::base::WriteFully(avb_image.fd, image_.data(), image_.size()));
267*288bf522SAndroid Build Coastguard Worker     AddAvbHashtreeFooter(avb_image.path);
268*288bf522SAndroid Build Coastguard Worker 
269*288bf522SAndroid Build Coastguard Worker     uint64_t corrupt_offset = 1024 * 1024 + 2 * 4096 + 50;
270*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(corrupt_offset, lseek64(avb_image.fd, corrupt_offset, 0));
271*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> corruption(20, 5);
272*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteFully(avb_image.fd, corruption.data(),
273*288bf522SAndroid Build Coastguard Worker                                           corruption.size()));
274*288bf522SAndroid Build Coastguard Worker 
275*288bf522SAndroid Build Coastguard Worker     struct fec_handle *handle = nullptr;
276*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_open(&handle, avb_image.path, O_RDWR, FEC_FS_EXT4, 2));
277*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<fec_handle> guard(handle);
278*288bf522SAndroid Build Coastguard Worker 
279*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024 * 1024, handle->data_size);  // filesystem size
280*288bf522SAndroid Build Coastguard Worker     fec_ecc_metadata ecc_metadata{};
281*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_ecc_get_metadata(handle, &ecc_metadata));
282*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(ecc_metadata.valid);
283*288bf522SAndroid Build Coastguard Worker }
284*288bf522SAndroid Build Coastguard Worker 
TEST_F(FecUnitTest,AvbImage_FecRead)285*288bf522SAndroid Build Coastguard Worker TEST_F(FecUnitTest, AvbImage_FecRead) {
286*288bf522SAndroid Build Coastguard Worker     TemporaryFile avb_image;
287*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(
288*288bf522SAndroid Build Coastguard Worker         android::base::WriteFully(avb_image.fd, image_.data(), image_.size()));
289*288bf522SAndroid Build Coastguard Worker     AddAvbHashtreeFooter(avb_image.path, "sha1");
290*288bf522SAndroid Build Coastguard Worker 
291*288bf522SAndroid Build Coastguard Worker     uint64_t corrupt_offset = 4096 * 10;
292*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(corrupt_offset, lseek64(avb_image.fd, corrupt_offset, 0));
293*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> corruption(50, 99);
294*288bf522SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteFully(avb_image.fd, corruption.data(),
295*288bf522SAndroid Build Coastguard Worker                                           corruption.size()));
296*288bf522SAndroid Build Coastguard Worker 
297*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> read_data(1024, 0);
298*288bf522SAndroid Build Coastguard Worker     struct fec_handle *handle = nullptr;
299*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(0, fec_open(&handle, avb_image.path, O_RDWR, FEC_FS_EXT4, 2));
300*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<fec_handle> guard(handle);
301*288bf522SAndroid Build Coastguard Worker 
302*288bf522SAndroid Build Coastguard Worker     // Verify the hashtree has the expected content.
303*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(std::vector<uint8_t>(hashtree_content_.begin() + 4096,
304*288bf522SAndroid Build Coastguard Worker                                    hashtree_content_.end()),
305*288bf522SAndroid Build Coastguard Worker               handle->hashtree().hash_data);
306*288bf522SAndroid Build Coastguard Worker 
307*288bf522SAndroid Build Coastguard Worker     // Verify the corruption gets corrected.
308*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(1024, fec_pread(handle, read_data.data(), 1024, corrupt_offset));
309*288bf522SAndroid Build Coastguard Worker     ASSERT_EQ(std::vector<uint8_t>(1024, 10), read_data);
310*288bf522SAndroid Build Coastguard Worker }
311