Merge "Switch to new project ID constants."
diff --git a/Android.bp b/Android.bp
index 676c958..c2f8936 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,6 +145,7 @@
"model/PublicVolume.cpp",
"model/StubVolume.cpp",
"model/VolumeBase.cpp",
+ "model/VolumeEncryption.cpp",
],
product_variables: {
arc: {
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index 8682bdc..276444c 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -66,7 +66,7 @@
using android::vold::IsFilesystemSupported;
using android::vold::kEmptyAuthentication;
using android::vold::KeyBuffer;
-using android::vold::makeGen;
+using android::vold::KeyGeneration;
using android::vold::retrieveKey;
using android::vold::retrieveOrGenerateKey;
using android::vold::SetQuotaInherit;
@@ -98,6 +98,11 @@
} // namespace
+// Returns KeyGeneration suitable for key as described in EncryptionOptions
+static KeyGeneration makeGen(const EncryptionOptions& options) {
+ 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);
}
@@ -230,13 +235,18 @@
// Retrieve the options to use for encryption policies on adoptable storage.
static bool get_volume_file_encryption_options(EncryptionOptions* options) {
- auto contents_mode =
- android::base::GetProperty("ro.crypto.volume.contents_mode", "aes-256-xts");
+ // If we give the empty string, libfscrypt will use the default (currently XTS)
+ auto contents_mode = android::base::GetProperty("ro.crypto.volume.contents_mode", "");
+ // HEH as default was always a mistake. Use the libfscrypt default (CTS)
+ // for devices launching on versions above Android 10.
+ auto first_api_level = GetFirstApiLevel();
+ constexpr uint64_t pre_gki_level = 29;
auto filenames_mode =
- android::base::GetProperty("ro.crypto.volume.filenames_mode", "aes-256-heh");
+ android::base::GetProperty("ro.crypto.volume.filenames_mode",
+ first_api_level > pre_gki_level ? "" : "aes-256-heh");
auto options_string = android::base::GetProperty("ro.crypto.volume.options",
- contents_mode + ":" + filenames_mode + ":v1");
- if (!ParseOptions(options_string, options)) {
+ contents_mode + ":" + filenames_mode);
+ if (!ParseOptionsForApiLevel(first_api_level, options_string, options)) {
LOG(ERROR) << "Unable to parse volume encryption options: " << options_string;
return false;
}
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index a7582c2..951536b 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -122,7 +122,8 @@
return false;
}
const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data());
- paramBuilder.Authorization(km::TAG_USER_SECURE_ID, at->user_id);
+ auto user_id = at->user_id; // Make a copy because at->user_id is unaligned.
+ paramBuilder.Authorization(km::TAG_USER_SECURE_ID, user_id);
paramBuilder.Authorization(km::TAG_USER_AUTH_TYPE, km::HardwareAuthenticatorType::PASSWORD);
paramBuilder.Authorization(km::TAG_AUTH_TIMEOUT, AUTH_TIMEOUT);
}
diff --git a/KeyUtil.cpp b/KeyUtil.cpp
index 2e810ff..6200c42 100644
--- a/KeyUtil.cpp
+++ b/KeyUtil.cpp
@@ -36,14 +36,6 @@
namespace android {
namespace vold {
-const KeyGeneration makeGen(const EncryptionOptions& options) {
- return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
-}
-
-const KeyGeneration makeGen(const CryptoType& crypto) {
- return KeyGeneration{crypto.get_keysize(), true, false};
-}
-
const KeyGeneration neverGen() {
return KeyGeneration{0, false, false};
}
diff --git a/KeyUtil.h b/KeyUtil.h
index 16aaf99..dcb1dc7 100644
--- a/KeyUtil.h
+++ b/KeyUtil.h
@@ -17,7 +17,6 @@
#ifndef ANDROID_VOLD_KEYUTIL_H
#define ANDROID_VOLD_KEYUTIL_H
-#include "CryptoType.h"
#include "KeyBuffer.h"
#include "KeyStorage.h"
@@ -41,12 +40,6 @@
// Generate a key as specified in KeyGeneration
bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key);
-// Returns KeyGeneration suitable for key as described in EncryptionOptions
-const KeyGeneration makeGen(const EncryptionOptions& options);
-
-// Returns KeyGeneration suitable for key as described in CryptoType
-const KeyGeneration makeGen(const CryptoType& crypto);
-
// Returns a key with allow_gen false so generateStorageKey returns false;
// this is used to indicate to retrieveOrGenerateKey that a key should not
// be generated.
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index 938ba34..7891bee 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -30,6 +30,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <fs_mgr.h>
@@ -54,11 +55,20 @@
using android::vold::KeyBuffer;
using namespace android::dm;
+// Parsed from metadata options
+struct CryptoOptions {
+ struct CryptoType cipher = invalid_crypto_type;
+ bool is_legacy = false;
+ bool set_dun = true; // Non-legacy driver always sets DUN
+ bool use_hw_wrapped_key = false;
+};
+
static const std::string kDmNameUserdata = "userdata";
static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";
+// The first entry in this table is the default crypto type.
constexpr CryptoType supported_crypto_types[] = {aes_256_xts, adiantum};
static_assert(validateSupportedCryptoTypes(64, supported_crypto_types,
@@ -68,12 +78,14 @@
constexpr CryptoType legacy_aes_256_xts =
CryptoType().set_config_name("aes-256-xts").set_kernel_name("AES-256-XTS").set_keysize(64);
-constexpr CryptoType legacy_crypto_types[] = {legacy_aes_256_xts};
-
-static_assert(validateSupportedCryptoTypes(64, legacy_crypto_types,
- array_length(legacy_crypto_types)),
+static_assert(isValidCryptoType(64, legacy_aes_256_xts),
"We have a CryptoType which was incompletely constructed.");
+// Returns KeyGeneration suitable for key as described in CryptoOptions
+const KeyGeneration makeGen(const CryptoOptions& options) {
+ return KeyGeneration{options.cipher.get_keysize(), true, options.use_hw_wrapped_key};
+}
+
static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
// We're about to mount data not verified by verified boot. Tell Keymaster that early boot has
// ended.
@@ -173,21 +185,38 @@
}
static bool create_crypto_blk_dev(const std::string& dm_name, const std::string& blk_device,
- bool is_legacy, const std::string& cipher, bool set_dun,
- const KeyBuffer& key, std::string* crypto_blkdev) {
- uint64_t nr_sec;
- if (!get_number_of_sectors(blk_device, &nr_sec)) return false;
+ const KeyBuffer& key, const CryptoOptions& options,
+ std::string* crypto_blkdev, uint64_t* nr_sec) {
+ if (!get_number_of_sectors(blk_device, nr_sec)) return false;
+ // TODO(paulcrowley): don't hardcode that DmTargetDefaultKey uses 4096-byte
+ // sectors
+ *nr_sec &= ~7;
+
+ KeyBuffer module_key;
+ if (options.use_hw_wrapped_key) {
+ if (!exportWrappedStorageKey(key, &module_key)) {
+ LOG(ERROR) << "Failed to get ephemeral wrapped key";
+ return false;
+ }
+ } else {
+ module_key = key;
+ }
KeyBuffer hex_key_buffer;
- if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) {
+ if (android::vold::StrToHex(module_key, hex_key_buffer) != android::OK) {
LOG(ERROR) << "Failed to turn key to hex";
return false;
}
std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size());
+ auto target = std::make_unique<DmTargetDefaultKey>(0, *nr_sec, options.cipher.get_kernel_name(),
+ hex_key, blk_device, 0);
+ if (options.is_legacy) target->SetIsLegacy();
+ if (options.set_dun) target->SetSetDun();
+ if (options.use_hw_wrapped_key) target->SetWrappedKeyV0();
+
DmTable table;
- table.Emplace<DmTargetDefaultKey>(0, nr_sec, cipher, hex_key, blk_device, 0, is_legacy,
- set_dun);
+ table.AddTarget(std::move(target));
auto& dm = DeviceMapper::Instance();
for (int i = 0;; i++) {
@@ -209,25 +238,38 @@
return true;
}
-static const CryptoType& lookup_cipher_in_table(const CryptoType table[], int table_len,
- const std::string& cipher_name) {
- if (cipher_name.empty()) return table[0];
- for (int i = 0; i < table_len; i++) {
- if (cipher_name == table[i].get_config_name()) {
- return table[i];
+static const CryptoType& lookup_cipher(const std::string& cipher_name) {
+ if (cipher_name.empty()) return supported_crypto_types[0];
+ for (size_t i = 0; i < array_length(supported_crypto_types); i++) {
+ if (cipher_name == supported_crypto_types[i].get_config_name()) {
+ return supported_crypto_types[i];
}
}
return invalid_crypto_type;
}
-static const CryptoType& lookup_cipher(const std::string& cipher_name, bool is_legacy) {
- if (is_legacy) {
- return lookup_cipher_in_table(legacy_crypto_types, array_length(legacy_crypto_types),
- cipher_name);
- } else {
- return lookup_cipher_in_table(supported_crypto_types, array_length(supported_crypto_types),
- cipher_name);
+static bool parse_options(const std::string& options_string, CryptoOptions* options) {
+ auto parts = android::base::Split(options_string, ":");
+ if (parts.size() < 1 || parts.size() > 2) {
+ LOG(ERROR) << "Invalid metadata encryption option: " << options_string;
+ return false;
}
+ std::string cipher_name = parts[0];
+ options->cipher = lookup_cipher(cipher_name);
+ if (options->cipher.get_kernel_name() == nullptr) {
+ LOG(ERROR) << "No metadata cipher named " << cipher_name << " found";
+ return false;
+ }
+
+ if (parts.size() == 2) {
+ if (parts[1] == "wrappedkey_v0") {
+ options->use_hw_wrapped_key = true;
+ } else {
+ LOG(ERROR) << "Invalid metadata encryption flag: " << parts[1];
+ return false;
+ }
+ }
+ return true;
}
bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::string& mount_point,
@@ -253,33 +295,36 @@
bool is_legacy;
if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false;
- // Non-legacy driver always sets DUN
- bool set_dun = !is_legacy || android::base::GetBoolProperty("ro.crypto.set_dun", false);
- if (!set_dun && data_rec->fs_mgr_flags.checkpoint_blk) {
- LOG(ERROR) << "Block checkpoints and metadata encryption require ro.crypto.set_dun option";
- return false;
+ CryptoOptions options;
+ if (is_legacy) {
+ if (!data_rec->metadata_encryption.empty()) {
+ LOG(ERROR) << "metadata_encryption options cannot be set in legacy mode";
+ return false;
+ }
+ options.cipher = legacy_aes_256_xts;
+ options.is_legacy = true;
+ options.set_dun = android::base::GetBoolProperty("ro.crypto.set_dun", false);
+ if (!options.set_dun && data_rec->fs_mgr_flags.checkpoint_blk) {
+ LOG(ERROR)
+ << "Block checkpoints and metadata encryption require ro.crypto.set_dun option";
+ return false;
+ }
+ } else {
+ if (!parse_options(data_rec->metadata_encryption, &options)) return false;
}
- auto cipher = lookup_cipher(data_rec->metadata_cipher, is_legacy);
- if (cipher.get_kernel_name() == nullptr) {
- LOG(ERROR) << "No metadata cipher named " << data_rec->metadata_cipher
- << " found, is_legacy=" << is_legacy;
- return false;
- }
-
- auto gen = needs_encrypt ? makeGen(cipher) : neverGen();
+ auto gen = needs_encrypt ? makeGen(options) : neverGen();
KeyBuffer key;
if (!read_key(data_rec->metadata_key_dir, gen, &key)) return false;
std::string crypto_blkdev;
- if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, is_legacy,
- cipher.get_kernel_name(), set_dun, key, &crypto_blkdev))
+ uint64_t nr_sec;
+ if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, key, options, &crypto_blkdev,
+ &nr_sec))
return false;
// FIXME handle the corrupt case
if (needs_encrypt) {
- uint64_t nr_sec;
- if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec;
off64_t size_already_done = 0;
auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec,
@@ -300,5 +345,27 @@
return true;
}
+static bool get_volume_options(CryptoOptions* options) {
+ return parse_options(android::base::GetProperty("ro.crypto.volume.metadata.encryption", ""),
+ options);
+}
+
+bool defaultkey_volume_keygen(KeyGeneration* gen) {
+ CryptoOptions options;
+ if (!get_volume_options(&options)) return false;
+ *gen = makeGen(options);
+ return true;
+}
+
+bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const KeyBuffer& key, std::string* out_crypto_blkdev) {
+ LOG(DEBUG) << "defaultkey_setup_ext_volume: " << label << " " << blk_device;
+
+ CryptoOptions options;
+ if (!get_volume_options(&options)) return false;
+ uint64_t nr_sec;
+ return create_crypto_blk_dev(label, blk_device, key, options, out_crypto_blkdev, &nr_sec);
+}
+
} // namespace vold
} // namespace android
diff --git a/MetadataCrypt.h b/MetadataCrypt.h
index a1ce7d8..dc68e7c 100644
--- a/MetadataCrypt.h
+++ b/MetadataCrypt.h
@@ -19,12 +19,21 @@
#include <string>
+#include "KeyBuffer.h"
+#include "KeyUtil.h"
+
namespace android {
namespace vold {
bool fscrypt_mount_metadata_encrypted(const std::string& block_device,
const std::string& mount_point, bool needs_encrypt);
+bool defaultkey_volume_keygen(KeyGeneration* gen);
+
+bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const android::vold::KeyBuffer& key,
+ std::string* out_crypto_blkdev);
+
} // namespace vold
} // namespace android
#endif
diff --git a/Process.cpp b/Process.cpp
index 3d8e3d7..277d6a3 100644
--- a/Process.cpp
+++ b/Process.cpp
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <fstream>
+#include <mntent.h>
#include <unordered_set>
#include <android-base/file.h>
@@ -81,6 +82,51 @@
return false;
}
+// TODO: Refactor the code with KillProcessesWithOpenFiles().
+int KillProcessesWithMounts(const std::string& prefix, int signal) {
+ std::unordered_set<pid_t> pids;
+
+ auto proc_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/proc"), closedir);
+ if (!proc_d) {
+ PLOG(ERROR) << "Failed to open proc";
+ return -1;
+ }
+
+ struct dirent* proc_de;
+ while ((proc_de = readdir(proc_d.get())) != nullptr) {
+ // We only care about valid PIDs
+ pid_t pid;
+ if (proc_de->d_type != DT_DIR) continue;
+ if (!android::base::ParseInt(proc_de->d_name, &pid)) continue;
+
+ // Look for references to prefix
+ std::string mounts_file(StringPrintf("/proc/%d/mounts", pid));
+ auto fp = std::unique_ptr<FILE, int (*)(FILE*)>(
+ setmntent(mounts_file.c_str(), "r"), endmntent);
+ if (!fp) {
+ PLOG(WARNING) << "Failed to open " << mounts_file;
+ continue;
+ }
+
+ // Check if obb directory is mounted, and get all packages of mounted app data directory.
+ mntent* mentry;
+ while ((mentry = getmntent(fp.get())) != nullptr) {
+ if (android::base::StartsWith(mentry->mnt_dir, prefix)) {
+ pids.insert(pid);
+ break;
+ }
+ }
+ }
+ if (signal != 0) {
+ for (const auto& pid : pids) {
+ LOG(WARNING) << "Killing pid "<< pid << " with signal " << strsignal(signal) <<
+ " because it has a mount with prefix " << prefix;
+ kill(pid, signal);
+ }
+ }
+ return pids.size();
+}
+
int KillProcessesWithOpenFiles(const std::string& prefix, int signal) {
std::unordered_set<pid_t> pids;
diff --git a/Process.h b/Process.h
index 1406782..1c59812 100644
--- a/Process.h
+++ b/Process.h
@@ -21,6 +21,7 @@
namespace vold {
int KillProcessesWithOpenFiles(const std::string& path, int signal);
+int KillProcessesWithMounts(const std::string& path, int signal);
} // namespace vold
} // namespace android
diff --git a/Utils.cpp b/Utils.cpp
index 0974a0b..82ad1f1 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -84,6 +84,9 @@
static const char* kAppMediaDir = "/Android/media/";
static const char* kAppObbDir = "/Android/obb/";
+static const char* kMediaProviderCtx = "u:r:mediaprovider:";
+static const char* kMediaProviderAppCtx = "u:r:mediaprovider_app:";
+
// Lock used to protect process-level SELinux changes from racing with each
// other between multiple threads.
static std::mutex kSecurityLock;
@@ -426,6 +429,31 @@
return -errno;
}
+status_t KillProcessesWithMountPrefix(const std::string& path) {
+ if (KillProcessesWithMounts(path, SIGINT) == 0) {
+ return OK;
+ }
+ if (sSleepOnUnmount) sleep(5);
+
+ if (KillProcessesWithMounts(path, SIGTERM) == 0) {
+ return OK;
+ }
+ if (sSleepOnUnmount) sleep(5);
+
+ if (KillProcessesWithMounts(path, SIGKILL) == 0) {
+ return OK;
+ }
+ if (sSleepOnUnmount) sleep(5);
+
+ // Send SIGKILL a second time to determine if we've
+ // actually killed everyone mount
+ if (KillProcessesWithMounts(path, SIGKILL) == 0) {
+ return OK;
+ }
+ PLOG(ERROR) << "Failed to kill processes using " << path;
+ return -EBUSY;
+}
+
status_t KillProcessesUsingPath(const std::string& path) {
if (KillProcessesWithOpenFiles(path, SIGINT) == 0) {
return OK;
@@ -883,6 +911,19 @@
}
}
+// TODO: Use a better way to determine if it's media provider app.
+bool IsFuseDaemon(const pid_t pid) {
+ auto path = StringPrintf("/proc/%d/mounts", pid);
+ char* tmp;
+ if (lgetfilecon(path.c_str(), &tmp) < 0) {
+ return false;
+ }
+ bool result = android::base::StartsWith(tmp, kMediaProviderAppCtx)
+ || android::base::StartsWith(tmp, kMediaProviderCtx);
+ freecon(tmp);
+ return result;
+}
+
bool IsFilesystemSupported(const std::string& fsType) {
std::string supported;
if (!ReadFileToString(kProcFilesystems, &supported)) {
@@ -1242,6 +1283,16 @@
return true;
}
+status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
+ if (access(path.c_str(), F_OK) != 0) {
+ PLOG(WARNING) << "Dir does not exist: " << path;
+ if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) {
+ return -errno;
+ }
+ }
+ return OK;
+}
+
status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
const std::string& relative_upper_path, android::base::unique_fd* fuse_fd) {
std::string pre_fuse_path(StringPrintf("/mnt/user/%d", user_id));
diff --git a/Utils.h b/Utils.h
index 21abc4d..5e6ff1b 100644
--- a/Utils.h
+++ b/Utils.h
@@ -35,6 +35,7 @@
namespace vold {
static const char* kPropFuse = "persist.sys.fuse";
+static const char* kVoldAppDataIsolationEnabled = "persist.sys.vold_app_data_isolation_enabled";
/* SELinux contexts used depending on the block device type */
extern security_context_t sBlkidContext;
@@ -69,6 +70,9 @@
/* Kills any processes using given path */
status_t KillProcessesUsingPath(const std::string& path);
+/* Kills any processes using given mount prifix */
+status_t KillProcessesWithMountPrefix(const std::string& path);
+
/* Creates bind mount from source to target */
status_t BindMount(const std::string& source, const std::string& target);
@@ -120,6 +124,7 @@
uint64_t GetTreeBytes(const std::string& path);
bool IsFilesystemSupported(const std::string& fsType);
+bool IsFuseDaemon(const pid_t pid);
/* Wipes contents of block device at given path */
status_t WipeBlockDevice(const std::string& path);
@@ -143,6 +148,8 @@
dev_t GetDevice(const std::string& path);
+status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
+
status_t RestoreconRecursive(const std::string& path);
// TODO: promote to android::base
diff --git a/VoldUtil.h b/VoldUtil.h
index 6ef8cb1..ce6b411 100644
--- a/VoldUtil.h
+++ b/VoldUtil.h
@@ -17,10 +17,7 @@
#pragma once
#include <fstab/fstab.h>
-#include <sys/cdefs.h>
extern android::fs_mgr::Fstab fstab_default;
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
-
#define DATA_MNT_POINT "/data"
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index f7b36bf..2b6565c 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -80,6 +80,7 @@
using android::vold::CreateDir;
using android::vold::DeleteDirContents;
using android::vold::DeleteDirContentsAndDir;
+using android::vold::EnsureDirExists;
using android::vold::IsFilesystemSupported;
using android::vold::PrepareAndroidDirs;
using android::vold::PrepareAppDirFromRoot;
@@ -104,6 +105,8 @@
static const unsigned int kMajorBlockExperimentalMin = 240;
static const unsigned int kMajorBlockExperimentalMax = 254;
+using ScanProcCallback = bool(*)(uid_t uid, pid_t pid, int nsFd, const char* name, void* params);
+
VolumeManager* VolumeManager::sInstance = NULL;
VolumeManager* VolumeManager::Instance() {
@@ -534,9 +537,9 @@
// TODO: Get rid of this guesswork altogether and instead exec a process
// immediately after fork to do our bindding for us.
static bool childProcess(const char* storageSource, const char* userSource, int nsFd,
- struct dirent* de) {
+ const char* name) {
if (setns(nsFd, CLONE_NEWNS) != 0) {
- async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns for %s :%s", de->d_name,
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns for %s :%s", name,
strerror(errno));
return false;
}
@@ -553,59 +556,82 @@
if (TEMP_FAILURE_RETRY(mount(storageSource, "/storage", NULL, MS_BIND | MS_REC, NULL)) == -1) {
async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s for %s :%s",
- storageSource, de->d_name, strerror(errno));
+ storageSource, name, strerror(errno));
return false;
}
if (TEMP_FAILURE_RETRY(mount(NULL, "/storage", NULL, MS_REC | MS_SLAVE, NULL)) == -1) {
async_safe_format_log(ANDROID_LOG_ERROR, "vold",
- "Failed to set MS_SLAVE to /storage for %s :%s", de->d_name,
+ "Failed to set MS_SLAVE to /storage for %s :%s", name,
strerror(errno));
return false;
}
if (TEMP_FAILURE_RETRY(mount(userSource, "/storage/self", NULL, MS_BIND, NULL)) == -1) {
async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s for %s :%s",
- userSource, de->d_name, strerror(errno));
+ userSource, name, strerror(errno));
return false;
}
return true;
}
-int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
- if (GetBoolProperty(android::vold::kPropFuse, false)) {
- // TODO(135341433): Implement fuse specific logic.
- return 0;
- }
- std::string mode;
+// Fork the process and remount storage
+bool forkAndRemountChild(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) {
+ int32_t mountMode = *static_cast<int32_t*>(params);
+ std::string userSource;
+ std::string storageSource;
+ pid_t child;
+ // Need to fix these paths to account for when sdcardfs is gone
switch (mountMode) {
case VoldNativeService::REMOUNT_MODE_NONE:
- mode = "none";
- break;
+ return true;
case VoldNativeService::REMOUNT_MODE_DEFAULT:
- mode = "default";
+ storageSource = "/mnt/runtime/default";
break;
case VoldNativeService::REMOUNT_MODE_READ:
- mode = "read";
+ storageSource = "/mnt/runtime/read";
break;
case VoldNativeService::REMOUNT_MODE_WRITE:
case VoldNativeService::REMOUNT_MODE_LEGACY:
case VoldNativeService::REMOUNT_MODE_INSTALLER:
- mode = "write";
+ storageSource = "/mnt/runtime/write";
break;
case VoldNativeService::REMOUNT_MODE_FULL:
- mode = "full";
+ storageSource = "/mnt/runtime/full";
break;
case VoldNativeService::REMOUNT_MODE_PASS_THROUGH:
- mode = "pass_through";
- break;
+ return true;
default:
PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode);
- return -1;
+ return false;
}
- LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
+ LOG(DEBUG) << "Remounting " << uid << " as " << storageSource;
+ // Fork a child to mount user-specific symlink helper into place
+ userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid));
+ if (!(child = fork())) {
+ if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, name)) {
+ _exit(0);
+ } else {
+ _exit(1);
+ }
+ }
+
+ if (child == -1) {
+ PLOG(ERROR) << "Failed to fork";
+ return false;
+ } else {
+ TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
+ }
+ return true;
+}
+
+// Helper function to scan all processes in /proc and call the callback if:
+// 1). pid belongs to an app process
+// 2). If input uid is 0 or it matches the process uid
+// 3). If userId is not -1 or userId matches the process userId
+bool scanProcProcesses(uid_t uid, userid_t userId, ScanProcCallback callback, void* params) {
DIR* dir;
struct dirent* de;
std::string rootName;
@@ -613,24 +639,22 @@
int pidFd;
int nsFd;
struct stat sb;
- pid_t child;
- std::string userSource;
- std::string storageSource;
static bool apexUpdatable = android::sysprop::ApexProperties::updatable().value_or(false);
if (!(dir = opendir("/proc"))) {
- PLOG(ERROR) << "Failed to opendir";
- return -1;
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to opendir");
+ return false;
}
// Figure out root namespace to compare against below
if (!android::vold::Readlinkat(dirfd(dir), "1/ns/mnt", &rootName)) {
- PLOG(ERROR) << "Failed to read root namespace";
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to read root namespace");
closedir(dir);
- return -1;
+ return false;
}
+ async_safe_format_log(ANDROID_LOG_INFO, "vold", "Start scanning all processes");
// Poke through all running PIDs look for apps running as UID
while ((de = readdir(dir))) {
pid_t pid;
@@ -645,21 +669,23 @@
goto next;
}
if (fstat(pidFd, &sb) != 0) {
- PLOG(WARNING) << "Failed to stat " << de->d_name;
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to stat %s", de->d_name);
goto next;
}
- if (sb.st_uid != uid) {
+ if (uid != 0 && sb.st_uid != uid) {
+ goto next;
+ }
+ if (userId != static_cast<userid_t>(-1) && multiuser_get_user_id(sb.st_uid) != userId) {
goto next;
}
// Matches so far, but refuse to touch if in root namespace
- LOG(DEBUG) << "Found matching PID " << de->d_name;
if (!android::vold::Readlinkat(pidFd, "ns/mnt", &pidName)) {
- PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold",
+ "Failed to read namespacefor %s", de->d_name);
goto next;
}
if (rootName == pidName) {
- LOG(WARNING) << "Skipping due to root namespace";
goto next;
}
@@ -674,11 +700,9 @@
// non-Java process whose UID is < AID_APP_START. (The UID condition
// is required to not filter out child processes spawned by apps.)
if (!android::vold::Readlinkat(pidFd, "exe", &exeName)) {
- PLOG(WARNING) << "Failed to read exe name for " << de->d_name;
goto next;
}
if (!StartsWith(exeName, "/system/bin/app_process") && sb.st_uid < AID_APP_START) {
- LOG(WARNING) << "Skipping due to native system process";
goto next;
}
}
@@ -687,39 +711,13 @@
// NOLINTNEXTLINE(android-cloexec-open): Deliberately not O_CLOEXEC
nsFd = openat(pidFd, "ns/mnt", O_RDONLY);
if (nsFd < 0) {
- PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold",
+ "Failed to open namespace for %s", de->d_name);
goto next;
}
- if (mode == "default") {
- storageSource = "/mnt/runtime/default";
- } else if (mode == "read") {
- storageSource = "/mnt/runtime/read";
- } else if (mode == "write") {
- storageSource = "/mnt/runtime/write";
- } else if (mode == "full") {
- storageSource = "/mnt/runtime/full";
- } else {
- // Sane default of no storage visible. No need to fork a child
- // to remount uid.
- goto next;
- }
-
- // Mount user-specific symlink helper into place
- userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid));
- if (!(child = fork())) {
- if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, de)) {
- _exit(0);
- } else {
- _exit(1);
- }
- }
-
- if (child == -1) {
- PLOG(ERROR) << "Failed to fork";
- goto next;
- } else {
- TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
+ if (!callback(sb.st_uid, pid, nsFd, de->d_name, params)) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed in callback");
}
next:
@@ -727,9 +725,204 @@
close(pidFd);
}
closedir(dir);
+ async_safe_format_log(ANDROID_LOG_INFO, "vold", "Finished scanning all processes");
+ return true;
+}
+
+int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
+ if (GetBoolProperty(android::vold::kPropFuse, false)) {
+ // TODO(135341433): Implement fuse specific logic.
+ return 0;
+ }
+ return scanProcProcesses(uid, static_cast<userid_t>(-1),
+ forkAndRemountChild, &mountMode) ? 0 : -1;
+}
+
+// Bind mount obb dir for an app if necessary.
+// How it works:
+// 1). Check if a pid is an app uid and not the FuseDaemon, if not then return.
+// 2). Get the mounts for that pid.
+// 3). If obb is already mounted then return, otherwise we need to mount obb for this pid.
+// 4). Get all packages and uid mounted for jit profile. These packages are all packages with
+// same uid or whitelisted apps.
+// 5a). If there's no package, it means it's not a process running app data isolation, so
+// just bind mount Android/obb dir.
+// 5b). Otherwise, for each package, create obb dir if it's not created and bind mount it.
+// TODO: Should we get some reliable data from system server instead of scanning /proc ?
+static bool bindMountAppObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) {
+ if (uid < AID_APP_START || uid > AID_APP_END) {
+ return true;
+ }
+ if (android::vold::IsFuseDaemon(pid)) {
+ return true;
+ }
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Start mounting obb for uid:%d, pid:%d", uid,
+ pid);
+
+ userid_t userId = multiuser_get_user_id(uid);
+ if (setns(nsFd, CLONE_NEWNS) != 0) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns %s", strerror(errno));
+ return false;
+ }
+
+ std::string profiles_path(StringPrintf("/data/misc/profiles/cur/%d/", userId));
+ // We search both .../obb and .../obb/$PKG paths here.
+ std::string obb_path(StringPrintf("/storage/emulated/%d/Android/obb", userId));
+ int profiles_path_len = profiles_path.length();
+ int obb_path_len = obb_path.length();
+
+ // TODO: Refactor the code as a util function so we can reuse the mount parsing code.
+ std::string mounts_file(StringPrintf("/proc/%d/mounts", pid));
+ auto fp = std::unique_ptr<FILE, int (*)(FILE*)>(
+ setmntent(mounts_file.c_str(), "r"), endmntent);
+ if (!fp) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Error opening %s: %s",
+ mounts_file.c_str(), strerror(errno));
+ return false;
+ }
+
+ // Check if obb directory is mounted, and get all packages of mounted app data directory.
+ bool obb_mounted = false;
+ std::vector<std::string> pkg_name_list;
+ mntent* mentry;
+ while ((mentry = getmntent(fp.get())) != nullptr) {
+ if (strncmp(mentry->mnt_dir, profiles_path.c_str(), profiles_path_len) == 0) {
+ pkg_name_list.push_back(std::string(mentry->mnt_dir + profiles_path_len));
+ }
+ if (strncmp(mentry->mnt_dir, obb_path.c_str(), obb_path_len) == 0) {
+ obb_mounted = true;
+ }
+ }
+
+ // Obb mounted in zygote already, so skip it
+ if (obb_mounted) {
+ return true;
+ }
+
+ // Ensure obb parent directory exists
+ std::string obbSource;
+ if (IsFilesystemSupported("sdcardfs")) {
+ obbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", userId);
+ } else {
+ obbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", userId, userId);
+ }
+ std::string obbTarget(StringPrintf("/storage/emulated/%d/Android/obb", userId));
+ auto status = EnsureDirExists(obbSource, 0771, AID_MEDIA_RW, AID_MEDIA_RW);
+ if (status != OK) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to create dir %s %s",
+ obbSource.c_str(), strerror(-status));
+ return false;
+ }
+
+ // It means app data isolation is not applied to this, so we can just bind the whole obb
+ // directory instead.
+ if (pkg_name_list.empty()) {
+ async_safe_format_log(ANDROID_LOG_INFO, "vold",
+ "Bind mounting whole obb directory for pid %d", pid);
+ status = BindMount(obbSource, obbTarget);
+ if (status != OK) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s",
+ obbSource.c_str(), obbTarget.c_str(), strerror(-status));
+ return false;
+ }
+ return true;
+ }
+
+ // Bind mount each app's obb directory
+ for (const auto& pkg_name : pkg_name_list) {
+ std::string appObbSource;
+ if (IsFilesystemSupported("sdcardfs")) {
+ appObbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s",
+ userId, pkg_name.c_str());
+ } else {
+ appObbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s",
+ userId, userId, pkg_name.c_str());
+ }
+ std::string appObbTarget(StringPrintf("/storage/emulated/%d/Android/obb/%s",
+ userId, pkg_name.c_str()));
+
+ status = EnsureDirExists(appObbSource, 0770, uid, AID_MEDIA_RW);
+ if (status != OK) {
+ async_safe_format_log(ANDROID_LOG_INFO, "vold", "Failed to ensure dir %s exists",
+ appObbSource.c_str());
+ continue;
+ }
+ async_safe_format_log(ANDROID_LOG_INFO, "vold",
+ "Bind mounting app obb directory(%s) for pid %d", pkg_name.c_str(),
+ pid);
+ status = BindMount(appObbSource, appObbTarget);
+ if (status != OK) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s",
+ obbSource.c_str(), obbTarget.c_str(), strerror(-status));
+ continue;
+ }
+ }
+ return true;
+}
+
+int VolumeManager::remountAppObb(userid_t userId) {
+ if (!GetBoolProperty(android::vold::kPropFuse, false)) {
+ return 0;
+ }
+ LOG(INFO) << "Start remounting app obb";
+ pid_t child;
+ if (!(child = fork())) {
+ // Child process
+ if (daemon(0, 0) == -1) {
+ PLOG(FATAL) << "Cannot create daemon";
+ }
+ // TODO(149548518): Refactor the code so minimize the work after fork to prevent deadlock.
+ if (scanProcProcesses(0, userId, bindMountAppObbDir, nullptr)) {
+ // As some forked zygote processes may not setuid and recognized as an app yet, sleep
+ // 3s and try again to catch 'em all.
+ usleep(3 * 1000 * 1000); // 3s
+ async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Retry remounting app obb");
+ scanProcProcesses(0, userId, bindMountAppObbDir, nullptr);
+ _exit(0);
+ } else {
+ _exit(1);
+ }
+ }
+ if (child == -1) {
+ PLOG(ERROR) << "Failed to fork";
+ return -1;
+ } else if (child == 0) {
+ // Parent
+ int stat_loc;
+ for (;;) {
+ if (waitpid(child, &stat_loc, 0) != -1 || errno != EINTR) {
+ break;
+ }
+ }
+ }
return 0;
}
+bool VolumeManager::updateFuseMountedProperty() {
+ if (mFuseMountedUsers.size() == 0) {
+ android::base::SetProperty("vold.fuse_running_users", "");
+ return true;
+ }
+ std::stringstream stream;
+ char const * sep = "";
+ for (const auto& userId : mFuseMountedUsers) {
+ stream << sep;
+ stream << userId;
+ sep = ", ";
+ }
+ return android::base::SetProperty("vold.fuse_running_users", stream.str());
+}
+
+bool VolumeManager::addFuseMountedUser(userid_t userId) {
+ mFuseMountedUsers.insert(userId);
+ return updateFuseMountedProperty();
+}
+
+bool VolumeManager::removeFuseMountedUser(userid_t userId) {
+ mFuseMountedUsers.erase(userId);
+ return updateFuseMountedProperty();
+}
+
int VolumeManager::reset() {
// Tear down all existing disks/volumes and start from a blank slate so
// newly connected framework hears all events.
@@ -745,6 +938,8 @@
updateVirtualDisk();
mAddedUsers.clear();
mStartedUsers.clear();
+ mFuseMountedUsers.clear();
+ updateFuseMountedProperty();
return 0;
}
@@ -764,6 +959,8 @@
mInternalEmulatedVolumes.clear();
mDisks.clear();
mPendingDisks.clear();
+ mFuseMountedUsers.clear();
+ updateFuseMountedProperty();
android::vold::sSleepOnUnmount = true;
return 0;
}
diff --git a/VolumeManager.h b/VolumeManager.h
index afea54e..a094eae 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -118,6 +118,10 @@
int setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol);
int remountUid(uid_t uid, int32_t remountMode);
+ int remountAppObb(userid_t userId);
+
+ bool addFuseMountedUser(userid_t userId);
+ bool removeFuseMountedUser(userid_t userId);
/* Reset all internal state, typically during framework boot */
int reset();
@@ -201,6 +205,8 @@
void handleDiskChanged(dev_t device);
void handleDiskRemoved(dev_t device);
+ bool updateFuseMountedProperty();
+
std::mutex mLock;
std::mutex mCryptLock;
@@ -224,6 +230,9 @@
int mNextObbId;
int mNextStubId;
bool mSecureKeyguardShowing;
+
+ // Set of all user id that fuse is ready to use.
+ std::unordered_set<userid_t> mFuseMountedUsers;
};
#endif
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 4487d3b..1431459 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -325,7 +325,7 @@
}
const KeyGeneration cryptfs_get_keygen() {
- return makeGen(get_crypto_type());
+ return KeyGeneration{get_crypto_type().get_keysize(), true, false};
}
/* Should we use keymaster? */
diff --git a/model/Disk.cpp b/model/Disk.cpp
index b2ecc50..a4324db 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -16,11 +16,11 @@
#include "Disk.h"
#include "FsCrypt.h"
-#include "KeyUtil.h"
#include "PrivateVolume.h"
#include "PublicVolume.h"
#include "Utils.h"
#include "VolumeBase.h"
+#include "VolumeEncryption.h"
#include "VolumeManager.h"
#include <android-base/file.h>
@@ -31,8 +31,6 @@
#include <android-base/strings.h>
#include <fscrypt/fscrypt.h>
-#include "cryptfs.h"
-
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
@@ -537,7 +535,7 @@
}
KeyBuffer key;
- if (!generateStorageKey(cryptfs_get_keygen(), &key)) {
+ if (!generate_volume_key(&key)) {
LOG(ERROR) << "Failed to generate key";
return -EIO;
}
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 8f8c87a..c2f92e4 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -49,6 +49,7 @@
mLabel = "emulated";
mFuseMounted = false;
mUseSdcardFs = IsFilesystemSupported("sdcardfs");
+ mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
}
EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid,
@@ -59,6 +60,7 @@
mLabel = fsUuid;
mFuseMounted = false;
mUseSdcardFs = IsFilesystemSupported("sdcardfs");
+ mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
}
EmulatedVolume::~EmulatedVolume() {}
@@ -94,14 +96,19 @@
} else {
androidSource = StringPrintf("/%s/%d/Android", mRawPath.c_str(), userId);
}
- std::string androidTarget(
- StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
- auto status = doFuseBindMount(androidSource, androidTarget);
+ status_t status = OK;
+ // When app data isolation is enabled, obb/ will be mounted per app, otherwise we should
+ // bind mount the whole Android/ to speed up reading.
+ if (!mAppDataIsolationEnabled) {
+ std::string androidTarget(
+ StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
+ status = doFuseBindMount(androidSource, androidTarget);
+ }
+
if (status != OK) {
return status;
}
-
// Installers get the same view as all other apps, with the sole exception that the
// OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires
// a special bind mount, since app-private and OBB dirs share the same GID, but we
@@ -118,6 +125,19 @@
if (status != OK) {
return status;
}
+
+ if (mAppDataIsolationEnabled) {
+ // Starting from now, fuse is running, and zygote will bind app obb data directory
+ if (!VolumeManager::Instance()->addFuseMountedUser(userId)) {
+ return UNKNOWN_ERROR;
+ }
+
+ // As all new processes created by zygote will bind app obb data directory, we just need
+ // to have a snapshot of all existing processes and see if any existing process needs to
+ // remount obb data directory.
+ VolumeManager::Instance()->remountAppObb(userId);
+ }
+
return OK;
}
@@ -135,16 +155,22 @@
// Intentional continue to try to unmount the other bind mount
}
}
+ // When app data isolation is enabled, kill all apps that obb/ is mounted, otherwise we should
+ // umount the whole Android/ dir.
+ if (mAppDataIsolationEnabled) {
+ std::string appObbDir(StringPrintf("%s/%d/Android/obb", getPath().c_str(), userId));
+ KillProcessesWithMountPrefix(appObbDir);
+ } else {
+ std::string androidTarget(
+ StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
- std::string androidTarget(
- StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
-
- LOG(INFO) << "Unmounting " << androidTarget;
- auto status = UnmountTree(androidTarget);
- if (status != OK) {
- return status;
+ LOG(INFO) << "Unmounting " << androidTarget;
+ auto status = UnmountTree(androidTarget);
+ if (status != OK) {
+ return status;
+ }
+ LOG(INFO) << "Unmounted " << androidTarget;
}
- LOG(INFO) << "Unmounted " << androidTarget;
return OK;
}
@@ -281,9 +307,15 @@
if (mFuseMounted) {
std::string label = getLabel();
+
+ // Update fuse mounted record
+ if (mAppDataIsolationEnabled &&
+ !VolumeManager::Instance()->removeFuseMountedUser(userId)) {
+ return UNKNOWN_ERROR;
+ }
+
// Ignoring unmount return status because we do want to try to unmount
// the rest cleanly.
-
unmountFuseBindMounts();
if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h
index 3f1b2e3..12d01ec 100644
--- a/model/EmulatedVolume.h
+++ b/model/EmulatedVolume.h
@@ -65,6 +65,9 @@
/* Whether to use sdcardfs for this volume */
bool mUseSdcardFs;
+ /* Whether to use app data isolation is enabled tor this volume */
+ bool mAppDataIsolationEnabled;
+
DISALLOW_COPY_AND_ASSIGN(EmulatedVolume);
};
diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp
index 75aa938..a54b05e 100644
--- a/model/PrivateVolume.cpp
+++ b/model/PrivateVolume.cpp
@@ -17,8 +17,8 @@
#include "PrivateVolume.h"
#include "EmulatedVolume.h"
#include "Utils.h"
+#include "VolumeEncryption.h"
#include "VolumeManager.h"
-#include "cryptfs.h"
#include "fs/Ext4.h"
#include "fs/F2fs.h"
@@ -87,9 +87,8 @@
// TODO: figure out better SELinux labels for private volumes
- int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(), mKeyRaw, &mDmDevPath);
- if (res != 0) {
- PLOG(ERROR) << getId() << " failed to setup cryptfs";
+ if (!setup_ext_volume(getId(), mRawDevPath, mKeyRaw, &mDmDevPath)) {
+ LOG(ERROR) << getId() << " failed to setup metadata encryption";
return -EIO;
}
diff --git a/model/VolumeEncryption.cpp b/model/VolumeEncryption.cpp
new file mode 100644
index 0000000..5b0e73d
--- /dev/null
+++ b/model/VolumeEncryption.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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 "VolumeEncryption.h"
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+#include "KeyBuffer.h"
+#include "KeyUtil.h"
+#include "MetadataCrypt.h"
+#include "cryptfs.h"
+
+namespace android {
+namespace vold {
+
+enum class VolumeMethod { kFailed, kCrypt, kDefaultKey };
+
+static VolumeMethod lookup_volume_method() {
+ constexpr uint64_t pre_gki_level = 29;
+ auto first_api_level =
+ android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ auto method = android::base::GetProperty("ro.crypto.volume.metadata.method", "default");
+ if (method == "default") {
+ return first_api_level > pre_gki_level ? VolumeMethod::kDefaultKey : VolumeMethod::kCrypt;
+ } else if (method == "dm-default-key") {
+ return VolumeMethod::kDefaultKey;
+ } else if (method == "dm-crypt") {
+ if (first_api_level > pre_gki_level) {
+ LOG(ERROR) << "volume encryption method dm-crypt cannot be used, "
+ "ro.product.first_api_level = "
+ << first_api_level;
+ return VolumeMethod::kFailed;
+ }
+ return VolumeMethod::kCrypt;
+ } else {
+ LOG(ERROR) << "Unknown volume encryption method: " << method;
+ return VolumeMethod::kFailed;
+ }
+}
+
+static VolumeMethod volume_method() {
+ static VolumeMethod method = lookup_volume_method();
+ return method;
+}
+
+bool generate_volume_key(android::vold::KeyBuffer* key) {
+ KeyGeneration gen;
+ switch (volume_method()) {
+ case VolumeMethod::kFailed:
+ LOG(ERROR) << "Volume encryption setup failed";
+ return false;
+ case VolumeMethod::kCrypt:
+ gen = cryptfs_get_keygen();
+ break;
+ case VolumeMethod::kDefaultKey:
+ if (!defaultkey_volume_keygen(&gen)) return false;
+ break;
+ }
+ if (!generateStorageKey(gen, key)) return false;
+ return true;
+}
+
+bool setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev) {
+ switch (volume_method()) {
+ case VolumeMethod::kFailed:
+ LOG(ERROR) << "Volume encryption setup failed";
+ return false;
+ case VolumeMethod::kCrypt:
+ return cryptfs_setup_ext_volume(label.c_str(), blk_device.c_str(), key,
+ out_crypto_blkdev) == 0;
+ case VolumeMethod::kDefaultKey:
+ return defaultkey_setup_ext_volume(label, blk_device, key, out_crypto_blkdev);
+ }
+}
+
+} // namespace vold
+} // namespace android
diff --git a/model/VolumeEncryption.h b/model/VolumeEncryption.h
new file mode 100644
index 0000000..d06c12b
--- /dev/null
+++ b/model/VolumeEncryption.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include "KeyBuffer.h"
+
+namespace android {
+namespace vold {
+
+bool generate_volume_key(android::vold::KeyBuffer* key);
+
+bool setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev);
+
+} // namespace vold
+} // namespace android