From: Josef Bacik <josef@toxicpanda.com>
To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org,
linux-btrfs@vger.kernel.org
Subject: [PATCH v2 30/36] btrfs: implement the fscrypt extent encryption hooks
Date: Tue, 10 Oct 2023 16:40:45 -0400 [thread overview]
Message-ID: <303db92bcd9f80f9e32b028a5d5477339b08e68f.1696970227.git.josef@toxicpanda.com> (raw)
In-Reply-To: <cover.1696970227.git.josef@toxicpanda.com>
This patch implements the necessary hooks from fscrypt to support
per-extent encryption. There's two main entry points
btrfs_fscrypt_load_extent_info
btrfs_fscrypt_save_extent_info
btrfs_fscrypt_load_extent_info gets called when we create the extent
maps from the file extent item at btrfs_get_extent() time. We read the
extent context, and pass it into fscrypt to create the appropriate
fscrypt_extent_info structure. This is then used on the bio's to make
sure the encryption is done properly.
btrfs_fscrypt_save_extent_info is used to generate the fscrypt context
from fscrypt and save it into the file extent item when we create a new
file extent item.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/defrag.c | 10 ++++++++-
fs/btrfs/file-item.c | 11 +++++++++-
fs/btrfs/file-item.h | 5 ++++-
fs/btrfs/file.c | 9 ++++++++
fs/btrfs/fscrypt.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
fs/btrfs/fscrypt.h | 31 ++++++++++++++++++++++++++++
fs/btrfs/inode.c | 22 +++++++++++++++++++-
fs/btrfs/tree-log.c | 10 +++++++++
8 files changed, 143 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
index 5244561e2016..f3b7438ddbc7 100644
--- a/fs/btrfs/defrag.c
+++ b/fs/btrfs/defrag.c
@@ -16,6 +16,7 @@
#include "defrag.h"
#include "file-item.h"
#include "super.h"
+#include "fscrypt.h"
static struct kmem_cache *btrfs_inode_defrag_cachep;
@@ -631,9 +632,12 @@ static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
struct btrfs_path path = { 0 };
struct extent_map *em;
struct btrfs_key key;
+ struct btrfs_fscrypt_ctx ctx;
u64 ino = btrfs_ino(inode);
int ret;
+ ctx.size = 0;
+
em = alloc_extent_map();
if (!em) {
ret = -ENOMEM;
@@ -728,7 +732,7 @@ static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
goto next;
/* Now this extent covers @start, convert it to em */
- btrfs_extent_item_to_extent_map(inode, &path, fi, em);
+ btrfs_extent_item_to_extent_map(inode, &path, fi, em, &ctx);
break;
next:
ret = btrfs_next_item(root, &path);
@@ -738,6 +742,10 @@ static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
goto not_found;
}
btrfs_release_path(&path);
+
+ ret = btrfs_fscrypt_load_extent_info(inode, em, &ctx);
+ if (ret)
+ goto err;
return em;
not_found:
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 26f35c1baedc..35036fab58c4 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -21,6 +21,7 @@
#include "accessors.h"
#include "file-item.h"
#include "super.h"
+#include "fscrypt.h"
#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) * 2) / \
@@ -1264,7 +1265,8 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
const struct btrfs_path *path,
struct btrfs_file_extent_item *fi,
- struct extent_map *em)
+ struct extent_map *em,
+ struct btrfs_fscrypt_ctx *ctx)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_root *root = inode->root;
@@ -1306,6 +1308,13 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
}
em->encryption_type = btrfs_file_extent_encryption(leaf, fi);
+ if (em->encryption_type != BTRFS_ENCRYPTION_NONE) {
+ ctx->size =
+ btrfs_file_extent_encryption_ctx_size(leaf, fi);
+ read_extent_buffer(leaf, ctx->ctx,
+ btrfs_file_extent_encryption_ctx_offset(fi),
+ ctx->size);
+ }
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
em->block_start = EXTENT_MAP_INLINE;
em->start = extent_start;
diff --git a/fs/btrfs/file-item.h b/fs/btrfs/file-item.h
index 04bd2d34efb1..bb79014024bd 100644
--- a/fs/btrfs/file-item.h
+++ b/fs/btrfs/file-item.h
@@ -5,6 +5,8 @@
#include "accessors.h"
+struct btrfs_fscrypt_ctx;
+
#define BTRFS_FILE_EXTENT_INLINE_DATA_START \
(offsetof(struct btrfs_file_extent_item, disk_bytenr))
@@ -63,7 +65,8 @@ int btrfs_lookup_csums_bitmap(struct btrfs_root *root, struct btrfs_path *path,
void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
const struct btrfs_path *path,
struct btrfs_file_extent_item *fi,
- struct extent_map *em);
+ struct extent_map *em,
+ struct btrfs_fscrypt_ctx *ctx);
int btrfs_inode_clear_file_extent_range(struct btrfs_inode *inode, u64 start,
u64 len);
int btrfs_inode_set_file_extent_range(struct btrfs_inode *inode, u64 start, u64 len);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index a19ac854e07f..be35cdd129b3 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -38,6 +38,7 @@
#include "ioctl.h"
#include "file.h"
#include "super.h"
+#include "fscrypt.h"
/* simple helper to fault in pages and copy. This should go away
* and be replaced with calls into generic code.
@@ -2275,6 +2276,14 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_num_bytes(leaf, extent, replace_len);
if (extent_info->is_new_extent)
btrfs_set_file_extent_generation(leaf, extent, trans->transid);
+ if (extent_info->fscrypt_info) {
+ ret = btrfs_fscrypt_save_extent_info(inode, path,
+ extent_info->fscrypt_info);
+ if (ret) {
+ btrfs_release_path(path);
+ return ret;
+ }
+ }
btrfs_mark_buffer_dirty(trans, leaf);
btrfs_release_path(path);
diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c
index 2d037b105b5f..7a7272cb83ec 100644
--- a/fs/btrfs/fscrypt.c
+++ b/fs/btrfs/fscrypt.c
@@ -214,7 +214,56 @@ static struct block_device **btrfs_fscrypt_get_devices(struct super_block *sb,
return devs;
}
+int btrfs_fscrypt_load_extent_info(struct btrfs_inode *inode,
+ struct extent_map *em,
+ struct btrfs_fscrypt_ctx *ctx)
+{
+ struct fscrypt_extent_info *info;
+ unsigned long nofs_flag;
+
+ if (ctx->size == 0)
+ return 0;
+
+ nofs_flag = memalloc_nofs_save();
+ info = fscrypt_load_extent_info(&inode->vfs_inode, ctx->ctx, ctx->size);
+ memalloc_nofs_restore(nofs_flag);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+ em->fscrypt_info = info;
+ return 0;
+}
+
+int btrfs_fscrypt_save_extent_info(struct btrfs_inode *inode,
+ struct btrfs_path *path,
+ struct fscrypt_extent_info *info)
+{
+ struct btrfs_file_extent_item *ei;
+ u8 ctx[BTRFS_MAX_EXTENT_CTX_SIZE];
+ ssize_t ctx_size;
+
+ ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_file_extent_item);
+
+ ctx_size = fscrypt_set_extent_context(&inode->vfs_inode, info, ctx);
+ if (ctx_size < 0) {
+ btrfs_err_rl(inode->root->fs_info, "invalid encrypt context\n");
+ return (int)ctx_size;
+ }
+ write_extent_buffer(path->nodes[0], ctx,
+ btrfs_file_extent_encryption_ctx_offset(ei),
+ ctx_size);
+ btrfs_set_file_extent_encryption_ctx_size(path->nodes[0], ei, ctx_size);
+ return 0;
+}
+
+size_t btrfs_fscrypt_extent_context_size(struct btrfs_inode *inode)
+{
+ return sizeof(struct btrfs_encryption_info) +
+ fscrypt_extent_context_size(&inode->vfs_inode);
+}
+
const struct fscrypt_operations btrfs_fscrypt_ops = {
+ .has_per_extent_encryption = 1,
.get_context = btrfs_fscrypt_get_context,
.set_context = btrfs_fscrypt_set_context,
.empty_dir = btrfs_fscrypt_empty_dir,
diff --git a/fs/btrfs/fscrypt.h b/fs/btrfs/fscrypt.h
index c08fd52c99b4..2882a4a9d978 100644
--- a/fs/btrfs/fscrypt.h
+++ b/fs/btrfs/fscrypt.h
@@ -8,6 +8,11 @@
#include "fs.h"
+struct btrfs_fscrypt_ctx {
+ u8 ctx[BTRFS_MAX_EXTENT_CTX_SIZE];
+ size_t size;
+};
+
#ifdef CONFIG_FS_ENCRYPTION
int btrfs_fscrypt_get_disk_name(struct extent_buffer *leaf,
struct btrfs_dir_item *di,
@@ -16,8 +21,29 @@ int btrfs_fscrypt_get_disk_name(struct extent_buffer *leaf,
bool btrfs_fscrypt_match_name(struct fscrypt_name *fname,
struct extent_buffer *leaf,
unsigned long de_name, u32 de_name_len);
+int btrfs_fscrypt_load_extent_info(struct btrfs_inode *inode,
+ struct extent_map *em,
+ struct btrfs_fscrypt_ctx *ctx);
+int btrfs_fscrypt_save_extent_info(struct btrfs_inode *inode,
+ struct btrfs_path *path,
+ struct fscrypt_extent_info *fi);
+size_t btrfs_fscrypt_extent_context_size(struct btrfs_inode *inode);
#else
+static inline int btrfs_fscrypt_save_extent_info(struct btrfs_inode *inode,
+ struct btrfs_path *path,
+ struct fscrypt_extent_info *fi)
+{
+ return 0;
+}
+
+static inline int btrfs_fscrypt_load_extent_info(struct btrfs_inode *inode,
+ struct extent_map *em,
+ struct btrfs_fscrypt_ctx *ctx)
+{
+ return 0;
+}
+
static inline int btrfs_fscrypt_get_disk_name(struct extent_buffer *leaf,
struct btrfs_dir_item *di,
struct fscrypt_str *qstr)
@@ -35,6 +61,11 @@ static inline bool btrfs_fscrypt_match_name(struct fscrypt_name *fname,
return !memcmp_extent_buffer(leaf, fname->disk_name.name, de_name,
de_name_len);
}
+
+static inline size_t btrfs_fscrypt_extent_context_size(struct btrfs_inode *inode)
+{
+ return 0;
+}
#endif /* CONFIG_FS_ENCRYPTION */
extern const struct fscrypt_operations btrfs_fscrypt_ops;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 99fb5a613fb8..4f23c3af60be 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2903,6 +2903,9 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
size_t fscrypt_context_size = 0;
int ret;
+ if (btrfs_stack_file_extent_encryption(stack_fi))
+ fscrypt_context_size = btrfs_fscrypt_extent_context_size(inode);
+
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
@@ -2941,6 +2944,12 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
btrfs_item_ptr_offset(leaf, path->slots[0]),
sizeof(struct btrfs_file_extent_item));
+ if (fscrypt_context_size) {
+ ret = btrfs_fscrypt_save_extent_info(inode, path, fscrypt_info);
+ if (ret)
+ goto out;
+ }
+
btrfs_mark_buffer_dirty(trans, leaf);
btrfs_release_path(path);
@@ -6865,6 +6874,7 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
struct btrfs_key found_key;
struct extent_map *em = NULL;
struct extent_map_tree *em_tree = &inode->extent_tree;
+ struct btrfs_fscrypt_ctx ctx;
read_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, len);
@@ -6878,6 +6888,9 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
else
goto out;
}
+
+ ctx.size = 0;
+
em = alloc_extent_map();
if (!em) {
ret = -ENOMEM;
@@ -6982,7 +6995,7 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
goto insert;
}
- btrfs_extent_item_to_extent_map(inode, path, item, em);
+ btrfs_extent_item_to_extent_map(inode, path, item, em, &ctx);
if (extent_type == BTRFS_FILE_EXTENT_REG ||
extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
@@ -7027,6 +7040,10 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
goto out;
}
+ ret = btrfs_fscrypt_load_extent_info(inode, em, &ctx);
+ if (ret)
+ goto out;
+
write_lock(&em_tree->lock);
ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len);
write_unlock(&em_tree->lock);
@@ -9703,6 +9720,9 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
return trans;
}
+ if (fscrypt_info)
+ fscrypt_context_size = btrfs_fscrypt_extent_context_size(inode);
+
extent_info.disk_offset = start;
extent_info.disk_len = len;
extent_info.data_offset = 0;
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 85267cf1f372..1082e1d7fd84 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -30,6 +30,7 @@
#include "file.h"
#include "orphan.h"
#include "tree-checker.h"
+#include "fscrypt.h"
#define MAX_CONFLICT_INODES 10
@@ -4631,6 +4632,9 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
size_t fscrypt_context_size = 0;
u8 encryption = em->encryption_type;
+ if (encryption)
+ fscrypt_context_size = btrfs_fscrypt_extent_context_size(inode);
+
btrfs_set_stack_file_extent_generation(&fi, trans->transid);
if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
btrfs_set_stack_file_extent_type(&fi, BTRFS_FILE_EXTENT_PREALLOC);
@@ -4691,6 +4695,12 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
write_extent_buffer(leaf, &fi,
btrfs_item_ptr_offset(leaf, path->slots[0]),
sizeof(fi));
+ if (fscrypt_context_size) {
+ ret = btrfs_fscrypt_save_extent_info(inode, path,
+ em->fscrypt_info);
+ if (ret)
+ return ret;
+ }
btrfs_mark_buffer_dirty(trans, leaf);
btrfs_release_path(path);
--
2.41.0
next prev parent reply other threads:[~2023-10-10 20:42 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-10 20:40 [PATCH v2 00/36] btrfs: add fscrypt support Josef Bacik
2023-10-10 20:40 ` [PATCH v2 01/36] fscrypt: use a flag to indicate that the master key is being evicted Josef Bacik
2023-10-15 6:22 ` Eric Biggers
2023-10-10 20:40 ` [PATCH v2 02/36] fscrypt: don't wipe mk secret until the last active user is gone Josef Bacik
2023-10-15 6:25 ` Eric Biggers
2023-10-10 20:40 ` [PATCH v2 03/36] fscrypt: add per-extent encryption support Josef Bacik
2023-10-15 6:36 ` Eric Biggers
2023-10-10 20:40 ` [PATCH v2 04/36] fscrypt: disable all but standard v2 policies for extent encryption Josef Bacik
2023-10-15 6:27 ` Eric Biggers
2023-10-10 20:40 ` [PATCH v2 05/36] blk-crypto: add a process bio callback Josef Bacik
2023-10-15 6:32 ` Eric Biggers
2023-10-10 20:40 ` [PATCH v2 06/36] fscrypt: expose fscrypt_nokey_name Josef Bacik
2023-10-10 20:40 ` [PATCH v2 07/36] fscrypt: add documentation about extent encryption Josef Bacik
2023-10-10 20:40 ` [PATCH v2 08/36] btrfs: add infrastructure for safe em freeing Josef Bacik
2023-10-10 20:40 ` [PATCH v2 09/36] btrfs: disable various operations on encrypted inodes Josef Bacik
2023-10-10 20:40 ` [PATCH v2 10/36] btrfs: disable verity " Josef Bacik
2023-10-10 20:40 ` [PATCH v2 11/36] btrfs: start using fscrypt hooks Josef Bacik
2023-10-10 20:40 ` [PATCH v2 12/36] btrfs: add inode encryption contexts Josef Bacik
2023-10-10 20:40 ` [PATCH v2 13/36] btrfs: add new FEATURE_INCOMPAT_ENCRYPT flag Josef Bacik
2023-10-10 20:40 ` [PATCH v2 14/36] btrfs: adapt readdir for encrypted and nokey names Josef Bacik
2023-10-10 20:40 ` [PATCH v2 15/36] btrfs: handle " Josef Bacik
2023-10-10 20:40 ` [PATCH v2 16/36] btrfs: implement fscrypt ioctls Josef Bacik
2023-10-10 20:40 ` [PATCH v2 17/36] btrfs: add encryption to CONFIG_BTRFS_DEBUG Josef Bacik
2023-10-10 20:40 ` [PATCH v2 18/36] btrfs: add get_devices hook for fscrypt Josef Bacik
2023-10-10 20:40 ` [PATCH v2 19/36] btrfs: turn on inlinecrypt mount option for encrypt Josef Bacik
2023-10-10 20:40 ` [PATCH v2 20/36] btrfs: set file extent encryption excplicitly Josef Bacik
2023-10-10 20:40 ` [PATCH v2 21/36] btrfs: add fscrypt_info and encryption_type to extent_map Josef Bacik
2023-10-10 20:40 ` [PATCH v2 22/36] btrfs: add fscrypt_info and encryption_type to ordered_extent Josef Bacik
2023-10-10 20:40 ` [PATCH v2 23/36] btrfs: plumb through setting the fscrypt_info for ordered extents Josef Bacik
2023-10-10 20:40 ` [PATCH v2 24/36] btrfs: populate the ordered_extent with the fscrypt context Josef Bacik
2023-10-10 20:40 ` [PATCH v2 25/36] btrfs: keep track of fscrypt info and orig_start for dio reads Josef Bacik
2023-10-10 20:40 ` [PATCH v2 26/36] btrfs: add an optional encryption context to the end of file extents Josef Bacik
2023-10-10 20:40 ` [PATCH v2 27/36] btrfs: explicitly track file extent length for replace and drop Josef Bacik
2023-10-10 20:40 ` [PATCH v2 28/36] btrfs: pass through fscrypt_extent_info to the file extent helpers Josef Bacik
2023-10-10 20:40 ` [PATCH v2 29/36] btrfs: pass the fscrypt_info through the replace extent infrastructure Josef Bacik
2023-10-10 20:40 ` Josef Bacik [this message]
2023-10-10 20:40 ` [PATCH v2 31/36] btrfs: setup fscrypt_extent_info for new extents Josef Bacik
2023-10-10 20:40 ` [PATCH v2 32/36] btrfs: populate ordered_extent with the orig offset Josef Bacik
2023-10-10 20:40 ` [PATCH v2 33/36] btrfs: set the bio fscrypt context when applicable Josef Bacik
2023-10-10 20:40 ` [PATCH v2 34/36] btrfs: add a bio argument to btrfs_csum_one_bio Josef Bacik
2023-10-10 20:40 ` [PATCH v2 35/36] btrfs: add orig_logical to btrfs_bio Josef Bacik
2023-10-10 20:40 ` [PATCH v2 36/36] btrfs: implement process_bio cb for fscrypt Josef Bacik
2023-11-21 23:02 ` [PATCH v2 00/36] btrfs: add fscrypt support Eric Biggers
2023-11-22 13:58 ` Josef Bacik
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=303db92bcd9f80f9e32b028a5d5477339b08e68f.1696970227.git.josef@toxicpanda.com \
--to=josef@toxicpanda.com \
--cc=ebiggers@kernel.org \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-fscrypt@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).