mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
fscrypt: Add safety checks to non-block-based en/decryption
fscrypt_encrypt_pagecache_blocks(), fscrypt_encrypt_block_inplace(), fscrypt_decrypt_block_inplace() would dereference a NULL fscrypt_inode_info pointer if they were to be called on a file that hasn't been opened yet or on a block-based filesystem. Since they have the ability to report errors anyway, add WARN_ON_ONCE checks for this. Reviewed-by: Christoph Hellwig <hch@lst.de> Link: https://patch.msgid.link/20260713023708.9245-18-ebiggers@kernel.org Signed-off-by: Eric Biggers <ebiggers@kernel.org>
This commit is contained in:
parent
1944540c40
commit
b3aa5b308c
|
|
@ -105,12 +105,17 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
|
|||
struct page *dest_page, unsigned int len,
|
||||
unsigned int offs)
|
||||
{
|
||||
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
union fscrypt_iv iv;
|
||||
struct scatterlist dst, src;
|
||||
int err;
|
||||
|
||||
if (WARN_ON_ONCE(ci == NULL)) /* File hasn't been opened yet? */
|
||||
return -ENOKEY;
|
||||
tfm = ci->ci_enc_key.tfm;
|
||||
if (WARN_ON_ONCE(tfm == NULL)) /* Called on block-based filesystem? */
|
||||
return -ENOKEY;
|
||||
|
||||
if (WARN_ON_ONCE(len <= 0))
|
||||
return -EINVAL;
|
||||
if (WARN_ON_ONCE(len % FSCRYPT_CONTENTS_ALIGNMENT != 0))
|
||||
|
|
@ -118,18 +123,22 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
|
|||
|
||||
fscrypt_generate_iv(&iv, index, ci);
|
||||
|
||||
skcipher_request_set_callback(
|
||||
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
NULL, NULL);
|
||||
sg_init_table(&dst, 1);
|
||||
sg_set_page(&dst, dest_page, len, offs);
|
||||
sg_init_table(&src, 1);
|
||||
sg_set_page(&src, src_page, len, offs);
|
||||
skcipher_request_set_crypt(req, &src, &dst, len, &iv);
|
||||
if (rw == FS_DECRYPT)
|
||||
err = crypto_skcipher_decrypt(req);
|
||||
else
|
||||
err = crypto_skcipher_encrypt(req);
|
||||
{
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG |
|
||||
CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
NULL, NULL);
|
||||
sg_init_table(&dst, 1);
|
||||
sg_set_page(&dst, dest_page, len, offs);
|
||||
sg_init_table(&src, 1);
|
||||
sg_set_page(&src, src_page, len, offs);
|
||||
skcipher_request_set_crypt(req, &src, &dst, len, &iv);
|
||||
if (rw == FS_DECRYPT)
|
||||
err = crypto_skcipher_decrypt(req);
|
||||
else
|
||||
err = crypto_skcipher_encrypt(req);
|
||||
}
|
||||
if (err)
|
||||
fscrypt_err(ci->ci_inode,
|
||||
"%scryption failed for data unit %llu: %d",
|
||||
|
|
@ -153,7 +162,7 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
|
|||
* which the plaintext data was located in the source page. Any other parts of
|
||||
* the bounce page will be left uninitialized.
|
||||
*
|
||||
* This is for use by the filesystem's ->writepages() method.
|
||||
* This is for use by the ->writepages() method of non-block-based filesystems.
|
||||
*
|
||||
* The bounce page allocation is mempool-backed, so it will always succeed when
|
||||
* @gfp_flags includes __GFP_DIRECT_RECLAIM, e.g. when it's GFP_NOFS. However,
|
||||
|
|
@ -167,14 +176,20 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
|
|||
{
|
||||
const struct inode *inode = folio->mapping->host;
|
||||
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;
|
||||
unsigned int du_bits;
|
||||
unsigned int du_size;
|
||||
struct page *ciphertext_page;
|
||||
u64 index = ((u64)folio->index << (PAGE_SHIFT - du_bits)) +
|
||||
(offs >> du_bits);
|
||||
u64 index;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
if (WARN_ON_ONCE(ci == NULL)) /* File hasn't been opened yet? */
|
||||
return ERR_PTR(-ENOKEY);
|
||||
|
||||
du_bits = ci->ci_data_unit_bits;
|
||||
du_size = 1U << du_bits;
|
||||
index = (folio_pos(folio) + offs) >> du_bits;
|
||||
|
||||
VM_BUG_ON_FOLIO(folio_test_large(folio), folio);
|
||||
if (WARN_ON_ONCE(!folio_test_locked(folio)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
@ -215,7 +230,8 @@ EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);
|
|||
* arbitrary page, not necessarily in the original pagecache page. The @inode
|
||||
* and @lblk_num must be specified, as they can't be determined from @page.
|
||||
*
|
||||
* This is not compatible with fscrypt_operations::supports_subblock_data_units.
|
||||
* This function only supports non-block-based filesystems that don't support
|
||||
* sub-block data units (as indicated by the fscrypt_operations fields).
|
||||
*
|
||||
* Return: 0 on success; -errno on failure
|
||||
*/
|
||||
|
|
@ -245,7 +261,8 @@ EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
|
|||
* arbitrary page, not necessarily in the original pagecache page. The @inode
|
||||
* and @lblk_num must be specified, as they can't be determined from @page.
|
||||
*
|
||||
* This is not compatible with fscrypt_operations::supports_subblock_data_units.
|
||||
* This function only supports non-block-based filesystems that don't support
|
||||
* sub-block data units (as indicated by the fscrypt_operations fields).
|
||||
*
|
||||
* Return: 0 on success; -errno on failure
|
||||
*/
|
||||
|
|
@ -275,7 +292,7 @@ int fscrypt_initialize(struct super_block *sb)
|
|||
mempool_t *pool;
|
||||
|
||||
/* pairs with smp_store_release() below */
|
||||
if (likely(smp_load_acquire(&fscrypt_bounce_page_pool)))
|
||||
if (smp_load_acquire(&fscrypt_bounce_page_pool))
|
||||
return 0;
|
||||
|
||||
/* No need to allocate a bounce page pool if this FS won't use it. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user