Merge "fs_mgr: support using libavb to enable dm-verity"

This commit is contained in:
Treehugger Robot 2017-01-25 18:24:28 +00:00 committed by Gerrit Code Review
commit 0a3c2392c7
11 changed files with 1110 additions and 5 deletions

View File

@ -11,7 +11,8 @@ common_static_libraries := \
libcrypto \
libext4_utils \
libsquashfs_utils \
libselinux
libselinux \
libavb
include $(CLEAR_VARS)
LOCAL_CLANG := true
@ -22,7 +23,9 @@ LOCAL_SRC_FILES:= \
fs_mgr_format.c \
fs_mgr_fstab.c \
fs_mgr_slotselect.c \
fs_mgr_verity.cpp
fs_mgr_verity.cpp \
fs_mgr_avb.cpp \
fs_mgr_avb_ops.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
system/vold \

View File

@ -46,6 +46,7 @@
#include <private/android_logger.h>
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_avb.h"
#include "fs_mgr_priv_verity.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
@ -670,11 +671,17 @@ 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;
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)) ||
@ -713,7 +720,22 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
}
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
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) {
INFO("AVB HASHTREE disabled\n");
} else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
FS_MGR_SETUP_AVB_SUCCESS) {
ERROR("Failed to set up AVB on partition: %s, skipping!\n",
fstab->recs[i].mount_point);
/* Skips mounting the device. */
continue;
}
} else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
INFO("Verity disabled");
@ -722,6 +744,7 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
continue;
}
}
int last_idx_inspected;
int top_idx = i;
@ -825,6 +848,10 @@ 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 {
@ -845,11 +872,17 @@ 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;
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;
@ -882,7 +915,22 @@ 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]);
}
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
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) {
INFO("AVB HASHTREE disabled\n");
} else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
FS_MGR_SETUP_AVB_SUCCESS) {
ERROR("Failed to set up AVB on partition: %s, skipping!\n",
fstab->recs[i].mount_point);
/* Skips mounting the device. */
continue;
}
} else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
INFO("Verity disabled");
@ -921,6 +969,9 @@ 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;
}

642
fs_mgr/fs_mgr_avb.cpp Normal file
View File

