From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
To: Chris Mason <clm@fb.com>, Josef Bacik <josef@toxicpanda.com>,
David Sterba <dsterba@suse.com>,
"Theodore Y . Ts'o" <tytso@mit.edu>,
Jaegeuk Kim <jaegeuk@kernel.org>,
kernel-team@meta.com, linux-btrfs@vger.kernel.org,
linux-fscrypt@vger.kernel.org, Eric Biggers <ebiggers@kernel.org>
Cc: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Subject: [PATCH v3 15/17] btrfs: start tracking extent encryption context info
Date: Tue, 8 Aug 2023 13:12:17 -0400 [thread overview]
Message-ID: <f37e7aab6ca74639a20242be10ce0864bf96cf9c.1691510179.git.sweettea-kernel@dorminy.me> (raw)
In-Reply-To: <cover.1691510179.git.sweettea-kernel@dorminy.me>
This puts the long-preserved 1-byte encryption field to work, storing
whether the extent is encrypted.
Since there is no way for a btrfs inode to be encrypted right now, we
set context length to be 0 in all locations.
This also adds the new encryption_context member to the end of the
file_extent item, which will begin with a length of the fscrypt context
following it; and an accessor for the context size. This allows checking
that the context size matches the item size.
It could be possible to pack the size and the encryption type into the
u8 encryption field, but this allows more flexibility in the future.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
fs/btrfs/accessors.h | 3 ++-
fs/btrfs/file-item.c | 5 +++++
fs/btrfs/fscrypt.h | 21 +++++++++++++++++++
fs/btrfs/inode.c | 25 ++++++++++++++++++----
fs/btrfs/tree-checker.c | 37 ++++++++++++++++++++++++++-------
fs/btrfs/tree-log.c | 2 ++
include/uapi/linux/btrfs_tree.h | 12 ++++++++++-
7 files changed, 91 insertions(+), 14 deletions(-)
diff --git a/fs/btrfs/accessors.h b/fs/btrfs/accessors.h
index 8cfc8214109c..93b11d5e21a9 100644
--- a/fs/btrfs/accessors.h
+++ b/fs/btrfs/accessors.h
@@ -935,7 +935,8 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_num_bytes,
struct btrfs_file_extent_item, disk_num_bytes, 64);
BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression,
struct btrfs_file_extent_item, compression, 8);
-
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_encryption,
+ struct btrfs_file_extent_item, encryption, 8);
BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 696bf695d8eb..f83f7020ed89 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -18,6 +18,7 @@
#include "print-tree.h"
#include "compression.h"
#include "fs.h"
+#include "fscrypt.h"
#include "accessors.h"
#include "file-item.h"
#include "super.h"
@@ -1272,6 +1273,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
em->generation = btrfs_file_extent_generation(leaf, fi);
if (type == BTRFS_FILE_EXTENT_REG ||
type == BTRFS_FILE_EXTENT_PREALLOC) {
+ u8 ctxsize;
em->start = extent_start;
em->len = extent_end - extent_start;
em->orig_start = extent_start -
@@ -1294,6 +1296,9 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
if (type == BTRFS_FILE_EXTENT_PREALLOC)
set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
}
+
+ ctxsize = btrfs_file_extent_ctxsize_from_item(leaf, path);
+ ASSERT(ctxsize == btrfs_file_extent_encryption_ctxsize(leaf, fi));
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
em->block_start = EXTENT_MAP_INLINE;
em->start = extent_start;
diff --git a/fs/btrfs/fscrypt.h b/fs/btrfs/fscrypt.h
index a489bb54b3b1..26627df9d5f9 100644
--- a/fs/btrfs/fscrypt.h
+++ b/fs/btrfs/fscrypt.h
@@ -4,10 +4,31 @@
#define BTRFS_FSCRYPT_H
#include <linux/fscrypt.h>
+#include "accessors.h"
#include "extent_io.h"
#include "fs.h"
+static inline u32
+btrfs_file_extent_encryption_ctxsize(const struct extent_buffer *eb,
+ struct btrfs_file_extent_item *e)
+{
+ if (!btrfs_file_extent_encryption(eb, e))
+ return 0;
+
+ return btrfs_get_32(eb, e, offsetof(struct btrfs_file_extent_item,
+ encryption_context));
+}
+
+static inline u8
+btrfs_file_extent_ctxsize_from_item(const struct extent_buffer *leaf,
+ const struct btrfs_path *path)
+{
+ return (btrfs_item_size(leaf, path->slots[0]) -
+ sizeof(struct btrfs_file_extent_item));
+}
+
+
#ifdef CONFIG_FS_ENCRYPTION
int btrfs_fscrypt_get_disk_name(struct extent_buffer *leaf,
struct btrfs_dir_item *di,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 7726957284c1..ed0579577263 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3000,7 +3000,7 @@ static int insert_ordered_extent_file_extent(struct btrfs_trans_handle *trans,
btrfs_set_stack_file_extent_num_bytes(&stack_fi, num_bytes);
btrfs_set_stack_file_extent_ram_bytes(&stack_fi, ram_bytes);
btrfs_set_stack_file_extent_compression(&stack_fi, oe->compress_type);
- /* Encryption and other encoding is reserved and all 0 */
+ /* Other encoding is reserved and always 0 */
/*
* For delalloc, when completing an ordered extent we update the inode's
@@ -6929,8 +6929,23 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
btrfs_extent_item_to_extent_map(inode, path, item, em);
- if (extent_type == BTRFS_FILE_EXTENT_REG ||
- extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
+ if (extent_type == BTRFS_FILE_EXTENT_REG) {
+ u8 item_ctxsize = btrfs_file_extent_ctxsize_from_item(leaf, path);
+ u8 encryption = btrfs_file_extent_encryption(leaf, item);
+ u32 ctxsize = btrfs_file_extent_encryption_ctxsize(leaf, item);
+
+
+ if (encryption == BTRFS_ENCRYPTION_FSCRYPT) {
+ if (ctxsize != item_ctxsize) {
+ btrfs_crit(fs_info,
+ "invalid encryption context size for inode %llu: itemsize %d item %d",
+ btrfs_ino(inode), ctxsize, item_ctxsize);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ }
+ goto insert;
+ } else if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
goto insert;
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
/*
@@ -9623,7 +9638,9 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
btrfs_set_stack_file_extent_num_bytes(&stack_fi, len);
btrfs_set_stack_file_extent_ram_bytes(&stack_fi, len);
btrfs_set_stack_file_extent_compression(&stack_fi, BTRFS_COMPRESS_NONE);
- /* Encryption and other encoding is reserved and all 0 */
+ btrfs_set_stack_file_extent_encryption(&stack_fi,
+ BTRFS_ENCRYPTION_NONE);
+ /* Other encoding is reserved and always 0 */
qgroup_released = btrfs_qgroup_release_data(inode, file_offset, len);
if (qgroup_released < 0)
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 038dfa8f1788..7f0fa170f3de 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -26,6 +26,7 @@
#include "volumes.h"
#include "misc.h"
#include "fs.h"
+#include "fscrypt.h"
#include "accessors.h"
#include "file-item.h"
#include "inode-item.h"
@@ -208,6 +209,7 @@ static int check_extent_data_item(struct extent_buffer *leaf,
u32 sectorsize = fs_info->sectorsize;
u32 item_size = btrfs_item_size(leaf, slot);
u64 extent_end;
+ u8 policy;
if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
file_extent_err(leaf, slot,
@@ -259,10 +261,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
BTRFS_NR_COMPRESS_TYPES - 1);
return -EUCLEAN;
}
- if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
+ policy = btrfs_file_extent_encryption(leaf, fi);
+ if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
file_extent_err(leaf, slot,
- "invalid encryption for file extent, have %u expect 0",
- btrfs_file_extent_encryption(leaf, fi));
+ "invalid encryption for file extent, have %u expect range [0, %u]",
+ policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
return -EUCLEAN;
}
if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
@@ -291,12 +294,30 @@ static int check_extent_data_item(struct extent_buffer *leaf,
return 0;
}
- /* Regular or preallocated extent has fixed item size */
- if (unlikely(item_size != sizeof(*fi))) {
- file_extent_err(leaf, slot,
+ if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
+ u8 ctxsize = btrfs_file_extent_encryption_ctxsize(leaf, fi);
+
+ if (unlikely(item_size != sizeof(*fi) + ctxsize)) {
+ file_extent_err(leaf, slot,
+ "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
+ item_size, sizeof(*fi), ctxsize);
+ return -EUCLEAN;
+ }
+ /* Only regular extents should be encrypted. */
+ if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG) {
+ file_extent_err(leaf, slot,
+ "invalid type for encrypted file extent, have %u expect %u",
+ btrfs_file_extent_type(leaf, fi),
+ BTRFS_FILE_EXTENT_REG);
+ return -EUCLEAN;
+ }
+ } else {
+ if (unlikely(item_size != sizeof(*fi))) {
+ file_extent_err(leaf, slot,
"invalid item size for reg/prealloc file extent, have %u expect %zu",
- item_size, sizeof(*fi));
- return -EUCLEAN;
+ item_size, sizeof(*fi));
+ return -EUCLEAN;
+ }
}
if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 3bf746668e07..9c73ae09f0a1 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -4634,6 +4634,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
u64 extent_offset = em->start - em->orig_start;
u64 block_len;
int ret;
+ u8 encryption = 0;
btrfs_set_stack_file_extent_generation(&fi, trans->transid);
if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
@@ -4655,6 +4656,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
btrfs_set_stack_file_extent_num_bytes(&fi, em->len);
btrfs_set_stack_file_extent_ram_bytes(&fi, em->ram_bytes);
btrfs_set_stack_file_extent_compression(&fi, em->compress_type);
+ btrfs_set_stack_file_extent_encryption(&fi, encryption);
ret = log_extent_csums(trans, inode, log, em, ctx);
if (ret)
diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h
index 029af0aeb65d..62b95ceee735 100644
--- a/include/uapi/linux/btrfs_tree.h
+++ b/include/uapi/linux/btrfs_tree.h
@@ -1048,8 +1048,14 @@ struct btrfs_file_extent_item {
* but not for stat.
*/
__u8 compression;
+
+ /*
+ * Type of encryption in use. Unencrypted value is 0.
+ */
__u8 encryption;
- __le16 other_encoding; /* spare for later use */
+
+ /* spare for later use */
+ __le16 other_encoding;
/* are we inline data or a real extent? */
__u8 type;
@@ -1075,6 +1081,10 @@ struct btrfs_file_extent_item {
* always reflects the size uncompressed and without encoding.
*/
__le64 num_bytes;
+ /*
+ * the encryption context, if any
+ */
+ __u8 encryption_context[0];
} __attribute__ ((__packed__));
--
2.41.0
next prev parent reply other threads:[~2023-08-08 18:10 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-08 17:12 [PATCH v3 00/17] btrfs: add encryption feature Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 01/17] btrfs: disable various operations on encrypted inodes Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 02/17] btrfs: disable verity " Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 03/17] fscrypt: expose fscrypt_nokey_name Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 04/17] btrfs: start using fscrypt hooks Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 05/17] btrfs: add inode encryption contexts Sweet Tea Dorminy
2023-08-09 20:20 ` Josef Bacik
2023-08-08 17:12 ` [PATCH v3 06/17] btrfs: add new FEATURE_INCOMPAT_ENCRYPT flag Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 07/17] btrfs: adapt readdir for encrypted and nokey names Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 08/17] btrfs: handle " Sweet Tea Dorminy
2023-08-09 20:32 ` Josef Bacik
2023-08-08 17:12 ` [PATCH v3 09/17] btrfs: implement fscrypt ioctls Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 10/17] btrfs: add encryption to CONFIG_BTRFS_DEBUG Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 11/17] btrfs: add get_devices hook for fscrypt Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 12/17] btrfs: turn on inlinecrypt mount option for encrypt Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 13/17] btrfs: turn on the encryption ioctls Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 14/17] btrfs: create and free extent fscrypt_infos Sweet Tea Dorminy
2023-08-08 17:12 ` Sweet Tea Dorminy [this message]
2023-08-08 17:12 ` [PATCH v3 16/17] btrfs: explicitly track file extent length and encryption Sweet Tea Dorminy
2023-08-08 17:12 ` [PATCH v3 17/17] btrfs: save and load fscrypt extent contexts Sweet Tea Dorminy
2023-08-09 20:38 ` Josef Bacik
2023-08-09 20:39 ` [PATCH v3 00/17] btrfs: add encryption feature 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=f37e7aab6ca74639a20242be10ce0864bf96cf9c.1691510179.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=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 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).