@@ -932,6 +932,10 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
nr_global_roots, 64);
+/* struct btrfs_file_extent_encryption_info */
+BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size,
+ 32);
+
/* struct btrfs_file_extent_item */
BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
type, 8);
@@ -970,6 +974,50 @@ 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 struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
+ const struct btrfs_file_extent_item *ei)
+{
+ unsigned long offset = (unsigned long)ei;
+
+ offset += offsetof(struct btrfs_file_extent_item, encryption_info);
+ return (struct btrfs_encryption_info *)offset;
+}
+
+static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
+ const struct btrfs_file_extent_item *ei)
+{
+ unsigned long offset = (unsigned long)ei;
+
+ offset += offsetof(struct btrfs_file_extent_item, encryption_info);
+ return offset + offsetof(struct btrfs_encryption_info, context);
+}
+
+static inline u32 btrfs_file_extent_encryption_ctx_size(
+ const struct extent_buffer *eb,
+ const struct btrfs_file_extent_item *ei)
+{
+ return btrfs_encryption_info_size(eb,
+ btrfs_file_extent_encryption_info(ei));
+}
+
+static inline void btrfs_set_file_extent_encryption_ctx_size(
+ const struct extent_buffer *eb,
+ struct btrfs_file_extent_item *ei,
+ u32 val)
+{
+ btrfs_set_encryption_info_size(eb,
+ btrfs_file_extent_encryption_info(ei),
+ val);
+}
+
+static inline u32 btrfs_file_extent_encryption_info_size(
+ const struct extent_buffer *eb,
+ const struct btrfs_file_extent_item *ei)
+{
+ return btrfs_encryption_info_size(eb,
+ btrfs_file_extent_encryption_info(ei));
+}
+
/* btrfs_qgroup_status_item */
BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
generation, 64);
@@ -229,6 +229,8 @@ 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;
+ u8 fe_type;
if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
file_extent_err(leaf, slot,
@@ -259,12 +261,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
SZ_4K);
return -EUCLEAN;
}
- if (unlikely(btrfs_file_extent_type(leaf, fi) >=
- BTRFS_NR_FILE_EXTENT_TYPES)) {
+
+ fe_type = btrfs_file_extent_type(leaf, fi);
+ if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
file_extent_err(leaf, slot,
"invalid type for file extent, have %u expect range [0, %u]",
- btrfs_file_extent_type(leaf, fi),
- BTRFS_NR_FILE_EXTENT_TYPES - 1);
+ fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
return -EUCLEAN;
}
@@ -286,6 +288,13 @@ static int check_extent_data_item(struct extent_buffer *leaf,
btrfs_file_extent_encryption(leaf, fi));
return -EUCLEAN;
}
+ 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 range [0, %u]",
+ policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
+ return -EUCLEAN;
+ }
if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
/* Inline extent must have 0 as key offset */
if (unlikely(key->offset)) {
@@ -312,12 +321,51 @@ 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) {
+ size_t fe_size = sizeof(*fi) +
+ sizeof(struct btrfs_encryption_info);
+ u32 ctxsize;
+
+ if (unlikely(item_size < fe_size)) {
+ file_extent_err(leaf, slot,
+ "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
+ item_size, sizeof(*fi));
+ return -EUCLEAN;
+ }
+
+ ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
+ if (unlikely(item_size != (fe_size + ctxsize))) {
+ file_extent_err(leaf, slot,
+ "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
+ item_size, fe_size, ctxsize);
+ return -EUCLEAN;
+ }
+
+ if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
+ file_extent_err(leaf, slot,
+ "invalid file extent context size, have %u expect a maximum of %u",
+ ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
+ return -EUCLEAN;
+ }
+
+ /*
+ * Only regular and prealloc extents should have an encryption
+ * context.
+ */
+ if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
+ fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
+ file_extent_err(leaf, slot,
+ "invalid type for encrypted file extent, have %u",
+ btrfs_file_extent_type(leaf, fi));
+ 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) ||
@@ -1016,6 +1016,24 @@ enum {
BTRFS_NR_FILE_EXTENT_TYPES = 3,
};
+/*
+ * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
+ * current extent context size from fscrypt, so this should give us plenty of
+ * breathing room for expansion later.
+ */
+#define BTRFS_MAX_EXTENT_CTX_SIZE 40
+
+enum {
+ BTRFS_ENCRYPTION_NONE,
+ BTRFS_ENCRYPTION_FSCRYPT,
+ BTRFS_NR_ENCRYPTION_TYPES,
+};
+
+struct btrfs_encryption_info {
+ __le32 size;
+ __u8 context[0];
+};
+
struct btrfs_file_extent_item {
/*
* transaction id that created this extent
@@ -1065,7 +1083,10 @@ struct btrfs_file_extent_item {
* always reflects the size uncompressed and without encoding.
*/
__le64 num_bytes;
-
+ /*
+ * the encryption info, if any
+ */
+ struct btrfs_encryption_info encryption_info[0];
} __attribute__ ((__packed__));
struct btrfs_csum_item {