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:
Linus Torvalds
2026-06-27 09:20:16 -07:00
4 changed files with 233 additions and 216 deletions

View File

@@ -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;

View File

@@ -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:

View File

@@ -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:

View File

@@ -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);