All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Add file-system authentication to BTRFS
@ 2020-05-14  9:24 Johannes Thumshirn
  2020-05-14  9:24 ` [PATCH v3 1/3] btrfs: rename btrfs_parse_device_options back to btrfs_parse_early_options Johannes Thumshirn
                   ` (4 more replies)
  0 siblings, 5 replies; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-14  9:24 UTC (permalink / raw)
  To: David Sterba
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn

From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

This series adds file-system authentication to BTRFS. 

Unlike other verified file-system techniques like fs-verity the
authenticated version of BTRFS does not need extra meta-data on disk.

This works because in BTRFS every on-disk block has a checksum, for meta-data
the checksum is in the header of each meta-data item. For data blocks, a
separate checksum tree exists, which holds the checksums for each block.

Currently BRTFS supports CRC32C, XXHASH64, SHA256 and Blake2b for checksumming
these blocks. This series adds a new checksum algorithm, HMAC(SHA-256), which
does need an authentication key. When no, or an incoreect authentication key
is supplied no valid checksum can be generated and a read, fsck or scrub
operation would detect invalid or tampered blocks once the file-system is
mounted again with the correct key. 

Getting the key inside the kernel is out of scope of this implementation, the
file-system driver assumes the key is already in the kernel's keyring at mount
time.

There was interest in also using keyed Blake2b from the community, but this
support is not yet included.

I have CCed Eric Biggers and Richard Weinberger in the submission, as they
previously have worked on filesystem authentication and I hope we can get
input from them as well.

Example usage:
Create a file-system with authentication key 0123456
mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk

Add the key to the kernel's keyring as keyid 'btrfs:foo'
keyctl add logon btrfs:foo 0123456 @u

Mount the fs using the 'btrfs:foo' key
mount -t btrfs -o auth_key=btrfs:foo,auth_hash_name="hmac(sha256)" /dev/disk /mnt/point

Note, this is a re-base of the work I did when I was still at SUSE, hence the
S-o-b being my SUSE address, while the Author being with my WDC address (to
not generate bouncing mails).

Changes since v2:
- Select CONFIG_CRYPTO_HMAC and CONFIG_KEYS (kbuild robot)
- Fix double free in error path
- Fix memory leak in error path
- Disallow nodatasum and nodatacow when authetication is use (Eric)
- Pass in authentication algorithm as mount option (Eric)
- Don't use the work "replay" in the documentation, as it is wrong and
  harmful in this context (Eric)
- Force key name to begin with 'btrfs:' (Eric)
- Use '4' as on-disk checksum type for HMAC(SHA256) to not have holes in the
  checksum types array.

Changes since v1:
- None, only rebased the series

Johannes Thumshirn (3):
  btrfs: rename btrfs_parse_device_options back to
    btrfs_parse_early_options
  btrfs: add authentication support
  btrfs: document btrfs authentication

 .../filesystems/btrfs-authentication.rst      | 168 ++++++++++++++++++
 fs/btrfs/Kconfig                              |   2 +
 fs/btrfs/ctree.c                              |  22 ++-
 fs/btrfs/ctree.h                              |   5 +-
 fs/btrfs/disk-io.c                            |  71 +++++++-
 fs/btrfs/ioctl.c                              |   7 +-
 fs/btrfs/super.c                              |  65 ++++++-
 include/uapi/linux/btrfs_tree.h               |   1 +
 8 files changed, 326 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/filesystems/btrfs-authentication.rst

-- 
2.26.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v3 1/3] btrfs: rename btrfs_parse_device_options back to btrfs_parse_early_options
  2020-05-14  9:24 [PATCH v3 0/3] Add file-system authentication to BTRFS Johannes Thumshirn
@ 2020-05-14  9:24 ` Johannes Thumshirn
  2020-05-14  9:24 ` [PATCH v3 2/3] btrfs: add authentication support Johannes Thumshirn
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-14  9:24 UTC (permalink / raw)
  To: David Sterba
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn, Johannes Thumshirn

From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

As btrfs_parse_device_options() now doesn't only parse the -o device mount
option but -o auth_key as well, it makes sense to rename it back to
btrfs_parse_early_options().

This reverts commit fa59f27c8c35bbe00af8eff23de446a7f4b048b0.

Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
---
 fs/btrfs/super.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 438ecba26557..07cec0d16348 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -482,8 +482,9 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 		case Opt_subvolrootid:
 		case Opt_device:
 			/*
-			 * These are parsed by btrfs_parse_subvol_options or
-			 * btrfs_parse_device_options and can be ignored here.
+			 * These are parsed by btrfs_parse_subvol_options
+			 * and btrfs_parse_early_options
+			 * and can be happily ignored here.
 			 */
 			break;
 		case Opt_nodatasum:
@@ -919,8 +920,9 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
  * All other options will be parsed on much later in the mount process and
  * only when we need to allocate a new super block.
  */
-static int btrfs_parse_device_options(const char *options, fmode_t flags,
-				      void *holder)
+static int btrfs_parse_early_options(struct btrfs_fs_info *info,
+				     const char *options, fmode_t flags,
+				     void *holder)
 {
 	substring_t args[MAX_OPT_ARGS];
 	char *device_name, *opts, *orig, *p;
@@ -987,7 +989,7 @@ static int btrfs_parse_subvol_options(const char *options, char **subvol_name,
 
 	/*
 	 * strsep changes the string, duplicate it because
-	 * btrfs_parse_device_options gets called later
+	 * btrfs_parse_early_options gets called later
 	 */
 	opts = kstrdup(options, GFP_KERNEL);
 	if (!opts)
@@ -1551,7 +1553,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 	}
 
 	mutex_lock(&uuid_mutex);
-	error = btrfs_parse_device_options(data, mode, fs_type);
+	error = btrfs_parse_early_options(fs_info, data, mode, fs_type);
 	if (error) {
 		mutex_unlock(&uuid_mutex);
 		goto error_fs_info;
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v3 2/3] btrfs: add authentication support
  2020-05-14  9:24 [PATCH v3 0/3] Add file-system authentication to BTRFS Johannes Thumshirn
  2020-05-14  9:24 ` [PATCH v3 1/3] btrfs: rename btrfs_parse_device_options back to btrfs_parse_early_options Johannes Thumshirn
@ 2020-05-14  9:24 ` Johannes Thumshirn
  2020-05-27 13:24   ` David Sterba
  2020-05-14  9:24 ` [PATCH v3 3/3] btrfs: document btrfs authentication Johannes Thumshirn
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-14  9:24 UTC (permalink / raw)
  To: David Sterba
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn, Johannes Thumshirn

From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

Add authentication support for a BTRFS file-system.

This works, because in BTRFS every meta-data block as well as every
data-block has a own checksum. For meta-data the checksum is in the
meta-data node itself. For data blocks, the checksums are stored in the
checksum tree.

When replacing the checksum algorithm with a keyed hash, like HMAC(SHA256),
a key is needed to mount a verified file-system. This key also needs to be
used at file-system creation time.

We have to used a keyed hash scheme, in contrast to doing a normal
cryptographic hash, to guarantee integrity of the file system, as a
potential attacker could just generate the corresponding cryptographic
hash for forged file-system operations and the changes would go unnoticed.

Having a keyed hash only on the topmost Node of a tree or even just in the
super-block and using cryptographic hashes on the normal meta-data nodes
and checksum tree entries doesn't work either, as the BTRFS B-Tree's Nodes
do not include the checksums of their respective child nodes, but only the
block pointers and offsets where to find them on disk.

Also note, we do not need a incompat R/O flag for this, because if an old
kernel tries to mount an authenticated file-system it will fail the
initial checksum type verification and thus refuses to mount.

The key has to be supplied by the kernel's keyring and the method of
getting the key securely into the kernel is not subject of this patch.

Example usage:
Create a file-system with authentication key 0123456
mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk

Add the key to the kernel's keyring as keyid 'btrfs:foo'
keyctl add logon btrfs:foo 0123456 @u

Mount the fs using the 'btrfs:foo' key
mount -o auth_key=btrfs:foo,auth_hash_name="hmac(sha256)" /dev/disk /mnt/point

Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>

---
 fs/btrfs/Kconfig                |  2 +
 fs/btrfs/ctree.c                | 22 +++++++++-
 fs/btrfs/ctree.h                |  5 ++-
 fs/btrfs/disk-io.c              | 71 +++++++++++++++++++++++++++++++--
 fs/btrfs/ioctl.c                |  7 +++-
 fs/btrfs/super.c                | 51 ++++++++++++++++++++++-
 include/uapi/linux/btrfs_tree.h |  1 +
 7 files changed, 150 insertions(+), 9 deletions(-)

diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index 575636f6491e..b7e9ce25b622 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -8,6 +8,8 @@ config BTRFS_FS
 	select CRYPTO_XXHASH
 	select CRYPTO_SHA256
 	select CRYPTO_BLAKE2B
+	select CRYPTO_HMAC
+	select KEYS
 	select ZLIB_INFLATE
 	select ZLIB_DEFLATE
 	select LZO_COMPRESS
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 746dec22f250..2907bd054dd6 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -31,7 +31,7 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
 
 static const struct btrfs_csums {
 	u16		size;
-	const char	name[10];
+	const char	name[12];
 	const char	driver[12];
 } btrfs_csums[] = {
 	[BTRFS_CSUM_TYPE_CRC32] = { .size = 4, .name = "crc32c" },
@@ -39,6 +39,7 @@ static const struct btrfs_csums {
 	[BTRFS_CSUM_TYPE_SHA256] = { .size = 32, .name = "sha256" },
 	[BTRFS_CSUM_TYPE_BLAKE2] = { .size = 32, .name = "blake2b",
 				     .driver = "blake2b-256" },
+	[BTRFS_CSUM_TYPE_HMAC_SHA256] = { .size = 32, .name = "hmac(sha256)" }
 };
 
 int btrfs_super_csum_size(const struct btrfs_super_block *s)
@@ -56,12 +57,29 @@ const char *btrfs_super_csum_name(u16 csum_type)
 	return btrfs_csums[csum_type].name;
 }
 
+static const char *btrfs_auth_csum_driver(struct btrfs_fs_info *fs_info)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(btrfs_csums); i++) {
+		if (!strncmp(fs_info->auth_hash_name, btrfs_csums[i].name,
+			     strlen(btrfs_csums[i].name)))
+			return btrfs_csums[i].driver[0] ?
+				btrfs_csums[i].driver : btrfs_csums[i].name;
+	}
+
+	return NULL;
+}
+
 /*
  * Return driver name if defined, otherwise the name that's also a valid driver
  * name
  */
-const char *btrfs_super_csum_driver(u16 csum_type)
+const char *btrfs_super_csum_driver(struct btrfs_fs_info *info, u16 csum_type)
 {
+	if (btrfs_test_opt(info, AUTH_KEY))
+		return btrfs_auth_csum_driver(info);
+
 	/* csum type is validated at mount time */
 	return btrfs_csums[csum_type].driver[0] ?
 		btrfs_csums[csum_type].driver :
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 0a1fa1526c43..b9e4cf5b9fd3 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -931,6 +931,8 @@ struct btrfs_fs_info {
 	struct rb_root swapfile_pins;
 
 	struct crypto_shash *csum_shash;
+	char *auth_key_name;
+	char *auth_hash_name;
 
 	/*
 	 * Number of send operations in progress.
@@ -1239,6 +1241,7 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info)
 #define BTRFS_MOUNT_NOLOGREPLAY		(1 << 27)
 #define BTRFS_MOUNT_REF_VERIFY		(1 << 28)
 #define BTRFS_MOUNT_DISCARD_ASYNC	(1 << 29)
+#define BTRFS_MOUNT_AUTH_KEY		(1 << 30)
 
 #define BTRFS_DEFAULT_COMMIT_INTERVAL	(30)
 #define BTRFS_DEFAULT_MAX_INLINE	(2048)
@@ -2186,7 +2189,7 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
 
 int btrfs_super_csum_size(const struct btrfs_super_block *s);
 const char *btrfs_super_csum_name(u16 csum_type);
-const char *btrfs_super_csum_driver(u16 csum_type);
+const char *btrfs_super_csum_driver(struct btrfs_fs_info *info, u16 csum_type);
 size_t __const btrfs_get_num_csums(void);
 
 
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 714b57553ed6..6ed5d1191cdf 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -17,6 +17,7 @@
 #include <linux/error-injection.h>
 #include <linux/crc32c.h>
 #include <linux/sched/mm.h>
+#include <keys/user-type.h>
 #include <asm/unaligned.h>
 #include <crypto/hash.h>
 #include "ctree.h"
@@ -100,8 +101,10 @@ void __cold btrfs_end_io_wq_exit(void)
 
 static void btrfs_free_csum_hash(struct btrfs_fs_info *fs_info)
 {
-	if (fs_info->csum_shash)
+	if (fs_info->csum_shash) {
 		crypto_free_shash(fs_info->csum_shash);
+		fs_info->csum_shash = NULL;
+	}
 }
 
 /*
@@ -339,6 +342,7 @@ static bool btrfs_supported_super_csum(u16 csum_type)
 	case BTRFS_CSUM_TYPE_XXHASH:
 	case BTRFS_CSUM_TYPE_SHA256:
 	case BTRFS_CSUM_TYPE_BLAKE2:
+	case BTRFS_CSUM_TYPE_HMAC_SHA256:
 		return true;
 	default:
 		return false;
@@ -1509,6 +1513,8 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
 	percpu_counter_destroy(&fs_info->dio_bytes);
 	percpu_counter_destroy(&fs_info->dev_replace.bio_counter);
 	btrfs_free_csum_hash(fs_info);
+	kfree(fs_info->auth_key_name);
+	kfree(fs_info->auth_hash_name);
 	btrfs_free_stripe_hash_table(fs_info);
 	btrfs_free_ref_cache(fs_info);
 	kfree(fs_info->balance_ctl);
@@ -2178,10 +2184,16 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info,
 static int btrfs_init_csum_hash(struct btrfs_fs_info *fs_info, u16 csum_type)
 {
 	struct crypto_shash *csum_shash;
-	const char *csum_driver = btrfs_super_csum_driver(csum_type);
+	const char *csum_driver;
+	struct key *key;
+	const struct user_key_payload *ukp;
+	int err = -EINVAL;
 
-	csum_shash = crypto_alloc_shash(csum_driver, 0, 0);
+	csum_driver = btrfs_super_csum_driver(fs_info, csum_type);
+	if (!csum_driver)
+		return err;
 
+	csum_shash = crypto_alloc_shash(csum_driver, 0, 0);
 	if (IS_ERR(csum_shash)) {
 		btrfs_err(fs_info, "error allocating %s hash for checksum",
 			  csum_driver);
@@ -2190,7 +2202,57 @@ static int btrfs_init_csum_hash(struct btrfs_fs_info *fs_info, u16 csum_type)
 
 	fs_info->csum_shash = csum_shash;
 
-	return 0;
+	/*
+	 * If we're not doing authentication, we're done by now. If we use
+	 * authentication and the auth_hash_name was bogus crypt_alloc_shash
+	 * would have dropped out by now. Validation that both auth_hash_name
+	 * and auth_key_name have been supplied is done in
+	 * btrfs_parse_early_options(), so we should be good to go from here on
+	 * and start authenticating the file-system.
+	 */
+	if (!btrfs_test_opt(fs_info, AUTH_KEY))
+		return 0;
+
+	if (strncmp(fs_info->auth_key_name, "btrfs:", 6)) {
+		btrfs_err(fs_info,
+			  "authentication key must start with 'btrfs:'");
+		goto out_free_hash;
+	}
+
+	key = request_key(&key_type_logon, fs_info->auth_key_name, NULL);
+	if (IS_ERR(key)) {
+		err = PTR_ERR(key);
+		goto out_free_hash;
+	}
+
+	down_read(&key->sem);
+
+	ukp = user_key_payload_locked(key);
+	if (!ukp) {
+		btrfs_err(fs_info, "error getting payload for key %s",
+			  fs_info->auth_key_name);
+		err = -EKEYREVOKED;
+		goto out;
+	}
+
+	err = crypto_shash_setkey(fs_info->csum_shash, ukp->data, ukp->datalen);
+	if (err)
+		btrfs_err(fs_info, "error setting key %s for verification",
+			  fs_info->auth_key_name);
+
+out:
+	if (err) {
+		btrfs_free_csum_hash(fs_info);
+	}
+
+	up_read(&key->sem);
+	key_put(key);
+
+	return err;
+
+out_free_hash:
+	btrfs_free_csum_hash(fs_info);
+	return err;
 }
 
 static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
@@ -3371,6 +3433,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
 	btrfs_stop_all_workers(fs_info);
 	btrfs_free_block_groups(fs_info);
 fail_alloc:
+	btrfs_free_csum_hash(fs_info);
 	btrfs_mapping_tree_free(&fs_info->mapping_tree);
 
 	iput(fs_info->btree_inode);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 40b729dce91c..59bbb2c860d5 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -242,7 +242,12 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 	else
 		binode_flags &= ~BTRFS_INODE_DIRSYNC;
 	if (fsflags & FS_NOCOW_FL) {
-		if (S_ISREG(inode->i_mode)) {
+		if (btrfs_test_opt(fs_info, AUTH_KEY)) {
+			btrfs_err(fs_info,
+				  "Cannot set nodatacow or nodatasum on authenticated file-system");
+			ret = -EPERM;
+			goto out_unlock;
+		} else if (S_ISREG(inode->i_mode)) {
 			/*
 			 * It's safe to turn csums off here, no extents exist.
 			 * Otherwise we want the flag to reflect the real COW
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 07cec0d16348..88164b916c28 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -342,6 +342,8 @@ enum {
 	Opt_treelog, Opt_notreelog,
 	Opt_usebackuproot,
 	Opt_user_subvol_rm_allowed,
+	Opt_auth_key,
+	Opt_auth_hash_name,
 
 	/* Deprecated options */
 	Opt_alloc_start,
@@ -410,6 +412,8 @@ static const match_table_t tokens = {
 	{Opt_notreelog, "notreelog"},
 	{Opt_usebackuproot, "usebackuproot"},
 	{Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
+	{Opt_auth_key, "auth_key=%s"},
+	{Opt_auth_hash_name, "auth_hash_name=%s"},
 
 	/* Deprecated options */
 	{Opt_alloc_start, "alloc_start=%s"},
@@ -488,6 +492,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			 */
 			break;
 		case Opt_nodatasum:
+			if (btrfs_test_opt(info, AUTH_KEY)) {
+				btrfs_info(info,
+					   "nodatasum not supported on an authnticated file-system");
+				break;
+			}
 			btrfs_set_and_info(info, NODATASUM,
 					   "setting nodatasum");
 			break;
@@ -503,6 +512,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			btrfs_clear_opt(info->mount_opt, NODATASUM);
 			break;
 		case Opt_nodatacow:
+			if (btrfs_test_opt(info, AUTH_KEY)) {
+				btrfs_info(info,
+					   "nodatacow not supported on an authnticated file-system");
+				break;
+			}
 			if (!btrfs_test_opt(info, NODATACOW)) {
 				if (!btrfs_test_opt(info, COMPRESS) ||
 				    !btrfs_test_opt(info, FORCE_COMPRESS)) {
@@ -950,7 +964,8 @@ static int btrfs_parse_early_options(struct btrfs_fs_info *info,
 			continue;
 
 		token = match_token(p, tokens, args);
-		if (token == Opt_device) {
+		switch (token) {
+		case Opt_device:
 			device_name = match_strdup(&args[0]);
 			if (!device_name) {
 				error = -ENOMEM;
@@ -963,9 +978,40 @@ static int btrfs_parse_early_options(struct btrfs_fs_info *info,
 				error = PTR_ERR(device);
 				goto out;
 			}
+			break;
+		case Opt_auth_key:
+			info->auth_key_name = match_strdup(&args[0]);
+			if (!info->auth_key_name) {
+				error = -ENOMEM;
+				goto out;
+			}
+			break;
+		case Opt_auth_hash_name:
+			info->auth_hash_name = match_strdup(&args[0]);
+			if (!info->auth_hash_name) {
+				error = -ENOMEM;
+				goto out;
+			}
+			break;
+		default:
+			break;
 		}
 	}
 
+	/*
+	 * Check that both auth_key_name and auth_hash_name are either present
+	 * or absent and error out if only one of them is set.
+	 */
+	if (info->auth_key_name && info->auth_hash_name) {
+		btrfs_info(info, "doing authentication");
+		btrfs_set_opt(info->mount_opt, AUTH_KEY);
+	} else if ((info->auth_key_name && !info->auth_hash_name) ||
+		   (!info->auth_key_name && info->auth_hash_name)) {
+		btrfs_err(info,
+			  "auth_key and auth_hash_name must be supplied together");
+		error = -EINVAL;
+	}
+
 out:
 	kfree(orig);
 	return error;
@@ -1405,6 +1451,8 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
 #endif
 	if (btrfs_test_opt(info, REF_VERIFY))
 		seq_puts(seq, ",ref_verify");
+	if (btrfs_test_opt(info, AUTH_KEY))
+		seq_printf(seq, ",auth_key=%s", info->auth_key_name);
 	seq_printf(seq, ",subvolid=%llu",
 		  BTRFS_I(d_inode(dentry))->root->root_key.objectid);
 	seq_puts(seq, ",subvol=");
@@ -2526,4 +2574,5 @@ MODULE_LICENSE("GPL");
 MODULE_SOFTDEP("pre: crc32c");
 MODULE_SOFTDEP("pre: xxhash64");
 MODULE_SOFTDEP("pre: sha256");
+MODULE_SOFTDEP("pre: hmac");
 MODULE_SOFTDEP("pre: blake2b-256");
diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h
index a3f3975df0de..dfc22b995f60 100644
--- a/include/uapi/linux/btrfs_tree.h
+++ b/include/uapi/linux/btrfs_tree.h
@@ -305,6 +305,7 @@ enum btrfs_csum_type {
 	BTRFS_CSUM_TYPE_XXHASH	= 1,
 	BTRFS_CSUM_TYPE_SHA256	= 2,
 	BTRFS_CSUM_TYPE_BLAKE2	= 3,
+	BTRFS_CSUM_TYPE_HMAC_SHA256 = 4,
 };
 
 /*
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-14  9:24 [PATCH v3 0/3] Add file-system authentication to BTRFS Johannes Thumshirn
  2020-05-14  9:24 ` [PATCH v3 1/3] btrfs: rename btrfs_parse_device_options back to btrfs_parse_early_options Johannes Thumshirn
  2020-05-14  9:24 ` [PATCH v3 2/3] btrfs: add authentication support Johannes Thumshirn
@ 2020-05-14  9:24 ` Johannes Thumshirn
  2020-05-14 12:26   ` Jonathan Corbet
  2020-05-24 19:55   ` David Sterba
  2020-05-25 13:10 ` [PATCH v3 0/3] Add file-system authentication to BTRFS David Sterba
  2020-05-27  2:08 ` Qu Wenruo
  4 siblings, 2 replies; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-14  9:24 UTC (permalink / raw)
  To: David Sterba
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn, Jonathan Corbet

From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

Document the design, guarantees and limitations of an authenticated BTRFS
file-system.

Cc: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
---
 .../filesystems/btrfs-authentication.rst      | 168 ++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 Documentation/filesystems/btrfs-authentication.rst

diff --git a/Documentation/filesystems/btrfs-authentication.rst b/Documentation/filesystems/btrfs-authentication.rst
new file mode 100644
index 000000000000..f13cab248fc0
--- /dev/null
+++ b/Documentation/filesystems/btrfs-authentication.rst
@@ -0,0 +1,168 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:orphan:
+
+.. BTRFS Authentication
+.. Western Digital or it's affiliates
+.. 2020
+
+Introduction
+============
+
+This document describes an approach get file contents _and_ full meta-data
+authentication for BTRFS.
+
+This is possible because BTRFS uses checksums embedded in its on-disk
+meta-data structures as well as checksums for each individual extent of data.
+The primary intent of these checksums was to detect bit-flips of data at rest.
+But this mechanism can be extended to provide authentication of all on-disk
+data when the checksum algorithm is replaced by a cryptographically secure
+keyed hash.
+
+BTRFS Data Structures
+---------------------
+
+BTRFS utilizes a special copy-on-write b-tree to store all contents of the
+file-system on disk.
+
+Meta-Data
+~~~~~~~~~
+
+On-disk meta-data in BTRFS is stored in copy-on-write b-trees. These b-trees
+are build using two data structures, ``struct btrfs_node`` and ``struct
+btrfs_leaf``. Both of these structures start with a ``struct btrfs_header``.
+This structure has amongst other fields a checksum field, protecting it's
+contents. As the checksum is the first entry in the structure, the whole
+structure is protected by this checksum. The superblock (``struct
+btrfs_super_block``) is the first on-disk structure which is read on mount and
+it as well starts with a checksum field protecting the rest of the structure.
+The super block is also needed to read the addresses of the other file system
+b-trees, so their location on disk is protected by the checksum.
+
+::
+
+          BTRFS Header
+          +------+------+--------+-------+-----------------+----+-------+---------+
+          | csum | fsid | bytenr | flags | chunk_tree_uuid | gen| owner | nritems |
+          +------+------+--------+-------+-----------------+----+-------+---------+
+          BTRFS Node
+          +--------+-------------+-------------+-----+
+          | Header | key pointer | key pointer | ... |
+          +--------+-------------+-------------+-----+
+          BTRFS Leaf
+          +--------+------+------+-----+
+          | Header | item | item | ... |
+          +--------+------+------+-----+
+
+            Figure 1: BTRFS Header, Node and Leaf data structures
+
+User-Data
+~~~~~~~~~
+
+User data in BRTFS is also protected by checksums, but this checksum is not
+stored alongside the data, as it is with meta-data, but stored in a separate
+b-tree, the checksum tree. The leafs of this tree store the checksums of the
+user-data.  The tree nodes and leafs are of ``struct btrfs_node`` or ``struct
+btrfs_leaf``, so integrity of this tree is protected as well.
+
+BTRFS Authentication
+====================
+
+This chapter introduces BTRFS authentication which enables BTRFS to verify
+the authenticity and integrity of metadata and file contents stored on disk.
+
+Threat Model
+------------
+
+BTRFS authentication enables detection of offline data modification. While it
+does not prevent it, it enables (trusted) code to check the integrity and
+authenticity of on-disk file contents and filesystem metadata. This covers
+attacks where file contents are swapped.
+
+BTRFS authentication will not protect against a rollback of full disk
+contents. Ie. an attacker can still dump the disk and restore it at a later
+time without detection. It will also not protect against a rollback of one
+transaction. That means an attacker is able to partially undo changes. This is
+possible, because BTRFS does not immediately overwrite obsolete versions of
+its meta-data but keeps older generations until they get garbage collected.
+
+BTRFS authentication does not cover attacks where an attacker is able to
+execute code on the device after the authentication key was provided.
+Additional measures like secure boot and trusted boot have to be taken to
+ensure that only trusted code is executed on a device.
+
+As the file-system authentication key is also needed to update data structures
+on disk, the key has to be in the kernel's keyring for the whole time the
+file-system is mounted. An attacker that is able to compromise the kernel can
+be able to extract the key from the kernel's keyring and thus can gain the
+ability to modify the file-system later on.
+
+Authentication
+--------------
+
+To be able to fully trust data read from disk, all BTRFS data structures
+stored on disk are authenticated. That is:
+
+- The super blocks
+- The file-system b-trees
+- The user-data
+
+
+Super-block
+~~~~~~~~~~~
+
+In order to be able to authenticate the file-system's super-block, the
+checksum stored in the checksum field at the beginning of ``struct
+btrfs_super_block`` protecting its contents is replaced by a
+cryptographically secure keyed hash. In order to generate a valid super-block
+or to validate the super-block, one has to provide a key as an additional
+input for the hash function. The super-block is the starting point to read all
+on disk tree structures, so if we cannot trust the authenticity of the
+super-block anymore, we cannot trust the whole file-system.
+
+B-Trees
+~~~~~~~
+
+Starting from the super-block's root-tree root, the root tree holds the b-tree
+roots of all other on disk b-trees. All other file-system meta-data can be
+derived from the trees stored in this tree. As all b-trees in BTRFS are built
+using ``struct btrfs_node`` and ``struct btrfs_leaf`` each building block of
+each tree is checksummed. These checksums are replaced with the cryptographically
+secure keyed hash algorithm and the authentication key used to verify the
+super-block in the mount phase. Without this key it is impossible to alter any
+of the file-system structure without generating invalid hashes.
+
+User-data
+~~~~~~~~~
+
+The checksums for the user or file-data are stored in a separate b-tree, the
+checksum tree. As this tree in itself is authenticated, only the data stored
+in it needs to be authenticated. This is done by replacing the checksums
+stored on disk by the cryptographically secure keyed hash algorithm used for
+the super-block and other meta-data. So each written file block will get
+checksummed with the authentication key and without supplying the correct key
+it is impossible to write data on disk, which can be read back without
+failing the authentication test. If this test is failed, an I/O error is
+reported back to the user.
+
+Key Management
+--------------
+
+For simplicity, BTRFS authentication uses a single key to compute the keyed
+hashes of the super-block, b-tree nodes and leafs as well as file-blocks. This
+key has to be available on creation of the file-system (`mkfs.btrfs`) to
+authenticate all b-tree elements and the super-blocks. Further, it has to be
+available on mount of the file-system to verify the meta-data and user-data
+stored in the file-system.
+
+Limitations
+-----------
+
+As some optional features of BTRFS disable the generation of checksums, these
+features are incompatible with an authenticated BTRFS.
+These features are:
+- nodatacow
+- nodatasum
+
+As well as any offline modifications to the file-system, like setting an FS
+label while the FS is unmounted.
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-14  9:24 ` [PATCH v3 3/3] btrfs: document btrfs authentication Johannes Thumshirn
@ 2020-05-14 12:26   ` Jonathan Corbet
  2020-05-14 14:54     ` Johannes Thumshirn
  2020-05-24 19:55   ` David Sterba
  1 sibling, 1 reply; 28+ messages in thread
From: Jonathan Corbet @ 2020-05-14 12:26 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: David Sterba, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger, Johannes Thumshirn

On Thu, 14 May 2020 11:24:15 +0200
Johannes Thumshirn <jth@kernel.org> wrote:

Quick question...

> Document the design, guarantees and limitations of an authenticated BTRFS
> file-system.
> 
> Cc: Jonathan Corbet <corbet@lwn.net>
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> ---
>  .../filesystems/btrfs-authentication.rst      | 168 ++++++++++++++++++
>  1 file changed, 168 insertions(+)
>  create mode 100644 Documentation/filesystems/btrfs-authentication.rst
> 
> diff --git a/Documentation/filesystems/btrfs-authentication.rst b/Documentation/filesystems/btrfs-authentication.rst
> new file mode 100644
> index 000000000000..f13cab248fc0
> --- /dev/null
> +++ b/Documentation/filesystems/btrfs-authentication.rst
> @@ -0,0 +1,168 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +:orphan:
> +

Why mark this "orphan" rather than just adding it to index.rst so it gets
built with the rest of the docs?

Thanks,

jon

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-14 12:26   ` Jonathan Corbet
@ 2020-05-14 14:54     ` Johannes Thumshirn
  2020-05-14 15:14       ` Richard Weinberger
  0 siblings, 1 reply; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-14 14:54 UTC (permalink / raw)
  To: Jonathan Corbet, Johannes Thumshirn
  Cc: David Sterba, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger

On 14/05/2020 14:26, Jonathan Corbet wrote:
> On Thu, 14 May 2020 11:24:15 +0200
> Johannes Thumshirn <jth@kernel.org> wrote:
> 
> Quick question...
> 
>> Document the design, guarantees and limitations of an authenticated BTRFS
>> file-system.
>>
>> Cc: Jonathan Corbet <corbet@lwn.net>
>> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>> ---
>>  .../filesystems/btrfs-authentication.rst      | 168 ++++++++++++++++++
>>  1 file changed, 168 insertions(+)
>>  create mode 100644 Documentation/filesystems/btrfs-authentication.rst
>>
>> diff --git a/Documentation/filesystems/btrfs-authentication.rst b/Documentation/filesystems/btrfs-authentication.rst
>> new file mode 100644
>> index 000000000000..f13cab248fc0
>> --- /dev/null
>> +++ b/Documentation/filesystems/btrfs-authentication.rst
>> @@ -0,0 +1,168 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +
>> +:orphan:
>> +
> 
> Why mark this "orphan" rather than just adding it to index.rst so it gets
> built with the rest of the docs?
>
I've no idea of rst and the ubifs-authentication.rst which I had open at the
time did have this as well, so I blindly copied it. Thanks for spotting, will
remove in the next iteration.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-14 14:54     ` Johannes Thumshirn
@ 2020-05-14 15:14       ` Richard Weinberger
  2020-05-14 16:00         ` Jonathan Corbet
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Weinberger @ 2020-05-14 15:14 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: Jonathan Corbet, Johannes Thumshirn, David Sterba, linux-fsdevel,
	linux-btrfs, Eric Biggers

----- Ursprüngliche Mail -----
>> Why mark this "orphan" rather than just adding it to index.rst so it gets
>> built with the rest of the docs?
>>
> I've no idea of rst and the ubifs-authentication.rst which I had open at the
> time did have this as well, so I blindly copied it. Thanks for spotting, will
> remove in the next iteration.

Well, the original ubifs-authentication documentation was written in in markdown
(which is IMHO muss less pain to write), later it was converted to rst by:

commit 09f4c750a8c7d1fc0b7bb3a7aa1de55de897a375
Author: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Date:   Fri Jul 26 09:51:14 2019 -0300

    docs: ubifs-authentication.md: convert to ReST
    
    The documentation standard is ReST and not markdown.
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
    Acked-by: Rob Herring <robh@kernel.org>
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>

But I have no idea what this orphan thingy is.

Thanks,
//richard

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-14 15:14       ` Richard Weinberger
@ 2020-05-14 16:00         ` Jonathan Corbet
  2020-05-14 16:05           ` Richard Weinberger
  0 siblings, 1 reply; 28+ messages in thread
From: Jonathan Corbet @ 2020-05-14 16:00 UTC (permalink / raw)
  To: Richard Weinberger
  Cc: Johannes Thumshirn, Johannes Thumshirn, David Sterba,
	linux-fsdevel, linux-btrfs, Eric Biggers

On Thu, 14 May 2020 17:14:36 +0200 (CEST)
Richard Weinberger <richard@nod.at> wrote:

> But I have no idea what this orphan thingy is.

It suppresses a warning from Sphinx that the file is not included in the
docs build.  Mauro did that with a lot of his conversions just to make his
life easier at the time, but it's not really something we want going
forward.

jon

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-14 16:00         ` Jonathan Corbet
@ 2020-05-14 16:05           ` Richard Weinberger
  0 siblings, 0 replies; 28+ messages in thread
From: Richard Weinberger @ 2020-05-14 16:05 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Johannes Thumshirn, Johannes Thumshirn, David Sterba,
	linux-fsdevel, linux-btrfs, Eric Biggers

----- Ursprüngliche Mail -----
> Von: "Jonathan Corbet" <corbet@lwn.net>
> An: "richard" <richard@nod.at>
> CC: "Johannes Thumshirn" <Johannes.Thumshirn@wdc.com>, "Johannes Thumshirn" <jth@kernel.org>, "David Sterba"
> <dsterba@suse.cz>, "linux-fsdevel" <linux-fsdevel@vger.kernel.org>, "linux-btrfs" <linux-btrfs@vger.kernel.org>, "Eric
> Biggers" <ebiggers@google.com>
> Gesendet: Donnerstag, 14. Mai 2020 18:00:18
> Betreff: Re: [PATCH v3 3/3] btrfs: document btrfs authentication

> On Thu, 14 May 2020 17:14:36 +0200 (CEST)
> Richard Weinberger <richard@nod.at> wrote:
> 
>> But I have no idea what this orphan thingy is.
> 
> It suppresses a warning from Sphinx that the file is not included in the
> docs build.  Mauro did that with a lot of his conversions just to make his
> life easier at the time, but it's not really something we want going
> forward.

Ahh, thanks for explaining. :-)

Thanks,
//richard

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-14  9:24 ` [PATCH v3 3/3] btrfs: document btrfs authentication Johannes Thumshirn
  2020-05-14 12:26   ` Jonathan Corbet
@ 2020-05-24 19:55   ` David Sterba
  2020-05-25 10:57     ` Johannes Thumshirn
  1 sibling, 1 reply; 28+ messages in thread
From: David Sterba @ 2020-05-24 19:55 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: David Sterba, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger, Johannes Thumshirn, Jonathan Corbet

On Thu, May 14, 2020 at 11:24:15AM +0200, Johannes Thumshirn wrote:
> +User-data
> +~~~~~~~~~
> +
> +The checksums for the user or file-data are stored in a separate b-tree, the
> +checksum tree. As this tree in itself is authenticated, only the data stored
> +in it needs to be authenticated. This is done by replacing the checksums
> +stored on disk by the cryptographically secure keyed hash algorithm used for
> +the super-block and other meta-data. So each written file block will get
> +checksummed with the authentication key and without supplying the correct key
> +it is impossible to write data on disk, which can be read back without
> +failing the authentication test. If this test is failed, an I/O error is
> +reported back to the user.

With same key K and same contents of data block B, the keyed hash on two
different filesystems is the same. Ie. there's no per-filesystem salt
(like a UUID) or per-transaction salt (generation, block address).

For metadata the per-transaction salt is inherently there as the hash is
calculated with the header included (containing the increasing
generation) and the filesystem UUID (available via blkid) or chunk tree
UUID (not so easy to user to read).

So there's an obvious discrepancy in the additional data besides the
variable contents of the data and metadata blocks.

The weakness of the data blocks may aid some attacks (I don't have a
concrete suggestion where and how exatly).

Suggested fix is to have a data block "header", with similar contents as
the metadata blocks, eg.

struct btrfs_hash_header {
	u8 fsid[BTRFS_FSID_SIZE];
	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
	__le64 generation;
};

Perhaps also with some extra item for future extensions, set to zeros
for now.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-24 19:55   ` David Sterba
@ 2020-05-25 10:57     ` Johannes Thumshirn
  2020-05-25 11:26       ` David Sterba
  0 siblings, 1 reply; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-25 10:57 UTC (permalink / raw)
  To: dsterba, Johannes Thumshirn
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Jonathan Corbet

On 24/05/2020 21:56, David Sterba wrote:
> On Thu, May 14, 2020 at 11:24:15AM +0200, Johannes Thumshirn wrote:
>> +User-data
>> +~~~~~~~~~
>> +
>> +The checksums for the user or file-data are stored in a separate b-tree, the
>> +checksum tree. As this tree in itself is authenticated, only the data stored
>> +in it needs to be authenticated. This is done by replacing the checksums
>> +stored on disk by the cryptographically secure keyed hash algorithm used for
>> +the super-block and other meta-data. So each written file block will get
>> +checksummed with the authentication key and without supplying the correct key
>> +it is impossible to write data on disk, which can be read back without
>> +failing the authentication test. If this test is failed, an I/O error is
>> +reported back to the user.
> 
> With same key K and same contents of data block B, the keyed hash on two
> different filesystems is the same. Ie. there's no per-filesystem salt
> (like a UUID) or per-transaction salt (generation, block address).

Correct.

> 
> For metadata the per-transaction salt is inherently there as the hash is
> calculated with the header included (containing the increasing
> generation) and the filesystem UUID (available via blkid) or chunk tree
> UUID (not so easy to user to read).
> 
> So there's an obvious discrepancy in the additional data besides the
> variable contents of the data and metadata blocks.
> 
> The weakness of the data blocks may aid some attacks (I don't have a
> concrete suggestion where and how exatly).

Yes but wouldn't this also need a hash that is prone to a known plaintext
attack or that has known collisions? But it would probably help in 
brute-forcing the key K of the filesystem. OTOH fsid, generation and the 
chunk-tree UUID can be read in plaintext from the FS as well so this would
only mitigate a rainbow table like attack, wouldn't it?

> 
> Suggested fix is to have a data block "header", with similar contents as
> the metadata blocks, eg.
> 
> struct btrfs_hash_header {
> 	u8 fsid[BTRFS_FSID_SIZE];
> 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
> 	__le64 generation;
> };
> 
> Perhaps also with some extra item for future extensions, set to zeros
> for now.
> 

This addition would be possible, yes. But if we'd add this header to every
checksum in the checksum tree it would be an incompatible on-disk format
change.

We could add this only for authenticated filesystems though, but would this
deviation make sense? I need to think more about it (and actually look at the
code to see how this could be done).


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-25 10:57     ` Johannes Thumshirn
@ 2020-05-25 11:26       ` David Sterba
  2020-05-25 11:44         ` Johannes Thumshirn
  0 siblings, 1 reply; 28+ messages in thread
From: David Sterba @ 2020-05-25 11:26 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: Johannes Thumshirn, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger, Jonathan Corbet

On Mon, May 25, 2020 at 10:57:13AM +0000, Johannes Thumshirn wrote:
> On 24/05/2020 21:56, David Sterba wrote:
> > On Thu, May 14, 2020 at 11:24:15AM +0200, Johannes Thumshirn wrote:
> > For metadata the per-transaction salt is inherently there as the hash is
> > calculated with the header included (containing the increasing
> > generation) and the filesystem UUID (available via blkid) or chunk tree
> > UUID (not so easy to user to read).
> > 
> > So there's an obvious discrepancy in the additional data besides the
> > variable contents of the data and metadata blocks.
> > 
> > The weakness of the data blocks may aid some attacks (I don't have a
> > concrete suggestion where and how exatly).
> 
> Yes but wouldn't this also need a hash that is prone to a known plaintext
> attack or that has known collisions? But it would probably help in 
> brute-forcing the key K of the filesystem. OTOH fsid, generation and the 
> chunk-tree UUID can be read in plaintext from the FS as well so this would
> only mitigate a rainbow table like attack, wouldn't it?

The goal here is to make attacks harder at a small cost.

> > Suggested fix is to have a data block "header", with similar contents as
> > the metadata blocks, eg.
> > 
> > struct btrfs_hash_header {
> > 	u8 fsid[BTRFS_FSID_SIZE];
> > 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
> > 	__le64 generation;
> > };
> > 
> > Perhaps also with some extra item for future extensions, set to zeros
> > for now.
> 
> This addition would be possible, yes. But if we'd add this header to every
> checksum in the checksum tree it would be an incompatible on-disk format
> change.

No. It's only in-memory and is built from known pieces of information
exactly to avoid storing it on disk.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 3/3] btrfs: document btrfs authentication
  2020-05-25 11:26       ` David Sterba
@ 2020-05-25 11:44         ` Johannes Thumshirn
  0 siblings, 0 replies; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-25 11:44 UTC (permalink / raw)
  To: dsterba
  Cc: Johannes Thumshirn, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger, Jonathan Corbet

On 25/05/2020 13:27, David Sterba wrote:
>>> Suggested fix is to have a data block "header", with similar contents as
>>> the metadata blocks, eg.
>>>
>>> struct btrfs_hash_header {
>>> 	u8 fsid[BTRFS_FSID_SIZE];
>>> 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
>>> 	__le64 generation;
>>> };
>>>
>>> Perhaps also with some extra item for future extensions, set to zeros
>>> for now.
>>
>> This addition would be possible, yes. But if we'd add this header to every
>> checksum in the checksum tree it would be an incompatible on-disk format
>> change.
> 
> No. It's only in-memory and is built from known pieces of information
> exactly to avoid storing it on disk.
> 

Ah OK, now I get what you meant. This should then be only for the authenticated 
FS I guess.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-14  9:24 [PATCH v3 0/3] Add file-system authentication to BTRFS Johannes Thumshirn
                   ` (2 preceding siblings ...)
  2020-05-14  9:24 ` [PATCH v3 3/3] btrfs: document btrfs authentication Johannes Thumshirn
@ 2020-05-25 13:10 ` David Sterba
  2020-05-26  7:50   ` Johannes Thumshirn
  2020-05-27  2:08 ` Qu Wenruo
  4 siblings, 1 reply; 28+ messages in thread
From: David Sterba @ 2020-05-25 13:10 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: David Sterba, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger, Johannes Thumshirn

On Thu, May 14, 2020 at 11:24:12AM +0200, Johannes Thumshirn wrote:
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> 
> This series adds file-system authentication to BTRFS. 
> 
> Unlike other verified file-system techniques like fs-verity the
> authenticated version of BTRFS does not need extra meta-data on disk.
> 
> This works because in BTRFS every on-disk block has a checksum, for meta-data
> the checksum is in the header of each meta-data item. For data blocks, a
> separate checksum tree exists, which holds the checksums for each block.
> 
> Currently BRTFS supports CRC32C, XXHASH64, SHA256 and Blake2b for checksumming
> these blocks. This series adds a new checksum algorithm, HMAC(SHA-256), which
> does need an authentication key. When no, or an incoreect authentication key
> is supplied no valid checksum can be generated and a read, fsck or scrub
> operation would detect invalid or tampered blocks once the file-system is
> mounted again with the correct key. 

As mentioned in the discussion under LWN article, https://lwn.net/Articles/818842/
ZFS implements split hash where one half is (partial) authenticated hash
and the other half is a checksum. This allows to have at least some sort
of verification when the auth key is not available. This applies to the
fixed size checksum area of metadata blocks, for data we can afford to
store both hashes in full.

I like this idea, however it brings interesting design decisions, "what
if" and corner cases:

- what hashes to use for the plain checksum, and thus what's the split
- what if one hash matches and the other not
- increased checksum calculation time due to doubled block read
- whether to store the same parital hash+checksum for data too

As the authenticated hash is the main usecase, I'd reserve most of the
32 byte buffer to it and use a weak hash for checksum: 24 bytes for HMAC
and 8 bytes for checksum. As an example: sha256+xxhash or
blake2b+xxhash.

I'd outright skip crc32c for the checksum so we have only small number
of authenticated checksums and avoid too many options, eg.
hmac-sha256-crc32c etc. The result will be still 2 authenticated hashes
with the added checksum hardcoded to xxhash.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-25 13:10 ` [PATCH v3 0/3] Add file-system authentication to BTRFS David Sterba
@ 2020-05-26  7:50   ` Johannes Thumshirn
  2020-05-26 11:53     ` David Sterba
  0 siblings, 1 reply; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-26  7:50 UTC (permalink / raw)
  To: dsterba, Johannes Thumshirn
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger

On 25/05/2020 15:11, David Sterba wrote:
> On Thu, May 14, 2020 at 11:24:12AM +0200, Johannes Thumshirn wrote:
>> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>>
>> This series adds file-system authentication to BTRFS. 
>>
>> Unlike other verified file-system techniques like fs-verity the
>> authenticated version of BTRFS does not need extra meta-data on disk.
>>
>> This works because in BTRFS every on-disk block has a checksum, for meta-data
>> the checksum is in the header of each meta-data item. For data blocks, a
>> separate checksum tree exists, which holds the checksums for each block.
>>
>> Currently BRTFS supports CRC32C, XXHASH64, SHA256 and Blake2b for checksumming
>> these blocks. This series adds a new checksum algorithm, HMAC(SHA-256), which
>> does need an authentication key. When no, or an incoreect authentication key
>> is supplied no valid checksum can be generated and a read, fsck or scrub
>> operation would detect invalid or tampered blocks once the file-system is
>> mounted again with the correct key. 
> 
> As mentioned in the discussion under LWN article, https://lwn.net/Articles/818842/
> ZFS implements split hash where one half is (partial) authenticated hash
> and the other half is a checksum. This allows to have at least some sort
> of verification when the auth key is not available. This applies to the
> fixed size checksum area of metadata blocks, for data we can afford to
> store both hashes in full.
> 
> I like this idea, however it brings interesting design decisions, "what
> if" and corner cases:
> 
> - what hashes to use for the plain checksum, and thus what's the split
> - what if one hash matches and the other not
> - increased checksum calculation time due to doubled block read
> - whether to store the same parital hash+checksum for data too
> 
> As the authenticated hash is the main usecase, I'd reserve most of the
> 32 byte buffer to it and use a weak hash for checksum: 24 bytes for HMAC
> and 8 bytes for checksum. As an example: sha256+xxhash or
> blake2b+xxhash.
> 
> I'd outright skip crc32c for the checksum so we have only small number
> of authenticated checksums and avoid too many options, eg.
> hmac-sha256-crc32c etc. The result will be still 2 authenticated hashes
> with the added checksum hardcoded to xxhash.
> 

Hmm I'm really not a fan of this. We would have to use something like 
sha2-224 to get the room for the 2nd checksum. So we're using a weaker
hash just so we can add a second checksum. On the other hand you've asked 
me to add the known pieces of information into the hashes as a salt to
"make attacks harder at a small cost".

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-26  7:50   ` Johannes Thumshirn
@ 2020-05-26 11:53     ` David Sterba
  2020-05-26 12:44       ` Johannes Thumshirn
  0 siblings, 1 reply; 28+ messages in thread
From: David Sterba @ 2020-05-26 11:53 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: dsterba, Johannes Thumshirn, linux-fsdevel, linux-btrfs,
	Eric Biggers, Richard Weinberger

On Tue, May 26, 2020 at 07:50:53AM +0000, Johannes Thumshirn wrote:
> On 25/05/2020 15:11, David Sterba wrote:
> > On Thu, May 14, 2020 at 11:24:12AM +0200, Johannes Thumshirn wrote:
> > As mentioned in the discussion under LWN article, https://lwn.net/Articles/818842/
> > ZFS implements split hash where one half is (partial) authenticated hash
> > and the other half is a checksum. This allows to have at least some sort
> > of verification when the auth key is not available. This applies to the
> > fixed size checksum area of metadata blocks, for data we can afford to
> > store both hashes in full.
> > 
> > I like this idea, however it brings interesting design decisions, "what
> > if" and corner cases:
> > 
> > - what hashes to use for the plain checksum, and thus what's the split
> > - what if one hash matches and the other not
> > - increased checksum calculation time due to doubled block read
> > - whether to store the same parital hash+checksum for data too
> > 
> > As the authenticated hash is the main usecase, I'd reserve most of the
> > 32 byte buffer to it and use a weak hash for checksum: 24 bytes for HMAC
> > and 8 bytes for checksum. As an example: sha256+xxhash or
> > blake2b+xxhash.
> > 
> > I'd outright skip crc32c for the checksum so we have only small number
> > of authenticated checksums and avoid too many options, eg.
> > hmac-sha256-crc32c etc. The result will be still 2 authenticated hashes
> > with the added checksum hardcoded to xxhash.
> 
> Hmm I'm really not a fan of this. We would have to use something like 
> sha2-224 to get the room for the 2nd checksum. So we're using a weaker
> hash just so we can add a second checksum.

The idea is to calculate full hash (32 bytes) and store only the part
(24 bytes). Yes this means there's some information loss and weakening,
but enables a usecase.

> On the other hand you've asked 
> me to add the known pieces of information into the hashes as a salt to
> "make attacks harder at a small cost".

Yes and this makes it harder to attack the hash, it should be there
regardless of the additional checksums.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-26 11:53     ` David Sterba
@ 2020-05-26 12:44       ` Johannes Thumshirn
  2020-06-01 14:59         ` David Sterba
  0 siblings, 1 reply; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-26 12:44 UTC (permalink / raw)
  To: dsterba
  Cc: Johannes Thumshirn, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger

On 26/05/2020 13:54, David Sterba wrote:
> On Tue, May 26, 2020 at 07:50:53AM +0000, Johannes Thumshirn wrote:
>> On 25/05/2020 15:11, David Sterba wrote:
>>> On Thu, May 14, 2020 at 11:24:12AM +0200, Johannes Thumshirn wrote:
>>> As mentioned in the discussion under LWN article, https://lwn.net/Articles/818842/
>>> ZFS implements split hash where one half is (partial) authenticated hash
>>> and the other half is a checksum. This allows to have at least some sort
>>> of verification when the auth key is not available. This applies to the
>>> fixed size checksum area of metadata blocks, for data we can afford to
>>> store both hashes in full.
>>>
>>> I like this idea, however it brings interesting design decisions, "what
>>> if" and corner cases:
>>>
>>> - what hashes to use for the plain checksum, and thus what's the split
>>> - what if one hash matches and the other not
>>> - increased checksum calculation time due to doubled block read
>>> - whether to store the same parital hash+checksum for data too
>>>
>>> As the authenticated hash is the main usecase, I'd reserve most of the
>>> 32 byte buffer to it and use a weak hash for checksum: 24 bytes for HMAC
>>> and 8 bytes for checksum. As an example: sha256+xxhash or
>>> blake2b+xxhash.
>>>
>>> I'd outright skip crc32c for the checksum so we have only small number
>>> of authenticated checksums and avoid too many options, eg.
>>> hmac-sha256-crc32c etc. The result will be still 2 authenticated hashes
>>> with the added checksum hardcoded to xxhash.
>>
>> Hmm I'm really not a fan of this. We would have to use something like 
>> sha2-224 to get the room for the 2nd checksum. So we're using a weaker
>> hash just so we can add a second checksum.
> 
> The idea is to calculate full hash (32 bytes) and store only the part
> (24 bytes). Yes this means there's some information loss and weakening,
> but enables a usecase.

I'm not enough a security expert to be able to judge this. Eric can I hear 
your opinion on this?

Thanks,
	Johannes

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-14  9:24 [PATCH v3 0/3] Add file-system authentication to BTRFS Johannes Thumshirn
                   ` (3 preceding siblings ...)
  2020-05-25 13:10 ` [PATCH v3 0/3] Add file-system authentication to BTRFS David Sterba
@ 2020-05-27  2:08 ` Qu Wenruo
  2020-05-27 11:27   ` David Sterba
  2020-05-27 13:11   ` David Sterba
  4 siblings, 2 replies; 28+ messages in thread
From: Qu Wenruo @ 2020-05-27  2:08 UTC (permalink / raw)
  To: Johannes Thumshirn, David Sterba
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn


[-- Attachment #1.1: Type: text/plain, Size: 4011 bytes --]



On 2020/5/14 下午5:24, Johannes Thumshirn wrote:
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> 
> This series adds file-system authentication to BTRFS. 
> 
> Unlike other verified file-system techniques like fs-verity the
> authenticated version of BTRFS does not need extra meta-data on disk.
> 
> This works because in BTRFS every on-disk block has a checksum, for meta-data
> the checksum is in the header of each meta-data item. For data blocks, a
> separate checksum tree exists, which holds the checksums for each block.
> 
> Currently BRTFS supports CRC32C, XXHASH64, SHA256 and Blake2b for checksumming
> these blocks. This series adds a new checksum algorithm, HMAC(SHA-256), which
> does need an authentication key. When no, or an incoreect authentication key
> is supplied no valid checksum can be generated and a read, fsck or scrub
> operation would detect invalid or tampered blocks once the file-system is
> mounted again with the correct key. 
> 
> Getting the key inside the kernel is out of scope of this implementation, the
> file-system driver assumes the key is already in the kernel's keyring at mount
> time.
> 
> There was interest in also using keyed Blake2b from the community, but this
> support is not yet included.
> 
> I have CCed Eric Biggers and Richard Weinberger in the submission, as they
> previously have worked on filesystem authentication and I hope we can get
> input from them as well.
> 
> Example usage:
> Create a file-system with authentication key 0123456
> mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk
> 
> Add the key to the kernel's keyring as keyid 'btrfs:foo'
> keyctl add logon btrfs:foo 0123456 @u
> 
> Mount the fs using the 'btrfs:foo' key
> mount -t btrfs -o auth_key=btrfs:foo,auth_hash_name="hmac(sha256)" /dev/disk /mnt/point
> 
> Note, this is a re-base of the work I did when I was still at SUSE, hence the
> S-o-b being my SUSE address, while the Author being with my WDC address (to
> not generate bouncing mails).
> 
> Changes since v2:
> - Select CONFIG_CRYPTO_HMAC and CONFIG_KEYS (kbuild robot)
> - Fix double free in error path
> - Fix memory leak in error path
> - Disallow nodatasum and nodatacow when authetication is use (Eric)

Since we're disabling NODATACOW usages, can we also disable the
following features?
- v1 space cache
  V1 space cache uses NODATACOW file to store space cache, althouhg it
  has inline csum, but it's fixed to crc32c. So attacker can easily
  utilize this hole to mess space cache, and do some DoS attack.

- fallocate
  I'm not 100% sure about this, but since nodatacow is already a second
  class citizen in btrfs, maybe not supporting fallocate is not a
  strange move.

Thanks,
Qu

> - Pass in authentication algorithm as mount option (Eric)
> - Don't use the work "replay" in the documentation, as it is wrong and
>   harmful in this context (Eric)
> - Force key name to begin with 'btrfs:' (Eric)
> - Use '4' as on-disk checksum type for HMAC(SHA256) to not have holes in the
>   checksum types array.
> 
> Changes since v1:
> - None, only rebased the series
> 
> Johannes Thumshirn (3):
>   btrfs: rename btrfs_parse_device_options back to
>     btrfs_parse_early_options
>   btrfs: add authentication support
>   btrfs: document btrfs authentication
> 
>  .../filesystems/btrfs-authentication.rst      | 168 ++++++++++++++++++
>  fs/btrfs/Kconfig                              |   2 +
>  fs/btrfs/ctree.c                              |  22 ++-
>  fs/btrfs/ctree.h                              |   5 +-
>  fs/btrfs/disk-io.c                            |  71 +++++++-
>  fs/btrfs/ioctl.c                              |   7 +-
>  fs/btrfs/super.c                              |  65 ++++++-
>  include/uapi/linux/btrfs_tree.h               |   1 +
>  8 files changed, 326 insertions(+), 15 deletions(-)
>  create mode 100644 Documentation/filesystems/btrfs-authentication.rst
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-27  2:08 ` Qu Wenruo
@ 2020-05-27 11:27   ` David Sterba
  2020-05-27 11:58     ` Qu Wenruo
  2020-05-27 13:11   ` David Sterba
  1 sibling, 1 reply; 28+ messages in thread
From: David Sterba @ 2020-05-27 11:27 UTC (permalink / raw)
  To: Qu Wenruo
  Cc: Johannes Thumshirn, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger, Johannes Thumshirn

On Wed, May 27, 2020 at 10:08:06AM +0800, Qu Wenruo wrote:
> > Changes since v2:
> > - Select CONFIG_CRYPTO_HMAC and CONFIG_KEYS (kbuild robot)
> > - Fix double free in error path
> > - Fix memory leak in error path
> > - Disallow nodatasum and nodatacow when authetication is use (Eric)
> 
> Since we're disabling NODATACOW usages, can we also disable the
> following features?
> - v1 space cache
>   V1 space cache uses NODATACOW file to store space cache, althouhg it
>   has inline csum, but it's fixed to crc32c. So attacker can easily
>   utilize this hole to mess space cache, and do some DoS attack.

That's a good point.

The v1 space cache will be phased out but it won't be in a timeframe
we'll get in the authentication. At this point we don't even have a way
to select v2 at mkfs time (it's work in progress though), so it would be
required to switch to v2 on the first mount.

> - fallocate
>   I'm not 100% sure about this, but since nodatacow is already a second
>   class citizen in btrfs, maybe not supporting fallocate is not a
>   strange move.

Fallocate is a standard file operation, not supporting would be quite
strange. What's the problem with fallocate and authentication?

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-27 11:27   ` David Sterba
@ 2020-05-27 11:58     ` Qu Wenruo
  0 siblings, 0 replies; 28+ messages in thread
From: Qu Wenruo @ 2020-05-27 11:58 UTC (permalink / raw)
  To: dsterba, Johannes Thumshirn, linux-fsdevel, linux-btrfs,
	Eric Biggers, Richard Weinberger, Johannes Thumshirn


[-- Attachment #1.1: Type: text/plain, Size: 1728 bytes --]



On 2020/5/27 下午7:27, David Sterba wrote:
> On Wed, May 27, 2020 at 10:08:06AM +0800, Qu Wenruo wrote:
>>> Changes since v2:
>>> - Select CONFIG_CRYPTO_HMAC and CONFIG_KEYS (kbuild robot)
>>> - Fix double free in error path
>>> - Fix memory leak in error path
>>> - Disallow nodatasum and nodatacow when authetication is use (Eric)
>>
>> Since we're disabling NODATACOW usages, can we also disable the
>> following features?
>> - v1 space cache
>>   V1 space cache uses NODATACOW file to store space cache, althouhg it
>>   has inline csum, but it's fixed to crc32c. So attacker can easily
>>   utilize this hole to mess space cache, and do some DoS attack.
> 
> That's a good point.
> 
> The v1 space cache will be phased out but it won't be in a timeframe
> we'll get in the authentication. At this point we don't even have a way
> to select v2 at mkfs time (it's work in progress though), so it would be
> required to switch to v2 on the first mount.
> 
>> - fallocate
>>   I'm not 100% sure about this, but since nodatacow is already a second
>>   class citizen in btrfs, maybe not supporting fallocate is not a
>>   strange move.
> 
> Fallocate is a standard file operation, not supporting would be quite
> strange. What's the problem with fallocate and authentication?
> 
As said, I'm not that sure about preallocate, but that's the remaining
user of nodatacow.
Although it's a pretty common interface, but in btrfs it doesn't really
make much sense.
In case like fallocate then snapshot use case, there is really no
benefit from writing into fallocated range.

Not to mention the extra cross-ref check involved when writing into
possible preallocated range.

Thanks,
Qu


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-27  2:08 ` Qu Wenruo
  2020-05-27 11:27   ` David Sterba
@ 2020-05-27 13:11   ` David Sterba
  1 sibling, 0 replies; 28+ messages in thread
From: David Sterba @ 2020-05-27 13:11 UTC (permalink / raw)
  To: Qu Wenruo
  Cc: Johannes Thumshirn, David Sterba, linux-fsdevel, linux-btrfs,
	Eric Biggers, Richard Weinberger, Johannes Thumshirn

On Wed, May 27, 2020 at 10:08:06AM +0800, Qu Wenruo wrote:
> > Changes since v2:
> > - Select CONFIG_CRYPTO_HMAC and CONFIG_KEYS (kbuild robot)
> > - Fix double free in error path
> > - Fix memory leak in error path
> > - Disallow nodatasum and nodatacow when authetication is use (Eric)
> 
> Since we're disabling NODATACOW usages, can we also disable the
> following features?
> - v1 space cache
>   V1 space cache uses NODATACOW file to store space cache, althouhg it
>   has inline csum, but it's fixed to crc32c. So attacker can easily
>   utilize this hole to mess space cache, and do some DoS attack.
> 
> - fallocate
>   I'm not 100% sure about this, but since nodatacow is already a second
>   class citizen in btrfs, maybe not supporting fallocate is not a
>   strange move.

- swapfile
  NODATACOW is required for swapfile, so authentication and swapfile are
  mutualy exclusive.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 2/3] btrfs: add authentication support
  2020-05-14  9:24 ` [PATCH v3 2/3] btrfs: add authentication support Johannes Thumshirn
@ 2020-05-27 13:24   ` David Sterba
  2020-05-27 13:54     ` Johannes Thumshirn
  2020-05-27 18:04     ` Johannes Thumshirn
  0 siblings, 2 replies; 28+ messages in thread
From: David Sterba @ 2020-05-27 13:24 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: David Sterba, linux-fsdevel, linux-btrfs, Eric Biggers,
	Richard Weinberger, Johannes Thumshirn, Johannes Thumshirn

On Thu, May 14, 2020 at 11:24:14AM +0200, Johannes Thumshirn wrote:
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> Example usage:
> Create a file-system with authentication key 0123456
> mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk
> 
> Add the key to the kernel's keyring as keyid 'btrfs:foo'
> keyctl add logon btrfs:foo 0123456 @u
> 
> Mount the fs using the 'btrfs:foo' key
> mount -o auth_key=btrfs:foo,auth_hash_name="hmac(sha256)" /dev/disk /mnt/point

I tried to follow the example but the filesystem does not mount. But
what almost shocked me was the way the key is specified on the userspace
side.

$ mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk

"0123456" are the raw bytes of the key? Seriously?

And how it's passed to the hmac code:

 gcry_mac_hd_t mac;
 gcry_mac_open(&mac, GCRY_MAC_HMAC_SHA256, 0, NULL);
 gcry_mac_setkey(mac, fs_info->auth_key, strlen(fs_info->auth_key));
 gcry_mac_write(mac, buf, length);
 gcry_mac_read(mac, out, &length);

Strlen means the key must avoid char 0 and I don't think we want do any
decoding from ascii-hex format, when there's the whole keyctl
infrastructure.

The key for all userspace commands needs to be specified the same way as
for kernel, ie. "--auth-key btrfs:foo" and use the appropriate ioctls to
read the key bytes.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 2/3] btrfs: add authentication support
  2020-05-27 13:24   ` David Sterba
@ 2020-05-27 13:54     ` Johannes Thumshirn
  2020-05-27 14:01       ` Johannes Thumshirn
  2020-05-27 18:04     ` Johannes Thumshirn
  1 sibling, 1 reply; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-27 13:54 UTC (permalink / raw)
  To: dsterba, Johannes Thumshirn
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn

On 27/05/2020 15:25, David Sterba wrote:
> On Thu, May 14, 2020 at 11:24:14AM +0200, Johannes Thumshirn wrote:
>> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>> Example usage:
>> Create a file-system with authentication key 0123456
>> mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk
>>
>> Add the key to the kernel's keyring as keyid 'btrfs:foo'
>> keyctl add logon btrfs:foo 0123456 @u
>>
>> Mount the fs using the 'btrfs:foo' key
>> mount -o auth_key=btrfs:foo,auth_hash_name="hmac(sha256)" /dev/disk /mnt/point
> 
> I tried to follow the example but the filesystem does not mount. But
> what almost shocked me was the way the key is specified on the userspace
> side.
> 
> $ mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk
> 
> "0123456" are the raw bytes of the key? Seriously?
> 
> And how it's passed to the hmac code:
> 
>  gcry_mac_hd_t mac;
>  gcry_mac_open(&mac, GCRY_MAC_HMAC_SHA256, 0, NULL);
>  gcry_mac_setkey(mac, fs_info->auth_key, strlen(fs_info->auth_key));
>  gcry_mac_write(mac, buf, length);
>  gcry_mac_read(mac, out, &length);
> 
> Strlen means the key must avoid char 0 and I don't think we want do any
> decoding from ascii-hex format, when there's the whole keyctl
> infrastructure.
> 
> The key for all userspace commands needs to be specified the same way as
> for kernel, ie. "--auth-key btrfs:foo" and use the appropriate ioctls to
> read the key bytes.
> 

Hohum?

Here's what I just did:

rapido1:/# keyctl add logon btrfs:foo 0123456 @u
1020349071
rapido1:/# mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/zram1
btrfs-progs v5.6
See http://btrfs.wiki.kernel.org for more information.

Detected a SSD, turning off metadata duplication.  Mkfs with -m dup if you want to force metadata duplication.
Label:              (null)
UUID:               56ae43ac-f333-4ed4-933a-356aed534115
[   31.005743] BTRFS: device fsid 56ae43ac-f333-4ed4-933a-356aed534115 devid 1 transid 5 /dev/zram1 scanned by mkfs.btrfs (241)

Sector size:        4096
Filesystem size:    3.00GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         single            8.00MiB
  System:           single            4.00MiB
SSD detected:       yes
Incompat features:  extref, skinny-metadata
Checksum:           hmac-sha256
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1     3.00GiB  /dev/zram1


rapido1:/# mount -o auth_key=btrfs:foo,auth_hash_name="hmac(sha256)" /dev/zram1 /mnt/       
[   65.959465] BTRFS info (device (efault)): doing authentication
[   65.963204] BTRFS info (device zram1): disk space caching is enabled
[   65.964137] BTRFS info (device zram1): has skinny extents
[   65.964912] BTRFS info (device zram1): flagging fs with big metadata feature
[   65.968302] BTRFS info (device zram1): enabling ssd optimizations
[   65.969551] BTRFS info (device zram1): checking UUID tree
rapido1:/#


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 2/3] btrfs: add authentication support
  2020-05-27 13:54     ` Johannes Thumshirn
@ 2020-05-27 14:01       ` Johannes Thumshirn
  0 siblings, 0 replies; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-27 14:01 UTC (permalink / raw)
  To: dsterba, Johannes Thumshirn
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn

On 27/05/2020 15:55, Johannes Thumshirn wrote:
> On 27/05/2020 15:25, David Sterba wrote:
>> On Thu, May 14, 2020 at 11:24:14AM +0200, Johannes Thumshirn wrote:
>>> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>>> Example usage:
>>> Create a file-system with authentication key 0123456
>>> mkfs.btrfs --csum "hmac(sha256)" --auth-key 0123456 /dev/disk
>>>
>>> Add the key to the kernel's keyring as keyid 'btrfs:foo'
>>> keyctl add logon btrfs:foo 0123456 @u
>>>
>>> Mount the fs using the 'btrfs:foo' key
>>> mount -o auth_key=btrfs:foo,auth_hash_name="hmac(sha256)" /dev/disk /mnt/point
>>
>> I tried to follow the example but the filesystem does not mount. But
>> what almost shocked me was the way the key is specified on the userspace
>> side.

OK I think I know what happened. Did I forget to send a v2 of the progs side?
I changed the csum_type number to not have holes in the array, this obviously needs
to be done in progs as well.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 2/3] btrfs: add authentication support
  2020-05-27 13:24   ` David Sterba
  2020-05-27 13:54     ` Johannes Thumshirn
@ 2020-05-27 18:04     ` Johannes Thumshirn
  2020-06-01 14:30       ` David Sterba
  2020-06-01 14:35       ` David Sterba
  1 sibling, 2 replies; 28+ messages in thread
From: Johannes Thumshirn @ 2020-05-27 18:04 UTC (permalink / raw)
  To: dsterba, Johannes Thumshirn
  Cc: linux-fsdevel, linux-btrfs, Eric Biggers, Richard Weinberger,
	Johannes Thumshirn

On 27/05/2020 15:25, David Sterba wrote:
> The key for all userspace commands needs to be specified the same way as
> for kernel, ie. "--auth-key btrfs:foo" and use the appropriate ioctls to
> read the key bytes.

Up to now I haven't been able to add a key to the kernel's keyring which 
can be read back to user-space.

How about passing in a key file, like it is done in UBIFS? Should be doable
both with libsodium and libgcrypt.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 2/3] btrfs: add authentication support
  2020-05-27 18:04     ` Johannes Thumshirn
@ 2020-06-01 14:30       ` David Sterba
  2020-06-01 14:35       ` David Sterba
  1 sibling, 0 replies; 28+ messages in thread
From: David Sterba @ 2020-06-01 14:30 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: dsterba, Johannes Thumshirn, linux-fsdevel, linux-btrfs,
	Eric Biggers, Richard Weinberger, Johannes Thumshirn

On Wed, May 27, 2020 at 06:04:57PM +0000, Johannes Thumshirn wrote:
> On 27/05/2020 15:25, David Sterba wrote:
> > The key for all userspace commands needs to be specified the same way as
> > for kernel, ie. "--auth-key btrfs:foo" and use the appropriate ioctls to
> > read the key bytes.
> 
> Up to now I haven't been able to add a key to the kernel's keyring which 
> can be read back to user-space.

This needs permissions on the key and I think keys from some keyrings
cannot be read back even with the permissions set. There's an ioctl
equivalent of 'keyctl read' which I used to emulate the reading. Setting
the permissions is cumbersome, as it needs to manually craft the hexa
value, but otherwise would seems a better way than either specifying the
key payload on command line or storing it in a file.

I've looked at other projects using keys, eg. ecryptfs-utils, it uses
keyctl_read_alloc, so that seems to be the preferred way.

> How about passing in a key file, like it is done in UBIFS? Should be doable
> both with libsodium and libgcrypt.

Keyfile would be better, that's what dm-crypt uses, but still.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 2/3] btrfs: add authentication support
  2020-05-27 18:04     ` Johannes Thumshirn
  2020-06-01 14:30       ` David Sterba
@ 2020-06-01 14:35       ` David Sterba
  1 sibling, 0 replies; 28+ messages in thread
From: David Sterba @ 2020-06-01 14:35 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: dsterba, Johannes Thumshirn, linux-fsdevel, linux-btrfs,
	Eric Biggers, Richard Weinberger, Johannes Thumshirn

On Wed, May 27, 2020 at 06:04:57PM +0000, Johannes Thumshirn wrote:
> On 27/05/2020 15:25, David Sterba wrote:
> > The key for all userspace commands needs to be specified the same way as
> > for kernel, ie. "--auth-key btrfs:foo" and use the appropriate ioctls to
> > read the key bytes.
> 
> Up to now I haven't been able to add a key to the kernel's keyring which 
> can be read back to user-space.

I was researching a possibility to use libkcapi, the API to use kernel
crypto implementaion, in order to avoid passing the raw key to userspace
completely. Basically, setting up what hash and key to use, pass the
buffer and get back the hash. API-wise it's just one more line to
specify the key -- by the numerical id. But no such interface is there,
only the raw bytes translating the request to the .setkey callback.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3 0/3] Add file-system authentication to BTRFS
  2020-05-26 12:44       ` Johannes Thumshirn
@ 2020-06-01 14:59         ` David Sterba
  0 siblings, 0 replies; 28+ messages in thread
From: David Sterba @ 2020-06-01 14:59 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: dsterba, Johannes Thumshirn, linux-fsdevel, linux-btrfs,
	Eric Biggers, Richard Weinberger

On Tue, May 26, 2020 at 12:44:28PM +0000, Johannes Thumshirn wrote:
> On 26/05/2020 13:54, David Sterba wrote:
> > On Tue, May 26, 2020 at 07:50:53AM +0000, Johannes Thumshirn wrote:
> >> On 25/05/2020 15:11, David Sterba wrote:
> >>> I'd outright skip crc32c for the checksum so we have only small number
> >>> of authenticated checksums and avoid too many options, eg.
> >>> hmac-sha256-crc32c etc. The result will be still 2 authenticated hashes
> >>> with the added checksum hardcoded to xxhash.
> >>
> >> Hmm I'm really not a fan of this. We would have to use something like 
> >> sha2-224 to get the room for the 2nd checksum. So we're using a weaker
> >> hash just so we can add a second checksum.
> > 
> > The idea is to calculate full hash (32 bytes) and store only the part
> > (24 bytes). Yes this means there's some information loss and weakening,
> > but enables a usecase.
> 
> I'm not enough a security expert to be able to judge this. Eric can I hear 
> your opinion on this?

Given that this has implications on strength and the usecases, I'd
rather let the filesystem provide the options and let the user choose
and not make the decision for their behalf.

This would increase number of authenticated hashes to 4 in the end:

1. authenticated with 32byte/256bit hash (sha256, blake2b)
   + full strength
   - no way to verify checksums without the key

2. authenticated with 24bytes/192bit hash (sha256, blake2b)
   where the last 8 bytes are xxhash64
   ~ weakened strength but should be still sufficient
   + possibility to verify checksums without the key
   - slight perf cost for the 2nd hash

As option 2 needs some evaluation and reasoning whether it does not
compromise the security, I don't insist on having it implemented in the
first phase. I have a prototype code for that so it might live in
linux-next for some time before we'd merge it.

Regarding backward compatibility, the checksums are easy compared to
other features. The supported status can be deteremined directly from
superblock so adding new types of checksum do not require compat bits
and the code for that.

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2020-06-01 14:59 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-14  9:24 [PATCH v3 0/3] Add file-system authentication to BTRFS Johannes Thumshirn
2020-05-14  9:24 ` [PATCH v3 1/3] btrfs: rename btrfs_parse_device_options back to btrfs_parse_early_options Johannes Thumshirn
2020-05-14  9:24 ` [PATCH v3 2/3] btrfs: add authentication support Johannes Thumshirn
2020-05-27 13:24   ` David Sterba
2020-05-27 13:54     ` Johannes Thumshirn
2020-05-27 14:01       ` Johannes Thumshirn
2020-05-27 18:04     ` Johannes Thumshirn
2020-06-01 14:30       ` David Sterba
2020-06-01 14:35       ` David Sterba
2020-05-14  9:24 ` [PATCH v3 3/3] btrfs: document btrfs authentication Johannes Thumshirn
2020-05-14 12:26   ` Jonathan Corbet
2020-05-14 14:54     ` Johannes Thumshirn
2020-05-14 15:14       ` Richard Weinberger
2020-05-14 16:00         ` Jonathan Corbet
2020-05-14 16:05           ` Richard Weinberger
2020-05-24 19:55   ` David Sterba
2020-05-25 10:57     ` Johannes Thumshirn
2020-05-25 11:26       ` David Sterba
2020-05-25 11:44         ` Johannes Thumshirn
2020-05-25 13:10 ` [PATCH v3 0/3] Add file-system authentication to BTRFS David Sterba
2020-05-26  7:50   ` Johannes Thumshirn
2020-05-26 11:53     ` David Sterba
2020-05-26 12:44       ` Johannes Thumshirn
2020-06-01 14:59         ` David Sterba
2020-05-27  2:08 ` Qu Wenruo
2020-05-27 11:27   ` David Sterba
2020-05-27 11:58     ` Qu Wenruo
2020-05-27 13:11   ` David Sterba

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.