ANDROID: fscrypt: fix DUN contiguity with inline encryption + IV_INO_LBLK_32 policies
IV_INO_LBLK_32 policies introduced the possibility that logically contiguous data blocks might not have contiguous DUNs (because of potential DUN wraparound). As such, whenever a page is merged into a bio, fscrypt_mergeable_bio() must be called to check DUN contiguity. Further, fscrypt inline encryption does not handle the case when the DUN wraps around within a page (which can happen when the data unit size != PAGE_SIZE). For now, we handle that by disallowing inline encryption with IV_INO_LBLK_32 policies when the data unit size != PAGE_SIZE (and dropping the now redundant check for this in fscrypt_dio_supported()). Bug: 144046242 Change-Id: I9cb414fcc284b197b9d3d1b9643029c6b875df5a Signed-off-by: Satya Tangirala <satyat@google.com>
This commit is contained in:
parent
cfed4cb19a
commit
6561560c01
@ -77,7 +77,8 @@ static int fscrypt_zeroout_range_inlinecrypt(const struct inode *inode,
|
||||
lblk += blocks_this_page;
|
||||
pblk += blocks_this_page;
|
||||
len -= blocks_this_page;
|
||||
} while (++i != BIO_MAX_PAGES && len != 0);
|
||||
} while (++i != BIO_MAX_PAGES && len != 0 &&
|
||||
fscrypt_mergeable_bio(bio, inode, lblk));
|
||||
|
||||
err = submit_bio_wait(bio);
|
||||
if (err)
|
||||
|
@ -88,6 +88,19 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
|
||||
!sb->s_cop->inline_crypt_enabled(sb))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* When a page contains multiple logically contiguous filesystem blocks,
|
||||
* some filesystem code only calls fscrypt_mergeable_bio() for the first
|
||||
* block in the page. This is fine for most of fscrypt's IV generation
|
||||
* strategies, where contiguous blocks imply contiguous IVs. But it
|
||||
* doesn't work with IV_INO_LBLK_32. For now, simply exclude
|
||||
* IV_INO_LBLK_32 with blocksize != PAGE_SIZE from inline encryption.
|
||||
*/
|
||||
if ((fscrypt_policy_flags(&ci->ci_policy) &
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
|
||||
sb->s_blocksize != PAGE_SIZE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The needed encryption settings must be supported either by
|
||||
* blk-crypto-fallback, or by hardware on all the filesystem's devices.
|
||||
@ -441,7 +454,6 @@ EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh);
|
||||
bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
const struct inode *inode = file_inode(iocb->ki_filp);
|
||||
const struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
const unsigned int blocksize = i_blocksize(inode);
|
||||
|
||||
/* If the file is unencrypted, no veto from us. */
|
||||
@ -459,15 +471,6 @@ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter)
|
||||
if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* With IV_INO_LBLK_32 and sub-page blocks, the DUN can wrap around in
|
||||
* the middle of a page. This isn't handled by the direct I/O code yet.
|
||||
*/
|
||||
if (blocksize != PAGE_SIZE &&
|
||||
(fscrypt_policy_flags(&ci->ci_policy) &
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
|
||||
@ -482,8 +485,6 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
|
||||
* targeting @pos, in order to avoid crossing a data unit number (DUN)
|
||||
* discontinuity. This is only needed for certain IV generation methods.
|
||||
*
|
||||
* This assumes block_size == PAGE_SIZE; see fscrypt_dio_supported().
|
||||
*
|
||||
* Return: the actual number of pages that can be submitted
|
||||
*/
|
||||
int fscrypt_limit_dio_pages(const struct inode *inode, loff_t pos, int nr_pages)
|
||||
@ -501,6 +502,10 @@ int fscrypt_limit_dio_pages(const struct inode *inode, loff_t pos, int nr_pages)
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32))
|
||||
return nr_pages;
|
||||
|
||||
/*
|
||||
* fscrypt_select_encryption_impl() ensures that block_size == PAGE_SIZE
|
||||
* when using FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32.
|
||||
*/
|
||||
if (WARN_ON_ONCE(i_blocksize(inode) != PAGE_SIZE))
|
||||
return 1;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user