Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6561560c authored by Satya Tangirala's avatar Satya Tangirala Committed by Eric Biggers
Browse files

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: default avatarSatya Tangirala <satyat@google.com>
parent cfed4cb1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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)
+17 −12
Original line number Diff line number Diff line
@@ -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;