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