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