Merge "fs_mgr: support using libavb to enable dm-verity"
This commit is contained in:
commit
0a3c2392c7
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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)) {
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -107,6 +107,7 @@ LOCAL_STATIC_LIBRARIES := \
|
|||
libz \
|
||||
libprocessgroup \
|
||||
libnl \
|
||||
libavb
|
||||
|
||||
# Create symlinks.
|
||||
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
|
||||
|
|
Loading…
Reference in New Issue