All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
To: "Theodore Y. Ts'o" <tytso@mit.edu>,
	Jaegeuk Kim <jaegeuk@kernel.org>,
	Eric Biggers <ebiggers@kernel.org>, Chris Mason <clm@fb.com>,
	Josef Bacik <josef@toxicpanda.com>,
	David Sterba <dsterba@suse.com>,
	linux-fscrypt@vger.kernel.org, linux-btrfs@vger.kernel.org,
	kernel-team@meta.com
Cc: Omar Sandoval <osandov@osandov.com>,
	Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Subject: [PATCH v3 15/22] btrfs: encrypt normal file extent data if appropriate
Date: Thu, 20 Oct 2022 12:58:34 -0400	[thread overview]
Message-ID: <cfb16a33dd7f56c9f2d13a5645e670de8df93d96.1666281277.git.sweettea-kernel@dorminy.me> (raw)
In-Reply-To: <cover.1666281276.git.sweettea-kernel@dorminy.me>

From: Omar Sandoval <osandov@osandov.com>

Add in the necessary calls to encrypt and decrypt data to achieve
encryption of normal data.

Since these are all page cache pages being encrypted, we can't encrypt
them in place and must encrypt/decrypt into a new page. fscrypt provides a pool
of pages for this purpose, which it calls bounce pages. For IO of
encrypted data, we use a bounce page for the actual IO, and
encrypt/decrypt from/to the actual page cache page on either side of the
IO.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
 fs/btrfs/extent_io.c    | 56 ++++++++++++++++++++++++++++++++++++-----
 fs/btrfs/file-item.c    |  9 +++++--
 fs/btrfs/fscrypt.c      | 32 ++++++++++++++++++++++-
 fs/btrfs/tree-checker.c | 11 +++++---
 4 files changed, 96 insertions(+), 12 deletions(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 4e4f28387ace..94d0636aafd0 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -113,6 +113,7 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
 {
 	struct bio *bio;
 	struct bio_vec *bv;
+	struct page *first_page;
 	struct inode *inode;
 	int mirror_num;
 
@@ -121,13 +122,17 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
 
 	bio = bio_ctrl->bio;
 	bv = bio_first_bvec_all(bio);
-	inode = bv->bv_page->mapping->host;
+	first_page = bio_first_page_all(bio);
+	if (fscrypt_is_bounce_page(first_page))
+		inode = fscrypt_pagecache_page(first_page)->mapping->host;
+	else
+		inode = first_page->mapping->host;
 	mirror_num = bio_ctrl->mirror_num;
 
 	/* Caller should ensure the bio has at least some range added */
 	ASSERT(bio->bi_iter.bi_size);
 
-	btrfs_bio(bio)->file_offset = page_offset(bv->bv_page) + bv->bv_offset;
+	btrfs_bio(bio)->file_offset = page_offset(first_page) + bv->bv_offset;
 
 	if (!is_data_inode(inode))
 		btrfs_submit_metadata_bio(inode, bio, mirror_num);
@@ -1014,9 +1019,19 @@ static void end_bio_extent_writepage(struct btrfs_bio *bbio)
 	ASSERT(!bio_flagged(bio, BIO_CLONED));
 	bio_for_each_segment_all(bvec, bio, iter_all) {
 		struct page *page = bvec->bv_page;
-		struct inode *inode = page->mapping->host;
-		struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-		const u32 sectorsize = fs_info->sectorsize;
+		struct inode *inode;
+		struct btrfs_fs_info *fs_info;
+		u32 sectorsize;
+		struct page *bounce_page = NULL;
+
+		if (fscrypt_is_bounce_page(page)) {
+			bounce_page = page;
+			page = fscrypt_pagecache_page(bounce_page);
+		}
+
+		inode = page->mapping->host;
+		fs_info = btrfs_sb(inode->i_sb);
+		sectorsize = fs_info->sectorsize;
 
 		/* Our read/write should always be sector aligned. */
 		if (!IS_ALIGNED(bvec->bv_offset, sectorsize))
@@ -1037,7 +1052,7 @@ static void end_bio_extent_writepage(struct btrfs_bio *bbio)
 		}
 
 		end_extent_writepage(page, error, start, end);
-
+		fscrypt_free_bounce_page(bounce_page);
 		btrfs_page_clear_writeback(fs_info, page, start, bvec->bv_len);
 	}
 
@@ -1229,6 +1244,17 @@ static void end_bio_extent_readpage(struct btrfs_bio *bbio)
 			}
 		}
 
+		if (likely(uptodate)) {
+			if (fscrypt_inode_uses_fs_layer_crypto(inode)) {
+				int ret = fscrypt_decrypt_pagecache_blocks(page,
+									   bvec->bv_len,
+									   bvec->bv_offset);
+				if (ret) {
+					error_bitmap = (unsigned int) -1;
+					uptodate = false;
+					}
+			}
+		}
 		if (likely(uptodate)) {
 			loff_t i_size = i_size_read(inode);
 			pgoff_t end_index = i_size >> PAGE_SHIFT;
@@ -1563,11 +1589,29 @@ static int submit_extent_page(blk_opf_t opf,
 			      bool force_bio_submit)
 {
 	int ret = 0;
+	struct page *bounce_page = NULL;
 	struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
 	unsigned int cur = pg_offset;
 
 	ASSERT(bio_ctrl);
 
+	if ((opf & REQ_OP_MASK) == REQ_OP_WRITE &&
+	    fscrypt_inode_uses_fs_layer_crypto(&inode->vfs_inode)) {
+		gfp_t gfp_flags = GFP_NOFS;
+
+		if (bio_ctrl->bio)
+			gfp_flags = GFP_NOWAIT | __GFP_NOWARN;
+		else
+			gfp_flags = GFP_NOFS;
+		bounce_page = fscrypt_encrypt_pagecache_blocks(page, size,
+							       pg_offset,
+							       gfp_flags);
+		if (IS_ERR(bounce_page))
+			return PTR_ERR(bounce_page);
+		page = bounce_page;
+		pg_offset = 0;
+	}
+
 	ASSERT(pg_offset < PAGE_SIZE && size <= PAGE_SIZE &&
 	       pg_offset + size <= PAGE_SIZE);
 
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 598dff14078f..e4ec6a97a85c 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -676,8 +676,13 @@ blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio,
 	shash->tfm = fs_info->csum_shash;
 
 	bio_for_each_segment(bvec, bio, iter) {
-		if (use_page_offsets)
-			offset = page_offset(bvec.bv_page) + bvec.bv_offset;
+		if (use_page_offsets) {
+			struct page *page = bvec.bv_page;
+
+			if (fscrypt_is_bounce_page(page))
+				page = fscrypt_pagecache_page(page);
+			offset = page_offset(page) + bvec.bv_offset;
+		}
 
 		if (!ordered) {
 			ordered = btrfs_lookup_ordered_extent(inode, offset);
diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c
index 717a9c244306..324436cba989 100644
--- a/fs/btrfs/fscrypt.c
+++ b/fs/btrfs/fscrypt.c
@@ -175,7 +175,37 @@ static int btrfs_fscrypt_get_extent_context(const struct inode *inode,
 					    size_t *extent_offset,
 					    size_t *extent_length)
 {
-	return len;
+	u64 offset = lblk_num << inode->i_blkbits;
+	struct extent_map *em;
+
+	/* Since IO must be in progress on this extent, this must succeed */
+	em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, PAGE_SIZE);
+	if (em) {
+		int ret = ctx ? em->fscrypt_context.len : 0;
+
+		if (em->block_start == EXTENT_MAP_HOLE) {
+			btrfs_info(BTRFS_I(inode)->root->fs_info,
+				   "extent context requested for block %llu of inode %llu without an extent",
+				   lblk_num, inode->i_ino);
+			free_extent_map(em);
+			return -ENOENT;
+		}
+
+		if (ctx)
+			memcpy(ctx, em->fscrypt_context.buffer,
+			       em->fscrypt_context.len);
+
+		if (extent_offset)
+			*extent_offset
+				 = (offset - em->start) >> inode->i_blkbits;
+
+		if (extent_length)
+			*extent_length = em->len >> inode->i_blkbits;
+
+		free_extent_map(em);
+		return ret;
+	}
+	return -EINVAL;
 }
 
 static int btrfs_fscrypt_set_extent_context(void *extent, void *ctx,
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 868ac7f2aeed..d17e34aea386 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -273,9 +273,14 @@ static int check_extent_data_item(struct extent_buffer *leaf,
 			return -EUCLEAN;
 		}
 
-		/* Compressed inline extent has no on-disk size, skip it */
-		if (btrfs_file_extent_compression(leaf, fi) !=
-		    BTRFS_COMPRESS_NONE)
+		/*
+		 * Compressed inline extent has no on-disk size; encrypted has
+		 * variable size; skip them
+		 */
+		if ((btrfs_file_extent_compression(leaf, fi) !=
+		     BTRFS_COMPRESS_NONE) ||
+		    (btrfs_file_extent_encryption(leaf, fi) !=
+		     BTRFS_ENCRYPTION_NONE))
 			return 0;
 
 		/* Uncompressed inline extent size must match item size */
-- 
2.35.1


  parent reply	other threads:[~2022-10-20 16:59 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-20 16:58 [PATCH v3 00/22] btrfs: add fscrypt integration Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 01/22] fscrypt: expose fscrypt_nokey_name Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 02/22] fscrypt: add fscrypt_have_same_policy() to check inode compatibility Sweet Tea Dorminy
2022-10-20 20:52   ` Josef Bacik
2022-10-20 16:58 ` [PATCH v3 03/22] fscrypt: allow fscrypt_generate_iv() to distinguish filenames Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 04/22] fscrypt: add extent-based encryption Sweet Tea Dorminy
2022-10-20 21:40   ` Eric Biggers
2022-10-20 22:20     ` Sweet Tea Dorminy
2022-10-20 21:45   ` Eric Biggers
2022-10-20 22:55     ` Sweet Tea Dorminy
2022-10-20 23:56       ` Eric Biggers
2022-10-21  0:37         ` Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 05/22] fscrypt: document btrfs' fscrypt quirks Sweet Tea Dorminy
2022-10-20 21:41   ` Eric Biggers
2022-10-20 22:07     ` Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 06/22] btrfs: use struct qstr instead of name and namelen Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 07/22] btrfs: setup qstrings from dentrys using fscrypt helper Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 08/22] btrfs: use struct fscrypt_str instead of struct qstr Sweet Tea Dorminy
2022-10-21 20:42   ` Josef Bacik
2022-10-20 16:58 ` [PATCH v3 09/22] btrfs: store directory encryption state Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 10/22] btrfs: disable various operations on encrypted inodes Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 11/22] btrfs: start using fscrypt hooks Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 12/22] btrfs: add fscrypt_context items Sweet Tea Dorminy
2022-10-21 20:54   ` Josef Bacik
2022-10-20 16:58 ` [PATCH v3 13/22] btrfs: translate btrfs encryption flags and encrypted inode flag Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 14/22] btrfs: store a fscrypt extent context per normal file extent Sweet Tea Dorminy
2022-10-20 16:58 ` Sweet Tea Dorminy [this message]
2022-10-21 20:58   ` [PATCH v3 15/22] btrfs: encrypt normal file extent data if appropriate Josef Bacik
2022-10-20 16:58 ` [PATCH v3 16/22] btrfs: Add new FEATURE_INCOMPAT_ENCRYPT feature flag Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 17/22] btrfs: implement fscrypt ioctls Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 18/22] btrfs: permit searching for nokey names for removal Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 19/22] btrfs: use correct name hash for nokey names Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 20/22] btrfs: adapt lookup for partially encrypted directories Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 21/22] fscrypt: add flag allowing partially-encrypted directories Sweet Tea Dorminy
2022-10-20 16:58 ` [PATCH v3 22/22] btrfs: encrypt verity items Sweet Tea Dorminy
2022-10-20 21:38 ` [PATCH v3 00/22] btrfs: add fscrypt integration Eric Biggers
2022-10-20 23:12   ` David Sterba

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cfb16a33dd7f56c9f2d13a5645e670de8df93d96.1666281277.git.sweettea-kernel@dorminy.me \
    --to=sweettea-kernel@dorminy.me \
    --cc=clm@fb.com \
    --cc=dsterba@suse.com \
    --cc=ebiggers@kernel.org \
    --cc=jaegeuk@kernel.org \
    --cc=josef@toxicpanda.com \
    --cc=kernel-team@meta.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-fscrypt@vger.kernel.org \
    --cc=osandov@osandov.com \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.