linux-f2fs-devel.lists.sourceforge.net archive mirror
 help / color / mirror / Atom feed
* [f2fs-dev] [PATCH v2 0/2] userspace support for metadata encryption.
@ 2020-12-17 15:10 Satya Tangirala via Linux-f2fs-devel
  2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support Satya Tangirala via Linux-f2fs-devel
  2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 2/2] libf2fs_io: Make metadata encryption work with sparse mode Satya Tangirala via Linux-f2fs-devel
  0 siblings, 2 replies; 6+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-12-17 15:10 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers, Chao Yu; +Cc: Satya Tangirala, linux-f2fs-devel

The kernel patches for metadata encryption are at:
https://lore.kernel.org/linux-fscrypt/20201217150435.1505269-1-satyat@google.com/

This patch series implements the userspace changes required for metadata
encryption support as implemented in the kernel changes above. All blocks
in the filesystem are encrypted with the user provided metadata encryption
key except for the superblock (and its redundant copy). The DUN for a block
is its offset from the start of the filesystem.

Patch 1 introduces two new options for mkfs.f2fs: '-A' to specify the
encryption algorithm, and '-M' to specify the encryption key.
mkfs.f2fs will store the encryption algorithm and the key identifier of the
key used for metadata encryption in the superblock itself. The rest of the
tools will obtain the encryption algorithm and the key identifier from the
superblock of the FS, and don't need any new options.

Patch 2 is an attempt at getting metadata encryption to work with sparse
mode. It is currently untested because I haven't yet figured out how to set
up the environment to compile and test sparse mode, but I've included it
here in case there are already objections to the approach.

Limitations: 
This patch requires the metadata encryption key to be readable from
userspace, and does not ensure that it is zeroed before the program exits
for any reason.

Changes v1 => v2:
 - update userspace tools to work with the kernel changes for v2
 - mkfs.f2fs stores the metadata crypt key identifier in the superblock,
   and the remaining tools use it to obtain the metadata encryption key.
   As such, only mkfs.f2fs requires new options.
 - use libkcapi for all encryption tasks.
 - updated man pages
 - cleanups and improved docs/error messages
 - added an attempt to make metadata encryption work with sparse mode


Satya Tangirala (2):
  f2fs-tools: Introduce metadata encryption support
  libf2fs_io: Make metadata encryption work with sparse mode

 README                        |   2 +
 configure.ac                  |   2 +
 fsck/main.c                   |   2 +
 fsck/mount.c                  |  27 +++-
 include/f2fs_fs.h             |  21 ++-
 include/f2fs_metadata_crypt.h |  33 ++++
 lib/Makefile.am               |   4 +-
 lib/f2fs_metadata_crypt.c     | 284 ++++++++++++++++++++++++++++++++++
 lib/libf2fs.c                 |   3 -
 lib/libf2fs_io.c              | 189 +++++++++++++++++++---
 man/fsck.f2fs.8               |   5 +-
 man/mkfs.f2fs.8               |  44 ++++++
 mkfs/f2fs_format.c            |   8 +-
 mkfs/f2fs_format_main.c       |  35 ++++-
 14 files changed, 624 insertions(+), 35 deletions(-)
 create mode 100644 include/f2fs_metadata_crypt.h
 create mode 100644 lib/f2fs_metadata_crypt.c

-- 
2.29.2.729.g45daf8777d-goog



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

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

