Merge "libfs_avb: adding two public APIs"
This commit is contained in:
commit
c7b5c4fa6b
14 changed files with 611 additions and 182 deletions
|
|
@ -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",
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
78
fs_mgr/libfs_avb/fs_avb_util.cpp
Normal file
78
fs_mgr/libfs_avb/fs_avb_util.cpp
Normal 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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
40
fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
Normal file
40
fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
Normal 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
|
||||
110
fs_mgr/libfs_avb/include/fs_avb/types.h
Normal file
110
fs_mgr/libfs_avb/include/fs_avb/types.h
Normal 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
8
fs_mgr/libfs_avb/run_tests.sh
Executable 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.
|
||||
93
fs_mgr/libfs_avb/tests/fs_avb_device_test.cpp
Normal file
93
fs_mgr/libfs_avb/tests/fs_avb_device_test.cpp
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
120
fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp
Normal file
120
fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp
Normal 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
|
||||
94
fs_mgr/libfs_avb/types.cpp
Normal file
94
fs_mgr/libfs_avb/types.cpp
Normal 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
|
||||
Loading…
Add table
Reference in a new issue