xref: /aosp_15_r20/system/update_engine/payload_generator/payload_generation_config_android.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
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 <android-base/parseint.h>
20 #include <base/logging.h>
21 #include <base/strings/string_number_conversions.h>
22 #include <base/strings/string_split.h>
23 #include <brillo/secure_blob.h>
24 #include <fec/io.h>
25 #include <libavb/libavb.h>
26 #include <verity/hash_tree_builder.h>
27 
28 #include "update_engine/common/utils.h"
29 #include "update_engine/payload_consumer/verity_writer_android.h"
30 #include "update_engine/payload_generator/extent_ranges.h"
31 
32 namespace chromeos_update_engine {
33 
34 namespace {
AvbDescriptorCallback(const AvbDescriptor * descriptor,void * user_data)35 bool AvbDescriptorCallback(const AvbDescriptor* descriptor, void* user_data) {
36   PartitionConfig* part = static_cast<PartitionConfig*>(user_data);
37   AvbDescriptor desc;
38   TEST_AND_RETURN_FALSE(
39       avb_descriptor_validate_and_byteswap(descriptor, &desc));
40   if (desc.tag != AVB_DESCRIPTOR_TAG_HASHTREE)
41     return true;
42 
43   AvbHashtreeDescriptor hashtree;
44   TEST_AND_RETURN_FALSE(avb_hashtree_descriptor_validate_and_byteswap(
45       reinterpret_cast<const AvbHashtreeDescriptor*>(descriptor), &hashtree));
46   // We only support version 1 right now, will need to introduce a new
47   // payload minor version to support new dm verity version.
48   TEST_AND_RETURN_FALSE(hashtree.dm_verity_version == 1);
49   part->verity.hash_tree_algorithm =
50       reinterpret_cast<const char*>(hashtree.hash_algorithm);
51 
52   const uint8_t* salt = reinterpret_cast<const uint8_t*>(descriptor) +
53                         sizeof(AvbHashtreeDescriptor) +
54                         hashtree.partition_name_len;
55   part->verity.hash_tree_salt.assign(salt, salt + hashtree.salt_len);
56 
57   TEST_AND_RETURN_FALSE(hashtree.data_block_size ==
58                         part->fs_interface->GetBlockSize());
59   part->verity.hash_tree_data_extent =
60       ExtentForBytes(hashtree.data_block_size, 0, hashtree.image_size);
61 
62   TEST_AND_RETURN_FALSE(hashtree.hash_block_size ==
63                         part->fs_interface->GetBlockSize());
64   part->verity.hash_tree_extent = ExtentForBytes(
65       hashtree.hash_block_size, hashtree.tree_offset, hashtree.tree_size);
66 
67   if (!part->disable_fec_computation) {
68     part->verity.fec_data_extent =
69         ExtentForBytes(hashtree.data_block_size, 0, hashtree.fec_offset);
70     part->verity.fec_extent = ExtentForBytes(
71         hashtree.data_block_size, hashtree.fec_offset, hashtree.fec_size);
72     part->verity.fec_roots = hashtree.fec_num_roots;
73   }
74   return true;
75 }
76 
77 // Generate hash tree and FEC based on the verity config and verify that it
78 // matches the hash tree and FEC stored in the image.
VerifyVerityConfig(const PartitionConfig & part)79 bool VerifyVerityConfig(const PartitionConfig& part) {
80   const size_t block_size = part.fs_interface->GetBlockSize();
81   if (part.verity.hash_tree_extent.num_blocks() != 0) {
82     auto hash_function =
83         HashTreeBuilder::HashFunction(part.verity.hash_tree_algorithm);
84     TEST_AND_RETURN_FALSE(hash_function != nullptr);
85     HashTreeBuilder hash_tree_builder(block_size, hash_function);
86     uint64_t data_size =
87         part.verity.hash_tree_data_extent.num_blocks() * block_size;
88     uint64_t tree_size = hash_tree_builder.CalculateSize(data_size);
89     TEST_AND_RETURN_FALSE(
90         tree_size == part.verity.hash_tree_extent.num_blocks() * block_size);
91     TEST_AND_RETURN_FALSE(
92         hash_tree_builder.Initialize(data_size, part.verity.hash_tree_salt));
93 
94     brillo::Blob buffer;
95     for (uint64_t offset = part.verity.hash_tree_data_extent.start_block() *
96                            block_size,
97                   data_end = offset + data_size;
98          offset < data_end;) {
99       constexpr uint64_t kBufferSize = 1024 * 1024;
100       size_t bytes_to_read = std::min(kBufferSize, data_end - offset);
101       TEST_AND_RETURN_FALSE(
102           utils::ReadFileChunk(part.path, offset, bytes_to_read, &buffer));
103       TEST_AND_RETURN_FALSE(
104           hash_tree_builder.Update(buffer.data(), buffer.size()));
105       offset += buffer.size();
106       buffer.clear();
107     }
108     TEST_AND_RETURN_FALSE(hash_tree_builder.BuildHashTree());
109     TEST_AND_RETURN_FALSE(utils::ReadFileChunk(
110         part.path,
111         part.verity.hash_tree_extent.start_block() * block_size,
112         tree_size,
113         &buffer));
114     TEST_AND_RETURN_FALSE(hash_tree_builder.CheckHashTree(buffer));
115   }
116 
117   if (part.verity.fec_extent.num_blocks() != 0) {
118     TEST_AND_RETURN_FALSE(VerityWriterAndroid::EncodeFEC(
119         part.path,
120         part.verity.fec_data_extent.start_block() * block_size,
121         part.verity.fec_data_extent.num_blocks() * block_size,
122         part.verity.fec_extent.start_block() * block_size,
123         part.verity.fec_extent.num_blocks() * block_size,
124         part.verity.fec_roots,
125         block_size,
126         true /* verify_mode */));
127   }
128   return true;
129 }
130 }  // namespace
131 
LoadVerityConfig()132 bool ImageConfig::LoadVerityConfig() {
133   for (PartitionConfig& part : partitions) {
134     // Parse AVB devices.
135     if (part.size > sizeof(AvbFooter)) {
136       uint64_t footer_offset = part.size - sizeof(AvbFooter);
137       brillo::Blob buffer;
138       TEST_AND_RETURN_FALSE(utils::ReadFileChunk(
139           part.path, footer_offset, sizeof(AvbFooter), &buffer));
140       if (memcmp(buffer.data(), AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) == 0) {
141         LOG(INFO) << "Parsing verity config from AVB footer for " << part.name;
142         AvbFooter footer;
143         TEST_AND_RETURN_FALSE(avb_footer_validate_and_byteswap(
144             reinterpret_cast<const AvbFooter*>(buffer.data()), &footer));
145         buffer.clear();
146 
147         TEST_AND_RETURN_FALSE(
148             footer.vbmeta_offset + sizeof(AvbVBMetaImageHeader) <= part.size);
149         TEST_AND_RETURN_FALSE(utils::ReadFileChunk(
150             part.path, footer.vbmeta_offset, footer.vbmeta_size, &buffer));
151         TEST_AND_RETURN_FALSE(avb_descriptor_foreach(
152             buffer.data(), buffer.size(), AvbDescriptorCallback, &part));
153       }
154     }
155 
156     // Parse VB1.0 devices with FEC metadata, devices with hash tree without
157     // FEC will be skipped for now.
158     if (part.verity.IsEmpty() && part.size > FEC_BLOCKSIZE) {
159       brillo::Blob fec_metadata;
160       TEST_AND_RETURN_FALSE(utils::ReadFileChunk(part.path,
161                                                  part.size - FEC_BLOCKSIZE,
162                                                  sizeof(fec_header),
163                                                  &fec_metadata));
164       const fec_header* header =
165           reinterpret_cast<const fec_header*>(fec_metadata.data());
166       if (header->magic == FEC_MAGIC) {
167         LOG(INFO)
168             << "Parsing verity config from Verified Boot 1.0 metadata for "
169             << part.name;
170         const size_t block_size = part.fs_interface->GetBlockSize();
171         // FEC_VERITY_DISABLE skips verifying verity hash tree, because we will
172         // verify it ourselves later.
173         fec::io fh(part.path, O_RDONLY, FEC_VERITY_DISABLE);
174         TEST_AND_RETURN_FALSE(fh);
175         fec_verity_metadata verity_data;
176         if (fh.get_verity_metadata(verity_data)) {
177           auto verity_table = base::SplitString(verity_data.table,
178                                                 " ",
179                                                 base::KEEP_WHITESPACE,
180                                                 base::SPLIT_WANT_ALL);
181           TEST_AND_RETURN_FALSE(verity_table.size() == 10);
182           size_t data_block_size = 0;
183           TEST_AND_RETURN_FALSE(
184               base::StringToSizeT(verity_table[3], &data_block_size));
185           TEST_AND_RETURN_FALSE(block_size == data_block_size);
186           size_t hash_block_size = 0;
187           TEST_AND_RETURN_FALSE(
188               base::StringToSizeT(verity_table[4], &hash_block_size));
189           TEST_AND_RETURN_FALSE(block_size == hash_block_size);
190           uint64_t num_data_blocks = 0;
191           TEST_AND_RETURN_FALSE(android::base::ParseUint<uint64_t>(
192               verity_table[5], &num_data_blocks));
193           part.verity.hash_tree_data_extent =
194               ExtentForRange(0, num_data_blocks);
195           uint64_t hash_start_block = 0;
196           TEST_AND_RETURN_FALSE(android::base::ParseUint<uint64_t>(
197               verity_table[6], &hash_start_block));
198           part.verity.hash_tree_algorithm = verity_table[7];
199           TEST_AND_RETURN_FALSE(base::HexStringToBytes(
200               verity_table[9], &part.verity.hash_tree_salt));
201           auto hash_function =
202               HashTreeBuilder::HashFunction(part.verity.hash_tree_algorithm);
203           TEST_AND_RETURN_FALSE(hash_function != nullptr);
204           HashTreeBuilder hash_tree_builder(block_size, hash_function);
205           uint64_t tree_size =
206               hash_tree_builder.CalculateSize(num_data_blocks * block_size);
207           part.verity.hash_tree_extent =
208               ExtentForRange(hash_start_block, tree_size / block_size);
209         }
210         fec_ecc_metadata ecc_data;
211         if (!part.disable_fec_computation && fh.get_ecc_metadata(ecc_data) &&
212             ecc_data.valid) {
213           TEST_AND_RETURN_FALSE(block_size == FEC_BLOCKSIZE);
214           part.verity.fec_data_extent = ExtentForRange(0, ecc_data.blocks);
215           part.verity.fec_extent =
216               ExtentForBytes(block_size, ecc_data.start, header->fec_size);
217           part.verity.fec_roots = ecc_data.roots;
218         }
219       }
220     }
221 
222     if (!part.verity.IsEmpty()) {
223       TEST_AND_RETURN_FALSE(VerifyVerityConfig(part));
224     }
225   }
226   return true;
227 }
228 
229 }  // namespace chromeos_update_engine
230