Merge "libfs_avb: support loading vbmeta structs from any partition"
am: 8dd6e5922b
Change-Id: If427c749caaa10b1c5f2bf2c239c982175f37806
This commit is contained in:
commit
035e2855db
14 changed files with 2112 additions and 56 deletions
|
|
@ -34,6 +34,12 @@ static std::string other_suffix(const std::string& slot_suffix) {
|
|||
return "";
|
||||
}
|
||||
|
||||
// Returns "_b" or "_a", which is *the other* slot of androidboot.slot_suffix
|
||||
// in kernel cmdline, or an empty string if that parameter does not exist.
|
||||
std::string fs_mgr_get_other_slot_suffix() {
|
||||
return other_suffix(fs_mgr_get_slot_suffix());
|
||||
}
|
||||
|
||||
// Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
|
||||
// if that parameter does not exist.
|
||||
std::string fs_mgr_get_slot_suffix() {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
|
|||
int fs_mgr_is_fs_verity(const struct fstab_rec* fstab);
|
||||
|
||||
std::string fs_mgr_get_slot_suffix();
|
||||
std::string fs_mgr_get_other_slot_suffix();
|
||||
std::set<std::string> fs_mgr_get_boot_devices();
|
||||
|
||||
struct FstabEntry {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,11 @@ cc_defaults {
|
|||
"tests/data/*",
|
||||
],
|
||||
static_libs: [
|
||||
"libavb",
|
||||
"libavb_host_sysdeps",
|
||||
"libdm",
|
||||
"libfs_avb",
|
||||
"libfstab",
|
||||
"libgtest_host",
|
||||
],
|
||||
shared_libs: [
|
||||
|
|
@ -86,8 +91,12 @@ cc_test_host {
|
|||
static_libs: [
|
||||
"libfs_avb_test_util",
|
||||
],
|
||||
shared_libs: [
|
||||
"libcrypto",
|
||||
],
|
||||
srcs: [
|
||||
"tests/basic_test.cpp",
|
||||
"tests/fs_avb_test.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
@ -96,10 +105,11 @@ cc_test_host {
|
|||
defaults: ["libfs_avb_host_test_defaults"],
|
||||
static_libs: [
|
||||
"libfs_avb_test_util",
|
||||
"libfstab",
|
||||
],
|
||||
srcs: [
|
||||
"avb_util.cpp",
|
||||
"util.cpp",
|
||||
"tests/avb_util_test.cpp",
|
||||
"tests/util_test.cpp",
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android-base/macros.h>
|
||||
|
|
@ -190,7 +191,8 @@ AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
|
|||
// Copies avb_slot_data->vbmeta_images[].
|
||||
for (size_t i = 0; i < avb_slot_data->num_vbmeta_images; i++) {
|
||||
out_vbmeta_images->emplace_back(VBMetaData(avb_slot_data->vbmeta_images[i].vbmeta_data,
|
||||
avb_slot_data->vbmeta_images[i].vbmeta_size));
|
||||
avb_slot_data->vbmeta_images[i].vbmeta_size,
|
||||
avb_slot_data->vbmeta_images[i].partition_name));
|
||||
}
|
||||
|
||||
// Free the local resource.
|
||||
|
|
|
|||
|
|
@ -16,19 +16,67 @@
|
|||
|
||||
#include "avb_util.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
using android::base::StartsWith;
|
||||
using android::base::unique_fd;
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
// Helper functions to print enum class VBMetaVerifyResult.
|
||||
const char* VBMetaVerifyResultToString(VBMetaVerifyResult result) {
|
||||
// clang-format off
|
||||
static const char* const name[] = {
|
||||
"ResultSuccess",
|
||||
"ResultError",
|
||||
"ResultErrorVerification",
|
||||
"ResultUnknown",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
uint32_t index = static_cast<uint32_t>(result);
|
||||
uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
|
||||
if (index >= unknown_index) {
|
||||
index = unknown_index;
|
||||
}
|
||||
|
||||
return name[index];
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult result) {
|
||||
os << VBMetaVerifyResultToString(result);
|
||||
return os;
|
||||
}
|
||||
|
||||
// class VBMetaData
|
||||
// ----------------
|
||||
std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) {
|
||||
auto vbmeta_header(std::make_unique<AvbVBMetaImageHeader>());
|
||||
|
||||
if (!vbmeta_header) return nullptr;
|
||||
|
||||
/* Byteswap the header. */
|
||||
avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_ptr_.get(),
|
||||
vbmeta_header.get());
|
||||
if (update_vbmeta_size) {
|
||||
vbmeta_size_ = sizeof(AvbVBMetaImageHeader) +
|
||||
vbmeta_header->authentication_data_block_size +
|
||||
vbmeta_header->auxiliary_data_block_size;
|
||||
}
|
||||
|
||||
return vbmeta_header;
|
||||
}
|
||||
|
||||
// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
|
||||
// See the following link for more details:
|
||||
// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
|
||||
|
|
@ -173,5 +221,300 @@ bool GetHashtreeDescriptor(const std::string& partition_name,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Converts a AVB partition_name (without A/B suffix) to a device partition name.
|
||||
// e.g., "system" => "system_a",
|
||||
// "system_other" => "system_b".
|
||||
//
|
||||
// If the device is non-A/B, converts it to a partition name without suffix.
|
||||
// e.g., "system" => "system",
|
||||
// "system_other" => "system".
|
||||
std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
|
||||
const std::string& ab_suffix,
|
||||
const std::string& ab_other_suffix) {
|
||||
bool is_other_slot = false;
|
||||
std::string sanitized_partition_name(avb_partition_name);
|
||||
|
||||
auto other_suffix = sanitized_partition_name.rfind("_other");
|
||||
if (other_suffix != std::string::npos) {
|
||||
sanitized_partition_name.erase(other_suffix); // converts system_other => system
|
||||
is_other_slot = true;
|
||||
}
|
||||
|
||||
auto append_suffix = is_other_slot ? ab_other_suffix : ab_suffix;
|
||||
return sanitized_partition_name + append_suffix;
|
||||
}
|
||||
|
||||
off64_t GetTotalSize(int fd) {
|
||||
off64_t saved_current = lseek64(fd, 0, SEEK_CUR);
|
||||
if (saved_current == -1) {
|
||||
PERROR << "Failed to get current position";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// lseek64() returns the resulting offset location from the beginning of the file.
|
||||
off64_t total_size = lseek64(fd, 0, SEEK_END);
|
||||
if (total_size == -1) {
|
||||
PERROR << "Failed to lseek64 to end of the partition";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Restores the original offset.
|
||||
if (lseek64(fd, saved_current, SEEK_SET) == -1) {
|
||||
PERROR << "Failed to lseek64 to the original offset: " << saved_current;
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
std::unique_ptr<AvbFooter> GetAvbFooter(int fd) {
|
||||
std::array<uint8_t, AVB_FOOTER_SIZE> footer_buf;
|
||||
auto footer(std::make_unique<AvbFooter>());
|
||||
|
||||
off64_t footer_offset = GetTotalSize(fd) - AVB_FOOTER_SIZE;
|
||||
|
||||
ssize_t num_read =
|
||||
TEMP_FAILURE_RETRY(pread64(fd, footer_buf.data(), AVB_FOOTER_SIZE, footer_offset));
|
||||
if (num_read < 0 || num_read != AVB_FOOTER_SIZE) {
|
||||
PERROR << "Failed to read AVB footer";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf.data(), footer.get())) {
|
||||
PERROR << "AVB footer verification failed.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return footer;
|
||||
}
|
||||
|
||||
bool VerifyPublicKeyBlob(const uint8_t* key, size_t length, const std::string& expected_key_blob) {
|
||||
if (expected_key_blob.empty()) { // no expectation of the key, return true.
|
||||
return true;
|
||||
}
|
||||
if (expected_key_blob.size() != length) {
|
||||
return false;
|
||||
}
|
||||
if (0 == memcmp(key, expected_key_blob.data(), length)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VBMetaVerifyResult VerifyVBMetaSignature(const VBMetaData& vbmeta,
|
||||
const std::string& expected_public_key_blob) {
|
||||
const uint8_t* pk_data;
|
||||
size_t pk_len;
|
||||
::AvbVBMetaVerifyResult vbmeta_ret;
|
||||
|
||||
vbmeta_ret = avb_vbmeta_image_verify(vbmeta.data(), vbmeta.size(), &pk_data, &pk_len);
|
||||
|
||||
switch (vbmeta_ret) {
|
||||
case AVB_VBMETA_VERIFY_RESULT_OK:
|
||||
if (pk_data == nullptr || pk_len <= 0) {
|
||||
LERROR << vbmeta.partition()
|
||||
<< ": Error verifying vbmeta image: failed to get public key";
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
if (!VerifyPublicKeyBlob(pk_data, pk_len, expected_public_key_blob)) {
|
||||
LERROR << vbmeta.partition() << ": Error verifying vbmeta image: public key used to"
|
||||
<< " sign data does not match key in chain descriptor";
|
||||
return VBMetaVerifyResult::kErrorVerification;
|
||||
}
|
||||
return VBMetaVerifyResult::kSuccess;
|
||||
case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
|
||||
case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
|
||||
case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
|
||||
LERROR << vbmeta.partition() << ": Error verifying vbmeta image: "
|
||||
<< avb_vbmeta_verify_result_to_string(vbmeta_ret);
|
||||
return VBMetaVerifyResult::kErrorVerification;
|
||||
case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
|
||||
// No way to continue this case.
|
||||
LERROR << vbmeta.partition() << ": Error verifying vbmeta image: invalid vbmeta header";
|
||||
break;
|
||||
case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
|
||||
// No way to continue this case.
|
||||
LERROR << vbmeta.partition()
|
||||
<< ": Error verifying vbmeta image: unsupported AVB version";
|
||||
break;
|
||||
default:
|
||||
LERROR << "Unknown vbmeta image verify return value: " << vbmeta_ret;
|
||||
break;
|
||||
}
|
||||
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
std::unique_ptr<VBMetaData> VerifyVBMetaData(int fd, const std::string& partition_name,
|
||||
const std::string& expected_public_key_blob,
|
||||
VBMetaVerifyResult* out_verify_result) {
|
||||
uint64_t vbmeta_offset = 0;
|
||||
uint64_t vbmeta_size = VBMetaData::kMaxVBMetaSize;
|
||||
bool is_vbmeta_partition = StartsWith(partition_name, "vbmeta");
|
||||
|
||||
if (!is_vbmeta_partition) {
|
||||
std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
|
||||
if (!footer) {
|
||||
return nullptr;
|
||||
}
|
||||
vbmeta_offset = footer->vbmeta_offset;
|
||||
vbmeta_size = footer->vbmeta_size;
|
||||
}
|
||||
|
||||
if (vbmeta_size > VBMetaData::kMaxVBMetaSize) {
|
||||
LERROR << "VbMeta size in footer exceeds kMaxVBMetaSize";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto vbmeta = std::make_unique<VBMetaData>(vbmeta_size, partition_name);
|
||||
ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, vbmeta->data(), vbmeta_size, vbmeta_offset));
|
||||
// Allows partial read for vbmeta partition, because its vbmeta_size is kMaxVBMetaSize.
|
||||
if (num_read < 0 || (!is_vbmeta_partition && static_cast<uint64_t>(num_read) != vbmeta_size)) {
|
||||
PERROR << partition_name << ": Failed to read vbmeta at offset " << vbmeta_offset
|
||||
<< " with size " << vbmeta_size;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto verify_result = VerifyVBMetaSignature(*vbmeta, expected_public_key_blob);
|
||||
if (out_verify_result != nullptr) *out_verify_result = verify_result;
|
||||
|
||||
if (verify_result == VBMetaVerifyResult::kSuccess ||
|
||||
verify_result == VBMetaVerifyResult::kErrorVerification) {
|
||||
return vbmeta;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool RollbackDetected(const std::string& partition_name ATTRIBUTE_UNUSED,
|
||||
uint64_t rollback_index ATTRIBUTE_UNUSED) {
|
||||
// TODO(bowgotsai): Support rollback protection.
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error) {
|
||||
CHECK(fatal_error != nullptr);
|
||||
std::vector<ChainInfo> chain_partitions;
|
||||
|
||||
size_t num_descriptors;
|
||||
std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
|
||||
avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
|
||||
|
||||
if (!descriptors || num_descriptors < 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_descriptors; i++) {
|
||||
AvbDescriptor desc;
|
||||
if (!avb_descriptor_validate_and_byteswap(descriptors[i], &desc)) {
|
||||
LERROR << "Descriptor[" << i << "] is invalid in vbmeta: " << vbmeta.partition();
|
||||
*fatal_error = true;
|
||||
return {};
|
||||
}
|
||||
if (desc.tag == AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) {
|
||||
AvbChainPartitionDescriptor chain_desc;
|
||||
if (!avb_chain_partition_descriptor_validate_and_byteswap(
|
||||
(AvbChainPartitionDescriptor*)descriptors[i], &chain_desc)) {
|
||||
LERROR << "Chain descriptor[" << i
|
||||
<< "] is invalid in vbmeta: " << vbmeta.partition();
|
||||
*fatal_error = true;
|
||||
return {};
|
||||
}
|
||||
const char* chain_partition_name =
|
||||
((const char*)descriptors[i]) + sizeof(AvbChainPartitionDescriptor);
|
||||
const char* chain_public_key_blob =
|
||||
chain_partition_name + chain_desc.partition_name_len;
|
||||
chain_partitions.emplace_back(
|
||||
std::string(chain_partition_name, chain_desc.partition_name_len),
|
||||
std::string(chain_public_key_blob, chain_desc.public_key_len));
|
||||
}
|
||||
}
|
||||
|
||||
return chain_partitions;
|
||||
}
|
||||
|
||||
VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
|
||||
const std::string& partition_name, const std::string& ab_suffix,
|
||||
const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
|
||||
bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
|
||||
std::function<std::string(const std::string&)> device_path_constructor,
|
||||
bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) {
|
||||
// Ensures the device path (might be a symlink created by init) is ready to access.
|
||||
auto device_path = device_path_constructor(
|
||||
AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix));
|
||||
if (!WaitForFile(device_path, 1s)) {
|
||||
PERROR << "No such partition: " << device_path;
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
unique_fd fd(TEMP_FAILURE_RETRY(open(device_path.c_str(), O_RDONLY | O_CLOEXEC)));
|
||||
if (fd < 0) {
|
||||
PERROR << "Failed to open: " << device_path;
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
VBMetaVerifyResult verify_result;
|
||||
std::unique_ptr<VBMetaData> vbmeta =
|
||||
VerifyVBMetaData(fd, partition_name, expected_public_key_blob, &verify_result);
|
||||
if (!vbmeta) {
|
||||
LERROR << partition_name << ": Failed to load vbmeta, result: " << verify_result;
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
if (!allow_verification_error && verify_result == VBMetaVerifyResult::kErrorVerification) {
|
||||
LERROR << partition_name << ": allow verification error is not allowed";
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header =
|
||||
vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
|
||||
if (!vbmeta_header) {
|
||||
LERROR << partition_name << ": Failed to get vbmeta header";
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
if (rollback_protection && RollbackDetected(partition_name, vbmeta_header->rollback_index)) {
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
// vbmeta flags can only be set by the top-level vbmeta image.
|
||||
if (is_chained_vbmeta && vbmeta_header->flags != 0) {
|
||||
LERROR << partition_name << ": chained vbmeta image has non-zero flags";
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
|
||||
if (out_vbmeta_images) {
|
||||
out_vbmeta_images->emplace_back(std::move(*vbmeta));
|
||||
}
|
||||
|
||||
// If verification has been disabled by setting a bit in the image, we're done.
|
||||
if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
|
||||
LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name;
|
||||
return verify_result;
|
||||
}
|
||||
|
||||
if (load_chained_vbmeta) {
|
||||
bool fatal_error = false;
|
||||
auto chain_partitions = GetChainPartitionInfo(*out_vbmeta_images->rbegin(), &fatal_error);
|
||||
if (fatal_error) {
|
||||
return VBMetaVerifyResult::kError;
|
||||
}
|
||||
for (auto& chain : chain_partitions) {
|
||||
auto sub_ret = LoadAndVerifyVbmetaImpl(
|
||||
chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob,
|
||||
allow_verification_error, load_chained_vbmeta, rollback_protection,
|
||||
device_path_constructor, true, /* is_chained_vbmeta */
|
||||
out_vbmeta_images);
|
||||
if (sub_ret != VBMetaVerifyResult::kSuccess) {
|
||||
verify_result = sub_ret; // might be 'ERROR' or 'ERROR VERIFICATION'.
|
||||
if (verify_result == VBMetaVerifyResult::kError) {
|
||||
return verify_result; // stop here if we got an 'ERROR'.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return verify_result;
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fstab/fstab.h>
|
||||
#include <libavb/libavb.h>
|
||||
#include <libdm/dm.h>
|
||||
|
||||
|
|
@ -27,6 +29,22 @@
|
|||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
enum class VBMetaVerifyResult {
|
||||
kSuccess = 0,
|
||||
kError = 1,
|
||||
kErrorVerification = 2,
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult);
|
||||
|
||||
struct ChainInfo {
|
||||
std::string partition_name;
|
||||
std::string public_key_blob;
|
||||
|
||||
ChainInfo(const std::string& chain_partition_name, const std::string& chain_public_key_blob)
|
||||
: partition_name(chain_partition_name), public_key_blob(chain_public_key_blob) {}
|
||||
};
|
||||
|
||||
// AvbHashtreeDescriptor to dm-verity table setup.
|
||||
bool GetHashtreeDescriptor(const std::string& partition_name,
|
||||
const std::vector<VBMetaData>& vbmeta_images,
|
||||
|
|
@ -41,5 +59,37 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor&
|
|||
const std::string& salt, const std::string& root_digest,
|
||||
bool wait_for_verity_dev);
|
||||
|
||||
// Maps AVB partition name to a device partition name.
|
||||
std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
|
||||
const std::string& ab_suffix,
|
||||
const std::string& ab_other_suffix);
|
||||
|
||||
// AvbFooter and AvbMetaImage maninpulations.
|
||||
off64_t GetTotalSize(int fd);
|
||||
|
||||
std::unique_ptr<AvbFooter> GetAvbFooter(int fd);
|
||||
|
||||
std::unique_ptr<VBMetaData> VerifyVBMetaData(int fd, const std::string& partition_name,
|
||||
const std::string& expected_public_key_blob,
|
||||
VBMetaVerifyResult* out_verify_result);
|
||||
|
||||
VBMetaVerifyResult VerifyVBMetaSignature(const VBMetaData& vbmeta,
|
||||
const std::string& expected_public_key_blob);
|
||||
|
||||
bool VerifyPublicKeyBlob(const uint8_t* key, size_t length, const std::string& expected_key_blob);
|
||||
|
||||
// Detects if whether a partition contains a rollback image.
|
||||
bool RollbackDetected(const std::string& partition_name, uint64_t rollback_index);
|
||||
|
||||
// Extracts chain partition info.
|
||||
std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error);
|
||||
|
||||
VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
|
||||
const std::string& partition_name, const std::string& ab_suffix,
|
||||
const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
|
||||
bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
|
||||
std::function<std::string(const std::string&)> device_path_constructor,
|
||||
bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images);
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
using android::base::Basename;
|
||||
using android::base::ParseUint;
|
||||
using android::base::ReadFileToString;
|
||||
using android::base::StringPrintf;
|
||||
|
||||
namespace android {
|
||||
|
|
@ -59,6 +60,51 @@ std::pair<size_t, bool> VerifyVbmetaDigest(const std::vector<VBMetaData>& vbmeta
|
|||
return std::make_pair(total_size, matched);
|
||||
}
|
||||
|
||||
template <typename Hasher>
|
||||
std::pair<std::string, size_t> CalculateVbmetaDigest(const std::vector<VBMetaData>& vbmeta_images) {
|
||||
std::string digest;
|
||||
size_t total_size = 0;
|
||||
|
||||
Hasher hasher;
|
||||
for (const auto& vbmeta : vbmeta_images) {
|
||||
hasher.update(vbmeta.data(), vbmeta.size());
|
||||
total_size += vbmeta.size();
|
||||
}
|
||||
|
||||
// Converts digest bytes to a hex string.
|
||||
digest = BytesToHex(hasher.finalize(), Hasher::DIGEST_SIZE);
|
||||
return std::make_pair(digest, total_size);
|
||||
}
|
||||
|
||||
// Helper functions to dump enum class AvbHandleStatus.
|
||||
const char* AvbHandleStatusToString(AvbHandleStatus status) {
|
||||
// clang-format off
|
||||
static const char* const name[] = {
|
||||
"Success",
|
||||
"Uninitialized",
|
||||
"HashtreeDisabled",
|
||||
"VerificationDisabled",
|
||||
"VerificationError",
|
||||
"Unknown",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
uint32_t index = static_cast<uint32_t>(status);
|
||||
uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
|
||||
if (index >= unknown_index) {
|
||||
index = unknown_index;
|
||||
}
|
||||
|
||||
return name[index];
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, AvbHandleStatus status) {
|
||||
os << AvbHandleStatusToString(status);
|
||||
return os;
|
||||
}
|
||||
|
||||
// class AvbVerifier
|
||||
// -----------------
|
||||
// Reads the following values from kernel cmdline and provides the
|
||||
// VerifyVbmetaImages() to verify AvbSlotVerifyData.
|
||||
// - androidboot.vbmeta.hash_alg
|
||||
|
|
@ -74,12 +120,6 @@ class AvbVerifier {
|
|||
AvbVerifier() = default;
|
||||
|
||||
private:
|
||||
enum HashAlgorithm {
|
||||
kInvalid = 0,
|
||||
kSHA256 = 1,
|
||||
kSHA512 = 2,
|
||||
};
|
||||
|
||||
HashAlgorithm hash_alg_;
|
||||
uint8_t digest_[SHA512_DIGEST_LENGTH];
|
||||
size_t vbmeta_size_;
|
||||
|
|
@ -105,10 +145,10 @@ std::unique_ptr<AvbVerifier> AvbVerifier::Create() {
|
|||
fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg);
|
||||
if (hash_alg == "sha256") {
|
||||
expected_digest_size = SHA256_DIGEST_LENGTH * 2;
|
||||
avb_verifier->hash_alg_ = kSHA256;
|
||||
avb_verifier->hash_alg_ = HashAlgorithm::kSHA256;
|
||||
} else if (hash_alg == "sha512") {
|
||||
expected_digest_size = SHA512_DIGEST_LENGTH * 2;
|
||||
avb_verifier->hash_alg_ = kSHA512;
|
||||
avb_verifier->hash_alg_ = HashAlgorithm::kSHA512;
|
||||
} else {
|
||||
LERROR << "Unknown hash algorithm: " << hash_alg.c_str();
|
||||
return nullptr;
|
||||
|
|
@ -140,10 +180,10 @@ bool AvbVerifier::VerifyVbmetaImages(const std::vector<VBMetaData>& vbmeta_image
|
|||
size_t total_size = 0;
|
||||
bool digest_matched = false;
|
||||
|
||||
if (hash_alg_ == kSHA256) {
|
||||
if (hash_alg_ == HashAlgorithm::kSHA256) {
|
||||
std::tie(total_size, digest_matched) =
|
||||
VerifyVbmetaDigest<SHA256Hasher>(vbmeta_images, digest_);
|
||||
} else if (hash_alg_ == kSHA512) {
|
||||
} else if (hash_alg_ == HashAlgorithm::kSHA512) {
|
||||
std::tie(total_size, digest_matched) =
|
||||
VerifyVbmetaDigest<SHA512Hasher>(vbmeta_images, digest_);
|
||||
}
|
||||
|
|
@ -162,6 +202,98 @@ bool AvbVerifier::VerifyVbmetaImages(const std::vector<VBMetaData>& vbmeta_image
|
|||
return true;
|
||||
}
|
||||
|
||||
// class AvbHandle
|
||||
// ---------------
|
||||
AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(
|
||||
const std::string& partition_name, const std::string& ab_suffix,
|
||||
const std::string& ab_other_suffix, const std::string& expected_public_key_path,
|
||||
const HashAlgorithm& hash_algorithm, bool allow_verification_error,
|
||||
bool load_chained_vbmeta, bool rollback_protection,
|
||||
std::function<std::string(const std::string&)> custom_device_path) {
|
||||
AvbUniquePtr avb_handle(new AvbHandle());
|
||||
if (!avb_handle) {
|
||||
LERROR << "Failed to allocate AvbHandle";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string expected_key_blob;
|
||||
if (!expected_public_key_path.empty()) {
|
||||
if (access(expected_public_key_path.c_str(), F_OK) != 0) {
|
||||
LERROR << "Expected public key path doesn't exist: " << expected_public_key_path;
|
||||
return nullptr;
|
||||
} else if (!ReadFileToString(expected_public_key_path, &expected_key_blob)) {
|
||||
LERROR << "Failed to load: " << expected_public_key_path;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto android_by_name_symlink = [](const std::string& partition_name_with_ab) {
|
||||
return "/dev/block/by-name/" + partition_name_with_ab;
|
||||
};
|
||||
|
||||
auto device_path = custom_device_path ? custom_device_path : android_by_name_symlink;
|
||||
|
||||
auto verify_result = LoadAndVerifyVbmetaImpl(
|
||||
partition_name, ab_suffix, ab_other_suffix, expected_key_blob, allow_verification_error,
|
||||
load_chained_vbmeta, rollback_protection, device_path, false,
|
||||
/* is_chained_vbmeta */ &avb_handle->vbmeta_images_);
|
||||
switch (verify_result) {
|
||||
case VBMetaVerifyResult::kSuccess:
|
||||
avb_handle->status_ = AvbHandleStatus::kSuccess;
|
||||
break;
|
||||
case VBMetaVerifyResult::kErrorVerification:
|
||||
avb_handle->status_ = AvbHandleStatus::kVerificationError;
|
||||
break;
|
||||
default:
|
||||
LERROR << "LoadAndVerifyVbmetaImpl failed, result: " << verify_result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
|
||||
avb_handle->avb_version_ = StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
|
||||
|
||||
// Checks any disabled flag is set.
|
||||
std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header =
|
||||
avb_handle->vbmeta_images_[0].GetVBMetaHeader();
|
||||
bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header->flags &
|
||||
AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
|
||||
bool hashtree_disabled =
|
||||
((AvbVBMetaImageFlags)vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
|
||||
if (verification_disabled) {
|
||||
avb_handle->status_ = AvbHandleStatus::kVerificationDisabled;
|
||||
} else if (hashtree_disabled) {
|
||||
avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled;
|
||||
}
|
||||
|
||||
// Calculates the summary info for all vbmeta_images_;
|
||||
std::string digest;
|
||||
size_t total_size;
|
||||
if (hash_algorithm == HashAlgorithm::kSHA256) {
|
||||
std::tie(digest, total_size) =
|
||||
CalculateVbmetaDigest<SHA256Hasher>(avb_handle->vbmeta_images_);
|
||||
} else if (hash_algorithm == HashAlgorithm::kSHA512) {
|
||||
std::tie(digest, total_size) =
|
||||
CalculateVbmetaDigest<SHA512Hasher>(avb_handle->vbmeta_images_);
|
||||
} else {
|
||||
LERROR << "Invalid hash algorithm";
|
||||
return nullptr;
|
||||
}
|
||||
avb_handle->vbmeta_info_ = VBMetaInfo(digest, hash_algorithm, total_size);
|
||||
|
||||
LINFO << "Returning avb_handle with status: " << avb_handle->status_;
|
||||
return avb_handle;
|
||||
}
|
||||
|
||||
AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta() {
|
||||
// Loads inline vbmeta images, starting from /vbmeta.
|
||||
return LoadAndVerifyVbmeta("vbmeta", fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix(),
|
||||
{} /* expected_public_key, already checked by bootloader */,
|
||||
HashAlgorithm::kSHA256,
|
||||
IsDeviceUnlocked(), /* allow_verification_error */
|
||||
true, /* load_chained_vbmeta */
|
||||
false, /* rollback_protection, already checked by bootloader */
|
||||
nullptr /* custom_device_path */);
|
||||
}
|
||||
|
||||
AvbUniquePtr AvbHandle::Open() {
|
||||
bool is_device_unlocked = IsDeviceUnlocked();
|
||||
|
|
@ -192,14 +324,14 @@ AvbUniquePtr AvbHandle::Open() {
|
|||
// for more details.
|
||||
switch (verify_result) {
|
||||
case AVB_SLOT_VERIFY_RESULT_OK:
|
||||
avb_handle->status_ = kAvbHandleSuccess;
|
||||
avb_handle->status_ = AvbHandleStatus::kSuccess;
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
|
||||
if (!is_device_unlocked) {
|
||||
LERROR << "ERROR_VERIFICATION isn't allowed when the device is LOCKED";
|
||||
return nullptr;
|
||||
}
|
||||
avb_handle->status_ = kAvbHandleVerificationError;
|
||||
avb_handle->status_ = AvbHandleStatus::kVerificationError;
|
||||
break;
|
||||
default:
|
||||
LERROR << "avb_slot_verify failed, result: " << verify_result;
|
||||
|
|
@ -220,7 +352,7 @@ AvbUniquePtr AvbHandle::Open() {
|
|||
AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
|
||||
|
||||
if (verification_disabled) {
|
||||
avb_handle->status_ = kAvbHandleVerificationDisabled;
|
||||
avb_handle->status_ = AvbHandleStatus::kVerificationDisabled;
|
||||
} else {
|
||||
// Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline.
|
||||
std::unique_ptr<AvbVerifier> avb_verifier = AvbVerifier::Create();
|
||||
|
|
@ -237,7 +369,7 @@ AvbUniquePtr AvbHandle::Open() {
|
|||
bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
|
||||
AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
|
||||
if (hashtree_disabled) {
|
||||
avb_handle->status_ = kAvbHandleHashtreeDisabled;
|
||||
avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,11 +378,12 @@ AvbUniquePtr AvbHandle::Open() {
|
|||
}
|
||||
|
||||
AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev) {
|
||||
if (!fstab_entry || status_ == kAvbHandleUninitialized || vbmeta_images_.size() < 1) {
|
||||
if (!fstab_entry || status_ == AvbHandleStatus::kUninitialized || vbmeta_images_.size() < 1) {
|
||||
return AvbHashtreeResult::kFail;
|
||||
}
|
||||
|
||||
if (status_ == kAvbHandleHashtreeDisabled || status_ == kAvbHandleVerificationDisabled) {
|
||||
if (status_ == AvbHandleStatus::kHashtreeDisabled ||
|
||||
status_ == AvbHandleStatus::kVerificationDisabled) {
|
||||
LINFO << "AVB HASHTREE disabled on: " << fstab_entry->mount_point;
|
||||
return AvbHashtreeResult::kDisabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -32,23 +33,56 @@ enum class AvbHashtreeResult {
|
|||
kDisabled,
|
||||
};
|
||||
|
||||
enum class HashAlgorithm {
|
||||
kInvalid = 0,
|
||||
kSHA256 = 1,
|
||||
kSHA512 = 2,
|
||||
};
|
||||
|
||||
enum class AvbHandleStatus {
|
||||
kSuccess = 0,
|
||||
kUninitialized = 1,
|
||||
kHashtreeDisabled = 2,
|
||||
kVerificationDisabled = 3,
|
||||
kVerificationError = 4,
|
||||
};
|
||||
|
||||
struct VBMetaInfo {
|
||||
std::string digest;
|
||||
HashAlgorithm hash_algorithm;
|
||||
size_t total_size;
|
||||
|
||||
VBMetaInfo() {}
|
||||
|
||||
VBMetaInfo(std::string digest_value, HashAlgorithm algorithm, size_t size)
|
||||
: digest(std::move(digest_value)), hash_algorithm(algorithm), total_size(size) {}
|
||||
};
|
||||
|
||||
class VBMetaData {
|
||||
public:
|
||||
// Constructors
|
||||
VBMetaData() : vbmeta_ptr_(nullptr), vbmeta_size_(0){};
|
||||
|
||||
VBMetaData(const uint8_t* data, size_t size)
|
||||
: vbmeta_ptr_(new (std::nothrow) uint8_t[size]), vbmeta_size_(size) {
|
||||
VBMetaData(const uint8_t* data, size_t size, const std::string& partition_name)
|
||||
: vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
|
||||
vbmeta_size_(size),
|
||||
partition_name_(partition_name) {
|
||||
// The ownership of data is NOT transferred, i.e., the caller still
|
||||
// needs to release the memory as we make a copy here.
|
||||
memcpy(vbmeta_ptr_.get(), data, size * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
explicit VBMetaData(size_t size)
|
||||
: vbmeta_ptr_(new (std::nothrow) uint8_t[size]), vbmeta_size_(size) {}
|
||||
explicit VBMetaData(size_t size, const std::string& partition_name)
|
||||
: vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
|
||||
vbmeta_size_(size),
|
||||
partition_name_(partition_name) {}
|
||||
|
||||
// Extracts vbmeta header from the vbmeta buffer, set update_vbmeta_size to
|
||||
// true to update vbmeta_size_ to the actual size with valid content.
|
||||
std::unique_ptr<AvbVBMetaImageHeader> GetVBMetaHeader(bool update_vbmeta_size = false);
|
||||
|
||||
// Get methods for each data member.
|
||||
const std::string& device_path() const { return device_path_; }
|
||||
const std::string& partition() const { return partition_name_; }
|
||||
uint8_t* data() const { return vbmeta_ptr_.get(); }
|
||||
const size_t& size() const { return vbmeta_size_; }
|
||||
|
||||
|
|
@ -56,9 +90,9 @@ class VBMetaData {
|
|||
static const size_t kMaxVBMetaSize = 64 * 1024;
|
||||
|
||||
private:
|
||||
std::string device_path_;
|
||||
std::unique_ptr<uint8_t[]> vbmeta_ptr_;
|
||||
size_t vbmeta_size_;
|
||||
std::string partition_name_;
|
||||
};
|
||||
|
||||
class FsManagerAvbOps;
|
||||
|
|
@ -71,7 +105,7 @@ using AvbUniquePtr = std::unique_ptr<AvbHandle>;
|
|||
// descriptors to load verity table into kernel through ioctl.
|
||||
class AvbHandle {
|
||||
public:
|
||||
// The factory method to return a AvbUniquePtr that holds
|
||||
// The factory methods to return a AvbUniquePtr that holds
|
||||
// the verified AVB (external/avb) metadata of all verified partitions
|
||||
// in vbmeta_images_.
|
||||
//
|
||||
|
|
@ -79,31 +113,40 @@ class AvbHandle {
|
|||
// - androidboot.vbmeta.{hash_alg, size, digest}.
|
||||
//
|
||||
// A typical usage will be:
|
||||
// - AvbUniquePtr handle = AvbHandle::Open();
|
||||
// - AvbUniquePtr handle = AvbHandle::Open(); or
|
||||
// - AvbUniquePtr handle = AvbHandle::LoadAndVerifyVbmeta();
|
||||
//
|
||||
// Possible return values:
|
||||
// - nullptr: any error when reading and verifying the metadata,
|
||||
// e.g., I/O error, digest value mismatch, size mismatch, etc.
|
||||
//
|
||||
// - a valid unique_ptr with status kAvbHandleHashtreeDisabled:
|
||||
// - a valid unique_ptr with status AvbHandleStatus::HashtreeDisabled:
|
||||
// to support the existing 'adb disable-verity' feature in Android.
|
||||
// It's very helpful for developers to make the filesystem writable to
|
||||
// allow replacing binaries on the device.
|
||||
//
|
||||
// - a valid unique_ptr with status kAvbHandleVerificationDisabled:
|
||||
// - a valid unique_ptr with status AvbHandleStatus::VerificationDisabled:
|
||||
// to support 'avbctl disable-verification': only the top-level
|
||||
// vbmeta is read, vbmeta structs in other partitions are not processed.
|
||||
// It's needed to bypass AVB when using the generic system.img to run
|
||||
// VTS for project Treble.
|
||||
//
|
||||
// - a valid unique_ptr with status kAvbHandleVerificationError:
|
||||
// - a valid unique_ptr with status AvbHandleStatus::VerificationError:
|
||||
// there is verification error when libavb loads vbmeta from each
|
||||
// partition. This is only allowed when the device is unlocked.
|
||||
//
|
||||
// - a valid unique_ptr with status kAvbHandleSuccess: the metadata
|
||||
// - a valid unique_ptr with status AvbHandleStatus::Success: the metadata
|
||||
// is verified and can be trusted.
|
||||
//
|
||||
static AvbUniquePtr Open();
|
||||
// TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
|
||||
static AvbUniquePtr Open(); // loads inline vbmeta, via libavb.
|
||||
static AvbUniquePtr LoadAndVerifyVbmeta(); // loads inline vbmeta.
|
||||
static AvbUniquePtr LoadAndVerifyVbmeta( // loads offline vbmeta.
|
||||
const std::string& partition_name, const std::string& ab_suffix,
|
||||
const std::string& ab_other_suffix, const std::string& expected_public_key,
|
||||
const HashAlgorithm& hash_algorithm, bool allow_verification_error,
|
||||
bool load_chained_vbmeta, bool rollback_protection,
|
||||
std::function<std::string(const std::string&)> custom_device_path = nullptr);
|
||||
|
||||
// Sets up dm-verity on the given fstab entry.
|
||||
// The 'wait_for_verity_dev' parameter makes this function wait for the
|
||||
|
|
@ -118,6 +161,8 @@ class AvbHandle {
|
|||
AvbHashtreeResult SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev);
|
||||
|
||||
const std::string& avb_version() const { return avb_version_; }
|
||||
const VBMetaInfo& vbmeta_info() const { return vbmeta_info_; }
|
||||
AvbHandleStatus status() const { return status_; }
|
||||
|
||||
AvbHandle(const AvbHandle&) = delete; // no copy
|
||||
AvbHandle& operator=(const AvbHandle&) = delete; // no assignment
|
||||
|
|
@ -126,17 +171,10 @@ class AvbHandle {
|
|||
AvbHandle& operator=(AvbHandle&&) noexcept = delete; // no move assignment
|
||||
|
||||
private:
|
||||
enum AvbHandleStatus {
|
||||
kAvbHandleSuccess = 0,
|
||||
kAvbHandleUninitialized,
|
||||
kAvbHandleHashtreeDisabled,
|
||||
kAvbHandleVerificationDisabled,
|
||||
kAvbHandleVerificationError,
|
||||
};
|
||||
|
||||
AvbHandle() : status_(kAvbHandleUninitialized) {}
|
||||
AvbHandle() : status_(AvbHandleStatus::kUninitialized) {}
|
||||
|
||||
std::vector<VBMetaData> vbmeta_images_;
|
||||
VBMetaInfo vbmeta_info_; // A summary info for vbmeta_images_.
|
||||
AvbHandleStatus status_;
|
||||
std::string avb_version_;
|
||||
};
|
||||
|
|
|
|||
1088
fs_mgr/libfs_avb/tests/avb_util_test.cpp
Normal file
1088
fs_mgr/libfs_avb/tests/avb_util_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
311
fs_mgr/libfs_avb/tests/fs_avb_test.cpp
Normal file
311
fs_mgr/libfs_avb/tests/fs_avb_test.cpp
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* 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 <endian.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <base/files/file_util.h>
|
||||
#include <base/strings/string_util.h>
|
||||
#include <fs_avb/fs_avb.h>
|
||||
#include <libavb/libavb.h>
|
||||
|
||||
#include "fs_avb_test_util.h"
|
||||
|
||||
// Target classes or functions to test:
|
||||
using android::fs_mgr::AvbHandle;
|
||||
using android::fs_mgr::AvbHandleStatus;
|
||||
using android::fs_mgr::HashAlgorithm;
|
||||
|
||||
namespace fs_avb_host_test {
|
||||
|
||||
class PublicFsAvbTest : public BaseFsAvbTest {
|
||||
public:
|
||||
PublicFsAvbTest(){};
|
||||
|
||||
protected:
|
||||
~PublicFsAvbTest(){};
|
||||
// Modifies |flags| field in the vbmeta header in an Avb image.
|
||||
// e.g., AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED.
|
||||
void ModifyVBMetaHeaderFlags(const base::FilePath& vbmeta_image_path, uint32_t flags);
|
||||
};
|
||||
|
||||
void PublicFsAvbTest::ModifyVBMetaHeaderFlags(const base::FilePath& vbmeta_image_path,
|
||||
uint32_t flags) {
|
||||
if (!base::PathExists(vbmeta_image_path)) return;
|
||||
|
||||
// Only support modifying the flags in vbmeta*.img.
|
||||
std::string image_file_name = vbmeta_image_path.RemoveExtension().BaseName().value();
|
||||
ASSERT_TRUE(base::StartsWith(image_file_name, "vbmeta", base::CompareCase::INSENSITIVE_ASCII));
|
||||
|
||||
android::base::unique_fd fd(open(vbmeta_image_path.value().c_str(), O_RDWR | O_CLOEXEC));
|
||||
EXPECT_TRUE(fd > 0);
|
||||
|
||||
auto flags_offset = offsetof(AvbVBMetaImageHeader, flags);
|
||||
uint32_t flags_data = htobe32(flags);
|
||||
EXPECT_EQ(flags_offset, lseek64(fd, flags_offset, SEEK_SET));
|
||||
EXPECT_EQ(sizeof flags_data, write(fd, &flags_data, sizeof flags_data));
|
||||
}
|
||||
|
||||
TEST_F(PublicFsAvbTest, LoadAndVerifyVbmeta) {
|
||||
// Generates a raw boot.img
|
||||
const size_t boot_image_size = 5 * 1024 * 1024;
|
||||
const size_t boot_partition_size = 10 * 1024 * 1024;
|
||||
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
|
||||
|
||||
// Adds AVB Hash Footer.
|
||||
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
|
||||
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates a raw system.img, use a smaller size to speed-up unit test.
|
||||
const size_t system_image_size = 10 * 1024 * 1024;
|
||||
const size_t system_partition_size = 15 * 1024 * 1024;
|
||||
base::FilePath system_path = GenerateImage("system.img", system_image_size);
|
||||
// Adds AVB Hashtree Footer.
|
||||
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
|
||||
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates chain partition descriptors.
|
||||
base::FilePath rsa2048_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
|
||||
base::FilePath rsa4096_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
|
||||
|
||||
// Makes a vbmeta image includeing 'boot' and 'system' chained descriptors.
|
||||
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
|
||||
data_dir_.Append("testkey_rsa8192.pem"),
|
||||
{}, /* include_descriptor_image_paths */
|
||||
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
|
||||
{"system", 2, rsa4096_public_key}},
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Calculates the digest of all chained partitions, to ensure the chained is formed properly.
|
||||
EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
|
||||
CalcVBMetaDigest("vbmeta.img", "sha256"));
|
||||
|
||||
// Invokes the public API from fs_avb.h.
|
||||
auto vbmeta_image_path = [this](const std::string& partition_name) {
|
||||
return test_dir_.Append(partition_name + ".img").value();
|
||||
};
|
||||
auto avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
"" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
|
||||
false /* allow_verification_error */, true /* load_chained_vbmeta */,
|
||||
true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_NE(nullptr, avb_handle);
|
||||
EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
|
||||
|
||||
// Checks the summary info for all vbmeta images.
|
||||
// Checks the digest matches the value calculated by CalcVBMetaDigest().
|
||||
EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
|
||||
avb_handle->vbmeta_info().digest);
|
||||
EXPECT_EQ(8576UL, avb_handle->vbmeta_info().total_size);
|
||||
EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
|
||||
|
||||
// Skip loading chained vbmeta.
|
||||
avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
"" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
|
||||
false /* allow_verification_error */, false /* load_chained_vbmeta */,
|
||||
true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_NE(nullptr, avb_handle);
|
||||
EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
|
||||
EXPECT_EQ("5c31197992b3c72a854ec7dc0eb9609ffebcffab7917ffd381a99ecee328f09c",
|
||||
avb_handle->vbmeta_info().digest);
|
||||
EXPECT_EQ(5184UL, avb_handle->vbmeta_info().total_size);
|
||||
EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
|
||||
}
|
||||
|
||||
TEST_F(PublicFsAvbTest, LoadAndVerifyVbmetaWithModifications) {
|
||||
// Generates a raw boot.img
|
||||
const size_t boot_image_size = 5 * 1024 * 1024;
|
||||
const size_t boot_partition_size = 10 * 1024 * 1024;
|
||||
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
|
||||
|
||||
// Adds AVB Hash Footer.
|
||||
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
|
||||
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates a raw system.img, use a smaller size to speed-up unit test.
|
||||
const size_t system_image_size = 10 * 1024 * 1024;
|
||||
const size_t system_partition_size = 15 * 1024 * 1024;
|
||||
base::FilePath system_path = GenerateImage("system.img", system_image_size);
|
||||
// Adds AVB Hashtree Footer.
|
||||
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
|
||||
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates chain partition descriptors.
|
||||
base::FilePath rsa2048_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
|
||||
base::FilePath rsa4096_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
|
||||
|
||||
// Makes a vbmeta image includeing 'boot' and 'system' chained descriptors.
|
||||
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
|
||||
data_dir_.Append("testkey_rsa8192.pem"),
|
||||
{}, /* include_descriptor_image_paths */
|
||||
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
|
||||
{"system", 2, rsa4096_public_key}},
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Calculates the digest of all chained partitions, to ensure the chained is formed properly.
|
||||
EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
|
||||
CalcVBMetaDigest("vbmeta.img", "sha256"));
|
||||
|
||||
// Sets AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED in the vbmeta.img.
|
||||
ModifyVBMetaHeaderFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
|
||||
|
||||
auto vbmeta_image_path = [this](const std::string& partition_name) {
|
||||
return test_dir_.Append(partition_name + ".img").value();
|
||||
};
|
||||
auto avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
"" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
|
||||
false /* allow_verification_error */, true /* load_chained_vbmeta */,
|
||||
true /* rollback_protection */, vbmeta_image_path);
|
||||
// Returns a null handler because allow_verification is not True.
|
||||
EXPECT_EQ(nullptr, avb_handle);
|
||||
|
||||
// Try again with allow_verification_error set to true.
|
||||
avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
"" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
|
||||
true /* allow_verification_error */, true /* load_chained_vbmeta */,
|
||||
true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_NE(nullptr, avb_handle);
|
||||
EXPECT_EQ(AvbHandleStatus::kHashtreeDisabled, avb_handle->status());
|
||||
|
||||
// Checks the summary info for all vbmeta images.
|
||||
// Checks the digest matches the value calculated by CalcVBMetaDigest().
|
||||
EXPECT_EQ("ae8f7ad95cbb7ce4f0feeeedc2a0a39824af5cd29dad4d028597cab4b8c2e83c",
|
||||
CalcVBMetaDigest("vbmeta.img", "sha256"));
|
||||
EXPECT_EQ("ae8f7ad95cbb7ce4f0feeeedc2a0a39824af5cd29dad4d028597cab4b8c2e83c",
|
||||
avb_handle->vbmeta_info().digest);
|
||||
EXPECT_EQ(8576UL, avb_handle->vbmeta_info().total_size);
|
||||
EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
|
||||
|
||||
// Sets AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED in the vbmeta.img.
|
||||
ModifyVBMetaHeaderFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
|
||||
// Loads the vbmeta with allow_verification_error set to true.
|
||||
avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
"" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
|
||||
true /* allow_verification_error */, true /* load_chained_vbmeta */,
|
||||
true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_NE(nullptr, avb_handle);
|
||||
EXPECT_EQ(AvbHandleStatus::kVerificationDisabled, avb_handle->status());
|
||||
// Only the top-level vbmeta.img is loaded, when VERIFICATION_DISABLED is set.
|
||||
// However, CalcVBMetaDigest() reads all vbmeta structs to calculate the digest,
|
||||
// including vbmeta.img, boot.img and syste.img. So we don't compare the digest here.
|
||||
EXPECT_EQ(5184UL, avb_handle->vbmeta_info().total_size);
|
||||
|
||||
// Sets a unknown flag in the vbmeta.imgm and expects to get
|
||||
// AvbHandleStatus::kVerificationError.
|
||||
ModifyVBMetaHeaderFlags(vbmeta_path, 0x10000000);
|
||||
// Loads the vbmeta with allow_verification_error set to true.
|
||||
avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
"" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
|
||||
true /* allow_verification_error */, true /* load_chained_vbmeta */,
|
||||
true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_NE(nullptr, avb_handle);
|
||||
EXPECT_EQ(AvbHandleStatus::kVerificationError, avb_handle->status());
|
||||
// Checks the digest matches the value calculated by CalcVBMetaDigest().
|
||||
EXPECT_EQ("8fb99c4f54500053c3582df5eaf04e9a533137398879188aad9968ec19a664f1",
|
||||
CalcVBMetaDigest("vbmeta.img", "sha256"));
|
||||
EXPECT_EQ("8fb99c4f54500053c3582df5eaf04e9a533137398879188aad9968ec19a664f1",
|
||||
avb_handle->vbmeta_info().digest);
|
||||
EXPECT_EQ(8576UL, avb_handle->vbmeta_info().total_size);
|
||||
EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
|
||||
}
|
||||
|
||||
TEST_F(PublicFsAvbTest, LoadAndVerifyVbmetaWithPublicKeys) {
|
||||
// Generates a raw boot.img
|
||||
const size_t boot_image_size = 5 * 1024 * 1024;
|
||||
const size_t boot_partition_size = 10 * 1024 * 1024;
|
||||
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
|
||||
|
||||
// Adds AVB Hash Footer.
|
||||
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
|
||||
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates a raw system.img, use a smaller size to speed-up unit test.
|
||||
const size_t system_image_size = 10 * 1024 * 1024;
|
||||
const size_t system_partition_size = 15 * 1024 * 1024;
|
||||
base::FilePath system_path = GenerateImage("system.img", system_image_size);
|
||||
// Adds AVB Hashtree Footer.
|
||||
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
|
||||
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates chain partition descriptors.
|
||||
base::FilePath rsa2048_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
|
||||
base::FilePath rsa4096_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
|
||||
base::FilePath rsa8192_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa8192.pem"));
|
||||
|
||||
// Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
|
||||
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
|
||||
data_dir_.Append("testkey_rsa8192.pem"),
|
||||
{}, /* include_descriptor_image_paths */
|
||||
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
|
||||
{"system", 2, rsa4096_public_key}},
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
auto vbmeta_image_path = [this](const std::string& partition_name) {
|
||||
return test_dir_.Append(partition_name + ".img").value();
|
||||
};
|
||||
std::vector<VBMetaData> vbmeta_images;
|
||||
// Uses the correct expected public key.
|
||||
auto avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
rsa8192_public_key.value(), HashAlgorithm::kSHA256, true /* allow_verification_error */,
|
||||
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_NE(nullptr, avb_handle);
|
||||
EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
|
||||
|
||||
// Uses a non-existed public key.
|
||||
avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
"/path/to/non-existed/key", HashAlgorithm::kSHA256, true /* allow_verification_error */,
|
||||
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_EQ(nullptr, avb_handle);
|
||||
|
||||
// Uses an incorrect public key, with allow_verification_error false.
|
||||
avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
rsa4096_public_key.value(), HashAlgorithm::kSHA256,
|
||||
false /* allow_verification_error */, true /* load_chained_vbmeta */,
|
||||
true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_EQ(nullptr, avb_handle);
|
||||
|
||||
// Uses an incorrect public key, with allow_verification_error true.
|
||||
avb_handle = AvbHandle::LoadAndVerifyVbmeta(
|
||||
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
|
||||
rsa4096_public_key.value(), HashAlgorithm::kSHA256, true /* allow_verification_error */,
|
||||
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path);
|
||||
EXPECT_NE(nullptr, avb_handle);
|
||||
EXPECT_EQ(AvbHandleStatus::kVerificationError, avb_handle->status());
|
||||
}
|
||||
|
||||
} // namespace fs_avb_host_test
|
||||
|
|
@ -69,7 +69,7 @@ std::string BaseFsAvbTest::CalcVBMetaDigest(const std::string& file_name,
|
|||
return trimmed_digest_data;
|
||||
}
|
||||
|
||||
void BaseFsAvbTest::GenerateVBMetaImage(
|
||||
base::FilePath BaseFsAvbTest::GenerateVBMetaImage(
|
||||
const std::string& file_name, const std::string& avb_algorithm, uint64_t rollback_index,
|
||||
const base::FilePath& key_path,
|
||||
const std::vector<base::FilePath>& include_descriptor_image_paths,
|
||||
|
|
@ -107,17 +107,19 @@ void BaseFsAvbTest::GenerateVBMetaImage(
|
|||
chain_partition_options.c_str(), additional_options.c_str(),
|
||||
vbmeta_image.path.value().c_str());
|
||||
int64_t file_size;
|
||||
ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
|
||||
EXPECT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
|
||||
vbmeta_image.content.resize(file_size);
|
||||
ASSERT_TRUE(base::ReadFile(vbmeta_image.path,
|
||||
EXPECT_TRUE(base::ReadFile(vbmeta_image.path,
|
||||
reinterpret_cast<char*>(vbmeta_image.content.data()), file_size));
|
||||
// Stores the generated vbmeta image into vbmeta_images_ member object.
|
||||
vbmeta_images_.emplace(file_name, std::move(vbmeta_image));
|
||||
|
||||
return vbmeta_images_[file_name].path; // returns the path.
|
||||
}
|
||||
|
||||
void BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path,
|
||||
const std::string& output_file_name,
|
||||
const size_t padding_size) {
|
||||
base::FilePath BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path,
|
||||
const std::string& output_file_name,
|
||||
const size_t padding_size) {
|
||||
VBMetaImage vbmeta_image;
|
||||
vbmeta_image.path = test_dir_.Append(output_file_name);
|
||||
EXPECT_COMMAND(0,
|
||||
|
|
@ -127,12 +129,15 @@ void BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path,
|
|||
" --padding_size %zu",
|
||||
image_path.value().c_str(), vbmeta_image.path.value().c_str(), padding_size);
|
||||
int64_t file_size;
|
||||
ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
|
||||
EXPECT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
|
||||
vbmeta_image.content.resize(file_size);
|
||||
ASSERT_TRUE(base::ReadFile(vbmeta_image.path,
|
||||
EXPECT_TRUE(base::ReadFile(vbmeta_image.path,
|
||||
reinterpret_cast<char*>(vbmeta_image.content.data()), file_size));
|
||||
// Stores the extracted vbmeta image into vbmeta_images_ member object.
|
||||
vbmeta_images_.emplace(output_file_name, std::move(vbmeta_image));
|
||||
|
||||
// Returns the output file path.
|
||||
return vbmeta_images_[output_file_name].path;
|
||||
}
|
||||
|
||||
// Generates a file with name |file_name| of size |image_size| with
|
||||
|
|
@ -179,6 +184,49 @@ void BaseFsAvbTest::AddAvbFooter(const base::FilePath& image_path, const std::st
|
|||
additional_options.c_str());
|
||||
}
|
||||
|
||||
VBMetaData BaseFsAvbTest::GenerateImageAndExtractVBMetaData(
|
||||
const std::string& partition_name, const size_t image_size, const size_t partition_size,
|
||||
const std::string& footer_type, const base::FilePath& avb_signing_key,
|
||||
const std::string& avb_algorithm, const uint64_t rollback_index) {
|
||||
// Generates a raw image first
|
||||
base::FilePath image_path = GenerateImage(partition_name + ".img", image_size);
|
||||
|
||||
// Appends AVB Hashtree Footer.
|
||||
AddAvbFooter(image_path, footer_type, partition_name, partition_size, avb_algorithm,
|
||||
rollback_index, avb_signing_key, "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Extracts vbmeta from the ram image into another *-vbmeta.img.
|
||||
auto vbmeta_image = ExtractVBMetaImage(image_path, partition_name + "-vbmeta.img");
|
||||
|
||||
// Loads *-vbmeta.img into a VBMetaData.
|
||||
std::string vbmeta_buffer;
|
||||
EXPECT_TRUE(base::ReadFileToString(vbmeta_image, &vbmeta_buffer));
|
||||
|
||||
return {(const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(), partition_name};
|
||||
}
|
||||
|
||||
VBMetaData BaseFsAvbTest::LoadVBMetaData(const std::string& file_name) {
|
||||
auto iter = vbmeta_images_.find(file_name);
|
||||
EXPECT_NE(iter, vbmeta_images_.end()); // ensures file_name is generated before.
|
||||
|
||||
// Gets the image path from iterator->second.path: VBMetaImage.path.
|
||||
base::FilePath image_path = iter->second.path;
|
||||
|
||||
// Loads the vbmeta_image into a VBMetaData.
|
||||
std::string vbmeta_buffer;
|
||||
EXPECT_TRUE(base::ReadFileToString(image_path, &vbmeta_buffer));
|
||||
|
||||
std::string partition_name = image_path.RemoveExtension().BaseName().value();
|
||||
return {(const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(), partition_name};
|
||||
}
|
||||
|
||||
VBMetaData BaseFsAvbTest::ExtractAndLoadVBMetaData(const base::FilePath& image_path,
|
||||
const std::string& output_file_name) {
|
||||
ExtractVBMetaImage(image_path, output_file_name);
|
||||
return LoadVBMetaData(output_file_name);
|
||||
}
|
||||
|
||||
std::string BaseFsAvbTest::InfoImage(const base::FilePath& image_path) {
|
||||
base::FilePath tmp_path = test_dir_.Append("info_output.txt");
|
||||
EXPECT_COMMAND(0, "avbtool info_image --image %s --output %s", image_path.value().c_str(),
|
||||
|
|
|
|||
|
|
@ -16,14 +16,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <base/files/file_path.h>
|
||||
#include <base/strings/stringprintf.h>
|
||||
#include <fs_avb/fs_avb.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Utility macro to run the command expressed by the printf()-style string
|
||||
|
|
@ -36,6 +42,8 @@
|
|||
EXPECT_EQ(WEXITSTATUS(rc), expected_exit_status); \
|
||||
} while (0);
|
||||
|
||||
using android::fs_mgr::VBMetaData;
|
||||
|
||||
namespace fs_avb_host_test {
|
||||
|
||||
struct VBMetaImage {
|
||||
|
|
@ -51,6 +59,10 @@ struct ChainPartitionConfig {
|
|||
base::FilePath key_blob_path;
|
||||
};
|
||||
|
||||
inline android::base::unique_fd OpenUniqueReadFd(const base::FilePath& file_path) {
|
||||
return android::base::unique_fd(open(file_path.value().c_str(), O_RDONLY | O_CLOEXEC));
|
||||
}
|
||||
|
||||
/* Base-class used for unit test. */
|
||||
class BaseFsAvbTest : public ::testing::Test {
|
||||
public:
|
||||
|
|
@ -66,16 +78,18 @@ class BaseFsAvbTest : public ::testing::Test {
|
|||
// Generates a vbmeta image with |file_name| by avbtool.
|
||||
// The generated vbmeta image will be written to disk, see the
|
||||
// |vbmeta_images_| variable for its path and the content.
|
||||
void GenerateVBMetaImage(const std::string& file_name, const std::string& avb_algorithm,
|
||||
uint64_t rollback_index, const base::FilePath& key_path,
|
||||
const std::vector<base::FilePath>& include_descriptor_image_paths,
|
||||
const std::vector<ChainPartitionConfig>& chain_partitions,
|
||||
const std::string& additional_options = "");
|
||||
base::FilePath GenerateVBMetaImage(
|
||||
const std::string& file_name, const std::string& avb_algorithm, uint64_t rollback_index,
|
||||
const base::FilePath& key_path,
|
||||
const std::vector<base::FilePath>& include_descriptor_image_paths,
|
||||
const std::vector<ChainPartitionConfig>& chain_partitions,
|
||||
const std::string& additional_options = "");
|
||||
// Similar to above, but extracts a vbmeta image from the given image_path.
|
||||
// The extracted vbmeta image will be written to disk, with |output_file_name|.
|
||||
// See the |vbmeta_images_| variable for its path and the content.
|
||||
void ExtractVBMetaImage(const base::FilePath& image_path, const std::string& output_file_name,
|
||||
const size_t padding_size = 0);
|
||||
base::FilePath ExtractVBMetaImage(const base::FilePath& image_path,
|
||||
const std::string& output_file_name,
|
||||
const size_t padding_size = 0);
|
||||
|
||||
// Generate a file with name |file_name| of size |image_size| with
|
||||
// known content (0x00 0x01 0x02 .. 0xff 0x00 0x01 ..).
|
||||
|
|
@ -86,9 +100,19 @@ class BaseFsAvbTest : public ::testing::Test {
|
|||
void AddAvbFooter(const base::FilePath& image_path, const std::string& footer_type,
|
||||
const std::string& partition_name, const uint64_t partition_size,
|
||||
const std::string& avb_algorithm, uint64_t rollback_index,
|
||||
const base::FilePath& key_path, const std::string& salt = "d00df00d",
|
||||
const base::FilePath& avb_signing_key, const std::string& salt = "d00df00d",
|
||||
const std::string& additional_options = "");
|
||||
|
||||
VBMetaData GenerateImageAndExtractVBMetaData(
|
||||
const std::string& partition_name, const size_t image_size, const size_t partition_size,
|
||||
const std::string& footer_type, const base::FilePath& avb_signing_key,
|
||||
const std::string& avb_algorithm, const uint64_t rollback_index);
|
||||
|
||||
VBMetaData ExtractAndLoadVBMetaData(const base::FilePath& image_path,
|
||||
const std::string& output_file_name);
|
||||
|
||||
VBMetaData LoadVBMetaData(const std::string& file_name);
|
||||
|
||||
// Returns the output of 'avbtool info_image' for the |image_path|.
|
||||
std::string InfoImage(const base::FilePath& image_path);
|
||||
// Same as above, but for an internal vbmeta image with |file_name| in |vbmeta_images_|.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "util.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue