Merge "libfs_avb: adding two public APIs"

This commit is contained in:
Treehugger Robot 2019-02-13 03:07:37 +00:00 committed by Gerrit Code Review
commit c7b5c4fa6b
14 changed files with 611 additions and 182 deletions

View file

@ -24,6 +24,8 @@ cc_library_static {
"avb_ops.cpp",
"avb_util.cpp",
"fs_avb.cpp",
"fs_avb_util.cpp",
"types.cpp",
"util.cpp",
],
static_libs: [
@ -98,6 +100,7 @@ cc_test_host {
srcs: [
"tests/basic_test.cpp",
"tests/fs_avb_test.cpp",
"tests/fs_avb_util_test.cpp",
],
}
@ -115,3 +118,26 @@ cc_test_host {
"tests/util_test.cpp",
],
}
cc_test {
name: "libfs_avb_device_test",
test_suites: ["device-tests"],
static_libs: [
"libavb",
"libdm",
"libfs_avb",
"libfstab",
],
shared_libs: [
"libbase",
"libcrypto",
],
srcs: [
"tests/fs_avb_device_test.cpp",
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
],
}

View file

@ -27,7 +27,7 @@
#include <string>
#include <vector>
#include <fs_avb/fs_avb.h>
#include <fs_avb/types.h>
#include <libavb/libavb.h>
namespace android {

View file

@ -34,56 +34,11 @@ 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
bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
const std::string& root_digest, const std::string& blk_device,
android::dm::DmTable* table) {
bool ConstructVerityTable(const FsAvbHashtreeDescriptor& hashtree_desc,
const std::string& blk_device, android::dm::DmTable* table) {
// Loads androidboot.veritymode from kernel cmdline.
std::string verity_mode;
if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
@ -104,12 +59,12 @@ bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std:
std::ostringstream hash_algorithm;
hash_algorithm << hashtree_desc.hash_algorithm;
android::dm::DmTargetVerity target(0, hashtree_desc.image_size / 512,
hashtree_desc.dm_verity_version, blk_device, blk_device,
hashtree_desc.data_block_size, hashtree_desc.hash_block_size,
hashtree_desc.image_size / hashtree_desc.data_block_size,
hashtree_desc.tree_offset / hashtree_desc.hash_block_size,
hash_algorithm.str(), root_digest, salt);
android::dm::DmTargetVerity target(
0, hashtree_desc.image_size / 512, hashtree_desc.dm_verity_version, blk_device,
blk_device, hashtree_desc.data_block_size, hashtree_desc.hash_block_size,
hashtree_desc.image_size / hashtree_desc.data_block_size,
hashtree_desc.tree_offset / hashtree_desc.hash_block_size, hash_algorithm.str(),
hashtree_desc.root_digest, hashtree_desc.salt);
if (hashtree_desc.fec_size > 0) {
target.UseFec(blk_device, hashtree_desc.fec_num_roots,
hashtree_desc.fec_offset / hashtree_desc.data_block_size,
@ -126,12 +81,10 @@ bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std:
return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
}
bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc,
const std::string& salt, const std::string& root_digest,
bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const FsAvbHashtreeDescriptor& hashtree_desc,
bool wait_for_verity_dev) {
android::dm::DmTable table;
if (!ConstructVerityTable(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) ||
!table.valid()) {
if (!ConstructVerityTable(hashtree_desc, fstab_entry->blk_device, &table) || !table.valid()) {
LERROR << "Failed to construct verity table.";
return false;
}
@ -164,12 +117,11 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor&
return true;
}
std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
std::string* out_salt, std::string* out_digest) {
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
bool found = false;
const uint8_t* desc_partition_name;
auto hashtree_desc = std::make_unique<AvbHashtreeDescriptor>();
auto hashtree_desc = std::make_unique<FsAvbHashtreeDescriptor>();
for (const auto& vbmeta : vbmeta_images) {
size_t num_descriptors;
@ -209,15 +161,17 @@ std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
}
if (!found) {
LERROR << "Partition descriptor not found: " << partition_name.c_str();
LERROR << "Hashtree descriptor not found: " << partition_name;
return nullptr;
}
hashtree_desc->partition_name = partition_name;
const uint8_t* desc_salt = desc_partition_name + hashtree_desc->partition_name_len;
*out_salt = BytesToHex(desc_salt, hashtree_desc->salt_len);
hashtree_desc->salt = BytesToHex(desc_salt, hashtree_desc->salt_len);
const uint8_t* desc_digest = desc_salt + hashtree_desc->salt_len;
*out_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len);
hashtree_desc->root_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len);
return hashtree_desc;
}
@ -235,18 +189,15 @@ bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity
return false;
}
std::string salt;
std::string root_digest;
std::unique_ptr<AvbHashtreeDescriptor> hashtree_descriptor =
GetHashtreeDescriptor(partition_name, vbmeta_images, &salt, &root_digest);
std::unique_ptr<FsAvbHashtreeDescriptor> hashtree_descriptor =
GetHashtreeDescriptor(partition_name, vbmeta_images);
if (!hashtree_descriptor) {
return false;
}
// Converts HASHTREE descriptor to verity table to load into kernel.
// When success, the new device path will be returned, e.g., /dev/block/dm-2.
return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, salt, root_digest,
wait_for_verity_dev);
return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, wait_for_verity_dev);
}
// Converts a AVB partition_name (without A/B suffix) to a device partition name.
@ -420,6 +371,10 @@ std::unique_ptr<VBMetaData> VerifyVBMetaData(int fd, const std::string& partitio
uint64_t vbmeta_size = VBMetaData::kMaxVBMetaSize;
bool is_vbmeta_partition = StartsWith(partition_name, "vbmeta");
if (out_verify_result) {
*out_verify_result = VBMetaVerifyResult::kError;
}
if (!is_vbmeta_partition) {
std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
if (!footer) {
@ -445,7 +400,10 @@ std::unique_ptr<VBMetaData> VerifyVBMetaData(int fd, const std::string& partitio
auto verify_result =
VerifyVBMetaSignature(*vbmeta, expected_public_key_blob, out_public_key_data);
if (out_verify_result != nullptr) *out_verify_result = verify_result;
if (out_verify_result != nullptr) {
*out_verify_result = verify_result;
}
if (verify_result == VBMetaVerifyResult::kSuccess ||
verify_result == VBMetaVerifyResult::kErrorVerification) {
@ -508,6 +466,10 @@ std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
const std::string& expected_public_key_blob, bool allow_verification_error,
bool rollback_protection, bool is_chained_vbmeta, std::string* out_public_key_data,
bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result) {
if (out_verify_result) {
*out_verify_result = VBMetaVerifyResult::kError;
}
// Ensures the device path (might be a symlink created by init) is ready to access.
if (!WaitForFile(image_path, 1s)) {
PERROR << "No such path: " << image_path;

View file

@ -24,19 +24,11 @@
#include <libavb/libavb.h>
#include <libdm/dm.h>
#include "fs_avb/fs_avb.h"
#include "fs_avb/types.h"
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;
@ -46,16 +38,13 @@ struct ChainInfo {
};
// AvbHashtreeDescriptor to dm-verity table setup.
std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
std::string* out_salt, std::string* out_digest);
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
const std::string& root_digest, const std::string& blk_device,
android::dm::DmTable* table);
bool ConstructVerityTable(const FsAvbHashtreeDescriptor& hashtree_desc,
const std::string& blk_device, android::dm::DmTable* table);
bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc,
const std::string& salt, const std::string& root_digest,
bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const FsAvbHashtreeDescriptor& hashtree_desc,
bool wait_for_verity_dev);
// Searches a Avb hashtree descriptor in vbmeta_images for fstab_entry, to enable dm-verity.

View file

@ -76,33 +76,6 @@ std::pair<std::string, size_t> CalculateVbmetaDigest(const std::vector<VBMetaDat
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

View file

@ -0,0 +1,78 @@
/*
* 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 "fs_avb/fs_avb_util.h"
#include <memory>
#include <string>
#include <vector>
#include <android-base/strings.h>
#include <fstab/fstab.h>
#include <libavb/libavb.h>
#include <libdm/dm.h>
#include "avb_util.h"
#include "util.h"
namespace android {
namespace fs_mgr {
// Given a FstabEntry, loads and verifies the vbmeta, to extract the Avb Hashtree descriptor.
std::unique_ptr<VBMetaData> LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
const std::string& expected_public_key_blob,
std::string* out_public_key_data,
std::string* out_avb_partition_name,
VBMetaVerifyResult* out_verify_result) {
// Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
// to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
std::string avb_partition_name = DeriveAvbPartitionName(fstab_entry, fs_mgr_get_slot_suffix(),
fs_mgr_get_other_slot_suffix());
if (out_avb_partition_name) {
*out_avb_partition_name = avb_partition_name;
}
// Updates fstab_entry->blk_device from <partition> to /dev/block/dm-<N> if
// it's a logical partition.
std::string device_path = fstab_entry.blk_device;
if (fstab_entry.fs_mgr_flags.logical &&
!android::base::StartsWith(fstab_entry.blk_device, "/")) {
dm::DeviceMapper& dm = dm::DeviceMapper::Instance();
if (!dm.GetDmDevicePathByName(fstab_entry.blk_device, &device_path)) {
LERROR << "Failed to resolve logical device path for: " << fstab_entry.blk_device;
return nullptr;
}
}
return LoadAndVerifyVbmetaByPath(device_path, avb_partition_name, expected_public_key_blob,
true /* allow_verification_error */,
false /* rollback_protection */, false /* is_chained_vbmeta */,
out_public_key_data, nullptr /* out_verification_disabled */,
out_verify_result);
}
// Given a path, loads and verifies the vbmeta, to extract the Avb Hashtree descriptor.
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& avb_partition_name, VBMetaData&& vbmeta) {
if (!vbmeta.size()) return nullptr;
std::vector<VBMetaData> vbmeta_images;
vbmeta_images.emplace_back(std::move(vbmeta));
return GetHashtreeDescriptor(avb_partition_name, vbmeta_images);
}
} // namespace fs_mgr
} // namespace android

View file

@ -21,32 +21,13 @@
#include <string>
#include <vector>
#include <fs_avb/types.h>
#include <fstab/fstab.h>
#include <libavb/libavb.h>
namespace android {
namespace fs_mgr {
enum class AvbHashtreeResult {
kSuccess = 0,
kFail,
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;
@ -58,51 +39,6 @@ struct VBMetaInfo {
: 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, 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, 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);
// Sets the vbmeta_path where we load the vbmeta data. Could be a partition or a file.
// e.g.,
// - /dev/block/by-name/system_a
// - /path/to/system_other.img.
void set_vbmeta_path(std::string vbmeta_path) { vbmeta_path_ = std::move(vbmeta_path); }
// Get methods for each data member.
const std::string& partition() const { return partition_name_; }
const std::string& vbmeta_path() const { return vbmeta_path_; }
uint8_t* data() const { return vbmeta_ptr_.get(); }
const size_t& size() const { return vbmeta_size_; }
// Maximum size of a vbmeta data - 64 KiB.
static const size_t kMaxVBMetaSize = 64 * 1024;
private:
std::unique_ptr<uint8_t[]> vbmeta_ptr_;
size_t vbmeta_size_;
std::string partition_name_;
std::string vbmeta_path_;
};
class FsManagerAvbOps;
class AvbHandle;

View file

@ -0,0 +1,40 @@
/*
* 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.
*/
#pragma once
#include <string>
#include <fs_avb/types.h>
#include <fstab/fstab.h>
#include <libavb/libavb.h>
namespace android {
namespace fs_mgr {
// Given a FstabEntry, loads and verifies the vbmeta.
std::unique_ptr<VBMetaData> LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
const std::string& expected_public_key_blob,
std::string* out_public_key_data,
std::string* out_avb_partition_name,
VBMetaVerifyResult* out_verify_result);
// Gets the hashtree descriptor for avb_partition_name from the vbmeta.
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& avb_partition_name, VBMetaData&& vbmeta);
} // namespace fs_mgr
} // namespace android

View file

@ -0,0 +1,110 @@
/*
* 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.
*/
#pragma once
#include <cstring>
#include <memory>
#include <ostream>
#include <libavb/libavb.h>
namespace android {
namespace fs_mgr {
enum class VBMetaVerifyResult {
kSuccess = 0,
kError = 1,
kErrorVerification = 2,
};
std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult);
enum class AvbHashtreeResult {
kSuccess = 0,
kFail,
kDisabled,
};
enum class HashAlgorithm {
kInvalid = 0,
kSHA256 = 1,
kSHA512 = 2,
};
enum class AvbHandleStatus {
kSuccess = 0,
kUninitialized = 1,
kHashtreeDisabled = 2,
kVerificationDisabled = 3,
kVerificationError = 4,
};
std::ostream& operator<<(std::ostream& os, AvbHandleStatus status);
struct FsAvbHashtreeDescriptor : AvbHashtreeDescriptor {
std::string partition_name;
std::string salt;
std::string root_digest;
};
class VBMetaData {
public:
// Constructors
VBMetaData() : vbmeta_ptr_(nullptr), vbmeta_size_(0){};
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.
std::memcpy(vbmeta_ptr_.get(), data, size * sizeof(uint8_t));
}
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);
// Sets the vbmeta_path where we load the vbmeta data. Could be a partition or a file.
// e.g.,
// - /dev/block/by-name/system_a
// - /path/to/system_other.img.
void set_vbmeta_path(std::string vbmeta_path) { vbmeta_path_ = std::move(vbmeta_path); }
// Get methods for each data member.
const std::string& partition() const { return partition_name_; }
const std::string& vbmeta_path() const { return vbmeta_path_; }
uint8_t* data() const { return vbmeta_ptr_.get(); }
const size_t& size() const { return vbmeta_size_; }
// Maximum size of a vbmeta data - 64 KiB.
static const size_t kMaxVBMetaSize = 64 * 1024;
private:
std::unique_ptr<uint8_t[]> vbmeta_ptr_;
size_t vbmeta_size_;
std::string partition_name_;
std::string vbmeta_path_;
};
} // namespace fs_mgr
} // namespace android

8
fs_mgr/libfs_avb/run_tests.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
#
# Run host tests
atest libfs_avb_test # Tests public libfs_avb APIs.
atest libfs_avb_internal_test # Tests libfs_avb private APIs.
# Run device tests
atest libfs_avb_device_test # Test public libfs_avb APIs on a device.

View file

@ -0,0 +1,93 @@
/*
* 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 <android-base/properties.h>
#include <fs_avb/fs_avb_util.h>
#include <fstab/fstab.h>
#include <gtest/gtest.h>
#include <sys/types.h>
#include <unistd.h>
using android::fs_mgr::Fstab;
using android::fs_mgr::FstabEntry;
using android::fs_mgr::VBMetaData;
using android::fs_mgr::VBMetaVerifyResult;
namespace fs_avb_device_test {
// system vbmeta might not be at the end of /system when dynamic partition is
// enabled. Therefore, disable it by default.
TEST(PublicFsAvbDeviceTest, DISABLED_LoadAndVerifyVbmeta_SystemVbmeta) {
Fstab fstab;
EXPECT_TRUE(ReadDefaultFstab(&fstab));
FstabEntry* system_entry = GetEntryForMountPoint(&fstab, "/system");
EXPECT_NE(nullptr, system_entry);
std::string out_public_key_data;
std::string out_avb_partition_name;
VBMetaVerifyResult out_verify_result;
std::unique_ptr<VBMetaData> vbmeta =
LoadAndVerifyVbmeta(*system_entry, "" /* expected_public_key_blob */,
&out_public_key_data, &out_avb_partition_name, &out_verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kSuccess, out_verify_result);
EXPECT_EQ("system", out_avb_partition_name);
EXPECT_NE("", out_public_key_data);
}
TEST(PublicFsAvbDeviceTest, GetHashtreeDescriptor_SystemOther) {
// Non-A/B device doesn't have system_other partition.
if (fs_mgr_get_slot_suffix() == "") return;
// Skip running this test if system_other is a logical partition.
// Note that system_other is still a physical partition on "retrofit" devices.
if (android::base::GetBoolProperty("ro.boot.dynamic_partitions", false) &&
!android::base::GetBoolProperty("ro.boot.dynamic_partitions_retrofit", false)) {
return;
}
Fstab fstab;
EXPECT_TRUE(ReadFstabFromFile("/system/etc/fstab.postinstall", &fstab));
// It should have two lines in the fstab, the first for logical system_other,
// the other for physical system_other.
EXPECT_EQ(2UL, fstab.size());
// Use the 2nd fstab entry, which is for physical system_other partition.
FstabEntry* system_other = &fstab[1];
EXPECT_NE(nullptr, system_other);
std::string out_public_key_data;
std::string out_avb_partition_name;
VBMetaVerifyResult out_verify_result;
std::unique_ptr<VBMetaData> system_other_vbmeta =
LoadAndVerifyVbmeta(*system_other, "" /* expected_public_key_blob */,
&out_public_key_data, &out_avb_partition_name, &out_verify_result);
EXPECT_NE(nullptr, system_other_vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kSuccess, out_verify_result);
EXPECT_EQ("system_other", out_avb_partition_name);
EXPECT_NE("", out_public_key_data);
auto hashtree_desc =
GetHashtreeDescriptor(out_avb_partition_name, std::move(*system_other_vbmeta));
EXPECT_NE(nullptr, hashtree_desc);
}
} // namespace fs_avb_device_test

View file

@ -29,7 +29,7 @@
#include <android-base/unique_fd.h>
#include <base/files/file_path.h>
#include <base/strings/stringprintf.h>
#include <fs_avb/fs_avb.h>
#include <fs_avb/types.h>
#include <gtest/gtest.h>
// Utility macro to run the command expressed by the printf()-style string

View file

@ -0,0 +1,120 @@
/*
* 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 <fs_avb/fs_avb_util.h>
#include "fs_avb_test_util.h"
namespace fs_avb_host_test {
class PublicFsAvbUtilTest : public BaseFsAvbTest {
public:
PublicFsAvbUtilTest(){};
protected:
~PublicFsAvbUtilTest(){};
};
TEST_F(PublicFsAvbUtilTest, GetHashtreeDescriptor) {
// Generates a raw system_other.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\"");
auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system-vbmeta.img");
auto hashtree_desc =
GetHashtreeDescriptor("system" /* avb_partition_name */, std::move(system_vbmeta));
EXPECT_NE(nullptr, hashtree_desc);
// Checks the returned hashtree_desc matches the following info returned by avbtool.
EXPECT_EQ(
"Footer version: 1.0\n"
"Image size: 15728640 bytes\n"
"Original image size: 10485760 bytes\n"
"VBMeta offset: 10661888\n"
"VBMeta size: 2112 bytes\n"
"--\n"
"Minimum libavb version: 1.0\n"
"Header Block: 256 bytes\n"
"Authentication Block: 576 bytes\n"
"Auxiliary Block: 1280 bytes\n"
"Algorithm: SHA512_RSA4096\n"
"Rollback Index: 20\n"
"Flags: 0\n"
"Release String: 'unit test'\n"
"Descriptors:\n"
" Hashtree descriptor:\n"
" Version of dm-verity: 1\n"
" Image Size: 10485760 bytes\n"
" Tree Offset: 10485760\n"
" Tree Size: 86016 bytes\n"
" Data Block Size: 4096 bytes\n"
" Hash Block Size: 4096 bytes\n"
" FEC num roots: 2\n"
" FEC offset: 10571776\n"
" FEC size: 90112 bytes\n"
" Hash Algorithm: sha1\n"
" Partition Name: system\n"
" Salt: d00df00d\n"
" Root Digest: a3d5dd307341393d85de356c384ff543ec1ed81b\n"
" Flags: 0\n",
InfoImage(system_path));
EXPECT_EQ(1UL, hashtree_desc->dm_verity_version);
EXPECT_EQ(10485760UL, hashtree_desc->image_size);
EXPECT_EQ(10485760UL, hashtree_desc->tree_offset);
EXPECT_EQ(86016UL, hashtree_desc->tree_size);
EXPECT_EQ(4096UL, hashtree_desc->data_block_size);
EXPECT_EQ(4096UL, hashtree_desc->hash_block_size);
EXPECT_EQ(2UL, hashtree_desc->fec_num_roots);
EXPECT_EQ(10571776UL, hashtree_desc->fec_offset);
EXPECT_EQ(90112UL, hashtree_desc->fec_size);
EXPECT_EQ(std::string("sha1"),
std::string(reinterpret_cast<const char*>(hashtree_desc->hash_algorithm)));
EXPECT_EQ(std::string("system").length(), hashtree_desc->partition_name_len);
EXPECT_EQ(hashtree_desc->partition_name, "system");
EXPECT_EQ(hashtree_desc->salt, "d00df00d");
EXPECT_EQ(hashtree_desc->root_digest, "a3d5dd307341393d85de356c384ff543ec1ed81b");
// Checks it's null if partition name doesn't match.
EXPECT_EQ(nullptr, GetHashtreeDescriptor("system_not_exist" /* avb_partition_name */,
std::move(system_vbmeta)));
}
TEST_F(PublicFsAvbUtilTest, GetHashtreeDescriptor_NotFound) {
// Generates a raw boot.img
const size_t image_size = 5 * 1024 * 1024;
const size_t partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", image_size);
// Appends AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", partition_size, "SHA256_RSA4096", 10,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Extracts boot vbmeta from boot.img into boot-vbmeta.img.
auto boot_vbmeta = ExtractAndLoadVBMetaData(boot_path, "boot-vbmeta.img");
auto hashtree_desc =
GetHashtreeDescriptor("boot" /* avb_partition_name */, std::move(boot_vbmeta));
EXPECT_EQ(nullptr, hashtree_desc);
}
} // namespace fs_avb_host_test

View file

@ -0,0 +1,94 @@
/*
* 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 "fs_avb/types.h"
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;
}
// 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 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;
}
} // namespace fs_mgr
} // namespace android