@@ -38,6 +38,7 @@ btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
btrfs-$(CONFIG_BTRFS_FS_REF_VERIFY) += ref-verify.o
btrfs-$(CONFIG_BLK_DEV_ZONED) += zoned.o
btrfs-$(CONFIG_FS_VERITY) += verity.o
+btrfs-$(CONFIG_FS_ENCRYPTION) += fscrypt.o
btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \
tests/extent-buffer-tests.o tests/btrfs-tests.o \
@@ -5,6 +5,7 @@
#include "ctree.h"
#include "disk-io.h"
+#include "fscrypt.h"
#include "transaction.h"
/*
@@ -390,15 +391,15 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
total_len = btrfs_item_size(leaf, path->slots[0]);
while (cur < total_len) {
- unsigned long name_ptr = (unsigned long)(dir_item + 1);
- this_len = sizeof(*dir_item) +
- btrfs_dir_name_len(leaf, dir_item) +
+ int dir_name_len = btrfs_dir_name_len(leaf, dir_item);
+ this_len = sizeof(*dir_item) + dir_name_len +
btrfs_dir_data_len(leaf, dir_item);
- if (btrfs_dir_name_len(leaf, dir_item) == fname_len(fname) &&
- memcmp_extent_buffer(leaf, fname_name(fname), name_ptr,
- fname_len(fname)) == 0)
+ if (btrfs_fscrypt_match_name(fname, leaf,
+ (unsigned long)(dir_item + 1),
+ dir_name_len)) {
return dir_item;
+ }
cur += this_len;
dir_item = (struct btrfs_dir_item *)((char *)dir_item +
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include <crypto/sha2.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/bio.h>
@@ -6956,6 +6957,42 @@ void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start,
}
}
+void extent_buffer_sha256(const struct extent_buffer *eb, unsigned long start,
+ unsigned long len, u8 *out)
+{
+ size_t cur;
+ size_t offset;
+ struct page *page;
+ char *kaddr;
+ unsigned long i = get_eb_page_index(start);
+ struct sha256_state sctx;
+
+ if (check_eb_range(eb, start, len))
+ return;
+
+ offset = get_eb_offset_in_page(eb, start);
+
+ /*
+ * TODO: This should maybe be using the crypto API, not the fallback,
+ * but fscrypt uses the fallback and this is only used in emulation of
+ * fscrypt's buffer sha256 method.
+ */
+ sha256_init(&sctx);
+ while (len > 0) {
+ page = eb->pages[i];
+ assert_eb_page_uptodate(eb, page);
+
+ cur = min(len, PAGE_SIZE - offset);
+ kaddr = page_address(page);
+ sha256_update(&sctx, (u8 *)(kaddr + offset), cur);
+
+ len -= cur;
+ offset = 0;
+ i++;
+ }
+ sha256_final(&sctx, out);
+}
+
void copy_extent_buffer_full(const struct extent_buffer *dst,
const struct extent_buffer *src)
{
@@ -223,6 +223,8 @@ void memmove_extent_buffer(const struct extent_buffer *dst,
unsigned long len);
void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start,
unsigned long len);
+void extent_buffer_sha256(const struct extent_buffer *eb, unsigned long start,
+ unsigned long len, u8 *out);
int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start,
unsigned long pos);
void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long start,
new file mode 100644
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Facebook
+ */
+
+#include "ctree.h"
+#include "fscrypt.h"
+
+/* fscrypt_match_name() but for an extent_buffer. */
+bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname,
+ struct extent_buffer *leaf, unsigned long de_name,
+ u32 de_name_len)
+{
+ const struct fscrypt_nokey_name *nokey_name =
+ (const void *)fname->crypto_buf.name;
+ u8 digest[SHA256_DIGEST_SIZE];
+
+ if (likely(fname->disk_name.name)) {
+ if (de_name_len != fname->disk_name.len)
+ return false;
+ return !memcmp_extent_buffer(leaf, fname->disk_name.name,
+ de_name, de_name_len);
+ }
+ if (de_name_len <= sizeof(nokey_name->bytes))
+ return false;
+ if (memcmp_extent_buffer(leaf, nokey_name->bytes, de_name,
+ sizeof(nokey_name->bytes)))
+ return false;
+ extent_buffer_sha256(leaf, de_name + sizeof(nokey_name->bytes),
+ de_name_len - sizeof(nokey_name->bytes), digest);
+ return !memcmp(digest, nokey_name->sha256, sizeof(digest));
+}
new file mode 100644
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_FSCRYPT_H
+#define BTRFS_FSCRYPT_H
+
+#include <linux/fscrypt.h>
+
+#ifdef CONFIG_FS_ENCRYPTION
+bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname,
+ struct extent_buffer *leaf,
+ unsigned long de_name, u32 de_name_len);
+
+#else
+static bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname,
+ struct extent_buffer *leaf,
+ unsigned long de_name, u32 de_name_len)
+{
+ if (de_name_len != fname->disk_name.len)
+ return false;
+ return !memcmp_extent_buffer(leaf, fname->disk_name.name,
+ de_name, de_name_len);
+}
+#endif
+
+#endif /* BTRFS_FSCRYPT_H */
@@ -7,6 +7,7 @@
#include "ctree.h"
#include "inode-item.h"
#include "disk-io.h"
+#include "fscrypt.h"
#include "transaction.h"
#include "print-tree.h"
@@ -62,10 +63,9 @@ struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
name_ptr = (unsigned long)(&extref->name);
ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
- if (ref_name_len == fname_len(fname) &&
- btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
- (memcmp_extent_buffer(leaf, fname_name(fname), name_ptr,
- fname_len(fname)) == 0))
+ if (btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
+ btrfs_fscrypt_match_name(fname, leaf, name_ptr,
+ ref_name_len))
return extref;
cur_offset += ref_name_len + sizeof(*extref);
@@ -55,6 +55,7 @@
#include "zoned.h"
#include "subpage.h"
#include "inode-item.h"
+#include "fscrypt.h"
struct btrfs_iget_args {
u64 ino;
@@ -5650,14 +5651,10 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info,
leaf = path->nodes[0];
ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
- if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(BTRFS_I(dir)) ||
- btrfs_root_ref_name_len(leaf, ref) != dentry->d_name.len)
+ if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(BTRFS_I(dir)))
goto out;
-
- ret = memcmp_extent_buffer(leaf, dentry->d_name.name,
- (unsigned long)(ref + 1),
- dentry->d_name.len);
- if (ret)
+ if (!btrfs_fscrypt_match_name(&fname, leaf, (unsigned long)(ref + 1),
+ btrfs_root_ref_name_len(leaf, ref)))
goto out;
btrfs_release_path(path);
@@ -8,6 +8,7 @@
#include "ctree.h"
#include "transaction.h"
#include "disk-io.h"
+#include "fscrypt.h"
#include "print-tree.h"
#include "qgroup.h"
#include "space-info.h"
@@ -352,14 +353,14 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
if (ret < 0)
goto out;
if (ret == 0) {
+ u32 name_len;
leaf = path->nodes[0];
ref = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_root_ref);
ptr = (unsigned long)(ref + 1);
+ name_len = btrfs_root_ref_name_len(leaf, ref);
if ((btrfs_root_ref_dirid(leaf, ref) != dirid) ||
- (btrfs_root_ref_name_len(leaf, ref) != fname_len(fname)) ||
- memcmp_extent_buffer(leaf, fname_name(fname), ptr,
- fname_len(fname))) {
+ !btrfs_fscrypt_match_name(fname, leaf, ptr, name_len)) {
err = -ENOENT;
goto out;
}