* [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support
  2020-12-17 15:10 [f2fs-dev] [PATCH v2 0/2] userspace support for metadata encryption Satya Tangirala via Linux-f2fs-devel
@ 2020-12-17 15:10 ` Satya Tangirala via Linux-f2fs-devel
  2020-12-17 15:47   ` Satya Tangirala via Linux-f2fs-devel
  2020-12-18  1:06   ` Chao Yu
  2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 2/2] libf2fs_io: Make metadata encryption work with sparse mode Satya Tangirala via Linux-f2fs-devel
  1 sibling, 2 replies; 6+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-12-17 15:10 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers, Chao Yu; +Cc: Satya Tangirala, linux-f2fs-devel

Introduce native metadata encryption support for f2fs. All blocks
other than the super block (and its redundant copy) are encrypted with the
specified metadata encryption key and algorithm. The IV for each block is
its block number in the filesystem.

This patch introduces two new options '-A' and '-M' for specifying metadata
crypt options to mkfs.f2fs. '-A' takes the desired metadata encryption
algorithm as argument. '-M' takes the linux key_serial of the metadata
crypt key as the argument. The keyring key provided must be of a key
type that supports reading the payload from userspace.

mkfs.f2fs stores the encryption algorithm and the key's identifier in the
superblock of the FS. The key's identifier is derived from the raw metadata
key. The key identifier will be verified at mount time by the kernel by
doing the same derivation on the raw metadata key (hence the metadata
crypt key must be inserted with the same description as what mkfs.f2fs
stores in the superblock and prints to stdout, before the filesystem can
be mounted). The actual metadata encryption key used to encrypt metadata
is derived from the raw metadata key (for details, refer to
f2fs_metadata_process_key_serial()).

The rest of the programs use the encryption algorithm and the key
identifier stored in the superblock of the FS. They also verify that
the payload of the key matches the identifier of the key, before proceeding
to use the key.

Signed-off-by: Satya Tangirala <satyat@google.com>
---
 README                        |   2 +
 configure.ac                  |   2 +
 fsck/main.c                   |   2 +
 fsck/mount.c                  |  27 +++-
 include/f2fs_fs.h             |  21 ++-
 include/f2fs_metadata_crypt.h |  33 ++++
 lib/Makefile.am               |   4 +-
 lib/f2fs_metadata_crypt.c     | 284 ++++++++++++++++++++++++++++++++++
 lib/libf2fs.c                 |   3 -
 lib/libf2fs_io.c              |  78 +++++++++-
 man/fsck.f2fs.8               |   5 +-
 man/mkfs.f2fs.8               |  44 ++++++
 mkfs/f2fs_format.c            |   8 +-
 mkfs/f2fs_format_main.c       |  35 ++++-
 14 files changed, 529 insertions(+), 19 deletions(-)
 create mode 100644 include/f2fs_metadata_crypt.h
 create mode 100644 lib/f2fs_metadata_crypt.c

diff --git a/README b/README
index 4ea3356..881bebc 100644
--- a/README
+++ b/README
@@ -13,6 +13,8 @@ You should install the following packages.
  - autoconf
  - libtool
  - libselinux1-dev
+ - libkeyutils-dev
+ - libkcapi-dev
 
 Initial compilation
 -------------------
diff --git a/configure.ac b/configure.ac
index 1e5619d..ddda70a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,9 +85,11 @@ AC_CHECK_HEADERS(m4_flatten([
 	attr/xattr.h
 	byteswap.h
 	fcntl.h
+	kcapi.h
 	linux/blkzoned.h
 	linux/falloc.h
 	linux/fs.h
+	linux/fscrypt.h
 	linux/hdreg.h
 	linux/limits.h
 	linux/posix_acl.h
diff --git a/fsck/main.c b/fsck/main.c
index 32559f1..36c9095 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -26,6 +26,8 @@
 #include <stdbool.h>
 #include "quotaio.h"
 
+#include "f2fs_metadata_crypt.h"
+
 struct f2fs_fsck gfsck;
 
 #ifdef WITH_ANDROID
diff --git a/fsck/mount.c b/fsck/mount.c
index 8ebc5b0..5cbc962 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -11,6 +11,7 @@
 #include "fsck.h"
 #include "node.h"
 #include "xattr.h"
+#include "f2fs_metadata_crypt.h"
 #include <locale.h>
 #include <stdbool.h>
 #ifdef HAVE_LINUX_POSIX_ACL_H
@@ -561,12 +562,21 @@ void print_sb_state(struct f2fs_super_block *sb)
 	if (f & cpu_to_le32(F2FS_FEATURE_COMPRESSION)) {
 		MSG(0, "%s", " compression");
 	}
+
 	MSG(0, "\n");
 	MSG(0, "Info: superblock encrypt level = %d, salt = ",
 					sb->encryption_level);
 	for (i = 0; i < 16; i++)
 		MSG(0, "%02x", sb->encrypt_pw_salt[i]);
 	MSG(0, "\n");
+
+	if (sb->metadata_crypt_alg) {
+		MSG(0, "Info: Metadata encryption enabled. Alg = %d, key identifier = fscrypt:",
+		    get_sb(metadata_crypt_alg));
+	}
+	for (i = 0; i < FSCRYPT_KEY_IDENTIFIER_SIZE; i++)
+		MSG(0, "%02x", sb->metadata_crypt_key_ident[i]);
+	MSG(0, "\n");
 }
 
 static inline bool is_valid_data_blkaddr(block_t blkaddr)
@@ -686,7 +696,7 @@ void update_superblock(struct f2fs_super_block *sb, int sb_mask)
 	memcpy(buf + F2FS_SUPER_OFFSET, sb, sizeof(*sb));
 	for (addr = SB0_ADDR; addr < SB_MAX_ADDR; addr++) {
 		if (SB_MASK(addr) & sb_mask) {
-			ret = dev_write_block(buf, addr);
+			ret = dev_write_block_no_encrypt(buf, addr);
 			ASSERT(ret >= 0);
 		}
 	}
@@ -940,7 +950,7 @@ int validate_super_block(struct f2fs_sb_info *sbi, enum SB_ADDR sb_addr)
 	if (!sbi->raw_super)
 		return -ENOMEM;
 
-	if (dev_read_block(buf, sb_addr))
+	if (dev_read_block_no_decrypt(buf, sb_addr))
 		return -1;
 
 	memcpy(sbi->raw_super, buf + F2FS_SUPER_OFFSET,
@@ -3499,6 +3509,19 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
 	}
 	sb = F2FS_RAW_SUPER(sbi);
 
+	/* Setup metadata encryption */
+	c.metadata_crypt_alg = get_sb(metadata_crypt_alg);
+	if (c.metadata_crypt_alg) {
+		ret = f2fs_metadata_process_key_ident(
+						sb->metadata_crypt_key_ident);
+		if (ret)
+			return ret;
+
+		ret = f2fs_metadata_verify_args();
+		if (ret)
+			return ret;
+	}
+
 	ret = check_sector_size(sb);
 	if (ret)
 		return -1;
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index b5bda13..1f12607 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -49,6 +49,8 @@
 #include <selinux/label.h>
 #endif
 
+#include <linux/fscrypt.h>
+
 #ifdef UNUSED
 #elif defined(__GNUC__)
 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
@@ -175,6 +177,9 @@ static inline uint64_t bswap_64(uint64_t val)
 
 #define NULL_SEGNO	((unsigned int)~0)
 
+#define ARRAY_SIZE(array)			\
+	(sizeof(array) / sizeof(array[0]))
+
 /*
  * Debugging interfaces
  */
@@ -345,6 +350,7 @@ typedef struct {
 	bool dbg_en;
 } dev_cache_config_t;
 
+struct kcapi_handle;
 struct f2fs_configuration {
 	u_int32_t reserved_segments;
 	u_int32_t new_reserved_segments;
@@ -441,6 +447,13 @@ struct f2fs_configuration {
 
 	/* cache parameters */
 	dev_cache_config_t cache_config;
+
+	/* metadata encryption */
+	__u8 *metadata_crypt_key;
+	__u8 metadata_crypt_key_ident[FSCRYPT_KEY_IDENTIFIER_SIZE];
+	int metadata_crypt_key_len;
+	int metadata_crypt_alg;
+	struct kcapi_handle *kcapi_handle;
 };
 
 #ifdef CONFIG_64BIT
@@ -675,7 +688,11 @@ struct f2fs_super_block {
 	__u8 hot_ext_count;		/* # of hot file extension */
 	__le16  s_encoding;		/* Filename charset encoding */
 	__le16  s_encoding_flags;	/* Filename charset encoding flags */
-	__u8 reserved[306];		/* valid reserved region */
+	/* The metadata encryption algorithm (FSCRYPT_MODE_*) */
+	__le32 metadata_crypt_alg;
+	/* The metadata crypt key identifier */
+	__u8 metadata_crypt_key_ident[FSCRYPT_KEY_IDENTIFIER_SIZE];
+	__u8 reserved[286];		/* valid reserved region */
 	__le32 crc;			/* checksum of superblock */
 } __attribute__((packed));
 
@@ -1237,12 +1254,14 @@ extern int dev_readahead(__u64, size_t UNUSED(len));
 #endif
 extern int dev_write(void *, __u64, size_t);
 extern int dev_write_block(void *, __u64);
+extern int dev_write_block_no_encrypt(void *, __u64);
 extern int dev_write_dump(void *, __u64, size_t);
 /* All bytes in the buffer must be 0 use dev_fill(). */
 extern int dev_fill(void *, __u64, size_t);
 extern int dev_fill_block(void *, __u64);
 
 extern int dev_read_block(void *, __u64);
+extern int dev_read_block_no_decrypt(void *, __u64);
 extern int dev_reada_block(__u64);
 
 extern int dev_read_version(void *, __u64, size_t);
diff --git a/include/f2fs_metadata_crypt.h b/include/f2fs_metadata_crypt.h
new file mode 100644
index 0000000..6aece31
--- /dev/null
+++ b/include/f2fs_metadata_crypt.h
@@ -0,0 +1,33 @@
+/**
+ * f2fs_metadata_crypt.h
+ *
+ * Copyright (c) 2020 Google LLC
+ *
+ * Dual licensed under the GPL or LGPL version 2 licenses.
+ */
+
+#include <inttypes.h>
+#include <linux/fscrypt.h>
+#include <keyutils.h>
+
+#ifndef HKDF_CONTEXT_METADATA_ENC_KEY
+#define HKDF_CONTEXT_KEY_IDENTIFIER	1
+#define HKDF_CONTEXT_METADATA_ENC_KEY	8
+#endif
+
+#ifndef FSCRYPT_MAX_IV_SIZE
+#define FSCRYPT_MAX_IV_SIZE 32
+#endif
+
+int f2fs_get_crypt_alg(const char *optarg);
+
+void f2fs_print_crypt_algs(void);
+
+int f2fs_metadata_process_key_serial(key_serial_t key_serial);
+
+int f2fs_metadata_process_key_ident(u8 key_ident[FSCRYPT_KEY_IDENTIFIER_SIZE]);
+
+int f2fs_metadata_verify_args(void);
+
+void *f2fs_metadata_crypt_blocks(void *src_buf, size_t len, __u64 blk_addr,
+	bool encrypt);
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 871d773..a0173d0 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,10 +2,10 @@
 
 lib_LTLIBRARIES = libf2fs.la
 
-libf2fs_la_SOURCES = libf2fs.c libf2fs_io.c libf2fs_zoned.c nls_utf8.c
+libf2fs_la_SOURCES = libf2fs.c libf2fs_io.c libf2fs_zoned.c nls_utf8.c f2fs_metadata_crypt.c
 libf2fs_la_CFLAGS = -Wall
 libf2fs_la_CPPFLAGS = -I$(top_srcdir)/include
-libf2fs_la_LDFLAGS = -version-info $(LIBF2FS_CURRENT):$(LIBF2FS_REVISION):$(LIBF2FS_AGE)
+libf2fs_la_LDFLAGS = -lkeyutils -lkcapi -version-info $(LIBF2FS_CURRENT):$(LIBF2FS_REVISION):$(LIBF2FS_AGE)
 
 root_libdir=@root_libdir@
 
diff --git a/lib/f2fs_metadata_crypt.c b/lib/f2fs_metadata_crypt.c
new file mode 100644
index 0000000..3869788
--- /dev/null
+++ b/lib/f2fs_metadata_crypt.c
@@ -0,0 +1,284 @@
+/**
+ * f2fs_metadata_crypt.c
+ *
+ * Copyright (c) 2020 Google LLC
+ *
+ * Dual licensed under the GPL or LGPL version 2 licenses.
+ */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/if_alg.h>
+#include <linux/socket.h>
+#include <assert.h>
+#include <errno.h>
+#include <kcapi.h>
+
+#include "f2fs_fs.h"
+#include "f2fs_metadata_crypt.h"
+
+extern struct f2fs_configuration c;
+const struct f2fs_crypt_mode {
+	const char *friendly_name;
+	const char *cipher_str;
+	unsigned int keysize;
+	unsigned int ivlen;
+} f2fs_crypt_modes[] = {
+	[FSCRYPT_MODE_AES_256_XTS] = {
+		.friendly_name = "AES-256-XTS",
+		.cipher_str = "xts(aes)",
+		.keysize = 64,
+		.ivlen = 16,
+	},
+	[FSCRYPT_MODE_ADIANTUM] = {
+		.friendly_name = "Adiantum",
+		.cipher_str = "adiantum(xchacha12,aes)",
+		.keysize = 32,
+		.ivlen = 32,
+	},
+};
+#define MAX_IV_LEN 32
+
+void f2fs_print_crypt_algs(void)
+{
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(f2fs_crypt_modes); i++) {
+		if (!f2fs_crypt_modes[i].friendly_name)
+			continue;
+		MSG(0, "\t%s\n", f2fs_crypt_modes[i].friendly_name);
+	}
+}
+
+int f2fs_get_crypt_alg(const char *optarg)
+{
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(f2fs_crypt_modes); i++) {
+		if (f2fs_crypt_modes[i].friendly_name &&
+		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+int f2fs_metadata_hkdf(u8 *key, unsigned int keysize,
+			u8 context_byte, u8 *dest, unsigned int dest_len)
+{
+	u8 info[9];
+
+	memcpy(info, "fscrypt\0", 8);
+	info[8] = context_byte;
+
+	return kcapi_hkdf("hmac(sha512)", key, keysize, NULL, 0,
+			  info, sizeof(info), dest, dest_len);
+}
+
+int f2fs_metadata_process_key_serial(key_serial_t key_serial)
+{
+	int err = 0;
+	u8 *metadata_key;
+
+	c.metadata_crypt_key_len =
+		keyctl_read_alloc(key_serial, (void **)&metadata_key);
+
+	if (c.metadata_crypt_key_len < 0) {
+		MSG(0, "\tSpecified metadata crypt key not found.\n");
+		return errno;
+	}
+
+	err = f2fs_metadata_hkdf(metadata_key, c.metadata_crypt_key_len,
+				 HKDF_CONTEXT_KEY_IDENTIFIER,
+				 c.metadata_crypt_key_ident,
+				 FSCRYPT_KEY_IDENTIFIER_SIZE);
+	if (err)
+		goto out;
+
+	c.metadata_crypt_key = malloc(c.metadata_crypt_key_len);
+	if (!c.metadata_crypt_key) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = f2fs_metadata_hkdf(metadata_key, c.metadata_crypt_key_len,
+				 HKDF_CONTEXT_METADATA_ENC_KEY,
+				 c.metadata_crypt_key,
+				 c.metadata_crypt_key_len);
+	if (err)
+		goto out_free_metadata_crypt_key;
+
+	goto out;
+
+out_free_metadata_crypt_key:
+	free(c.metadata_crypt_key);
+out:
+	free(metadata_key);
+	return err;
+}
+
+int f2fs_metadata_process_key_ident(u8 key_ident[FSCRYPT_KEY_IDENTIFIER_SIZE])
+{
+	char key_desc[FSCRYPT_KEY_DESC_PREFIX_SIZE +
+		      FSCRYPT_KEY_IDENTIFIER_SIZE * 2 + 1];
+	char *prefix = "fscrypt:";
+	int prefix_len = strlen(prefix);
+	int offset = prefix_len;
+	int i = 0;
+	key_serial_t key_serial;
+	int err;
+
+	memcpy(key_desc, prefix, prefix_len);
+	for (i = 0; i < FSCRYPT_KEY_IDENTIFIER_SIZE; i++, offset += 2)
+		sprintf(key_desc + offset, "%02x", key_ident[i]);
+
+	key_serial = request_key("user", key_desc, NULL, 0);
+	if (key_serial == -1) {
+		MSG(0, "The metadata key was not found. Expected to find a key with type \"user\" in a process subscribed keyring.\n");
+		MSG(0, "The required key descriptor is %s\n", key_desc);
+		return -errno;
+	}
+
+	err = f2fs_metadata_process_key_serial(key_serial);
+	if (err)
+		return err;
+
+	if (memcmp(key_ident, c.metadata_crypt_key_ident,
+		   FSCRYPT_KEY_IDENTIFIER_SIZE)) {
+		MSG(0, "The metadata key had incorrect key identifier\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int f2fs_metadata_verify_args(void)
+{
+	const struct f2fs_crypt_mode *crypt_mode;
+	int ret;
+
+	/* If neither specified, nothing to do */
+	if (!c.metadata_crypt_key && !c.metadata_crypt_alg)
+		return 0;
+
+	/* We need both specified */
+	if (!c.metadata_crypt_key || !c.metadata_crypt_alg)
+		return -EINVAL;
+
+	if (c.metadata_crypt_alg < 0 ||
+	    c.metadata_crypt_alg >= ARRAY_SIZE(f2fs_crypt_modes))
+		return -EINVAL;
+
+	crypt_mode = &f2fs_crypt_modes[c.metadata_crypt_alg];
+
+	if (!crypt_mode->keysize) {
+		MSG(0, "\tInvalid crypto mode %d\n", c.metadata_crypt_alg);
+		return -EINVAL;
+	}
+
+	if (c.metadata_crypt_key_len != crypt_mode->keysize) {
+		MSG(0, "\tMetadata encryption key length %d didn't match required size %d\n",
+		    c.metadata_crypt_key_len, crypt_mode->keysize);
+
+		return -EINVAL;
+	}
+
+	ret = kcapi_cipher_init(&c.kcapi_handle, crypt_mode->cipher_str, 0);
+
+	if (ret) {
+		switch (ret) {
+		case -ENOENT:
+			MSG(0, "The required metadata crypto algorithm %s was not available. Maybe support for the algorithm or CRYPTO_USER_API_SKCIPHER wasn't enabled in the kernel config.\n",
+			    crypt_mode->cipher_str);
+			break;
+		case -EOPNOTSUPP:
+			MSG(0, "The AF_ALG family isn't available. Maybe it's not enabled in the kernel config, or its use isn't allowed by the SELinux policy.\n");
+			break;
+		case -EINVAL:
+			MSG(0, "The accept syscall failed while trying to use the kernel crypto API.\n");
+			break;
+		case -ENOMEM:
+			MSG(0, "Not enough memory to allocate crypto cipher.\n");
+			break;
+		default:
+			MSG(0, "Something went wrong while setting up the crypto cipher %d\n",
+			    ret);
+		}
+		return ret;
+	}
+
+	ret = kcapi_cipher_setkey(c.kcapi_handle, c.metadata_crypt_key,
+				  c.metadata_crypt_key_len);
+	if (ret < 0) {
+		MSG(0, "Couldn't set key for metadata cipher.\n");
+		kcapi_cipher_destroy(c.kcapi_handle);
+		return ret;
+	}
+
+	return 0;
+}
+
+void f2fs_metadata_crypt_gen_iv(u8 iv[FSCRYPT_MAX_IV_SIZE], __u64 blk_addr)
+{
+	int i = 0;
+
+	memset(iv, 0, FSCRYPT_MAX_IV_SIZE);
+
+	while (blk_addr > 0) {
+		iv[i] = blk_addr & 0xFF;
+		blk_addr >>= 8;
+		i++;
+	}
+}
+
+int f2fs_metadata_crypt_block(u8 *buf, u8 iv[FSCRYPT_MAX_IV_SIZE], bool encrypt)
+{
+	int ret;
+
+	if (encrypt)
+		ret = kcapi_cipher_encrypt(c.kcapi_handle, buf, F2FS_BLKSIZE,
+					   iv, buf, F2FS_BLKSIZE, 0);
+	else
+		ret = kcapi_cipher_decrypt(c.kcapi_handle, buf, F2FS_BLKSIZE,
+					   iv, buf, F2FS_BLKSIZE, 0);
+	if (ret != F2FS_BLKSIZE) {
+		if (ret < 0)
+			MSG(0, "\tFailed to en/decrypt blocks. Errno %d\n", ret);
+		else
+			MSG(0, "\tFailed to en/decrypt the entire block (only part of it was en/decrypted)\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void *f2fs_metadata_crypt_blocks(void *buf, size_t len, __u64 blk_addr,
+				 bool encrypt)
+{
+	u8 *out_buf;
+	u8 iv[FSCRYPT_MAX_IV_SIZE];
+	int blk_offset;
+	int ret;
+
+	if (!c.metadata_crypt_key)
+		return buf;
+
+	out_buf = malloc(len);
+	memcpy(out_buf, buf, len);
+
+	for (blk_offset = 0; blk_offset < len / F2FS_BLKSIZE; blk_offset++) {
+		f2fs_metadata_crypt_gen_iv(iv, blk_addr + blk_offset);
+		ret = f2fs_metadata_crypt_block(
+					out_buf + blk_offset * F2FS_BLKSIZE,
+					iv, encrypt);
+		if (ret) {
+			free(out_buf);
+			return NULL;
+		}
+	}
+
+	return out_buf;
+}
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 55fa391..6950c04 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -1270,9 +1270,6 @@ unsigned int calc_extra_isize(void)
 	return size - F2FS_EXTRA_ISIZE_OFFSET;
 }
 
-#define ARRAY_SIZE(array)			\
-	(sizeof(array) / sizeof(array[0]))
-
 static const struct {
 	char *name;
 	__u16 encoding_magic;
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 138285d..df3723d 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -33,6 +33,7 @@
 #include <assert.h>
 #include <inttypes.h>
 #include "f2fs_fs.h"
+#include "f2fs_metadata_crypt.h"
 
 struct f2fs_configuration c;
 
@@ -499,10 +500,12 @@ static int sparse_write_blk(__u64 block, int count, const void *buf) { return 0;
 static int sparse_write_zeroed_blk(__u64 block, int count) { return 0; }
 #endif
 
-int dev_read(void *buf, __u64 offset, size_t len)
+static int __dev_read(void *buf, __u64 offset, size_t len, bool metadata_decrypt)
 {
 	int fd;
+	__u64 blk_addr = offset >> F2FS_BLKSIZE_BITS;
 	int err;
+	void *new_buf = NULL;
 
 	if (c.sparse_mode)
 		return sparse_read_blk(offset / F2FS_BLKSIZE,
@@ -521,9 +524,24 @@ int dev_read(void *buf, __u64 offset, size_t len)
 		return -1;
 	if (read(fd, buf, len) < 0)
 		return -1;
+	if (metadata_decrypt) {
+		new_buf = f2fs_metadata_crypt_blocks(buf, len, blk_addr, false);
+		if (!new_buf)
+			return -1;
+		if (new_buf != buf) {
+			memcpy(buf, new_buf, len);
+			free(new_buf);
+		}
+	}
+
 	return 0;
 }
 
+int dev_read(void *buf, __u64 offset, size_t len)
+{
+	return __dev_read(buf, offset, len, true);
+}
+
 #ifdef POSIX_FADV_WILLNEED
 int dev_readahead(__u64 offset, size_t len)
 #else
@@ -541,9 +559,13 @@ int dev_readahead(__u64 offset, size_t UNUSED(len))
 #endif
 }
 
-int dev_write(void *buf, __u64 offset, size_t len)
+static int __dev_write(void *buf, __u64 offset, size_t len,
+		       bool metadata_encrypt)
 {
 	int fd;
+	__u64 blk_addr = offset >> F2FS_BLKSIZE_BITS;
+	void *src_buf = buf;
+	int err = -1;
 
 	if (c.dry_run)
 		return 0;
@@ -562,11 +584,26 @@ int dev_write(void *buf, __u64 offset, size_t len)
 	 */
 	if (dcache_update_cache(fd, buf, (off64_t)offset, len) < 0)
 		return -1;
+	if (metadata_encrypt) {
+		buf = f2fs_metadata_crypt_blocks(buf, len, blk_addr, true);
+		if (!buf)
+			return -1;
+	}
 	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
-		return -1;
+		goto out;
 	if (write(fd, buf, len) < 0)
-		return -1;
-	return 0;
+		goto out;
+
+	err = 0;
+out:
+	if (buf != src_buf)
+		free(buf);
+	return err;
+}
+
+int dev_write(void *buf, __u64 offset, size_t len)
+{
+	return __dev_write(buf, offset, len, true);
 }
 
 int dev_write_block(void *buf, __u64 blk_addr)
@@ -574,6 +611,12 @@ int dev_write_block(void *buf, __u64 blk_addr)
 	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
 }
 
+int dev_write_block_no_encrypt(void *buf, __u64 blk_addr)
+{
+	return __dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE,
+			   false);
+}
+
 int dev_write_dump(void *buf, __u64 offset, size_t len)
 {
 	if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
@@ -586,6 +629,9 @@ int dev_write_dump(void *buf, __u64 offset, size_t len)
 int dev_fill(void *buf, __u64 offset, size_t len)
 {
 	int fd;
+	__u64 blk_addr = offset >> F2FS_BLKSIZE_BITS;
+	void *src_buf = buf;
+	int err = -1;
 
 	if (c.sparse_mode)
 		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
@@ -598,11 +644,21 @@ int dev_fill(void *buf, __u64 offset, size_t len)
 	/* Only allow fill to zero */
 	if (*((__u8*)buf))
 		return -1;
-	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
+
+	buf = f2fs_metadata_crypt_blocks(buf, len, blk_addr, true);
+	if (!buf)
 		return -1;
+
+	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
+		goto out;
 	if (write(fd, buf, len) < 0)
-		return -1;
-	return 0;
+		goto out;
+
+	err = 0;
+out:
+	if (buf != src_buf)
+		free(buf);
+	return err;
 }
 
 int dev_fill_block(void *buf, __u64 blk_addr)
@@ -615,6 +671,12 @@ int dev_read_block(void *buf, __u64 blk_addr)
 	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
 }
 
+int dev_read_block_no_decrypt(void *buf, __u64 blk_addr)
+{
+	return __dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE,
+			  false);
+}
+
 int dev_reada_block(__u64 blk_addr)
 {
 	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
diff --git a/man/fsck.f2fs.8 b/man/fsck.f2fs.8
index af1076c..56943cd 100644
--- a/man/fsck.f2fs.8
+++ b/man/fsck.f2fs.8
@@ -30,7 +30,10 @@ fsck.f2fs \- check a Linux F2FS file system
 .B fsck.f2fs
 is used to check an f2fs file system (usually in a disk partition).
 \fIdevice\fP is the special file corresponding to the device (e.g.
-\fI/dev/sdXX\fP).
+\fI/dev/sdXX\fP). If the filesystem has metadata encryption enabled,
+then the required metadata encryption key should be added to a process
+subscribed keyring with key-type "user". The other requirements for
+metadata encryption are listed under the \-M option for mkfs.f2fs.
 .PP
 The exit code returned by
 .B fsck.f2fs
diff --git a/man/mkfs.f2fs.8 b/man/mkfs.f2fs.8
index e2aee76..0ea114f 100644
--- a/man/mkfs.f2fs.8
+++ b/man/mkfs.f2fs.8
@@ -12,6 +12,10 @@ mkfs.f2fs \- create an F2FS file system
 .I heap-based-allocation
 ]
 [
+.B \-A
+.I metadata-encryption-algorithm
+]
+[
 .B \-c
 .I device-list
 ]
@@ -44,6 +48,10 @@ mkfs.f2fs \- create an F2FS file system
 .B \-m
 ]
 [
+.B \-M
+.I metadata-crypt-key-serial
+]
+[
 .B \-o
 .I overprovision-ratio-percentage
 ]
@@ -110,6 +118,24 @@ Specify 1 or 0 to enable/disable heap based block allocation policy.
 If the value is equal to 1, each of active log areas are initially
 assigned separately according to the whole volume size.
 The default value is 1.
+
+.TP
+.BI \-A " metadata-encryption-algorithm"
+Specify the encryption algorithm to use for metadata encryption. The \-M
+option must also be specified, providing the metadata crypt key to use.
+Check the description of the \-M option for requirements before using this
+pair of options.
+The following values are supported for this option:
+.RS 1.2i
+.TP 1.2i
+.B AES-256-XTS
+Use xts(aes) for metadata encryption. The required key length is 64 bytes.
+.TP
+.B Adiantum
+Use adiantum (adiantum(xchacha12,aes)) for metadata encryption. The
+required key length is 32 bytes.
+.RE
+
 .TP
 .BI \-c " device-list"
 Build f2fs with these additional comma separated devices, so that the user can
@@ -147,6 +173,24 @@ Specify the volume label to the partition mounted as F2FS.
 .BI \-m
 Specify f2fs filesystem to supports the block zoned feature.
 Without it, the filesystem doesn't support the feature.
+
+.TP
+.BI \-M
+Specify the key_serial (as returned by keyctl) of the metadata crypt key to
+use for metadata encryption. This key is not used directly as the
+encryption key - the encryption key is derived from this key using
+hmac(sha512). This option must be specified along with the \-A option.
+The length of the key must match the required key length of the chosen
+algorithm.
+.P
+.RS
+The kernel must support the AF_ALG socket family (and it must be allowed
+by the SELinux policy), the kernel crypto userspace API for symmetric
+ciphers (i.e. CONFIG_CRYPTO_USER_API_SKCIPHER) must be enabled, and
+crypto API support for the chosen encryption algorithm must be enabled for
+this option to work.
+.RE
+
 .TP
 .BI \-o " overprovision-ratio-percentage"
 Specify the percentage of the volume that will be used as overprovision area.
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index a6c542e..2d68aa4 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -537,6 +537,12 @@ static int f2fs_prepare_super_block(void)
 		set_sb(s_encoding_flags, c.s_encoding_flags);
 	}
 
+	if (c.metadata_crypt_key) {
+		set_sb(metadata_crypt_alg, c.metadata_crypt_alg);
+		memcpy(sb->metadata_crypt_key_ident, c.metadata_crypt_key_ident,
+		       FSCRYPT_KEY_IDENTIFIER_SIZE);
+	}
+
 	sb->feature = c.feature;
 
 	if (get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) {
@@ -1046,7 +1052,7 @@ static int f2fs_write_super_block(void)
 	memcpy(zero_buff + F2FS_SUPER_OFFSET, sb, sizeof(*sb));
 	DBG(1, "\tWriting super block, at offset 0x%08x\n", 0);
 	for (index = 0; index < 2; index++) {
-		if (dev_write_block(zero_buff, index)) {
+		if (dev_write_block_no_encrypt(zero_buff, index)) {
 			MSG(1, "\tError: While while writing super_blk "
 					"on disk!!! index : %d\n", index);
 			free(zero_buff);
diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c
index f2f0a80..139251c 100644
--- a/mkfs/f2fs_format_main.c
+++ b/mkfs/f2fs_format_main.c
@@ -28,6 +28,7 @@
 
 #include "f2fs_fs.h"
 #include "f2fs_format_utils.h"
+#include "f2fs_metadata_crypt.h"
 
 #ifdef WITH_ANDROID
 #include <sparse/sparse.h>
@@ -44,6 +45,7 @@ static void mkfs_usage()
 	MSG(0, "\nUsage: mkfs.f2fs [options] device [sectors]\n");
 	MSG(0, "[options]:\n");
 	MSG(0, "  -a heap-based allocation [default:0]\n");
+	MSG(0, "  -A Metadata encryption algorithm\n");
 	MSG(0, "  -c device1[,device2,...] up to 7 additional devices, except meta device\n");
 	MSG(0, "  -d debug level [default:0]\n");
 	MSG(0, "  -e [cold file ext list] e.g. \"mp3,gif,mov\"\n");
@@ -54,6 +56,7 @@ static void mkfs_usage()
 	MSG(0, "  -l label\n");
 	MSG(0, "  -U uuid\n");
 	MSG(0, "  -m support zoned block device [default:0]\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -o overprovision percentage [default:auto]\n");
 	MSG(0, "  -O feature1[,feature2,...] e.g. \"encrypt\"\n");
 	MSG(0, "  -C [encoding[:flag1,...]] Support casefolding with optional flags\n");
@@ -73,6 +76,8 @@ static void mkfs_usage()
 
 static void f2fs_show_info()
 {
+	int i;
+
 	MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n",
 				F2FS_TOOLS_VERSION,
 				F2FS_TOOLS_DATE);
@@ -97,6 +102,14 @@ static void f2fs_show_info()
 					f2fs_encoding2str(c.s_encoding));
 	if (c.feature & le32_to_cpu(F2FS_FEATURE_PRJQUOTA))
 		MSG(0, "Info: Enable Project quota\n");
+
+	if (c.metadata_crypt_alg) {
+		MSG(0, "Info: Metadata alg is %d\n", c.metadata_crypt_alg);
+		MSG(0, "Info: Metadata key ident is fscrypt:");
+		for (i = 0; i < FSCRYPT_KEY_IDENTIFIER_SIZE; i++)
+			MSG(0, "%02x", c.metadata_crypt_key_ident[i]);
+		MSG(0, "\n");
+	}
 }
 
 static void add_default_options(void)
@@ -125,7 +138,7 @@ static void add_default_options(void)
 
 static void f2fs_parse_options(int argc, char *argv[])
 {
-	static const char *option_string = "qa:c:C:d:e:E:g:il:mo:O:rR:s:S:z:t:T:U:Vfw:";
+	static const char *option_string = "qa:A:c:C:d:e:E:g:il:mM:o:O:rR:s:S:z:t:T:U:Vfw:";
 	int32_t option=0;
 	int val;
 	char *token;
@@ -138,6 +151,14 @@ static void f2fs_parse_options(int argc, char *argv[])
 		case 'a':
 			c.heap = atoi(optarg);
 			break;
+		case 'A':
+			c.metadata_crypt_alg = f2fs_get_crypt_alg(optarg);
+			if (c.metadata_crypt_alg < 0) {
+				MSG(0, "Error: invalid crypt algorithm specified. The choices are:");
+				f2fs_print_crypt_algs();
+				exit(1);
+			}
+			break;
 		case 'c':
 			if (c.ndevs >= MAX_DEVICES) {
 				MSG(0, "Error: Too many devices\n");
@@ -178,6 +199,15 @@ static void f2fs_parse_options(int argc, char *argv[])
 		case 'm':
 			c.zoned_mode = 1;
 			break;
+		case 'M': {
+			key_serial_t key_serial = strtol(optarg, NULL, 10);
+
+			if (f2fs_metadata_process_key_serial(key_serial)) {
+				MSG(0, "Error: Invalid metadata key\n");
+				mkfs_usage();
+			}
+			break;
+		}
 		case 'o':
 			c.overprovision = atof(optarg);
 			break;
@@ -244,6 +274,9 @@ static void f2fs_parse_options(int argc, char *argv[])
 		}
 	}
 
+	if (f2fs_metadata_verify_args())
+		exit(1);
+
 	add_default_options();
 
 	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
-- 
2.29.2.729.g45daf8777d-goog



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

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

* [f2fs-dev] [PATCH v2 2/2] libf2fs_io: Make metadata encryption work with sparse mode
  2020-12-17 15:10 [f2fs-dev] [PATCH v2 0/2] userspace support for metadata encryption Satya Tangirala via Linux-f2fs-devel
  2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support Satya Tangirala via Linux-f2fs-devel
@ 2020-12-17 15:10 ` Satya Tangirala via Linux-f2fs-devel
  1 sibling, 0 replies; 6+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-12-17 15:10 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers, Chao Yu; +Cc: Satya Tangirala, linux-f2fs-devel

This patch is an *untested* attempt to make metadata encryption work with
sparse mode. It's included only in case there are already objections to the
approach.

The easiest way to make metadata encryption work with sparse mode might
be to encrypt buffers before the calls to sparse_write_blk() and decrypt
buffers after the calls to sparse_read_blk() (and just call
sparse_write_blk() from sparse_write_zeroed_blk() if metadata encryption is
enabled). I didn't do that here because multiple reads on unchanging data
would cause unnecessary decryptions, and multiple writes of the same block
would cause unnecessary encryptions.

Instead, in this patch, I opted to allow each block to be stored as either
ciphertext or plaintext. This patch keeps track of whether each block
needs to be encrypted before being written out into the sparse file. Any
writes to a block will cause the block to store the plaintext (and we
mark the block as requiring encryption if the write was supposed to be
encrypted). Any reads that want decrypted plaintext from an encrypted
block will cause the block to first be decrypted and marked as requiring
encryption. Any reads that want the *cipher*-text (not decrypted) data
from a decrypted block will cause the block to first be encrypted and
marked as no longer requiring encryption (this case shouldn't happen
afaict - so each block will be encrypted and decrypted at most once).

Signed-off-by: Satya Tangirala <satyat@google.com>
---
 lib/libf2fs_io.c | 111 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 95 insertions(+), 16 deletions(-)

diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index df3723d..eec02ae 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -41,6 +41,11 @@ struct f2fs_configuration c;
 #include <sparse/sparse.h>
 struct sparse_file *f2fs_sparse_file;
 static char **blocks;
+/*
+ * Whether the block in @blocks needs encryption before being written out to
+ * disk.
+ */
+static bool *block_needs_encryption;
 u_int64_t blocks_count;
 static char *zeroed_block;
 #endif
@@ -397,24 +402,65 @@ int dev_read_version(void *buf, __u64 offset, size_t len)
 }
 
 #ifdef WITH_ANDROID
-static int sparse_read_blk(__u64 block, int count, void *buf)
+static int sparse_read_blk(__u64 block, int count, void *buf,
+			   bool metadata_decrypt)
 {
 	int i;
 	char *out = buf;
 	__u64 cur_block;
+	char *crypt_block;
 
 	for (i = 0; i < count; ++i) {
 		cur_block = block + i;
-		if (blocks[cur_block])
+		if (blocks[cur_block]) {
+			/*
+			 * If metadata_decrypt, caller wants the ciphertext
+			 * *decrypted* with the metadata_key. If
+			 * !metadata_decrypt, caller wants the ciphertext as is.
+			 *
+			 * If block_needs_encryption[cur_block], then cur_block
+			 * is decrypted. Otherwise it is encrypted, and the
+			 * ciphertext is currently stored as the block data.
+			 *
+			 * Hence, if metadata_decrypt && !block_needs_encryption,
+			 * we need to decrypt the (currently encrypted) block
+			 * data, and if !metadata_decrypt &&
+			 * block_needs_encryption, we need to encrypt the
+			 * (currently plaintext) block data
+			 *
+			 * We shouldn't actually need the !metadata_decrypt &&
+			 * block_needs_encryption case, since the only way that
+			 * can happen is if we write an encrypted block and then
+			 * try to read that block's ciphertext (without
+			 * decrypting it), which afaict the f2fs userspace tools
+			 * don't do.
+			 */
+			if (metadata_decrypt != block_needs_encryption[cur_block]) {
+				crypt_block = f2fs_metadata_crypt_blocks(
+						blocks[cur_block], F2FS_BLKSIZE,
+						cur_block,
+						block_needs_encryption[cur_block]);
+				if (!crypt_block)
+					return -EINVAL;
+				block_needs_encryption[cur_block] =
+					!block_needs_encryption[cur_block];
+				if (crypt_block != blocks[cur_block] &&
+				    blocks[cur_block] != zeroed_block) {
+					free(blocks[cur_block]);
+				}
+				blocks[cur_block] = crypt_block;
+			}
 			memcpy(out + (i * F2FS_BLKSIZE),
 					blocks[cur_block], F2FS_BLKSIZE);
+		}
 		else if (blocks)
 			memset(out + (i * F2FS_BLKSIZE), 0, F2FS_BLKSIZE);
 	}
 	return 0;
 }
 
-static int sparse_write_blk(__u64 block, int count, const void *buf)
+static int sparse_write_blk(__u64 block, int count, const void *buf,
+			    bool metadata_encrypt)
 {
 	int i;
 	__u64 cur_block;
@@ -429,13 +475,14 @@ static int sparse_write_blk(__u64 block, int count, const void *buf)
 			if (!blocks[cur_block])
 				return -ENOMEM;
 		}
+		block_needs_encryption[cur_block] = metadata_encrypt;
 		memcpy(blocks[cur_block], in + (i * F2FS_BLKSIZE),
 				F2FS_BLKSIZE);
 	}
 	return 0;
 }
 
-static int sparse_write_zeroed_blk(__u64 block, int count)
+static int sparse_write_zeroed_blk(__u64 block, int count, bool metadata_encrypt)
 {
 	int i;
 	__u64 cur_block;
@@ -444,6 +491,7 @@ static int sparse_write_zeroed_blk(__u64 block, int count)
 		cur_block = block + i;
 		if (blocks[cur_block])
 			continue;
+		block_needs_encryption[cur_block] = metadata_encrypt;
 		blocks[cur_block] = zeroed_block;
 	}
 	return 0;
@@ -461,15 +509,23 @@ static int sparse_import_segment(void *UNUSED(priv), const void *data, int len,
 	if (!nr_blocks || len % F2FS_BLKSIZE)
 		return 0;
 
-	return sparse_write_blk(block, nr_blocks, data);
+	return sparse_write_blk(block, nr_blocks, data, false);
+}
+
+static inline void sparse_replace_block(uint64_t blk_num, char *new_block)
+{
+	if (blocks[cur_block] != zeroed_block)
+		free(blocks[blk_num]);
+	blocks[blk_num] = new_block;
 }
 
 static int sparse_merge_blocks(uint64_t start, uint64_t num, int zero)
 {
-	char *buf;
+	char *buf, *enc_buf;
 	uint64_t i;
+	uint64_t cur_block;
 
-	if (zero) {
+	if (zero && !c.metadata_crypt_key) {
 		blocks[start] = NULL;
 		return sparse_file_add_fill(f2fs_sparse_file, 0x0,
 					F2FS_BLKSIZE * num, start);
@@ -483,9 +539,20 @@ static int sparse_merge_blocks(uint64_t start, uint64_t num, int zero)
 	}
 
 	for (i = 0; i < num; i++) {
-		memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE);
-		free(blocks[start + i]);
-		blocks[start + i] = NULL;
+		cur_block = start + i;
+		if (block_needs_encryption[cur_block]) {
+			enc_buf = f2fs_metadata_crypt_blocks(blocks[cur_block],
+							     F2FS_BLKSIZE,
+							     cur_block, true);
+			if (!enc_buf)
+				return -ENOMEM;
+
+			if (enc_buf != block[cur_block])
+				sparse_replace_block(cur_block, enc_buf);
+		}
+
+		memcpy(buf + i * F2FS_BLKSIZE, blocks[cur_block], F2FS_BLKSIZE);
+		sparse_replace_block(cur_block, NULL);
 	}
 
 	/* free_sparse_blocks will release this buf. */
@@ -495,9 +562,12 @@ static int sparse_merge_blocks(uint64_t start, uint64_t num, int zero)
 					F2FS_BLKSIZE * num, start);
 }
 #else
