vold: remove session keyring workaround for old kernels
The android-4.14-stable and later kernels support the FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY ioctls. This has superseded the old way of adding fscrypt keys to the kernel, which was to use the add_key() syscall to add keys to the "session" keyring. On kernels that support the ioctls, Android doesn't use the obsolete way. Since upgrading even just to Android 14 requires at minimum a android-4.14-stable kernel (according to https://source.android.com/docs/core/architecture/kernel/android-common#compatibility-matrix), there is no need to support the obsolete way anymore. Therefore, this commit removes the code that added and removed keys to/from the session keyring. Now the ioctls are used unconditionally. Flag: N/A for the following reasons: - Removing obsolete code, which is fairly safe - Very early code, so runtime flag cannot be used - This topic also removes code from init, which cannot use aconfig libraries because they do not support recovery_available Bug: 311736104 Test: Build and boot Cuttlefish Change-Id: I0d9abbda77b1ac838ea6f014dbe22ab032c0e5ae
This commit is contained in:
parent
1dd20644dc
commit
0e87a83cba
4 changed files with 0 additions and 153 deletions
|
@ -62,7 +62,6 @@ cc_defaults {
|
||||||
"libincfs",
|
"libincfs",
|
||||||
"libhidlbase",
|
"libhidlbase",
|
||||||
"libkeymint_support",
|
"libkeymint_support",
|
||||||
"libkeyutils",
|
|
||||||
"liblog",
|
"liblog",
|
||||||
"liblogwrap",
|
"liblogwrap",
|
||||||
"libselinux",
|
"libselinux",
|
||||||
|
|
24
FsCrypt.cpp
24
FsCrypt.cpp
|
@ -50,7 +50,6 @@
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
#include <fscrypt/fscrypt.h>
|
#include <fscrypt/fscrypt.h>
|
||||||
#include <keyutils.h>
|
|
||||||
#include <libdm/dm.h>
|
#include <libdm/dm.h>
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
|
@ -76,7 +75,6 @@ using android::vold::retrieveOrGenerateKey;
|
||||||
using android::vold::SetDefaultAcl;
|
using android::vold::SetDefaultAcl;
|
||||||
using android::vold::SetQuotaInherit;
|
using android::vold::SetQuotaInherit;
|
||||||
using android::vold::SetQuotaProjectId;
|
using android::vold::SetQuotaProjectId;
|
||||||
using android::vold::writeStringToFile;
|
|
||||||
using namespace android::fscrypt;
|
using namespace android::fscrypt;
|
||||||
using namespace android::dm;
|
using namespace android::dm;
|
||||||
|
|
||||||
|
@ -632,27 +630,6 @@ bool fscrypt_create_user_keys(userid_t user_id, int serial, bool ephemeral) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Lock" all encrypted directories whose key has been removed. This is needed
|
|
||||||
// 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_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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evicts all the user's keys of one type from all volumes (internal and adoptable).
|
// Evicts all the user's keys of one type from all volumes (internal and adoptable).
|
||||||
// This evicts either CE keys or DE keys, depending on which map is passed.
|
// This evicts either CE keys or DE keys, depending on which map is passed.
|
||||||
static bool evict_user_keys(std::map<userid_t, UserPolicies>& policy_map, userid_t user_id) {
|
static bool evict_user_keys(std::map<userid_t, UserPolicies>& policy_map, userid_t user_id) {
|
||||||
|
@ -665,7 +642,6 @@ static bool evict_user_keys(std::map<userid_t, UserPolicies>& policy_map, userid
|
||||||
success &= android::vold::evictKey(BuildDataPath(volume_uuid), policy);
|
success &= android::vold::evictKey(BuildDataPath(volume_uuid), policy);
|
||||||
}
|
}
|
||||||
policy_map.erase(it);
|
policy_map.erase(it);
|
||||||
drop_caches_if_needed();
|
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
115
KeyUtil.cpp
115
KeyUtil.cpp
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
#include <keyutils.h>
|
|
||||||
|
|
||||||
#include "KeyStorage.h"
|
#include "KeyStorage.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
@ -75,39 +74,6 @@ bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isFsKeyringSupportedImpl() {
|
|
||||||
android::base::unique_fd fd(open("/data", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
|
||||||
|
|
||||||
// FS_IOC_ADD_ENCRYPTION_KEY with a NULL argument will fail with ENOTTY if
|
|
||||||
// the ioctl isn't supported. Otherwise it will fail with another error
|
|
||||||
// code such as EFAULT.
|
|
||||||
//
|
|
||||||
// Note that there's no need to check for FS_IOC_REMOVE_ENCRYPTION_KEY,
|
|
||||||
// since it's guaranteed to be available if FS_IOC_ADD_ENCRYPTION_KEY is.
|
|
||||||
// There's also no need to check for support on external volumes separately
|
|
||||||
// from /data, since either the kernel supports the ioctls on all
|
|
||||||
// fscrypt-capable filesystems or it doesn't.
|
|
||||||
errno = 0;
|
|
||||||
(void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, NULL);
|
|
||||||
if (errno == ENOTTY) {
|
|
||||||
LOG(INFO) << "Kernel doesn't support FS_IOC_ADD_ENCRYPTION_KEY. Falling back to "
|
|
||||||
"session keyring";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (errno != EFAULT) {
|
|
||||||
PLOG(WARNING) << "Unexpected error from FS_IOC_ADD_ENCRYPTION_KEY";
|
|
||||||
}
|
|
||||||
LOG(DEBUG) << "Detected support for FS_IOC_ADD_ENCRYPTION_KEY";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if the kernel supports the ioctls to add/remove fscrypt keys
|
|
||||||
// directly to/from the filesystem.
|
|
||||||
bool isFsKeyringSupported(void) {
|
|
||||||
static bool supported = isFsKeyringSupportedImpl();
|
|
||||||
return supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get raw keyref - used to make keyname and to pass to ioctl
|
// Get raw keyref - used to make keyname and to pass to ioctl
|
||||||
static std::string generateKeyRef(const uint8_t* key, int length) {
|
static std::string generateKeyRef(const uint8_t* key, int length) {
|
||||||
SHA512_CTX c;
|
SHA512_CTX c;
|
||||||
|
@ -127,20 +93,6 @@ static std::string generateKeyRef(const uint8_t* key, int length) {
|
||||||
return std::string((char*)key_ref2, FSCRYPT_KEY_DESCRIPTOR_SIZE);
|
return std::string((char*)key_ref2, FSCRYPT_KEY_DESCRIPTOR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
|
|
||||||
if (key.size() != FSCRYPT_MAX_KEY_SIZE) {
|
|
||||||
LOG(ERROR) << "Wrong size key " << key.size();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
static_assert(FSCRYPT_MAX_KEY_SIZE == sizeof(fs_key->raw), "Mismatch of max key sizes");
|
|
||||||
fs_key->mode = 0; // unused by kernel
|
|
||||||
memcpy(fs_key->raw, key.data(), key.size());
|
|
||||||
fs_key->size = key.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
|
|
||||||
|
|
||||||
static std::string keyrefstring(const std::string& raw_ref) {
|
static std::string keyrefstring(const std::string& raw_ref) {
|
||||||
std::ostringstream o;
|
std::ostringstream o;
|
||||||
for (unsigned char i : raw_ref) {
|
for (unsigned char i : raw_ref) {
|
||||||
|
@ -149,44 +101,6 @@ static std::string keyrefstring(const std::string& raw_ref) {
|
||||||
return o.str();
|
return o.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string buildLegacyKeyName(const std::string& prefix, const std::string& raw_ref) {
|
|
||||||
return prefix + ":" + keyrefstring(raw_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the ID of the keyring we store all fscrypt keys in when the kernel is too
|
|
||||||
// old to support FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY.
|
|
||||||
static bool fscryptKeyring(key_serial_t* device_keyring) {
|
|
||||||
*device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
|
|
||||||
if (*device_keyring == -1) {
|
|
||||||
PLOG(ERROR) << "Unable to find device keyring";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an encryption key to the legacy global session keyring.
|
|
||||||
static bool installKeyLegacy(const KeyBuffer& key, const std::string& raw_ref) {
|
|
||||||
// Place fscrypt_key into automatically zeroing buffer.
|
|
||||||
KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
|
|
||||||
fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
|
|
||||||
|
|
||||||
if (!fillKey(key, &fs_key)) return false;
|
|
||||||
key_serial_t device_keyring;
|
|
||||||
if (!fscryptKeyring(&device_keyring)) return false;
|
|
||||||
for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
|
|
||||||
auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
|
|
||||||
key_serial_t key_id =
|
|
||||||
add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
|
|
||||||
if (key_id == -1) {
|
|
||||||
PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
|
|
||||||
<< " in process " << getpid();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build a struct fscrypt_key_specifier for use in the key management ioctls.
|
// Build a struct fscrypt_key_specifier for use in the key management ioctls.
|
||||||
static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) {
|
static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) {
|
||||||
switch (policy.options.version) {
|
switch (policy.options.version) {
|
||||||
|
@ -230,9 +144,6 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
|
||||||
// "descriptor", which must be provided by userspace. We use the
|
// "descriptor", which must be provided by userspace. We use the
|
||||||
// first 8 bytes from the double SHA-512 of the key itself.
|
// first 8 bytes from the double SHA-512 of the key itself.
|
||||||
policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
|
policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
|
||||||
if (!isFsKeyringSupported()) {
|
|
||||||
return installKeyLegacy(key, policy->key_raw_ref);
|
|
||||||
}
|
|
||||||
if (!buildKeySpecifier(&arg->key_spec, *policy)) {
|
if (!buildKeySpecifier(&arg->key_spec, *policy)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -276,29 +187,6 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove an encryption key from the legacy global session keyring.
|
|
||||||
static bool evictKeyLegacy(const std::string& raw_ref) {
|
|
||||||
key_serial_t device_keyring;
|
|
||||||
if (!fscryptKeyring(&device_keyring)) return false;
|
|
||||||
bool success = true;
|
|
||||||
for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
|
|
||||||
auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
|
|
||||||
auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
|
|
||||||
|
|
||||||
// Unlink the key from the keyring. Prefer unlinking to revoking or
|
|
||||||
// invalidating, since unlinking is actually no less secure currently, and
|
|
||||||
// it avoids bugs in certain kernel versions where the keyring key is
|
|
||||||
// referenced from places it shouldn't be.
|
|
||||||
if (keyctl_unlink(key_serial, device_keyring) != 0) {
|
|
||||||
PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
|
|
||||||
success = false;
|
|
||||||
} else {
|
|
||||||
LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void waitForBusyFiles(const struct fscrypt_key_specifier key_spec, const std::string ref,
|
static void waitForBusyFiles(const struct fscrypt_key_specifier key_spec, const std::string ref,
|
||||||
const std::string mountpoint) {
|
const std::string mountpoint) {
|
||||||
android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
||||||
|
@ -359,9 +247,6 @@ static void waitForBusyFiles(const struct fscrypt_key_specifier key_spec, const
|
||||||
|
|
||||||
bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
|
bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
|
||||||
const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
|
const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
|
||||||
if (policy.options.version == 1 && !isFsKeyringSupported()) {
|
|
||||||
return evictKeyLegacy(policy.key_raw_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
|
13
KeyUtil.h
13
KeyUtil.h
|
@ -43,28 +43,15 @@ bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key);
|
||||||
// be generated.
|
// be generated.
|
||||||
const KeyGeneration neverGen();
|
const KeyGeneration neverGen();
|
||||||
|
|
||||||
bool isFsKeyringSupported(void);
|
|
||||||
|
|
||||||
// Install a file-based encryption key to the kernel, for use by encrypted files
|
// Install a file-based encryption key to the kernel, for use by encrypted files
|
||||||
// on the specified filesystem using the specified encryption policy version.
|
// on the specified filesystem using the specified encryption policy version.
|
||||||
//
|
//
|
||||||
// For v1 policies, we use FS_IOC_ADD_ENCRYPTION_KEY if the kernel supports it.
|
|
||||||
// Otherwise we add the key to the legacy global session keyring.
|
|
||||||
//
|
|
||||||
// For v2 policies, we always use FS_IOC_ADD_ENCRYPTION_KEY; it's the only way
|
|
||||||
// the kernel supports.
|
|
||||||
//
|
|
||||||
// Returns %true on success, %false on failure. On success also sets *policy
|
// Returns %true on success, %false on failure. On success also sets *policy
|
||||||
// to the EncryptionPolicy used to refer to this key.
|
// to the EncryptionPolicy used to refer to this key.
|
||||||
bool installKey(const std::string& mountpoint, const android::fscrypt::EncryptionOptions& options,
|
bool installKey(const std::string& mountpoint, const android::fscrypt::EncryptionOptions& options,
|
||||||
const KeyBuffer& key, android::fscrypt::EncryptionPolicy* policy);
|
const KeyBuffer& key, android::fscrypt::EncryptionPolicy* policy);
|
||||||
|
|
||||||
// Evict a file-based encryption key from the kernel.
|
// Evict a file-based encryption key from the kernel.
|
||||||
//
|
|
||||||
// We use FS_IOC_REMOVE_ENCRYPTION_KEY if the kernel supports it. Otherwise we
|
|
||||||
// remove the key from the legacy global session keyring.
|
|
||||||
//
|
|
||||||
// In the latter case, the caller is responsible for dropping caches.
|
|
||||||
bool evictKey(const std::string& mountpoint, const android::fscrypt::EncryptionPolicy& policy);
|
bool evictKey(const std::string& mountpoint, const android::fscrypt::EncryptionPolicy& policy);
|
||||||
|
|
||||||
// Retrieves the key from the named directory, or generates it if it doesn't
|
// Retrieves the key from the named directory, or generates it if it doesn't
|
||||||
|
|
Loading…
Reference in a new issue