@ -0,0 +1,642 @@
/*
* Copyright (C) 2016 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 <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libgen.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <libavb/libavb.h>
#include <openssl/sha.h>
#include <sys/ioctl.h>
#include <utils/Compat.h>
#include "fs_mgr.h"
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_avb.h"
#include "fs_mgr_priv_dm_ioctl.h"
#include "fs_mgr_priv_sha.h"
/* The format of dm-verity construction parameters:
* <version> <dev> <hash_dev> <data_block_size> <hash_block_size>
* <num_data_blocks> <hash_start_block> <algorithm> <digest> <salt>
*/
#define VERITY_TABLE_FORMAT \
"%u %s %s %u %u " \
"%" PRIu64 " %" PRIu64 " %s %s %s "
#define VERITY_TABLE_PARAMS(hashtree_desc, blk_device, digest, salt) \
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, /* num_data_blocks. */ \
hashtree_desc.tree_offset / \
hashtree_desc.hash_block_size, /* hash_start_block. */ \
(char *)hashtree_desc.hash_algorithm, digest, salt
#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
/* The default format of dm-verity optional parameters:
* <#opt_params> ignore_zero_blocks restart_on_corruption
*/
#define VERITY_TABLE_OPT_DEFAULT_FORMAT "2 %s %s"
#define VERITY_TABLE_OPT_DEFAULT_PARAMS \
VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
/* The FEC (forward error correction) format of dm-verity optional parameters:
* <#opt_params> use_fec_from_device <fec_dev>
* fec_roots <num> fec_blocks <num> fec_start <offset>
* ignore_zero_blocks restart_on_corruption
*/
#define VERITY_TABLE_OPT_FEC_FORMAT \
"10 use_fec_from_device %s fec_roots %u fec_blocks %" PRIu64 \
" fec_start %" PRIu64 " %s %s"
/* Note that fec_blocks is the size that FEC covers, *not* the
* size of the FEC data. Since we use FEC for everything up until
* the FEC data, it's the same as the offset (fec_start).
*/
#define VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device) \
blk_device, hashtree_desc.fec_num_roots, \
hashtree_desc.fec_offset / \
hashtree_desc.data_block_size, /* fec_blocks */ \
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);
switch (c) {
case '0' ... '9':
*value = c - '0';
break;
case 'a' ... 'f':
*value = c - 'a' + 10;
break;
case 'A' ... 'F':
*value = c - 'A' + 10;
break;
default:
return false;
}
return true;
}
static bool hex_to_bytes(uint8_t *bytes,
size_t bytes_len,
const std::string &hex)
{
FS_MGR_CHECK(bytes != nullptr);
if (hex.size() % 2 != 0) {
return false;
}
if (hex.size() / 2 > bytes_len) {
return false;
}
for (size_t i = 0, j = 0, n = hex.size(); i < n; i += 2, ++j) {
uint8_t high;
if (!nibble_value(hex[i], &high)) {
return false;
}
uint8_t low;
if (!nibble_value(hex[i + 1], &low)) {
return false;
}
bytes[j] = (high << 4) | low;
}
return true;
}
static std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len)
{
FS_MGR_CHECK(bytes != nullptr);
static const char *hex_digits = "0123456789abcdef";
std::string hex;
for (size_t i = 0; i < bytes_len; i++) {
hex.push_back(hex_digits[(bytes[i] & 0xF0) >> 4]);
hex.push_back(hex_digits[bytes[i] & 0x0F]);
}
return hex;
}
static bool load_vbmeta_prop(androidboot_vbmeta *vbmeta_prop)
{
FS_MGR_CHECK(vbmeta_prop != nullptr);
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
std::string hash_alg;
std::string digest;
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");
} 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;
}
} else if (key == "androidboot.vbmeta.digest") {
digest = value;
}
}
// Reads hash algorithm.
size_t expected_digest_size = 0;
if (hash_alg == "sha256") {
expected_digest_size = SHA256_DIGEST_LENGTH * 2;
vbmeta_prop->hash_alg = kSHA256;
} else if (hash_alg == "sha512") {
expected_digest_size = SHA512_DIGEST_LENGTH * 2;
vbmeta_prop->hash_alg = kSHA512;
} else {
ERROR("Unknown hash algorithm: %s\n", hash_alg.c_str());
return false;
}
// Reads digest.
if (digest.size() != expected_digest_size) {
ERROR("Unexpected digest size: %zu (expected %zu)\n", digest.size(),
expected_digest_size);
return false;
}
if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest),
digest)) {
ERROR("Hash digest contains non-hexidecimal character: %s\n",
digest.c_str());
return false;
}
return true;
}
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)
{
if (verify_data.num_vbmeta_images == 0) {
ERROR("No vbmeta images\n");
return false;
}
size_t total_size = 0;
bool digest_matched = false;
if (vbmeta_prop.hash_alg == kSHA256) {
std::tie(total_size, digest_matched) =
verify_vbmeta_digest<SHA256Hasher>(verify_data, vbmeta_prop);
} else if (vbmeta_prop.hash_alg == kSHA512) {
std::tie(total_size, digest_matched) =
verify_vbmeta_digest<SHA512Hasher>(verify_data, vbmeta_prop);
}
if (total_size != vbmeta_prop.vbmeta_size) {
ERROR("total vbmeta size mismatch: %zu (expected: %zu)\n", total_size,
vbmeta_prop.vbmeta_size);
return false;
}
if (!digest_matched) {
ERROR("vbmeta digest mismatch\n");
return false;
}
return true;
}
static bool hashtree_load_verity_table(
struct dm_ioctl *io,
const std::string &dm_device_name,
int fd,
const std::string &blk_device,
const AvbHashtreeDescriptor &hashtree_desc,
const std::string &salt,
const std::string &root_digest)
{
fs_mgr_verity_ioctl_init(io, dm_device_name, DM_STATUS_TABLE_FLAG);
// The buffer consists of [dm_ioctl][dm_target_spec][verity_params].
char *buffer = (char *)io;
// Builds the dm_target_spec arguments.
struct dm_target_spec *dm_target =
(struct dm_target_spec *)&buffer[sizeof(struct dm_ioctl)];
io->target_count = 1;
dm_target->status = 0;
dm_target->sector_start = 0;
dm_target->length = hashtree_desc.image_size / 512;
strcpy(dm_target->target_type, "verity");
// Builds the verity params.
char *verity_params =
buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
size_t bufsize = DM_BUF_SIZE - (verity_params - buffer);
int res = 0;
if (hashtree_desc.fec_size > 0) {
res = snprintf(
verity_params, bufsize,
VERITY_TABLE_FORMAT VERITY_TABLE_OPT_FEC_FORMAT,
VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
root_digest.c_str(), salt.c_str()),
VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device.c_str()));
} else {
res = snprintf(verity_params, bufsize,
VERITY_TABLE_FORMAT VERITY_TABLE_OPT_DEFAULT_FORMAT,
VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
root_digest.c_str(), salt.c_str()),
VERITY_TABLE_OPT_DEFAULT_PARAMS);
}
if (res < 0 || (size_t)res >= bufsize) {
ERROR("Error building verity table; insufficient buffer size?\n");
return false;
}
INFO("loading verity table: '%s'", verity_params);
// Sets ext target boundary.
verity_params += strlen(verity_params) + 1;
verity_params = (char *)(((unsigned long)verity_params + 7) & ~7);
dm_target->next = verity_params - buffer;
// Sends the ioctl to load the verity table.
if (ioctl(fd, DM_TABLE_LOAD, io)) {
ERROR("Error loading verity table (%s)\n", strerror(errno));
return false;
}
return true;
}
static bool hashtree_dm_verity_setup(struct fstab_rec *fstab_entry,
const AvbHashtreeDescriptor &hashtree_desc,
const std::string &salt,
const std::string &root_digest)
{
// Gets the device mapper fd.
android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
if (fd < 0) {
ERROR("Error opening device mapper (%s)\n", strerror(errno));
return false;
}
// Creates the device.
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
struct dm_ioctl *io = (struct dm_ioctl *)buffer;
const std::string mount_point(basename(fstab_entry->mount_point));
if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
ERROR("Couldn't create verity device!\n");
return false;
}
// Gets the name of the device file.
std::string verity_blk_name;
if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
ERROR("Couldn't get verity device number!\n");
return false;
}
// Loads the verity mapping table.
if (!hashtree_load_verity_table(io, mount_point, fd,
std::string(fstab_entry->blk_device),
hashtree_desc, salt, root_digest)) {
ERROR("Couldn't load verity table!\n");
return false;
}
// Activates the device.
if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
return false;
}
// Marks the underlying block device as read-only.
fs_mgr_set_blk_ro(fstab_entry->blk_device);
// TODO(bowgotsai): support verified all partition at boot.
// Updates fstab_rec->blk_device to verity device name.
free(fstab_entry->blk_device);
fstab_entry->blk_device = strdup(verity_blk_name.c_str());
// Makes sure we've set everything up properly.
if (fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
return false;
}
return true;
}
static bool get_hashtree_descriptor(const std::string &partition_name,
const AvbSlotVerifyData &verify_data,
AvbHashtreeDescriptor *out_hashtree_desc,
std::string *out_salt,
std::string *out_digest)
{
bool found = false;
const uint8_t *desc_partition_name;
for (size_t i = 0; i < verify_data.num_vbmeta_images && !found; i++) {
// Get descriptors from vbmeta_images[i].
size_t num_descriptors;
std::unique_ptr<const AvbDescriptor *[], decltype(&avb_free)>
descriptors(
avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
verify_data.vbmeta_images[i].vbmeta_size,
&num_descriptors),
avb_free);
if (!descriptors || num_descriptors < 1) {
continue;
}
// Ensures that hashtree descriptor is either in /vbmeta or in
// the same partition for verity setup.
std::string vbmeta_partition_name(
verify_data.vbmeta_images[i].partition_name);
if (vbmeta_partition_name != "vbmeta" &&
vbmeta_partition_name != partition_name) {
WARNING("Skip vbmeta image at %s for partition: %s\n",
verify_data.vbmeta_images[i].partition_name,
partition_name.c_str());
continue;
}
for (size_t j = 0; j < num_descriptors && !found; j++) {
AvbDescriptor desc;
if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) {
WARNING("Descriptor is invalid.\n");
continue;
}
if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
desc_partition_name = (const uint8_t *)descriptors[j] +
sizeof(AvbHashtreeDescriptor);
if (!avb_hashtree_descriptor_validate_and_byteswap(
(AvbHashtreeDescriptor *)descriptors[j],
out_hashtree_desc)) {
continue;
}
if (out_hashtree_desc->partition_name_len !=
partition_name.length()) {
continue;
}
// Notes that desc_partition_name is not NUL-terminated.
std::string hashtree_partition_name(
(const char *)desc_partition_name,
out_hashtree_desc->partition_name_len);
if (hashtree_partition_name == partition_name) {
found = true;
}
}
}
}
if (!found) {
ERROR("Partition descriptor not found: %s\n", partition_name.c_str());
return false;
}
const uint8_t *desc_salt =
desc_partition_name + out_hashtree_desc->partition_name_len;
*out_salt = bytes_to_hex(desc_salt, out_hashtree_desc->salt_len);
const uint8_t *desc_digest = desc_salt + out_hashtree_desc->salt_len;
*out_digest = bytes_to_hex(desc_digest, out_hashtree_desc->root_digest_len);
return true;
}
static inline bool polling_vbmeta_blk_device(struct fstab *fstab)
{
// It needs the block device symlink: fstab_rec->blk_device to read
// /vbmeta partition. However, the symlink created by ueventd might
// not be ready at this point. Use test_access() to poll it before
// trying to read the partition.
struct fstab_rec *fstab_entry =
fs_mgr_get_entry_for_mount_point(fstab, "/vbmeta");
// Makes sure /vbmeta block device is ready to access.
if (fs_mgr_test_access(fstab_entry->blk_device) < 0) {
return false;
}
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. They will then be imported by init
// process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
//
// 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 =
android::base::GetProperty("ro.boot.vbmeta.hash_alg", "");
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);
if (!polling_vbmeta_blk_device(fstab)) {
ERROR("Failed to find block device of /vbmeta\n");
return FS_MGR_SETUP_AVB_FAIL;
}
// 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;
}
fs_mgr_avb_ops = fs_mgr_dummy_avb_ops_new(fstab);
if (fs_mgr_avb_ops == nullptr) {
ERROR("Failed to allocate dummy avb_ops\n");
return FS_MGR_SETUP_AVB_FAIL;
}
// 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};
const char *ab_suffix =
android::base::GetProperty("ro.boot.slot_suffix", "").c_str();
AvbSlotVerifyResult verify_result = avb_slot_verify(
fs_mgr_avb_ops, requested_partitions, ab_suffix,
fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_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) {
ERROR("ERROR_VERIFICATION isn't allowed\n");
goto fail;
}
} else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
ERROR("avb_slot_verify failed, result: %d\n", verify_result);
goto fail;
}
// Verifies vbmeta images against the digest passed from bootloader.
if (!verify_vbmeta_images(*fs_mgr_avb_verify_data, fs_mgr_vbmeta_prop)) {
ERROR("verify_vbmeta_images failed\n");
goto fail;
} 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,
&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;
}
}
if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
return FS_MGR_SETUP_AVB_SUCCESS;
}
fail:
fs_mgr_unload_vbmeta_images();
return FS_MGR_SETUP_AVB_FAIL;
}
void fs_mgr_unload_vbmeta_images()
{
if (fs_mgr_avb_verify_data != nullptr) {
avb_slot_verify_data_free(fs_mgr_avb_verify_data);
}
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;
}
std::string partition_name(basename(fstab_entry->mount_point));
if (!avb_validate_utf8((const uint8_t *)partition_name.c_str(),
partition_name.length())) {
ERROR("Partition name: %s is not valid UTF-8.\n",
partition_name.c_str());
return FS_MGR_SETUP_AVB_FAIL;
}
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;
}
// 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 FS_MGR_SETUP_AVB_SUCCESS;
}

