@@ -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,
@@ -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;
@@ -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,
@@ -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)
@@ -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) ||
@@ -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)
@@ -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__));
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(-)