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.
Fix fscrypt_zeroout_range_inline_crypt by calling
fscrypt_mergeable_bio() before each page merge.
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()).
Fixes: c2b86b727a
("FROMLIST: Update Inline Encryption from v6 to upstream version of patch series")
Change-Id: I9cb414fcc284b197b9d3d1b9643029c6b875df5a
Signed-off-by: Satya Tangirala <satyat@google.com>
This commit is contained in:
parent
b4518aa55c
commit
a79db694f3
@ -74,7 +74,8 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
|
||||
len -= blocks_this_page;
|
||||
lblk += blocks_this_page;
|
||||
pblk += blocks_this_page;
|
||||
if (num_pages == BIO_MAX_PAGES || !len) {
|
||||
if (num_pages == BIO_MAX_PAGES || !len ||
|
||||
!fscrypt_mergeable_bio(bio, inode, lblk)) {
|
||||
err = submit_bio_wait(bio);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -87,6 +87,19 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci,
|
||||
if (!(sb->s_flags & SB_INLINECRYPT))
|
||||
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;
|
||||
|
||||
/*
|
||||
* blk-crypto must support the crypto configuration we'll use for the
|
||||
* inode on all devices in the sb
|
||||
@ -397,7 +410,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. */
|
||||
@ -415,15 +427,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);
|
||||
@ -438,8 +441,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)
|
||||
@ -457,6 +458,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