Merge "fs_mgr_avb: refactors how vbmeta is loaded" am: fc500ddb52

am: a6db40c7cd

Change-Id: I353b7601d616aa736d82659ad90c4828aec07383
This commit is contained in:
Bowgo Tsai 2017-04-13 20:15:05 +00:00 committed by android-build-merger
commit 0265f55b44
6 changed files with 335 additions and 341 deletions

View file

@ -707,6 +707,23 @@ static int handle_encryptable(const struct fstab_rec* rec)
}
}
static std::string extract_by_name_prefix(struct fstab* fstab) {
// We assume that there's an entry for the /misc mount point in the
// fstab file and use that to get the device file by-name prefix.
// The device needs not to have an actual /misc partition.
// e.g.,
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/
struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
if (fstab_entry == nullptr) {
LERROR << "/misc mount point not found in fstab";
return "";
}
std::string full_path(fstab_entry->blk_device);
size_t end_slash = full_path.find_last_of("/");
return full_path.substr(0, end_slash + 1);
}
// TODO: add ueventd notifiers if they don't exist.
// This is just doing a wait_for_device for maximum of 1s
int fs_mgr_test_access(const char *device) {
@ -750,17 +767,12 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
int mret = -1;
int mount_errno = 0;
int attempted_idx = -1;
int avb_ret = FS_MGR_SETUP_AVB_FAIL;
FsManagerAvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return -1;
}
if (fs_mgr_is_avb_used() &&
(avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
return -1;
}
for (i = 0; i < fstab->num_entries; i++) {
/* Don't mount entries that are managed by vold or not for the mount mode*/
if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
@ -799,16 +811,15 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
}
if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
/* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
* should set up the device without using dm-verity.
* The actual mounting still take place in the following
* mount_with_alternatives().
*/
if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
LINFO << "AVB HASHTREE disabled";
} else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
FS_MGR_SETUP_AVB_SUCCESS) {
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return -1;
}
}
if (!avb_handle->SetUpAvb(&fstab->recs[i])) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@ -934,10 +945,6 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
}
}
if (fs_mgr_is_avb_used()) {
fs_mgr_unload_vbmeta_images();
}
if (error_count) {
return -1;
} else {
@ -976,17 +983,12 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
int mount_errors = 0;
int first_mount_errno = 0;
char *m;
int avb_ret = FS_MGR_SETUP_AVB_FAIL;
FsManagerAvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return ret;
}
if (fs_mgr_is_avb_used() &&
(avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
return ret;
}
for (i = 0; i < fstab->num_entries; i++) {
if (!fs_match(fstab->recs[i].mount_point, n_name)) {
continue;
@ -1021,16 +1023,15 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat);
}
if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
/* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
* should set up the device without using dm-verity.
* The actual mounting still take place in the following
* mount_with_alternatives().
*/
if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
LINFO << "AVB HASHTREE disabled";
} else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
FS_MGR_SETUP_AVB_SUCCESS) {
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return -1;
}
}
if (!avb_handle->SetUpAvb(&fstab->recs[i])) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@ -1079,9 +1080,6 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
}
out:
if (fs_mgr_is_avb_used()) {
fs_mgr_unload_vbmeta_images();
}
return ret;
}

View file

