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