/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "reader.h" #include "super_vbmeta_format.h" #include "utility.h" #include "writer.h" #define FAKE_DATA_SIZE 40960 #define FAKE_PARTITION_SIZE FAKE_DATA_SIZE * 25 using android::base::Result; using android::fs_mgr::GetFileSize; using android::fs_mgr::ReadVBMetaImage; using SparsePtr = std::unique_ptr; void GeneratePartitionImage(int fd, const std::string& file_name, const std::string& partition_name) { std::unique_ptr buffer = std::make_unique(FAKE_DATA_SIZE); for (size_t c = 0; c < FAKE_DATA_SIZE; c++) { buffer[c] = uint8_t(c); } SparsePtr file(sparse_file_new(512 /* block size */, FAKE_DATA_SIZE), sparse_file_destroy); EXPECT_TRUE(file); EXPECT_EQ(0, sparse_file_add_data(file.get(), buffer.get(), FAKE_DATA_SIZE, 0 /* offset in blocks */)); EXPECT_EQ(0, sparse_file_write(file.get(), fd, false /* gz */, true /* sparse */, false /* crc */)); std::stringstream cmd; cmd << "avbtool add_hashtree_footer" << " --image " << file_name << " --partition_name " << partition_name << " --partition_size " << FAKE_PARTITION_SIZE << " --algorithm SHA256_RSA2048" << " --key data/testkey_rsa2048.pem"; int rc = system(cmd.str().c_str()); EXPECT_TRUE(WIFEXITED(rc)); EXPECT_EQ(WEXITSTATUS(rc), 0); } void GenerateVBMetaImage(const std::string& vbmeta_file_name, const std::string& include_file_name) { std::stringstream cmd; cmd << "avbtool make_vbmeta_image" << " --output " << vbmeta_file_name << " --include_descriptors_from_image " << include_file_name; int rc = system(cmd.str().c_str()); EXPECT_TRUE(WIFEXITED(rc)); EXPECT_EQ(WEXITSTATUS(rc), 0); } std::string ReadVBMetaImageFromFile(const std::string& file) { android::base::unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC)); EXPECT_GT(fd, 0); Result file_size = GetFileSize(fd); EXPECT_RESULT_OK(file_size); std::unique_ptr buffer = std::make_unique(VBMETA_IMAGE_MAX_SIZE); EXPECT_TRUE(android::base::ReadFully(fd, buffer.get(), file_size.value())); return std::string(reinterpret_cast(buffer.get()), VBMETA_IMAGE_MAX_SIZE); } TEST(VBMetaTableTest, VBMetaTableBasic) { TemporaryDir td; // Generate Partition Image TemporaryFile system_tf(std::string(td.path)); std::string system_path(system_tf.path); GeneratePartitionImage(system_tf.fd, system_path, "system"); system_tf.release(); TemporaryFile vendor_tf(std::string(td.path)); std::string vendor_path(vendor_tf.path); GeneratePartitionImage(vendor_tf.fd, vendor_path, "vendor"); vendor_tf.release(); TemporaryFile product_tf(std::string(td.path)); std::string product_path(product_tf.path); GeneratePartitionImage(product_tf.fd, product_path, "product"); product_tf.release(); // Generate VBMeta Image std::string vbmeta_system_path(td.path); vbmeta_system_path.append("/vbmeta_system.img"); GenerateVBMetaImage(vbmeta_system_path, system_path); std::string vbmeta_vendor_path(td.path); vbmeta_vendor_path.append("/vbmeta_vendor.img"); GenerateVBMetaImage(vbmeta_vendor_path, vendor_path); std::string vbmeta_product_path(td.path); vbmeta_product_path.append("/vbmeta_product.img"); GenerateVBMetaImage(vbmeta_product_path, product_path); // Generate Super VBMeta Image std::string super_vbmeta_path(td.path); super_vbmeta_path.append("/super_vbmeta.img"); std::stringstream cmd; cmd << "vbmake" << " --image " << "vbmeta_system" << "=" << vbmeta_system_path << " --image " << "vbmeta_vendor" << "=" << vbmeta_vendor_path << " --image " << "vbmeta_product" << "=" << vbmeta_product_path << " --output=" << super_vbmeta_path; int rc = system(cmd.str().c_str()); ASSERT_TRUE(WIFEXITED(rc)); ASSERT_EQ(WEXITSTATUS(rc), 0); android::base::unique_fd fd(open(super_vbmeta_path.c_str(), O_RDONLY | O_CLOEXEC)); EXPECT_GT(fd, 0); // Check the size of vbmeta table Result super_vbmeta_size = GetFileSize(fd); EXPECT_RESULT_OK(super_vbmeta_size); EXPECT_EQ(super_vbmeta_size.value(), SUPER_VBMETA_TABLE_MAX_SIZE * 2 + VBMETA_IMAGE_MAX_SIZE * 3); // Check Primary vbmeta table is equal to Backup one VBMetaTable table; EXPECT_RESULT_OK(android::fs_mgr::ReadPrimaryVBMetaTable(fd, &table)); VBMetaTable table_backup; EXPECT_RESULT_OK(android::fs_mgr::ReadBackupVBMetaTable(fd, &table_backup)); EXPECT_EQ(android::fs_mgr::SerializeVBMetaTable(table), android::fs_mgr::SerializeVBMetaTable(table_backup)); // Check vbmeta table Header Checksum std::string serial_table = android::fs_mgr::SerializeVBMetaTable(table); std::string serial_removed_checksum(serial_table); // Replace checksum 32 bytes (starts at 16th byte) with 0 serial_removed_checksum.replace(16, 32, 32, 0); uint8_t test_checksum[32]; ::SHA256(reinterpret_cast(serial_removed_checksum.c_str()), table.header.total_size, &test_checksum[0]); EXPECT_EQ(memcmp(table.header.checksum, test_checksum, 32), 0); // Check vbmeta table descriptors and vbmeta images EXPECT_EQ(table.descriptors.size(), 3); EXPECT_EQ(table.descriptors[0].vbmeta_index, 0); EXPECT_EQ(table.descriptors[0].vbmeta_name_length, 14); EXPECT_EQ(table.descriptors[0].vbmeta_name, "vbmeta_product"); Result vbmeta_product_content = ReadVBMetaImage(fd, 0); EXPECT_RESULT_OK(vbmeta_product_content); EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_product_path), vbmeta_product_content.value()); EXPECT_EQ(table.descriptors[1].vbmeta_index, 1); EXPECT_EQ(table.descriptors[1].vbmeta_name_length, 13); EXPECT_EQ(table.descriptors[1].vbmeta_name, "vbmeta_system"); Result vbmeta_system_content = ReadVBMetaImage(fd, 1); EXPECT_RESULT_OK(vbmeta_system_content); EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_system_path), vbmeta_system_content.value()); EXPECT_EQ(table.descriptors[2].vbmeta_index, 2); EXPECT_EQ(table.descriptors[2].vbmeta_name_length, 13); EXPECT_EQ(table.descriptors[2].vbmeta_name, "vbmeta_vendor"); Result vbmeta_vendor_content = ReadVBMetaImage(fd, 2); EXPECT_RESULT_OK(vbmeta_vendor_content); EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_vendor_path), vbmeta_vendor_content.value()); } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }