upload android base code part6

This commit is contained in:
August 2018-08-08 17:48:24 +08:00
parent 421e214c7d
commit 4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions

View file

@ -0,0 +1 @@
../init/.clang-format

View file

@ -0,0 +1,79 @@
//
// Copyright (C) 2017 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.
//
cc_defaults {
name: "fs_mgr_defaults",
sanitize: {
misc_undefined: ["integer"],
},
local_include_dirs: ["include/"],
cppflags: ["-Werror"],
}
cc_library_static {
name: "libfs_mgr",
defaults: ["fs_mgr_defaults"],
export_include_dirs: ["include"],
include_dirs: ["system/vold"],
srcs: [
"fs_mgr.cpp",
"fs_mgr_dm_ioctl.cpp",
"fs_mgr_format.cpp",
"fs_mgr_verity.cpp",
"fs_mgr_avb.cpp",
"fs_mgr_avb_ops.cpp",
],
static_libs: [
"libfec",
"libfec_rs",
"libbase",
"libcrypto_utils",
"libcrypto",
"libext4_utils",
"libsquashfs_utils",
"libselinux",
"libavb",
"libfstab",
],
export_static_lib_headers: [
"libfstab",
],
whole_static_libs: [
"liblogwrap",
"libfstab",
],
product_variables: {
debuggable: {
cppflags: ["-DALLOW_ADBD_DISABLE_VERITY=1"],
},
eng: {
cppflags: ["-DALLOW_SKIP_SECURE_CHECK=1"],
},
},
}
cc_library_static {
name: "libfstab",
vendor_available: true,
defaults: ["fs_mgr_defaults"],
srcs: [
"fs_mgr_fstab.cpp",
"fs_mgr_boot_config.cpp",
"fs_mgr_slotselect.cpp",
],
export_include_dirs: ["include_fstab"],
header_libs: ["libbase_headers"],
}

View file