206
fs_mgr/fs_mgr_avb_ops.cpp Normal file
View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <string>
#include <android-base/macros.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <libavb/libavb.h>
#include <utils/Compat.h>
#include "fs_mgr.h"
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
static struct fstab *fs_mgr_fstab = nullptr;
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.
//
// In AVB, we can assume that there's an entry for the /misc mount
// point and use that to get the device file for the misc partition.
// From there we'll assume that a by-name scheme is used
// so we can just replace the trailing "misc" by the given
// |partition|, e.g.
//
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
struct fstab_rec *fstab_entry =
fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
if (fstab_entry == nullptr) {
ERROR("Partition (%s) not found in fstab\n", partition);
return AVB_IO_RESULT_ERROR_IO;
}
std::string partition_name(partition);
std::string path(fstab_entry->blk_device);
// Replaces the last field of device file if it's not misc.
if (!android::base::StartsWith(partition_name, "misc")) {
size_t end_slash = path.find_last_of("/");
std::string by_name_prefix(path.substr(0, end_slash + 1));
path = by_name_prefix + partition_name;
}
android::base::unique_fd fd(
TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
ERROR("Failed to open %s (%s)\n", path.c_str(), strerror(errno));
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) {
ERROR("Failed to lseek64 to end of the partition\n");
return AVB_IO_RESULT_ERROR_IO;
}
offset = total_size + offset;
// Repositions the offset to the beginning.
if (lseek64(fd, 0, SEEK_SET) == -1) {
ERROR("Failed to lseek64 to the beginning of the partition\n");
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) {
ERROR("Failed to read %zu bytes from %s offset %" PRId64 " (%s)\n",
num_bytes, path.c_str(), offset, strerror(errno));
return AVB_IO_RESULT_ERROR_IO;
}
if (out_num_read != nullptr) {
*out_num_read = num_read;
}
return AVB_IO_RESULT_OK;
}
static AvbIOResult dummy_read_rollback_index(AvbOps *ops ATTRIBUTE_UNUSED,
size_t rollback_index_location
ATTRIBUTE_UNUSED,
uint64_t *out_rollback_index)
{
// rollback_index has been checked in bootloader phase.
// In user-space, returns the smallest value 0 to pass the check.
*out_rollback_index = 0;
return AVB_IO_RESULT_OK;
}
static AvbIOResult dummy_validate_vbmeta_public_key(
AvbOps *ops ATTRIBUTE_UNUSED,
const uint8_t *public_key_data ATTRIBUTE_UNUSED,
size_t public_key_length ATTRIBUTE_UNUSED,
const uint8_t *public_key_metadata ATTRIBUTE_UNUSED,
size_t public_key_metadata_length ATTRIBUTE_UNUSED,
bool *out_is_trusted)
{
// vbmeta public key has been checked in bootloader phase.
// In user-space, returns true to pass the check.
//
// 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;
}
static AvbIOResult dummy_read_is_device_unlocked(AvbOps *ops ATTRIBUTE_UNUSED,
bool *out_is_unlocked)
{
// The function is for bootloader to update the value into
// androidboot.vbmeta.device_state in kernel cmdline.
// In user-space, returns true as we don't need to update it anymore.
*out_is_unlocked = true;
return AVB_IO_RESULT_OK;
}
static AvbIOResult dummy_get_unique_guid_for_partition(
AvbOps *ops ATTRIBUTE_UNUSED,
const char *partition ATTRIBUTE_UNUSED,
char *guid_buf,
size_t guid_buf_size)
{
// The function is for bootloader to set the correct UUID
// for a given partition in kernel cmdline.
// In user-space, returns a faking one as we don't need to update
// it anymore.
snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
return AVB_IO_RESULT_OK;
}
AvbOps *fs_mgr_dummy_avb_ops_new(struct fstab *fstab)
{
AvbOps *ops;
// Assigns the fstab to the static variable for later use.
fs_mgr_fstab = fstab;
ops = (AvbOps *)calloc(1, sizeof(AvbOps));
if (ops == nullptr) {
ERROR("Error allocating memory for AvbOps.\n");
return nullptr;
}
// 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;
}
void fs_mgr_dummy_avb_ops_free(AvbOps *ops)
{
free(ops);
}

