diff options
author | Eric Biggers <ebiggers@google.com> | 2020-07-22 01:59:19 +0300 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2020-07-22 02:02:13 +0300 |
commit | ab673b987488c4fab7a0bc4824a48211f9d910e3 (patch) | |
tree | 16ec1d6324aa8c0fe60f3d5f45f35b65de43f2ae /include/linux/fscrypt.h | |
parent | 777afe4e68d7ac37711d36098bea65650ec305a0 (diff) | |
download | linux-ab673b987488c4fab7a0bc4824a48211f9d910e3.tar.xz |
fscrypt: use smp_load_acquire() for ->i_crypt_info
Normally smp_store_release() or cmpxchg_release() is paired with
smp_load_acquire(). Sometimes smp_load_acquire() can be replaced with
the more lightweight READ_ONCE(). However, for this to be safe, all the
published memory must only be accessed in a way that involves the
pointer itself. This may not be the case if allocating the object also
involves initializing a static or global variable, for example.
fscrypt_info includes various sub-objects which are internal to and are
allocated by other kernel subsystems such as keyrings and crypto. So by
using READ_ONCE() for ->i_crypt_info, we're relying on internal
implementation details of these other kernel subsystems.
Remove this fragile assumption by using smp_load_acquire() instead.
(Note: I haven't seen any real-world problems here. This change is just
fixing the code to be guaranteed correct and less fragile.)
Fixes: e37a784d8b6a ("fscrypt: use READ_ONCE() to access ->i_crypt_info")
Link: https://lore.kernel.org/r/20200721225920.114347-5-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
Diffstat (limited to 'include/linux/fscrypt.h')
-rw-r--r-- | include/linux/fscrypt.h | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index bb257411365f..991ff8575d0e 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -74,10 +74,15 @@ struct fscrypt_operations { struct request_queue **devs); }; -static inline bool fscrypt_has_encryption_key(const struct inode *inode) +static inline struct fscrypt_info *fscrypt_get_info(const struct inode *inode) { - /* pairs with cmpxchg_release() in fscrypt_get_encryption_info() */ - return READ_ONCE(inode->i_crypt_info) != NULL; + /* + * Pairs with the cmpxchg_release() in fscrypt_get_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 + * ACQUIRE the memory the other task published. + */ + return smp_load_acquire(&inode->i_crypt_info); } /** @@ -234,9 +239,9 @@ static inline void fscrypt_set_ops(struct super_block *sb, } #else /* !CONFIG_FS_ENCRYPTION */ -static inline bool fscrypt_has_encryption_key(const struct inode *inode) +static inline struct fscrypt_info *fscrypt_get_info(const struct inode *inode) { - return false; + return NULL; } static inline bool fscrypt_needs_contents_encryption(const struct inode *inode) @@ -620,6 +625,20 @@ static inline bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode) } /** + * fscrypt_has_encryption_key() - check whether an inode has had its key set up + * @inode: the inode to check + * + * Return: %true if the inode has had its encryption key set up, else %false. + * + * Usually this should be preceded by fscrypt_get_encryption_info() to try to + * set up the key first. + */ +static inline bool fscrypt_has_encryption_key(const struct inode *inode) +{ + return fscrypt_get_info(inode) != NULL; +} + +/** * fscrypt_require_key() - require an inode's encryption key * @inode: the inode we need the key for * |