upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
1
android/system/core/fs_mgr/.clang-format
Symbolic link
1
android/system/core/fs_mgr/.clang-format
Symbolic link
|
@ -0,0 +1 @@
|
|||
../init/.clang-format
|
79
android/system/core/fs_mgr/Android.bp
Normal file
79
android/system/core/fs_mgr/Android.bp
Normal 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"],
|
||||
}
|
38
android/system/core/fs_mgr/Android.mk
Normal file
38
android/system/core/fs_mgr/Android.mk
Normal 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)
|
1396
android/system/core/fs_mgr/fs_mgr.cpp
Normal file
1396
android/system/core/fs_mgr/fs_mgr.cpp
Normal file
File diff suppressed because it is too large
Load diff
610
android/system/core/fs_mgr/fs_mgr_avb.cpp
Normal file
610
android/system/core/fs_mgr/fs_mgr_avb.cpp
Normal 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;
|
||||
}
|
199
android/system/core/fs_mgr/fs_mgr_avb_ops.cpp
Normal file
199
android/system/core/fs_mgr/fs_mgr_avb_ops.cpp
Normal 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);
|
||||
}
|
77
android/system/core/fs_mgr/fs_mgr_boot_config.cpp
Normal file
77
android/system/core/fs_mgr/fs_mgr_boot_config.cpp
Normal 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;
|
||||
}
|
80
android/system/core/fs_mgr/fs_mgr_dm_ioctl.cpp
Normal file
80
android/system/core/fs_mgr/fs_mgr_dm_ioctl.cpp
Normal 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;
|
||||
}
|
124
android/system/core/fs_mgr/fs_mgr_format.cpp
Normal file
124
android/system/core/fs_mgr/fs_mgr_format.cpp
Normal 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;
|
||||
}
|
908
android/system/core/fs_mgr/fs_mgr_fstab.cpp
Normal file
908
android/system/core/fs_mgr/fs_mgr_fstab.cpp
Normal 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;
|
||||
}
|
118
android/system/core/fs_mgr/fs_mgr_main.cpp
Normal file
118
android/system/core/fs_mgr/fs_mgr_main.cpp
Normal 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);
|
||||
}
|
128
android/system/core/fs_mgr/fs_mgr_priv.h
Normal file
128
android/system/core/fs_mgr/fs_mgr_priv.h
Normal 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 */
|
68
android/system/core/fs_mgr/fs_mgr_priv_avb_ops.h
Normal file
68
android/system/core/fs_mgr/fs_mgr_priv_avb_ops.h
Normal 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 */
|
26
android/system/core/fs_mgr/fs_mgr_priv_boot_config.h
Normal file
26
android/system/core/fs_mgr/fs_mgr_priv_boot_config.h
Normal 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 */
|
34
android/system/core/fs_mgr/fs_mgr_priv_dm_ioctl.h
Normal file
34
android/system/core/fs_mgr/fs_mgr_priv_dm_ioctl.h
Normal 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 */
|
62
android/system/core/fs_mgr/fs_mgr_priv_sha.h
Normal file
62
android/system/core/fs_mgr/fs_mgr_priv_sha.h
Normal 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 */
|
62
android/system/core/fs_mgr/fs_mgr_slotselect.cpp
Normal file
62
android/system/core/fs_mgr/fs_mgr_slotselect.cpp
Normal 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;
|
||||
}
|
953
android/system/core/fs_mgr/fs_mgr_verity.cpp
Normal file
953
android/system/core/fs_mgr/fs_mgr_verity.cpp
Normal 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, ¶ms.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, ¶ms.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, ¶ms.table,
|
||||
fstab->fs_mgr_flags & MF_SLOTSELECT);
|
||||
|
||||
// load the verity mapping table
|
||||
if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
|
||||
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, ¶ms,
|
||||
format_verity_table) == 0) {
|
||||
goto loaded;
|
||||
}
|
||||
}
|
||||
|
||||
// try the legacy format for backwards compatibility
|
||||
if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
|
||||
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, ¶ms,
|
||||
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;
|
||||
}
|
92
android/system/core/fs_mgr/include/fs_mgr.h
Normal file
92
android/system/core/fs_mgr/include/fs_mgr.h
Normal 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 */
|
131
android/system/core/fs_mgr/include/fs_mgr_avb.h
Normal file
131
android/system/core/fs_mgr/include/fs_mgr_avb.h
Normal 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 */
|
101
android/system/core/fs_mgr/include_fstab/fstab/fstab.h
Normal file
101
android/system/core/fs_mgr/include_fstab/fstab/fstab.h
Normal 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 */
|
Loading…
Add table
Add a link
Reference in a new issue