// SPDX-License-Identifier: GPL-2.0
/*
* Filesystem-level keyring for fscrypt
*
* Copyright 2019 Google LLC
*/
/*
* This file implements management of fscrypt master keys in the
* filesystem-level keyring, including the ioctls:
*
* - FS_IOC_ADD_ENCRYPTION_KEY
* - FS_IOC_REMOVE_ENCRYPTION_KEY
* - FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS
* - FS_IOC_GET_ENCRYPTION_KEY_STATUS
*
* See the "User API" section of Documentation/filesystems/fscrypt.rst for more
* information about these ioctls.
*/
#include <asm/unaligned.h>
#include <crypto/skcipher.h>
#include <linux/key-type.h>
#include <linux/random.h>
#include <linux/seq_file.h>
#include "fscrypt_private.h"
/* The master encryption keys for a filesystem (->s_master_keys) */
struct fscrypt_keyring {
/*
* Lock that protects ->key_hashtable. It does *not* protect the
* fscrypt_master_key structs themselves.
*/
spinlock_t lock;
/* Hash table that maps fscrypt_key_specifier to fscrypt_master_key */
struct hlist_head key_hashtable[128];
};
static void wipe_master_key_secret(struct fscrypt_master_key_secret *secret)
{
fscrypt_destroy_hkdf(&secret->hkdf);
memzero_explicit(secret, sizeof(*secret));
}
static void move_master_key_secret(struct fscrypt_master_key_secret *dst,
struct fscrypt_master_key_secret *src)
{
memcpy(dst, src, sizeof(*dst));
memzero_explicit(src, sizeof(*src));
}
static void fscrypt_free_master_key(struct rcu_head *head)
{
struct fscrypt_master_key *mk =
container_of(head, struct fscrypt_master_key, mk_rcu_head);
/*
* The master key secret and any embedded subkeys should have already
* been wiped when the last active reference to the fscrypt_master_key
* struct was dropped; doing it here would be unnecessarily late.
* Nevertheless, use kfree_sensitive() in case anything was missed.
*/
kfree_sensitive(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
* fscrypt_master_key struct itself after an RCU grace period ensures
* that concurrent keyring lookups can no longer find it.
*/
WARN_ON(refcount_read(&mk->mk_active_refs) != 0);
key_put(mk->mk_users);
mk->mk_users = NULL;
call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
}
void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk)
{
struct super_block *sb = mk->mk_sb;
struct fscrypt_keyring *keyring = sb->s_master_keys;
size_t i;
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.
*/
spin_lock(&keyring->lock);
hlist_del_rcu(&mk->mk_node);
spin_unlock(&keyring->lock);
/*
* ->mk_active_refs == 0 implies that ->mk_secret is not present and
* that ->mk_decrypted_inodes is empty.
*/
WARN_ON(is_master_key_secret_present(&mk->mk_secret));
WARN_ON(!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]);
}
memzero_explicit(&mk->mk_ino_hash_key,
sizeof(mk->mk_ino_hash_key));
mk->mk_ino_hash_key_initialized = false;
/* Drop the structural ref associated with the active refs. */
fscrypt_put_master_key(mk);
}
static inline bool valid_key_spec(const struct fscrypt_key_specifier *spec)
{
if (spec->__reserved)
return false;
return master_key_spec_len(spec) != 0;
}
static int fscrypt_user_key_instantiate(struct key *key,
struct key_preparsed_payload *prep)
{
/*
* We just charge FSCRYPT_MAX_KEY_SIZE bytes to the user's key quota for
* each key, regardless of the exact key size. The amount of memory
* actually used is greater than the size of the raw key anyway.
*/
return key_payload_reserve(key, FSCRYPT_MAX_KEY_SIZE);
}
static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
{
seq_puts(m, key->description);
}
/*
* Type of key in ->mk_users. Each key of this type represents a particular
* user who has added a particular master key.
*
* Note that the name of this key type really should be somethi