-static int sparse_read_blk(__u64 block, int count, void *buf) { return 0; }
-static int sparse_write_blk(__u64 block, int count, const void *buf) { return 0; }
-static int sparse_write_zeroed_blk(__u64 block, int count) { return 0; }
+static int sparse_read_blk(__u64 block, int count, void *buf,
+			   bool metadata_decrypt) { return 0; }
+static int sparse_write_blk(__u64 block, int count, const void *buf,
+			    bool metadata_encrypt) { return 0; }
+static int sparse_write_zeroed_blk(__u64 block, int count,
+				   bool metadata_encrypt) { return 0; }
 #endif
 
 static int __dev_read(void *buf, __u64 offset, size_t len, bool metadata_decrypt)
@@ -509,7 +579,8 @@ static int __dev_read(void *buf, __u64 offset, size_t len, bool metadata_decrypt
 
 	if (c.sparse_mode)
 		return sparse_read_blk(offset / F2FS_BLKSIZE,
-					len / F2FS_BLKSIZE, buf);
+					len / F2FS_BLKSIZE, buf,
+					metadata_decrypt);
 
 	fd = __get_device_fd(&offset);
 	if (fd < 0)
@@ -572,7 +643,8 @@ static int __dev_write(void *buf, __u64 offset, size_t len,
 
 	if (c.sparse_mode)
 		return sparse_write_blk(offset / F2FS_BLKSIZE,
-					len / F2FS_BLKSIZE, buf);
+					len / F2FS_BLKSIZE, buf,
+					metadata_encrypt);
 
 	fd = __get_device_fd(&offset);
 	if (fd < 0)
