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 { 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. 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 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