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