@ -0,0 +1,38 @@
# Copyright 2011 The Android Open Source Project
LOCAL_PATH:= $(call my-dir)
common_static_libraries := \
liblogwrap \
libfec \
libfec_rs \
libbase \
libcrypto_utils \
libcrypto \
libext4_utils \
libsquashfs_utils \
libselinux \
libavb
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SANITIZE := integer
LOCAL_SRC_FILES:= fs_mgr_main.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_MODULE:= fs_mgr
LOCAL_MODULE_TAGS := optional
LOCAL_REQUIRED_MODULES := mke2fs mke2fs.conf e2fsdroid
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := libfs_mgr \
$(common_static_libraries) \
libcutils \
liblog \
libc \
libsparse \
libz \
libselinux
LOCAL_CXX_STL := libc++_static
LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,610 @@
/*
* 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 "fs_mgr_avb.h"
#include <fcntl.h>
#include <libgen.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sstream>
#include <string>
#include <vector>
#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 <libavb/libavb.h>
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_avb_ops.h"
#include "fs_mgr_priv_dm_ioctl.h"
#include "fs_mgr_priv_sha.h"
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;
}
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.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);
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_;
};
std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() {
std::string cmdline;
if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
PERROR << "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 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.hash_alg") {
hash_alg = value;
} else if (key == "androidboot.vbmeta.size") {
if (!android::base::ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) {
return nullptr;
}
} 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;
avb_verifier->hash_alg_ = kSHA256;
} else if (hash_alg == "sha512") {
expected_digest_size = SHA512_DIGEST_LENGTH * 2;
avb_verifier->hash_alg_ = kSHA512;
} else {
LERROR << "Unknown hash algorithm: " << hash_alg.c_str();
return nullptr;
}
// Reads digest.
if (digest.size() != expected_digest_size) {
LERROR << "Unexpected digest size: " << digest.size()
<< " (expected: " << expected_digest_size << ")";
return nullptr;
}
if (!hex_to_bytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) {
LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str();
return nullptr;
}
return avb_verifier;
}
bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
if (verify_data.num_vbmeta_images == 0) {
LERROR << "No vbmeta images";
return false;
}
size_t total_size = 0;
bool digest_matched = false;
if (hash_alg_ == kSHA256) {
std::tie(total_size, digest_matched) =
verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
} else if (hash_alg_ == kSHA512) {
std::tie(total_size, digest_matched) =
verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
}
if (total_size != vbmeta_size_) {
LERROR << "total vbmeta size mismatch: " << total_size << " (expected: " << vbmeta_size_
<< ")";
return false;
}
if (!digest_matched) {
LERROR << "vbmeta digest mismatch";
return false;
}
return true;
}
// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
// See the following link for more details:
// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
static std::string construct_verity_table(const AvbHashtreeDescriptor& hashtree_desc,
const std::string& salt, const std::string& root_digest,
const std::string& blk_device) {
// Loads androidboot.veritymode from kernel cmdline.
std::string verity_mode;
if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
verity_mode = "enforcing"; // Defaults to enforcing when it's absent.
}
// Converts veritymode to the format used in kernel.
std::string dm_verity_mode;
if (verity_mode == "enforcing") {
dm_verity_mode = "restart_on_corruption";
} else if (verity_mode == "logging") {
dm_verity_mode = "ignore_corruption";
} else if (verity_mode != "eio") { // Default dm_verity_mode is eio.
LERROR << "Unknown androidboot.veritymode: " << verity_mode;
return "";
}
// dm-verity construction parameters:
// <version> <dev> <hash_dev>
// <data_block_size> <hash_block_size>
// <num_data_blocks> <hash_start_block>
// <algorithm> <digest> <salt>
// [<#opt_params> <opt_params>]
std::ostringstream verity_table;
verity_table << hashtree_desc.dm_verity_version << " " << blk_device << " " << blk_device << " "
<< hashtree_desc.data_block_size << " " << hashtree_desc.hash_block_size << " "
<< hashtree_desc.image_size / hashtree_desc.data_block_size << " "
<< hashtree_desc.tree_offset / hashtree_desc.hash_block_size << " "
<< hashtree_desc.hash_algorithm << " " << root_digest << " " << salt;
// Continued from the above optional parameters:
// [<#opt_params> <opt_params>]
int optional_argc = 0;
std::ostringstream optional_args;
// dm-verity optional parameters for FEC (forward error correction):
// use_fec_from_device <fec_dev>
// fec_roots <num>
// fec_blocks <num>
// fec_start <offset>
if (hashtree_desc.fec_size > 0) {
// 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).
optional_argc += 8;
// clang-format off
optional_args << "use_fec_from_device " << blk_device
<< " fec_roots " << hashtree_desc.fec_num_roots
<< " fec_blocks " << hashtree_desc.fec_offset / hashtree_desc.data_block_size
<< " fec_start " << hashtree_desc.fec_offset / hashtree_desc.data_block_size
<< " ";
// clang-format on
}
if (!dm_verity_mode.empty()) {
optional_argc += 1;
optional_args << dm_verity_mode << " ";
}
// Always use ignore_zero_blocks.
optional_argc += 1;
optional_args << "ignore_zero_blocks";
verity_table << " " << optional_argc << " " << optional_args.str();
return verity_table.str();
}
static bool load_verity_table(struct dm_ioctl* io, const std::string& dm_device_name, int fd,
uint64_t image_size, const std::string& verity_table) {
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 = 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);
LINFO << "Loading verity table: '" << verity_table << "'";
// Copies verity_table to verity_params (including the terminating null byte).
if (verity_table.size() > bufsize - 1) {
LERROR << "Verity table size too large: " << verity_table.size()
<< " (max allowable size: " << bufsize - 1 << ")";
return false;
}
memcpy(verity_params, verity_table.c_str(), verity_table.size() + 1);
// Sets ext target boundary.
verity_params += verity_table.size() + 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)) {
PERROR << "Error loading verity table";
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,
bool wait_for_verity_dev) {
// Gets the device mapper fd.
android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
if (fd < 0) {
PERROR << "Error opening device mapper";
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)) {
LERROR << "Couldn't create verity device!";
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)) {
LERROR << "Couldn't get verity device number!";
return false;
}
std::string verity_table =
construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device);
if (verity_table.empty()) {
LERROR << "Failed to construct verity table.";
return false;
}
// Loads the verity mapping table.
if (!load_verity_table(io, mount_point, fd, hashtree_desc.image_size, verity_table)) {
LERROR << "Couldn't load verity table!";
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);
// 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 (wait_for_verity_dev && !fs_mgr_wait_for_file(verity_blk_name, 1s)) {
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 in /vbmeta or /boot 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 != "boot" && // for legacy device to append top-level vbmeta
vbmeta_partition_name != partition_name) {
LWARNING << "Skip vbmeta image at " << verify_data.vbmeta_images[i].partition_name
<< " for partition: " << 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)) {
LWARNING << "Descriptor[" << j << "] is invalid";
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) {
LERROR << "Partition descriptor not found: " << 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;
}
FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const fstab& fstab) {
FsManagerAvbOps avb_ops(fstab);
return DoOpen(&avb_ops);
}
FsManagerAvbUniquePtr FsManagerAvbHandle::Open(ByNameSymlinkMap&& by_name_symlink_map) {
if (by_name_symlink_map.empty()) {
LERROR << "Empty by_name_symlink_map when opening FsManagerAvbHandle";
return nullptr;
}
FsManagerAvbOps avb_ops(std::move(by_name_symlink_map));
return DoOpen(&avb_ops);
}
FsManagerAvbUniquePtr FsManagerAvbHandle::DoOpen(FsManagerAvbOps* avb_ops) {
bool is_device_unlocked = fs_mgr_is_device_unlocked();
FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
if (!avb_handle) {
LERROR << "Failed to allocate FsManagerAvbHandle";
return nullptr;
}
AvbSlotVerifyFlags flags = is_device_unlocked ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
: AVB_SLOT_VERIFY_FLAGS_NONE;
AvbSlotVerifyResult verify_result =
avb_ops->AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &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 the device is UNLOCKED, i.e., |allow_verification_error| is true for
// AvbSlotVerify(), then the following return values are all non-fatal:
// * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION
// * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED
// * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX
// The latter two results were checked by bootloader prior to start fs_mgr so
// we just need to handle the first result here. See *dummy* operations in
// FsManagerAvbOps and the comments in external/avb/libavb/avb_slot_verify.h
// for more details.
switch (verify_result) {
case AVB_SLOT_VERIFY_RESULT_OK:
avb_handle->status_ = kAvbHandleSuccess;
break;
case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
if (!is_device_unlocked) {
LERROR << "ERROR_VERIFICATION isn't allowed when the device is LOCKED";
return nullptr;
}
avb_handle->status_ = kAvbHandleVerificationError;
break;
default:
LERROR << "avb_slot_verify failed, result: " << verify_result;
return nullptr;
}
// Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
avb_handle->avb_version_ =
android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
// Checks whether FLAGS_VERIFICATION_DISABLED is set:
// - Only the top-level vbmeta struct is read.
// - vbmeta struct in other partitions are NOT processed, including AVB HASH descriptor(s)
// and AVB HASHTREE descriptor(s).
AvbVBMetaImageHeader vbmeta_header;
avb_vbmeta_image_header_to_host_byte_order(
(AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
&vbmeta_header);
bool verification_disabled =
((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
if (verification_disabled) {
avb_handle->status_ = kAvbHandleVerificationDisabled;
} else {
// Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline.
std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
if (!avb_verifier) {
LERROR << "Failed to create FsManagerAvbVerifier";
return nullptr;
}
if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
LERROR << "VerifyVbmetaImages failed";
return nullptr;
}
// Checks whether FLAGS_HASHTREE_DISABLED is set.
bool hashtree_disabled =
((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
if (hashtree_disabled) {
avb_handle->status_ = kAvbHandleHashtreeDisabled;
}
}
LINFO << "Returning avb_handle with status: " << avb_handle->status_;
return avb_handle;
}
SetUpAvbHashtreeResult FsManagerAvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
bool wait_for_verity_dev) {
if (!fstab_entry || status_ == kAvbHandleUninitialized || !avb_slot_data_ ||
avb_slot_data_->num_vbmeta_images < 1) {
return SetUpAvbHashtreeResult::kFail;
}
if (status_ == kAvbHandleHashtreeDisabled || status_ == kAvbHandleVerificationDisabled) {
LINFO << "AVB HASHTREE disabled on: " << fstab_entry->mount_point;
return SetUpAvbHashtreeResult::kDisabled;
}
// Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
// to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
std::string partition_name(basename(fstab_entry->blk_device));
if (fstab_entry->fs_mgr_flags & MF_SLOTSELECT) {
auto ab_suffix = partition_name.rfind(fs_mgr_get_slot_suffix());
if (ab_suffix != std::string::npos) {
partition_name.erase(ab_suffix);
}
}
AvbHashtreeDescriptor hashtree_descriptor;
std::string salt;
std::string root_digest;
if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt,
&root_digest)) {
return SetUpAvbHashtreeResult::kFail;
}
// Converts HASHTREE descriptor to verity_table_params.
if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest,
wait_for_verity_dev)) {
return SetUpAvbHashtreeResult::kFail;
}
return SetUpAvbHashtreeResult::kSuccess;
}

View file

@ -0,0 +1,199 @@
/*
* 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 "fs_mgr_priv_avb_ops.h"
#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_priv.h"
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,
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;
}
static AvbIOResult dummy_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED,
const char* partition ATTRIBUTE_UNUSED,
uint64_t* out_size_num_byte) {
// The function is for bootloader to load entire content of AVB HASH partitions.
// In user-space, returns 0 as we only need to set up AVB HASHTHREE partitions.
*out_size_num_byte = 0;
return AVB_IO_RESULT_OK;
}
void FsManagerAvbOps::InitializeAvbOps() {
// 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. Also zero the entire
// struct so operations added in the future will be set to NULL.
memset(&avb_ops_, 0, sizeof(AvbOps));
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;
avb_ops_.get_size_of_partition = dummy_get_size_of_partition;
// Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
avb_ops_.user_data = this;
}
FsManagerAvbOps::FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map)
: by_name_symlink_map_(std::move(by_name_symlink_map)) {
InitializeAvbOps();
}
FsManagerAvbOps::FsManagerAvbOps(const fstab& fstab) {
// Constructs the by-name symlink map for each fstab record.
// /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a =>
// by_name_symlink_map_["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
for (int i = 0; i < fstab.num_entries; i++) {
std::string partition_name = basename(fstab.recs[i].blk_device);
by_name_symlink_map_[partition_name] = fstab.recs[i].blk_device;
}
InitializeAvbOps();
}
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
size_t num_bytes, void* buffer,
size_t* out_num_read) {
const auto iter = by_name_symlink_map_.find(partition);
if (iter == by_name_symlink_map_.end()) {
LERROR << "by-name symlink not found for partition: '" << partition << "'";
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
}
std::string path = iter->second;
// Ensures the device path (a symlink created by init) is ready to access.
if (!fs_mgr_wait_for_file(path, 1s)) {
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;
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) {
PERROR << "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) {
PERROR << "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 << " 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,
AvbSlotVerifyFlags flags,
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};
// The |hashtree_error_mode| field doesn't matter as it only
// influences the generated kernel cmdline parameters.
return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, out_data);
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (C) 2017 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 <string>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/properties.h>
#include "fs_mgr_priv.h"
// Tries to get the given boot config value from kernel cmdline.
// Returns true if successfully found, false otherwise.
bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) {
FS_MGR_CHECK(out_val != nullptr);
std::string cmdline;
std::string cmdline_key("androidboot." + key);
if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
std::vector<std::string> pieces = android::base::Split(entry, "=");
if (pieces.size() == 2) {
if (pieces[0] == cmdline_key) {
*out_val = pieces[1];
return true;
}
}
}
}
return false;
}
// Tries to get the boot config value in properties, kernel cmdline and
// device tree (in that order). returns 'true' if successfully found, 'false'
// otherwise
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
FS_MGR_CHECK(out_val != nullptr);
// first check if we have "ro.boot" property already
*out_val = android::base::GetProperty("ro.boot." + key, "");
if (!out_val->empty()) {
return true;
}
// fallback to kernel cmdline, properties may not be ready yet
if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) {
return true;
}
// lastly, check the device tree
if (is_dt_compatible()) {
std::string file_name = get_android_dt_dir() + "/" + key;
if (android::base::ReadFileToString(file_name, out_val)) {
if (!out_val->empty()) {
out_val->pop_back(); // Trims the trailing '\0' out.
return true;
}
}
}
return false;
}

View file

@ -0,0 +1,80 @@
/*
* 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 <string.h>
#include <android-base/logging.h>
#include <sys/ioctl.h>
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags) {
memset(io, 0, DM_BUF_SIZE);
io->data_size = DM_BUF_SIZE;
io->data_start = sizeof(struct dm_ioctl);
io->version[0] = 4;
io->version[1] = 0;
io->version[2] = 0;
io->flags = flags | DM_READONLY_FLAG;
if (!name.empty()) {
strlcpy(io->name, name.c_str(), sizeof(io->name));
}
}
bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
fs_mgr_verity_ioctl_init(io, name, 1);
if (ioctl(fd, DM_DEV_CREATE, io)) {
PERROR << "Error creating device mapping";
return false;
}
return true;
}
bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
fs_mgr_verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_REMOVE, io)) {
PERROR << "Error removing device mapping";
return false;
}
return true;
}
bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
std::string* out_dev_name) {
FS_MGR_CHECK(out_dev_name != nullptr);
fs_mgr_verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_STATUS, io)) {
PERROR << "Error fetching verity device number";
return false;
}
int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
*out_dev_name = "/dev/block/dm-" + std::to_string(dev_num);
return true;
}
bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd) {
fs_mgr_verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
PERROR << "Error activating verity device";
return false;
}
return true;
}

View file

@ -0,0 +1,124 @@
/*
* Copyright (C) 2015 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 <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>
#include <cutils/partition_utils.h>
#include <sys/mount.h>
#include <ext4_utils/ext4.h>
#include <ext4_utils/ext4_utils.h>
#include <logwrap/logwrap.h>
#include <selinux/android.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
#include "fs_mgr_priv.h"
#include "cryptfs.h"
static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
{
uint64_t dev_sz;
int fd, rc = 0;
if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
PERROR << "Cannot open block device";
return -1;
}
if ((ioctl(fd, BLKGETSIZE64, &dev_sz)) == -1) {
PERROR << "Cannot get block device size";
close(fd);
return -1;
}
close(fd);
/* Format the partition using the calculated length */
if (crypt_footer) {
dev_sz -= CRYPT_FOOTER_OFFSET;
}
std::string size_str = std::to_string(dev_sz / 4096);
const char* const mke2fs_args[] = {
"/system/bin/mke2fs", "-t", "ext4", "-b", "4096", fs_blkdev, size_str.c_str(), nullptr};
rc = android_fork_execvp_ext(arraysize(mke2fs_args), const_cast<char**>(mke2fs_args), NULL,
true, LOG_KLOG, true, nullptr, nullptr, 0);
if (rc) {
LERROR << "mke2fs returned " << rc;
return rc;
}
const char* const e2fsdroid_args[] = {
"/system/bin/e2fsdroid",
"-e",
"-a",
fs_mnt_point,
fs_blkdev,
nullptr};
rc = android_fork_execvp_ext(arraysize(e2fsdroid_args), const_cast<char**>(e2fsdroid_args),
NULL, true, LOG_KLOG, true, nullptr, nullptr, 0);
if (rc) {
LERROR << "e2fsdroid returned " << rc;
}
return rc;
}
static int format_legacy_ext4(char *fs_blkdev)
{
const char* const args[] = {"/system/bin/make_ext4fs", fs_blkdev, nullptr};
return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), NULL, true,
LOG_KLOG, true, nullptr, nullptr, 0);
}
static int format_f2fs(char *fs_blkdev)
{
const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), NULL, true,
LOG_KLOG, true, nullptr, nullptr, 0);
}
int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
{
int rc = -EINVAL;
LERROR << __FUNCTION__ << ": Format " << fstab->blk_device
<< " as '" << fstab->fs_type << "'";
if (!strncmp(fstab->fs_type, "f2fs", 4)) {
rc = format_f2fs(fstab->blk_device);
} else if (!strncmp(fstab->fs_type, "ext4", 4)) {
if(crypt_footer)
rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
else
rc = format_legacy_ext4(fstab->blk_device);
} else {
LERROR << "File system type '" << fstab->fs_type << "' is not supported";
}
return rc;
}

