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