vold: use new ioctls to add/remove fscrypt keys when supported
When the kernel supports the new fscrypt key management ioctls, use them
instead of add_key() and keyctl_unlink().
This will be needed in order to support v2 encryption policies, since v2
encryption policies only support the new ioctls.
The new ioctls have other advantages too. For example,
FS_IOC_REMOVE_ENCRYPTION_KEY automatically evicts exactly the necessary
kernel objects, so the drop_caches sysctl is no longer needed. This
makes evicting keys faster and more reliable.
FS_IOC_REMOVE_ENCRYPTION_KEY also detects if any files are still open
and therefore couldn't be "locked", whereas this went undetected before.
Therefore, to start out this patch adds support for using the new ioctls
for v1 encryption policies, i.e. on existing devices.
(Originally based on a patch by Satya Tangirala <satyat@google.com>)
Bug: 140500828
Test: tested that a device using v1 policies continues to work, both
with and without an updated kernel. See
If64028d8580584b2c33c614cabd5d6b93657f608 for more details.
Also checked via the log that the filesystem-level keyring is in
fact used when supported.
Change-Id: I296ef78138578a3fd773797ac0cd46af1296b959
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index 8d78473..e28002f 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -199,13 +199,23 @@
return false;
}
+// Install a key for use by encrypted files on the /data filesystem.
+static bool install_data_key(const KeyBuffer& key, std::string* raw_ref) {
+ return android::vold::installKey(key, DATA_MNT_POINT, raw_ref);
+}
+
+// Evict a key for use by encrypted files on the /data filesystem.
+static bool evict_data_key(const std::string& raw_ref) {
+ return android::vold::evictKey(DATA_MNT_POINT, raw_ref);
+}
+
static bool read_and_install_user_ce_key(userid_t user_id,
const android::vold::KeyAuthentication& auth) {
if (s_ce_key_raw_refs.count(user_id) != 0) return true;
KeyBuffer ce_key;
if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
std::string ce_raw_ref;
- if (!android::vold::installKey(ce_key, &ce_raw_ref)) return false;
+ if (!install_data_key(ce_key, &ce_raw_ref)) return false;
s_ce_keys[user_id] = std::move(ce_key);
s_ce_key_raw_refs[user_id] = ce_raw_ref;
LOG(DEBUG) << "Installed ce key for user " << user_id;
@@ -255,10 +265,10 @@
return false;
}
std::string de_raw_ref;
- if (!android::vold::installKey(de_key, &de_raw_ref)) return false;
+ if (!install_data_key(de_key, &de_raw_ref)) return false;
s_de_key_raw_refs[user_id] = de_raw_ref;
std::string ce_raw_ref;
- if (!android::vold::installKey(ce_key, &ce_raw_ref)) return false;
+ if (!install_data_key(ce_key, &ce_raw_ref)) return false;
s_ce_keys[user_id] = ce_key;
s_ce_key_raw_refs[user_id] = ce_raw_ref;
LOG(DEBUG) << "Created keys for user " << user_id;
@@ -325,7 +335,7 @@
KeyBuffer key;
if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
std::string raw_ref;
- if (!android::vold::installKey(key, &raw_ref)) return false;
+ if (!install_data_key(key, &raw_ref)) return false;
s_de_key_raw_refs[user_id] = raw_ref;
LOG(DEBUG) << "Installed de key for user " << user_id;
}
@@ -345,7 +355,7 @@
PolicyKeyRef device_ref;
if (!android::vold::retrieveAndInstallKey(true, kEmptyAuthentication, device_key_path,
- device_key_temp, &device_ref.key_raw_ref))
+ device_key_temp, "", &device_ref.key_raw_ref))
return false;
get_data_file_encryption_modes(&device_ref);
@@ -360,7 +370,7 @@
KeyBuffer per_boot_key;
if (!android::vold::randomKey(&per_boot_key)) return false;
std::string per_boot_raw_ref;
- if (!android::vold::installKey(per_boot_key, &per_boot_raw_ref)) return false;
+ if (!install_data_key(per_boot_key, &per_boot_raw_ref)) return false;
std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref;
if (!android::vold::writeStringToFile(per_boot_raw_ref, per_boot_ref_filename)) return false;
LOG(INFO) << "Wrote per boot key reference to:" << per_boot_ref_filename;
@@ -419,15 +429,20 @@
}
// "Lock" all encrypted directories whose key has been removed. This is needed
-// because merely removing the keyring key doesn't affect inodes in the kernel's
-// inode cache whose per-file key was already set up. So to remove the per-file
-// keys and make the files "appear encrypted", these inodes must be evicted.
+// in the case where the keys are being put in the session keyring (rather in
+// the newer filesystem-level keyrings), because removing a key from the session
+// keyring doesn't affect inodes in the kernel's inode cache whose per-file key
+// was already set up. So to remove the per-file keys and make the files
+// "appear encrypted", these inodes must be evicted.
//
// To do this, sync() to clean all dirty inodes, then drop all reclaimable slab
// objects systemwide. This is overkill, but it's the best available method
// currently. Don't use drop_caches mode "3" because that also evicts pagecache
// for in-use files; all files relevant here are already closed and sync'ed.
-static void drop_caches() {
+static void drop_caches_if_needed() {
+ if (android::vold::isFsKeyringSupported()) {
+ return;
+ }
sync();
if (!writeStringToFile("2", "/proc/sys/vm/drop_caches")) {
PLOG(ERROR) << "Failed to drop caches during key eviction";
@@ -440,8 +455,8 @@
std::string raw_ref;
// If we haven't loaded the CE key, no need to evict it.
if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) {
- success &= android::vold::evictKey(raw_ref);
- drop_caches();
+ success &= evict_data_key(raw_ref);
+ drop_caches_if_needed();
}
s_ce_key_raw_refs.erase(user_id);
return success;
@@ -455,8 +470,7 @@
bool success = true;
std::string raw_ref;
success &= evict_ce_key(user_id);
- success &=
- lookup_key_ref(s_de_key_raw_refs, user_id, &raw_ref) && android::vold::evictKey(raw_ref);
+ success &= lookup_key_ref(s_de_key_raw_refs, user_id, &raw_ref) && evict_data_key(raw_ref);
s_de_key_raw_refs.erase(user_id);
auto it = s_ephemeral_users.find(user_id);
if (it != s_ephemeral_users.end()) {
@@ -546,7 +560,7 @@
return false;
}
android::vold::KeyAuthentication auth("", secdiscardable_hash);
- if (!android::vold::retrieveAndInstallKey(true, auth, key_path, key_path + "_tmp",
+ if (!android::vold::retrieveAndInstallKey(true, auth, key_path, key_path + "_tmp", volume_uuid,
&key_ref->key_raw_ref))
return false;
key_ref->contents_mode =