View file

@ -0,0 +1,908 @@
/*
* Copyright (C) 2014 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 <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <unistd.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "fs_mgr_priv.h"
const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
struct fs_mgr_flag_values {
char *key_loc;
char* key_dir;
char *verity_loc;
long long part_length;
char *label;
int partnum;
int swap_prio;
int max_comp_streams;
unsigned int zram_size;
uint64_t reserved_size;
unsigned int file_contents_mode;
unsigned int file_names_mode;
unsigned int erase_blk_size;
unsigned int logical_blk_size;
};
struct flag_list {
const char *name;
unsigned int flag;
};
static struct flag_list mount_flags[] = {
{ "noatime", MS_NOATIME },
{ "noexec", MS_NOEXEC },
{ "nosuid", MS_NOSUID },
{ "nodev", MS_NODEV },
{ "nodiratime", MS_NODIRATIME },
{ "ro", MS_RDONLY },
{ "rw", 0 },
{ "remount", MS_REMOUNT },
{ "bind", MS_BIND },
{ "rec", MS_REC },
{ "unbindable", MS_UNBINDABLE },
{ "private", MS_PRIVATE },
{ "slave", MS_SLAVE },
{ "shared", MS_SHARED },
{ "defaults", 0 },
{ 0, 0 },
};
static struct flag_list fs_mgr_flags[] = {
{"wait", MF_WAIT},
{"check", MF_CHECK},
{"encryptable=", MF_CRYPT},
{"forceencrypt=", MF_FORCECRYPT},
{"fileencryption=", MF_FILEENCRYPTION},
{"forcefdeorfbe=", MF_FORCEFDEORFBE},
{"keydirectory=", MF_KEYDIRECTORY},
{"nonremovable", MF_NONREMOVABLE},
{"voldmanaged=", MF_VOLDMANAGED},
{"length=", MF_LENGTH},
{"recoveryonly", MF_RECOVERYONLY},
{"swapprio=", MF_SWAPPRIO},
{"zramsize=", MF_ZRAMSIZE},
{"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},
{"slotselect", MF_SLOTSELECT},
{"nofail", MF_NOFAIL},
{"latemount", MF_LATEMOUNT},
{"reservedsize=", MF_RESERVEDSIZE},
{"quota", MF_QUOTA},
{"eraseblk=", MF_ERASEBLKSIZE},
{"logicalblk=", MF_LOGICALBLKSIZE},
{"defaults", 0},
{0, 0},
};
#define EM_AES_256_XTS 1
#define EM_ICE 2
#define EM_AES_256_CTS 3
#define EM_AES_256_HEH 4
static const struct flag_list file_contents_encryption_modes[] = {
{"aes-256-xts", EM_AES_256_XTS},
{"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
{"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
{0, 0},
};
static const struct flag_list file_names_encryption_modes[] = {
{"aes-256-cts", EM_AES_256_CTS},
{"aes-256-heh", EM_AES_256_HEH},
{0, 0},
};
static unsigned int encryption_mode_to_flag(const struct flag_list *list,
const char *mode, const char *type)
{
const struct flag_list *j;
for (j = list; j->name; ++j) {
if (!strcmp(mode, j->name)) {
return j->flag;
}
}
LERROR << "Unknown " << type << " encryption mode: " << mode;
return 0;
}
static const char *flag_to_encryption_mode(const struct flag_list *list,
unsigned int flag)
{
const struct flag_list *j;
for (j = list; j->name; ++j) {
if (flag == j->flag) {
return j->name;
}
}
return nullptr;
}
static uint64_t calculate_zram_size(unsigned int percentage)
{
uint64_t total;
total = sysconf(_SC_PHYS_PAGES);
total *= percentage;
total /= 100;
total *= sysconf(_SC_PAGESIZE);
return total;
}
static uint64_t parse_size(const char *arg)
{
char *endptr;
uint64_t size = strtoull(arg, &endptr, 10);
if (*endptr == 'k' || *endptr == 'K')
size *= 1024LL;
else if (*endptr == 'm' || *endptr == 'M')
size *= 1024LL * 1024LL;
else if (*endptr == 'g' || *endptr == 'G')
size *= 1024LL * 1024LL * 1024LL;
return size;
}
/* fills 'dt_value' with the underlying device tree value string without
* the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
* otherwise.
*/
static bool read_dt_file(const std::string& file_name, std::string* dt_value)
{
if (android::base::ReadFileToString(file_name, dt_value)) {
if (!dt_value->empty()) {
// trim the trailing '\0' out, otherwise the comparison
// will produce false-negatives.
dt_value->resize(dt_value->size() - 1);
return true;
}
}
return false;
}
static int parse_flags(char *flags, struct flag_list *fl,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
{
int f = 0;
int i;
char *p;
char *savep;
/* initialize flag values. If we find a relevant flag, we'll
* update the value */
if (flag_vals) {
memset(flag_vals, 0, sizeof(*flag_vals));
flag_vals->partnum = -1;
flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
}
/* initialize fs_options to the null string */
if (fs_options && (fs_options_len > 0)) {
fs_options[0] = '\0';
}
p = strtok_r(flags, ",", &savep);
while (p) {
/* Look for the flag "p" in the flag list "fl"
* If not found, the loop exits with fl[i].name being null.
*/
for (i = 0; fl[i].name; i++) {
if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
f |= fl[i].flag;
if ((fl[i].flag == MF_CRYPT) && flag_vals) {
/* The encryptable flag is followed by an = and the
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
/* If the verify flag is followed by an = and the
* location for the verity state, get it and return it.
*/
char *start = strchr(p, '=');
if (start) {
flag_vals->verity_loc = strdup(start + 1);
}
} else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
/* The forceencrypt flag is followed by an = and the
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
/* The forcefdeorfbe flag is followed by an = and the
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
flag_vals->file_contents_mode = EM_AES_256_XTS;
flag_vals->file_names_mode = EM_AES_256_CTS;
} else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
/* The fileencryption flag is followed by an = and
* the mode of contents encryption, then optionally a
* : and the mode of filenames encryption (defaults
* to aes-256-cts). Get it and return it.
*/
char *mode = strchr(p, '=') + 1;
char *colon = strchr(mode, ':');
if (colon) {
*colon = '\0';
}
flag_vals->file_contents_mode =
encryption_mode_to_flag(file_contents_encryption_modes,
mode, "file contents");
if (colon) {
flag_vals->file_names_mode =
encryption_mode_to_flag(file_names_encryption_modes,
colon + 1, "file names");
} else {
flag_vals->file_names_mode = EM_AES_256_CTS;
}
} else if ((fl[i].flag == MF_KEYDIRECTORY) && flag_vals) {
/* The metadata flag is followed by an = and the
* directory for the keys. Get it and return it.
*/
flag_vals->key_dir = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
*/
flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
/* The voldmanaged flag is followed by an = and the
* label, a colon and the partition number or the
* word "auto", e.g.
* voldmanaged=sdcard:3
* Get and return them.
*/
char *label_start;
char *label_end;
char *part_start;
label_start = strchr(p, '=') + 1;
label_end = strchr(p, ':');
if (label_end) {
flag_vals->label = strndup(label_start,
(int) (label_end - label_start));
part_start = strchr(p, ':') + 1;
if (!strcmp(part_start, "auto")) {
flag_vals->partnum = -1;
} else {
flag_vals->partnum = strtol(part_start, NULL, 0);
}
} else {
LERROR << "Warning: voldmanaged= flag malformed";
}
} else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
int is_percent = !!strrchr(p, '%');
unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
if (is_percent)
flag_vals->zram_size = calculate_zram_size(val);
else
flag_vals->zram_size = val;
} else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
/* The reserved flag is followed by an = and the
* reserved size of the partition. Get it and return it.
*/
flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_ERASEBLKSIZE) && flag_vals) {
/* The erase block size flag is followed by an = and the flash
* erase block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->erase_blk_size = val;
} else if ((fl[i].flag == MF_LOGICALBLKSIZE) && flag_vals) {
/* The logical block size flag is followed by an = and the flash
* logical block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->logical_blk_size = val;
}
break;
}
}
if (!fl[i].name) {
if (fs_options) {
/* It's not a known flag, so it must be a filesystem specific
* option. Add it to fs_options if it was passed in.
*/
strlcat(fs_options, p, fs_options_len);
strlcat(fs_options, ",", fs_options_len);
} else {
/* fs_options was not passed in, so if the flag is unknown
* it's an error.
*/
LERROR << "Warning: unknown flag " << p;
}
}
p = strtok_r(NULL, ",", &savep);
}
if (fs_options && fs_options[0]) {
/* remove the last trailing comma from the list of options */
fs_options[strlen(fs_options) - 1] = '\0';
}
return f;
}
static std::string init_android_dt_dir() {
std::string android_dt_dir;
// The platform may specify a custom Android DT path in kernel cmdline
if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
// Fall back to the standard procfs-based path
android_dt_dir = kDefaultAndroidDtDir;
}
return android_dt_dir;
}
// FIXME: The same logic is duplicated in system/core/init/
const std::string& get_android_dt_dir() {
// Set once and saves time for subsequent calls to this function
static const std::string kAndroidDtDir = init_android_dt_dir();
return kAndroidDtDir;
}
static bool is_dt_fstab_compatible() {
std::string dt_value;
std::string file_name = get_android_dt_dir() + "/fstab/compatible";
if (read_dt_file(file_name, &dt_value)) {
if (dt_value == "android,fstab") {
return true;
}
}
return false;
}
static std::string read_fstab_from_dt() {
std::string fstab;
if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
return fstab;
}
std::string fstabdir_name = get_android_dt_dir() + "/fstab";
std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
if (!fstabdir) return fstab;
dirent* dp;
while ((dp = readdir(fstabdir.get())) != NULL) {
// skip over name, compatible and .
if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
// create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
std::vector<std::string> fstab_entry;
std::string file_name;
std::string value;
// skip a partition entry if the status property is present and not set to ok
file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
if (read_dt_file(file_name, &value)) {
if (value != "okay" && value != "ok") {
LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
continue;
}
}
file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
fstab.clear();
break;
}
fstab_entry.push_back(value);
fstab_entry.push_back(android::base::StringPrintf("/%s", dp->d_name));
file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
fstab.clear();
break;
}
fstab_entry.push_back(value);
file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
fstab.clear();
break;
}
fstab_entry.push_back(value);
file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
fstab.clear();
break;
}
fstab_entry.push_back(value);
fstab += android::base::Join(fstab_entry, " ");
fstab += '\n';
}
return fstab;
}
bool is_dt_compatible() {
std::string file_name = get_android_dt_dir() + "/compatible";
std::string dt_value;
if (read_dt_file(file_name, &dt_value)) {
if (dt_value == "android,firmware") {
return true;
}
}
return false;
}
static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
{
int cnt, entries;
ssize_t len;
size_t alloc_len = 0;
char *line = NULL;
const char *delim = " \t";
char *save_ptr, *p;
struct fstab *fstab = NULL;
struct fs_mgr_flag_values flag_vals;
#define FS_OPTIONS_LEN 1024
char tmp_fs_options[FS_OPTIONS_LEN];
entries = 0;
while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
/* if the last character is a newline, shorten the string by 1 byte */
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
/* Skip any leading whitespace */
p = line;
while (isspace(*p)) {
p++;
}
/* ignore comments or empty lines */
if (*p == '#' || *p == '\0')
continue;
entries++;
}
if (!entries) {
LERROR << "No entries found in fstab";
goto err;
}
/* Allocate and init the fstab structure */
fstab = static_cast<struct fstab *>(calloc(1, sizeof(struct fstab)));
fstab->num_entries = entries;
fstab->recs = static_cast<struct fstab_rec *>(
calloc(fstab->num_entries, sizeof(struct fstab_rec)));
fseek(fstab_file, 0, SEEK_SET);
cnt = 0;
while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
/* if the last character is a newline, shorten the string by 1 byte */
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
/* Skip any leading whitespace */
p = line;
while (isspace(*p)) {
p++;
}
/* ignore comments or empty lines */
if (*p == '#' || *p == '\0')
continue;
/* If a non-comment entry is greater than the size we allocated, give an
* error and quit. This can happen in the unlikely case the file changes
* between the two reads.
*/
if (cnt >= entries) {
LERROR << "Tried to process more entries than counted";
break;
}
if (!(p = strtok_r(line, delim, &save_ptr))) {
LERROR << "Error parsing mount source";
goto err;
}
fstab->recs[cnt].blk_device = strdup(p);
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_point";
goto err;
}
fstab->recs[cnt].mount_point = strdup(p);
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_type";
goto err;
}
fstab->recs[cnt].fs_type = strdup(p);
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_flags";
goto err;
}
tmp_fs_options[0] = '\0';
fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
tmp_fs_options, FS_OPTIONS_LEN);
/* fs_options are optional */
if (tmp_fs_options[0]) {
fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
} else {
fstab->recs[cnt].fs_options = NULL;
}
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_mgr_options";
goto err;
}
fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
&flag_vals, NULL, 0);
fstab->recs[cnt].key_loc = flag_vals.key_loc;
fstab->recs[cnt].key_dir = flag_vals.key_dir;
fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
fstab->recs[cnt].length = flag_vals.part_length;
fstab->recs[cnt].label = flag_vals.label;
fstab->recs[cnt].partnum = flag_vals.partnum;
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
fstab->recs[cnt].zram_size = flag_vals.zram_size;
fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
fstab->recs[cnt].file_contents_mode = flag_vals.file_contents_mode;
fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode;
fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
cnt++;
}
/* If an A/B partition, modify block device to be the real block device */
if (!fs_mgr_update_for_slotselect(fstab)) {
LERROR << "Error updating for slotselect";
goto err;
}
free(line);
return fstab;
err:
free(line);
if (fstab)
fs_mgr_free_fstab(fstab);
return NULL;
}
/* merges fstab entries from both a and b, then returns the merged result.
* note that the caller should only manage the return pointer without
* doing further memory management for the two inputs, i.e. only need to
* frees up memory of the return value without touching a and b. */
static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
{
if (!a) return b;
if (!b) return a;
int total_entries = a->num_entries + b->num_entries;
a->recs = static_cast<struct fstab_rec *>(realloc(
a->recs, total_entries * (sizeof(struct fstab_rec))));
if (!a->recs) {
LERROR << __FUNCTION__ << "(): failed to allocate fstab recs";
// If realloc() fails the original block is left untouched;
// it is not freed or moved. So we have to free both a and b here.
fs_mgr_free_fstab(a);
fs_mgr_free_fstab(b);
return nullptr;
}
for (int i = a->num_entries, j = 0; i < total_entries; i++, j++) {
// copy the pointer directly *without* malloc and memcpy
a->recs[i] = b->recs[j];
}
// Frees up b, but don't free b->recs[X] to make sure they are
// accessible through a->recs[X].
free(b->fstab_filename);
free(b);
a->num_entries = total_entries;
return a;
}
struct fstab *fs_mgr_read_fstab(const char *fstab_path)
{
FILE *fstab_file;
struct fstab *fstab;
fstab_file = fopen(fstab_path, "r");
if (!fstab_file) {
PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
return nullptr;
}
fstab = fs_mgr_read_fstab_file(fstab_file);
if (fstab) {
fstab->fstab_filename = strdup(fstab_path);
} else {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
}
fclose(fstab_file);
return fstab;
}
/* Returns fstab entries parsed from the device tree if they
* exist
*/
struct fstab *fs_mgr_read_fstab_dt()
{
std::string fstab_buf = read_fstab_from_dt();
if (fstab_buf.empty()) {
LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
return nullptr;
}
std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
fstab_buf.length(), "r"), fclose);
if (!fstab_file) {
PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
return nullptr;
}
struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
if (!fstab) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
<< std::endl << fstab_buf;
}
return fstab;
}
/*
* tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
* or /. loads the first one found and also combines fstab entries passed
* in from device tree.
*/
struct fstab *fs_mgr_read_fstab_default()
{
std::string hw;
std::string default_fstab;
// Use different fstab paths for normal boot and recovery boot, respectively
if (access("/sbin/recovery", F_OK) == 0) {
default_fstab = "/etc/recovery.fstab";
} else if (fs_mgr_get_boot_config("hardware", &hw)) { // normal boot
for (const char *prefix : {"/odm/etc/fstab.","/vendor/etc/fstab.", "/fstab."}) {
default_fstab = prefix + hw;
if (access(default_fstab.c_str(), F_OK) == 0) break;
}
} else {
LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
}
// combines fstab entries passed in from device tree with
// the ones found from default_fstab file
struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
struct fstab *fstab = fs_mgr_read_fstab(default_fstab.c_str());
return in_place_merge(fstab_dt, fstab);
}
void fs_mgr_free_fstab(struct fstab *fstab)
{
int i;
if (!fstab) {
return;
}
for (i = 0; i < fstab->num_entries; i++) {
/* Free the pointers return by strdup(3) */
free(fstab->recs[i].blk_device);
free(fstab->recs[i].mount_point);
free(fstab->recs[i].fs_type);
free(fstab->recs[i].fs_options);
free(fstab->recs[i].key_loc);
free(fstab->recs[i].key_dir);
free(fstab->recs[i].label);
}
/* Free the fstab_recs array created by calloc(3) */
free(fstab->recs);
/* Free the fstab filename */
free(fstab->fstab_filename);
/* Free fstab */
free(fstab);
}
/* Add an entry to the fstab, and return 0 on success or -1 on error */
int fs_mgr_add_entry(struct fstab *fstab,
const char *mount_point, const char *fs_type,
const char *blk_device)
{
struct fstab_rec *new_fstab_recs;
int n = fstab->num_entries;
new_fstab_recs = (struct fstab_rec *)
realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
if (!new_fstab_recs) {
return -1;
}
/* A new entry was added, so initialize it */
memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
new_fstab_recs[n].mount_point = strdup(mount_point);
new_fstab_recs[n].fs_type = strdup(fs_type);
new_fstab_recs[n].blk_device = strdup(blk_device);
new_fstab_recs[n].length = 0;
/* Update the fstab struct */
fstab->recs = new_fstab_recs;
fstab->num_entries++;
return 0;
}
/*
* Returns the 1st matching fstab_rec that follows the start_rec.
* start_rec is the result of a previous search or NULL.
*/
struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
{
int i;
if (!fstab) {
return NULL;
}
if (start_rec) {
for (i = 0; i < fstab->num_entries; i++) {
if (&fstab->recs[i] == start_rec) {
i++;
break;
}
}
} else {
i = 0;
}
for (; i < fstab->num_entries; i++) {
int len = strlen(fstab->recs[i].mount_point);
if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
(path[len] == '\0' || path[len] == '/')) {
return &fstab->recs[i];
}
}
return NULL;
}
/*
* Returns the 1st matching mount point.
* There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
* and give the fstab_rec from the previous search.
*/
struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
{
return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
}
int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VOLDMANAGED;
}
int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_NONREMOVABLE;
}
int fs_mgr_is_verified(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VERIFY;
}
int fs_mgr_is_avb(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_AVB;
}
int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
}
int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
}
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
}
void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
const char **contents_mode_ret,
const char **filenames_mode_ret)
{
*contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
fstab->file_contents_mode);
*filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
fstab->file_names_mode);
}
int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
}
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
}
int fs_mgr_is_notrim(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_NOTRIM;
}
int fs_mgr_is_formattable(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & (MF_FORMATTABLE);
}
int fs_mgr_is_slotselect(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_SLOTSELECT;
}
int fs_mgr_is_nofail(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_NOFAIL;
}
int fs_mgr_is_latemount(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_LATEMOUNT;
}
int fs_mgr_is_quota(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_QUOTA;
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (C) 2012 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "fs_mgr_priv.h"
#ifdef _LIBGEN_H
#warning "libgen.h must not be included"
#endif
char *me = nullptr;
static void usage(void)
{
LERROR << me << ": usage: " << me
<< " <-a | -n mnt_point blk_dev | -u> <fstab_file>";
exit(1);
}
/* Parse the command line. If an error is encountered, print an error message
* and exit the program, do not return to the caller.
* Return the number of argv[] entries consumed.
*/
static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
const char **n_name, const char **n_blk_dev)
{
me = basename(argv[0]);
if (argc <= 1) {
usage();
}
if (!strcmp(argv[1], "-a")) {
if (argc != 3) {
usage();
}
*a_flag = 1;
}
if (!strcmp(argv[1], "-n")) {
if (argc != 5) {
usage();
}
*n_flag = 1;
*n_name = argv[2];
*n_blk_dev = argv[3];
}
if (!strcmp(argv[1], "-u")) {
if (argc != 3) {
usage();
}
*u_flag = 1;
}
/* If no flag is specified, it's an error */
if (!(*a_flag | *n_flag | *u_flag)) {
usage();
}
/* If more than one flag is specified, it's an error */
if ((*a_flag + *n_flag + *u_flag) > 1) {
usage();
}
return;
}
int main(int argc, char * const argv[])
{
int a_flag=0;
int u_flag=0;
int n_flag=0;
const char *n_name=NULL;
const char *n_blk_dev=NULL;
const char *fstab_file=NULL;
struct fstab *fstab=NULL;
setenv("ANDROID_LOG_TAGS", "*:i", 1); // Set log level to INFO
android::base::InitLogging(
const_cast<char **>(argv), &android::base::KernelLogger);
parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
/* The name of the fstab file is last, after the option */
fstab_file = argv[argc - 1];
fstab = fs_mgr_read_fstab(fstab_file);
if (a_flag) {
return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
} else if (n_flag) {
return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
} else if (u_flag) {
return fs_mgr_unmount_all(fstab);
} else {
LERROR << me << ": Internal error, unknown option";
exit(1);
}
fs_mgr_free_fstab(fstab);
/* Should not get here */
exit(1);
}

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2012 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_H
#define __CORE_FS_MGR_PRIV_H
#include <chrono>
#include <string>
#include <android-base/logging.h>
#include "fs_mgr.h"
#include "fs_mgr_priv_boot_config.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 "
#define FS_MGR_TAG "[libfs_mgr]"
// Logs a message to kernel
#define LINFO LOG(INFO) << FS_MGR_TAG
#define LWARNING LOG(WARNING) << FS_MGR_TAG
#define LERROR LOG(ERROR) << FS_MGR_TAG
// Logs a message with strerror(errno) at the end
#define PINFO PLOG(INFO) << FS_MGR_TAG
#define PWARNING PLOG(WARNING) << FS_MGR_TAG
#define PERROR PLOG(ERROR) << FS_MGR_TAG
#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
/* fstab has the following format:
*
* Any line starting with a # is a comment and ignored
*
* Any blank line is ignored
*
* All other lines must be in this format:
* <source> <mount_point> <fs_type> <mount_flags> <fs_options> <fs_mgr_options>
*
* <mount_flags> is a comma separated list of flags that can be passed to the
* mount command. The list includes noatime, nosuid, nodev, nodiratime,
* ro, rw, remount, defaults.
*
* <fs_options> is a comma separated list of options accepted by the filesystem being
* mounted. It is passed directly to mount without being parsed
*
* <fs_mgr_options> is a comma separated list of flags that control the operation of
* the fs_mgr program. The list includes "wait", which will wait till
* the <source> file exists, and "check", which requests that the fs_mgr
* run an fscheck program on the <source> before mounting the filesystem.
* If check is specifed on a read-only filesystem, it is ignored.
* Also, "encryptable" means that filesystem can be encrypted.
* The "encryptable" flag _MUST_ be followed by a = and a string which
* is the location of the encryption keys. It can either be a path
* to a file or partition which contains the keys, or the word "footer"
* which means the keys are in the last 16 Kbytes of the partition
* containing the filesystem.
*
* When the fs_mgr is requested to mount all filesystems, it will first mount all the
* filesystems that do _NOT_ specify check (including filesystems that are read-only and
* specify check, because check is ignored in that case) and then it will check and mount
* filesystem marked with check.
*
*/
#define MF_WAIT 0x1
#define MF_CHECK 0x2
#define MF_CRYPT 0x4
#define MF_NONREMOVABLE 0x8
#define MF_VOLDMANAGED 0x10
#define MF_LENGTH 0x20
#define MF_RECOVERYONLY 0x40
#define MF_SWAPPRIO 0x80
#define MF_ZRAMSIZE 0x100
#define MF_VERIFY 0x200
#define MF_FORCECRYPT 0x400
#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
external storage */
#define MF_NOTRIM 0x1000
#define MF_FILEENCRYPTION 0x2000
#define MF_FORMATTABLE 0x4000
#define MF_SLOTSELECT 0x8000
#define MF_FORCEFDEORFBE 0x10000
#define MF_LATEMOUNT 0x20000
#define MF_NOFAIL 0x40000
#define MF_VERIFYATBOOT 0x80000
#define MF_MAX_COMP_STREAMS 0x100000
#define MF_RESERVEDSIZE 0x200000
#define MF_QUOTA 0x400000
#define MF_ERASEBLKSIZE 0x800000
#define MF_LOGICALBLKSIZE 0X1000000
#define MF_AVB 0X2000000
#define MF_KEYDIRECTORY 0X4000000
#define DM_BUF_SIZE 4096
using namespace std::chrono_literals;
int fs_mgr_set_blk_ro(const char *blockdev);
bool fs_mgr_wait_for_file(const std::string& filename,
const std::chrono::milliseconds relative_timeout);
bool fs_mgr_update_for_slotselect(struct fstab *fstab);
bool fs_mgr_is_device_unlocked();
const std::string& get_android_dt_dir();
bool is_dt_compatible();
bool is_device_secure();
int load_verity_state(struct fstab_rec* fstab, int* mode);
#endif /* __CORE_FS_MGR_PRIV_H */

View file

@ -0,0 +1,68 @@
/*
* 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_PRIV_AVB_OPS_H
#define __CORE_FS_MGR_PRIV_AVB_OPS_H
#include <map>
#include <string>
#include <libavb/libavb.h>
#include "fs_mgr.h"
// 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 fstab& fstab);
FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map);
static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
}
AvbIOResult ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes,
void* buffer, size_t* out_num_read);
AvbSlotVerifyResult AvbSlotVerify(const std::string& ab_suffix, AvbSlotVerifyFlags flags,
AvbSlotVerifyData** out_data);
private:
void InitializeAvbOps();
AvbOps avb_ops_;
std::map<std::string, std::string> by_name_symlink_map_;
};
#endif /* __CORE_FS_MGR_PRIV_AVB_OPS_H */

View file

@ -0,0 +1,26 @@
/*
* Copyright (C) 2017 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_BOOTCONFIG_H
#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H
#include <sys/cdefs.h>
#include <string>
bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val);
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */

View file

@ -0,0 +1,34 @@
/*
* 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_DM_IOCTL_H
#define __CORE_FS_MGR_PRIV_DM_IOCTL_H
#include <linux/dm-ioctl.h>
#include <string>
void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags);
bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
std::string* out_dev_name);
bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd);
#endif /* __CORE_FS_MGR_PRIV_DM_IOCTL_H */

