Merge patch series "Move fscrypt and fsverity info out of struct inode"
Eric Biggers <ebiggers@kernel.org> says: This is a cleaned-up implementation of moving the i_crypt_info and i_verity_info pointers out of 'struct inode' and into the fs-specific part of the inode, as proposed previously by Christian at https://lore.kernel.org/r/20250723-work-inode-fscrypt-v4-0-c8e11488a0e6@kernel.org/ The high-level concept is still the same: fs/crypto/ and fs/verity/ locate the pointer by adding an offset to the address of struct inode. The offset is retrieved from fscrypt_operations or fsverity_operations. I've cleaned up a lot of the details, including: - Grouped changes into patches differently - Rewrote commit messages and comments to be clearer - Adjusted code formatting to be consistent with existing code - Removed unneeded #ifdefs - Improved choice and location of VFS_WARN_ON_ONCE() statements - Added missing kerneldoc for ubifs_inode::i_crypt_info - Moved field initialization to init_once functions when they exist - Improved ceph offset calculation and removed unneeded static_asserts - fsverity_get_info() now checks IS_VERITY() instead of v_ops - fscrypt_put_encryption_info() no longer checks IS_ENCRYPTED(), since I no longer think it's actually correct there. - verity_data_blocks() now keeps doing a raw dereference - Dropped fscrypt_set_inode_info() - Renamed some functions - Do offset calculation using int, so we don't rely on unsigned overflow - And more. * patches from https://lore.kernel.org/20250810075706.172910-1-ebiggers@kernel.org: fsverity: check IS_VERITY() in fsverity_cleanup_inode() fs: remove inode::i_verity_info btrfs: move verity info pointer to fs-specific part of inode f2fs: move verity info pointer to fs-specific part of inode ext4: move verity info pointer to fs-specific part of inode fsverity: add support for info in fs-specific part of inode fs: remove inode::i_crypt_info ceph: move crypt info pointer to fs-specific part of inode ubifs: move crypt info pointer to fs-specific part of inode f2fs: move crypt info pointer to fs-specific part of inode ext4: move crypt info pointer to fs-specific part of inode fscrypt: add support for info in fs-specific part of inode fscrypt: replace raw loads of info pointer with helper function Link: https://lore.kernel.org/20250810075706.172910-1-ebiggers@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
commit
f0883b9c39
|
@ -338,6 +338,11 @@ struct btrfs_inode {
|
|||
struct list_head delayed_iput;
|
||||
|
||||
struct rw_semaphore i_mmap_lock;
|
||||
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
struct fsverity_info *i_verity_info;
|
||||
#endif
|
||||
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
|
||||
|
|
|
@ -7961,6 +7961,9 @@ static void init_once(void *foo)
|
|||
struct btrfs_inode *ei = foo;
|
||||
|
||||
inode_init_once(&ei->vfs_inode);
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
ei->i_verity_info = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __cold btrfs_destroy_cachep(void)
|
||||
|
|
|
@ -802,6 +802,8 @@ static int btrfs_write_merkle_tree_block(struct inode *inode, const void *buf,
|
|||
}
|
||||
|
||||
const struct fsverity_operations btrfs_verityops = {
|
||||
.inode_info_offs = (int)offsetof(struct btrfs_inode, i_verity_info) -
|
||||
(int)offsetof(struct btrfs_inode, vfs_inode),
|
||||
.begin_enable_verity = btrfs_begin_enable_verity,
|
||||
.end_enable_verity = btrfs_end_enable_verity,
|
||||
.get_verity_descriptor = btrfs_get_verity_descriptor,
|
||||
|
|
|
@ -133,6 +133,8 @@ static const union fscrypt_policy *ceph_get_dummy_policy(struct super_block *sb)
|
|||
}
|
||||
|
||||
static struct fscrypt_operations ceph_fscrypt_ops = {
|
||||
.inode_info_offs = (int)offsetof(struct ceph_inode_info, i_crypt_info) -
|
||||
(int)offsetof(struct ceph_inode_info, netfs.inode),
|
||||
.needs_bounce_pages = 1,
|
||||
.get_context = ceph_crypt_get_context,
|
||||
.set_context = ceph_crypt_set_context,
|
||||
|
|
|
@ -665,6 +665,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
|
|||
ci->i_work_mask = 0;
|
||||
memset(&ci->i_btime, '\0', sizeof(ci->i_btime));
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
ci->i_crypt_info = NULL;
|
||||
ci->fscrypt_auth = NULL;
|
||||
ci->fscrypt_auth_len = 0;
|
||||
#endif
|
||||
|
|
|
@ -463,6 +463,7 @@ struct ceph_inode_info {
|
|||
unsigned long i_work_mask;
|
||||
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
struct fscrypt_inode_info *i_crypt_info;
|
||||
u32 fscrypt_auth_len;
|
||||
u32 fscrypt_file_len;
|
||||
u8 *fscrypt_auth;
|
||||
|
|
|
@ -113,7 +113,7 @@ out:
|
|||
int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
|
||||
sector_t pblk, unsigned int len)
|
||||
{
|
||||
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
|
||||
const unsigned int du_bits = ci->ci_data_unit_bits;
|
||||
const unsigned int du_size = 1U << du_bits;
|
||||
const unsigned int du_per_page_bits = PAGE_SHIFT - du_bits;
|
||||
|
|
|
@ -173,7 +173,7 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
|
|||
size_t len, size_t offs, gfp_t gfp_flags)
|
||||
{
|
||||
const struct inode *inode = folio->mapping->host;
|
||||
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
|
||||
const unsigned int du_bits = ci->ci_data_unit_bits;
|
||||
const unsigned int du_size = 1U << du_bits;
|
||||
struct page *ciphertext_page;
|
||||
|
@ -232,8 +232,9 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
|
|||
{
|
||||
if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units))
|
||||
return -EOPNOTSUPP;
|
||||
return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_ENCRYPT,
|
||||
lblk_num, page, page, len, offs);
|
||||
return fscrypt_crypt_data_unit(fscrypt_get_inode_info_raw(inode),
|
||||
FS_ENCRYPT, lblk_num, page, page, len,
|
||||
offs);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
|
||||
|
||||
|
@ -255,7 +256,7 @@ int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
|
|||
size_t offs)
|
||||
{
|
||||
const struct inode *inode = folio->mapping->host;
|
||||
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
|
||||
const unsigned int du_bits = ci->ci_data_unit_bits;
|
||||
const unsigned int du_size = 1U << du_bits;
|
||||
u64 index = ((u64)folio->index << (PAGE_SHIFT - du_bits)) +
|
||||
|
@ -305,8 +306,9 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
|
|||
{
|
||||
if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units))
|
||||
return -EOPNOTSUPP;
|
||||
return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_DECRYPT,
|
||||
lblk_num, page, page, len, offs);
|
||||
return fscrypt_crypt_data_unit(fscrypt_get_inode_info_raw(inode),
|
||||
FS_DECRYPT, lblk_num, page, page, len,
|
||||
offs);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
|||
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
||||
u8 *out, unsigned int olen)
|
||||
{
|
||||
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
|
||||
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
union fscrypt_iv iv;
|
||||
|
@ -138,7 +138,7 @@ static int fname_decrypt(const struct inode *inode,
|
|||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
{
|
||||
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
|
||||
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
union fscrypt_iv iv;
|
||||
|
@ -274,8 +274,9 @@ bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
|||
bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
|
||||
u32 max_len, u32 *encrypted_len_ret)
|
||||
{
|
||||
return __fscrypt_fname_encrypted_size(&inode->i_crypt_info->ci_policy,
|
||||
orig_len, max_len,
|
||||
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
|
||||
|
||||
return __fscrypt_fname_encrypted_size(&ci->ci_policy, orig_len, max_len,
|
||||
encrypted_len_ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_fname_encrypted_size);
|
||||
|
@ -543,7 +544,7 @@ EXPORT_SYMBOL_GPL(fscrypt_match_name);
|
|||
*/
|
||||
u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name)
|
||||
{
|
||||
const struct fscrypt_inode_info *ci = dir->i_crypt_info;
|
||||
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(dir);
|
||||
|
||||
WARN_ON_ONCE(!ci->ci_dirhash_key_initialized);
|
||||
|
||||
|
|
|
@ -249,8 +249,8 @@ struct fscrypt_prepared_key {
|
|||
* fscrypt_inode_info - the "encryption key" for an inode
|
||||
*
|
||||
* When an encrypted file's key is made available, an instance of this struct is
|
||||
* allocated and stored in ->i_crypt_info. Once created, it remains until the
|
||||
* inode is evicted.
|
||||
* allocated and a pointer to it is stored in the file's in-memory inode. Once
|
||||
* created, it remains until the inode is evicted.
|
||||
*/
|
||||
struct fscrypt_inode_info {
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ int fscrypt_prepare_setflags(struct inode *inode,
|
|||
err = fscrypt_require_key(inode);
|
||||
if (err)
|
||||
return err;
|
||||
ci = inode->i_crypt_info;
|
||||
ci = fscrypt_get_inode_info_raw(inode);
|
||||
if (ci->ci_policy.version != FSCRYPT_POLICY_V2)
|
||||
return -EINVAL;
|
||||
mk = ci->ci_master_key;
|
||||
|
|
|
@ -263,7 +263,7 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
|
|||
|
||||
bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
|
||||
{
|
||||
return inode->i_crypt_info->ci_inlinecrypt;
|
||||
return fscrypt_get_inode_info_raw(inode)->ci_inlinecrypt;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_inode_uses_inline_crypto);
|
||||
|
||||
|
@ -307,7 +307,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
|
|||
|
||||
if (!fscrypt_inode_uses_inline_crypto(inode))
|
||||
return;
|
||||
ci = inode->i_crypt_info;
|
||||
ci = fscrypt_get_inode_info_raw(inode);
|
||||
|
||||
fscrypt_generate_dun(ci, first_lblk, dun);
|
||||
bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask);
|
||||
|
@ -385,22 +385,24 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
|
|||
u64 next_lblk)
|
||||
{
|
||||
const struct bio_crypt_ctx *bc = bio->bi_crypt_context;
|
||||
const struct fscrypt_inode_info *ci;
|
||||
u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
|
||||
|
||||
if (!!bc != fscrypt_inode_uses_inline_crypto(inode))
|
||||
return false;
|
||||
if (!bc)
|
||||
return true;
|
||||
ci = fscrypt_get_inode_info_raw(inode);
|
||||
|
||||
/*
|
||||
* Comparing the key pointers is good enough, as all I/O for each key
|
||||
* uses the same pointer. I.e., there's currently no need to support
|
||||
* merging requests where the keys are the same but the pointers differ.
|
||||
*/
|
||||
if (bc->bc_key != inode->i_crypt_info->ci_enc_key.blk_key)
|
||||
if (bc->bc_key != ci->ci_enc_key.blk_key)
|
||||
return false;
|
||||
|
||||
fscrypt_generate_dun(inode->i_crypt_info, next_lblk, next_dun);
|
||||
fscrypt_generate_dun(ci, next_lblk, next_dun);
|
||||
return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio);
|
||||
|
@ -502,7 +504,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
|
|||
if (nr_blocks <= 1)
|
||||
return nr_blocks;
|
||||
|
||||
ci = inode->i_crypt_info;
|
||||
ci = fscrypt_get_inode_info_raw(inode);
|
||||
if (!(fscrypt_policy_flags(&ci->ci_policy) &
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32))
|
||||
return nr_blocks;
|
||||
|
|
|
@ -642,15 +642,16 @@ fscrypt_setup_encryption_info(struct inode *inode,
|
|||
goto out;
|
||||
|
||||
/*
|
||||
* For existing inodes, multiple tasks may race to set ->i_crypt_info.
|
||||
* So use cmpxchg_release(). This pairs with the smp_load_acquire() in
|
||||
* fscrypt_get_inode_info(). I.e., here we publish ->i_crypt_info with
|
||||
* a RELEASE barrier so that other tasks can ACQUIRE it.
|
||||
* For existing inodes, multiple tasks may race to set the inode's
|
||||
* fscrypt info pointer. So use cmpxchg_release(). This pairs with the
|
||||
* smp_load_acquire() in fscrypt_get_inode_info(). I.e., publish the
|
||||
* pointer with a RELEASE barrier so that other tasks can ACQUIRE it.
|
||||
*/
|
||||
if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL) {
|
||||
if (cmpxchg_release(fscrypt_inode_info_addr(inode), NULL, crypt_info) ==
|
||||
NULL) {
|
||||
/*
|
||||
* We won the race and set ->i_crypt_info to our crypt_info.
|
||||
* Now link it into the master key's inode list.
|
||||
* We won the race and set the inode's fscrypt info to our
|
||||
* crypt_info. Now link it into the master key's inode list.
|
||||
*/
|
||||
if (mk) {
|
||||
crypt_info->ci_master_key = mk;
|
||||
|
@ -681,13 +682,13 @@ out:
|
|||
* %false unless the operation being performed is needed in
|
||||
* order for files (or directories) to be deleted.
|
||||
*
|
||||
* Set up ->i_crypt_info, if it hasn't already been done.
|
||||
* Set up the inode's encryption key, if it hasn't already been done.
|
||||
*
|
||||
* Note: unless ->i_crypt_info is already set, this isn't %GFP_NOFS-safe. So
|
||||
* Note: unless the key setup was already done, this isn't %GFP_NOFS-safe. So
|
||||
* generally this shouldn't be called from within a filesystem transaction.
|
||||
*
|
||||
* Return: 0 if ->i_crypt_info was set or was already set, *or* if the
|
||||
* encryption key is unavailable. (Use fscrypt_has_encryption_key() to
|
||||
* Return: 0 if the key is now set up, *or* if it couldn't be set up because the
|
||||
* needed master key is absent. (Use fscrypt_has_encryption_key() to
|
||||
* distinguish these cases.) Also can return another -errno code.
|
||||
*/
|
||||
int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported)
|
||||
|
@ -741,9 +742,9 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported)
|
|||
* ->i_ino doesn't need to be set yet.
|
||||
* @encrypt_ret: (output) set to %true if the new inode will be encrypted
|
||||
*
|
||||
* If the directory is encrypted, set up its ->i_crypt_info in preparation for
|
||||
* If the directory is encrypted, set up its encryption key in preparation for
|
||||
* encrypting the name of the new file. Also, if the new inode will be
|
||||
* encrypted, set up its ->i_crypt_info and set *encrypt_ret=true.
|
||||
* encrypted, set up its encryption key too and set *encrypt_ret=true.
|
||||
*
|
||||
* This isn't %GFP_NOFS-safe, and therefore it should be called before starting
|
||||
* any filesystem transaction to create the inode. For this reason, ->i_ino
|
||||
|
@ -752,8 +753,8 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported)
|
|||
* This doesn't persist the new inode's encryption context. That still needs to
|
||||
* be done later by calling fscrypt_set_context().
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the encryption key is missing, or another
|
||||
* -errno code
|
||||
* Return: 0 on success, -ENOKEY if a key needs to be set up for @dir or @inode
|
||||
* but the needed master key is absent, or another -errno code
|
||||
*/
|
||||
int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
|
||||
bool *encrypt_ret)
|
||||
|
@ -800,8 +801,16 @@ EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode);
|
|||
*/
|
||||
void fscrypt_put_encryption_info(struct inode *inode)
|
||||
{
|
||||
put_crypt_info(inode->i_crypt_info);
|
||||
inode->i_crypt_info = NULL;
|
||||
/*
|
||||
* Ideally we'd start with a lightweight IS_ENCRYPTED() check here
|
||||
* before proceeding to retrieve and check the pointer. However, during
|
||||
* inode creation, the fscrypt_inode_info is set before S_ENCRYPTED. If
|
||||
* an error occurs, it needs to be cleaned up regardless.
|
||||
*/
|
||||
struct fscrypt_inode_info **ci_addr = fscrypt_inode_info_addr(inode);
|
||||
|
||||
put_crypt_info(*ci_addr);
|
||||
*ci_addr = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_put_encryption_info);
|
||||
|
||||
|
|
|
@ -727,7 +727,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir)
|
|||
err = fscrypt_require_key(dir);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return &dir->i_crypt_info->ci_policy;
|
||||
return &fscrypt_get_inode_info_raw(dir)->ci_policy;
|
||||
}
|
||||
|
||||
return fscrypt_get_dummy_policy(dir->i_sb);
|
||||
|
@ -746,7 +746,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir)
|
|||
*/
|
||||
int fscrypt_context_for_new_inode(void *ctx, struct inode *inode)
|
||||
{
|
||||
struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
|
||||
|
||||
BUILD_BUG_ON(sizeof(union fscrypt_context) !=
|
||||
FSCRYPT_SET_CONTEXT_MAX_SIZE);
|
||||
|
@ -771,7 +771,7 @@ EXPORT_SYMBOL_GPL(fscrypt_context_for_new_inode);
|
|||
*/
|
||||
int fscrypt_set_context(struct inode *inode, void *fs_data)
|
||||
{
|
||||
struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
struct fscrypt_inode_info *ci;
|
||||
union fscrypt_context ctx;
|
||||
int ctxsize;
|
||||
|
||||
|
@ -783,6 +783,7 @@ int fscrypt_set_context(struct inode *inode, void *fs_data)
|
|||
* This may be the first time the inode number is available, so do any
|
||||
* delayed key setup that requires the inode number.
|
||||
*/
|
||||
ci = fscrypt_get_inode_info_raw(inode);
|
||||
if (ci->ci_policy.version == FSCRYPT_POLICY_V2 &&
|
||||
(ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32))
|
||||
fscrypt_hash_inode_number(ci, ci->ci_master_key);
|
||||
|
|
|
@ -227,6 +227,8 @@ static bool ext4_has_stable_inodes(struct super_block *sb)
|
|||
}
|
||||
|
||||
const struct fscrypt_operations ext4_cryptops = {
|
||||
.inode_info_offs = (int)offsetof(struct ext4_inode_info, i_crypt_info) -
|
||||
(int)offsetof(struct ext4_inode_info, vfs_inode),
|
||||
.needs_bounce_pages = 1,
|
||||
.has_32bit_inodes = 1,
|
||||
.supports_subblock_data_units = 1,
|
||||
|
|
|
@ -1182,6 +1182,14 @@ struct ext4_inode_info {
|
|||
__u32 i_csum_seed;
|
||||
|
||||
kprojid_t i_projid;
|
||||
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
struct fscrypt_inode_info *i_crypt_info;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
struct fsverity_info *i_verity_info;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -1470,6 +1470,12 @@ static void init_once(void *foo)
|
|||
init_rwsem(&ei->i_data_sem);
|
||||
inode_init_once(&ei->vfs_inode);
|
||||
ext4_fc_init_inode(&ei->vfs_inode);
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
ei->i_crypt_info = NULL;
|
||||
#endif
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
ei->i_verity_info = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __init init_inodecache(void)
|
||||
|
|
|
@ -389,6 +389,8 @@ static int ext4_write_merkle_tree_block(struct inode *inode, const void *buf,
|
|||
}
|
||||
|
||||
const struct fsverity_operations ext4_verityops = {
|
||||
.inode_info_offs = (int)offsetof(struct ext4_inode_info, i_verity_info) -
|
||||
(int)offsetof(struct ext4_inode_info, vfs_inode),
|
||||
.begin_enable_verity = ext4_begin_enable_verity,
|
||||
.end_enable_verity = ext4_end_enable_verity,
|
||||
.get_verity_descriptor = ext4_get_verity_descriptor,
|
||||
|
|
|
@ -907,6 +907,12 @@ struct f2fs_inode_info {
|
|||
|
||||
unsigned int atomic_write_cnt;
|
||||
loff_t original_i_size; /* original i_size before atomic write */
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
struct fscrypt_inode_info *i_crypt_info; /* filesystem encryption info */
|
||||
#endif
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
struct fsverity_info *i_verity_info; /* filesystem verity info */
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void get_read_extent_info(struct extent_info *ext,
|
||||
|
|
|
@ -480,6 +480,12 @@ static void init_once(void *foo)
|
|||
struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
|
||||
|
||||
inode_init_once(&fi->vfs_inode);
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
fi->i_crypt_info = NULL;
|
||||
#endif
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
fi->i_verity_info = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
|
@ -3570,6 +3576,8 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,
|
|||
}
|
||||
|
||||
static const struct fscrypt_operations f2fs_cryptops = {
|
||||
.inode_info_offs = (int)offsetof(struct f2fs_inode_info, i_crypt_info) -
|
||||
(int)offsetof(struct f2fs_inode_info, vfs_inode),
|
||||
.needs_bounce_pages = 1,
|
||||
.has_32bit_inodes = 1,
|
||||
.supports_subblock_data_units = 1,
|
||||
|
@ -3581,7 +3589,7 @@ static const struct fscrypt_operations f2fs_cryptops = {
|
|||
.has_stable_inodes = f2fs_has_stable_inodes,
|
||||
.get_devices = f2fs_get_devices,
|
||||
};
|
||||
#endif
|
||||
#endif /* CONFIG_FS_ENCRYPTION */
|
||||
|
||||
static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
|
||||
u64 ino, u32 generation)
|
||||
|
|
|
@ -287,6 +287,8 @@ static int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf,
|
|||
}
|
||||
|
||||
const struct fsverity_operations f2fs_verityops = {
|
||||
.inode_info_offs = (int)offsetof(struct f2fs_inode_info, i_verity_info) -
|
||||
(int)offsetof(struct f2fs_inode_info, vfs_inode),
|
||||
.begin_enable_verity = f2fs_begin_enable_verity,
|
||||
.end_enable_verity = f2fs_end_enable_verity,
|
||||
.get_verity_descriptor = f2fs_get_verity_descriptor,
|
||||
|
|
|
@ -88,6 +88,8 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
|||
}
|
||||
|
||||
const struct fscrypt_operations ubifs_crypt_operations = {
|
||||
.inode_info_offs = (int)offsetof(struct ubifs_inode, i_crypt_info) -
|
||||
(int)offsetof(struct ubifs_inode, vfs_inode),
|
||||
.legacy_key_prefix = "ubifs:",
|
||||
.get_context = ubifs_crypt_get_context,
|
||||
.set_context = ubifs_crypt_set_context,
|
||||
|
|
|
@ -365,6 +365,7 @@ struct ubifs_gced_idx_leb {
|
|||
* @read_in_a_row: number of consecutive pages read in a row (for bulk read)
|
||||
* @data_len: length of the data attached to the inode
|
||||
* @data: inode's data
|
||||
* @i_crypt_info: inode's fscrypt information
|
||||
*
|
||||
* @ui_mutex exists for two main reasons. At first it prevents inodes from
|
||||
* being written back while UBIFS changing them, being in the middle of an VFS
|
||||
|
@ -416,6 +417,9 @@ struct ubifs_inode {
|
|||
pgoff_t read_in_a_row;
|
||||
int data_len;
|
||||
void *data;
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
struct fscrypt_inode_info *i_crypt_info;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -284,9 +284,9 @@ static int enable_verity(struct file *filp,
|
|||
/* Successfully enabled verity */
|
||||
|
||||
/*
|
||||
* Readers can start using ->i_verity_info immediately, so it
|
||||
* can't be rolled back once set. So don't set it until just
|
||||
* after the filesystem has successfully enabled verity.
|
||||
* Readers can start using the inode's verity info immediately,
|
||||
* so it can't be rolled back once set. So don't set it until
|
||||
* just after the filesystem has successfully enabled verity.
|
||||
*/
|
||||
fsverity_set_info(inode, vi);
|
||||
}
|
||||
|
|
|
@ -63,10 +63,11 @@ struct merkle_tree_params {
|
|||
* fsverity_info - cached verity metadata for an inode
|
||||
*
|
||||
* When a verity file is first opened, an instance of this struct is allocated
|
||||
* and stored in ->i_verity_info; it remains until the inode is evicted. It
|
||||
* caches information about the Merkle tree that's needed to efficiently verify
|
||||
* data read from the file. It also caches the file digest. The Merkle tree
|
||||
* pages themselves are not cached here, but the filesystem may cache them.
|
||||
* and a pointer to it is stored in the file's in-memory inode. It remains
|
||||
* until the inode is evicted. It caches information about the Merkle tree
|
||||
* that's needed to efficiently verify data read from the file. It also caches
|
||||
* the file digest. The Merkle tree pages themselves are not cached here, but
|
||||
* the filesystem may cache them.
|
||||
*/
|
||||
struct fsverity_info {
|
||||
struct merkle_tree_params tree_params;
|
||||
|
|
|
@ -244,17 +244,17 @@ fail:
|
|||
void fsverity_set_info(struct inode *inode, struct fsverity_info *vi)
|
||||
{
|
||||
/*
|
||||
* Multiple tasks may race to set ->i_verity_info, so use
|
||||
* cmpxchg_release(). This pairs with the smp_load_acquire() in
|
||||
* fsverity_get_info(). I.e., here we publish ->i_verity_info with a
|
||||
* RELEASE barrier so that other tasks can ACQUIRE it.
|
||||
* Multiple tasks may race to set the inode's verity info pointer, so
|
||||
* use cmpxchg_release(). This pairs with the smp_load_acquire() in
|
||||
* fsverity_get_info(). I.e., publish the pointer with a RELEASE
|
||||
* barrier so that other tasks can ACQUIRE it.
|
||||
*/
|
||||
if (cmpxchg_release(&inode->i_verity_info, NULL, vi) != NULL) {
|
||||
/* Lost the race, so free the fsverity_info we allocated. */
|
||||
if (cmpxchg_release(fsverity_info_addr(inode), NULL, vi) != NULL) {
|
||||
/* Lost the race, so free the verity info we allocated. */
|
||||
fsverity_free_info(vi);
|
||||
/*
|
||||
* Afterwards, the caller may access ->i_verity_info directly,
|
||||
* so make sure to ACQUIRE the winning fsverity_info.
|
||||
* Afterwards, the caller may access the inode's verity info
|
||||
* directly, so make sure to ACQUIRE the winning verity info.
|
||||
*/
|
||||
(void)fsverity_get_info(inode);
|
||||
}
|
||||
|
@ -350,7 +350,6 @@ int fsverity_get_descriptor(struct inode *inode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure the inode has an ->i_verity_info */
|
||||
static int ensure_verity_info(struct inode *inode)
|
||||
{
|
||||
struct fsverity_info *vi = fsverity_get_info(inode);
|
||||
|
@ -395,8 +394,10 @@ EXPORT_SYMBOL_GPL(__fsverity_prepare_setattr);
|
|||
|
||||
void __fsverity_cleanup_inode(struct inode *inode)
|
||||
{
|
||||
fsverity_free_info(inode->i_verity_info);
|
||||
inode->i_verity_info = NULL;
|
||||
struct fsverity_info **vi_addr = fsverity_info_addr(inode);
|
||||
|
||||
fsverity_free_info(*vi_addr);
|
||||
*vi_addr = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fsverity_cleanup_inode);
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ verify_data_blocks(struct folio *data_folio, size_t len, size_t offset,
|
|||
unsigned long max_ra_pages)
|
||||
{
|
||||
struct inode *inode = data_folio->mapping->host;
|
||||
struct fsverity_info *vi = inode->i_verity_info;
|
||||
struct fsverity_info *vi = *fsverity_info_addr(inode);
|
||||
const unsigned int block_size = vi->tree_params.block_size;
|
||||
u64 pos = (u64)data_folio->index << PAGE_SHIFT;
|
||||
|
||||
|
|
|
@ -72,9 +72,7 @@ struct swap_info_struct;
|
|||
struct seq_file;
|
||||
struct workqueue_struct;
|
||||
struct iov_iter;
|
||||
struct fscrypt_inode_info;
|
||||
struct fscrypt_operations;
|
||||
struct fsverity_info;
|
||||
struct fsverity_operations;
|
||||
struct fsnotify_mark_connector;
|
||||
struct fsnotify_sb_info;
|
||||
|
@ -780,14 +778,6 @@ struct inode {
|
|||
struct fsnotify_mark_connector __rcu *i_fsnotify_marks;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
struct fscrypt_inode_info *i_crypt_info;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
struct fsverity_info *i_verity_info;
|
||||
#endif
|
||||
|
||||
void *i_private; /* fs or device private pointer */
|
||||
} __randomize_layout;
|
||||
|
||||
|
|
|
@ -61,6 +61,12 @@ struct fscrypt_name {
|
|||
|
||||
/* Crypto operations for filesystems */
|
||||
struct fscrypt_operations {
|
||||
/*
|
||||
* The offset of the pointer to struct fscrypt_inode_info in the
|
||||
* filesystem-specific part of the inode, relative to the beginning of
|
||||
* the common part of the inode (the 'struct inode').
|
||||
*/
|
||||
ptrdiff_t inode_info_offs;
|
||||
|
||||
/*
|
||||
* If set, then fs/crypto/ will allocate a global bounce page pool the
|
||||
|
@ -195,16 +201,44 @@ struct fscrypt_operations {
|
|||
int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name,
|
||||
struct dentry *dentry, unsigned int flags);
|
||||
|
||||
/*
|
||||
* Returns the address of the fscrypt info pointer within the
|
||||
* filesystem-specific part of the inode. (To save memory on filesystems that
|
||||
* don't support fscrypt, a field in 'struct inode' itself is no longer used.)
|
||||
*/
|
||||
static inline struct fscrypt_inode_info **
|
||||
fscrypt_inode_info_addr(const struct inode *inode)
|
||||
{
|
||||
VFS_WARN_ON_ONCE(inode->i_sb->s_cop->inode_info_offs == 0);
|
||||
return (void *)inode + inode->i_sb->s_cop->inode_info_offs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the inode's fscrypt info pointer, using a raw dereference. Since this
|
||||
* uses a raw dereference with no memory barrier, it is appropriate to use only
|
||||
* when the caller knows the inode's key setup already happened, resulting in
|
||||
* non-NULL fscrypt info. E.g., the file contents en/decryption functions use
|
||||
* this, since fscrypt_file_open() set up the key.
|
||||
*/
|
||||
static inline struct fscrypt_inode_info *
|
||||
fscrypt_get_inode_info_raw(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_inode_info *ci = *fscrypt_inode_info_addr(inode);
|
||||
|
||||
VFS_WARN_ON_ONCE(ci == NULL);
|
||||
return ci;
|
||||
}
|
||||
|
||||
static inline struct fscrypt_inode_info *
|
||||
fscrypt_get_inode_info(const struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* Pairs with the cmpxchg_release() in fscrypt_setup_encryption_info().
|
||||
* I.e., another task may publish ->i_crypt_info concurrently, executing
|
||||
* a RELEASE barrier. We need to use smp_load_acquire() here to safely
|
||||
* I.e., another task may publish the fscrypt info concurrently,
|
||||
* executing a RELEASE barrier. Use smp_load_acquire() here to safely
|
||||
* ACQUIRE the memory the other task published.
|
||||
*/
|
||||
return smp_load_acquire(&inode->i_crypt_info);
|
||||
return smp_load_acquire(fscrypt_inode_info_addr(inode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,8 +26,16 @@
|
|||
/* Arbitrary limit to bound the kmalloc() size. Can be changed. */
|
||||
#define FS_VERITY_MAX_DESCRIPTOR_SIZE 16384
|
||||
|
||||
struct fsverity_info;
|
||||
|
||||
/* Verity operations for filesystems */
|
||||
struct fsverity_operations {
|
||||
/**
|
||||
* The offset of the pointer to struct fsverity_info in the
|
||||
* filesystem-specific part of the inode, relative to the beginning of
|
||||
* the common part of the inode (the 'struct inode').
|
||||
*/
|
||||
ptrdiff_t inode_info_offs;
|
||||
|
||||
/**
|
||||
* Begin enabling verity on the given file.
|
||||
|
@ -124,15 +132,37 @@ struct fsverity_operations {
|
|||
|
||||
#ifdef CONFIG_FS_VERITY
|
||||
|
||||
/*
|
||||
* Returns the address of the verity info pointer within the filesystem-specific
|
||||
* part of the inode. (To save memory on filesystems that don't support
|
||||
* fsverity, a field in 'struct inode' itself is no longer used.)
|
||||
*/
|
||||
static inline struct fsverity_info **
|
||||
fsverity_info_addr(const struct inode *inode)
|
||||
{
|
||||
VFS_WARN_ON_ONCE(inode->i_sb->s_vop->inode_info_offs == 0);
|
||||
return (void *)inode + inode->i_sb->s_vop->inode_info_offs;
|
||||
}
|
||||
|
||||
static inline struct fsverity_info *fsverity_get_info(const struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* Pairs with the cmpxchg_release() in fsverity_set_info().
|
||||
* I.e., another task may publish ->i_verity_info concurrently,
|
||||
* executing a RELEASE barrier. We need to use smp_load_acquire() here
|
||||
* to safely ACQUIRE the memory the other task published.
|
||||
* Since this function can be called on inodes belonging to filesystems
|
||||
* that don't support fsverity at all, and fsverity_info_addr() doesn't
|
||||
* work on such filesystems, we have to start with an IS_VERITY() check.
|
||||
* Checking IS_VERITY() here is also useful to minimize the overhead of
|
||||
* fsverity_active() on non-verity files.
|
||||
*/
|
||||
return smp_load_acquire(&inode->i_verity_info);
|
||||
if (!IS_VERITY(inode))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Pairs with the cmpxchg_release() in fsverity_set_info(). I.e.,
|
||||
* another task may publish the inode's verity info concurrently,
|
||||
* executing a RELEASE barrier. Use smp_load_acquire() here to safely
|
||||
* ACQUIRE the memory the other task published.
|
||||
*/
|
||||
return smp_load_acquire(fsverity_info_addr(inode));
|
||||
}
|
||||
|
||||
/* enable.c */
|
||||
|
@ -156,12 +186,19 @@ void __fsverity_cleanup_inode(struct inode *inode);
|
|||
* fsverity_cleanup_inode() - free the inode's verity info, if present
|
||||
* @inode: an inode being evicted
|
||||
*
|
||||
* Filesystems must call this on inode eviction to free ->i_verity_info.
|
||||
* Filesystems must call this on inode eviction to free the inode's verity info.
|
||||
*/
|
||||
static inline void fsverity_cleanup_inode(struct inode *inode)
|
||||
{
|
||||
if (inode->i_verity_info)
|
||||
/*
|
||||
* Only IS_VERITY() inodes can have verity info, so start by checking
|
||||
* for IS_VERITY() (which is faster than retrieving the pointer to the
|
||||
* verity info). This minimizes overhead for non-verity inodes.
|
||||
*/
|
||||
if (IS_VERITY(inode))
|
||||
__fsverity_cleanup_inode(inode);
|
||||
else
|
||||
VFS_WARN_ON_ONCE(*fsverity_info_addr(inode) != NULL);
|
||||
}
|
||||
|
||||
/* read_metadata.c */
|
||||
|
@ -267,12 +304,12 @@ static inline bool fsverity_verify_page(struct page *page)
|
|||
* fsverity_active() - do reads from the inode need to go through fs-verity?
|
||||
* @inode: inode to check
|
||||
*
|
||||
* This checks whether ->i_verity_info has been set.
|
||||
* This checks whether the inode's verity info has been set.
|
||||
*
|
||||
* Filesystems call this from ->readahead() to check whether the pages need to
|
||||
* be verified or not. Don't use IS_VERITY() for this purpose; it's subject to
|
||||
* a race condition where the file is being read concurrently with
|
||||
* FS_IOC_ENABLE_VERITY completing. (S_VERITY is set before ->i_verity_info.)
|
||||
* FS_IOC_ENABLE_VERITY completing. (S_VERITY is set before the verity info.)
|
||||
*
|
||||
* Return: true if reads need to go through fs-verity, otherwise false
|
||||
*/
|
||||
|
@ -287,7 +324,7 @@ static inline bool fsverity_active(const struct inode *inode)
|
|||
* @filp: the struct file being set up
|
||||
*
|
||||
* When opening a verity file, deny the open if it is for writing. Otherwise,
|
||||
* set up the inode's ->i_verity_info if not already done.
|
||||
* set up the inode's verity info if not already done.
|
||||
*
|
||||
* When combined with fscrypt, this must be called after fscrypt_file_open().
|
||||
* Otherwise, we won't have the key set up to decrypt the verity metadata.
|
||||
|
|
Loading…
Reference in New Issue