[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, &sector_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, &sector_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);