[automerger skipped] Clean up potential busy files after key eviction. am: 759ac5f87c -s ours
am skip reason: Merged-In I9e39e5bb0f5190284552bcd252b6213a22a51e91 with SHA-1 a21962b207 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/system/vold/+/21649087
Change-Id: I16aa0e7cfe276c918affdbddc58e593e2f1c2eeb
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 8f413c4..1ccfc09 100644
--- a/Android.bp
+++ b/Android.bp
@@ -19,8 +19,9 @@
"clang-analyzer-security*",
"android-*",
],
- tidy_flags: [
- "-warnings-as-errors=clang-analyzer-security*,cert-*",
+ tidy_checks_as_errors: [
+ "clang-analyzer-security*",
+ "cert-*",
],
}
@@ -42,6 +43,8 @@
],
shared_libs: [
"android.hardware.boot@1.0",
+ "android.hardware.boot-V1-ndk",
+ "libboot_control_client",
"libbase",
"libbinder",
"libcrypto",
@@ -165,7 +168,7 @@
"libkeymint_support",
],
whole_static_libs: [
- "com.android.sysprop.apex",
+ "libcom.android.sysprop.apex",
"libc++fs",
],
}
@@ -187,7 +190,7 @@
required: [
"mke2fs",
"vold_prepare_subdirs",
- "fuse_media.o",
+ "fuseMedia.o",
],
shared_libs: [
diff --git a/Checkpoint.cpp b/Checkpoint.cpp
index 755f0e3..4766d79 100644
--- a/Checkpoint.cpp
+++ b/Checkpoint.cpp
@@ -26,12 +26,12 @@
#include <thread>
#include <vector>
+#include <BootControlClient.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/unique_fd.h>
-#include <android/hardware/boot/1.0/IBootControl.h>
#include <cutils/android_reboot.h>
#include <fcntl.h>
#include <fs_mgr.h>
@@ -48,11 +48,7 @@
using android::binder::Status;
using android::fs_mgr::Fstab;
using android::fs_mgr::ReadFstabFromFile;
-using android::hardware::hidl_string;
-using android::hardware::boot::V1_0::BoolResult;
-using android::hardware::boot::V1_0::CommandResult;
-using android::hardware::boot::V1_0::IBootControl;
-using android::hardware::boot::V1_0::Slot;
+using android::hal::BootControlClient;
namespace android {
namespace vold {
@@ -128,11 +124,10 @@
if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
std::string content = std::to_string(retry + 1);
if (retry == -1) {
- sp<IBootControl> module = IBootControl::getService();
+ auto module = BootControlClient::WaitForService();
if (module) {
- std::string suffix;
- auto cb = [&suffix](hidl_string s) { suffix = s; };
- if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
+ std::string suffix = module->GetSuffix(module->GetCurrentSlot());
+ if (!suffix.empty()) content += " " + suffix;
}
}
if (!android::base::WriteStringToFile(content, kMetadataCPFile))
@@ -143,6 +138,7 @@
namespace {
volatile bool isCheckpointing = false;
+volatile bool isBow = true;
volatile bool needsCheckpointWasCalled = false;
@@ -162,10 +158,9 @@
<< "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
return Status::ok();
}
- sp<IBootControl> module = IBootControl::getService();
+ auto module = BootControlClient::WaitForService();
if (module) {
- CommandResult cr;
- module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
+ auto cr = module->MarkBootSuccessful();
if (!cr.success)
return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
LOG(INFO) << "Marked slot as booted successfully.";
@@ -173,6 +168,8 @@
if (!SetProperty("ota.warm_reset", "0")) {
LOG(WARNING) << "Failed to reset the warm reset flag";
}
+ } else {
+ LOG(ERROR) << "Failed to get BootControl HAL, not marking slot as successful.";
}
// Must take action for list of mounted checkpointed things here
// To do this, we walk the list of mounted file systems.
@@ -198,7 +195,7 @@
return error(EINVAL, "Failed to remount");
}
}
- } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
+ } else if (fstab_rec->fs_mgr_flags.checkpoint_blk && isBow) {
if (!setBowState(mount_rec.blk_device, "2"))
return error(EINVAL, "Failed to set bow state");
}
@@ -254,12 +251,11 @@
if (content == "0") return true;
if (content.substr(0, 3) == "-1 ") {
std::string oldSuffix = content.substr(3);
- sp<IBootControl> module = IBootControl::getService();
+ auto module = BootControlClient::WaitForService();
std::string newSuffix;
if (module) {
- auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
- module->getSuffix(module->getCurrentSlot(), cb);
+ newSuffix = module->GetSuffix(module->GetCurrentSlot());
if (oldSuffix == newSuffix) return true;
}
}
@@ -276,11 +272,11 @@
bool ret;
std::string content;
- sp<IBootControl> module = IBootControl::getService();
+ auto module = BootControlClient::WaitForService();
if (isCheckpointing) return isCheckpointing;
-
- if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
+ // In case of INVALID slot or other failures, we do not perform checkpoint.
+ if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
isCheckpointing = true;
return true;
}
@@ -386,7 +382,7 @@
LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
<< nanoseconds_to_milliseconds(time) << "ms for checkpoint";
- setBowState(mount_rec.blk_device, "1");
+ isBow &= setBowState(mount_rec.blk_device, "1");
}
if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index 6c08177..f871a32 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -33,7 +33,6 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <selinux/android.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -44,7 +43,6 @@
#include "android/os/IVold.h"
-#define EMULATED_USES_SELINUX 0
#define MANAGE_MISC_DIRS 0
#include <cutils/fs.h>
@@ -94,9 +92,16 @@
const std::string systemwide_volume_key_dir =
std::string() + DATA_MNT_POINT + "/misc/vold/volume_keys";
+const std::string data_data_dir = std::string() + DATA_MNT_POINT + "/data";
+const std::string data_user_0_dir = std::string() + DATA_MNT_POINT + "/user/0";
+const std::string media_obb_dir = std::string() + DATA_MNT_POINT + "/media/obb";
+
// Some users are ephemeral, don't try to wipe their keys from disk
std::set<userid_t> s_ephemeral_users;
+// The system DE encryption policy
+EncryptionPolicy s_device_policy;
+
// Map user ids to encryption policies
std::map<userid_t, EncryptionPolicy> s_de_policies;
std::map<userid_t, EncryptionPolicy> s_ce_policies;
@@ -108,10 +113,6 @@
return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
}
-static bool fscrypt_is_emulated() {
- return property_get_bool("persist.sys.emulate_fbe", false);
-}
-
static const char* escape_empty(const std::string& value) {
return value.empty() ? "null" : value.c_str();
}
@@ -307,15 +308,26 @@
return true;
}
+// Prepare a directory without assigning it an encryption policy. The directory
+// will inherit the encryption policy of its parent directory, or will be
+// unencrypted if the parent directory is unencrypted.
static bool prepare_dir(const std::string& dir, mode_t mode, uid_t uid, gid_t gid) {
LOG(DEBUG) << "Preparing: " << dir;
- if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
+ if (android::vold::PrepareDir(dir, mode, uid, gid, 0) != 0) {
PLOG(ERROR) << "Failed to prepare " << dir;
return false;
}
return true;
}
+// Prepare a directory and assign it the given encryption policy.
+static bool prepare_dir_with_policy(const std::string& dir, mode_t mode, uid_t uid, gid_t gid,
+ const EncryptionPolicy& policy) {
+ if (!prepare_dir(dir, mode, uid, gid)) return false;
+ if (IsFbeEnabled() && !EnsurePolicy(policy, dir)) return false;
+ return true;
+}
+
static bool destroy_dir(const std::string& dir) {
LOG(DEBUG) << "Destroying: " << dir;
if (rmdir(dir.c_str()) != 0 && errno != ENOENT) {
@@ -365,7 +377,6 @@
EncryptionPolicy* policy) {
auto refi = key_map.find(user_id);
if (refi == key_map.end()) {
- LOG(DEBUG) << "Cannot find key for " << user_id;
return false;
}
*policy = refi->second;
@@ -406,7 +417,11 @@
userid_t user_id = std::stoi(entry->d_name);
auto key_path = de_dir + "/" + entry->d_name;
KeyBuffer de_key;
- if (!retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false;
+ if (!retrieveKey(key_path, kEmptyAuthentication, &de_key)) {
+ // This is probably a partially removed user, so ignore
+ if (user_id != 0) continue;
+ return false;
+ }
EncryptionPolicy de_policy;
if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
auto ret = s_de_policies.insert({user_id, de_policy});
@@ -443,11 +458,12 @@
makeGen(options), &device_key))
return false;
- EncryptionPolicy device_policy;
- if (!install_storage_key(DATA_MNT_POINT, options, device_key, &device_policy)) return false;
+ // This initializes s_device_policy, which is a global variable so that
+ // fscrypt_init_user0() can access it later.
+ if (!install_storage_key(DATA_MNT_POINT, options, device_key, &s_device_policy)) return false;
std::string options_string;
- if (!OptionsToString(device_policy.options, &options_string)) {
+ if (!OptionsToString(s_device_policy.options, &options_string)) {
LOG(ERROR) << "Unable to serialize options";
return false;
}
@@ -455,7 +471,7 @@
if (!android::vold::writeStringToFile(options_string, options_filename)) return false;
std::string ref_filename = std::string(DATA_MNT_POINT) + fscrypt_key_ref;
- if (!android::vold::writeStringToFile(device_policy.key_raw_ref, ref_filename)) return false;
+ if (!android::vold::writeStringToFile(s_device_policy.key_raw_ref, ref_filename)) return false;
LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;
KeyBuffer per_boot_key;
@@ -470,11 +486,58 @@
return true;
}
+static bool prepare_special_dirs() {
+ // Ensure that /data/data and its "alias" /data/user/0 exist, and create the
+ // bind mount of /data/data onto /data/user/0. This *should* happen in
+ // fscrypt_prepare_user_storage(). However, it actually must be done early,
+ // before the rest of user 0's CE storage is prepared. This is because
+ // zygote may need to set up app data isolation before then, which requires
+ // mounting a tmpfs over /data/data to ensure it remains hidden. This issue
+ // arises due to /data/data being in the top-level directory.
+
+ // /data/user/0 used to be a symlink to /data/data, so we must first delete
+ // the old symlink if present.
+ if (android::vold::IsSymlink(data_user_0_dir) && android::vold::Unlink(data_user_0_dir) != 0)
+ return false;
+ // On first boot, we'll be creating /data/data for the first time, and user
+ // 0's CE key will be installed already since it was just created. Take the
+ // opportunity to also set the encryption policy of /data/data right away.
+ EncryptionPolicy ce_policy;
+ if (lookup_policy(s_ce_policies, 0, &ce_policy)) {
+ if (!prepare_dir_with_policy(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM, ce_policy))
+ return false;
+ } else {
+ if (!prepare_dir(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
+ // EnsurePolicy() will have to happen later, in fscrypt_prepare_user_storage().
+ }
+ if (!prepare_dir(data_user_0_dir, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
+ if (android::vold::BindMount(data_data_dir, data_user_0_dir) != 0) return false;
+
+ // If /data/media/obb doesn't exist, create it and encrypt it with the
+ // device policy. Normally, device-policy-encrypted directories are created
+ // and encrypted by init; /data/media/obb is special because it is located
+ // in /data/media. Since /data/media also contains per-user encrypted
+ // directories, by design only vold can write to it. As a side effect of
+ // that, vold must create /data/media/obb.
+ //
+ // We must tolerate /data/media/obb being unencrypted if it already exists
+ // on-disk, since it used to be unencrypted (b/64566063).
+ if (android::vold::pathExists(media_obb_dir)) {
+ if (!prepare_dir(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
+ } else {
+ if (!prepare_dir_with_policy(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW,
+ s_device_policy))
+ return false;
+ }
+ return true;
+}
+
bool fscrypt_init_user0_done;
bool fscrypt_init_user0() {
LOG(DEBUG) << "fscrypt_init_user0";
- if (fscrypt_is_native()) {
+
+ if (IsFbeEnabled()) {
if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
@@ -485,24 +548,23 @@
// explicit calls to install DE keys for secondary users
if (!load_all_de_keys()) return false;
}
- // We can only safely prepare DE storage here, since CE keys are probably
- // entangled with user credentials. The framework will always prepare CE
- // storage once CE keys are installed.
+
+ // Now that user 0's CE key has been created, we can prepare /data/data.
+ if (!prepare_special_dirs()) return false;
+
+ // With the exception of what is done by prepare_special_dirs() above, we
+ // only prepare DE storage here, since user 0's CE key won't be installed
+ // yet unless it was just created. The framework will prepare the user's CE
+ // storage later, once their CE key is installed.
if (!fscrypt_prepare_user_storage("", 0, 0, android::os::IVold::STORAGE_FLAG_DE)) {
LOG(ERROR) << "Failed to prepare user 0 storage";
return false;
}
- // If this is a non-FBE device that recently left an emulated mode,
- // restore user data directories to known-good state.
- if (!fscrypt_is_native() && !fscrypt_is_emulated()) {
- fscrypt_unlock_user_key(0, 0, "!");
- }
-
// In some scenarios (e.g. userspace reboot) we might unmount userdata
// without doing a hard reboot. If CE keys were stored in fs keyring then
// they will be lost after unmount. Attempt to re-install them.
- if (fscrypt_is_native() && android::vold::isFsKeyringSupported()) {
+ if (IsFbeEnabled() && android::vold::isFsKeyringSupported()) {
if (!try_reload_ce_keys()) return false;
}
@@ -512,7 +574,7 @@
bool fscrypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral) {
LOG(DEBUG) << "fscrypt_vold_create_user_key for " << user_id << " serial " << serial;
- if (!fscrypt_is_native()) {
+ if (!IsFbeEnabled()) {
return true;
}
// FIXME test for existence of key that is not loaded yet
@@ -563,7 +625,7 @@
bool fscrypt_destroy_user_key(userid_t user_id) {
LOG(DEBUG) << "fscrypt_destroy_user_key(" << user_id << ")";
- if (!fscrypt_is_native()) {
+ if (!IsFbeEnabled()) {
return true;
}
bool success = true;
@@ -592,36 +654,6 @@
return success;
}
-static bool emulated_lock(const std::string& path) {
- if (chmod(path.c_str(), 0000) != 0) {
- PLOG(ERROR) << "Failed to chmod " << path;
- return false;
- }
-#if EMULATED_USES_SELINUX
- if (setfilecon(path.c_str(), "u:object_r:storage_stub_file:s0") != 0) {
- PLOG(WARNING) << "Failed to setfilecon " << path;
- return false;
- }
-#endif
- return true;
-}
-
-static bool emulated_unlock(const std::string& path, mode_t mode) {
- if (chmod(path.c_str(), mode) != 0) {
- PLOG(ERROR) << "Failed to chmod " << path;
- // FIXME temporary workaround for b/26713622
- if (fscrypt_is_emulated()) return false;
- }
-#if EMULATED_USES_SELINUX
- if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_FORCE) != 0) {
- PLOG(WARNING) << "Failed to restorecon " << path;
- // FIXME temporary workaround for b/26713622
- if (fscrypt_is_emulated()) return false;
- }
-#endif
- return true;
-}
-
static bool parse_hex(const std::string& hex, std::string* result) {
if (hex == "!") {
*result = "";
@@ -712,7 +744,7 @@
bool fscrypt_add_user_key_auth(userid_t user_id, int serial, const std::string& secret_hex) {
LOG(DEBUG) << "fscrypt_add_user_key_auth " << user_id << " serial=" << serial;
- if (!fscrypt_is_native()) return true;
+ if (!IsFbeEnabled()) return true;
auto auth = authentication_from_hex(secret_hex);
if (!auth) return false;
return fscrypt_rewrap_user_key(user_id, serial, kEmptyAuthentication, *auth);
@@ -720,7 +752,7 @@
bool fscrypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& secret_hex) {
LOG(DEBUG) << "fscrypt_clear_user_key_auth " << user_id << " serial=" << serial;
- if (!fscrypt_is_native()) return true;
+ if (!IsFbeEnabled()) return true;
auto auth = authentication_from_hex(secret_hex);
if (!auth) return false;
return fscrypt_rewrap_user_key(user_id, serial, *auth, kEmptyAuthentication);
@@ -728,7 +760,7 @@
bool fscrypt_fixate_newest_user_key_auth(userid_t user_id) {
LOG(DEBUG) << "fscrypt_fixate_newest_user_key_auth " << user_id;
- if (!fscrypt_is_native()) return true;
+ if (!IsFbeEnabled()) return true;
if (s_ephemeral_users.count(user_id) != 0) return true;
auto const directory_path = get_ce_key_directory_path(user_id);
auto const paths = get_ce_key_paths(directory_path);
@@ -751,7 +783,7 @@
// TODO: rename to 'install' for consistency, and take flags to know which keys to install
bool fscrypt_unlock_user_key(userid_t user_id, int serial, const std::string& secret_hex) {
LOG(DEBUG) << "fscrypt_unlock_user_key " << user_id << " serial=" << serial;
- if (fscrypt_is_native()) {
+ if (IsFbeEnabled()) {
if (s_ce_policies.count(user_id) != 0) {
LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id;
return true;
@@ -762,17 +794,6 @@
LOG(ERROR) << "Couldn't read key for " << user_id;
return false;
}
- } else {
- // When in emulation mode, we just use chmod. However, we also
- // unlock directories when not in emulation mode, to bring devices
- // back into a known-good state.
- if (!emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) ||
- !emulated_unlock(android::vold::BuildDataMiscCePath("", user_id), 01771) ||
- !emulated_unlock(android::vold::BuildDataMediaCePath("", user_id), 0770) ||
- !emulated_unlock(android::vold::BuildDataUserCePath("", user_id), 0771)) {
- LOG(ERROR) << "Failed to unlock user " << user_id;
- return false;
- }
}
return true;
}
@@ -780,19 +801,9 @@
// TODO: rename to 'evict' for consistency
bool fscrypt_lock_user_key(userid_t user_id) {
LOG(DEBUG) << "fscrypt_lock_user_key " << user_id;
- if (fscrypt_is_native()) {
+ if (IsFbeEnabled()) {
return evict_ce_key(user_id);
- } else if (fscrypt_is_emulated()) {
- // When in emulation mode, we just use chmod
- if (!emulated_lock(android::vold::BuildDataSystemCePath(user_id)) ||
- !emulated_lock(android::vold::BuildDataMiscCePath("", user_id)) ||
- !emulated_lock(android::vold::BuildDataMediaCePath("", user_id)) ||
- !emulated_lock(android::vold::BuildDataUserCePath("", user_id))) {
- LOG(ERROR) << "Failed to lock user " << user_id;
- return false;
- }
}
-
return true;
}
@@ -836,11 +847,26 @@
auto profiles_de_path = android::vold::BuildDataProfilesDePath(user_id);
// DE_n key
+ EncryptionPolicy de_policy;
auto system_de_path = android::vold::BuildDataSystemDePath(user_id);
auto misc_de_path = android::vold::BuildDataMiscDePath(volume_uuid, user_id);
auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
+ if (IsFbeEnabled()) {
+ if (volume_uuid.empty()) {
+ if (!lookup_policy(s_de_policies, user_id, &de_policy)) {
+ LOG(ERROR) << "Cannot find DE policy for user " << user_id;
+ return false;
+ }
+ } else {
+ auto misc_de_empty_volume_path = android::vold::BuildDataMiscDePath("", user_id);
+ if (!read_or_create_volkey(misc_de_empty_volume_path, volume_uuid, &de_policy)) {
+ return false;
+ }
+ }
+ }
+
if (volume_uuid.empty()) {
if (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
#if MANAGE_MISC_DIRS
@@ -850,43 +876,49 @@
#endif
if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
- if (!prepare_dir(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
- if (!prepare_dir(vendor_de_path, 0771, AID_ROOT, AID_ROOT)) return false;
+ if (!prepare_dir_with_policy(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM, de_policy))
+ return false;
+ if (!prepare_dir_with_policy(vendor_de_path, 0771, AID_ROOT, AID_ROOT, de_policy))
+ return false;
}
- if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
- if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
-
- if (fscrypt_is_native()) {
- EncryptionPolicy de_policy;
- if (volume_uuid.empty()) {
- if (!lookup_policy(s_de_policies, user_id, &de_policy)) return false;
- if (!EnsurePolicy(de_policy, system_de_path)) return false;
- if (!EnsurePolicy(de_policy, vendor_de_path)) return false;
- } else {
- auto misc_de_empty_volume_path = android::vold::BuildDataMiscDePath("", user_id);
- if (!read_or_create_volkey(misc_de_empty_volume_path, volume_uuid, &de_policy)) {
- return false;
- }
- }
- if (!EnsurePolicy(de_policy, misc_de_path)) return false;
- if (!EnsurePolicy(de_policy, user_de_path)) return false;
- }
+ if (!prepare_dir_with_policy(misc_de_path, 01771, AID_SYSTEM, AID_MISC, de_policy))
+ return false;
+ if (!prepare_dir_with_policy(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM, de_policy))
+ return false;
}
if (flags & android::os::IVold::STORAGE_FLAG_CE) {
// CE_n key
+ EncryptionPolicy ce_policy;
auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
auto misc_ce_path = android::vold::BuildDataMiscCePath(volume_uuid, user_id);
auto vendor_ce_path = android::vold::BuildDataVendorCePath(user_id);
auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
- if (volume_uuid.empty()) {
- if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
- if (!prepare_dir(vendor_ce_path, 0771, AID_ROOT, AID_ROOT)) return false;
+ if (IsFbeEnabled()) {
+ if (volume_uuid.empty()) {
+ if (!lookup_policy(s_ce_policies, user_id, &ce_policy)) {
+ LOG(ERROR) << "Cannot find CE policy for user " << user_id;
+ return false;
+ }
+ } else {
+ auto misc_ce_empty_volume_path = android::vold::BuildDataMiscCePath("", user_id);
+ if (!read_or_create_volkey(misc_ce_empty_volume_path, volume_uuid, &ce_policy)) {
+ return false;
+ }
+ }
}
- if (!prepare_dir(media_ce_path, 02770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
+
+ if (volume_uuid.empty()) {
+ if (!prepare_dir_with_policy(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM, ce_policy))
+ return false;
+ if (!prepare_dir_with_policy(vendor_ce_path, 0771, AID_ROOT, AID_ROOT, ce_policy))
+ return false;
+ }
+ if (!prepare_dir_with_policy(media_ce_path, 02770, AID_MEDIA_RW, AID_MEDIA_RW, ce_policy))
+ return false;
// On devices without sdcardfs (kernel 5.4+), the path permissions aren't fixed
// up automatically; therefore, use a default ACL, to ensure apps with MEDIA_RW
// can keep reading external storage; in particular, this allows app cloning
@@ -895,26 +927,10 @@
if (ret != android::OK) {
return false;
}
-
- if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false;
- if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
-
- if (fscrypt_is_native()) {
- EncryptionPolicy ce_policy;
- if (volume_uuid.empty()) {
- if (!lookup_policy(s_ce_policies, user_id, &ce_policy)) return false;
- if (!EnsurePolicy(ce_policy, system_ce_path)) return false;
- if (!EnsurePolicy(ce_policy, vendor_ce_path)) return false;
- } else {
- auto misc_ce_empty_volume_path = android::vold::BuildDataMiscCePath("", user_id);
- if (!read_or_create_volkey(misc_ce_empty_volume_path, volume_uuid, &ce_policy)) {
- return false;
- }
- }
- if (!EnsurePolicy(ce_policy, media_ce_path)) return false;
- if (!EnsurePolicy(ce_policy, misc_ce_path)) return false;
- if (!EnsurePolicy(ce_policy, user_ce_path)) return false;
- }
+ if (!prepare_dir_with_policy(misc_ce_path, 01771, AID_SYSTEM, AID_MISC, ce_policy))
+ return false;
+ if (!prepare_dir_with_policy(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM, ce_policy))
+ return false;
if (volume_uuid.empty()) {
// Now that credentials have been installed, we can run restorecon
@@ -952,7 +968,7 @@
res &= destroy_dir(system_ce_path);
res &= destroy_dir(vendor_ce_path);
} else {
- if (fscrypt_is_native()) {
+ if (IsFbeEnabled()) {
auto misc_ce_empty_volume_path = android::vold::BuildDataMiscCePath("", user_id);
res &= destroy_volkey(misc_ce_empty_volume_path, volume_uuid);
}
@@ -982,7 +998,7 @@
res &= destroy_dir(system_de_path);
res &= destroy_dir(vendor_de_path);
} else {
- if (fscrypt_is_native()) {
+ if (IsFbeEnabled()) {
auto misc_de_empty_volume_path = android::vold::BuildDataMiscDePath("", user_id);
res &= destroy_volkey(misc_de_empty_volume_path, volume_uuid);
}
diff --git a/KeyBuffer.h b/KeyBuffer.h
index a68311f..4468220 100644
--- a/KeyBuffer.h
+++ b/KeyBuffer.h
@@ -17,32 +17,18 @@
#ifndef ANDROID_VOLD_KEYBUFFER_H
#define ANDROID_VOLD_KEYBUFFER_H
-#include <cstring>
+#include <string.h>
#include <memory>
#include <vector>
namespace android {
namespace vold {
-/**
- * Variant of memset() that should never be optimized away. Borrowed from keymaster code.
- */
-#ifdef __clang__
-#define OPTNONE __attribute__((optnone))
-#else // not __clang__
-#define OPTNONE __attribute__((optimize("O0")))
-#endif // not __clang__
-inline OPTNONE void* memset_s(void* s, int c, size_t n) {
- if (!s) return s;
- return memset(s, c, n);
-}
-#undef OPTNONE
-
// Allocator that delegates useful work to standard one but zeroes data before deallocating.
class ZeroingAllocator : public std::allocator<char> {
public:
void deallocate(pointer p, size_type n) {
- memset_s(p, 0, n);
+ memset_explicit(p, 0, n);
std::allocator<char>::deallocate(p, n);
}
};
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index b4abc27..837bb1a 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -57,16 +57,14 @@
static const char* kCurrentVersion = "1";
static const char* kRmPath = "/system/bin/rm";
static const char* kSecdiscardPath = "/system/bin/secdiscard";
-static const char* kStretch_none = "none";
-static const char* kStretch_nopassword = "nopassword";
static const char* kHashPrefix_secdiscardable = "Android secdiscardable SHA512";
static const char* kHashPrefix_keygen = "Android key wrapping key generation SHA512";
static const char* kFn_encrypted_key = "encrypted_key";
static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";
static const char* kFn_secdiscardable = "secdiscardable";
-static const char* kFn_stretching = "stretching";
static const char* kFn_version = "version";
+// Note: old key directories may contain a file named "stretching".
namespace {
@@ -191,9 +189,13 @@
}
bool readSecdiscardable(const std::string& filename, std::string* hash) {
- std::string secdiscardable;
- if (!readFileToString(filename, &secdiscardable)) return false;
- hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable, hash);
+ if (pathExists(filename)) {
+ std::string secdiscardable;
+ if (!readFileToString(filename, &secdiscardable)) return false;
+ hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable, hash);
+ } else {
+ *hash = "";
+ }
return true;
}
@@ -408,36 +410,9 @@
return true;
}
-static std::string getStretching(const KeyAuthentication& auth) {
- if (auth.usesKeystore()) {
- return kStretch_nopassword;
- } else {
- return kStretch_none;
- }
-}
-
-static bool stretchSecret(const std::string& stretching, const std::string& secret,
- std::string* stretched) {
- if (stretching == kStretch_nopassword) {
- if (!secret.empty()) {
- LOG(WARNING) << "Password present but stretching is nopassword";
- // Continue anyway
- }
- stretched->clear();
- } else if (stretching == kStretch_none) {
- *stretched = secret;
- } else {
- LOG(ERROR) << "Unknown stretching type: " << stretching;
- return false;
- }
- return true;
-}
-
-static bool generateAppId(const KeyAuthentication& auth, const std::string& stretching,
- const std::string& secdiscardable_hash, std::string* appId) {
- std::string stretched;
- if (!stretchSecret(stretching, auth.secret, &stretched)) return false;
- *appId = secdiscardable_hash + stretched;
+static std::string generateAppId(const KeyAuthentication& auth,
+ const std::string& secdiscardable_hash) {
+ std::string appId = secdiscardable_hash + auth.secret;
const std::lock_guard<std::mutex> scope_lock(storage_binding_info.guard);
switch (storage_binding_info.state) {
@@ -445,14 +420,13 @@
storage_binding_info.state = StorageBindingInfo::State::NOT_USED;
break;
case StorageBindingInfo::State::IN_USE:
- appId->append(storage_binding_info.seed.begin(), storage_binding_info.seed.end());
+ appId.append(storage_binding_info.seed.begin(), storage_binding_info.seed.end());
break;
case StorageBindingInfo::State::NOT_USED:
// noop
break;
}
-
- return true;
+ return appId;
}
static void logOpensslError() {
@@ -563,9 +537,12 @@
// Creates a directory at the given path |dir| and stores |key| in it, in such a
// way that it can only be retrieved via Keystore (if no secret is given in
-// |auth|) or with the given secret (if a secret is given in |auth|), and can be
-// securely deleted. If a storage binding seed has been set, then the storage
-// binding seed will be required to retrieve the key as well.
+// |auth|) or with the given secret (if a secret is given in |auth|). In the
+// former case, an attempt is made to make the key securely deletable. In the
+// latter case, secure deletion is expected to be handled at a higher level.
+//
+// If a storage binding seed has been set, then the storage binding seed will be
+// required to retrieve the key as well.
static bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBuffer& key) {
if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), 0700)) == -1) {
PLOG(ERROR) << "key mkdir " << dir;
@@ -573,11 +550,10 @@
}
if (!writeStringToFile(kCurrentVersion, dir + "/" + kFn_version)) return false;
std::string secdiscardable_hash;
- if (!createSecdiscardable(dir + "/" + kFn_secdiscardable, &secdiscardable_hash)) return false;
- std::string stretching = getStretching(auth);
- if (!writeStringToFile(stretching, dir + "/" + kFn_stretching)) return false;
- std::string appId;
- if (!generateAppId(auth, stretching, secdiscardable_hash, &appId)) return false;
+ if (auth.usesKeystore() &&
+ !createSecdiscardable(dir + "/" + kFn_secdiscardable, &secdiscardable_hash))
+ return false;
+ std::string appId = generateAppId(auth, secdiscardable_hash);
std::string encryptedKey;
if (auth.usesKeystore()) {
Keystore keystore;
@@ -629,10 +605,7 @@
}
std::string secdiscardable_hash;
if (!readSecdiscardable(dir + "/" + kFn_secdiscardable, &secdiscardable_hash)) return false;
- std::string stretching;
- if (!readFileToString(dir + "/" + kFn_stretching, &stretching)) return false;
- std::string appId;
- if (!generateAppId(auth, stretching, secdiscardable_hash, &appId)) return false;
+ std::string appId = generateAppId(auth, secdiscardable_hash);
std::string encryptedMessage;
if (!readFileToString(dir + "/" + kFn_encrypted_key, &encryptedMessage)) return false;
if (auth.usesKeystore()) {
@@ -687,8 +660,11 @@
kSecdiscardPath,
"--",
dir + "/" + kFn_encrypted_key,
- dir + "/" + kFn_secdiscardable,
};
+ auto secdiscardable = dir + "/" + kFn_secdiscardable;
+ if (pathExists(secdiscardable)) {
+ secdiscard_cmd.push_back(secdiscardable);
+ }
// Try each thing, even if previous things failed.
for (auto& fn : {kFn_keymaster_key_blob, kFn_keymaster_key_blob_upgraded}) {
diff --git a/Keystore.cpp b/Keystore.cpp
index d993b0d..6040f2d 100644
--- a/Keystore.cpp
+++ b/Keystore.cpp
@@ -48,7 +48,7 @@
}
static void zeroize_vector(std::vector<uint8_t>& vec) {
- memset_s(vec.data(), 0, vec.size());
+ memset_explicit(vec.data(), 0, vec.size());
}
static bool logKeystore2ExceptionIfPresent(::ndk::ScopedAStatus& rc, const std::string& func_name) {
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index 5c9e644..0c32c3b 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -63,6 +63,7 @@
};
static const std::string kDmNameUserdata = "userdata";
+static const std::string kDmNameUserdataZoned = "userdata_zoned";
// The first entry in this table is the default crypto type.
constexpr CryptoType supported_crypto_types[] = {aes_256_xts, adiantum};
@@ -88,12 +89,13 @@
LOG(INFO) << "Not pre-creating userdata encryption device; device already exists";
return;
}
- if (!dm.CreateEmptyDevice(kDmNameUserdata)) {
+
+ if (!dm.CreatePlaceholderDevice(kDmNameUserdata)) {
LOG(ERROR) << "Failed to pre-create userdata metadata encryption device";
}
}
-static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
+static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device, bool needs_encrypt) {
// fs_mgr_do_mount runs fsck. Use setexeccon to run trusted
// partitions in the fsck domain.
if (setexeccon(android::vold::sFsckContext)) {
@@ -102,7 +104,8 @@
}
auto mount_rc = fs_mgr_do_mount(&fstab_default, const_cast<char*>(mount_point),
const_cast<char*>(blk_device), nullptr,
- android::vold::cp_needsCheckpoint(), true);
+ needs_encrypt? false: android::vold::cp_needsCheckpoint(),
+ true);
if (setexeccon(nullptr)) {
PLOG(ERROR) << "Failed to clear setexeccon";
return false;
@@ -115,7 +118,7 @@
return true;
}
-static bool read_key(const std::string& metadata_key_dir, const KeyGeneration& gen,
+static bool read_key(const std::string& metadata_key_dir, const KeyGeneration& gen, bool first_key,
KeyBuffer* key) {
if (metadata_key_dir.empty()) {
LOG(ERROR) << "Failed to get metadata_key_dir";
@@ -127,7 +130,7 @@
if (!MkdirsSync(dir, 0700)) return false;
auto in_dsu = android::base::GetBoolProperty("ro.gsid.image_running", false);
// !pathExists(dir) does not imply there's a factory reset when in DSU mode.
- if (!pathExists(dir) && !in_dsu) {
+ if (!pathExists(dir) && !in_dsu && first_key) {
auto delete_all = android::base::GetBoolProperty(
"ro.crypto.metadata_init_delete_all_keys.enabled", false);
if (delete_all) {
@@ -191,7 +194,7 @@
LOG(ERROR) << "Failed to populate default-key device " << dm_name;
return false;
}
- if (!dm.WaitForDevice(dm_name, 5s, crypto_blkdev)) {
+ if (!dm.WaitForDevice(dm_name, 20s, crypto_blkdev)) {
LOG(ERROR) << "Failed to wait for default-key device " << dm_name;
return false;
}
@@ -238,10 +241,11 @@
bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::string& mount_point,
bool needs_encrypt, bool should_format,
- const std::string& fs_type) {
+ const std::string& fs_type, const std::string& zoned_device) {
LOG(DEBUG) << "fscrypt_mount_metadata_encrypted: " << mount_point
<< " encrypt: " << needs_encrypt << " format: " << should_format << " with "
- << fs_type;
+ << fs_type << " block device: " << blk_device
+ << " and zoned device: " << zoned_device;
auto encrypted_state = android::base::GetProperty("ro.crypto.state", "");
if (encrypted_state != "" && encrypted_state != "encrypted") {
LOG(ERROR) << "fscrypt_mount_metadata_encrypted got unexpected starting state: "
@@ -280,9 +284,13 @@
return false;
}
+ auto default_metadata_key_dir = data_rec->metadata_key_dir;
+ if (!zoned_device.empty()) {
+ default_metadata_key_dir = default_metadata_key_dir + "/default";
+ }
auto gen = needs_encrypt ? makeGen(options) : neverGen();
KeyBuffer key;
- if (!read_key(data_rec->metadata_key_dir, gen, &key)) {
+ if (!read_key(default_metadata_key_dir, gen, true, &key)) {
LOG(ERROR) << "read_key failed in mountFstab";
return false;
}
@@ -295,6 +303,23 @@
return false;
}
+ // create dm-default-key for zoned device
+ std::string crypto_zoned_blkdev;
+ if (!zoned_device.empty()) {
+ auto zoned_metadata_key_dir = data_rec->metadata_key_dir + "/zoned";
+
+ if (!read_key(zoned_metadata_key_dir, gen, false, &key)) {
+ LOG(ERROR) << "read_key failed with zoned device: " << zoned_device;
+ return false;
+ }
+ if (!create_crypto_blk_dev(kDmNameUserdataZoned, zoned_device, key, options,
+ &crypto_zoned_blkdev, &nr_sec)) {
+ LOG(ERROR) << "fscrypt_mount_metadata_encrypted: failed with zoned device: "
+ << zoned_device;
+ return false;
+ }
+ }
+
if (needs_encrypt) {
if (should_format) {
status_t error;
@@ -302,7 +327,7 @@
if (fs_type == "ext4") {
error = ext4::Format(crypto_blkdev, 0, mount_point);
} else if (fs_type == "f2fs") {
- error = f2fs::Format(crypto_blkdev);
+ error = f2fs::Format(crypto_blkdev, crypto_zoned_blkdev);
} else {
LOG(ERROR) << "Unknown filesystem type: " << fs_type;
return false;
@@ -314,6 +339,10 @@
}
LOG(DEBUG) << "Format of " << crypto_blkdev << " for " << mount_point << " succeeded.";
} else {
+ if (!zoned_device.empty()) {
+ LOG(ERROR) << "encrypt_inplace cannot support zoned device; should format it.";
+ return false;
+ }
if (!encrypt_inplace(crypto_blkdev, blk_device, nr_sec)) {
LOG(ERROR) << "encrypt_inplace failed in mountFstab";
return false;
@@ -322,7 +351,7 @@
}
LOG(DEBUG) << "Mounting metadata-encrypted filesystem:" << mount_point;
- mount_via_fs_mgr(mount_point.c_str(), crypto_blkdev.c_str());
+ mount_via_fs_mgr(mount_point.c_str(), crypto_blkdev.c_str(), needs_encrypt);
// Record that there's at least one fstab entry with metadata encryption
if (!android::base::SetProperty("ro.crypto.metadata.enabled", "true")) {
diff --git a/MetadataCrypt.h b/MetadataCrypt.h
index 06131ad..f6d6b8e 100644
--- a/MetadataCrypt.h
+++ b/MetadataCrypt.h
@@ -28,7 +28,8 @@
void defaultkey_precreate_dm_device();
bool fscrypt_mount_metadata_encrypted(const std::string& block_device,
const std::string& mount_point, bool needs_encrypt,
- bool should_format, const std::string& fs_type);
+ bool should_format, const std::string& fs_type,
+ const std::string& zoned_device);
bool defaultkey_volume_keygen(KeyGeneration* gen);
diff --git a/Utils.cpp b/Utils.cpp
index e8049ed..157b839 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -23,6 +23,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -100,13 +101,21 @@
status_t CreateDeviceNode(const std::string& path, dev_t dev) {
std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
- status_t res = 0;
+ auto clearfscreatecon = android::base::make_scope_guard([] { setfscreatecon(nullptr); });
+ auto secontext = std::unique_ptr<char, void (*)(char*)>(nullptr, freecon);
+ char* tmp_secontext;
- char* secontext = nullptr;
- if (sehandle) {
- if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {
- setfscreatecon(secontext);
+ if (selabel_lookup(sehandle, &tmp_secontext, cpath, S_IFBLK) == 0) {
+ secontext.reset(tmp_secontext);
+ if (setfscreatecon(secontext.get()) != 0) {
+ LOG(ERROR) << "Failed to setfscreatecon for device node " << path;
+ return -EINVAL;
}
+ } else if (errno == ENOENT) {
+ LOG(DEBUG) << "No selabel defined for device node " << path;
+ } else {
+ PLOG(ERROR) << "Failed to look up selabel for device node " << path;
+ return -errno;
}
mode_t mode = 0660 | S_IFBLK;
@@ -114,16 +123,10 @@
if (errno != EEXIST) {
PLOG(ERROR) << "Failed to create device node for " << major(dev) << ":" << minor(dev)
<< " at " << path;
- res = -errno;
+ return -errno;
}
}
-
- if (secontext) {
- setfscreatecon(nullptr);
- freecon(secontext);
- }
-
- return res;
+ return OK;
}
status_t DestroyDeviceNode(const std::string& path) {
@@ -449,29 +452,26 @@
unsigned int attrs) {
std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
+ auto clearfscreatecon = android::base::make_scope_guard([] { setfscreatecon(nullptr); });
+ auto secontext = std::unique_ptr<char, void (*)(char*)>(nullptr, freecon);
+ char* tmp_secontext;
- char* secontext = nullptr;
- if (sehandle) {
- if (!selabel_lookup(sehandle, &secontext, cpath, S_IFDIR)) {
- setfscreatecon(secontext);
+ if (selabel_lookup(sehandle, &tmp_secontext, cpath, S_IFDIR) == 0) {
+ secontext.reset(tmp_secontext);
+ if (setfscreatecon(secontext.get()) != 0) {
+ LOG(ERROR) << "Failed to setfscreatecon for directory " << path;
+ return -EINVAL;
}
- }
-
- int res = fs_prepare_dir(cpath, mode, uid, gid);
-
- if (secontext) {
- setfscreatecon(nullptr);
- freecon(secontext);
- }
-
- if (res) return -errno;
- if (attrs) res = SetAttrs(path, attrs);
-
- if (res == 0) {
- return OK;
+ } else if (errno == ENOENT) {
+ LOG(DEBUG) << "No selabel defined for directory " << path;
} else {
+ PLOG(ERROR) << "Failed to look up selabel for directory " << path;
return -errno;
}
+
+ if (fs_prepare_dir(cpath, mode, uid, gid) != 0) return -errno;
+ if (attrs && SetAttrs(path, attrs) != 0) return -errno;
+ return OK;
}
status_t ForceUnmount(const std::string& path) {
@@ -766,7 +766,7 @@
}
pid_t timer_pid = fork();
if (timer_pid == 0) {
- sleep(timeout.count());
+ std::this_thread::sleep_for(timeout);
_exit(ETIMEDOUT);
}
if (timer_pid == -1) {
@@ -1160,14 +1160,6 @@
std::string BuildDataUserCePath(const std::string& volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
- if (volumeUuid.empty() && userId == 0) {
- std::string legacy = StringPrintf("%s/data", data.c_str());
- struct stat sb;
- if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
- /* /data/data is dir, return /data/data for legacy system */
- return legacy;
- }
- }
return StringPrintf("%s/user/%u", data.c_str(), userId);
}
@@ -1187,6 +1179,12 @@
}
}
+// Returns true if |path| exists and is a symlink.
+bool IsSymlink(const std::string& path) {
+ struct stat stbuf;
+ return lstat(path.c_str(), &stbuf) == 0 && S_ISLNK(stbuf.st_mode);
+}
+
// Returns true if |path1| names the same existing file or directory as |path2|.
bool IsSameFile(const std::string& path1, const std::string& path2) {
struct stat stbuf1, stbuf2;
@@ -1450,7 +1448,10 @@
status_t AbortFuseConnections() {
namespace fs = std::filesystem;
- for (const auto& itEntry : fs::directory_iterator("/sys/fs/fuse/connections")) {
+ static constexpr const char* kFuseConnections = "/sys/fs/fuse/connections";
+
+ std::error_code ec;
+ for (const auto& itEntry : fs::directory_iterator(kFuseConnections, ec)) {
std::string fsPath = itEntry.path().string() + "/filesystem";
std::string fs;
@@ -1470,6 +1471,11 @@
}
}
+ if (ec) {
+ LOG(WARNING) << "Failed to iterate through " << kFuseConnections << ": " << ec.message();
+ return -ec.value();
+ }
+
return OK;
}
@@ -1766,13 +1772,23 @@
}
bool IsFuseBpfEnabled() {
- std::string bpf_override = android::base::GetProperty("persist.sys.fuse.bpf.override", "");
- if (bpf_override == "true") {
+ // TODO Once kernel supports flag, trigger off kernel flag unless
+ // ro.fuse.bpf.enabled is explicitly set to false
+ bool enabled;
+ if (base::GetProperty("ro.fuse.bpf.is_running", "") != "")
+ enabled = base::GetBoolProperty("ro.fuse.bpf.is_running", false);
+ else if (base::GetProperty("persist.sys.fuse.bpf.override", "") != "")
+ enabled = base::GetBoolProperty("persist.sys.fuse.bpf.override", false);
+ else
+ enabled = base::GetBoolProperty("ro.fuse.bpf.enabled", false);
+
+ if (enabled) {
+ base::SetProperty("ro.fuse.bpf.is_running", "true");
return true;
- } else if (bpf_override == "false") {
+ } else {
+ base::SetProperty("ro.fuse.bpf.is_running", "false");
return false;
}
- return base::GetBoolProperty("ro.fuse.bpf.enabled", false);
}
} // namespace vold
diff --git a/Utils.h b/Utils.h
index 429669b..fbd0f30 100644
--- a/Utils.h
+++ b/Utils.h
@@ -162,6 +162,8 @@
dev_t GetDevice(const std::string& path);
+bool IsSymlink(const std::string& path);
+
bool IsSameFile(const std::string& path1, const std::string& path2);
status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 5e838f6..601323f 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -182,11 +182,13 @@
return translate(VolumeManager::Instance()->abortFuse());
}
-binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) {
+binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial,
+ int32_t sharesStorageWithUserId) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
- return translate(VolumeManager::Instance()->onUserAdded(userId, userSerial));
+ return translate(
+ VolumeManager::Instance()->onUserAdded(userId, userSerial, sharesStorageWithUserId));
}
binder::Status VoldNativeService::onUserRemoved(int32_t userId) {
@@ -568,22 +570,24 @@
}
binder::Status VoldNativeService::mountFstab(const std::string& blkDevice,
- const std::string& mountPoint) {
+ const std::string& mountPoint,
+ const std::string& zonedDevice) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
- return translateBool(
- fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, false, false, "null"));
+ return translateBool(fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, false, false,
+ "null", zonedDevice));
}
binder::Status VoldNativeService::encryptFstab(const std::string& blkDevice,
const std::string& mountPoint, bool shouldFormat,
- const std::string& fsType) {
+ const std::string& fsType,
+ const std::string& zonedDevice) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
- return translateBool(
- fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, true, shouldFormat, fsType));
+ return translateBool(fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, true, shouldFormat,
+ fsType, zonedDevice));
}
binder::Status VoldNativeService::setStorageBindingSeed(const std::vector<uint8_t>& seed) {
diff --git a/VoldNativeService.h b/VoldNativeService.h
index ac5d852..12a93f5 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -38,7 +38,7 @@
binder::Status shutdown();
binder::Status abortFuse();
- binder::Status onUserAdded(int32_t userId, int32_t userSerial);
+ binder::Status onUserAdded(int32_t userId, int32_t userSerial, int32_t sharesStorageWithUserId);
binder::Status onUserRemoved(int32_t userId);
binder::Status onUserStarted(int32_t userId);
binder::Status onUserStopped(int32_t userId);
@@ -104,9 +104,11 @@
binder::Status fbeEnable();
binder::Status initUser0();
- binder::Status mountFstab(const std::string& blkDevice, const std::string& mountPoint);
+ binder::Status mountFstab(const std::string& blkDevice, const std::string& mountPoint,
+ const std::string& zonedDevice);
binder::Status encryptFstab(const std::string& blkDevice, const std::string& mountPoint,
- bool shouldFormat, const std::string& fsType);
+ bool shouldFormat, const std::string& fsType,
+ const std::string& zonedDevice);
binder::Status setStorageBindingSeed(const std::vector<uint8_t>& seed);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index a7d39c1..e29b920 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -81,6 +81,7 @@
using android::vold::DeleteDirContents;
using android::vold::DeleteDirContentsAndDir;
using android::vold::EnsureDirExists;
+using android::vold::GetFuseMountPathForUser;
using android::vold::IsFilesystemSupported;
using android::vold::IsSdcardfsUsed;
using android::vold::IsVirtioBlkDevice;
@@ -358,7 +359,7 @@
LOG(ERROR) << "Failed to unlink " << keyPath;
success = false;
}
- if (fscrypt_is_native()) {
+ if (IsFbeEnabled()) {
if (!fscrypt_destroy_volume_keys(fsUuid)) {
success = false;
}
@@ -424,10 +425,21 @@
}
}
-int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) {
+userid_t VolumeManager::getSharedStorageUser(userid_t userId) {
+ if (mSharedStorageUser.find(userId) == mSharedStorageUser.end()) {
+ return USER_UNKNOWN;
+ }
+ return mSharedStorageUser.at(userId);
+}
+
+int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber,
+ userid_t sharesStorageWithUserId) {
LOG(INFO) << "onUserAdded: " << userId;
mAddedUsers[userId] = userSerialNumber;
+ if (sharesStorageWithUserId != USER_UNKNOWN) {
+ mSharedStorageUser[userId] = sharesStorageWithUserId;
+ }
return 0;
}
@@ -436,6 +448,7 @@
onUserStopped(userId);
mAddedUsers.erase(userId);
+ mSharedStorageUser.erase(userId);
return 0;
}
@@ -914,6 +927,7 @@
updateVirtualDisk();
mAddedUsers.clear();
mStartedUsers.clear();
+ mSharedStorageUser.clear();
// Abort all FUSE connections to avoid deadlocks if the FUSE daemon was killed
// with FUSE fds open.
diff --git a/VolumeManager.h b/VolumeManager.h
index a8117c9..943a144 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -104,9 +104,11 @@
const std::set<userid_t>& getStartedUsers() const { return mStartedUsers; }
+ userid_t getSharedStorageUser(userid_t userId);
+
int forgetPartition(const std::string& partGuid, const std::string& fsUuid);
- int onUserAdded(userid_t userId, int userSerialNumber);
+ int onUserAdded(userid_t userId, int userSerialNumber, userid_t cloneParentUserId);
int onUserRemoved(userid_t userId);
int onUserStarted(userid_t userId);
int onUserStopped(userid_t userId);
@@ -225,6 +227,8 @@
std::list<std::shared_ptr<android::vold::VolumeBase>> mInternalEmulatedVolumes;
std::unordered_map<userid_t, int> mAddedUsers;
+ // Map of users to a user with which they can share storage (eg clone profiles)
+ std::unordered_map<userid_t, userid_t> mSharedStorageUser;
// This needs to be a regular set because we care about the ordering here;
// user 0 should always go first, because it is responsible for sdcardfs.
std::set<userid_t> mStartedUsers;
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index ea75864..c798959 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -30,7 +30,7 @@
void reset();
void shutdown();
- void onUserAdded(int userId, int userSerial);
+ void onUserAdded(int userId, int userSerial, int sharesStorageWithUserId);
void onUserRemoved(int userId);
void onUserStarted(int userId);
void onUserStopped(int userId);
@@ -80,8 +80,8 @@
void fbeEnable();
void initUser0();
- void mountFstab(@utf8InCpp String blkDevice, @utf8InCpp String mountPoint);
- void encryptFstab(@utf8InCpp String blkDevice, @utf8InCpp String mountPoint, boolean shouldFormat, @utf8InCpp String fsType);
+ void mountFstab(@utf8InCpp String blkDevice, @utf8InCpp String mountPoint, @utf8InCpp String zonedDevice);
+ void encryptFstab(@utf8InCpp String blkDevice, @utf8InCpp String mountPoint, boolean shouldFormat, @utf8InCpp String fsType, @utf8InCpp String zonedDevice);
void setStorageBindingSeed(in byte[] seed);
diff --git a/cryptfs.cpp b/cryptfs.cpp
index ab8f3ec..be8ba3c 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -95,37 +95,6 @@
}
/*
- * If the ro.crypto.fde_sector_size system property is set, append the
- * parameters to make dm-crypt use the specified crypto sector size and round
- * the crypto device size down to a crypto sector boundary.
- */
-static int add_sector_size_param(DmTargetCrypt* target, uint64_t* nr_sec) {
- constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
- char value[PROPERTY_VALUE_MAX];
-
- if (property_get(DM_CRYPT_SECTOR_SIZE, value, "") > 0) {
- unsigned int sector_size;
-
- if (!ParseUint(value, §or_size) || sector_size < 512 || sector_size > 4096 ||
- (sector_size & (sector_size - 1)) != 0) {
- SLOGE("Invalid value for %s: %s. Must be >= 512, <= 4096, and a power of 2\n",
- DM_CRYPT_SECTOR_SIZE, value);
- return -1;
- }
-
- target->SetSectorSize(sector_size);
-
- // With this option, IVs will match the sector numbering, instead
- // of being hard-coded to being based on 512-byte sectors.
- target->SetIvLargeSectors();
-
- // Round the crypto device size down to a crypto sector boundary.
- *nr_sec &= ~((sector_size / 512) - 1);
- }
- return 0;
-}
-
-/*
* Called by vold when it's asked to mount an encrypted external
* storage volume. The incoming partition has no crypto header/footer,
* as any metadata is been stored in a separate, small partition. We
@@ -145,8 +114,25 @@
return -1;
}
- auto& dm = DeviceMapper::Instance();
+ constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
+ char value[PROPERTY_VALUE_MAX];
+ unsigned int sector_size = 0;
+ if (property_get(DM_CRYPT_SECTOR_SIZE, value, "") > 0) {
+ if (!ParseUint(value, §or_size) || sector_size < 512 || sector_size > 4096 ||
+ (sector_size & (sector_size - 1)) != 0) {
+ SLOGE("Invalid value for %s: %s. Must be >= 512, <= 4096, and a power of 2\n",
+ DM_CRYPT_SECTOR_SIZE, value);
+ return -1;
+ }
+ }
+
+ // Round the crypto device size down to a crypto sector boundary.
+ if (sector_size > 0) {
+ nr_sec &= ~((sector_size / 512) - 1);
+ }
+
+ auto& dm = DeviceMapper::Instance();
// We need two ASCII characters to represent each byte, and need space for
// the '\0' terminator.
char key_ascii[MAX_KEY_LEN * 2 + 1];
@@ -156,13 +142,17 @@
key_ascii, 0, real_blkdev, 0);
target->AllowDiscards();
- if (fscrypt_is_native() &&
+ if (IsFbeEnabled() &&
android::base::GetBoolProperty("ro.crypto.allow_encrypt_override", false)) {
target->AllowEncryptOverride();
}
- if (add_sector_size_param(target.get(), &nr_sec)) {
- SLOGE("Error processing dm-crypt sector size param\n");
- return -1;
+
+ // Append the parameters to make dm-crypt use the specified crypto sector size.
+ if (sector_size > 0) {
+ target->SetSectorSize(sector_size);
+ // With this option, IVs will match the sector numbering, instead
+ // of being hard-coded to being based on 512-byte sectors.
+ target->SetIvLargeSectors();
}
DmTable table;
diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp
index 52f6772..293efc4 100644
--- a/fs/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -182,7 +182,7 @@
if (android::base::GetBoolProperty("vold.has_quota", false)) {
options += ",quota";
}
- if (fscrypt_is_native()) {
+ if (IsFbeEnabled()) {
options += ",encrypt";
}
if (needs_casefold) {
diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp
index 55b0823..23363e3 100644
--- a/fs/F2fs.cpp
+++ b/fs/F2fs.cpp
@@ -71,7 +71,7 @@
return res;
}
-status_t Format(const std::string& source) {
+status_t Format(const std::string& source, const std::string& zoned_device) {
std::vector<char const*> cmd;
cmd.emplace_back(kMkfsPath);
@@ -96,6 +96,11 @@
cmd.emplace_back("-C");
cmd.emplace_back("utf8");
}
+ if (!zoned_device.empty()) {
+ cmd.emplace_back("-c");
+ cmd.emplace_back(zoned_device.c_str());
+ cmd.emplace_back("-m");
+ }
cmd.emplace_back(source.c_str());
return logwrap_fork_execvp(cmd.size(), cmd.data(), nullptr, false, LOG_KLOG,
false, nullptr);
diff --git a/fs/F2fs.h b/fs/F2fs.h
index f710212..cdad581 100644
--- a/fs/F2fs.h
+++ b/fs/F2fs.h
@@ -29,7 +29,7 @@
status_t Check(const std::string& source);
status_t Mount(const std::string& source, const std::string& target);
-status_t Format(const std::string& source);
+status_t Format(const std::string& source, const std::string& zoned_device = "");
} // namespace f2fs
} // namespace vold
diff --git a/main.cpp b/main.cpp
index b07ee68..078ee14 100644
--- a/main.cpp
+++ b/main.cpp
@@ -82,9 +82,11 @@
parse_args(argc, argv);
sehandle = selinux_android_file_context_handle();
- if (sehandle) {
- selinux_android_set_sehandle(sehandle);
+ if (!sehandle) {
+ LOG(ERROR) << "Failed to get SELinux file contexts handle";
+ exit(1);
}
+ selinux_android_set_sehandle(sehandle);
mkdir("/dev/block/vold", 0755);
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 270d097..270dcd4 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -18,6 +18,7 @@
#include "AppFuseUtil.h"
#include "Utils.h"
+#include "VolumeBase.h"
#include "VolumeManager.h"
#include <android-base/logging.h>
@@ -49,7 +50,6 @@
mRawPath = rawPath;
mLabel = "emulated";
mFuseMounted = false;
- mFuseBpfEnabled = IsFuseBpfEnabled();
mUseSdcardFs = IsSdcardfsUsed();
mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
}
@@ -61,14 +61,13 @@
mRawPath = rawPath;
mLabel = fsUuid;
mFuseMounted = false;
- mFuseBpfEnabled = IsFuseBpfEnabled();
mUseSdcardFs = IsSdcardfsUsed();
mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
}
EmulatedVolume::~EmulatedVolume() {}
-std::string EmulatedVolume::getLabel() {
+std::string EmulatedVolume::getLabel() const {
// We could have migrated storage to an adopted private volume, so always
// call primary storage "emulated" to avoid media rescans.
if (getMountFlags() & MountFlags::kPrimary) {
@@ -91,6 +90,29 @@
return OK;
}
+// Bind mounts the volume 'volume' onto this volume.
+status_t EmulatedVolume::bindMountVolume(const EmulatedVolume& volume,
+ std::list<std::string>& pathsToUnmount) {
+ int myUserId = getMountUserId();
+ int volumeUserId = volume.getMountUserId();
+ std::string label = volume.getLabel();
+
+ // eg /mnt/user/10/emulated/10
+ std::string srcUserPath = GetFuseMountPathForUser(volumeUserId, label);
+ std::string srcPath = StringPrintf("%s/%d", srcUserPath.c_str(), volumeUserId);
+ // eg /mnt/user/0/emulated/10
+ std::string dstUserPath = GetFuseMountPathForUser(myUserId, label);
+ std::string dstPath = StringPrintf("%s/%d", dstUserPath.c_str(), volumeUserId);
+
+ auto status = doFuseBindMount(srcPath, dstPath, pathsToUnmount);
+ if (status == OK) {
+ // Store the mount path, so we can unmount it when this volume goes away
+ mSharedStorageMountPath = dstPath;
+ }
+
+ return status;
+}
+
status_t EmulatedVolume::mountFuseBindMounts() {
std::string androidSource;
std::string label = getLabel();
@@ -152,6 +174,59 @@
}
}
+ // For users that share their volume with another user (eg a clone
+ // profile), the current mount setup can cause page cache inconsistency
+ // issues. Let's say this is user 10, and the user it shares storage with
+ // is user 0.
+ // Then:
+ // * The FUSE daemon for user 0 serves /mnt/user/0
+ // * The FUSE daemon for user 10 serves /mnt/user/10
+ // The emulated volume for user 10 would be located at two paths:
+ // /mnt/user/0/emulated/10
+ // /mnt/user/10/emulated/10
+ // Since these paths refer to the same files but are served by different FUSE
+ // daemons, this can result in page cache inconsistency issues. To prevent this,
+ // bind mount the relevant paths for the involved users:
+ // 1. /mnt/user/10/emulated/10 =B=> /mnt/user/0/emulated/10
+ // 2. /mnt/user/0/emulated/0 =B=> /mnt/user/10/emulated/0
+ //
+ // This will ensure that any access to the volume for a specific user always
+ // goes through a single FUSE daemon.
+ userid_t sharedStorageUserId = VolumeManager::Instance()->getSharedStorageUser(userId);
+ if (sharedStorageUserId != USER_UNKNOWN) {
+ auto filter_fn = [&](const VolumeBase& vol) {
+ if (vol.getState() != VolumeBase::State::kMounted) {
+ // The volume must be mounted
+ return false;
+ }
+ if (vol.getType() != VolumeBase::Type::kEmulated) {
+ return false;
+ }
+ if (vol.getMountUserId() != sharedStorageUserId) {
+ return false;
+ }
+ if ((vol.getMountFlags() & MountFlags::kPrimary) == 0) {
+ // We only care about the primary emulated volume, so not a private
+ // volume with an emulated volume stacked on top.
+ return false;
+ }
+ return true;
+ };
+ auto vol = VolumeManager::Instance()->findVolumeWithFilter(filter_fn);
+ if (vol != nullptr) {
+ auto sharedVol = static_cast<EmulatedVolume*>(vol.get());
+ // Bind mount this volume in the other user's primary volume
+ status = sharedVol->bindMountVolume(*this, pathsToUnmount);
+ if (status != OK) {
+ return status;
+ }
+ // And vice-versa
+ status = bindMountVolume(*sharedVol, pathsToUnmount);
+ if (status != OK) {
+ return status;
+ }
+ }
+ }
unmount_guard.Disable();
return OK;
}
@@ -160,6 +235,14 @@
std::string label = getLabel();
int userId = getMountUserId();
+ if (!mSharedStorageMountPath.empty()) {
+ LOG(INFO) << "Unmounting " << mSharedStorageMountPath;
+ auto status = UnmountTree(mSharedStorageMountPath);
+ if (status != OK) {
+ LOG(ERROR) << "Failed to unmount " << mSharedStorageMountPath;
+ }
+ mSharedStorageMountPath = "";
+ }
if (mUseSdcardFs || mAppDataIsolationEnabled) {
std::string installerTarget(
StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
@@ -361,7 +444,7 @@
}
}
- if (!mFuseBpfEnabled) {
+ if (!IsFuseBpfEnabled()) {
// Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
res = mountFuseBindMounts();
if (res != OK) {
@@ -420,7 +503,7 @@
if (mFuseMounted) {
std::string label = getLabel();
- if (!mFuseBpfEnabled) {
+ if (!IsFuseBpfEnabled()) {
// Ignoring unmount return status because we do want to try to
// unmount the rest cleanly.
unmountFuseBindMounts();
diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h
index 0f39fbd..0389ea7 100644
--- a/model/EmulatedVolume.h
+++ b/model/EmulatedVolume.h
@@ -52,7 +52,9 @@
status_t mountFuseBindMounts();
status_t unmountFuseBindMounts();
- std::string getLabel();
+ status_t bindMountVolume(const EmulatedVolume& vol, std::list<std::string>& pathsToUnmount);
+
+ std::string getLabel() const;
std::string mRawPath;
std::string mLabel;
@@ -64,15 +66,15 @@
/* Whether we mounted FUSE for this volume */
bool mFuseMounted;
- /* Whether the FUSE BPF feature is enabled */
- bool mFuseBpfEnabled;
-
/* Whether to use sdcardfs for this volume */
bool mUseSdcardFs;
/* Whether to use app data isolation is enabled tor this volume */
bool mAppDataIsolationEnabled;
+ /* Location of bind mount for another profile that shares storage with us */
+ std::string mSharedStorageMountPath = "";
+
DISALLOW_COPY_AND_ASSIGN(EmulatedVolume);
};
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index bf54c95..b13a0ea 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -308,12 +308,14 @@
}
status_t PublicVolume::doFormat(const std::string& fsType) {
- bool useVfat = vfat::IsSupported();
- bool useExfat = exfat::IsSupported();
+ bool isVfatSup = vfat::IsSupported();
+ bool isExfatSup = exfat::IsSupported();
status_t res = OK;
- // Resolve the target filesystem type
- if (fsType == "auto" && useVfat && useExfat) {
+ enum { NONE, VFAT, EXFAT } fsPick = NONE;
+
+ // Resolve auto requests
+ if (fsType == "auto" && isVfatSup && isExfatSup) {
uint64_t size = 0;
res = GetBlockDevSize(mDevPath, &size);
@@ -324,29 +326,34 @@
// If both vfat & exfat are supported use exfat for SDXC (>~32GiB) cards
if (size > 32896LL * 1024 * 1024) {
- useVfat = false;
+ fsPick = EXFAT;
} else {
- useExfat = false;
+ fsPick = VFAT;
}
- } else if (fsType == "vfat") {
- useExfat = false;
- } else if (fsType == "exfat") {
- useVfat = false;
+ } else if (fsType == "auto" && isExfatSup) {
+ fsPick = EXFAT;
+ } else if (fsType == "auto" && isVfatSup) {
+ fsPick = VFAT;
}
- if (!useVfat && !useExfat) {
- LOG(ERROR) << "Unsupported filesystem " << fsType;
- return -EINVAL;
+ // Resolve explicit requests
+ if (fsType == "vfat" && isVfatSup) {
+ fsPick = VFAT;
+ } else if (fsType == "exfat" && isExfatSup) {
+ fsPick = EXFAT;
}
if (WipeBlockDevice(mDevPath) != OK) {
LOG(WARNING) << getId() << " failed to wipe";
}
- if (useVfat) {
+ if (fsPick == VFAT) {
res = vfat::Format(mDevPath, 0);
- } else if (useExfat) {
+ } else if (fsPick == EXFAT) {
res = exfat::Format(mDevPath);
+ } else {
+ LOG(ERROR) << "Unsupported filesystem " << fsType;
+ return -EINVAL;
}
if (res != OK) {
diff --git a/secdiscard.cpp b/secdiscard.cpp
index b91f321..490e5a1 100644
--- a/secdiscard.cpp
+++ b/secdiscard.cpp
@@ -97,7 +97,7 @@
TEMP_FAILURE_RETRY(open(target.c_str(), O_WRONLY | O_CLOEXEC, 0)));
if (fd == -1) {
LOG(ERROR) << "Secure discard open failed for: " << target;
- return 0;
+ continue;
}
__u32 set = 1;
ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
diff --git a/tests/Android.bp b/tests/Android.bp
index 3c4f07b..da63d95 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -16,3 +16,27 @@
static_libs: ["libvold"],
shared_libs: ["libbinder"]
}
+
+cc_fuzz {
+ name: "vold_native_service_fuzzer",
+ defaults: [
+ "vold_default_flags",
+ "vold_default_libs",
+ "keystore2_use_latest_aidl_ndk_shared",
+ "service_fuzzer_defaults",
+ ],
+ static_libs: [
+ "libvold",
+ "android.security.maintenance-ndk",
+ "libkeymint_support",
+ ],
+ header_libs: ["libvold_headers"],
+ srcs: [
+ "VoldFuzzer.cpp",
+ ],
+ fuzz_config: {
+ cc: [
+ "maco@google.com",
+ ],
+ }
+}
diff --git a/tests/VoldFuzzer.cpp b/tests/VoldFuzzer.cpp
new file mode 100644
index 0000000..630a785
--- /dev/null
+++ b/tests/VoldFuzzer.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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 <android-base/logging.h>
+#include <fuzzbinder/libbinder_driver.h>
+
+#include "VoldNativeService.h"
+#include "sehandle.h"
+
+using ::android::fuzzService;
+using ::android::sp;
+
+struct selabel_handle* sehandle;
+
+extern "C" int LLVMFuzzerInitialize(int argc, char argv) {
+ sehandle = selinux_android_file_context_handle();
+ if (!sehandle) {
+ LOG(ERROR) << "Failed to get SELinux file contexts handle in voldFuzzer!";
+ exit(1);
+ }
+ selinux_android_set_sehandle(sehandle);
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto voldService = sp<android::vold::VoldNativeService>::make();
+ fuzzService(voldService, FuzzedDataProvider(data, size));
+ return 0;
+}
\ No newline at end of file
diff --git a/vdc.cpp b/vdc.cpp
index 740e246..b63abbb 100644
--- a/vdc.cpp
+++ b/vdc.cpp
@@ -124,14 +124,14 @@
checkStatus(args, vold->reset());
} else if (args[0] == "cryptfs" && args[1] == "bindkeys") {
bindkeys(args, vold);
- } else if (args[0] == "cryptfs" && args[1] == "mountFstab" && args.size() == 4) {
- checkStatus(args, vold->mountFstab(args[2], args[3]));
- } else if (args[0] == "cryptfs" && args[1] == "encryptFstab" && args.size() == 6) {
+ } else if (args[0] == "cryptfs" && args[1] == "mountFstab" && args.size() == 5) {
+ checkStatus(args, vold->mountFstab(args[2], args[3], args[4]));
+ } else if (args[0] == "cryptfs" && args[1] == "encryptFstab" && args.size() == 7) {
auto shouldFormat = android::base::ParseBool(args[4]);
if (shouldFormat == android::base::ParseBoolResult::kError) exit(EINVAL);
checkStatus(args, vold->encryptFstab(args[2], args[3],
shouldFormat == android::base::ParseBoolResult::kTrue,
- args[5]));
+ args[5], args[6]));
} else if (args[0] == "checkpoint" && args[1] == "supportsCheckpoint" && args.size() == 2) {
bool supported = false;
checkStatus(args, vold->supportsCheckpoint(&supported));
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
index 94d7f15..60e82f5 100644
--- a/vold_prepare_subdirs.cpp
+++ b/vold_prepare_subdirs.cpp
@@ -58,32 +58,32 @@
const std::string& path, uid_t user_id) {
auto clearfscreatecon = android::base::make_scope_guard([] { setfscreatecon(nullptr); });
auto secontext = std::unique_ptr<char, void (*)(char*)>(nullptr, freecon);
- if (sehandle) {
- char* tmp_secontext;
+ char* tmp_secontext;
- if (selabel_lookup(sehandle, &tmp_secontext, path.c_str(), S_IFDIR) == 0) {
- secontext.reset(tmp_secontext);
-
- if (user_id != (uid_t)-1) {
- if (selinux_android_context_with_level(secontext.get(), &tmp_secontext, user_id,
- (uid_t)-1) != 0) {
- PLOG(ERROR) << "Unable to create context with level for: " << path;
- return false;
- }
- secontext.reset(tmp_secontext); // Free the context
+ if (selabel_lookup(sehandle, &tmp_secontext, path.c_str(), S_IFDIR) == 0) {
+ secontext.reset(tmp_secontext);
+ if (user_id != (uid_t)-1) {
+ if (selinux_android_context_with_level(secontext.get(), &tmp_secontext, user_id,
+ (uid_t)-1) != 0) {
+ PLOG(ERROR) << "Unable to create context with level for: " << path;
+ return false;
}
+ secontext.reset(tmp_secontext);
}
+ if (setfscreatecon(secontext.get()) != 0) {
+ LOG(ERROR) << "Failed to setfscreatecon for directory " << path;
+ return false;
+ }
+ } else if (errno == ENOENT) {
+ LOG(DEBUG) << "No selabel defined for directory " << path;
+ } else {
+ PLOG(ERROR) << "Failed to look up selabel for directory " << path;
+ return false;
}
LOG(DEBUG) << "Setting up mode " << std::oct << mode << std::dec << " uid " << uid << " gid "
<< gid << " context " << (secontext ? secontext.get() : "null")
<< " on path: " << path;
- if (secontext) {
- if (setfscreatecon(secontext.get()) != 0) {
- PLOG(ERROR) << "Unable to setfscreatecon for: " << path;
- return false;
- }
- }
if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) {
return false;
}
@@ -114,6 +114,9 @@
static bool rmrf_contents(const std::string& path) {
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(path.c_str()), closedir);
if (!dirp) {
+ if (errno == ENOENT) {
+ return true;
+ }
PLOG(ERROR) << "Unable to open directory: " << path;
return false;
}
@@ -165,6 +168,10 @@
static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int flags) {
struct selabel_handle* sehandle = selinux_android_file_context_handle();
+ if (!sehandle) {
+ LOG(ERROR) << "Failed to get SELinux file contexts handle";
+ return false;
+ }
if (flags & android::os::IVold::STORAGE_FLAG_DE) {
auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);