@ -28,6 +28,7 @@
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
@ -85,24 +86,6 @@
hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_start */ \
VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
AvbSlotVerifyData* fs_mgr_avb_verify_data = nullptr;
AvbOps* fs_mgr_avb_ops = nullptr;
enum HashAlgorithm {
kInvalid = 0,
kSHA256 = 1,
kSHA512 = 2,
};
struct androidboot_vbmeta {
HashAlgorithm hash_alg;
uint8_t digest[SHA512_DIGEST_LENGTH];
size_t vbmeta_size;
bool allow_verification_error;
};
androidboot_vbmeta fs_mgr_vbmeta_prop;
static inline bool nibble_value(const char& c, uint8_t* value) {
FS_MGR_CHECK(value != nullptr);
@ -159,27 +142,78 @@ static std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
return hex;
}
static bool load_vbmeta_prop(androidboot_vbmeta* vbmeta_prop) {
FS_MGR_CHECK(vbmeta_prop != nullptr);
template <typename Hasher>
static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data,
const uint8_t* expected_digest) {
size_t total_size = 0;
Hasher hasher;
for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
hasher.update(verify_data.vbmeta_images[n].vbmeta_data,
verify_data.vbmeta_images[n].vbmeta_size);
total_size += verify_data.vbmeta_images[n].vbmeta_size;
}
bool matched = (memcmp(hasher.finalize(), expected_digest, Hasher::DIGEST_SIZE) == 0);
return std::make_pair(total_size, matched);
}
// Reads the following values from kernel cmdline and provides the
// VerifyVbmetaImages() to verify AvbSlotVerifyData.
// - androidboot.vbmeta.device_state
// - androidboot.vbmeta.hash_alg
// - androidboot.vbmeta.size
// - androidboot.vbmeta.digest
class FsManagerAvbVerifier {
public:
// The factory method to return a unique_ptr<FsManagerAvbVerifier>
static std::unique_ptr<FsManagerAvbVerifier> Create();
bool VerifyVbmetaImages(const AvbSlotVerifyData& verify_data);
bool IsDeviceUnlocked() { return is_device_unlocked_; }
protected:
FsManagerAvbVerifier() = default;
private:
enum HashAlgorithm {
kInvalid = 0,
kSHA256 = 1,
kSHA512 = 2,
};
HashAlgorithm hash_alg_;
uint8_t digest_[SHA512_DIGEST_LENGTH];
size_t vbmeta_size_;
bool is_device_unlocked_;
};
std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() {
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
LERROR << "Failed to read /proc/cmdline";
return nullptr;
}
std::unique_ptr<FsManagerAvbVerifier> avb_verifier(new FsManagerAvbVerifier());
if (!avb_verifier) {
LERROR << "Failed to create unique_ptr<FsManagerAvbVerifier>";
return nullptr;
}
std::string hash_alg;
std::string digest;
std::string hash_alg;
for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
std::vector<std::string> pieces = android::base::Split(entry, "=");
const std::string& key = pieces[0];
const std::string& value = pieces[1];
if (key == "androidboot.vbmeta.device_state") {
vbmeta_prop->allow_verification_error = (value == "unlocked");
avb_verifier->is_device_unlocked_ = (value == "unlocked");
} else if (key == "androidboot.vbmeta.hash_alg") {
hash_alg = value;
} else if (key == "androidboot.vbmeta.size") {
if (!android::base::ParseUint(value.c_str(), &vbmeta_prop->vbmeta_size)) {
return false;
if (!android::base::ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) {
return nullptr;
}
} else if (key == "androidboot.vbmeta.digest") {
digest = value;
@ -190,48 +224,31 @@ static bool load_vbmeta_prop(androidboot_vbmeta* vbmeta_prop) {
size_t expected_digest_size = 0;
if (hash_alg == "sha256") {
expected_digest_size = SHA256_DIGEST_LENGTH * 2;
vbmeta_prop->hash_alg = kSHA256;
avb_verifier->hash_alg_ = kSHA256;
} else if (hash_alg == "sha512") {
expected_digest_size = SHA512_DIGEST_LENGTH * 2;
vbmeta_prop->hash_alg = kSHA512;
avb_verifier->hash_alg_ = kSHA512;
} else {
LERROR << "Unknown hash algorithm: " << hash_alg.c_str();
return false;
return nullptr;
}
// Reads digest.
if (digest.size() != expected_digest_size) {
LERROR << "Unexpected digest size: " << digest.size()
<< " (expected: " << expected_digest_size << ")";
return false;
return nullptr;
}
if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest), digest)) {
if (!hex_to_bytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) {
LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str();
return false;
return nullptr;
}
return true;
return avb_verifier;
}
template <typename Hasher>
static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data,
const androidboot_vbmeta& vbmeta_prop) {
size_t total_size = 0;
Hasher hasher;
for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
hasher.update(verify_data.vbmeta_images[n].vbmeta_data,
verify_data.vbmeta_images[n].vbmeta_size);
total_size += verify_data.vbmeta_images[n].vbmeta_size;
}
bool matched = (memcmp(hasher.finalize(), vbmeta_prop.digest, Hasher::DIGEST_SIZE) == 0);
return std::make_pair(total_size, matched);
}
static bool verify_vbmeta_images(const AvbSlotVerifyData& verify_data,
const androidboot_vbmeta& vbmeta_prop) {
bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
if (verify_data.num_vbmeta_images == 0) {
LERROR << "No vbmeta images";
return false;
@ -240,17 +257,17 @@ static bool verify_vbmeta_images(const AvbSlotVerifyData& verify_data,
size_t total_size = 0;
bool digest_matched = false;
if (vbmeta_prop.hash_alg == kSHA256) {
if (hash_alg_ == kSHA256) {
std::tie(total_size, digest_matched) =
verify_vbmeta_digest<SHA256Hasher>(verify_data, vbmeta_prop);
} else if (vbmeta_prop.hash_alg == kSHA512) {
verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
} else if (hash_alg_ == kSHA512) {
std::tie(total_size, digest_matched) =
verify_vbmeta_digest<SHA512Hasher>(verify_data, vbmeta_prop);
verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
}
if (total_size != vbmeta_prop.vbmeta_size) {
LERROR << "total vbmeta size mismatch: " << total_size
<< " (expected: " << vbmeta_prop.vbmeta_size << ")";
if (total_size != vbmeta_size_) {
LERROR << "total vbmeta size mismatch: " << total_size << " (expected: " << vbmeta_size_
<< ")";
return false;
}
@ -408,8 +425,7 @@ static bool get_hashtree_descriptor(const std::string& partition_name,
continue;
}
if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
desc_partition_name =
(const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
desc_partition_name = (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
if (!avb_hashtree_descriptor_validate_and_byteswap(
(AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
continue;
@ -441,134 +457,96 @@ static bool get_hashtree_descriptor(const std::string& partition_name,
return true;
}
static bool init_is_avb_used() {
// When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
// size, digest} in kernel cmdline or in device tree. They will then be
// imported by init process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
//
// In case of early mount, init properties are not initialized, so we also
// ensure we look into kernel command line and device tree if the property is
// not found
//
// Checks hash_alg as an indicator for whether AVB is used.
// We don't have to parse and check all of them here. The check will
// be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will
// be returned when there is an error.
std::string hash_alg;
if (!fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg)) {
return false;
}
if (hash_alg == "sha256" || hash_alg == "sha512") {
return true;
}
return false;
}
bool fs_mgr_is_avb_used() {
static bool result = init_is_avb_used();
return result;
}
int fs_mgr_load_vbmeta_images(struct fstab* fstab) {
FS_MGR_CHECK(fstab != nullptr);
// Gets the expected hash value of vbmeta images from
// kernel cmdline.
if (!load_vbmeta_prop(&fs_mgr_vbmeta_prop)) {
return FS_MGR_SETUP_AVB_FAIL;
FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const std::string& device_file_by_name_prefix) {
if (device_file_by_name_prefix.empty()) {
LERROR << "Missing device file by-name prefix";
return nullptr;
}
fs_mgr_avb_ops = fs_mgr_dummy_avb_ops_new(fstab);
if (fs_mgr_avb_ops == nullptr) {
LERROR << "Failed to allocate dummy avb_ops";
return FS_MGR_SETUP_AVB_FAIL;
// Gets the expected hash value of vbmeta images from kernel cmdline.
std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
if (!avb_verifier) {
LERROR << "Failed to create FsManagerAvbVerifier";
return nullptr;
}
// Invokes avb_slot_verify() to load and verify all vbmeta images.
// Sets requested_partitions to nullptr as it's to copy the contents
// of HASH partitions into fs_mgr_avb_verify_data, which is not required as
// fs_mgr only deals with HASHTREE partitions.
const char* requested_partitions[] = {nullptr};
std::string ab_suffix = fs_mgr_get_slot_suffix();
FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
if (!avb_handle) {
LERROR << "Failed to allocate FsManagerAvbHandle";
return nullptr;
}
AvbSlotVerifyResult verify_result =
avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix.c_str(),
fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
FsManagerAvbOps avb_ops(device_file_by_name_prefix);
AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify(
fs_mgr_get_slot_suffix(), avb_verifier->IsDeviceUnlocked(), &avb_handle->avb_slot_data_);
// Only allow two verify results:
// - AVB_SLOT_VERIFY_RESULT_OK.
// - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state).
if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
if (!fs_mgr_vbmeta_prop.allow_verification_error) {
if (!avb_verifier->IsDeviceUnlocked()) {
LERROR << "ERROR_VERIFICATION isn't allowed";
goto fail;
return nullptr;
}
} else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
LERROR << "avb_slot_verify failed, result: " << verify_result;
goto fail;
return nullptr;
}
// Verifies vbmeta images against the digest passed from bootloader.
if (!verify_vbmeta_images(*fs_mgr_avb_verify_data, fs_mgr_vbmeta_prop)) {
LERROR << "verify_vbmeta_images failed";
goto fail;
if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
LERROR << "VerifyVbmetaImages failed";
return nullptr;
} else {
// Checks whether FLAGS_HASHTREE_DISABLED is set.
AvbVBMetaImageHeader vbmeta_header;
avb_vbmeta_image_header_to_host_byte_order(
(AvbVBMetaImageHeader*)fs_mgr_avb_verify_data->vbmeta_images[0].vbmeta_data,
(AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
&vbmeta_header);
bool hashtree_disabled =
((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
if (hashtree_disabled) {
return FS_MGR_SETUP_AVB_HASHTREE_DISABLED;
avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled;
return avb_handle;
}
}
if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
return FS_MGR_SETUP_AVB_SUCCESS;
avb_handle->status_ = kFsManagerAvbHandleSuccess;
return avb_handle;
}
fail:
fs_mgr_unload_vbmeta_images();
return FS_MGR_SETUP_AVB_FAIL;
return nullptr;
}
void fs_mgr_unload_vbmeta_images() {
if (fs_mgr_avb_verify_data != nullptr) {
avb_slot_verify_data_free(fs_mgr_avb_verify_data);
bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry) {
if (!fstab_entry) return false;
if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) {
return false;
}
if (fs_mgr_avb_ops != nullptr) {
fs_mgr_dummy_avb_ops_free(fs_mgr_avb_ops);
}
}
int fs_mgr_setup_avb(struct fstab_rec* fstab_entry) {
if (!fstab_entry || !fs_mgr_avb_verify_data || fs_mgr_avb_verify_data->num_vbmeta_images < 1) {
return FS_MGR_SETUP_AVB_FAIL;
if (status_ == kFsManagerAvbHandleHashtreeDisabled) {
LINFO << "AVB HASHTREE disabled on:" << fstab_entry->mount_point;
return true;
}
if (status_ != kFsManagerAvbHandleSuccess) return false;
std::string partition_name(basename(fstab_entry->mount_point));
if (!avb_validate_utf8((const uint8_t*)partition_name.c_str(), partition_name.length())) {
LERROR << "Partition name: " << partition_name.c_str() << " is not valid UTF-8.";
return FS_MGR_SETUP_AVB_FAIL;
return false;
}
AvbHashtreeDescriptor hashtree_descriptor;
std::string salt;
std::string root_digest;
if (!get_hashtree_descriptor(partition_name, *fs_mgr_avb_verify_data, &hashtree_descriptor,
&salt, &root_digest)) {
return FS_MGR_SETUP_AVB_FAIL;
if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt,
&root_digest)) {
return false;
}
// Converts HASHTREE descriptor to verity_table_params.
if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest)) {
return FS_MGR_SETUP_AVB_FAIL;
return false;
}
return FS_MGR_SETUP_AVB_SUCCESS;
return true;
}

View file

@ -39,91 +39,10 @@
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
static std::string fstab_by_name_prefix;
static std::string extract_by_name_prefix(struct fstab* fstab) {
// In AVB, we can assume that there's an entry for the /misc mount
// point in the fstab file and use that to get the device file for
// the misc partition. The device needs not to have an actual /misc
// partition. Then returns the prefix by removing the trailing "misc":
//
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/
struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
if (fstab_entry == nullptr) {
LERROR << "/misc mount point not found in fstab";
return "";
}
std::string full_path(fstab_entry->blk_device);
size_t end_slash = full_path.find_last_of("/");
return full_path.substr(0, end_slash + 1);
}
static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition,
int64_t offset, size_t num_bytes, void* buffer,
size_t* out_num_read) {
// The input |partition| name is with ab_suffix, e.g. system_a.
// Slot suffix (e.g. _a) will be appended to the device file path
// for partitions having 'slotselect' optin in fstab file, but it
// won't be appended to the mount point.
//
// Appends |partition| to the fstab_by_name_prefix, which is obtained
// by removing the trailing "misc" from the device file of /misc mount
// point. e.g.,
//
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
std::string path = fstab_by_name_prefix + partition;
// Ensures the device path (a symlink created by init) is ready to
// access. fs_mgr_test_access() will test a few iterations if the
// path doesn't exist yet.
if (fs_mgr_test_access(path.c_str()) < 0) {
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
}
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
PERROR << "Failed to open " << path.c_str();
return AVB_IO_RESULT_ERROR_IO;
}
// If offset is negative, interprets its absolute value as the
// number of bytes from the end of the partition.
if (offset < 0) {
off64_t total_size = lseek64(fd, 0, SEEK_END);
if (total_size == -1) {
LERROR << "Failed to lseek64 to end of the partition";
return AVB_IO_RESULT_ERROR_IO;
}
offset = total_size + offset;
// Repositions the offset to the beginning.
if (lseek64(fd, 0, SEEK_SET) == -1) {
LERROR << "Failed to lseek64 to the beginning of the partition";
return AVB_IO_RESULT_ERROR_IO;
}
}
// On Linux, we never get partial reads from block devices (except
// for EOF).
ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
if (num_read < 0 || (size_t)num_read != num_bytes) {
PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
<< offset;
return AVB_IO_RESULT_ERROR_IO;
}
if (out_num_read != nullptr) {
*out_num_read = num_read;
}
return AVB_IO_RESULT_OK;
static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
size_t num_bytes, void* buffer, size_t* out_num_read) {
return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
partition, offset, num_bytes, buffer, out_num_read);
}
static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
@ -145,7 +64,6 @@ static AvbIOResult dummy_validate_vbmeta_public_key(
// Addtionally, user-space should check
// androidboot.vbmeta.{hash_alg, size, digest} against the digest
// of all vbmeta images after invoking avb_slot_verify().
*out_is_trusted = true;
return AVB_IO_RESULT_OK;
}
@ -170,28 +88,86 @@ static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNU
return AVB_IO_RESULT_OK;
}
AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) {
AvbOps* ops;
fstab_by_name_prefix = extract_by_name_prefix(fstab);
if (fstab_by_name_prefix.empty()) return nullptr;
ops = (AvbOps*)calloc(1, sizeof(AvbOps));
if (ops == nullptr) {
LERROR << "Error allocating memory for AvbOps";
return nullptr;
FsManagerAvbOps::FsManagerAvbOps(const std::string& device_file_by_name_prefix)
: device_file_by_name_prefix_(device_file_by_name_prefix) {
if (device_file_by_name_prefix_.back() != '/') {
device_file_by_name_prefix_ += '/';
}
// We only need to provide the implementation of read_from_partition()
// operation since that's all what is being used by the avb_slot_verify().
// Other I/O operations are only required in bootloader but not in
// user-space so we set them as dummy operations.
avb_ops_.read_from_partition = read_from_partition;
avb_ops_.read_rollback_index = dummy_read_rollback_index;
avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked;
avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
// We only need these operations since that's all what is being used
// by the avb_slot_verify(); Most of them are dummy operations because
// they're only required in bootloader but not required in user-space.
ops->read_from_partition = read_from_partition;
ops->read_rollback_index = dummy_read_rollback_index;
ops->validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
ops->read_is_device_unlocked = dummy_read_is_device_unlocked;
ops->get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
return ops;
// Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
avb_ops_.user_data = this;
}
void fs_mgr_dummy_avb_ops_free(AvbOps* ops) { free(ops); }
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
size_t num_bytes, void* buffer,
size_t* out_num_read) {
// Appends |partition| to the device_file_by_name_prefix_, e.g.,
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
std::string path = device_file_by_name_prefix_ + partition;
// Ensures the device path (a symlink created by init) is ready to
// access. fs_mgr_test_access() will test a few iterations if the
// path doesn't exist yet.
if (fs_mgr_test_access(path.c_str()) < 0) {
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
}
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
PERROR << "Failed to open " << path.c_str();
return AVB_IO_RESULT_ERROR_IO;
}
// If offset is negative, interprets its absolute value as the
// number of bytes from the end of the partition.
if (offset < 0) {
off64_t total_size = lseek64(fd, 0, SEEK_END);
if (total_size == -1) {
LERROR << "Failed to lseek64 to end of the partition";
return AVB_IO_RESULT_ERROR_IO;
}
offset = total_size + offset;
// Repositions the offset to the beginning.
if (lseek64(fd, 0, SEEK_SET) == -1) {
LERROR << "Failed to lseek64 to the beginning of the partition";
return AVB_IO_RESULT_ERROR_IO;
}
}
// On Linux, we never get partial reads from block devices (except
// for EOF).
ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
if (num_read < 0 || (size_t)num_read != num_bytes) {
PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
<< offset;
return AVB_IO_RESULT_ERROR_IO;
}
if (out_num_read != nullptr) {
*out_num_read = num_read;
}
return AVB_IO_RESULT_OK;
}
AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
bool allow_verification_error,
AvbSlotVerifyData** out_data) {
// Invokes avb_slot_verify() to load and verify all vbmeta images.
// Sets requested_partitions to nullptr as it's to copy the contents
// of HASH partitions into handle>avb_slot_data_, which is not required as
// fs_mgr only deals with HASHTREE partitions.
const char* requested_partitions[] = {nullptr};
return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(),
allow_verification_error, out_data);
}

View file

@ -29,31 +29,34 @@
#include "fs_mgr.h"
__BEGIN_DECLS
// This class provides C++ bindings to interact with libavb, a small
// self-contained piece of code that's intended to be used in bootloaders.
// It mainly contains two functions:
// - ReadFromPartition(): to read AVB metadata from a given partition.
// It provides the implementation of AvbOps.read_from_partition() when
// reading metadata through libavb.
// - AvbSlotVerify(): the C++ binding of libavb->avb_slot_verify() to
// read and verify the metadata and store it into the out_data parameter.
// The caller MUST check the integrity of metadata against the
// androidboot.vbmeta.{hash_alg, size, digest} values from /proc/cmdline.
// e.g., see class FsManagerAvbVerifier for more details.
//
class FsManagerAvbOps {
public:
FsManagerAvbOps(const std::string& device_file_by_name_prefix);
/* Allocates a "dummy" AvbOps instance solely for use in user-space.
* Returns nullptr on OOM.
*
* It mainly provides read_from_partitions() for user-space to get
* AvbSlotVerifyData.vbmeta_images[] and the caller MUST check their
* integrity against the androidboot.vbmeta.{hash_alg, size, digest}
* values from /proc/cmdline, e.g. verify_vbmeta_images()
* in fs_mgr_avb.cpp.
*
* Other I/O operations are only required in boot loader so we set
* them as dummy operations here.
* - Will allow any public key for signing.
* - returns 0 for any rollback index location.
* - returns device is unlocked regardless of the actual state.
* - returns a dummy guid for any partition.
*
* Frees with fs_mgr_dummy_avb_ops_free().
*/
AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab);
static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
}
/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */
void fs_mgr_dummy_avb_ops_free(AvbOps* ops);
AvbIOResult ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes,
void* buffer, size_t* out_num_read);
__END_DECLS
AvbSlotVerifyResult AvbSlotVerify(const std::string& ab_suffix, bool allow_verification_error,
AvbSlotVerifyData** out_data);
private:
AvbOps avb_ops_;
std::string device_file_by_name_prefix_;
};
#endif /* __CORE_FS_MGR_AVB_OPS_H */

View file

@ -17,40 +17,77 @@
#ifndef __CORE_FS_MGR_PRIV_AVB_H
#define __CORE_FS_MGR_PRIV_AVB_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include <memory>
#include <string>
#include <libavb/libavb.h>
#include "fs_mgr.h"
__BEGIN_DECLS
enum FsManagerAvbHandleStatus {
kFsManagerAvbHandleSuccess = 0,
kFsManagerAvbHandleHashtreeDisabled = 1,
kFsManagerAvbHandleFail = 2,
};
#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2)
#define FS_MGR_SETUP_AVB_FAIL (-1)
#define FS_MGR_SETUP_AVB_SUCCESS 0
class FsManagerAvbHandle;
using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
bool fs_mgr_is_avb_used();
// Provides a factory method to return a unique_ptr pointing to itself and the
// SetUpAvb() function to extract dm-verity parameters from AVB metadata to
// load verity table into kernel through ioctl.
class FsManagerAvbHandle {
public:
// The factory method to return a FsManagerAvbUniquePtr that holds
// the verified AVB (external/avb) metadata of all verified partitions
// in avb_slot_data_.vbmeta_images[].
//
// The metadata is checked against the following values from /proc/cmdline.
// - androidboot.vbmeta.{hash_alg, size, digest}.
//
// A typical usage will be:
// - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
//
// 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 kFsMgrAvbHandleHashtreeDisabled:
// 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 kFsMgrAvbHandleSuccess: the metadata
// is verified and can be trusted.
//
static FsManagerAvbUniquePtr Open(const std::string& device_file_by_name_prefix);
/* Gets AVB metadata through external/avb/libavb for all partitions:
* AvbSlotVerifyData.vbmeta_images[] and checks their integrity
* against the androidboot.vbmeta.{hash_alg, size, digest} values
* from /proc/cmdline.
*
* Return values:
* - FS_MGR_SETUP_AVB_SUCCESS: the metadata cab be trusted.
* - FS_MGR_SETUP_AVB_FAIL: any error when reading and verifying the
* metadata, e.g. I/O error, digest value mismatch, size mismatch.
* - FS_MGR_SETUP_AVB_HASHTREE_DISABLED: 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.
*/
int fs_mgr_load_vbmeta_images(struct fstab* fstab);
// Sets up dm-verity on the given fstab entry.
// Returns true if the mount point is eligible to mount, it includes:
// - status_ is kFsMgrAvbHandleHashtreeDisabled or
// - status_ is kFsMgrAvbHandleSuccess and sending ioctl DM_TABLE_LOAD
// to load verity table is success.
// Otherwise, returns false.
bool SetUpAvb(fstab_rec* fstab_entry);
void fs_mgr_unload_vbmeta_images();
FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
int fs_mgr_setup_avb(struct fstab_rec* fstab_entry);
FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move
FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
__END_DECLS
~FsManagerAvbHandle() {
if (avb_slot_data_) {
avb_slot_verify_data_free(avb_slot_data_);
}
};
protected:
FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleFail) {}
private:
AvbSlotVerifyData* avb_slot_data_;
FsManagerAvbHandleStatus status_;
};
#endif /* __CORE_FS_MGR_PRIV_AVB_H */

View file

@ -20,16 +20,18 @@
#include <openssl/sha.h>
class SHA256Hasher {
private:
private:
SHA256_CTX sha256_ctx;
uint8_t hash[SHA256_DIGEST_LENGTH];
public:
public:
enum { DIGEST_SIZE = SHA256_DIGEST_LENGTH };
SHA256Hasher() { SHA256_Init(&sha256_ctx); }
void update(const void* data, size_t data_size) { SHA256_Update(&sha256_ctx, data, data_size); }
void update(const uint8_t* data, size_t data_size) {
SHA256_Update(&sha256_ctx, data, data_size);
}
const uint8_t* finalize() {
SHA256_Final(hash, &sha256_ctx);
@ -38,11 +40,11 @@ class SHA256Hasher {
};
class SHA512Hasher {
private:
private:
SHA512_CTX sha512_ctx;
uint8_t hash[SHA512_DIGEST_LENGTH];
public:
public:
enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH };
SHA512Hasher() { SHA512_Init(&sha512_ctx); }