mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-21 22:47:51 -04:00
Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/linux
Pull fscrypt fixes from Eric Biggers: - Fix a bug where in a specific edge case, file contents en/decryption could be done with the wrong data unit size - Fix the data structure used for keeping track of users that have added an fscrypt key to be a simple list instead of a 'struct key' keyring This fixes issues such as a lockdep report found by syzbot and possible unintended interactions with the keyctl() system calls * tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/linux: fscrypt: Replace mk_users keyring with simple list fscrypt: Fix key setup in edge case with multiple data unit sizes
This commit is contained in:
@@ -236,7 +236,7 @@ struct fscrypt_symlink_data {
|
||||
* @tfm: crypto API transform object
|
||||
* @blk_key: key for blk-crypto
|
||||
*
|
||||
* Normally only one of the fields will be non-NULL.
|
||||
* Only one of the fields is non-NULL.
|
||||
*/
|
||||
struct fscrypt_prepared_key {
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
@@ -245,6 +245,15 @@ struct fscrypt_prepared_key {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* An entry in the linked list ->mk_mode_keys */
|
||||
struct fscrypt_mode_key {
|
||||
struct fscrypt_prepared_key key;
|
||||
struct list_head link;
|
||||
u8 hkdf_context;
|
||||
u8 mode_num;
|
||||
u8 data_unit_bits;
|
||||
};
|
||||
|
||||
/*
|
||||
* fscrypt_inode_info - the "encryption key" for an inode
|
||||
*
|
||||
@@ -430,20 +439,12 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
|
||||
* @prep_key, depending on which encryption implementation the file will use.
|
||||
*/
|
||||
static inline bool
|
||||
fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
|
||||
fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
|
||||
const struct fscrypt_inode_info *ci)
|
||||
{
|
||||
/*
|
||||
* The two smp_load_acquire()'s here pair with the smp_store_release()'s
|
||||
* in fscrypt_prepare_inline_crypt_key() and fscrypt_prepare_key().
|
||||
* I.e., in some cases (namely, if this prep_key is a per-mode
|
||||
* encryption key) another task can publish blk_key or tfm concurrently,
|
||||
* executing a RELEASE barrier. We need to use smp_load_acquire() here
|
||||
* to safely ACQUIRE the memory the other task published.
|
||||
*/
|
||||
if (fscrypt_using_inline_encryption(ci))
|
||||
return smp_load_acquire(&prep_key->blk_key) != NULL;
|
||||
return smp_load_acquire(&prep_key->tfm) != NULL;
|
||||
return prep_key->blk_key != NULL;
|
||||
return prep_key->tfm != NULL;
|
||||
}
|
||||
|
||||
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
|
||||
@@ -486,15 +487,28 @@ fscrypt_derive_sw_secret(struct super_block *sb,
|
||||
}
|
||||
|
||||
static inline bool
|
||||
fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
|
||||
fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
|
||||
const struct fscrypt_inode_info *ci)
|
||||
{
|
||||
return smp_load_acquire(&prep_key->tfm) != NULL;
|
||||
return prep_key->tfm != NULL;
|
||||
}
|
||||
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
|
||||
|
||||
/* keyring.c */
|
||||
|
||||
/*
|
||||
* fscrypt_master_key_user - a user's claim to a master key
|
||||
*/
|
||||
struct fscrypt_master_key_user {
|
||||
struct list_head link;
|
||||
kuid_t uid;
|
||||
/*
|
||||
* This 'struct key' contains no secret. It exists solely to charge the
|
||||
* appropriate user's key quota.
|
||||
*/
|
||||
struct key *quota_key;
|
||||
};
|
||||
|
||||
/*
|
||||
* fscrypt_master_key_secret - secret key material of an in-use master key
|
||||
*/
|
||||
@@ -577,8 +591,8 @@ struct fscrypt_master_key {
|
||||
/*
|
||||
* Active and structural reference counts. An active ref guarantees
|
||||
* that the struct continues to exist, continues to be in the keyring
|
||||
* ->s_master_keys, and that any embedded subkeys (e.g.
|
||||
* ->mk_direct_keys) that have been prepared continue to exist.
|
||||
* ->s_master_keys, and that any non-file-scoped subkeys (e.g.
|
||||
* ->mk_mode_keys) that have been prepared continue to exist.
|
||||
* A structural ref only guarantees that the struct continues to exist.
|
||||
*
|
||||
* There is one active ref associated with ->mk_present being true, and
|
||||
@@ -610,19 +624,18 @@ struct fscrypt_master_key {
|
||||
struct fscrypt_key_specifier mk_spec;
|
||||
|
||||
/*
|
||||
* Keyring which contains a key of type 'key_type_fscrypt_user' for each
|
||||
* user who has added this key. Normally each key will be added by just
|
||||
* one user, but it's possible that multiple users share a key, and in
|
||||
* that case we need to keep track of those users so that one user can't
|
||||
* remove the key before the others want it removed too.
|
||||
* List of user claims to this key (struct fscrypt_master_key_user).
|
||||
* Normally each key will be added by just one user, but it's possible
|
||||
* that multiple users share a key, and in that case we need to keep
|
||||
* track of those users so that one user can't remove the key before the
|
||||
* others want it removed too.
|
||||
*
|
||||
* This is NULL for v1 policy keys; those can only be added by root.
|
||||
* Used only for v2 policy keys. v1 policy keys can be added only by
|
||||
* root, so user tracking doesn't apply to them.
|
||||
*
|
||||
* Locking: protected by ->mk_sem. (We don't just rely on the keyrings
|
||||
* subsystem semaphore ->mk_users->sem, as we need support for atomic
|
||||
* search+insert along with proper synchronization with other fields.)
|
||||
* Locking: protected by ->mk_sem.
|
||||
*/
|
||||
struct key *mk_users;
|
||||
struct list_head mk_users;
|
||||
|
||||
/*
|
||||
* List of inodes that were unlocked using this key. This allows the
|
||||
@@ -632,12 +645,21 @@ struct fscrypt_master_key {
|
||||
spinlock_t mk_decrypted_inodes_lock;
|
||||
|
||||
/*
|
||||
* Per-mode encryption keys for the various types of encryption policies
|
||||
* that use them. Allocated and derived on-demand.
|
||||
* A list of 'struct fscrypt_mode_key' for the (hkdf_context, mode_num,
|
||||
* data_unit_bits, inlinecrypt) combinations that are in use for this
|
||||
* master key, for hkdf_context in [HKDF_CONTEXT_DIRECT_KEY,
|
||||
* HKDF_CONTEXT_IV_INO_LBLK_32_KEY, HKDF_CONTEXT_IV_INO_LBLK_64_KEY].
|
||||
*
|
||||
* This is a linked list and not a hash table because in practice
|
||||
* there's just a single encryption policy per master key, using
|
||||
* _at most_ 2 nodes in this list. Per-file keys don't use this at all.
|
||||
*
|
||||
* This list is append-only until the master key is fully removed, at
|
||||
* which time the list is cleared. Before then,
|
||||
* fscrypt_mode_key_setup_mutex synchronizes appends, and searches use
|
||||
* the RCU read lock together with ->mk_sem held for read.
|
||||
*/
|
||||
struct fscrypt_prepared_key mk_direct_keys[FSCRYPT_MODE_MAX + 1];
|
||||
struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[FSCRYPT_MODE_MAX + 1];
|
||||
struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[FSCRYPT_MODE_MAX + 1];
|
||||
struct list_head mk_mode_keys;
|
||||
|
||||
/* Hash key for inode numbers. Initialized only when needed. */
|
||||
siphash_key_t mk_ino_hash_key;
|
||||
|
||||
@@ -198,13 +198,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
|
||||
* I.e., here we publish ->blk_key with a RELEASE barrier so that
|
||||
* concurrent tasks can ACQUIRE it. Note that this concurrency is only
|
||||
* possible for per-mode keys, not for per-file keys.
|
||||
*/
|
||||
smp_store_release(&prep_key->blk_key, blk_key);
|
||||
prep_key->blk_key = blk_key;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
@@ -65,36 +65,33 @@ static void fscrypt_free_master_key(struct rcu_head *head)
|
||||
kfree_sensitive(mk);
|
||||
}
|
||||
|
||||
static void clear_mk_users(struct fscrypt_master_key *mk);
|
||||
|
||||
void fscrypt_put_master_key(struct fscrypt_master_key *mk)
|
||||
{
|
||||
if (!refcount_dec_and_test(&mk->mk_struct_refs))
|
||||
return;
|
||||
/*
|
||||
* No structural references left, so free ->mk_users, and also free the
|
||||
* No structural references left, so clear ->mk_users, and also free the
|
||||
* fscrypt_master_key struct itself after an RCU grace period ensures
|
||||
* that concurrent keyring lookups can no longer find it.
|
||||
*/
|
||||
WARN_ON_ONCE(refcount_read(&mk->mk_active_refs) != 0);
|
||||
if (mk->mk_users) {
|
||||
/* Clear the keyring so the quota gets released right away. */
|
||||
keyring_clear(mk->mk_users);
|
||||
key_put(mk->mk_users);
|
||||
mk->mk_users = NULL;
|
||||
}
|
||||
clear_mk_users(mk);
|
||||
call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
|
||||
}
|
||||
|
||||
void fscrypt_put_master_key_activeref(struct super_block *sb,
|
||||
struct fscrypt_master_key *mk)
|
||||
{
|
||||
size_t i;
|
||||
struct fscrypt_mode_key *node, *tmp;
|
||||
|
||||
if (!refcount_dec_and_test(&mk->mk_active_refs))
|
||||
return;
|
||||
/*
|
||||
* No active references left, so complete the full removal of this
|
||||
* fscrypt_master_key struct by removing it from the keyring and
|
||||
* destroying any subkeys embedded in it.
|
||||
* destroying any non-file-scoped subkeys.
|
||||
*/
|
||||
|
||||
if (WARN_ON_ONCE(!sb->s_master_keys))
|
||||
@@ -110,13 +107,16 @@ void fscrypt_put_master_key_activeref(struct super_block *sb,
|
||||
WARN_ON_ONCE(mk->mk_present);
|
||||
WARN_ON_ONCE(!list_empty(&mk->mk_decrypted_inodes));
|
||||
|
||||
for (i = 0; i <= FSCRYPT_MODE_MAX; i++) {
|
||||
fscrypt_destroy_prepared_key(
|
||||
sb, &mk->mk_direct_keys[i]);
|
||||
fscrypt_destroy_prepared_key(
|
||||
sb, &mk->mk_iv_ino_lblk_64_keys[i]);
|
||||
fscrypt_destroy_prepared_key(
|
||||
sb, &mk->mk_iv_ino_lblk_32_keys[i]);
|
||||
/*
|
||||
* Destroy any non-file-scoped subkeys. Since ->mk_active_refs == 0,
|
||||
* they're no longer referenced by any inodes. Nor can key setup run
|
||||
* and use them again. So they're no longer needed. (This implies no
|
||||
* concurrent readers, so we don't need list_del_rcu() for example.)
|
||||
*/
|
||||
list_for_each_entry_safe(node, tmp, &mk->mk_mode_keys, link) {
|
||||
fscrypt_destroy_prepared_key(sb, &node->key);
|
||||
list_del(&node->link);
|
||||
kfree(node);
|
||||
}
|
||||
memzero_explicit(&mk->mk_ino_hash_key,
|
||||
sizeof(mk->mk_ino_hash_key));
|
||||
@@ -162,8 +162,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
|
||||
}
|
||||
|
||||
/*
|
||||
* Type of key in ->mk_users. Each key of this type represents a particular
|
||||
* user who has added a particular master key.
|
||||
* Type of fscrypt_master_key_user::quota_key. This contains no secret; it
|
||||
* exists solely to charge a user's key quota.
|
||||
*
|
||||
* Note that the name of this key type really should be something like
|
||||
* ".fscrypt-user" instead of simply ".fscrypt". But the shorter name is chosen
|
||||
@@ -177,30 +177,9 @@ static struct key_type key_type_fscrypt_user = {
|
||||
.describe = fscrypt_user_key_describe,
|
||||
};
|
||||
|
||||
#define FSCRYPT_MK_USERS_DESCRIPTION_SIZE \
|
||||
(CONST_STRLEN("fscrypt-") + 2 * FSCRYPT_KEY_IDENTIFIER_SIZE + \
|
||||
CONST_STRLEN("-users") + 1)
|
||||
|
||||
#define FSCRYPT_MK_USER_DESCRIPTION_SIZE \
|
||||
(2 * FSCRYPT_KEY_IDENTIFIER_SIZE + CONST_STRLEN(".uid.") + 10 + 1)
|
||||
|
||||
static void format_mk_users_keyring_description(
|
||||
char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE],
|
||||
const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
|
||||
{
|
||||
sprintf(description, "fscrypt-%*phN-users",
|
||||
FSCRYPT_KEY_IDENTIFIER_SIZE, mk_identifier);
|
||||
}
|
||||
|
||||
static void format_mk_user_description(
|
||||
char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE],
|
||||
const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
|
||||
{
|
||||
|
||||
sprintf(description, "%*phN.uid.%u", FSCRYPT_KEY_IDENTIFIER_SIZE,
|
||||
mk_identifier, __kuid_val(current_fsuid()));
|
||||
}
|
||||
|
||||
/* Create ->s_master_keys if needed. Synchronized by fscrypt_add_key_mutex. */
|
||||
static int allocate_filesystem_keyring(struct super_block *sb)
|
||||
{
|
||||
@@ -335,91 +314,94 @@ fscrypt_find_master_key(struct super_block *sb,
|
||||
return mk;
|
||||
}
|
||||
|
||||
static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
|
||||
/* Find the current user's claim in ->mk_users. ->mk_sem must be held. */
|
||||
static struct fscrypt_master_key_user *
|
||||
find_master_key_user(struct fscrypt_master_key *mk)
|
||||
{
|
||||
char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE];
|
||||
struct key *keyring;
|
||||
struct fscrypt_master_key_user *mk_user;
|
||||
kuid_t uid = current_fsuid();
|
||||
|
||||
format_mk_users_keyring_description(description,
|
||||
mk->mk_spec.u.identifier);
|
||||
keyring = keyring_alloc(description, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
|
||||
current_cred(), KEY_POS_SEARCH |
|
||||
KEY_USR_SEARCH | KEY_USR_READ | KEY_USR_VIEW,
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
|
||||
if (IS_ERR(keyring))
|
||||
return PTR_ERR(keyring);
|
||||
|
||||
mk->mk_users = keyring;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the current user's "key" in the master key's ->mk_users.
|
||||
* Returns ERR_PTR(-ENOKEY) if not found.
|
||||
*/
|
||||
static struct key *find_master_key_user(struct fscrypt_master_key *mk)
|
||||
{
|
||||
char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
|
||||
key_ref_t keyref;
|
||||
|
||||
format_mk_user_description(description, mk->mk_spec.u.identifier);
|
||||
|
||||
/*
|
||||
* We need to mark the keyring reference as "possessed" so that we
|
||||
* acquire permission to search it, via the KEY_POS_SEARCH permission.
|
||||
*/
|
||||
keyref = keyring_search(make_key_ref(mk->mk_users, true /*possessed*/),
|
||||
&key_type_fscrypt_user, description, false);
|
||||
if (IS_ERR(keyref)) {
|
||||
if (PTR_ERR(keyref) == -EAGAIN || /* not found */
|
||||
PTR_ERR(keyref) == -EKEYREVOKED) /* recently invalidated */
|
||||
keyref = ERR_PTR(-ENOKEY);
|
||||
return ERR_CAST(keyref);
|
||||
list_for_each_entry(mk_user, &mk->mk_users, link) {
|
||||
if (uid_eq(mk_user->uid, uid))
|
||||
return mk_user;
|
||||
}
|
||||
return key_ref_to_ptr(keyref);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give the current user a "key" in ->mk_users. This charges the user's quota
|
||||
* Give the current user a claim in ->mk_users. This charges the user's quota
|
||||
* and marks the master key as added by the current user, so that it cannot be
|
||||
* removed by another user with the key. Either ->mk_sem must be held for
|
||||
* write, or the master key must be still undergoing initialization.
|
||||
*/
|
||||
static int add_master_key_user(struct fscrypt_master_key *mk)
|
||||
{
|
||||
kuid_t uid = current_fsuid();
|
||||
char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
|
||||
struct key *mk_user;
|
||||
struct key *quota_key;
|
||||
struct fscrypt_master_key_user *mk_user;
|
||||
int err;
|
||||
|
||||
format_mk_user_description(description, mk->mk_spec.u.identifier);
|
||||
mk_user = key_alloc(&key_type_fscrypt_user, description,
|
||||
current_fsuid(), current_gid(), current_cred(),
|
||||
KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
|
||||
if (IS_ERR(mk_user))
|
||||
return PTR_ERR(mk_user);
|
||||
snprintf(description, sizeof(description), "%*phN.uid.%u",
|
||||
FSCRYPT_KEY_IDENTIFIER_SIZE, mk->mk_spec.u.identifier,
|
||||
__kuid_val(uid));
|
||||
quota_key = key_alloc(&key_type_fscrypt_user, description, uid,
|
||||
current_gid(), current_cred(),
|
||||
KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
|
||||
if (IS_ERR(quota_key))
|
||||
return PTR_ERR(quota_key);
|
||||
|
||||
err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
|
||||
key_put(mk_user);
|
||||
return err;
|
||||
err = key_instantiate_and_link(quota_key, NULL, 0, NULL, NULL);
|
||||
if (err) {
|
||||
key_put(quota_key);
|
||||
return err;
|
||||
}
|
||||
|
||||
mk_user = kzalloc_obj(*mk_user);
|
||||
if (!mk_user) {
|
||||
key_put(quota_key);
|
||||
return -ENOMEM;
|
||||
}
|
||||
mk_user->uid = uid;
|
||||
mk_user->quota_key = quota_key;
|
||||
list_add(&mk_user->link, &mk->mk_users);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unlink_and_free_mk_user(struct fscrypt_master_key_user *mk_user)
|
||||
{
|
||||
list_del(&mk_user->link);
|
||||
key_put(mk_user->quota_key);
|
||||
kfree(mk_user);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the current user's "key" from ->mk_users.
|
||||
* Remove the current user's claim from ->mk_users.
|
||||
* ->mk_sem must be held for write.
|
||||
*
|
||||
* Returns 0 if removed, -ENOKEY if not found, or another -errno code.
|
||||
* Returns 0 if removed or -ENOKEY if not found.
|
||||
*/
|
||||
static int remove_master_key_user(struct fscrypt_master_key *mk)
|
||||
{
|
||||
struct key *mk_user;
|
||||
int err;
|
||||
struct fscrypt_master_key_user *mk_user;
|
||||
|
||||
mk_user = find_master_key_user(mk);
|
||||
if (IS_ERR(mk_user))
|
||||
return PTR_ERR(mk_user);
|
||||
err = key_unlink(mk->mk_users, mk_user);
|
||||
key_put(mk_user);
|
||||
return err;
|
||||
if (!mk_user)
|
||||
return -ENOKEY;
|
||||
unlink_and_free_mk_user(mk_user);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear ->mk_users. Either ->mk_sem must be held for write, or 'mk' must have
|
||||
* no structural references left.
|
||||
*/
|
||||
static void clear_mk_users(struct fscrypt_master_key *mk)
|
||||
{
|
||||
struct fscrypt_master_key_user *mk_user, *tmp;
|
||||
|
||||
list_for_each_entry_safe(mk_user, tmp, &mk->mk_users, link)
|
||||
unlink_and_free_mk_user(mk_user);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -442,13 +424,14 @@ static int add_new_master_key(struct super_block *sb,
|
||||
refcount_set(&mk->mk_struct_refs, 1);
|
||||
mk->mk_spec = *mk_spec;
|
||||
|
||||
INIT_LIST_HEAD(&mk->mk_users);
|
||||
|
||||
INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
|
||||
spin_lock_init(&mk->mk_decrypted_inodes_lock);
|
||||
|
||||
INIT_LIST_HEAD(&mk->mk_mode_keys);
|
||||
|
||||
if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
|
||||
err = allocate_master_key_users_keyring(mk);
|
||||
if (err)
|
||||
goto out_put;
|
||||
err = add_master_key_user(mk);
|
||||
if (err)
|
||||
goto out_put;
|
||||
@@ -477,19 +460,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
|
||||
int err;
|
||||
|
||||
/*
|
||||
* If the current user is already in ->mk_users, then there's nothing to
|
||||
* do. Otherwise, we need to add the user to ->mk_users. (Neither is
|
||||
* applicable for v1 policy keys, which have NULL ->mk_users.)
|
||||
* For v2 policy keys (FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER): If the current
|
||||
* user is already in ->mk_users, then there's nothing to do.
|
||||
* Otherwise, add the user to ->mk_users.
|
||||
*/
|
||||
if (mk->mk_users) {
|
||||
struct key *mk_user = find_master_key_user(mk);
|
||||
|
||||
if (mk_user != ERR_PTR(-ENOKEY)) {
|
||||
if (IS_ERR(mk_user))
|
||||
return PTR_ERR(mk_user);
|
||||
key_put(mk_user);
|
||||
if (mk->mk_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
|
||||
if (find_master_key_user(mk) != NULL)
|
||||
return 0;
|
||||
}
|
||||
err = add_master_key_user(mk);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -888,7 +865,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
|
||||
{
|
||||
struct fscrypt_key_specifier mk_spec;
|
||||
struct fscrypt_master_key *mk;
|
||||
struct key *mk_user;
|
||||
int err;
|
||||
|
||||
mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
|
||||
@@ -900,13 +876,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
|
||||
goto out;
|
||||
}
|
||||
down_read(&mk->mk_sem);
|
||||
mk_user = find_master_key_user(mk);
|
||||
if (IS_ERR(mk_user)) {
|
||||
err = PTR_ERR(mk_user);
|
||||
} else {
|
||||
key_put(mk_user);
|
||||
if (find_master_key_user(mk) != NULL)
|
||||
err = 0;
|
||||
}
|
||||
else
|
||||
err = -ENOKEY;
|
||||
up_read(&mk->mk_sem);
|
||||
fscrypt_put_master_key(mk);
|
||||
out:
|
||||
@@ -1098,16 +1071,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
|
||||
down_write(&mk->mk_sem);
|
||||
|
||||
/* If relevant, remove current user's (or all users) claim to the key */
|
||||
if (mk->mk_users && mk->mk_users->keys.nr_leaves_on_tree != 0) {
|
||||
if (all_users)
|
||||
err = keyring_clear(mk->mk_users);
|
||||
else
|
||||
if (!list_empty(&mk->mk_users)) {
|
||||
if (all_users) {
|
||||
clear_mk_users(mk);
|
||||
err = 0;
|
||||
} else {
|
||||
err = remove_master_key_user(mk);
|
||||
}
|
||||
if (err) {
|
||||
up_write(&mk->mk_sem);
|
||||
goto out_put_key;
|
||||
}
|
||||
if (mk->mk_users->keys.nr_leaves_on_tree != 0) {
|
||||
if (!list_empty(&mk->mk_users)) {
|
||||
/*
|
||||
* Other users have still added the key too. We removed
|
||||
* the current user's claim to the key, but we still
|
||||
@@ -1193,6 +1168,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
|
||||
struct super_block *sb = file_inode(filp)->i_sb;
|
||||
struct fscrypt_get_key_status_arg arg;
|
||||
struct fscrypt_master_key *mk;
|
||||
kuid_t uid;
|
||||
const struct fscrypt_master_key_user *mk_user;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&arg, uarg, sizeof(arg)))
|
||||
@@ -1225,19 +1202,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
|
||||
}
|
||||
|
||||
arg.status = FSCRYPT_KEY_STATUS_PRESENT;
|
||||
if (mk->mk_users) {
|
||||
struct key *mk_user;
|
||||
|
||||
arg.user_count = mk->mk_users->keys.nr_leaves_on_tree;
|
||||
mk_user = find_master_key_user(mk);
|
||||
if (!IS_ERR(mk_user)) {
|
||||
uid = current_fsuid();
|
||||
list_for_each_entry(mk_user, &mk->mk_users, link) {
|
||||
arg.user_count++;
|
||||
if (uid_eq(mk_user->uid, uid))
|
||||
arg.status_flags |=
|
||||
FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF;
|
||||
key_put(mk_user);
|
||||
} else if (mk_user != ERR_PTR(-ENOKEY)) {
|
||||
err = PTR_ERR(mk_user);
|
||||
goto out_release_key;
|
||||
}
|
||||
}
|
||||
err = 0;
|
||||
out_release_key:
|
||||
|
||||
@@ -163,13 +163,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
|
||||
tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
/*
|
||||
* Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
|
||||
* I.e., here we publish ->tfm with a RELEASE barrier so that
|
||||
* concurrent tasks can ACQUIRE it. Note that this concurrency is only
|
||||
* possible for per-mode keys, not for per-file keys.
|
||||
*/
|
||||
smp_store_release(&prep_key->tfm, tfm);
|
||||
prep_key->tfm = tfm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -190,9 +184,37 @@ int fscrypt_set_per_file_enc_key(struct fscrypt_inode_info *ci,
|
||||
return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the fscrypt_prepared_key (if any) for a particular (mk, hkdf_context,
|
||||
* mode_num, data_unit_bits, inlinecrypt) combination.
|
||||
*
|
||||
* The caller must hold ->mk_sem for reading and ->mk_present must be true,
|
||||
* ensuring that ->mk_mode_keys is still append-only.
|
||||
*/
|
||||
static struct fscrypt_prepared_key *
|
||||
fscrypt_find_mode_key(struct fscrypt_master_key *mk, u8 hkdf_context,
|
||||
u8 mode_num, const struct fscrypt_inode_info *ci)
|
||||
{
|
||||
struct fscrypt_mode_key *node;
|
||||
|
||||
/*
|
||||
* The RCU read lock here is used only to synchronize with concurrent
|
||||
* list_add_tail_rcu(). Concurrent deletions are impossible here, so
|
||||
* returning a pointer to a node without taking any refcount is safe.
|
||||
*/
|
||||
guard(rcu)();
|
||||
list_for_each_entry_rcu(node, &mk->mk_mode_keys, link) {
|
||||
if (node->hkdf_context == hkdf_context &&
|
||||
node->mode_num == mode_num &&
|
||||
node->data_unit_bits == ci->ci_data_unit_bits &&
|
||||
fscrypt_is_key_prepared(&node->key, ci))
|
||||
return &node->key;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
|
||||
struct fscrypt_master_key *mk,
|
||||
struct fscrypt_prepared_key *keys,
|
||||
u8 hkdf_context, bool include_fs_uuid)
|
||||
{
|
||||
const struct inode *inode = ci->ci_inode;
|
||||
@@ -200,7 +222,8 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
|
||||
struct fscrypt_mode *mode = ci->ci_mode;
|
||||
const u8 mode_num = mode - fscrypt_modes;
|
||||
struct fscrypt_prepared_key *prep_key;
|
||||
u8 mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
|
||||
struct fscrypt_mode_key *new_node;
|
||||
u8 raw_mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
|
||||
u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
|
||||
unsigned int hkdf_infolen = 0;
|
||||
bool use_hw_wrapped_key = false;
|
||||
@@ -223,48 +246,56 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
|
||||
use_hw_wrapped_key = true;
|
||||
}
|
||||
|
||||
prep_key = &keys[mode_num];
|
||||
if (fscrypt_is_key_prepared(prep_key, ci)) {
|
||||
prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
|
||||
if (prep_key) {
|
||||
ci->ci_enc_key = *prep_key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&fscrypt_mode_key_setup_mutex);
|
||||
guard(mutex)(&fscrypt_mode_key_setup_mutex);
|
||||
|
||||
if (fscrypt_is_key_prepared(prep_key, ci))
|
||||
goto done_unlock;
|
||||
prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
|
||||
if (prep_key) {
|
||||
ci->ci_enc_key = *prep_key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_node = kzalloc_obj(*new_node);
|
||||
if (!new_node)
|
||||
return -ENOMEM;
|
||||
new_node->hkdf_context = hkdf_context;
|
||||
new_node->mode_num = mode_num;
|
||||
new_node->data_unit_bits = ci->ci_data_unit_bits;
|
||||
prep_key = &new_node->key;
|
||||
|
||||
if (use_hw_wrapped_key) {
|
||||
err = fscrypt_prepare_inline_crypt_key(prep_key,
|
||||
mk->mk_secret.bytes,
|
||||
mk->mk_secret.size, true,
|
||||
ci);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
goto done_unlock;
|
||||
} else {
|
||||
static_assert(sizeof(mode_num) == 1);
|
||||
static_assert(sizeof(sb->s_uuid) == 16);
|
||||
static_assert(sizeof(hkdf_info) == 17);
|
||||
hkdf_info[hkdf_infolen++] = mode_num;
|
||||
if (include_fs_uuid) {
|
||||
memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
|
||||
sizeof(sb->s_uuid));
|
||||
hkdf_infolen += sizeof(sb->s_uuid);
|
||||
}
|
||||
fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context,
|
||||
hkdf_info, hkdf_infolen, raw_mode_key,
|
||||
mode->keysize);
|
||||
err = fscrypt_prepare_key(prep_key, raw_mode_key, ci);
|
||||
memzero_explicit(raw_mode_key, mode->keysize);
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(sizeof(mode_num) != 1);
|
||||
BUILD_BUG_ON(sizeof(sb->s_uuid) != 16);
|
||||
BUILD_BUG_ON(sizeof(hkdf_info) != 17);
|
||||
hkdf_info[hkdf_infolen++] = mode_num;
|
||||
if (include_fs_uuid) {
|
||||
memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
|
||||
sizeof(sb->s_uuid));
|
||||
hkdf_infolen += sizeof(sb->s_uuid);
|
||||
if (err) {
|
||||
kfree(new_node);
|
||||
return err;
|
||||
}
|
||||
fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context, hkdf_info,
|
||||
hkdf_infolen, mode_key, mode->keysize);
|
||||
err = fscrypt_prepare_key(prep_key, mode_key, ci);
|
||||
memzero_explicit(mode_key, mode->keysize);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
done_unlock:
|
||||
list_add_tail_rcu(&new_node->link, &mk->mk_mode_keys);
|
||||
ci->ci_enc_key = *prep_key;
|
||||
err = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&fscrypt_mode_key_setup_mutex);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -311,8 +342,8 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_inode_info *ci,
|
||||
{
|
||||
int err;
|
||||
|
||||
err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys,
|
||||
HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true);
|
||||
err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_IV_INO_LBLK_32_KEY,
|
||||
true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -364,8 +395,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
|
||||
* encryption key. This ensures that the master key is
|
||||
* consistently used only for HKDF, avoiding key reuse issues.
|
||||
*/
|
||||
err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys,
|
||||
HKDF_CONTEXT_DIRECT_KEY, false);
|
||||
err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_DIRECT_KEY,
|
||||
false);
|
||||
} else if (ci->ci_policy.v2.flags &
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
|
||||
/*
|
||||
@@ -374,9 +405,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
|
||||
* the IVs. This format is optimized for use with inline
|
||||
* encryption hardware compliant with the UFS standard.
|
||||
*/
|
||||
err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
|
||||
HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
|
||||
true);
|
||||
err = setup_per_mode_enc_key(
|
||||
ci, mk, HKDF_CONTEXT_IV_INO_LBLK_64_KEY, true);
|
||||
} else if (ci->ci_policy.v2.flags &
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
|
||||
err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk);
|
||||
|
||||
Reference in New Issue
Block a user