@@ -635,7 +707,8 @@ int dev_fill(void *buf, __u64 offset, size_t len)
 
 	if (c.sparse_mode)
 		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
-						len / F2FS_BLKSIZE);
+						len / F2FS_BLKSIZE,
+						true);
 
 	fd = __get_device_fd(&offset);
 	if (fd < 0)
@@ -725,6 +798,12 @@ int f2fs_init_sparse_file(void)
 		return -1;
 	}
 
+	block_needs_encryption = calloc(blocks_count, sizeof(bool));
+	if (!block_needs_encryption) {
+		MSG(0, "\tError: Calloc Failed for block encryption bookkeeping!!!\n");
+		return -1;
+	}
+
 	zeroed_block = calloc(1, F2FS_BLKSIZE);
 	if (!zeroed_block) {
 		MSG(0, "\tError: Calloc Failed for zeroed block!!!\n");
-- 
2.29.2.729.g45daf8777d-goog



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

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

* Re: [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support
  2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support Satya Tangirala via Linux-f2fs-devel
@ 2020-12-17 15:47   ` Satya Tangirala via Linux-f2fs-devel
  2020-12-18  1:06   ` Chao Yu
  1 sibling, 0 replies; 6+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-12-17 15:47 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers, Chao Yu; +Cc: linux-f2fs-devel

I still need to update configure.ac to check for the new libraries -
I'll do that in v3 of the patch series


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

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

* Re: [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support
  2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support Satya Tangirala via Linux-f2fs-devel
  2020-12-17 15:47   ` Satya Tangirala via Linux-f2fs-devel
@ 2020-12-18  1:06   ` Chao Yu
  2020-12-18  6:33     ` Satya Tangirala via Linux-f2fs-devel
  1 sibling, 1 reply; 6+ messages in thread
From: Chao Yu @ 2020-12-18  1:06 UTC (permalink / raw)
  To: Satya Tangirala, Jaegeuk Kim, Eric Biggers, Chao Yu; +Cc: linux-f2fs-devel

On 2020/12/17 23:10, Satya Tangirala via Linux-f2fs-devel wrote:
> Introduce native metadata encryption support for f2fs. All blocks
> other than the super block (and its redundant copy) are encrypted with the
> specified metadata encryption key and algorithm. The IV for each block is
> its block number in the filesystem.

The same question as kernel side patchset, for node block, why not using its
nid as IV value?

Thanks,


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

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

* Re: [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support
  2020-12-18  1:06   ` Chao Yu
@ 2020-12-18  6:33     ` Satya Tangirala via Linux-f2fs-devel
  0 siblings, 0 replies; 6+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-12-18  6:33 UTC (permalink / raw)
  To: Chao Yu; +Cc: Eric Biggers, Jaegeuk Kim, linux-f2fs-devel

On Fri, Dec 18, 2020 at 09:06:00AM +0800, Chao Yu wrote:
> On 2020/12/17 23:10, Satya Tangirala via Linux-f2fs-devel wrote:
> > Introduce native metadata encryption support for f2fs. All blocks
> > other than the super block (and its redundant copy) are encrypted with the
> > specified metadata encryption key and algorithm. The IV for each block is
> > its block number in the filesystem.
> 
> The same question as kernel side patchset, for node block, why not using its
> nid as IV value?
> 
I addressed this on the kernel side patchset too (because
the reason is kernel related) at
https://lore.kernel.org/linux-fscrypt/X9t8y3rElyAPCLoD@google.com/

But in summary, I think using nid as the IV value would have been good
if we had the ability to specify the IV for each data unit in a bio
independently of all the other data units in the bio. However, we can
only specify the DUN of the first data unit in each bio with the
bi_crypt_context, so it's better to make physically contiguous data
units also have contiguous DUNs, which won't be the case if the DUN is
not related to the physical block address (I'm not familiar with nids,
but it sounds like nids are independent of block address).

Does that make sense or is there something I'm missing?

> Thanks,


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

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

end of thread, other threads:[~2020-12-18  6:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-17 15:10 [f2fs-dev] [PATCH v2 0/2] userspace support for metadata encryption Satya Tangirala via Linux-f2fs-devel
2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 1/2] f2fs-tools: Introduce metadata encryption support Satya Tangirala via Linux-f2fs-devel
2020-12-17 15:47   ` Satya Tangirala via Linux-f2fs-devel
2020-12-18  1:06   ` Chao Yu
2020-12-18  6:33     ` Satya Tangirala via Linux-f2fs-devel
2020-12-17 15:10 ` [f2fs-dev] [PATCH v2 2/2] libf2fs_io: Make metadata encryption work with sparse mode Satya Tangirala via Linux-f2fs-devel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).