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