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 "reader.h" 18 19 #include <stddef.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <unistd.h> 23 24 #include <functional> 25 26 #include <android-base/file.h> 27 #include <android-base/unique_fd.h> 28 29 #include "utility.h" 30 31 namespace android { 32 namespace fs_mgr { 33 34 static_assert(sizeof(LpMetadataHeaderV1_0) == offsetof(LpMetadataHeader, flags), 35 "Incorrect LpMetadataHeader v0 size"); 36 37 // Helper class for reading descriptors and memory buffers in the same manner. 38 class Reader { 39 public: ~Reader()40 virtual ~Reader(){}; 41 virtual bool ReadFully(void* buffer, size_t length) = 0; 42 }; 43 44 class FileReader final : public Reader { 45 public: FileReader(int fd)46 explicit FileReader(int fd) : fd_(fd) {} ReadFully(void * buffer,size_t length)47 bool ReadFully(void* buffer, size_t length) override { 48 return android::base::ReadFully(fd_, buffer, length); 49 } 50 51 private: 52 int fd_; 53 }; 54 55 class MemoryReader final : public Reader { 56 public: MemoryReader(const void * buffer,size_t size)57 MemoryReader(const void* buffer, size_t size) 58 : buffer_(reinterpret_cast<const uint8_t*>(buffer)), size_(size), pos_(0) {} ReadFully(void * out,size_t length)59 bool ReadFully(void* out, size_t length) override { 60 if (size_ - pos_ < length) { 61 errno = EINVAL; 62 return false; 63 } 64 memcpy(out, buffer_ + pos_, length); 65 pos_ += length; 66 return true; 67 } 68 69 private: 70 const uint8_t* buffer_; 71 size_t size_; 72 size_t pos_; 73 }; 74 ParseGeometry(const void * buffer,LpMetadataGeometry * geometry)75 bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) { 76 static_assert(sizeof(*geometry) <= LP_METADATA_GEOMETRY_SIZE); 77 memcpy(geometry, buffer, sizeof(*geometry)); 78 79 // Check the magic signature. 80 if (geometry->magic != LP_METADATA_GEOMETRY_MAGIC) { 81 LERROR << "Logical partition metadata has invalid geometry magic signature."; 82 return false; 83 } 84 // Reject if the struct size is larger than what we compiled. This is so we 85 // can compute a checksum with the |struct_size| field rather than using 86 // sizeof. 87 if (geometry->struct_size > sizeof(LpMetadataGeometry)) { 88 LERROR << "Logical partition metadata has unrecognized fields."; 89 return false; 90 } 91 // Recompute and check the CRC32. 92 { 93 LpMetadataGeometry temp = *geometry; 94 memset(&temp.checksum, 0, sizeof(temp.checksum)); 95 SHA256(&temp, temp.struct_size, temp.checksum); 96 if (memcmp(temp.checksum, geometry->checksum, sizeof(temp.checksum)) != 0) { 97 LERROR << "Logical partition metadata has invalid geometry checksum."; 98 return false; 99 } 100 } 101 // Check that the struct size is equal (this will have to change if we ever 102 // change the struct size in a release). 103 if (geometry->struct_size != sizeof(LpMetadataGeometry)) { 104 LERROR << "Logical partition metadata has invalid struct size."; 105 return false; 106 } 107 if (geometry->metadata_slot_count == 0) { 108 LERROR << "Logical partition metadata has invalid slot count."; 109 return false; 110 } 111 if (geometry->metadata_max_size % LP_SECTOR_SIZE != 0) { 112 LERROR << "Metadata max size is not sector-aligned."; 113 return false; 114 } 115 return true; 116 } 117 ReadPrimaryGeometry(int fd,LpMetadataGeometry * geometry)118 bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) { 119 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE); 120 if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) { 121 PERROR << __PRETTY_FUNCTION__ << " lseek failed"; 122 return false; 123 } 124 if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) { 125 PERROR << __PRETTY_FUNCTION__ << " read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed"; 126 return false; 127 } 128 return ParseGeometry(buffer.get(), geometry); 129 } 130 ReadBackupGeometry(int fd,LpMetadataGeometry * geometry)131 bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) { 132 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE); 133 if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) { 134 PERROR << __PRETTY_FUNCTION__ << " lseek failed"; 135 return false; 136 } 137 if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) { 138 PERROR << __PRETTY_FUNCTION__ << " backup read " << LP_METADATA_GEOMETRY_SIZE 139 << " bytes failed"; 140 return false; 141 } 142 return ParseGeometry(buffer.get(), geometry); 143 } 144 145 // Read and validate geometry information from a block device that holds 146 // logical partitions. If the information is corrupted, this will attempt 147 // to read it from a secondary backup location. ReadLogicalPartitionGeometry(int fd,LpMetadataGeometry * geometry)148 bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) { 149 if (ReadPrimaryGeometry(fd, geometry)) { 150 return true; 151 } 152 return ReadBackupGeometry(fd, geometry); 153 } 154 ValidateTableBounds(const LpMetadataHeader & header,const LpMetadataTableDescriptor & table)155 static bool ValidateTableBounds(const LpMetadataHeader& header, 156 const LpMetadataTableDescriptor& table) { 157 if (table.offset > header.tables_size) { 158 return false; 159 } 160 uint64_t table_size = uint64_t(table.num_entries) * table.entry_size; 161 if (header.tables_size - table.offset < table_size) { 162 return false; 163 } 164 return true; 165 } 166 ReadMetadataHeader(Reader * reader,LpMetadata * metadata)167 static bool ReadMetadataHeader(Reader* reader, LpMetadata* metadata) { 168 // Note we zero the struct since older files will result in a partial read. 169 LpMetadataHeader& header = metadata->header; 170 memset(&header, 0, sizeof(header)); 171 172 if (!reader->ReadFully(&header, sizeof(LpMetadataHeaderV1_0))) { 173 PERROR << __PRETTY_FUNCTION__ << " read failed"; 174 return false; 175 } 176 177 // Do basic validity checks before computing the checksum. 178 if (header.magic != LP_METADATA_HEADER_MAGIC) { 179 LERROR << "Logical partition metadata has invalid magic value."; 180 return false; 181 } 182 if (header.major_version != LP_METADATA_MAJOR_VERSION || 183 header.minor_version > LP_METADATA_MINOR_VERSION_MAX) { 184 LERROR << "Logical partition metadata has incompatible version."; 185 return false; 186 } 187 188 // Validate the header struct size against the reported version. 189 uint32_t expected_struct_size = sizeof(header); 190 if (header.minor_version < LP_METADATA_VERSION_FOR_EXPANDED_HEADER) { 191 expected_struct_size = sizeof(LpMetadataHeaderV1_0); 192 } 193 if (header.header_size != expected_struct_size) { 194 LERROR << "Invalid partition metadata header struct size."; 195 return false; 196 } 197 198 // Read in any remaining fields, the last step needed before checksumming. 199 if (size_t remaining_bytes = header.header_size - sizeof(LpMetadataHeaderV1_0)) { 200 uint8_t* offset = reinterpret_cast<uint8_t*>(&header) + sizeof(LpMetadataHeaderV1_0); 201 if (!reader->ReadFully(offset, remaining_bytes)) { 202 PERROR << __PRETTY_FUNCTION__ << " read failed"; 203 return false; 204 } 205 } 206 207 // To compute the header's checksum, we have to temporarily set its checksum 208 // field to 0. Note that we must only compute up to |header_size|. 209 { 210 LpMetadataHeader temp = header; 211 memset(&temp.header_checksum, 0, sizeof(temp.header_checksum)); 212 SHA256(&temp, temp.header_size, temp.header_checksum); 213 if (memcmp(temp.header_checksum, header.header_checksum, sizeof(temp.header_checksum)) != 214 0) { 215 LERROR << "Logical partition metadata has invalid checksum."; 216 return false; 217 } 218 } 219 220 if (!ValidateTableBounds(header, header.partitions) || 221 !ValidateTableBounds(header, header.extents) || 222 !ValidateTableBounds(header, header.groups) || 223 !ValidateTableBounds(header, header.block_devices)) { 224 LERROR << "Logical partition metadata has invalid table bounds."; 225 return false; 226 } 227 // Check that table entry sizes can accomodate their respective structs. If 228 // table sizes change, these checks will have to be adjusted. 229 if (header.partitions.entry_size != sizeof(LpMetadataPartition)) { 230 LERROR << "Logical partition metadata has invalid partition table entry size."; 231 return false; 232 } 233 if (header.extents.entry_size != sizeof(LpMetadataExtent)) { 234 LERROR << "Logical partition metadata has invalid extent table entry size."; 235 return false; 236 } 237 if (header.groups.entry_size != sizeof(LpMetadataPartitionGroup)) { 238 LERROR << "Logical partition metadata has invalid group table entry size."; 239 return false; 240 } 241 return true; 242 } 243 244 // Parse and validate all metadata at the current position in the given file 245 // descriptor. ParseMetadata(const LpMetadataGeometry & geometry,Reader * reader)246 static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, 247 Reader* reader) { 248 // First read and validate the header. 249 std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>(); 250 251 metadata->geometry = geometry; 252 if (!ReadMetadataHeader(reader, metadata.get())) { 253 return nullptr; 254 } 255 256 LpMetadataHeader& header = metadata->header; 257 258 // Check the table size. 259 if (header.tables_size > geometry.metadata_max_size) { 260 LERROR << "Invalid partition metadata header table size."; 261 return nullptr; 262 } 263 264 // Read the metadata payload. Allocation is fallible since the table size 265 // could be large. 266 std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[header.tables_size]); 267 if (!buffer) { 268 LERROR << "Out of memory reading logical partition tables."; 269 return nullptr; 270 } 271 if (!reader->ReadFully(buffer.get(), header.tables_size)) { 272 PERROR << __PRETTY_FUNCTION__ << " read " << header.tables_size << "bytes failed"; 273 return nullptr; 274 } 275 276 uint8_t checksum[32]; 277 SHA256(buffer.get(), header.tables_size, checksum); 278 if (memcmp(checksum, header.tables_checksum, sizeof(checksum)) != 0) { 279 LERROR << "Logical partition metadata has invalid table checksum."; 280 return nullptr; 281 } 282 283 uint32_t valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V0; 284 if (metadata->header.minor_version >= LP_METADATA_VERSION_FOR_UPDATED_ATTR) { 285 valid_attributes |= LP_PARTITION_ATTRIBUTE_MASK_V1; 286 } 287 288 // ValidateTableSize ensured that |cursor| is valid for the number of 289 // entries in the table. 290 uint8_t* cursor = buffer.get() + header.partitions.offset; 291 for (size_t i = 0; i < header.partitions.num_entries; i++) { 292 LpMetadataPartition partition; 293 memcpy(&partition, cursor, sizeof(partition)); 294 cursor += header.partitions.entry_size; 295 296 if (partition.attributes & ~valid_attributes) { 297 LERROR << "Logical partition has invalid attribute set."; 298 return nullptr; 299 } 300 if (partition.first_extent_index + partition.num_extents < partition.first_extent_index) { 301 LERROR << "Logical partition first_extent_index + num_extents overflowed."; 302 return nullptr; 303 } 304 if (partition.first_extent_index + partition.num_extents > header.extents.num_entries) { 305 LERROR << "Logical partition has invalid extent list."; 306 return nullptr; 307 } 308 if (partition.group_index >= header.groups.num_entries) { 309 LERROR << "Logical partition has invalid group index."; 310 return nullptr; 311 } 312 313 metadata->partitions.push_back(partition); 314 } 315 316 cursor = buffer.get() + header.extents.offset; 317 for (size_t i = 0; i < header.extents.num_entries; i++) { 318 LpMetadataExtent extent; 319 memcpy(&extent, cursor, sizeof(extent)); 320 cursor += header.extents.entry_size; 321 322 if (extent.target_type == LP_TARGET_TYPE_LINEAR && 323 extent.target_source >= header.block_devices.num_entries) { 324 LERROR << "Logical partition extent has invalid block device."; 325 return nullptr; 326 } 327 328 metadata->extents.push_back(extent); 329 } 330 331 cursor = buffer.get() + header.groups.offset; 332 for (size_t i = 0; i < header.groups.num_entries; i++) { 333 LpMetadataPartitionGroup group = {}; 334 memcpy(&group, cursor, sizeof(group)); 335 cursor += header.groups.entry_size; 336 337 metadata->groups.push_back(group); 338 } 339 340 cursor = buffer.get() + header.block_devices.offset; 341 for (size_t i = 0; i < header.block_devices.num_entries; i++) { 342 LpMetadataBlockDevice device = {}; 343 memcpy(&device, cursor, sizeof(device)); 344 cursor += header.block_devices.entry_size; 345 346 metadata->block_devices.push_back(device); 347 } 348 349 const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(*metadata.get()); 350 if (!super_device) { 351 LERROR << "Metadata does not specify a super device."; 352 return nullptr; 353 } 354 355 // Check that the metadata area and logical partition areas don't overlap. 356 uint64_t metadata_region = 357 GetTotalMetadataSize(geometry.metadata_max_size, geometry.metadata_slot_count); 358 if (metadata_region > super_device->first_logical_sector * LP_SECTOR_SIZE) { 359 LERROR << "Logical partition metadata overlaps with logical partition contents."; 360 return nullptr; 361 } 362 return metadata; 363 } 364 ParseMetadata(const LpMetadataGeometry & geometry,const void * buffer,size_t size)365 std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer, 366 size_t size) { 367 MemoryReader reader(buffer, size); 368 return ParseMetadata(geometry, &reader); 369 } 370 ParseMetadata(const LpMetadataGeometry & geometry,int fd)371 std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, int fd) { 372 FileReader reader(fd); 373 return ParseMetadata(geometry, &reader); 374 } 375 ReadPrimaryMetadata(int fd,const LpMetadataGeometry & geometry,uint32_t slot_number)376 std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry, 377 uint32_t slot_number) { 378 int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number); 379 if (SeekFile64(fd, offset, SEEK_SET) < 0) { 380 PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset; 381 return nullptr; 382 } 383 return ParseMetadata(geometry, fd); 384 } 385 ReadBackupMetadata(int fd,const LpMetadataGeometry & geometry,uint32_t slot_number)386 std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry, 387 uint32_t slot_number) { 388 int64_t offset = GetBackupMetadataOffset(geometry, slot_number); 389 if (SeekFile64(fd, offset, SEEK_SET) < 0) { 390 PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset; 391 return nullptr; 392 } 393 return ParseMetadata(geometry, fd); 394 } 395 396 namespace { 397 AdjustMetadataForSlot(LpMetadata * metadata,uint32_t slot_number)398 bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) { 399 std::string slot_suffix = SlotSuffixForSlotNumber(slot_number); 400 for (auto& partition : metadata->partitions) { 401 if (!(partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED)) { 402 continue; 403 } 404 std::string partition_name = GetPartitionName(partition) + slot_suffix; 405 if (partition_name.size() > sizeof(partition.name)) { 406 LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name; 407 return false; 408 } 409 strncpy(partition.name, partition_name.c_str(), sizeof(partition.name)); 410 partition.attributes &= ~LP_PARTITION_ATTR_SLOT_SUFFIXED; 411 } 412 for (auto& block_device : metadata->block_devices) { 413 if (!(block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED)) { 414 continue; 415 } 416 std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix; 417 if (!UpdateBlockDevicePartitionName(&block_device, partition_name)) { 418 LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name; 419 return false; 420 } 421 block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED; 422 } 423 for (auto& group : metadata->groups) { 424 if (!(group.flags & LP_GROUP_SLOT_SUFFIXED)) { 425 continue; 426 } 427 std::string group_name = GetPartitionGroupName(group) + slot_suffix; 428 if (!UpdatePartitionGroupName(&group, group_name)) { 429 LERROR << __PRETTY_FUNCTION__ << " group name too long: " << group_name; 430 return false; 431 } 432 group.flags &= ~LP_GROUP_SLOT_SUFFIXED; 433 } 434 return true; 435 } 436 437 } // namespace 438 ReadMetadata(const IPartitionOpener & opener,const std::string & super_partition,uint32_t slot_number)439 std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener, 440 const std::string& super_partition, uint32_t slot_number) { 441 android::base::unique_fd fd = opener.Open(super_partition, O_RDONLY); 442 if (fd < 0) { 443 PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition; 444 return nullptr; 445 } 446 447 LpMetadataGeometry geometry; 448 if (!ReadLogicalPartitionGeometry(fd, &geometry)) { 449 return nullptr; 450 } 451 if (slot_number >= geometry.metadata_slot_count) { 452 LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number"; 453 return nullptr; 454 } 455 456 std::vector<int64_t> offsets = { 457 GetPrimaryMetadataOffset(geometry, slot_number), 458 GetBackupMetadataOffset(geometry, slot_number), 459 }; 460 std::unique_ptr<LpMetadata> metadata; 461 462 for (const auto& offset : offsets) { 463 if (SeekFile64(fd, offset, SEEK_SET) < 0) { 464 PERROR << __PRETTY_FUNCTION__ << " lseek failed, offset " << offset; 465 continue; 466 } 467 if ((metadata = ParseMetadata(geometry, fd)) != nullptr) { 468 break; 469 } 470 } 471 if (!metadata || !AdjustMetadataForSlot(metadata.get(), slot_number)) { 472 return nullptr; 473 } 474 return metadata; 475 } 476 ReadMetadata(const std::string & super_partition,uint32_t slot_number)477 std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number) { 478 return ReadMetadata(PartitionOpener(), super_partition, slot_number); 479 } 480 NameFromFixedArray(const char * name,size_t buffer_size)481 static std::string NameFromFixedArray(const char* name, size_t buffer_size) { 482 // If the end of the buffer has a null character, it's safe to assume the 483 // buffer is null terminated. Otherwise, we cap the string to the input 484 // buffer size. 485 if (name[buffer_size - 1] == '\0') { 486 return std::string(name); 487 } 488 return std::string(name, buffer_size); 489 } 490 GetPartitionName(const LpMetadataPartition & partition)491 std::string GetPartitionName(const LpMetadataPartition& partition) { 492 return NameFromFixedArray(partition.name, sizeof(partition.name)); 493 } 494 GetPartitionGroupName(const LpMetadataPartitionGroup & group)495 std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group) { 496 return NameFromFixedArray(group.name, sizeof(group.name)); 497 } 498 GetBlockDevicePartitionName(const LpMetadataBlockDevice & block_device)499 std::string GetBlockDevicePartitionName(const LpMetadataBlockDevice& block_device) { 500 return NameFromFixedArray(block_device.partition_name, sizeof(block_device.partition_name)); 501 } 502 503 } // namespace fs_mgr 504 } // namespace android 505