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 <fcntl.h>
18 #include <linux/memfd.h>
19 #include <stdio.h>
20 #include <sys/syscall.h>
21
22 #include <android-base/file.h>
23 #include <android-base/unique_fd.h>
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26 #include <liblp/builder.h>
27
28 #include "images.h"
29 #include "liblp_test.h"
30 #include "reader.h"
31 #include "test_partition_opener.h"
32 #include "utility.h"
33 #include "writer.h"
34
35 using namespace std;
36 using namespace android::fs_mgr;
37 using namespace android::fs_mgr::testing;
38 using ::testing::_;
39 using ::testing::Return;
40 using unique_fd = android::base::unique_fd;
41
42 // Our tests assume a 128KiB disk with two 512 byte metadata slots.
43 static const size_t kDiskSize = 131072;
44 static const size_t kMetadataSize = 512;
45 static const size_t kMetadataSlots = 2;
46 static const BlockDeviceInfo kSuperInfo{"super", kDiskSize, 0, 0, 4096};
47
48 // Helper function for creating an in-memory file descriptor. This lets us
49 // simulate read/writing logical partition metadata as if we had a block device
50 // for a physical partition.
CreateFakeDisk(off_t size)51 static unique_fd CreateFakeDisk(off_t size) {
52 unique_fd fd(syscall(__NR_memfd_create, "fake_disk", MFD_ALLOW_SEALING));
53 if (fd < 0) {
54 perror("memfd_create");
55 return {};
56 }
57 if (ftruncate(fd, size) < 0) {
58 perror("ftruncate");
59 return {};
60 }
61 // Prevent anything from accidentally growing/shrinking the file, as it
62 // would not be allowed on an actual partition.
63 if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
64 perror("fcntl");
65 return {};
66 }
67 // Write garbage to the "disk" so we can tell what has been zeroed or not.
68 unique_ptr<uint8_t[]> buffer = make_unique<uint8_t[]>(size);
69 memset(buffer.get(), 0xcc, size);
70 if (!android::base::WriteFully(fd, buffer.get(), size)) {
71 return {};
72 }
73 return fd;
74 }
75
76 // Create a disk of the default size.
CreateFakeDisk()77 static unique_fd CreateFakeDisk() {
78 return CreateFakeDisk(kDiskSize);
79 }
80
81 // Create a MetadataBuilder around some default sizes.
CreateDefaultBuilder()82 static unique_ptr<MetadataBuilder> CreateDefaultBuilder() {
83 unique_ptr<MetadataBuilder> builder =
84 MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
85 return builder;
86 }
87
88 class DefaultPartitionOpener final : public TestPartitionOpener {
89 public:
DefaultPartitionOpener(int fd)90 explicit DefaultPartitionOpener(int fd)
91 : TestPartitionOpener({{"super", fd}}, {{"super", kSuperInfo}}) {}
92 };
93
AddDefaultPartitions(MetadataBuilder * builder)94 static bool AddDefaultPartitions(MetadataBuilder* builder) {
95 Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_NONE);
96 if (!system) {
97 return false;
98 }
99 return builder->ResizePartition(system, 24 * 1024);
100 }
101
102 // Create a temporary disk and flash it with the default partition setup.
CreateFlashedDisk()103 static unique_fd CreateFlashedDisk() {
104 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
105 if (!builder || !AddDefaultPartitions(builder.get())) {
106 return {};
107 }
108 unique_fd fd = CreateFakeDisk();
109 if (fd < 0) {
110 return {};
111 }
112 // Export and flash.
113 unique_ptr<LpMetadata> exported = builder->Export();
114 if (!exported) {
115 return {};
116 }
117
118 DefaultPartitionOpener opener(fd);
119 if (!FlashPartitionTable(opener, "super", *exported.get())) {
120 return {};
121 }
122 return fd;
123 }
124
125 // Test that our CreateFakeDisk() function works.
TEST_F(LiblpTest,CreateFakeDisk)126 TEST_F(LiblpTest, CreateFakeDisk) {
127 unique_fd fd = CreateFakeDisk();
128 ASSERT_GE(fd, 0);
129
130 uint64_t size;
131 ASSERT_TRUE(GetDescriptorSize(fd, &size));
132 ASSERT_EQ(size, kDiskSize);
133
134 DefaultPartitionOpener opener(fd);
135
136 // Verify that we can't read unwritten metadata.
137 ASSERT_EQ(ReadMetadata(opener, "super", 1), nullptr);
138 }
139
140 // Flashing metadata should not work if the metadata was created for a larger
141 // disk than the destination disk.
TEST_F(LiblpTest,ExportDiskTooSmall)142 TEST_F(LiblpTest, ExportDiskTooSmall) {
143 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize + 4096, 512, 2);
144 ASSERT_NE(builder, nullptr);
145 unique_ptr<LpMetadata> exported = builder->Export();
146 ASSERT_NE(exported, nullptr);
147
148 // A larger geometry should fail to flash, since there won't be enough
149 // space to store the logical partition range that was specified.
150 unique_fd fd = CreateFakeDisk();
151 ASSERT_GE(fd, 0);
152
153 DefaultPartitionOpener opener(fd);
154
155 EXPECT_FALSE(FlashPartitionTable(opener, "super", *exported.get()));
156 }
157
158 // Test the basics of flashing a partition and reading it back.
TEST_F(LiblpTest,FlashAndReadback)159 TEST_F(LiblpTest, FlashAndReadback) {
160 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
161 ASSERT_NE(builder, nullptr);
162 ASSERT_TRUE(AddDefaultPartitions(builder.get()));
163
164 unique_fd fd = CreateFakeDisk();
165 ASSERT_GE(fd, 0);
166
167 DefaultPartitionOpener opener(fd);
168
169 // Export and flash.
170 unique_ptr<LpMetadata> exported = builder->Export();
171 ASSERT_NE(exported, nullptr);
172 ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
173
174 // Read back. Note that some fields are only filled in during
175 // serialization, so exported and imported will not be identical. For
176 // example, table sizes and checksums are computed in WritePartitionTable.
177 // Therefore we check on a field-by-field basis.
178 unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
179 ASSERT_NE(imported, nullptr);
180
181 // Check geometry and header.
182 EXPECT_EQ(exported->geometry.metadata_max_size, imported->geometry.metadata_max_size);
183 EXPECT_EQ(exported->geometry.metadata_slot_count, imported->geometry.metadata_slot_count);
184 EXPECT_EQ(exported->header.major_version, imported->header.major_version);
185 EXPECT_EQ(exported->header.minor_version, imported->header.minor_version);
186 EXPECT_EQ(exported->header.header_size, imported->header.header_size);
187
188 // Check partition tables.
189 ASSERT_EQ(exported->partitions.size(), imported->partitions.size());
190 EXPECT_EQ(GetPartitionName(exported->partitions[0]), GetPartitionName(imported->partitions[0]));
191 EXPECT_EQ(exported->partitions[0].attributes, imported->partitions[0].attributes);
192 EXPECT_EQ(exported->partitions[0].first_extent_index,
193 imported->partitions[0].first_extent_index);
194 EXPECT_EQ(exported->partitions[0].num_extents, imported->partitions[0].num_extents);
195
196 // Check extent tables.
197 ASSERT_EQ(exported->extents.size(), imported->extents.size());
198 EXPECT_EQ(exported->extents[0].num_sectors, imported->extents[0].num_sectors);
199 EXPECT_EQ(exported->extents[0].target_type, imported->extents[0].target_type);
200 EXPECT_EQ(exported->extents[0].target_data, imported->extents[0].target_data);
201
202 // Check block devices table.
203 ASSERT_EQ(exported->block_devices.size(), imported->block_devices.size());
204 EXPECT_EQ(exported->block_devices[0].first_logical_sector,
205 imported->block_devices[0].first_logical_sector);
206 }
207
208 // Test that we can update metadata slots without disturbing others.
TEST_F(LiblpTest,UpdateAnyMetadataSlot)209 TEST_F(LiblpTest, UpdateAnyMetadataSlot) {
210 unique_fd fd = CreateFlashedDisk();
211 ASSERT_GE(fd, 0);
212
213 DefaultPartitionOpener opener(fd);
214
215 unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
216 ASSERT_NE(imported, nullptr);
217 ASSERT_EQ(imported->partitions.size(), 1);
218 EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
219
220 // Change the name before writing to the next slot.
221 strncpy(imported->partitions[0].name, "vendor", sizeof(imported->partitions[0].name));
222 ASSERT_TRUE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
223
224 // Read back the original slot, make sure it hasn't changed.
225 imported = ReadMetadata(opener, "super", 0);
226 ASSERT_NE(imported, nullptr);
227 ASSERT_EQ(imported->partitions.size(), 1);
228 EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
229
230 // Now read back the new slot, and verify that it has a different name.
231 imported = ReadMetadata(opener, "super", 1);
232 ASSERT_NE(imported, nullptr);
233 ASSERT_EQ(imported->partitions.size(), 1);
234 EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
235
236 auto super_device = GetMetadataSuperBlockDevice(*imported.get());
237 ASSERT_NE(super_device, nullptr);
238
239 uint64_t last_sector = super_device->size / LP_SECTOR_SIZE;
240
241 // Verify that we didn't overwrite anything in the logical paritition area.
242 // We expect the disk to be filled with 0xcc on creation so we can read
243 // this back and compare it.
244 char expected[LP_SECTOR_SIZE];
245 memset(expected, 0xcc, sizeof(expected));
246 for (uint64_t i = super_device->first_logical_sector; i < last_sector; i++) {
247 char buffer[LP_SECTOR_SIZE];
248 ASSERT_GE(lseek(fd, i * LP_SECTOR_SIZE, SEEK_SET), 0);
249 ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
250 ASSERT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
251 }
252 }
253
TEST_F(LiblpTest,InvalidMetadataSlot)254 TEST_F(LiblpTest, InvalidMetadataSlot) {
255 unique_fd fd = CreateFlashedDisk();
256 ASSERT_GE(fd, 0);
257
258 DefaultPartitionOpener opener(fd);
259
260 // Make sure all slots are filled.
261 unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
262 ASSERT_NE(metadata, nullptr);
263 for (uint32_t i = 1; i < kMetadataSlots; i++) {
264 ASSERT_TRUE(UpdatePartitionTable(opener, "super", *metadata.get(), i));
265 }
266
267 // Verify that we can't read unavailable slots.
268 EXPECT_EQ(ReadMetadata(opener, "super", kMetadataSlots), nullptr);
269 }
270
271 // Test that updating a metadata slot does not allow it to be computed based
272 // on mismatching geometry.
TEST_F(LiblpTest,NoChangingGeometry)273 TEST_F(LiblpTest, NoChangingGeometry) {
274 unique_fd fd = CreateFlashedDisk();
275 ASSERT_GE(fd, 0);
276
277 DefaultPartitionOpener opener(fd);
278
279 unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
280 ASSERT_NE(imported, nullptr);
281 ASSERT_TRUE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
282
283 imported->geometry.metadata_max_size += LP_SECTOR_SIZE;
284 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
285
286 imported = ReadMetadata(opener, "super", 0);
287 ASSERT_NE(imported, nullptr);
288 imported->geometry.metadata_slot_count++;
289 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
290
291 imported = ReadMetadata(opener, "super", 0);
292 ASSERT_NE(imported, nullptr);
293 ASSERT_EQ(imported->block_devices.size(), 1);
294 imported->block_devices[0].first_logical_sector++;
295 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
296
297 imported = ReadMetadata(opener, "super", 0);
298 ASSERT_NE(imported, nullptr);
299 }
300
301 // Test that changing one bit of metadata is enough to break the checksum.
TEST_F(LiblpTest,BitFlipGeometry)302 TEST_F(LiblpTest, BitFlipGeometry) {
303 unique_fd fd = CreateFlashedDisk();
304 ASSERT_GE(fd, 0);
305
306 DefaultPartitionOpener opener(fd);
307
308 LpMetadataGeometry geometry;
309 ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
310 ASSERT_TRUE(android::base::ReadFully(fd, &geometry, sizeof(geometry)));
311
312 LpMetadataGeometry bad_geometry = geometry;
313 bad_geometry.metadata_slot_count++;
314 ASSERT_TRUE(android::base::WriteFully(fd, &bad_geometry, sizeof(bad_geometry)));
315
316 unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
317 ASSERT_NE(metadata, nullptr);
318 EXPECT_EQ(metadata->geometry.metadata_slot_count, 2);
319 }
320
TEST_F(LiblpTest,ReadBackupGeometry)321 TEST_F(LiblpTest, ReadBackupGeometry) {
322 unique_fd fd = CreateFlashedDisk();
323 ASSERT_GE(fd, 0);
324
325 DefaultPartitionOpener opener(fd);
326
327 char corruption[LP_METADATA_GEOMETRY_SIZE];
328 memset(corruption, 0xff, sizeof(corruption));
329
330 // Corrupt the primary geometry.
331 ASSERT_GE(lseek(fd, GetPrimaryGeometryOffset(), SEEK_SET), 0);
332 ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
333 EXPECT_NE(ReadMetadata(opener, "super", 0), nullptr);
334
335 // Corrupt the backup geometry.
336 ASSERT_GE(lseek(fd, GetBackupGeometryOffset(), SEEK_SET), 0);
337 ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
338 EXPECT_EQ(ReadMetadata(opener, "super", 0), nullptr);
339 }
340
TEST_F(LiblpTest,ReadBackupMetadata)341 TEST_F(LiblpTest, ReadBackupMetadata) {
342 unique_fd fd = CreateFlashedDisk();
343 ASSERT_GE(fd, 0);
344
345 DefaultPartitionOpener opener(fd);
346
347 unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
348
349 char corruption[kMetadataSize];
350 memset(corruption, 0xff, sizeof(corruption));
351
352 off_t offset = GetPrimaryMetadataOffset(metadata->geometry, 0);
353
354 ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
355 ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
356 EXPECT_NE(ReadMetadata(opener, "super", 0), nullptr);
357
358 offset = GetBackupMetadataOffset(metadata->geometry, 0);
359
360 // Corrupt the backup metadata.
361 ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
362 ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
363 EXPECT_EQ(ReadMetadata(opener, "super", 0), nullptr);
364 }
365
366 // Test that we don't attempt to write metadata if it would overflow its
367 // reserved space.
TEST_F(LiblpTest,TooManyPartitions)368 TEST_F(LiblpTest, TooManyPartitions) {
369 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
370 ASSERT_NE(builder, nullptr);
371
372 // Compute the maximum number of partitions we can fit in 512 bytes of
373 // metadata. By default there is the header, one partition group, and a
374 // block device entry.
375 static const size_t kMaxPartitionTableSize = kMetadataSize - sizeof(LpMetadataHeaderV1_0) -
376 sizeof(LpMetadataPartitionGroup) -
377 sizeof(LpMetadataBlockDevice);
378 size_t max_partitions = kMaxPartitionTableSize / sizeof(LpMetadataPartition);
379
380 // Add this number of partitions.
381 Partition* partition = nullptr;
382 for (size_t i = 0; i < max_partitions; i++) {
383 partition = builder->AddPartition(to_string(i), LP_PARTITION_ATTR_NONE);
384 ASSERT_NE(partition, nullptr);
385 }
386
387 unique_ptr<LpMetadata> exported = builder->Export();
388 ASSERT_NE(exported, nullptr);
389
390 unique_fd fd = CreateFakeDisk();
391 ASSERT_GE(fd, 0);
392
393 DefaultPartitionOpener opener(fd);
394
395 // Check that we are able to write our table.
396 ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
397
398 // Check that adding one more partition overflows the metadata allotment.
399 partition = builder->AddPartition("final", LP_PARTITION_ATTR_NONE);
400 EXPECT_NE(partition, nullptr);
401
402 exported = builder->Export();
403 ASSERT_NE(exported, nullptr);
404
405 // The new table should be too large to be written.
406 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *exported.get(), 1));
407
408 auto super_device = GetMetadataSuperBlockDevice(*exported.get());
409 ASSERT_NE(super_device, nullptr);
410
411 // Check that the first and last logical sectors weren't touched when we
412 // wrote this almost-full metadata.
413 char expected[LP_SECTOR_SIZE];
414 memset(expected, 0xcc, sizeof(expected));
415 char buffer[LP_SECTOR_SIZE];
416 ASSERT_GE(lseek(fd, super_device->first_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
417 ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
418 EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
419 }
420
421 // Test that we can read and write image files.
TEST_F(LiblpTest,ImageFiles)422 TEST_F(LiblpTest, ImageFiles) {
423 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
424 ASSERT_NE(builder, nullptr);
425 ASSERT_TRUE(AddDefaultPartitions(builder.get()));
426 unique_ptr<LpMetadata> exported = builder->Export();
427 ASSERT_NE(exported, nullptr);
428
429 unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
430 ASSERT_GE(fd, 0);
431 ASSERT_TRUE(WriteToImageFile(fd, *exported.get()));
432
433 unique_ptr<LpMetadata> imported = ReadFromImageFile(fd);
434 ASSERT_NE(imported, nullptr);
435 }
436
437 // Test that we can read images from buffers.
TEST_F(LiblpTest,ImageFilesInMemory)438 TEST_F(LiblpTest, ImageFilesInMemory) {
439 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
440 ASSERT_NE(builder, nullptr);
441 ASSERT_TRUE(AddDefaultPartitions(builder.get()));
442 unique_ptr<LpMetadata> exported = builder->Export();
443
444 unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
445 ASSERT_GE(fd, 0);
446 ASSERT_TRUE(WriteToImageFile(fd, *exported.get()));
447
448 int64_t offset = SeekFile64(fd, 0, SEEK_CUR);
449 ASSERT_GE(offset, 0);
450 ASSERT_EQ(SeekFile64(fd, 0, SEEK_SET), 0);
451
452 size_t bytes = static_cast<size_t>(offset);
453 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(bytes);
454 ASSERT_TRUE(android::base::ReadFully(fd, buffer.get(), bytes));
455 ASSERT_NE(ReadFromImageBlob(buffer.get(), bytes), nullptr);
456 }
457
458 class BadWriter {
459 public:
460 // When requested, write garbage instead of the requested bytes, then
461 // return false.
operator ()(int fd,const std::string & blob)462 bool operator()(int fd, const std::string& blob) {
463 write_count_++;
464 if (write_count_ == fail_on_write_) {
465 std::unique_ptr<char[]> new_data = std::make_unique<char[]>(blob.size());
466 memset(new_data.get(), 0xe5, blob.size());
467 EXPECT_TRUE(android::base::WriteFully(fd, new_data.get(), blob.size()));
468 return false;
469 } else {
470 if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
471 return false;
472 }
473 return fail_after_write_ != write_count_;
474 }
475 }
Reset()476 void Reset() {
477 fail_on_write_ = 0;
478 fail_after_write_ = 0;
479 write_count_ = 0;
480 }
FailOnWrite(int number)481 void FailOnWrite(int number) {
482 Reset();
483 fail_on_write_ = number;
484 }
FailAfterWrite(int number)485 void FailAfterWrite(int number) {
486 Reset();
487 fail_after_write_ = number;
488 }
489
490 private:
491 int fail_on_write_ = 0;
492 int fail_after_write_ = 0;
493 int write_count_ = 0;
494 };
495
496 // Test that an interrupted flash operation on the "primary" copy of metadata
497 // is not fatal.
TEST_F(LiblpTest,UpdatePrimaryMetadataFailure)498 TEST_F(LiblpTest, UpdatePrimaryMetadataFailure) {
499 unique_fd fd = CreateFlashedDisk();
500 ASSERT_GE(fd, 0);
501
502 DefaultPartitionOpener opener(fd);
503
504 BadWriter writer;
505
506 // Read and write it back.
507 writer.FailOnWrite(1);
508 unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
509 ASSERT_NE(imported, nullptr);
510 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
511
512 // We should still be able to read the backup copy.
513 imported = ReadMetadata(opener, "super", 0);
514 ASSERT_NE(imported, nullptr);
515
516 // Flash again, this time fail the backup copy. We should still be able
517 // to read the primary.
518 writer.FailOnWrite(3);
519 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
520 imported = ReadMetadata(opener, "super", 0);
521 ASSERT_NE(imported, nullptr);
522 }
523
524 // Test that an interrupted flash operation on the "backup" copy of metadata
525 // is not fatal.
TEST_F(LiblpTest,UpdateBackupMetadataFailure)526 TEST_F(LiblpTest, UpdateBackupMetadataFailure) {
527 unique_fd fd = CreateFlashedDisk();
528 ASSERT_GE(fd, 0);
529
530 DefaultPartitionOpener opener(fd);
531
532 BadWriter writer;
533
534 // Read and write it back.
535 writer.FailOnWrite(2);
536 unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
537 ASSERT_NE(imported, nullptr);
538 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
539
540 // We should still be able to read the primary copy.
541 imported = ReadMetadata(opener, "super", 0);
542 ASSERT_NE(imported, nullptr);
543
544 // Flash again, this time fail the primary copy. We should still be able
545 // to read the primary.
546 writer.FailOnWrite(2);
547 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
548 imported = ReadMetadata(opener, "super", 0);
549 ASSERT_NE(imported, nullptr);
550 }
551
552 // Test that an interrupted write *in between* writing metadata will read
553 // the correct metadata copy. The primary is always considered newer than
554 // the backup.
TEST_F(LiblpTest,UpdateMetadataCleanFailure)555 TEST_F(LiblpTest, UpdateMetadataCleanFailure) {
556 unique_fd fd = CreateFlashedDisk();
557 ASSERT_GE(fd, 0);
558
559 DefaultPartitionOpener opener(fd);
560
561 BadWriter writer;
562
563 // Change the name of the existing partition.
564 unique_ptr<LpMetadata> new_table = ReadMetadata(opener, "super", 0);
565 ASSERT_NE(new_table, nullptr);
566 ASSERT_GE(new_table->partitions.size(), 1);
567 new_table->partitions[0].name[0]++;
568
569 // Flash it, but fail to write the backup copy.
570 writer.FailAfterWrite(2);
571 ASSERT_FALSE(UpdatePartitionTable(opener, "super", *new_table.get(), 0, writer));
572
573 // When we read back, we should get the updated primary copy.
574 unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
575 ASSERT_NE(imported, nullptr);
576 ASSERT_GE(new_table->partitions.size(), 1);
577 ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
578
579 // Flash again. After, the backup and primary copy should be coherent.
580 // Note that the sync step should have used the primary to sync, not
581 // the backup.
582 writer.Reset();
583 ASSERT_TRUE(UpdatePartitionTable(opener, "super", *new_table.get(), 0, writer));
584
585 imported = ReadMetadata(opener, "super", 0);
586 ASSERT_NE(imported, nullptr);
587 ASSERT_GE(new_table->partitions.size(), 1);
588 ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
589 }
590
591 // Test that writing a sparse image can be read back.
TEST_F(LiblpTest,FlashSparseImage)592 TEST_F(LiblpTest, FlashSparseImage) {
593 unique_fd fd = CreateFakeDisk();
594 ASSERT_GE(fd, 0);
595
596 BlockDeviceInfo device_info("super", kDiskSize, 0, 0, 512);
597 unique_ptr<MetadataBuilder> builder =
598 MetadataBuilder::New(device_info, kMetadataSize, kMetadataSlots);
599 ASSERT_NE(builder, nullptr);
600 ASSERT_TRUE(AddDefaultPartitions(builder.get()));
601
602 unique_ptr<LpMetadata> exported = builder->Export();
603 ASSERT_NE(exported, nullptr);
604
605 // Build the sparse file.
606 ImageBuilder sparse(*exported.get(), 512, {}, true /* sparsify */);
607 ASSERT_TRUE(sparse.IsValid());
608 ASSERT_TRUE(sparse.Build());
609
610 const auto& images = sparse.device_images();
611 ASSERT_EQ(images.size(), static_cast<size_t>(1));
612
613 // Write it to the fake disk.
614 ASSERT_NE(lseek(fd.get(), 0, SEEK_SET), -1);
615 int ret = sparse_file_write(images[0].get(), fd.get(), false, false, false);
616 ASSERT_EQ(ret, 0);
617
618 // Verify that we can read both sets of metadata.
619 LpMetadataGeometry geometry;
620 ASSERT_TRUE(ReadPrimaryGeometry(fd.get(), &geometry));
621 ASSERT_TRUE(ReadBackupGeometry(fd.get(), &geometry));
622 ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
623 ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
624 }
625
TEST_F(LiblpTest,AutoSlotSuffixing)626 TEST_F(LiblpTest, AutoSlotSuffixing) {
627 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
628 ASSERT_NE(builder, nullptr);
629 ASSERT_TRUE(AddDefaultPartitions(builder.get()));
630 ASSERT_TRUE(builder->AddGroup("example", 0));
631 builder->SetAutoSlotSuffixing();
632
633 auto fd = CreateFakeDisk();
634 ASSERT_GE(fd, 0);
635
636 // Note: we bind the same fd to both names, since we want to make sure the
637 // exact same bits are getting read back in each test.
638 TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
639 {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
640 auto exported = builder->Export();
641 ASSERT_NE(exported, nullptr);
642 ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));
643
644 auto metadata = ReadMetadata(opener, "super_b", 1);
645 ASSERT_NE(metadata, nullptr);
646 ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
647 EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_b");
648 ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
649 EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_b");
650 ASSERT_EQ(metadata->groups.size(), static_cast<size_t>(2));
651 EXPECT_EQ(GetPartitionGroupName(metadata->groups[0]), "default");
652 EXPECT_EQ(GetPartitionGroupName(metadata->groups[1]), "example_b");
653 EXPECT_EQ(metadata->groups[0].flags, 0);
654 EXPECT_EQ(metadata->groups[1].flags, 0);
655
656 metadata = ReadMetadata(opener, "super_a", 0);
657 ASSERT_NE(metadata, nullptr);
658 ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
659 EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_a");
660 ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
661 EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
662 ASSERT_EQ(metadata->groups.size(), static_cast<size_t>(2));
663 EXPECT_EQ(GetPartitionGroupName(metadata->groups[0]), "default");
664 EXPECT_EQ(GetPartitionGroupName(metadata->groups[1]), "example_a");
665 EXPECT_EQ(metadata->groups[0].flags, 0);
666 EXPECT_EQ(metadata->groups[1].flags, 0);
667 }
668
TEST_F(LiblpTest,UpdateRetrofit)669 TEST_F(LiblpTest, UpdateRetrofit) {
670 ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
671 .WillByDefault(Return(true));
672
673 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
674 ASSERT_NE(builder, nullptr);
675 ASSERT_TRUE(AddDefaultPartitions(builder.get()));
676 ASSERT_TRUE(builder->AddGroup("example", 0));
677 builder->SetAutoSlotSuffixing();
678
679 auto fd = CreateFakeDisk();
680 ASSERT_GE(fd, 0);
681
682 // Note: we bind the same fd to both names, since we want to make sure the
683 // exact same bits are getting read back in each test.
684 TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
685 {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
686 auto exported = builder->Export();
687 ASSERT_NE(exported, nullptr);
688 ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));
689
690 builder = MetadataBuilder::NewForUpdate(opener, "super_a", 0, 1);
691 ASSERT_NE(builder, nullptr);
692 auto updated = builder->Export();
693 ASSERT_NE(updated, nullptr);
694 ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
695 EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_b");
696 ASSERT_TRUE(updated->groups.empty());
697 ASSERT_TRUE(updated->partitions.empty());
698 ASSERT_TRUE(updated->extents.empty());
699 }
700
TEST_F(LiblpTest,UpdateNonRetrofit)701 TEST_F(LiblpTest, UpdateNonRetrofit) {
702 ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
703 .WillByDefault(Return(false));
704
705 unique_fd fd = CreateFlashedDisk();
706 ASSERT_GE(fd, 0);
707
708 DefaultPartitionOpener opener(fd);
709 auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
710 ASSERT_NE(builder, nullptr);
711 auto updated = builder->Export();
712 ASSERT_NE(updated, nullptr);
713 ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
714 EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super");
715 }
716
TEST_F(LiblpTest,UpdateVirtualAB)717 TEST_F(LiblpTest, UpdateVirtualAB) {
718 ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _))
719 .WillByDefault(Return(true));
720
721 unique_fd fd = CreateFlashedDisk();
722 ASSERT_GE(fd, 0);
723
724 DefaultPartitionOpener opener(fd);
725 auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
726 ASSERT_NE(builder, nullptr);
727 auto updated = builder->Export();
728 ASSERT_NE(updated, nullptr);
729 ASSERT_TRUE(UpdatePartitionTable(opener, "super", *updated.get(), 1));
730
731 // Validate old slot.
732 auto metadata = ReadMetadata(opener, "super", 0);
733 ASSERT_NE(metadata, nullptr);
734 ASSERT_EQ(metadata->header.minor_version, 0);
735 ASSERT_GE(metadata->partitions.size(), 1);
736 ASSERT_EQ(metadata->partitions[0].attributes & LP_PARTITION_ATTR_UPDATED, 0);
737
738 // Validate new slot.
739 metadata = ReadMetadata(opener, "super", 1);
740 ASSERT_NE(metadata, nullptr);
741 ASSERT_EQ(metadata->header.minor_version, 1);
742 ASSERT_GE(metadata->partitions.size(), 1);
743 ASSERT_NE(metadata->partitions[0].attributes & LP_PARTITION_ATTR_UPDATED, 0);
744 }
745
TEST_F(LiblpTest,ReadExpandedHeader)746 TEST_F(LiblpTest, ReadExpandedHeader) {
747 unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
748 ASSERT_NE(builder, nullptr);
749 ASSERT_TRUE(AddDefaultPartitions(builder.get()));
750
751 builder->RequireExpandedMetadataHeader();
752
753 unique_fd fd = CreateFakeDisk();
754 ASSERT_GE(fd, 0);
755
756 DefaultPartitionOpener opener(fd);
757
758 // Export and flash.
759 unique_ptr<LpMetadata> exported = builder->Export();
760 ASSERT_NE(exported, nullptr);
761 exported->header.flags = 0x5e5e5e5e;
762 ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
763
764 unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
765 ASSERT_NE(imported, nullptr);
766 EXPECT_EQ(imported->header.header_size, sizeof(LpMetadataHeaderV1_2));
767 EXPECT_EQ(imported->header.header_size, exported->header.header_size);
768 EXPECT_EQ(imported->header.flags, exported->header.flags);
769 }
770