@@ -3,6 +3,8 @@
#ifndef BTRFS_ACCESSORS_H
#define BTRFS_ACCESSORS_H
+#include "fscrypt.h"
+
struct btrfs_map_token {
struct extent_buffer *eb;
char *kaddr;
@@ -936,6 +938,16 @@ 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);
+static inline u8 btrfs_stack_file_extent_encryption_ctxsize(
+ struct btrfs_file_extent_item *e)
+{
+ u8 ctxsize;
+
+ btrfs_unpack_encryption(e->encryption, NULL, &ctxsize);
+ return ctxsize;
+}
BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
@@ -958,6 +970,25 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
other_encoding, 16);
+static inline u8
+btrfs_file_extent_encryption_ctxsize(const struct extent_buffer *eb,
+ struct btrfs_file_extent_item *e)
+{
+ u8 ctxsize;
+
+ btrfs_unpack_encryption(btrfs_file_extent_encryption(eb, e),
+ NULL, &ctxsize);
+ return ctxsize;
+}
+
+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));
+}
+
/* btrfs_qgroup_status_item */
BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
generation, 64);
@@ -1272,6 +1272,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 -
@@ -1287,6 +1288,10 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
em->compress_type = compress_type;
em->block_start = bytenr;
em->block_len = em->orig_block_len;
+ } else if (btrfs_file_extent_encryption(leaf, fi)) {
+ set_bit(EXTENT_FLAG_ENCRYPTED, &em->flags);
+ em->block_start = bytenr;
+ em->block_len = em->orig_block_len;
} else {
bytenr += btrfs_file_extent_offset(leaf, fi);
em->block_start = bytenr;
@@ -1294,6 +1299,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;
@@ -8,6 +8,30 @@
#include "fs.h"
+#define BTRFS_ENCRYPTION_POLICY_BITS 2
+#define BTRFS_ENCRYPTION_CTXSIZE_BITS 6
+
+#define BTRFS_ENCRYPTION_POLICY_MASK ((1 << BTRFS_ENCRYPTION_POLICY_BITS) - 1)
+#define BTRFS_ENCRYPTION_CTXSIZE_MASK \
+ (((1 << BTRFS_ENCRYPTION_CTXSIZE_BITS) - 1) << \
+ BTRFS_ENCRYPTION_POLICY_BITS)
+
+static inline void btrfs_unpack_encryption(u8 encryption,
+ u8 *policy,
+ u8 *ctxsize)
+{
+ if (policy)
+ *policy = encryption & BTRFS_ENCRYPTION_POLICY_MASK;
+ if (ctxsize)
+ *ctxsize = ((encryption & BTRFS_ENCRYPTION_CTXSIZE_MASK) >>
+ BTRFS_ENCRYPTION_POLICY_BITS);
+}
+
+static inline u8 btrfs_pack_encryption(u8 policy, u8 ctxsize)
+{
+ return policy | (ctxsize << BTRFS_ENCRYPTION_POLICY_BITS);
+}
+
#ifdef CONFIG_FS_ENCRYPTION
bool btrfs_fscrypt_match_name(struct fscrypt_name *fname,
struct extent_buffer *leaf,
@@ -3151,7 +3151,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
@@ -7070,8 +7070,24 @@ 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);
+ u8 policy, ctxsize;
+
+ btrfs_unpack_encryption(encryption, &policy, &ctxsize);
+
+ if (policy == 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) {
/*
@@ -9763,7 +9779,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)
@@ -208,6 +208,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 +260,12 @@ 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))) {
+ btrfs_unpack_encryption(btrfs_file_extent_encryption(leaf, fi),
+ &policy, NULL);
+ 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) ||
@@ -4634,6 +4634,8 @@ 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 = btrfs_pack_encryption(IS_ENCRYPTED(&inode->vfs_inode) ?
+ BTRFS_ENCRYPTION_FSCRYPT : 0, 0);
btrfs_set_stack_file_extent_generation(&fi, trans->transid);
if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
@@ -4655,6 +4657,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)
This puts the long-preserved 1-byte encryption field to work, storing whether the extent is encrypted and the length of its fscrypt_context. Since there is no way for a btrfs inode to be encrypted right now, we set context length to be 0 in all locations. We then update all the locations which check the size of an extent item to expect the size to agree with the context length. The 1-byte field packs the encryption type and context length together, to avoid a format change. Right now we don't anticipate very many encryption policies, so 2 bits should be ample; similarly right now we can't imagine a context larger than fscrypt's current contexts, which are 40 bytes, so 6 bits is ample to store the context's size; and therefore we can pack these together into the one-byte encryption field without touching other space reserved for future use. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> --- fs/btrfs/accessors.h | 31 +++++++++++++++++++++++++++++++ fs/btrfs/file-item.c | 8 ++++++++ fs/btrfs/fscrypt.h | 24 ++++++++++++++++++++++++ fs/btrfs/inode.c | 26 ++++++++++++++++++++++---- fs/btrfs/tree-checker.c | 37 +++++++++++++++++++++++++++++-------- fs/btrfs/tree-log.c | 3 +++ 6 files changed, 117 insertions(+), 12 deletions(-)