Add and use prepare_dir_with_policy() helper function
Having prepare_dir() and EnsurePolicy() be separate operations is
error-prone; it lengthens the window of time that files could
accidentally be created in new directories before they are encrypted,
and it makes it easier to accidentally never encrypt a directory.
To partially address this, add a function prepare_dir_with_policy() that
combines the two steps, and use it everywhere possible. This function
is now the only place in vold that calls EnsurePolicy().
As a follow-up change, we could go a bit further and make this helper
function create the directory under a temporary name and move it into
place already-encrypted. This change just focuses on getting the helper
function in place, without changing the behavior too much.
Change-Id: I98ab345df235120db6727f7dbe0da6a8b6ef2579
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index 7a5178d..e253aa9 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -314,6 +314,9 @@
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 (android::vold::PrepareDir(dir, mode, uid, gid, 0) != 0) {
@@ -323,6 +326,14 @@
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 (fscrypt_is_native() && !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) {
@@ -372,7 +383,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;
@@ -479,18 +489,29 @@
}
static bool prepare_special_dirs() {
- // Create /data/user/0 and its bind-mount alias /data/data. 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.
- //
+ // 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;
- if (!prepare_dir(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM)) 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;
@@ -503,9 +524,13 @@
//
// We must tolerate /data/media/obb being unencrypted if it already exists
// on-disk, since it used to be unencrypted (b/64566063).
- bool encrypt_obb = !android::vold::pathExists(media_obb_dir) && fscrypt_is_native();
- if (!prepare_dir(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
- if (encrypt_obb && !EnsurePolicy(s_device_policy, media_obb_dir)) return false;
+ 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;
}
@@ -514,25 +539,23 @@
bool fscrypt_init_user0() {
LOG(DEBUG) << "fscrypt_init_user0";
- if (!prepare_special_dirs()) return false;
-
if (fscrypt_is_native()) {
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;
if (!android::vold::pathExists(get_de_key_path(0))) {
if (!create_and_install_user_keys(0, false)) return false;
- // Since /data/user/0 was created already, and directory creation
- // and encryption should always happen together, encrypt
- // /data/user/0 right away without waiting for the request to
- // prepare user 0's CE storage.
- if (!EnsurePolicy(s_ce_policies[0], data_user_0_dir)) return false;
}
// TODO: switch to loading only DE_0 here once framework makes
// explicit calls to install DE keys for secondary users
if (!load_all_de_keys()) return false;
}
- // We only prepare DE storage here, since user 0's CE key won't be 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)) {
@@ -883,11 +906,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 (fscrypt_is_native()) {
+ 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
@@ -897,43 +935,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 (fscrypt_is_native()) {
+ 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
@@ -942,26 +986,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