59
fs_mgr/fs_mgr_avb_ops.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CORE_FS_MGR_AVB_OPS_H
#define __CORE_FS_MGR_AVB_OPS_H
#include <libavb/libavb.h>
#include "fs_mgr.h"
__BEGIN_DECLS
/* 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);
/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */
void fs_mgr_dummy_avb_ops_free(AvbOps *ops);
__END_DECLS
#endif /* __CORE_FS_MGR_AVB_OPS_H */

View File

@ -68,7 +68,7 @@ bool fs_mgr_get_verity_device_name(struct dm_ioctl *io,
int fd,
std::string *out_dev_name)
{
CHECK(out_dev_name != nullptr);
FS_MGR_CHECK(out_dev_name != nullptr);
fs_mgr_verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_STATUS, io)) {

View File

@ -79,6 +79,7 @@ static struct flag_list fs_mgr_flags[] = {
{ "max_comp_streams=", MF_MAX_COMP_STREAMS },
{ "verifyatboot", MF_VERIFYATBOOT },
{ "verify", MF_VERIFY },
{ "avb", MF_AVB },
{ "noemulatedsd", MF_NOEMULATEDSD },
{ "notrim", MF_NOTRIM },
{ "formattable", MF_FORMATTABLE },

View File

@ -20,6 +20,17 @@
#include <cutils/klog.h>
#include <fs_mgr.h>
#ifdef __cplusplus
#include <android-base/logging.h>
/* The CHECK() in logging.h will use program invocation name as the tag.
* Thus, the log will have prefix "init: " when libfs_mgr is statically
* linked in the init process. This might be opaque when debugging.
* Appends "in libfs_mgr" at the end of the abort message to explicitly
* indicate the check happens in fs_mgr.
*/
#define FS_MGR_CHECK(x) CHECK(x) << "in libfs_mgr "
#endif
__BEGIN_DECLS
#define INFO(x...) KLOG_INFO("fs_mgr", x)
@ -91,6 +102,7 @@ __BEGIN_DECLS
#define MF_QUOTA 0x400000
#define MF_ERASEBLKSIZE 0x800000
#define MF_LOGICALBLKSIZE 0X1000000
#define MF_AVB 0X2000000
#define DM_BUF_SIZE 4096

56
fs_mgr/fs_mgr_priv_avb.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2016 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.
*/
#ifndef __CORE_FS_MGR_PRIV_AVB_H
#define __CORE_FS_MGR_PRIV_AVB_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include "fs_mgr.h"
__BEGIN_DECLS
#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2)
#define FS_MGR_SETUP_AVB_FAIL (-1)
#define FS_MGR_SETUP_AVB_SUCCESS 0
bool fs_mgr_is_avb_used();
/* 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);
void fs_mgr_unload_vbmeta_images();
int fs_mgr_setup_avb(struct fstab_rec *fstab_entry);
__END_DECLS
#endif /* __CORE_FS_MGR_PRIV_AVB_H */

74
fs_mgr/fs_mgr_priv_sha.h Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2016 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.
*/
#ifndef __CORE_FS_MGR_PRIV_SHA_H
#define __CORE_FS_MGR_PRIV_SHA_H
#include <openssl/sha.h>
class SHA256Hasher
{
private:
SHA256_CTX sha256_ctx;
uint8_t hash[SHA256_DIGEST_LENGTH];
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);
}
const uint8_t *finalize()
{
SHA256_Final(hash, &sha256_ctx);
return hash;
}
};
class SHA512Hasher
{
private:
SHA512_CTX sha512_ctx;
uint8_t hash[SHA512_DIGEST_LENGTH];
public:
enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH };
SHA512Hasher()
{
SHA512_Init(&sha512_ctx);
}
void update(const uint8_t *data, size_t data_size)
{
SHA512_Update(&sha512_ctx, data, data_size);
}
const uint8_t *finalize()
{
SHA512_Final(hash, &sha512_ctx);
return hash;
}
};
#endif /* __CORE_FS_MGR_PRIV_SHA_H */

View File

@ -107,6 +107,7 @@ LOCAL_STATIC_LIBRARIES := \
libz \
libprocessgroup \
libnl \
libavb
# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \