blob: 6b4fc5d338c122c36f486c9ce9c9c70a07477beb [file] [log] [blame]
/*
* 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 <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <android-base/file.h>
#include <gtest/gtest.h>
#include <openssl/sha.h>
#include <sparse/sparse.h>
#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<sparse_file, decltype(&sparse_file_destroy)>;
void GeneratePartitionImage(int fd, const std::string& file_name,
const std::string& partition_name) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(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 external/avb/test/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<uint64_t> file_size = GetFileSize(fd);
EXPECT_TRUE(file_size);
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
EXPECT_TRUE(android::base::ReadFully(fd, buffer.get(), file_size.value()));
return std::string(reinterpret_cast<char*>(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<uint64_t> super_vbmeta_size = GetFileSize(fd);
EXPECT_TRUE(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_TRUE(android::fs_mgr::ReadPrimaryVBMetaTable(fd, &table));
VBMetaTable table_backup;
EXPECT_TRUE(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<const uint8_t*>(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<std::string> vbmeta_product_content = ReadVBMetaImage(fd, 0);
EXPECT_TRUE(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<std::string> vbmeta_system_content = ReadVBMetaImage(fd, 1);
EXPECT_TRUE(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<std::string> vbmeta_vendor_content = ReadVBMetaImage(fd, 2);
EXPECT_TRUE(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();
}