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