View file

@ -0,0 +1,62 @@
/*
* 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 uint8_t* 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

@ -0,0 +1,62 @@
/*
* Copyright (C) 2015 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 <stdio.h>
#include <string>
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
// Returns "_a" or "_b" based on two possible values in kernel cmdline:
// - androidboot.slot = a or b OR
// - androidboot.slot_suffix = _a or _b
// TODO: remove slot_suffix once it's deprecated.
std::string fs_mgr_get_slot_suffix() {
std::string slot;
std::string ab_suffix;
if (fs_mgr_get_boot_config("slot", &slot)) {
ab_suffix = "_" + slot;
} else if (!fs_mgr_get_boot_config("slot_suffix", &ab_suffix)) {
ab_suffix = "";
}
return ab_suffix;
}
// Updates |fstab| for slot_suffix. Returns true on success, false on error.
bool fs_mgr_update_for_slotselect(struct fstab *fstab) {
int n;
std::string ab_suffix;
for (n = 0; n < fstab->num_entries; n++) {
if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
char *tmp;
if (ab_suffix.empty()) {
ab_suffix = fs_mgr_get_slot_suffix();
// Returns false as non A/B devices should not have MF_SLOTSELECT.
if (ab_suffix.empty()) return false;
}
if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
free(fstab->recs[n].blk_device);
fstab->recs[n].blk_device = tmp;
} else {
return false;
}
}
}
return true;
}

View file

@ -0,0 +1,953 @@
/*
* Copyright (C) 2013 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 <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <crypto_utils/android_pubkey.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
#include <openssl/obj_mac.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include "fec/io.h"
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
#define VERITY_TABLE_RSA_KEY "/verity_key"
#define VERITY_TABLE_HASH_IDX 8
#define VERITY_TABLE_SALT_IDX 9
#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
#define VERITY_TABLE_OPT_LOGGING "ignore_corruption"
#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
#define VERITY_TABLE_OPT_FEC_FORMAT \
"use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 \
" fec_roots %u " VERITY_TABLE_OPT_IGNZERO
#define VERITY_TABLE_OPT_FEC_ARGS 9
#define METADATA_MAGIC 0x01564c54
#define METADATA_TAG_MAX_LENGTH 63
#define METADATA_EOD "eod"
#define VERITY_LASTSIG_TAG "verity_lastsig"
#define VERITY_STATE_TAG "verity_state"
#define VERITY_STATE_HEADER 0x83c0ae9d
#define VERITY_STATE_VERSION 1
#define VERITY_KMSG_RESTART "dm-verity device corrupted"
#define VERITY_KMSG_BUFSIZE 1024
#define READ_BUF_SIZE 4096
#define __STRINGIFY(x) #x
#define STRINGIFY(x) __STRINGIFY(x)
struct verity_state {
uint32_t header;
uint32_t version;
int32_t mode;
};
extern struct fs_info info;
static RSA *load_key(const char *path)
{
uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
FILE* f = fopen(path, "r");
if (!f) {
LERROR << "Can't open " << path;
return NULL;
}
if (!fread(key_data, sizeof(key_data), 1, f)) {
LERROR << "Could not read key!";
fclose(f);
return NULL;
}
fclose(f);
RSA* key = NULL;
if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
LERROR << "Could not parse key!";
return NULL;
}
return key;
}
static int verify_table(const uint8_t *signature, size_t signature_size,
const char *table, uint32_t table_length)
{
RSA *key;
uint8_t hash_buf[SHA256_DIGEST_LENGTH];
int retval = -1;
// Hash the table
SHA256((uint8_t*)table, table_length, hash_buf);
// Now get the public key from the keyfile
key = load_key(VERITY_TABLE_RSA_KEY);
if (!key) {
LERROR << "Couldn't load verity keys";
goto out;
}
// verify the result
if (!RSA_verify(NID_sha256, hash_buf, sizeof(hash_buf), signature,
signature_size, key)) {
LERROR << "Couldn't verify table";
goto out;
}
retval = 0;
out:
RSA_free(key);
return retval;
}
static int verify_verity_signature(const struct fec_verity_metadata& verity)
{
if (verify_table(verity.signature, sizeof(verity.signature),
verity.table, verity.table_length) == 0 ||
verify_table(verity.ecc_signature, sizeof(verity.ecc_signature),
verity.table, verity.table_length) == 0) {
return 0;
}
return -1;
}
static int invalidate_table(char *table, size_t table_length)
{
size_t n = 0;
size_t idx = 0;
size_t cleared = 0;
while (n < table_length) {
if (table[n++] == ' ') {
++idx;
}
if (idx != VERITY_TABLE_HASH_IDX && idx != VERITY_TABLE_SALT_IDX) {
continue;
}
while (n < table_length && table[n] != ' ') {
table[n++] = '0';
}
if (++cleared == 2) {
return 0;
}
}
return -1;
}
struct verity_table_params {
char *table;
int mode;
struct fec_ecc_metadata ecc;
const char *ecc_dev;
};
typedef bool (*format_verity_table_func)(char *buf, const size_t bufsize,
const struct verity_table_params *params);
static bool format_verity_table(char *buf, const size_t bufsize,
const struct verity_table_params *params)
{
const char *mode_flag = NULL;
int res = -1;
if (params->mode == VERITY_MODE_RESTART) {
mode_flag = VERITY_TABLE_OPT_RESTART;
} else if (params->mode == VERITY_MODE_LOGGING) {
mode_flag = VERITY_TABLE_OPT_LOGGING;
}
if (params->ecc.valid) {
if (mode_flag) {
res = snprintf(buf, bufsize,
"%s %u %s " VERITY_TABLE_OPT_FEC_FORMAT,
params->table, 1 + VERITY_TABLE_OPT_FEC_ARGS, mode_flag, params->ecc_dev,
params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
} else {
res = snprintf(buf, bufsize,
"%s %u " VERITY_TABLE_OPT_FEC_FORMAT,
params->table, VERITY_TABLE_OPT_FEC_ARGS, params->ecc_dev,
params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
}
} else if (mode_flag) {
res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
mode_flag);
} else {
res = snprintf(buf, bufsize, "%s 1 " VERITY_TABLE_OPT_IGNZERO, params->table);
}
if (res < 0 || (size_t)res >= bufsize) {
LERROR << "Error building verity table; insufficient buffer size?";
return false;
}
return true;
}
static bool format_legacy_verity_table(char *buf, const size_t bufsize,
const struct verity_table_params *params)
{
int res;
if (params->mode == VERITY_MODE_EIO) {
res = strlcpy(buf, params->table, bufsize);
} else {
res = snprintf(buf, bufsize, "%s %d", params->table, params->mode);
}
if (res < 0 || (size_t)res >= bufsize) {
LERROR << "Error building verity table; insufficient buffer size?";
return false;
}
return true;
}
static int load_verity_table(struct dm_ioctl *io, const std::string &name,
uint64_t device_size, int fd,
const struct verity_table_params *params, format_verity_table_func format)
{
char *verity_params;
char *buffer = (char*) io;
size_t bufsize;
fs_mgr_verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
// set tgt arguments
io->target_count = 1;
tgt->status = 0;
tgt->sector_start = 0;
tgt->length = device_size / 512;
strcpy(tgt->target_type, "verity");
// build the verity params
verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
bufsize = DM_BUF_SIZE - (verity_params - buffer);
if (!format(verity_params, bufsize, params)) {
LERROR << "Failed to format verity parameters";
return -1;
}
LINFO << "loading verity table: '" << verity_params << "'";
// set next target boundary
verity_params += strlen(verity_params) + 1;
verity_params = (char*)(((uintptr_t)verity_params + 7) & ~7);
tgt->next = verity_params - buffer;
// send the ioctl to load the verity table
if (ioctl(fd, DM_TABLE_LOAD, io)) {
PERROR << "Error loading verity table";
return -1;
}
return 0;
}
static int check_verity_restart(const char *fname)
{
char buffer[VERITY_KMSG_BUFSIZE + 1];
int fd;
int rc = 0;
ssize_t size;
struct stat s;
fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
if (fd == -1) {
if (errno != ENOENT) {
PERROR << "Failed to open " << fname;
}
goto out;
}
if (fstat(fd, &s) == -1) {
PERROR << "Failed to fstat " << fname;
goto out;
}
size = VERITY_KMSG_BUFSIZE;
if (size > s.st_size) {
size = s.st_size;
}
if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
PERROR << "Failed to lseek " << (intmax_t)(s.st_size - size) << " " << fname;
goto out;
}
if (!android::base::ReadFully(fd, buffer, size)) {
PERROR << "Failed to read " << size << " bytes from " << fname;
goto out;
}
buffer[size] = '\0';
if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
rc = 1;
}
out:
if (fd != -1) {
close(fd);
}
return rc;
}
static int was_verity_restart()
{
static const char* files[] = {
// clang-format off
"/sys/fs/pstore/console-ramoops-0",
"/sys/fs/pstore/console-ramoops",
"/proc/last_kmsg",
NULL
// clang-format on
};
int i;
for (i = 0; files[i]; ++i) {
if (check_verity_restart(files[i])) {
return 1;
}
}
return 0;
}
static int metadata_add(FILE *fp, long start, const char *tag,
unsigned int length, off64_t *offset)
{
if (fseek(fp, start, SEEK_SET) < 0 ||
fprintf(fp, "%s %u\n", tag, length) < 0) {
return -1;
}
*offset = ftell(fp);
if (fseek(fp, length, SEEK_CUR) < 0 ||
fprintf(fp, METADATA_EOD " 0\n") < 0) {
return -1;
}
return 0;
}
static int metadata_find(const char *fname, const char *stag,
unsigned int slength, off64_t *offset)
{
FILE *fp = NULL;
char tag[METADATA_TAG_MAX_LENGTH + 1];
int rc = -1;
int n;
long start = 0x4000; /* skip cryptfs metadata area */
uint32_t magic;
unsigned int length = 0;
if (!fname) {
return -1;
}
fp = fopen(fname, "r+");
if (!fp) {
PERROR << "Failed to open " << fname;
goto out;
}
/* check magic */
if (fseek(fp, start, SEEK_SET) < 0 ||
fread(&magic, sizeof(magic), 1, fp) != 1) {
PERROR << "Failed to read magic from " << fname;
goto out;
}
if (magic != METADATA_MAGIC) {
magic = METADATA_MAGIC;
if (fseek(fp, start, SEEK_SET) < 0 ||
fwrite(&magic, sizeof(magic), 1, fp) != 1) {
PERROR << "Failed to write magic to " << fname;
goto out;
}
rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
if (rc < 0) {
PERROR << "Failed to add metadata to " << fname;
}
goto out;
}
start += sizeof(magic);
while (1) {
n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
tag, &length);
if (n == 2 && strcmp(tag, METADATA_EOD)) {
/* found a tag */
start = ftell(fp);
if (!strcmp(tag, stag) && length == slength) {
*offset = start;
rc = 0;
goto out;
}
start += length;
if (fseek(fp, length, SEEK_CUR) < 0) {
PERROR << "Failed to seek " << fname;
goto out;
}
} else {
rc = metadata_add(fp, start, stag, slength, offset);
if (rc < 0) {
PERROR << "Failed to write metadata to " << fname;
}
goto out;
}
}
out:
if (fp) {
fflush(fp);
fclose(fp);
}
return rc;
}
static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
{
int fd;
int rc = -1;
struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
if (fd == -1) {
PERROR << "Failed to open " << fname;
goto out;
}
if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
PERROR << "Failed to write " << sizeof(s) << " bytes to " << fname
<< " to offset " << offset;
goto out;
}
rc = 0;
out:
if (fd != -1) {
close(fd);
}
return rc;
}
static int read_verity_state(const char *fname, off64_t offset, int *mode)
{
int fd = -1;
int rc = -1;
struct verity_state s;
fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
if (fd == -1) {
PERROR << "Failed to open " << fname;
goto out;
}
if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
PERROR << "Failed to read " << sizeof(s) << " bytes from " << fname
<< " offset " << offset;
goto out;
}
if (s.header != VERITY_STATE_HEADER) {
/* space allocated, but no state written. write default state */
*mode = VERITY_MODE_DEFAULT;
rc = write_verity_state(fname, offset, *mode);
goto out;
}
if (s.version != VERITY_STATE_VERSION) {
LERROR << "Unsupported verity state version (" << s.version << ")";
goto out;
}
if (s.mode < VERITY_MODE_EIO ||
s.mode > VERITY_MODE_LAST) {
LERROR << "Unsupported verity mode (" << s.mode << ")";
goto out;
}
*mode = s.mode;
rc = 0;
out:
if (fd != -1) {
close(fd);
}
return rc;
}
static int read_partition(const char *path, uint64_t size)
{
char buf[READ_BUF_SIZE];
ssize_t size_read;
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
PERROR << "Failed to open " << path;
return -errno;
}
while (size) {
size_read = TEMP_FAILURE_RETRY(read(fd, buf, READ_BUF_SIZE));
if (size_read == -1) {
PERROR << "Error in reading partition " << path;
return -errno;
}
size -= size_read;
}
return 0;
}
static int compare_last_signature(struct fstab_rec *fstab, int *match)
{
char tag[METADATA_TAG_MAX_LENGTH + 1];
int fd = -1;
int rc = -1;
off64_t offset = 0;
struct fec_handle *f = NULL;
struct fec_verity_metadata verity;
uint8_t curr[SHA256_DIGEST_LENGTH];
uint8_t prev[SHA256_DIGEST_LENGTH];
*match = 1;
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
FEC_DEFAULT_ROOTS) == -1) {
PERROR << "Failed to open '" << fstab->blk_device << "'";
return rc;
}
// read verity metadata
if (fec_verity_get_metadata(f, &verity) == -1) {
PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
goto out;
}
SHA256(verity.signature, sizeof(verity.signature), curr);
if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
basename(fstab->mount_point)) >= (int)sizeof(tag)) {
LERROR << "Metadata tag name too long for " << fstab->mount_point;
goto out;
}
if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_LENGTH,
&offset) < 0) {
goto out;
}
fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
if (fd == -1) {
PERROR << "Failed to open " << fstab->verity_loc;
goto out;
}
if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
offset)) != sizeof(prev)) {
PERROR << "Failed to read " << sizeof(prev) << " bytes from "
<< fstab->verity_loc << " offset " << offset;
goto out;
}
*match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH);
if (!*match) {
/* update current signature hash */
if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
offset)) != sizeof(curr)) {
PERROR << "Failed to write " << sizeof(curr) << " bytes to "
<< fstab->verity_loc << " offset " << offset;
goto out;
}
}
rc = 0;
out:
fec_close(f);
return rc;
}
static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
{
char tag[METADATA_TAG_MAX_LENGTH + 1];
if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
basename(fstab->mount_point)) >= (int)sizeof(tag)) {
LERROR << "Metadata tag name too long for " << fstab->mount_point;
return -1;
}
return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
offset);
}
int load_verity_state(struct fstab_rec* fstab, int* mode) {
int match = 0;
off64_t offset = 0;
/* unless otherwise specified, use EIO mode */
*mode = VERITY_MODE_EIO;
/* use the kernel parameter if set */
std::string veritymode;
if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
if (veritymode == "enforcing") {
*mode = VERITY_MODE_DEFAULT;
}
return 0;
}
if (get_verity_state_offset(fstab, &offset) < 0) {
/* fall back to stateless behavior */
return 0;
}
if (was_verity_restart()) {
/* device was restarted after dm-verity detected a corrupted
* block, so use EIO mode */
return write_verity_state(fstab->verity_loc, offset, *mode);
}
if (!compare_last_signature(fstab, &match) && !match) {
/* partition has been reflashed, reset dm-verity state */
*mode = VERITY_MODE_DEFAULT;
return write_verity_state(fstab->verity_loc, offset, *mode);
}
return read_verity_state(fstab->verity_loc, offset, mode);
}
// Update the verity table using the actual block device path.
// Two cases:
// Case-1: verity table is shared for devices with different by-name prefix.
// Example:
// verity table token: /dev/block/bootdevice/by-name/vendor
// blk_device-1 (non-A/B): /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
// blk_device-2 (A/B): /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor_a
//
// Case-2: append A/B suffix in the verity table.
// Example:
// verity table token: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
// blk_device: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor_a
static void update_verity_table_blk_device(const std::string& blk_device, char** table,
bool slot_select) {
bool updated = false;
std::string result, ab_suffix;
auto tokens = android::base::Split(*table, " ");
// If slot_select is set, it means blk_device is already updated with ab_suffix.
if (slot_select) ab_suffix = fs_mgr_get_slot_suffix();
for (const auto& token : tokens) {
std::string new_token;
if (android::base::StartsWith(token, "/dev/block/")) {
if (token == blk_device) return; // no need to update if they're already the same.
std::size_t found1 = blk_device.find("by-name");
std::size_t found2 = token.find("by-name");
if (found1 != std::string::npos && found2 != std::string::npos &&
blk_device.substr(found1) == token.substr(found2) + ab_suffix) {
new_token = blk_device;
}
}
if (!new_token.empty()) {
updated = true;
LINFO << "Verity table: updated block device from '" << token << "' to '" << new_token
<< "'";
} else {
new_token = token;
}
if (result.empty()) {
result = new_token;
} else {
result += " " + new_token;
}
}
if (!updated) {
return;
}
free(*table);
*table = strdup(result.c_str());
}
// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
// verity device to get created before return
int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
{
int retval = FS_MGR_SETUP_VERITY_FAIL;
int fd = -1;
std::string verity_blk_name;
struct fec_handle *f = NULL;
struct fec_verity_metadata verity;
struct verity_table_params params = { .table = NULL };
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
const std::string mount_point(basename(fstab->mount_point));
bool verified_at_boot = false;
// This is a public API and so deserves its own check to see if verity
// setup is needed at all.
if (!is_device_secure()) {
LINFO << "Verity setup skipped for " << mount_point;
return FS_MGR_SETUP_VERITY_SKIPPED;
}
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
FEC_DEFAULT_ROOTS) < 0) {
PERROR << "Failed to open '" << fstab->blk_device << "'";
return retval;
}
// read verity metadata
if (fec_verity_get_metadata(f, &verity) < 0) {
PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
// Allow verity disabled when the device is unlocked without metadata
if (fs_mgr_is_device_unlocked()) {
retval = FS_MGR_SETUP_VERITY_SKIPPED;
LWARNING << "Allow invalid metadata when the device is unlocked";
}
goto out;
}
#ifdef ALLOW_ADBD_DISABLE_VERITY
if (verity.disabled) {
retval = FS_MGR_SETUP_VERITY_DISABLED;
LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG";
goto out;
}
#endif
// read ecc metadata
if (fec_ecc_get_metadata(f, &params.ecc) < 0) {
params.ecc.valid = false;
}
params.ecc_dev = fstab->blk_device;
// get the device mapper fd
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
PERROR << "Error opening device mapper";
goto out;
}
// create the device
if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
LERROR << "Couldn't create verity device!";
goto out;
}
// get the name of the device file
if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
LERROR << "Couldn't get verity device number!";
goto out;
}
if (load_verity_state(fstab, &params.mode) < 0) {
/* if accessing or updating the state failed, switch to the default
* safe mode. This makes sure the device won't end up in an endless
* restart loop, and no corrupted data will be exposed to userspace
* without a warning. */
params.mode = VERITY_MODE_EIO;
}
if (!verity.table) {
goto out;
}
params.table = strdup(verity.table);
if (!params.table) {
goto out;
}
// verify the signature on the table
if (verify_verity_signature(verity) < 0) {
// Allow signature verification error when the device is unlocked
if (fs_mgr_is_device_unlocked()) {
retval = FS_MGR_SETUP_VERITY_SKIPPED;
LWARNING << "Allow signature verification error when the device is unlocked";
goto out;
}
if (params.mode == VERITY_MODE_LOGGING) {
// the user has been warned, allow mounting without dm-verity
retval = FS_MGR_SETUP_VERITY_SKIPPED;
goto out;
}
// invalidate root hash and salt to trigger device-specific recovery
if (invalidate_table(params.table, verity.table_length) < 0) {
goto out;
}
}
LINFO << "Enabling dm-verity for " << mount_point.c_str()
<< " (mode " << params.mode << ")";
// Update the verity params using the actual block device path
update_verity_table_blk_device(fstab->blk_device, &params.table,
fstab->fs_mgr_flags & MF_SLOTSELECT);
// load the verity mapping table
if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
format_verity_table) == 0) {
goto loaded;
}
if (params.ecc.valid) {
// kernel may not support error correction, try without
LINFO << "Disabling error correction for " << mount_point.c_str();
params.ecc.valid = false;
if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
format_verity_table) == 0) {
goto loaded;
}
}
// try the legacy format for backwards compatibility
if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
format_legacy_verity_table) == 0) {
goto loaded;
}
if (params.mode != VERITY_MODE_EIO) {
// as a last resort, EIO mode should always be supported
LINFO << "Falling back to EIO mode for " << mount_point.c_str();
params.mode = VERITY_MODE_EIO;
if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
format_legacy_verity_table) == 0) {
goto loaded;
}
}
LERROR << "Failed to load verity table for " << mount_point.c_str();
goto out;
loaded:
// activate the device
if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
goto out;
}
// mark the underlying block device as read-only
fs_mgr_set_blk_ro(fstab->blk_device);
// Verify the entire partition in one go
// If there is an error, allow it to mount as a normal verity partition.
if (fstab->fs_mgr_flags & MF_VERIFYATBOOT) {
LINFO << "Verifying partition " << fstab->blk_device << " at boot";
int err = read_partition(verity_blk_name.c_str(), verity.data_size);
if (!err) {
LINFO << "Verified verity partition "
<< fstab->blk_device << " at boot";
verified_at_boot = true;
}
}
// assign the new verity block device as the block device
if (!verified_at_boot) {
free(fstab->blk_device);
fstab->blk_device = strdup(verity_blk_name.c_str());
} else if (!fs_mgr_destroy_verity_device(io, mount_point, fd)) {
LERROR << "Failed to remove verity device " << mount_point.c_str();
goto out;
}
// make sure we've set everything up properly
if (wait_for_verity_dev && !fs_mgr_wait_for_file(fstab->blk_device, 1s)) {
goto out;
}
retval = FS_MGR_SETUP_VERITY_SUCCESS;
out:
if (fd != -1) {
close(fd);
}
fec_close(f);
free(params.table);
return retval;
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (C) 2012 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_H
#define __CORE_FS_MGR_H
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <linux/dm-ioctl.h>
#include <fstab/fstab.h>
// Magic number at start of verity metadata
#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
// Replacement magic number at start of verity metadata to cleanly
// turn verity off in userdebug builds.
#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
__BEGIN_DECLS
// Verity modes
enum verity_mode {
VERITY_MODE_EIO = 0,
VERITY_MODE_LOGGING = 1,
VERITY_MODE_RESTART = 2,
VERITY_MODE_LAST = VERITY_MODE_RESTART,
VERITY_MODE_DEFAULT = VERITY_MODE_RESTART
};
// Mount modes
enum mount_mode {
MOUNT_MODE_DEFAULT = 0,
MOUNT_MODE_EARLY = 1,
MOUNT_MODE_LATE = 2
};
// Callback function for verity status
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
#define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 2
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
#define FS_MGR_DOMNT_SUCCESS 0
int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_mount_one(struct fstab_rec *rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
bool fs_mgr_load_verity_state(int* mode);
bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
#define FS_MGR_SETUP_VERITY_SKIPPED (-3)
#define FS_MGR_SETUP_VERITY_DISABLED (-2)
#define FS_MGR_SETUP_VERITY_FAIL (-1)
#define FS_MGR_SETUP_VERITY_SUCCESS 0
int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
__END_DECLS
#endif /* __CORE_FS_MGR_H */

View file

@ -0,0 +1,131 @@
/*
* Copyright (C) 2017 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_AVB_H
#define __CORE_FS_MGR_AVB_H
#include <map>
#include <memory>
#include <string>
#include <libavb/libavb.h>
#include "fs_mgr.h"
enum class SetUpAvbHashtreeResult {
kSuccess = 0,
kFail,
kDisabled,
};
class FsManagerAvbOps;
class FsManagerAvbHandle;
using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
using ByNameSymlinkMap = std::map<std::string, std::string>;
// Provides a factory method to return a unique_ptr pointing to itself and the
// SetUpAvbHashtree() function to extract dm-verity parameters from AVB HASHTREE
// descriptors 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();
//
// There are two overloaded Open() functions with a single parameter.
// The argument can be a ByNameSymlinkMap describing the mapping from partition
// name to by-name symlink, or a fstab file to which the ByNameSymlinkMap is
// constructed from. e.g.,
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a ->
// - ByNameSymlinkMap["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
//
// 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 kAvbHandleHashtreeDisabled:
// 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 kAvbHandleVerificationDisabled:
// to support 'avbctl disable-verification': only the top-level
// vbmeta is read, vbmeta structs in other partitions are not processed.
// It's needed to bypass AVB when using the generic system.img to run
// VTS for project Treble.
//
// - a valid unique_ptr with status kAvbHandleVerificationError:
// there is verification error when libavb loads vbmeta from each
// partition. This is only allowed when the device is unlocked.
//
// - a valid unique_ptr with status kAvbHandleSuccess: the metadata
// is verified and can be trusted.
//
static FsManagerAvbUniquePtr Open(const fstab& fstab);
static FsManagerAvbUniquePtr Open(ByNameSymlinkMap&& by_name_symlink_map);
// Sets up dm-verity on the given fstab entry.
// The 'wait_for_verity_dev' parameter makes this function wait for the
// verity device to get created before return.
//
// Return value:
// - kSuccess: successfully loads dm-verity table into kernel.
// - kFailed: failed to setup dm-verity, e.g., vbmeta verification error,
// failed to get the HASHTREE descriptor, runtime error when set up
// device-mapper, etc.
// - kDisabled: hashtree is disabled.
SetUpAvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
const std::string& avb_version() const { return avb_version_; }
FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move
FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
~FsManagerAvbHandle() {
if (avb_slot_data_) {
avb_slot_verify_data_free(avb_slot_data_);
}
};
private:
enum AvbHandleStatus {
kAvbHandleSuccess = 0,
kAvbHandleUninitialized,
kAvbHandleHashtreeDisabled,
kAvbHandleVerificationDisabled,
kAvbHandleVerificationError,
};
FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
static FsManagerAvbUniquePtr DoOpen(FsManagerAvbOps* avb_ops);
AvbSlotVerifyData* avb_slot_data_;
AvbHandleStatus status_;
std::string avb_version_;
};
#endif /* __CORE_FS_MGR_AVB_H */

View file

@ -0,0 +1,101 @@
/*
* Copyright (C) 2012 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_TAB_H
#define __CORE_FS_TAB_H
#include <linux/dm-ioctl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
// C++ only headers
// TODO: move this into separate header files under include/fs_mgr/*.h
#ifdef __cplusplus
#include <string>
#endif
__BEGIN_DECLS
/*
* The entries must be kept in the same order as they were seen in the fstab.
* Unless explicitly requested, a lookup on mount point should always
* return the 1st one.
*/
struct fstab {
int num_entries;
struct fstab_rec* recs;
char* fstab_filename;
};
struct fstab_rec {
char* blk_device;
char* mount_point;
char* fs_type;
unsigned long flags;
char* fs_options;
int fs_mgr_flags;
char* key_loc;
char* key_dir;
char* verity_loc;
long long length;
char* label;
int partnum;
int swap_prio;
int max_comp_streams;
unsigned int zram_size;
uint64_t reserved_size;
unsigned int file_contents_mode;
unsigned int file_names_mode;
unsigned int erase_blk_size;
unsigned int logical_blk_size;
};
struct fstab* fs_mgr_read_fstab_default();
struct fstab* fs_mgr_read_fstab_dt();
struct fstab* fs_mgr_read_fstab(const char* fstab_path);
void fs_mgr_free_fstab(struct fstab* fstab);
int fs_mgr_add_entry(struct fstab* fstab, const char* mount_point, const char* fs_type,
const char* blk_device);
struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const char* path);
int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab);
int fs_mgr_is_nonremovable(const struct fstab_rec* fstab);
int fs_mgr_is_verified(const struct fstab_rec* fstab);
int fs_mgr_is_verifyatboot(const struct fstab_rec* fstab);
int fs_mgr_is_avb(const struct fstab_rec* fstab);
int fs_mgr_is_encryptable(const struct fstab_rec* fstab);
int fs_mgr_is_file_encrypted(const struct fstab_rec* fstab);
void fs_mgr_get_file_encryption_modes(const struct fstab_rec* fstab, const char** contents_mode_ret,
const char** filenames_mode_ret);
int fs_mgr_is_convertible_to_fbe(const struct fstab_rec* fstab);
int fs_mgr_is_noemulatedsd(const struct fstab_rec* fstab);
int fs_mgr_is_notrim(const struct fstab_rec* fstab);
int fs_mgr_is_formattable(const struct fstab_rec* fstab);
int fs_mgr_is_slotselect(const struct fstab_rec* fstab);
int fs_mgr_is_nofail(const struct fstab_rec* fstab);
int fs_mgr_is_latemount(const struct fstab_rec* fstab);
int fs_mgr_is_quota(const struct fstab_rec* fstab);
__END_DECLS
// C++ only functions
// TODO: move this into separate header files under include/fs_mgr/*.h
#ifdef __cplusplus
std::string fs_mgr_get_slot_suffix();
#endif
#endif /* __CORE_FS_TAB_H */