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