@@ -6538,6 +6538,7 @@ static int run_next_block(struct btrfs_root *root,
for (i = 0; i < nritems; i++) {
struct btrfs_file_extent_item *fi;
unsigned long inline_offset;
+ u8 ivsize;
inline_offset = offsetof(struct btrfs_file_extent_item,
disk_bytenr);
@@ -6673,8 +6674,9 @@ static int run_next_block(struct btrfs_root *root,
continue;
/* Prealloc/regular extent must have fixed item size */
+ ivsize = btrfs_file_extent_encryption_ivsize(buf, fi);
if (btrfs_item_size(buf, i) !=
- sizeof(struct btrfs_file_extent_item)) {
+ sizeof(struct btrfs_file_extent_item) + ivsize) {
ret = -EUCLEAN;
error(
"invalid file extent item size, have %u expect %zu",
@@ -25,6 +25,7 @@
#include "kerncompat.h"
#include "common/extent-cache.h"
#include "kernel-shared/extent_io.h"
+#include "kernel-shared/fscrypt.h"
#include "ioctl.h"
struct btrfs_root;
@@ -989,7 +990,10 @@ struct btrfs_file_extent_item {
* uncompressed and without encoding.
*/
__le64 num_bytes;
-
+ /*
+ * The IV used to encrypt the data in this extent.
+ */
+ u8 iv[0];
} __attribute__ ((__packed__));
struct btrfs_dev_stats_item {
@@ -2446,6 +2450,24 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
encryption, 8);
BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
other_encoding, 16);
+static inline u8
+btrfs_file_extent_encryption_ivsize(const struct extent_buffer *eb,
+ struct btrfs_file_extent_item *e)
+{
+ u8 ivsize;
+ btrfs_unpack_encryption(btrfs_file_extent_encryption(eb, e),
+ NULL, &ivsize);
+ return ivsize;
+}
+
+static inline u8
+btrfs_file_extent_ivsize_from_item(const struct extent_buffer *leaf,
+ 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_version, struct btrfs_qgroup_status_item,
new file mode 100644
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_FSCRYPT_H
+#define BTRFS_FSCRYPT_H
+
+#define BTRFS_ENCRYPTION_POLICY_MASK 0x0f
+#define BTRFS_ENCRYPTION_IVSIZE_MASK 0xf0
+
+/* Actually from include/linux/fscrypt.h */
+#define FSCRYPT_MAX_IV_SIZE 32
+
+static inline void btrfs_unpack_encryption(u8 encryption,
+ u8 *policy,
+ u8 *ivsize)
+{
+ if (policy)
+ *policy = encryption & BTRFS_ENCRYPTION_POLICY_MASK;
+ if (ivsize) {
+ u8 transformed_ivsize =
+ (encryption & BTRFS_ENCRYPTION_IVSIZE_MASK) >> 4;
+ *ivsize = (transformed_ivsize ?
+ (1 << (transformed_ivsize - 1)) : 0);
+ }
+}
+
+static inline u8 btrfs_pack_encryption(u8 policy, u8 ivsize)
+{
+ u8 transformed_ivsize = ivsize ? ilog2(ivsize) + 1 : 0;
+ return policy | (transformed_ivsize << 4);
+}
+
+#endif // BTRFS_FSCRYPT_H
@@ -354,6 +354,26 @@ static void compress_type_to_str(u8 compress_type, char *ret)
}
}
+static void generate_encryption_string(struct extent_buffer *leaf,
+ struct btrfs_file_extent_item *fi,
+ char *ret)
+{
+ u8 encryption = btrfs_file_extent_encryption(leaf, fi);
+ u8 policy, ivsize;
+ u8 iv[FSCRYPT_MAX_IV_SIZE];
+ btrfs_unpack_encryption(encryption, &policy, &ivsize);
+ if (ivsize)
+ read_extent_buffer(leaf, iv, (unsigned long)fi->iv, ivsize);
+ ret += sprintf(ret, "(%hhu, %hhu", policy, ivsize);
+ if (ivsize) {
+ int i;
+ ret += sprintf(ret, ": IV ");
+ for (i = 0; i < ivsize; i++)
+ ret += sprintf(ret, "%02hhx", iv[i]);
+ }
+ sprintf(ret, ")");
+}
+
static const char* file_extent_type_to_str(u8 type)
{
switch (type) {
@@ -370,9 +390,11 @@ static void print_file_extent_item(struct extent_buffer *eb,
{
unsigned char extent_type = btrfs_file_extent_type(eb, fi);
char compress_str[16];
+ char encrypt_str[16];
compress_type_to_str(btrfs_file_extent_compression(eb, fi),
compress_str);
+ generate_encryption_string(eb, fi, encrypt_str);
printf("\t\tgeneration %llu type %hhu (%s)\n",
btrfs_file_extent_generation(eb, fi),
@@ -405,6 +427,9 @@ static void print_file_extent_item(struct extent_buffer *eb,
printf("\t\textent compression %hhu (%s)\n",
btrfs_file_extent_compression(eb, fi),
compress_str);
+ printf("\t\textent encryption %hhu (%s)\n",
+ btrfs_file_extent_encryption(eb, fi),
+ encrypt_str);
}
/* Caller should ensure sizeof(*ret) >= 16("DATA|TREE_BLOCK") */
Encrypted file extents now have the 'encryption' field set to a encryption type plus an IV length, and have an IV appended to the item. This necessitates adjusting the struct to have a variable-length iv member at the end, and printing IVs if one is provided. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> --- check/main.c | 4 +++- kernel-shared/ctree.h | 24 +++++++++++++++++++++++- kernel-shared/fscrypt.h | 32 ++++++++++++++++++++++++++++++++ kernel-shared/print-tree.c | 25 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 kernel-shared/fscrypt.h