All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1] userspace support for F2FS metadata encryption
@ 2020-10-05  7:41 ` Satya Tangirala via Linux-f2fs-devel
  0 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala @ 2020-10-05  7:41 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers
  Cc: linux-f2fs-devel, linux-fscrypt, Satya Tangirala

The kernel patches for F2FS metadata encryption are at:

https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/

This patch 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.

This patch introduces two new options for the userspace tools: '-A' to
specify the encryption algorithm, and '-M' to specify the encryption key.
mkfs.f2fs will store the encryption algorithm used for metadata encryption
in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
of the tools only take the '-M' option, and will obtain the encryption
algorithm from the superblock of the FS.

Limitations: 
Metadata encryption with sparse storage has not been implemented yet in
this patch.

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.

Satya Tangirala (1):
  f2fs-tools: Introduce metadata encryption support

 fsck/main.c                   |  47 ++++++-
 fsck/mount.c                  |  33 ++++-
 include/f2fs_fs.h             |  10 +-
 include/f2fs_metadata_crypt.h |  21 ++++
 lib/Makefile.am               |   4 +-
 lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
 lib/libf2fs_io.c              |  87 +++++++++++--
 mkfs/f2fs_format.c            |   5 +-
 mkfs/f2fs_format_main.c       |  33 ++++-
 9 files changed, 446 insertions(+), 20 deletions(-)
 create mode 100644 include/f2fs_metadata_crypt.h
 create mode 100644 lib/f2fs_metadata_crypt.c

-- 
2.28.0.806.g8561365e88-goog


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

* [f2fs-dev] [PATCH 0/1] userspace support for F2FS metadata encryption
@ 2020-10-05  7:41 ` Satya Tangirala via Linux-f2fs-devel
  0 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-10-05  7:41 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers
  Cc: linux-fscrypt, Satya Tangirala, linux-f2fs-devel

The kernel patches for F2FS metadata encryption are at:

https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/

This patch 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.

This patch introduces two new options for the userspace tools: '-A' to
specify the encryption algorithm, and '-M' to specify the encryption key.
mkfs.f2fs will store the encryption algorithm used for metadata encryption
in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
of the tools only take the '-M' option, and will obtain the encryption
algorithm from the superblock of the FS.

Limitations: 
Metadata encryption with sparse storage has not been implemented yet in
this patch.

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.

Satya Tangirala (1):
  f2fs-tools: Introduce metadata encryption support

 fsck/main.c                   |  47 ++++++-
 fsck/mount.c                  |  33 ++++-
 include/f2fs_fs.h             |  10 +-
 include/f2fs_metadata_crypt.h |  21 ++++
 lib/Makefile.am               |   4 +-
 lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
 lib/libf2fs_io.c              |  87 +++++++++++--
 mkfs/f2fs_format.c            |   5 +-
 mkfs/f2fs_format_main.c       |  33 ++++-
 9 files changed, 446 insertions(+), 20 deletions(-)
 create mode 100644 include/f2fs_metadata_crypt.h
 create mode 100644 lib/f2fs_metadata_crypt.c

-- 
2.28.0.806.g8561365e88-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] 18+ messages in thread

* [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
  2020-10-05  7:41 ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
@ 2020-10-05  7:41   ` Satya Tangirala via Linux-f2fs-devel
  -1 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala @ 2020-10-05  7:41 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers
  Cc: linux-f2fs-devel, linux-fscrypt, Satya Tangirala

Introduce native metadata encryption support for F2FS. All blocks
other than the super block are encrypted with the specified metadata
encryption key and algorithm. The data unit number for each block is its
block number in the filesystem.

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

mkfs.f2fs takes both these arguments, and stores the encryption algorithm
in the superblock of the FS.

The rest of the programs only take '-M', and use the encryption algorithm
stored in the superblock of the FS.

Signed-off-by: Satya Tangirala <satyat@google.com>
---
 fsck/main.c                   |  47 ++++++-
 fsck/mount.c                  |  33 ++++-
 include/f2fs_fs.h             |  10 +-
 include/f2fs_metadata_crypt.h |  21 ++++
 lib/Makefile.am               |   4 +-
 lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
 lib/libf2fs_io.c              |  87 +++++++++++--
 mkfs/f2fs_format.c            |   5 +-
 mkfs/f2fs_format_main.c       |  33 ++++-
 9 files changed, 446 insertions(+), 20 deletions(-)
 create mode 100644 include/f2fs_metadata_crypt.h
 create mode 100644 lib/f2fs_metadata_crypt.c

diff --git a/fsck/main.c b/fsck/main.c
index 32559f1..6a4d867 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
@@ -62,6 +64,7 @@ void fsck_usage()
 			" (default 0)\n");
 	MSG(0, "  -m <max-hash-collision>  set max cache hash collision"
 			" (default 16)\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -C encoding[:flag1,flag2] Set options for enabling"
 			" casefolding\n");
 	MSG(0, "  -d debug level [default:0]\n");
@@ -92,6 +95,7 @@ void dump_usage()
 	MSG(0, "  -S sparse_mode\n");
 	MSG(0, "  -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n");
 	MSG(0, "  -b blk_addr (in 4KB)\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -V print the version number and exit\n");
 
 	exit(1);
@@ -107,6 +111,7 @@ void defrag_usage()
 	MSG(0, "  -l length [default:512 (2MB)]\n");
 	MSG(0, "  -t target block address [default: main_blkaddr + 2MB]\n");
 	MSG(0, "  -i set direction as shrink [default: expand]\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -V print the version number and exit\n");
 	exit(1);
 }
@@ -119,6 +124,7 @@ void resize_usage()
 	MSG(0, "  -i extended node bitmap, node ratio is 20%% by default\n");
 	MSG(0, "  -s safe resize (Does not resize metadata)");
 	MSG(0, "  -t target sectors [default: device size]\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -V print the version number and exit\n");
 	exit(1);
 }
@@ -129,6 +135,7 @@ void sload_usage()
 	MSG(0, "[options]:\n");
 	MSG(0, "  -C fs_config\n");
 	MSG(0, "  -f source directory [path of the source directory]\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -p product out directory\n");
 	MSG(0, "  -s file_contexts\n");
 	MSG(0, "  -S sparse_mode\n");
@@ -200,7 +207,7 @@ void f2fs_parse_options(int argc, char *argv[])
 	}
 
 	if (!strcmp("fsck.f2fs", prog)) {
-		const char *option_string = ":aC:c:m:d:fg:O:p:q:StyV";
+		const char *option_string = ":aC:c:m:M:d:fg:O:p:q:StyV";
 		int opt = 0, val;
 		char *token;
 		struct option long_opt[] = {
@@ -243,6 +250,12 @@ void f2fs_parse_options(int argc, char *argv[])
 				c.cache_config.max_hash_collision =
 						atoi(optarg);
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					fsck_usage();
+				}
+				break;
 			case 'g':
 				if (!strcmp(optarg, "android"))
 					c.defset = CONF_ANDROID;
@@ -345,7 +358,7 @@ void f2fs_parse_options(int argc, char *argv[])
 				break;
 		}
 	} else if (!strcmp("dump.f2fs", prog)) {
-		const char *option_string = "d:i:n:s:Sa:b:V";
+		const char *option_string = "d:i:n:s:Sa:b:M:V";
 		static struct dump_option dump_opt = {
 			.nid = 0,	/* default root ino */
 			.start_nat = -1,
@@ -413,6 +426,12 @@ void f2fs_parse_options(int argc, char *argv[])
 					ret = sscanf(optarg, "%x",
 							&dump_opt.blk_addr);
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					dump_usage();
+				}
+				break;
 			case 'V':
 				show_version(prog);
 				exit(0);
@@ -427,7 +446,7 @@ void f2fs_parse_options(int argc, char *argv[])
 
 		c.private = &dump_opt;
 	} else if (!strcmp("defrag.f2fs", prog)) {
-		const char *option_string = "d:s:Sl:t:iV";
+		const char *option_string = "d:M:s:Sl:t:iV";
 
 		c.func = DEFRAG;
 		while ((option = getopt(argc, argv, option_string)) != EOF) {
@@ -473,6 +492,12 @@ void f2fs_parse_options(int argc, char *argv[])
 			case 'i':
 				c.defrag_shrink = 1;
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					defrag_usage();
+				}
+				break;
 			case 'V':
 				show_version(prog);
 				exit(0);
@@ -485,7 +510,7 @@ void f2fs_parse_options(int argc, char *argv[])
 				break;
 		}
 	} else if (!strcmp("resize.f2fs", prog)) {
-		const char *option_string = "d:st:iV";
+		const char *option_string = "d:M:st:iV";
 
 		c.func = RESIZE;
 		while ((option = getopt(argc, argv, option_string)) != EOF) {
@@ -515,6 +540,12 @@ void f2fs_parse_options(int argc, char *argv[])
 			case 'i':
 				c.large_nat_bitmap = 1;
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					resize_usage();
+				}
+				break;
 			case 'V':
 				show_version(prog);
 				exit(0);
@@ -527,7 +558,7 @@ void f2fs_parse_options(int argc, char *argv[])
 				break;
 		}
 	} else if (!strcmp("sload.f2fs", prog)) {
-		const char *option_string = "C:d:f:p:s:St:T:V";
+		const char *option_string = "C:d:f:M:p:s:St:T:V";
 #ifdef HAVE_LIBSELINUX
 		int max_nr_opt = (int)sizeof(c.seopt_file) /
 			sizeof(c.seopt_file[0]);
@@ -553,6 +584,12 @@ void f2fs_parse_options(int argc, char *argv[])
 			case 'f':
 				c.from_dir = absolute_path(optarg);
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					sload_usage();
+				}
+				break;
 			case 'p':
 				c.target_out_dir = absolute_path(optarg);
 				break;
diff --git a/fsck/mount.c b/fsck/mount.c
index 8ebc5b0..7520a8a 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,6 +562,10 @@ void print_sb_state(struct f2fs_super_block *sb)
 	if (f & cpu_to_le32(F2FS_FEATURE_COMPRESSION)) {
 		MSG(0, "%s", " compression");
 	}
+	if (sb->metadata_crypt_alg) {
+		MSG(0, "%s", " metadata_crypt");
+	}
+
 	MSG(0, "\n");
 	MSG(0, "Info: superblock encrypt level = %d, salt = ",
 					sb->encryption_level);
@@ -686,7 +691,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_unencrypted(buf, addr);
 			ASSERT(ret >= 0);
 		}
 	}
@@ -927,6 +932,24 @@ int sanity_check_raw_super(struct f2fs_super_block *sb, enum SB_ADDR sb_addr)
 		return -1;
 	}
 
+	/*
+	 * Check that metadata encryption is enabled on superblock when metadata
+	 * crypt key is specified
+	 */
+	if (get_sb(metadata_crypt_alg) && !c.metadata_crypt_key) {
+		MSG(0, "\tFilesystem has metadata encryption, but we're missing the metadata encryption key.\n");
+		return -1;
+	}
+
+	/*
+	 * Check that metadata encryption is disabled on superblock when metadata
+	 * crypt key is not specified
+	 */
+	if (!get_sb(metadata_crypt_alg) && c.metadata_crypt_key) {
+		MSG(0, "\tFilesystem has does not have metadata encryption, but a metadata encryption key was specified.\n");
+		return -1;
+	}
+
 	if (sanity_check_area_boundary(sb, sb_addr))
 		return -1;
 	return 0;
@@ -940,7 +963,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_unencrypted(buf, sb_addr))
 		return -1;
 
 	memcpy(sbi->raw_super, buf + F2FS_SUPER_OFFSET,
@@ -3499,6 +3522,12 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
 	}
 	sb = F2FS_RAW_SUPER(sbi);
 
+	/* Get metadata encryption algorithm */
+	c.metadata_crypt_alg = get_sb(metadata_crypt_alg);
+
+	if (f2fs_metadata_verify_args())
+		exit(1);
+
 	ret = check_sector_size(sb);
 	if (ret)
 		return -1;
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index b5bda13..6b1912d 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -441,6 +441,11 @@ struct f2fs_configuration {
 
 	/* cache parameters */
 	dev_cache_config_t cache_config;
+
+	/* metadata encryption */
+	__u8 *metadata_crypt_key;
+	int metadata_crypt_key_len;
+	int metadata_crypt_alg;
 };
 
 #ifdef CONFIG_64BIT
@@ -675,7 +680,8 @@ 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 */
+	__le32	metadata_crypt_alg;	/* The metadata encryption algorithm (FSCRYPT_MODE_*) */
+	__u8 reserved[302];		/* valid reserved region */
 	__le32 crc;			/* checksum of superblock */
 } __attribute__((packed));
 
@@ -1237,12 +1243,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_unencrypted(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_unencrypted(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..d15873d
--- /dev/null
+++ b/include/f2fs_metadata_crypt.h
@@ -0,0 +1,21 @@
+/**
+ * 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>
+
+int f2fs_get_crypt_alg(const char *optarg);
+
+void f2fs_print_crypt_algs(void);
+
+int f2fs_metadata_process_key(const char *key_serial);
+
+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..a82d753 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 -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..faf399a
--- /dev/null
+++ b/lib/f2fs_metadata_crypt.c
@@ -0,0 +1,226 @@
+/**
+ * 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 <keyutils.h>
+
+#include "f2fs_fs.h"
+#include "f2fs_metadata_crypt.h"
+
+extern struct f2fs_configuration c;
+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 <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
+		if (f2fs_crypt_modes[i].friendly_name &&
+		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+int f2fs_metadata_process_key(const char *key_serial_str)
+{
+	key_serial_t key_serial = strtol(key_serial_str, NULL, 10);
+
+	c.metadata_crypt_key_len =
+		keyctl_read_alloc(key_serial, (void **)&c.metadata_crypt_key);
+
+	if (c.metadata_crypt_key_len < 0)
+		return errno;
+
+	return 0;
+}
+
+int f2fs_metadata_verify_args(void)
+{
+	/* 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_key_len !=
+	    f2fs_crypt_modes[c.metadata_crypt_alg].keysize) {
+		MSG(0, "\tMetadata encryption key length %d didn't match required size %d\n",
+		    c.metadata_crypt_key_len,
+		    f2fs_crypt_modes[c.metadata_crypt_alg].keysize);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void f2fs_metadata_crypt_gen_iv(struct af_alg_iv *iv, __u64 blk_addr)
+{
+	int i = 0;
+
+	memset(iv->iv, 0, iv->ivlen);
+
+	while (blk_addr > 0) {
+		iv->iv[i] = blk_addr & 0xFF;
+		blk_addr >>= 8;
+		i++;
+	}
+}
+
+int f2fs_metadata_crypt_block(void *buf, size_t len, __u64 blk_addr,
+			      bool encrypt)
+{
+	struct f2fs_crypt_mode *crypt_mode;
+	int sockfd, fd;
+	struct sockaddr_alg sa = {
+		.salg_family = AF_ALG,
+		.salg_type = "skcipher",
+	};
+	struct msghdr msg = {};
+	struct cmsghdr *cmsg;
+	char cbuf[CMSG_SPACE(4) + CMSG_SPACE(4 + MAX_IV_LEN)] = {0};
+	int blk_offset;
+	struct af_alg_iv *iv;
+	struct iovec iov;
+	int err;
+
+	crypt_mode = &f2fs_crypt_modes[c.metadata_crypt_alg];
+	memcpy(sa.salg_name, crypt_mode->cipher_str,
+	       strlen(crypt_mode->cipher_str));
+
+	sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+	if (sockfd < 0)
+		return errno;
+	err = bind(sockfd, (struct sockaddr *)&sa, sizeof(sa));
+	if (err) {
+		MSG(0, "\tCouldn't bind crypto socket. Maybe support for the crypto algorithm isn't enabled?\n");
+		close(sockfd);
+		return errno;
+	}
+	err = setsockopt(sockfd, SOL_ALG, ALG_SET_KEY, c.metadata_crypt_key,
+			 crypt_mode->keysize);
+	if (err) {
+		MSG(0, "\tCouldn't set crypto socket options.\n");
+		close(sockfd);
+		return errno;
+	}
+	fd = accept(sockfd, NULL, 0);
+	if (fd < 0)
+		goto err_out;
+
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof(cbuf);
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level = SOL_ALG;
+	cmsg->cmsg_type = ALG_SET_OP;
+	cmsg->cmsg_len = CMSG_LEN(4);
+	*(__u32 *)CMSG_DATA(cmsg) = encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+
+	cmsg = CMSG_NXTHDR(&msg, cmsg);
+	cmsg->cmsg_level = SOL_ALG;
+	cmsg->cmsg_type = ALG_SET_IV;
+	cmsg->cmsg_len = CMSG_LEN(4 + MAX_IV_LEN);
+	iv = (void *)CMSG_DATA(cmsg);
+	iv->ivlen = crypt_mode->ivlen;
+
+	iov.iov_len = F2FS_BLKSIZE;
+
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	for (blk_offset = 0; blk_offset < len / F2FS_BLKSIZE; blk_offset++) {
+		f2fs_metadata_crypt_gen_iv(iv, blk_addr + blk_offset);
+
+		iov.iov_base = (char *)buf + blk_offset * F2FS_BLKSIZE;
+
+		err = sendmsg(fd, &msg, 0);
+		if (err < 0)
+			goto err_out;
+		err = read(fd, (char *)buf + blk_offset * F2FS_BLKSIZE,
+			   F2FS_BLKSIZE);
+		if (err < 0)
+			goto err_out;
+	}
+
+	close(fd);
+	close(sockfd);
+
+	return 0;
+
+err_out:
+	err = errno;
+	close(fd);
+	close(sockfd);
+
+	return err;
+}
+
+void *f2fs_metadata_crypt_blocks(void *buf, size_t len, __u64 blk_addr,
+	bool encrypt)
+{
+	int err = 0;
+	void *enc_buf;
+
+	if (!c.metadata_crypt_key)
+		return buf;
+
+	enc_buf = malloc(len);
+	memcpy(enc_buf, buf, len);
+
+	err = f2fs_metadata_crypt_block(enc_buf, len, blk_addr, encrypt);
+	if (err) {
+		MSG(0, "\tFailed to en/decrypt blocks. Errno %d\n", err);
+		free(enc_buf);
+		return NULL;
+	}
+
+	return enc_buf;
+}
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 138285d..f117e1e 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)
+int __dev_read(void *buf, __u64 offset, size_t len, bool unencrypted)
 {
 	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,29 @@ int dev_read(void *buf, __u64 offset, size_t len)
 		return -1;
 	if (read(fd, buf, len) < 0)
 		return -1;
+	if (!unencrypted) {
+		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, false);
+}
+
+int dev_read_unencrypted(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,13 +564,17 @@ int dev_readahead(__u64 offset, size_t UNUSED(len))
 #endif
 }
 
-int dev_write(void *buf, __u64 offset, size_t len)
+int __dev_write(void *buf, __u64 offset, size_t len, bool unencrypted)
 {
 	int fd;
+	__u64 blk_addr = offset >> F2FS_BLKSIZE_BITS;
+	void *src_buf = buf;
+	int err = -1;
 
 	if (c.dry_run)
 		return 0;
 
+	/* TODO: handle sparse mode with metadata encryption */
 	if (c.sparse_mode)
 		return sparse_write_blk(offset / F2FS_BLKSIZE,
 					len / F2FS_BLKSIZE, buf);
@@ -562,11 +589,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 (!unencrypted) {
+		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, false);
 }
 
 int dev_write_block(void *buf, __u64 blk_addr)
@@ -574,6 +616,16 @@ int dev_write_block(void *buf, __u64 blk_addr)
 	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
 }
 
+static int dev_write_unencrypted(void *buf, __u64 offset, size_t len)
+{
+	return __dev_write(buf, offset, len, true);
+}
+
+int dev_write_block_unencrypted(void *buf, __u64 blk_addr)
+{
+	return dev_write_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
+}
+
 int dev_write_dump(void *buf, __u64 offset, size_t len)
 {
 	if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
@@ -586,7 +638,11 @@ 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;
 
+	/* TODO: handle sparse mode with metadata encryption */
 	if (c.sparse_mode)
 		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
 						len / F2FS_BLKSIZE);
@@ -598,11 +654,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 +681,11 @@ int dev_read_block(void *buf, __u64 blk_addr)
 	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
 }
 
+int dev_read_block_unencrypted(void *buf, __u64 blk_addr)
+{
+	return dev_read_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
+}
+
 int dev_reada_block(__u64 blk_addr)
 {
 	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index a6c542e..bf587bf 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -537,6 +537,9 @@ 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);
+
 	sb->feature = c.feature;
 
 	if (get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) {
@@ -1046,7 +1049,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_unencrypted(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..8856850 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");
@@ -97,6 +100,12 @@ 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_key)
+		MSG(0, "Info: Metadata key is %s\n", c.metadata_crypt_key);
+
+	if (c.metadata_crypt_alg)
+		MSG(0, "Info: Metadata alg is %d\n", c.metadata_crypt_alg);
 }
 
 static void add_default_options(void)
@@ -125,7 +134,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 +147,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 +195,12 @@ static void f2fs_parse_options(int argc, char *argv[])
 		case 'm':
 			c.zoned_mode = 1;
 			break;
+		case 'M':
+			if (f2fs_metadata_process_key(optarg)) {
+				MSG(0, "Error: Invalid metadata key\n");
+				mkfs_usage();
+			}
+			break;
 		case 'o':
 			c.overprovision = atof(optarg);
 			break;
@@ -244,6 +267,14 @@ static void f2fs_parse_options(int argc, char *argv[])
 		}
 	}
 
+	if ((!!c.metadata_crypt_key) != (!!c.metadata_crypt_alg)) {
+		MSG(0, "\tError: Both the metadata crypt key and crypt algorithm must be specified!");
+		exit(1);
+	}
+
+	if (f2fs_metadata_verify_args())
+		exit(1);
+
 	add_default_options();
 
 	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
-- 
2.28.0.806.g8561365e88-goog


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

* [f2fs-dev] [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
@ 2020-10-05  7:41   ` Satya Tangirala via Linux-f2fs-devel
  0 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-10-05  7:41 UTC (permalink / raw)
  To: Jaegeuk Kim, Eric Biggers
  Cc: linux-fscrypt, Satya Tangirala, linux-f2fs-devel

Introduce native metadata encryption support for F2FS. All blocks
other than the super block are encrypted with the specified metadata
encryption key and algorithm. The data unit number for each block is its
block number in the filesystem.

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

mkfs.f2fs takes both these arguments, and stores the encryption algorithm
in the superblock of the FS.

The rest of the programs only take '-M', and use the encryption algorithm
stored in the superblock of the FS.

Signed-off-by: Satya Tangirala <satyat@google.com>
---
 fsck/main.c                   |  47 ++++++-
 fsck/mount.c                  |  33 ++++-
 include/f2fs_fs.h             |  10 +-
 include/f2fs_metadata_crypt.h |  21 ++++
 lib/Makefile.am               |   4 +-
 lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
 lib/libf2fs_io.c              |  87 +++++++++++--
 mkfs/f2fs_format.c            |   5 +-
 mkfs/f2fs_format_main.c       |  33 ++++-
 9 files changed, 446 insertions(+), 20 deletions(-)
 create mode 100644 include/f2fs_metadata_crypt.h
 create mode 100644 lib/f2fs_metadata_crypt.c

diff --git a/fsck/main.c b/fsck/main.c
index 32559f1..6a4d867 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
@@ -62,6 +64,7 @@ void fsck_usage()
 			" (default 0)\n");
 	MSG(0, "  -m <max-hash-collision>  set max cache hash collision"
 			" (default 16)\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -C encoding[:flag1,flag2] Set options for enabling"
 			" casefolding\n");
 	MSG(0, "  -d debug level [default:0]\n");
@@ -92,6 +95,7 @@ void dump_usage()
 	MSG(0, "  -S sparse_mode\n");
 	MSG(0, "  -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n");
 	MSG(0, "  -b blk_addr (in 4KB)\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -V print the version number and exit\n");
 
 	exit(1);
@@ -107,6 +111,7 @@ void defrag_usage()
 	MSG(0, "  -l length [default:512 (2MB)]\n");
 	MSG(0, "  -t target block address [default: main_blkaddr + 2MB]\n");
 	MSG(0, "  -i set direction as shrink [default: expand]\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -V print the version number and exit\n");
 	exit(1);
 }
@@ -119,6 +124,7 @@ void resize_usage()
 	MSG(0, "  -i extended node bitmap, node ratio is 20%% by default\n");
 	MSG(0, "  -s safe resize (Does not resize metadata)");
 	MSG(0, "  -t target sectors [default: device size]\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -V print the version number and exit\n");
 	exit(1);
 }
@@ -129,6 +135,7 @@ void sload_usage()
 	MSG(0, "[options]:\n");
 	MSG(0, "  -C fs_config\n");
 	MSG(0, "  -f source directory [path of the source directory]\n");
+	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
 	MSG(0, "  -p product out directory\n");
 	MSG(0, "  -s file_contexts\n");
 	MSG(0, "  -S sparse_mode\n");
@@ -200,7 +207,7 @@ void f2fs_parse_options(int argc, char *argv[])
 	}
 
 	if (!strcmp("fsck.f2fs", prog)) {
-		const char *option_string = ":aC:c:m:d:fg:O:p:q:StyV";
+		const char *option_string = ":aC:c:m:M:d:fg:O:p:q:StyV";
 		int opt = 0, val;
 		char *token;
 		struct option long_opt[] = {
@@ -243,6 +250,12 @@ void f2fs_parse_options(int argc, char *argv[])
 				c.cache_config.max_hash_collision =
 						atoi(optarg);
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					fsck_usage();
+				}
+				break;
 			case 'g':
 				if (!strcmp(optarg, "android"))
 					c.defset = CONF_ANDROID;
@@ -345,7 +358,7 @@ void f2fs_parse_options(int argc, char *argv[])
 				break;
 		}
 	} else if (!strcmp("dump.f2fs", prog)) {
-		const char *option_string = "d:i:n:s:Sa:b:V";
+		const char *option_string = "d:i:n:s:Sa:b:M:V";
 		static struct dump_option dump_opt = {
 			.nid = 0,	/* default root ino */
 			.start_nat = -1,
@@ -413,6 +426,12 @@ void f2fs_parse_options(int argc, char *argv[])
 					ret = sscanf(optarg, "%x",
 							&dump_opt.blk_addr);
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					dump_usage();
+				}
+				break;
 			case 'V':
 				show_version(prog);
 				exit(0);
@@ -427,7 +446,7 @@ void f2fs_parse_options(int argc, char *argv[])
 
 		c.private = &dump_opt;
 	} else if (!strcmp("defrag.f2fs", prog)) {
-		const char *option_string = "d:s:Sl:t:iV";
+		const char *option_string = "d:M:s:Sl:t:iV";
 
 		c.func = DEFRAG;
 		while ((option = getopt(argc, argv, option_string)) != EOF) {
@@ -473,6 +492,12 @@ void f2fs_parse_options(int argc, char *argv[])
 			case 'i':
 				c.defrag_shrink = 1;
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					defrag_usage();
+				}
+				break;
 			case 'V':
 				show_version(prog);
 				exit(0);
@@ -485,7 +510,7 @@ void f2fs_parse_options(int argc, char *argv[])
 				break;
 		}
 	} else if (!strcmp("resize.f2fs", prog)) {
-		const char *option_string = "d:st:iV";
+		const char *option_string = "d:M:st:iV";
 
 		c.func = RESIZE;
 		while ((option = getopt(argc, argv, option_string)) != EOF) {
@@ -515,6 +540,12 @@ void f2fs_parse_options(int argc, char *argv[])
 			case 'i':
 				c.large_nat_bitmap = 1;
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					resize_usage();
+				}
+				break;
 			case 'V':
 				show_version(prog);
 				exit(0);
@@ -527,7 +558,7 @@ void f2fs_parse_options(int argc, char *argv[])
 				break;
 		}
 	} else if (!strcmp("sload.f2fs", prog)) {
-		const char *option_string = "C:d:f:p:s:St:T:V";
+		const char *option_string = "C:d:f:M:p:s:St:T:V";
 #ifdef HAVE_LIBSELINUX
 		int max_nr_opt = (int)sizeof(c.seopt_file) /
 			sizeof(c.seopt_file[0]);
@@ -553,6 +584,12 @@ void f2fs_parse_options(int argc, char *argv[])
 			case 'f':
 				c.from_dir = absolute_path(optarg);
 				break;
+			case 'M':
+				if (f2fs_metadata_process_key(optarg)) {
+					MSG(0, "Error: Invalid metadata key\n");
+					sload_usage();
+				}
+				break;
 			case 'p':
 				c.target_out_dir = absolute_path(optarg);
 				break;
diff --git a/fsck/mount.c b/fsck/mount.c
index 8ebc5b0..7520a8a 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,6 +562,10 @@ void print_sb_state(struct f2fs_super_block *sb)
 	if (f & cpu_to_le32(F2FS_FEATURE_COMPRESSION)) {
 		MSG(0, "%s", " compression");
 	}
+	if (sb->metadata_crypt_alg) {
+		MSG(0, "%s", " metadata_crypt");
+	}
+
 	MSG(0, "\n");
 	MSG(0, "Info: superblock encrypt level = %d, salt = ",
 					sb->encryption_level);
@@ -686,7 +691,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_unencrypted(buf, addr);
 			ASSERT(ret >= 0);
 		}
 	}
@@ -927,6 +932,24 @@ int sanity_check_raw_super(struct f2fs_super_block *sb, enum SB_ADDR sb_addr)
 		return -1;
 	}
 
+	/*
+	 * Check that metadata encryption is enabled on superblock when metadata
+	 * crypt key is specified
+	 */
+	if (get_sb(metadata_crypt_alg) && !c.metadata_crypt_key) {
+		MSG(0, "\tFilesystem has metadata encryption, but we're missing the metadata encryption key.\n");
+		return -1;
+	}
+
+	/*
+	 * Check that metadata encryption is disabled on superblock when metadata
+	 * crypt key is not specified
+	 */
+	if (!get_sb(metadata_crypt_alg) && c.metadata_crypt_key) {
+		MSG(0, "\tFilesystem has does not have metadata encryption, but a metadata encryption key was specified.\n");
+		return -1;
+	}
+
 	if (sanity_check_area_boundary(sb, sb_addr))
 		return -1;
 	return 0;
@@ -940,7 +963,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_unencrypted(buf, sb_addr))
 		return -1;
 
 	memcpy(sbi->raw_super, buf + F2FS_SUPER_OFFSET,
@@ -3499,6 +3522,12 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
 	}
 	sb = F2FS_RAW_SUPER(sbi);
 
+	/* Get metadata encryption algorithm */
+	c.metadata_crypt_alg = get_sb(metadata_crypt_alg);
+
+	if (f2fs_metadata_verify_args())
+		exit(1);
+
 	ret = check_sector_size(sb);
 	if (ret)
 		return -1;
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index b5bda13..6b1912d 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -441,6 +441,11 @@ struct f2fs_configuration {
 
 	/* cache parameters */
 	dev_cache_config_t cache_config;
+
+	/* metadata encryption */
+	__u8 *metadata_crypt_key;
+	int metadata_crypt_key_len;
+	int metadata_crypt_alg;
 };
 
 #ifdef CONFIG_64BIT
@@ -675,7 +680,8 @@ 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 */
+	__le32	metadata_crypt_alg;	/* The metadata encryption algorithm (FSCRYPT_MODE_*) */
+	__u8 reserved[302];		/* valid reserved region */
 	__le32 crc;			/* checksum of superblock */
 } __attribute__((packed));
 
@@ -1237,12 +1243,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_unencrypted(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_unencrypted(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..d15873d
--- /dev/null
+++ b/include/f2fs_metadata_crypt.h
@@ -0,0 +1,21 @@
+/**
+ * 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>
+
+int f2fs_get_crypt_alg(const char *optarg);
+
+void f2fs_print_crypt_algs(void);
+
+int f2fs_metadata_process_key(const char *key_serial);
+
+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..a82d753 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 -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..faf399a
--- /dev/null
+++ b/lib/f2fs_metadata_crypt.c
@@ -0,0 +1,226 @@
+/**
+ * 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 <keyutils.h>
+
+#include "f2fs_fs.h"
+#include "f2fs_metadata_crypt.h"
+
+extern struct f2fs_configuration c;
+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 <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
+		if (f2fs_crypt_modes[i].friendly_name &&
+		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+int f2fs_metadata_process_key(const char *key_serial_str)
+{
+	key_serial_t key_serial = strtol(key_serial_str, NULL, 10);
+
+	c.metadata_crypt_key_len =
+		keyctl_read_alloc(key_serial, (void **)&c.metadata_crypt_key);
+
+	if (c.metadata_crypt_key_len < 0)
+		return errno;
+
+	return 0;
+}
+
+int f2fs_metadata_verify_args(void)
+{
+	/* 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_key_len !=
+	    f2fs_crypt_modes[c.metadata_crypt_alg].keysize) {
+		MSG(0, "\tMetadata encryption key length %d didn't match required size %d\n",
+		    c.metadata_crypt_key_len,
+		    f2fs_crypt_modes[c.metadata_crypt_alg].keysize);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void f2fs_metadata_crypt_gen_iv(struct af_alg_iv *iv, __u64 blk_addr)
+{
+	int i = 0;
+
+	memset(iv->iv, 0, iv->ivlen);
+
+	while (blk_addr > 0) {
+		iv->iv[i] = blk_addr & 0xFF;
+		blk_addr >>= 8;
+		i++;
+	}
+}
+
+int f2fs_metadata_crypt_block(void *buf, size_t len, __u64 blk_addr,
+			      bool encrypt)
+{
+	struct f2fs_crypt_mode *crypt_mode;
+	int sockfd, fd;
+	struct sockaddr_alg sa = {
+		.salg_family = AF_ALG,
+		.salg_type = "skcipher",
+	};
+	struct msghdr msg = {};
+	struct cmsghdr *cmsg;
+	char cbuf[CMSG_SPACE(4) + CMSG_SPACE(4 + MAX_IV_LEN)] = {0};
+	int blk_offset;
+	struct af_alg_iv *iv;
+	struct iovec iov;
+	int err;
+
+	crypt_mode = &f2fs_crypt_modes[c.metadata_crypt_alg];
+	memcpy(sa.salg_name, crypt_mode->cipher_str,
+	       strlen(crypt_mode->cipher_str));
+
+	sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+	if (sockfd < 0)
+		return errno;
+	err = bind(sockfd, (struct sockaddr *)&sa, sizeof(sa));
+	if (err) {
+		MSG(0, "\tCouldn't bind crypto socket. Maybe support for the crypto algorithm isn't enabled?\n");
+		close(sockfd);
+		return errno;
+	}
+	err = setsockopt(sockfd, SOL_ALG, ALG_SET_KEY, c.metadata_crypt_key,
+			 crypt_mode->keysize);
+	if (err) {
+		MSG(0, "\tCouldn't set crypto socket options.\n");
+		close(sockfd);
+		return errno;
+	}
+	fd = accept(sockfd, NULL, 0);
+	if (fd < 0)
+		goto err_out;
+
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof(cbuf);
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level = SOL_ALG;
+	cmsg->cmsg_type = ALG_SET_OP;
+	cmsg->cmsg_len = CMSG_LEN(4);
+	*(__u32 *)CMSG_DATA(cmsg) = encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+
+	cmsg = CMSG_NXTHDR(&msg, cmsg);
+	cmsg->cmsg_level = SOL_ALG;
+	cmsg->cmsg_type = ALG_SET_IV;
+	cmsg->cmsg_len = CMSG_LEN(4 + MAX_IV_LEN);
+	iv = (void *)CMSG_DATA(cmsg);
+	iv->ivlen = crypt_mode->ivlen;
+
+	iov.iov_len = F2FS_BLKSIZE;
+
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	for (blk_offset = 0; blk_offset < len / F2FS_BLKSIZE; blk_offset++) {
+		f2fs_metadata_crypt_gen_iv(iv, blk_addr + blk_offset);
+
+		iov.iov_base = (char *)buf + blk_offset * F2FS_BLKSIZE;
+
+		err = sendmsg(fd, &msg, 0);
+		if (err < 0)
+			goto err_out;
+		err = read(fd, (char *)buf + blk_offset * F2FS_BLKSIZE,
+			   F2FS_BLKSIZE);
+		if (err < 0)
+			goto err_out;
+	}
+
+	close(fd);
+	close(sockfd);
+
+	return 0;
+
+err_out:
+	err = errno;
+	close(fd);
+	close(sockfd);
+
+	return err;
+}
+
+void *f2fs_metadata_crypt_blocks(void *buf, size_t len, __u64 blk_addr,
+	bool encrypt)
+{
+	int err = 0;
+	void *enc_buf;
+
+	if (!c.metadata_crypt_key)
+		return buf;
+
+	enc_buf = malloc(len);
+	memcpy(enc_buf, buf, len);
+
+	err = f2fs_metadata_crypt_block(enc_buf, len, blk_addr, encrypt);
+	if (err) {
+		MSG(0, "\tFailed to en/decrypt blocks. Errno %d\n", err);
+		free(enc_buf);
+		return NULL;
+	}
+
+	return enc_buf;
+}
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 138285d..f117e1e 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)
+int __dev_read(void *buf, __u64 offset, size_t len, bool unencrypted)
 {
 	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,29 @@ int dev_read(void *buf, __u64 offset, size_t len)
 		return -1;
 	if (read(fd, buf, len) < 0)
 		return -1;
+	if (!unencrypted) {
+		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, false);
+}
+
+int dev_read_unencrypted(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,13 +564,17 @@ int dev_readahead(__u64 offset, size_t UNUSED(len))
 #endif
 }
 
-int dev_write(void *buf, __u64 offset, size_t len)
+int __dev_write(void *buf, __u64 offset, size_t len, bool unencrypted)
 {
 	int fd;
+	__u64 blk_addr = offset >> F2FS_BLKSIZE_BITS;
+	void *src_buf = buf;
+	int err = -1;
 
 	if (c.dry_run)
 		return 0;
 
+	/* TODO: handle sparse mode with metadata encryption */
 	if (c.sparse_mode)
 		return sparse_write_blk(offset / F2FS_BLKSIZE,
 					len / F2FS_BLKSIZE, buf);
@@ -562,11 +589,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 (!unencrypted) {
+		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, false);
 }
 
 int dev_write_block(void *buf, __u64 blk_addr)
@@ -574,6 +616,16 @@ int dev_write_block(void *buf, __u64 blk_addr)
 	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
 }
 
+static int dev_write_unencrypted(void *buf, __u64 offset, size_t len)
+{
+	return __dev_write(buf, offset, len, true);
+}
+
+int dev_write_block_unencrypted(void *buf, __u64 blk_addr)
+{
+	return dev_write_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
+}
+
 int dev_write_dump(void *buf, __u64 offset, size_t len)
 {
 	if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
@@ -586,7 +638,11 @@ 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;
 
+	/* TODO: handle sparse mode with metadata encryption */
 	if (c.sparse_mode)
 		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
 						len / F2FS_BLKSIZE);
@@ -598,11 +654,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 +681,11 @@ int dev_read_block(void *buf, __u64 blk_addr)
 	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
 }
 
+int dev_read_block_unencrypted(void *buf, __u64 blk_addr)
+{
+	return dev_read_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
+}
+
 int dev_reada_block(__u64 blk_addr)
 {
 	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index a6c542e..bf587bf 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -537,6 +537,9 @@ 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);
+
 	sb->feature = c.feature;
 
 	if (get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) {
@@ -1046,7 +1049,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_unencrypted(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..8856850 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");
@@ -97,6 +100,12 @@ 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_key)
+		MSG(0, "Info: Metadata key is %s\n", c.metadata_crypt_key);
+
+	if (c.metadata_crypt_alg)
+		MSG(0, "Info: Metadata alg is %d\n", c.metadata_crypt_alg);
 }
 
 static void add_default_options(void)
@@ -125,7 +134,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 +147,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 +195,12 @@ static void f2fs_parse_options(int argc, char *argv[])
 		case 'm':
 			c.zoned_mode = 1;
 			break;
+		case 'M':
+			if (f2fs_metadata_process_key(optarg)) {
+				MSG(0, "Error: Invalid metadata key\n");
+				mkfs_usage();
+			}
+			break;
 		case 'o':
 			c.overprovision = atof(optarg);
 			break;
@@ -244,6 +267,14 @@ static void f2fs_parse_options(int argc, char *argv[])
 		}
 	}
 
+	if ((!!c.metadata_crypt_key) != (!!c.metadata_crypt_alg)) {
+		MSG(0, "\tError: Both the metadata crypt key and crypt algorithm must be specified!");
+		exit(1);
+	}
+
+	if (f2fs_metadata_verify_args())
+		exit(1);
+
 	add_default_options();
 
 	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
-- 
2.28.0.806.g8561365e88-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] 18+ messages in thread

* Re: [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
  2020-10-05  7:41   ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
@ 2020-10-07 19:42     ` jaegeuk
  -1 siblings, 0 replies; 18+ messages in thread
From: jaegeuk @ 2020-10-07 19:42 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Eric Biggers, linux-f2fs-devel, linux-fscrypt

Hi Satya,

On 10/05, Satya Tangirala wrote:
> Introduce native metadata encryption support for F2FS. All blocks
> other than the super block are encrypted with the specified metadata
> encryption key and algorithm. The data unit number for each block is its
> block number in the filesystem.
> 
> This patch introduces two new options '-A' and '-M' for specifying metadata
> crypt options. '-A' takes the desired metadata encryption algorithm as
> argument. '-M' takes the linux key_serial of the metadata encryption key as
> the argument. The keyring key provided must be of a key type that supports
> reading the payload from userspace.

Could you please update manpages as well?

> 
> mkfs.f2fs takes both these arguments, and stores the encryption algorithm
> in the superblock of the FS.
> 
> The rest of the programs only take '-M', and use the encryption algorithm
> stored in the superblock of the FS.
> 
> Signed-off-by: Satya Tangirala <satyat@google.com>
> ---
>  fsck/main.c                   |  47 ++++++-
>  fsck/mount.c                  |  33 ++++-
>  include/f2fs_fs.h             |  10 +-
>  include/f2fs_metadata_crypt.h |  21 ++++
>  lib/Makefile.am               |   4 +-
>  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
>  lib/libf2fs_io.c              |  87 +++++++++++--
>  mkfs/f2fs_format.c            |   5 +-
>  mkfs/f2fs_format_main.c       |  33 ++++-
>  9 files changed, 446 insertions(+), 20 deletions(-)
>  create mode 100644 include/f2fs_metadata_crypt.h
>  create mode 100644 lib/f2fs_metadata_crypt.c
> 
> diff --git a/fsck/main.c b/fsck/main.c
> index 32559f1..6a4d867 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
> @@ -62,6 +64,7 @@ void fsck_usage()
>  			" (default 0)\n");
>  	MSG(0, "  -m <max-hash-collision>  set max cache hash collision"
>  			" (default 16)\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -C encoding[:flag1,flag2] Set options for enabling"
>  			" casefolding\n");
>  	MSG(0, "  -d debug level [default:0]\n");
> @@ -92,6 +95,7 @@ void dump_usage()
>  	MSG(0, "  -S sparse_mode\n");
>  	MSG(0, "  -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n");
>  	MSG(0, "  -b blk_addr (in 4KB)\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -V print the version number and exit\n");
>  
>  	exit(1);
> @@ -107,6 +111,7 @@ void defrag_usage()
>  	MSG(0, "  -l length [default:512 (2MB)]\n");
>  	MSG(0, "  -t target block address [default: main_blkaddr + 2MB]\n");
>  	MSG(0, "  -i set direction as shrink [default: expand]\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -V print the version number and exit\n");
>  	exit(1);
>  }
> @@ -119,6 +124,7 @@ void resize_usage()
>  	MSG(0, "  -i extended node bitmap, node ratio is 20%% by default\n");
>  	MSG(0, "  -s safe resize (Does not resize metadata)");
>  	MSG(0, "  -t target sectors [default: device size]\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -V print the version number and exit\n");
>  	exit(1);
>  }
> @@ -129,6 +135,7 @@ void sload_usage()
>  	MSG(0, "[options]:\n");
>  	MSG(0, "  -C fs_config\n");
>  	MSG(0, "  -f source directory [path of the source directory]\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -p product out directory\n");
>  	MSG(0, "  -s file_contexts\n");
>  	MSG(0, "  -S sparse_mode\n");
> @@ -200,7 +207,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  	}
>  
>  	if (!strcmp("fsck.f2fs", prog)) {
> -		const char *option_string = ":aC:c:m:d:fg:O:p:q:StyV";
> +		const char *option_string = ":aC:c:m:M:d:fg:O:p:q:StyV";
>  		int opt = 0, val;
>  		char *token;
>  		struct option long_opt[] = {
> @@ -243,6 +250,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  				c.cache_config.max_hash_collision =
>  						atoi(optarg);
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					fsck_usage();
> +				}
> +				break;
>  			case 'g':
>  				if (!strcmp(optarg, "android"))
>  					c.defset = CONF_ANDROID;
> @@ -345,7 +358,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  				break;
>  		}
>  	} else if (!strcmp("dump.f2fs", prog)) {
> -		const char *option_string = "d:i:n:s:Sa:b:V";
> +		const char *option_string = "d:i:n:s:Sa:b:M:V";
>  		static struct dump_option dump_opt = {
>  			.nid = 0,	/* default root ino */
>  			.start_nat = -1,
> @@ -413,6 +426,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  					ret = sscanf(optarg, "%x",
>  							&dump_opt.blk_addr);
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					dump_usage();
> +				}
> +				break;
>  			case 'V':
>  				show_version(prog);
>  				exit(0);
> @@ -427,7 +446,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  
>  		c.private = &dump_opt;
>  	} else if (!strcmp("defrag.f2fs", prog)) {
> -		const char *option_string = "d:s:Sl:t:iV";
> +		const char *option_string = "d:M:s:Sl:t:iV";
>  
>  		c.func = DEFRAG;
>  		while ((option = getopt(argc, argv, option_string)) != EOF) {
> @@ -473,6 +492,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  			case 'i':
>  				c.defrag_shrink = 1;
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					defrag_usage();
> +				}
> +				break;
>  			case 'V':
>  				show_version(prog);
>  				exit(0);
> @@ -485,7 +510,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  				break;
>  		}
>  	} else if (!strcmp("resize.f2fs", prog)) {
> -		const char *option_string = "d:st:iV";
> +		const char *option_string = "d:M:st:iV";
>  
>  		c.func = RESIZE;
>  		while ((option = getopt(argc, argv, option_string)) != EOF) {
> @@ -515,6 +540,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  			case 'i':
>  				c.large_nat_bitmap = 1;
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					resize_usage();
> +				}
> +				break;
>  			case 'V':
>  				show_version(prog);
>  				exit(0);
> @@ -527,7 +558,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  				break;
>  		}
>  	} else if (!strcmp("sload.f2fs", prog)) {
> -		const char *option_string = "C:d:f:p:s:St:T:V";
> +		const char *option_string = "C:d:f:M:p:s:St:T:V";
>  #ifdef HAVE_LIBSELINUX
>  		int max_nr_opt = (int)sizeof(c.seopt_file) /
>  			sizeof(c.seopt_file[0]);
> @@ -553,6 +584,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  			case 'f':
>  				c.from_dir = absolute_path(optarg);
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					sload_usage();
> +				}
> +				break;
>  			case 'p':
>  				c.target_out_dir = absolute_path(optarg);
>  				break;
> diff --git a/fsck/mount.c b/fsck/mount.c
> index 8ebc5b0..7520a8a 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,6 +562,10 @@ void print_sb_state(struct f2fs_super_block *sb)
>  	if (f & cpu_to_le32(F2FS_FEATURE_COMPRESSION)) {
>  		MSG(0, "%s", " compression");
>  	}
> +	if (sb->metadata_crypt_alg) {
> +		MSG(0, "%s", " metadata_crypt");
> +	}
> +
>  	MSG(0, "\n");
>  	MSG(0, "Info: superblock encrypt level = %d, salt = ",
>  					sb->encryption_level);
> @@ -686,7 +691,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_unencrypted(buf, addr);
>  			ASSERT(ret >= 0);
>  		}
>  	}
> @@ -927,6 +932,24 @@ int sanity_check_raw_super(struct f2fs_super_block *sb, enum SB_ADDR sb_addr)
>  		return -1;
>  	}
>  
> +	/*
> +	 * Check that metadata encryption is enabled on superblock when metadata
> +	 * crypt key is specified
> +	 */
> +	if (get_sb(metadata_crypt_alg) && !c.metadata_crypt_key) {
> +		MSG(0, "\tFilesystem has metadata encryption, but we're missing the metadata encryption key.\n");
> +		return -1;
> +	}
> +
> +	/*
> +	 * Check that metadata encryption is disabled on superblock when metadata
> +	 * crypt key is not specified
> +	 */
> +	if (!get_sb(metadata_crypt_alg) && c.metadata_crypt_key) {
> +		MSG(0, "\tFilesystem has does not have metadata encryption, but a metadata encryption key was specified.\n");
> +		return -1;
> +	}
> +
>  	if (sanity_check_area_boundary(sb, sb_addr))
>  		return -1;
>  	return 0;
> @@ -940,7 +963,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_unencrypted(buf, sb_addr))
>  		return -1;
>  
>  	memcpy(sbi->raw_super, buf + F2FS_SUPER_OFFSET,
> @@ -3499,6 +3522,12 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
>  	}
>  	sb = F2FS_RAW_SUPER(sbi);
>  
> +	/* Get metadata encryption algorithm */
> +	c.metadata_crypt_alg = get_sb(metadata_crypt_alg);
> +
> +	if (f2fs_metadata_verify_args())
> +		exit(1);
> +
>  	ret = check_sector_size(sb);
>  	if (ret)
>  		return -1;
> diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
> index b5bda13..6b1912d 100644
> --- a/include/f2fs_fs.h
> +++ b/include/f2fs_fs.h
> @@ -441,6 +441,11 @@ struct f2fs_configuration {
>  
>  	/* cache parameters */
>  	dev_cache_config_t cache_config;
> +
> +	/* metadata encryption */
> +	__u8 *metadata_crypt_key;
> +	int metadata_crypt_key_len;
> +	int metadata_crypt_alg;
>  };
>  
>  #ifdef CONFIG_64BIT
> @@ -675,7 +680,8 @@ 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 */
> +	__le32	metadata_crypt_alg;	/* The metadata encryption algorithm (FSCRYPT_MODE_*) */
> +	__u8 reserved[302];		/* valid reserved region */
>  	__le32 crc;			/* checksum of superblock */
>  } __attribute__((packed));
>  
> @@ -1237,12 +1243,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_unencrypted(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_unencrypted(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..d15873d
> --- /dev/null
> +++ b/include/f2fs_metadata_crypt.h
> @@ -0,0 +1,21 @@
> +/**
> + * 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>
> +
> +int f2fs_get_crypt_alg(const char *optarg);
> +
> +void f2fs_print_crypt_algs(void);
> +
> +int f2fs_metadata_process_key(const char *key_serial);
> +
> +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..a82d753 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 -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..faf399a
> --- /dev/null
> +++ b/lib/f2fs_metadata_crypt.c
> @@ -0,0 +1,226 @@
> +/**
> + * 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 <keyutils.h>
> +
> +#include "f2fs_fs.h"
> +#include "f2fs_metadata_crypt.h"
> +
> +extern struct f2fs_configuration c;
> +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 <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
> +		if (f2fs_crypt_modes[i].friendly_name &&
> +		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
> +			return i;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int f2fs_metadata_process_key(const char *key_serial_str)
> +{
> +	key_serial_t key_serial = strtol(key_serial_str, NULL, 10);
> +
> +	c.metadata_crypt_key_len =
> +		keyctl_read_alloc(key_serial, (void **)&c.metadata_crypt_key);
> +
> +	if (c.metadata_crypt_key_len < 0)
> +		return errno;
> +
> +	return 0;
> +}
> +
> +int f2fs_metadata_verify_args(void)
> +{
> +	/* 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_key_len !=
> +	    f2fs_crypt_modes[c.metadata_crypt_alg].keysize) {
> +		MSG(0, "\tMetadata encryption key length %d didn't match required size %d\n",
> +		    c.metadata_crypt_key_len,
> +		    f2fs_crypt_modes[c.metadata_crypt_alg].keysize);
> +
> +		return -EINVAL;
> +	}

Need to check sparse mode here?

And, what about multiple partition case?

> +
> +	return 0;
> +}
> +
> +void f2fs_metadata_crypt_gen_iv(struct af_alg_iv *iv, __u64 blk_addr)
> +{
> +	int i = 0;
> +
> +	memset(iv->iv, 0, iv->ivlen);
> +
> +	while (blk_addr > 0) {
> +		iv->iv[i] = blk_addr & 0xFF;
> +		blk_addr >>= 8;
> +		i++;
> +	}
> +}
> +
> +int f2fs_metadata_crypt_block(void *buf, size_t len, __u64 blk_addr,
> +			      bool encrypt)
> +{
> +	struct f2fs_crypt_mode *crypt_mode;
> +	int sockfd, fd;
> +	struct sockaddr_alg sa = {
> +		.salg_family = AF_ALG,
> +		.salg_type = "skcipher",
> +	};
> +	struct msghdr msg = {};
> +	struct cmsghdr *cmsg;
> +	char cbuf[CMSG_SPACE(4) + CMSG_SPACE(4 + MAX_IV_LEN)] = {0};
> +	int blk_offset;
> +	struct af_alg_iv *iv;
> +	struct iovec iov;
> +	int err;
> +
> +	crypt_mode = &f2fs_crypt_modes[c.metadata_crypt_alg];
> +	memcpy(sa.salg_name, crypt_mode->cipher_str,
> +	       strlen(crypt_mode->cipher_str));
> +
> +	sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
> +	if (sockfd < 0)
> +		return errno;
> +	err = bind(sockfd, (struct sockaddr *)&sa, sizeof(sa));
> +	if (err) {
> +		MSG(0, "\tCouldn't bind crypto socket. Maybe support for the crypto algorithm isn't enabled?\n");
> +		close(sockfd);
> +		return errno;
> +	}
> +	err = setsockopt(sockfd, SOL_ALG, ALG_SET_KEY, c.metadata_crypt_key,
> +			 crypt_mode->keysize);
> +	if (err) {
> +		MSG(0, "\tCouldn't set crypto socket options.\n");
> +		close(sockfd);
> +		return errno;
> +	}
> +	fd = accept(sockfd, NULL, 0);
> +	if (fd < 0)
> +		goto err_out;
> +
> +	msg.msg_control = cbuf;
> +	msg.msg_controllen = sizeof(cbuf);
> +
> +	cmsg = CMSG_FIRSTHDR(&msg);
> +	cmsg->cmsg_level = SOL_ALG;
> +	cmsg->cmsg_type = ALG_SET_OP;
> +	cmsg->cmsg_len = CMSG_LEN(4);
> +	*(__u32 *)CMSG_DATA(cmsg) = encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
> +
> +	cmsg = CMSG_NXTHDR(&msg, cmsg);
> +	cmsg->cmsg_level = SOL_ALG;
> +	cmsg->cmsg_type = ALG_SET_IV;
> +	cmsg->cmsg_len = CMSG_LEN(4 + MAX_IV_LEN);
> +	iv = (void *)CMSG_DATA(cmsg);
> +	iv->ivlen = crypt_mode->ivlen;
> +
> +	iov.iov_len = F2FS_BLKSIZE;
> +
> +	msg.msg_iov = &iov;
> +	msg.msg_iovlen = 1;
> +
> +	for (blk_offset = 0; blk_offset < len / F2FS_BLKSIZE; blk_offset++) {
> +		f2fs_metadata_crypt_gen_iv(iv, blk_addr + blk_offset);
> +
> +		iov.iov_base = (char *)buf + blk_offset * F2FS_BLKSIZE;
> +
> +		err = sendmsg(fd, &msg, 0);
> +		if (err < 0)
> +			goto err_out;
> +		err = read(fd, (char *)buf + blk_offset * F2FS_BLKSIZE,
> +			   F2FS_BLKSIZE);
> +		if (err < 0)
> +			goto err_out;
> +	}
> +
> +	close(fd);
> +	close(sockfd);
> +
> +	return 0;
> +
> +err_out:
> +	err = errno;
> +	close(fd);
> +	close(sockfd);
> +
> +	return err;
> +}
> +
> +void *f2fs_metadata_crypt_blocks(void *buf, size_t len, __u64 blk_addr,
> +	bool encrypt)
> +{
> +	int err = 0;
> +	void *enc_buf;
> +
> +	if (!c.metadata_crypt_key)
> +		return buf;
> +
> +	enc_buf = malloc(len);
> +	memcpy(enc_buf, buf, len);
> +
> +	err = f2fs_metadata_crypt_block(enc_buf, len, blk_addr, encrypt);
> +	if (err) {
> +		MSG(0, "\tFailed to en/decrypt blocks. Errno %d\n", err);
> +		free(enc_buf);
> +		return NULL;
> +	}
> +
> +	return enc_buf;
> +}
> diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
> index 138285d..f117e1e 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)
> +int __dev_read(void *buf, __u64 offset, size_t len, bool unencrypted)
>  {
>  	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,29 @@ int dev_read(void *buf, __u64 offset, size_t len)
>  		return -1;
>  	if (read(fd, buf, len) < 0)
>  		return -1;
> +	if (!unencrypted) {
> +		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, false);
> +}
> +
> +int dev_read_unencrypted(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,13 +564,17 @@ int dev_readahead(__u64 offset, size_t UNUSED(len))
>  #endif
>  }
>  
> -int dev_write(void *buf, __u64 offset, size_t len)
> +int __dev_write(void *buf, __u64 offset, size_t len, bool unencrypted)
>  {
>  	int fd;
> +	__u64 blk_addr = offset >> F2FS_BLKSIZE_BITS;
> +	void *src_buf = buf;
> +	int err = -1;
>  
>  	if (c.dry_run)
>  		return 0;
>  
> +	/* TODO: handle sparse mode with metadata encryption */
>  	if (c.sparse_mode)
>  		return sparse_write_blk(offset / F2FS_BLKSIZE,
>  					len / F2FS_BLKSIZE, buf);
> @@ -562,11 +589,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 (!unencrypted) {
> +		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, false);
>  }
>  
>  int dev_write_block(void *buf, __u64 blk_addr)
> @@ -574,6 +616,16 @@ int dev_write_block(void *buf, __u64 blk_addr)
>  	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
>  }
>  
> +static int dev_write_unencrypted(void *buf, __u64 offset, size_t len)
> +{
> +	return __dev_write(buf, offset, len, true);
> +}
> +
> +int dev_write_block_unencrypted(void *buf, __u64 blk_addr)
> +{
> +	return dev_write_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
> +}
> +
>  int dev_write_dump(void *buf, __u64 offset, size_t len)
>  {
>  	if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
> @@ -586,7 +638,11 @@ 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;
>  
> +	/* TODO: handle sparse mode with metadata encryption */
>  	if (c.sparse_mode)
>  		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
>  						len / F2FS_BLKSIZE);
> @@ -598,11 +654,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 +681,11 @@ int dev_read_block(void *buf, __u64 blk_addr)
>  	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
>  }
>  
> +int dev_read_block_unencrypted(void *buf, __u64 blk_addr)
> +{
> +	return dev_read_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
> +}
> +
>  int dev_reada_block(__u64 blk_addr)
>  {
>  	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
> diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
> index a6c542e..bf587bf 100644
> --- a/mkfs/f2fs_format.c
> +++ b/mkfs/f2fs_format.c
> @@ -537,6 +537,9 @@ 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);
> +
>  	sb->feature = c.feature;
>  
>  	if (get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) {
> @@ -1046,7 +1049,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_unencrypted(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..8856850 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");
> @@ -97,6 +100,12 @@ 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_key)
> +		MSG(0, "Info: Metadata key is %s\n", c.metadata_crypt_key);
> +
> +	if (c.metadata_crypt_alg)
> +		MSG(0, "Info: Metadata alg is %d\n", c.metadata_crypt_alg);
>  }
>  
>  static void add_default_options(void)
> @@ -125,7 +134,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 +147,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 +195,12 @@ static void f2fs_parse_options(int argc, char *argv[])
>  		case 'm':
>  			c.zoned_mode = 1;
>  			break;
> +		case 'M':
> +			if (f2fs_metadata_process_key(optarg)) {
> +				MSG(0, "Error: Invalid metadata key\n");
> +				mkfs_usage();
> +			}
> +			break;
>  		case 'o':
>  			c.overprovision = atof(optarg);
>  			break;
> @@ -244,6 +267,14 @@ static void f2fs_parse_options(int argc, char *argv[])
>  		}
>  	}
>  
> +	if ((!!c.metadata_crypt_key) != (!!c.metadata_crypt_alg)) {
> +		MSG(0, "\tError: Both the metadata crypt key and crypt algorithm must be specified!");
> +		exit(1);
> +	}
> +
> +	if (f2fs_metadata_verify_args())
> +		exit(1);
> +
>  	add_default_options();

Need to check options after add_default_options()?

Thanks,

>  
>  	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
> -- 
> 2.28.0.806.g8561365e88-goog

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

* Re: [f2fs-dev] [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
@ 2020-10-07 19:42     ` jaegeuk
  0 siblings, 0 replies; 18+ messages in thread
From: jaegeuk @ 2020-10-07 19:42 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Eric Biggers, linux-fscrypt, linux-f2fs-devel

Hi Satya,

On 10/05, Satya Tangirala wrote:
> Introduce native metadata encryption support for F2FS. All blocks
> other than the super block are encrypted with the specified metadata
> encryption key and algorithm. The data unit number for each block is its
> block number in the filesystem.
> 
> This patch introduces two new options '-A' and '-M' for specifying metadata
> crypt options. '-A' takes the desired metadata encryption algorithm as
> argument. '-M' takes the linux key_serial of the metadata encryption key as
> the argument. The keyring key provided must be of a key type that supports
> reading the payload from userspace.

Could you please update manpages as well?

> 
> mkfs.f2fs takes both these arguments, and stores the encryption algorithm
> in the superblock of the FS.
> 
> The rest of the programs only take '-M', and use the encryption algorithm
> stored in the superblock of the FS.
> 
> Signed-off-by: Satya Tangirala <satyat@google.com>
> ---
>  fsck/main.c                   |  47 ++++++-
>  fsck/mount.c                  |  33 ++++-
>  include/f2fs_fs.h             |  10 +-
>  include/f2fs_metadata_crypt.h |  21 ++++
>  lib/Makefile.am               |   4 +-
>  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
>  lib/libf2fs_io.c              |  87 +++++++++++--
>  mkfs/f2fs_format.c            |   5 +-
>  mkfs/f2fs_format_main.c       |  33 ++++-
>  9 files changed, 446 insertions(+), 20 deletions(-)
>  create mode 100644 include/f2fs_metadata_crypt.h
>  create mode 100644 lib/f2fs_metadata_crypt.c
> 
> diff --git a/fsck/main.c b/fsck/main.c
> index 32559f1..6a4d867 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
> @@ -62,6 +64,7 @@ void fsck_usage()
>  			" (default 0)\n");
>  	MSG(0, "  -m <max-hash-collision>  set max cache hash collision"
>  			" (default 16)\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -C encoding[:flag1,flag2] Set options for enabling"
>  			" casefolding\n");
>  	MSG(0, "  -d debug level [default:0]\n");
> @@ -92,6 +95,7 @@ void dump_usage()
>  	MSG(0, "  -S sparse_mode\n");
>  	MSG(0, "  -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n");
>  	MSG(0, "  -b blk_addr (in 4KB)\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -V print the version number and exit\n");
>  
>  	exit(1);
> @@ -107,6 +111,7 @@ void defrag_usage()
>  	MSG(0, "  -l length [default:512 (2MB)]\n");
>  	MSG(0, "  -t target block address [default: main_blkaddr + 2MB]\n");
>  	MSG(0, "  -i set direction as shrink [default: expand]\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -V print the version number and exit\n");
>  	exit(1);
>  }
> @@ -119,6 +124,7 @@ void resize_usage()
>  	MSG(0, "  -i extended node bitmap, node ratio is 20%% by default\n");
>  	MSG(0, "  -s safe resize (Does not resize metadata)");
>  	MSG(0, "  -t target sectors [default: device size]\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -V print the version number and exit\n");
>  	exit(1);
>  }
> @@ -129,6 +135,7 @@ void sload_usage()
>  	MSG(0, "[options]:\n");
>  	MSG(0, "  -C fs_config\n");
>  	MSG(0, "  -f source directory [path of the source directory]\n");
> +	MSG(0, "  -M Metadata encryption key_serial in keyring\n");
>  	MSG(0, "  -p product out directory\n");
>  	MSG(0, "  -s file_contexts\n");
>  	MSG(0, "  -S sparse_mode\n");
> @@ -200,7 +207,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  	}
>  
>  	if (!strcmp("fsck.f2fs", prog)) {
> -		const char *option_string = ":aC:c:m:d:fg:O:p:q:StyV";
> +		const char *option_string = ":aC:c:m:M:d:fg:O:p:q:StyV";
>  		int opt = 0, val;
>  		char *token;
>  		struct option long_opt[] = {
> @@ -243,6 +250,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  				c.cache_config.max_hash_collision =
>  						atoi(optarg);
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					fsck_usage();
> +				}
> +				break;
>  			case 'g':
>  				if (!strcmp(optarg, "android"))
>  					c.defset = CONF_ANDROID;
> @@ -345,7 +358,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  				break;
>  		}
>  	} else if (!strcmp("dump.f2fs", prog)) {
> -		const char *option_string = "d:i:n:s:Sa:b:V";
> +		const char *option_string = "d:i:n:s:Sa:b:M:V";
>  		static struct dump_option dump_opt = {
>  			.nid = 0,	/* default root ino */
>  			.start_nat = -1,
> @@ -413,6 +426,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  					ret = sscanf(optarg, "%x",
>  							&dump_opt.blk_addr);
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					dump_usage();
> +				}
> +				break;
>  			case 'V':
>  				show_version(prog);
>  				exit(0);
> @@ -427,7 +446,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  
>  		c.private = &dump_opt;
>  	} else if (!strcmp("defrag.f2fs", prog)) {
> -		const char *option_string = "d:s:Sl:t:iV";
> +		const char *option_string = "d:M:s:Sl:t:iV";
>  
>  		c.func = DEFRAG;
>  		while ((option = getopt(argc, argv, option_string)) != EOF) {
> @@ -473,6 +492,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  			case 'i':
>  				c.defrag_shrink = 1;
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					defrag_usage();
> +				}
> +				break;
>  			case 'V':
>  				show_version(prog);
>  				exit(0);
> @@ -485,7 +510,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  				break;
>  		}
>  	} else if (!strcmp("resize.f2fs", prog)) {
> -		const char *option_string = "d:st:iV";
> +		const char *option_string = "d:M:st:iV";
>  
>  		c.func = RESIZE;
>  		while ((option = getopt(argc, argv, option_string)) != EOF) {
> @@ -515,6 +540,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  			case 'i':
>  				c.large_nat_bitmap = 1;
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					resize_usage();
> +				}
> +				break;
>  			case 'V':
>  				show_version(prog);
>  				exit(0);
> @@ -527,7 +558,7 @@ void f2fs_parse_options(int argc, char *argv[])
>  				break;
>  		}
>  	} else if (!strcmp("sload.f2fs", prog)) {
> -		const char *option_string = "C:d:f:p:s:St:T:V";
> +		const char *option_string = "C:d:f:M:p:s:St:T:V";
>  #ifdef HAVE_LIBSELINUX
>  		int max_nr_opt = (int)sizeof(c.seopt_file) /
>  			sizeof(c.seopt_file[0]);
> @@ -553,6 +584,12 @@ void f2fs_parse_options(int argc, char *argv[])
>  			case 'f':
>  				c.from_dir = absolute_path(optarg);
>  				break;
> +			case 'M':
> +				if (f2fs_metadata_process_key(optarg)) {
> +					MSG(0, "Error: Invalid metadata key\n");
> +					sload_usage();
> +				}
> +				break;
>  			case 'p':
>  				c.target_out_dir = absolute_path(optarg);
>  				break;
> diff --git a/fsck/mount.c b/fsck/mount.c
> index 8ebc5b0..7520a8a 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,6 +562,10 @@ void print_sb_state(struct f2fs_super_block *sb)
>  	if (f & cpu_to_le32(F2FS_FEATURE_COMPRESSION)) {
>  		MSG(0, "%s", " compression");
>  	}
> +	if (sb->metadata_crypt_alg) {
> +		MSG(0, "%s", " metadata_crypt");
> +	}
> +
>  	MSG(0, "\n");
>  	MSG(0, "Info: superblock encrypt level = %d, salt = ",
>  					sb->encryption_level);
> @@ -686,7 +691,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_unencrypted(buf, addr);
>  			ASSERT(ret >= 0);
>  		}
>  	}
> @@ -927,6 +932,24 @@ int sanity_check_raw_super(struct f2fs_super_block *sb, enum SB_ADDR sb_addr)
>  		return -1;
>  	}
>  
> +	/*
> +	 * Check that metadata encryption is enabled on superblock when metadata
> +	 * crypt key is specified
> +	 */
> +	if (get_sb(metadata_crypt_alg) && !c.metadata_crypt_key) {
> +		MSG(0, "\tFilesystem has metadata encryption, but we're missing the metadata encryption key.\n");
> +		return -1;
> +	}
> +
> +	/*
> +	 * Check that metadata encryption is disabled on superblock when metadata
> +	 * crypt key is not specified
> +	 */
> +	if (!get_sb(metadata_crypt_alg) && c.metadata_crypt_key) {
> +		MSG(0, "\tFilesystem has does not have metadata encryption, but a metadata encryption key was specified.\n");
> +		return -1;
> +	}
> +
>  	if (sanity_check_area_boundary(sb, sb_addr))
>  		return -1;
>  	return 0;
> @@ -940,7 +963,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_unencrypted(buf, sb_addr))
>  		return -1;
>  
>  	memcpy(sbi->raw_super, buf + F2FS_SUPER_OFFSET,
> @@ -3499,6 +3522,12 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
>  	}
>  	sb = F2FS_RAW_SUPER(sbi);
>  
> +	/* Get metadata encryption algorithm */
> +	c.metadata_crypt_alg = get_sb(metadata_crypt_alg);
> +
> +	if (f2fs_metadata_verify_args())
> +		exit(1);
> +
>  	ret = check_sector_size(sb);
>  	if (ret)
>  		return -1;
> diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
> index b5bda13..6b1912d 100644
> --- a/include/f2fs_fs.h
> +++ b/include/f2fs_fs.h
> @@ -441,6 +441,11 @@ struct f2fs_configuration {
>  
>  	/* cache parameters */
>  	dev_cache_config_t cache_config;
> +
> +	/* metadata encryption */
> +	__u8 *metadata_crypt_key;
> +	int metadata_crypt_key_len;
> +	int metadata_crypt_alg;
>  };
>  
>  #ifdef CONFIG_64BIT
> @@ -675,7 +680,8 @@ 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 */
> +	__le32	metadata_crypt_alg;	/* The metadata encryption algorithm (FSCRYPT_MODE_*) */
> +	__u8 reserved[302];		/* valid reserved region */
>  	__le32 crc;			/* checksum of superblock */
>  } __attribute__((packed));
>  
> @@ -1237,12 +1243,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_unencrypted(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_unencrypted(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..d15873d
> --- /dev/null
> +++ b/include/f2fs_metadata_crypt.h
> @@ -0,0 +1,21 @@
> +/**
> + * 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>
> +
> +int f2fs_get_crypt_alg(const char *optarg);
> +
> +void f2fs_print_crypt_algs(void);
> +
> +int f2fs_metadata_process_key(const char *key_serial);
> +
> +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..a82d753 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 -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..faf399a
> --- /dev/null
> +++ b/lib/f2fs_metadata_crypt.c
> @@ -0,0 +1,226 @@
> +/**
> + * 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 <keyutils.h>
> +
> +#include "f2fs_fs.h"
> +#include "f2fs_metadata_crypt.h"
> +
> +extern struct f2fs_configuration c;
> +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 <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
> +		if (f2fs_crypt_modes[i].friendly_name &&
> +		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
> +			return i;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int f2fs_metadata_process_key(const char *key_serial_str)
> +{
> +	key_serial_t key_serial = strtol(key_serial_str, NULL, 10);
> +
> +	c.metadata_crypt_key_len =
> +		keyctl_read_alloc(key_serial, (void **)&c.metadata_crypt_key);
> +
> +	if (c.metadata_crypt_key_len < 0)
> +		return errno;
> +
> +	return 0;
> +}
> +
> +int f2fs_metadata_verify_args(void)
> +{
> +	/* 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_key_len !=
> +	    f2fs_crypt_modes[c.metadata_crypt_alg].keysize) {
> +		MSG(0, "\tMetadata encryption key length %d didn't match required size %d\n",
> +		    c.metadata_crypt_key_len,
> +		    f2fs_crypt_modes[c.metadata_crypt_alg].keysize);
> +
> +		return -EINVAL;
> +	}

Need to check sparse mode here?

And, what about multiple partition case?

> +
> +	return 0;
> +}
> +
> +void f2fs_metadata_crypt_gen_iv(struct af_alg_iv *iv, __u64 blk_addr)
> +{
> +	int i = 0;
> +
> +	memset(iv->iv, 0, iv->ivlen);
> +
> +	while (blk_addr > 0) {
> +		iv->iv[i] = blk_addr & 0xFF;
> +		blk_addr >>= 8;
> +		i++;
> +	}
> +}
> +
> +int f2fs_metadata_crypt_block(void *buf, size_t len, __u64 blk_addr,
> +			      bool encrypt)
> +{
> +	struct f2fs_crypt_mode *crypt_mode;
> +	int sockfd, fd;
> +	struct sockaddr_alg sa = {
> +		.salg_family = AF_ALG,
> +		.salg_type = "skcipher",
> +	};
> +	struct msghdr msg = {};
> +	struct cmsghdr *cmsg;
> +	char cbuf[CMSG_SPACE(4) + CMSG_SPACE(4 + MAX_IV_LEN)] = {0};
> +	int blk_offset;
> +	struct af_alg_iv *iv;
> +	struct iovec iov;
> +	int err;
> +
> +	crypt_mode = &f2fs_crypt_modes[c.metadata_crypt_alg];
> +	memcpy(sa.salg_name, crypt_mode->cipher_str,
> +	       strlen(crypt_mode->cipher_str));
> +
> +	sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
> +	if (sockfd < 0)
> +		return errno;
> +	err = bind(sockfd, (struct sockaddr *)&sa, sizeof(sa));
> +	if (err) {
> +		MSG(0, "\tCouldn't bind crypto socket. Maybe support for the crypto algorithm isn't enabled?\n");
> +		close(sockfd);
> +		return errno;
> +	}
> +	err = setsockopt(sockfd, SOL_ALG, ALG_SET_KEY, c.metadata_crypt_key,
> +			 crypt_mode->keysize);
> +	if (err) {
> +		MSG(0, "\tCouldn't set crypto socket options.\n");
> +		close(sockfd);
> +		return errno;
> +	}
> +	fd = accept(sockfd, NULL, 0);
> +	if (fd < 0)
> +		goto err_out;
> +
> +	msg.msg_control = cbuf;
> +	msg.msg_controllen = sizeof(cbuf);
> +
> +	cmsg = CMSG_FIRSTHDR(&msg);
> +	cmsg->cmsg_level = SOL_ALG;
> +	cmsg->cmsg_type = ALG_SET_OP;
> +	cmsg->cmsg_len = CMSG_LEN(4);
> +	*(__u32 *)CMSG_DATA(cmsg) = encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
> +
> +	cmsg = CMSG_NXTHDR(&msg, cmsg);
> +	cmsg->cmsg_level = SOL_ALG;
> +	cmsg->cmsg_type = ALG_SET_IV;
> +	cmsg->cmsg_len = CMSG_LEN(4 + MAX_IV_LEN);
> +	iv = (void *)CMSG_DATA(cmsg);
> +	iv->ivlen = crypt_mode->ivlen;
> +
> +	iov.iov_len = F2FS_BLKSIZE;
> +
> +	msg.msg_iov = &iov;
> +	msg.msg_iovlen = 1;
> +
> +	for (blk_offset = 0; blk_offset < len / F2FS_BLKSIZE; blk_offset++) {
> +		f2fs_metadata_crypt_gen_iv(iv, blk_addr + blk_offset);
> +
> +		iov.iov_base = (char *)buf + blk_offset * F2FS_BLKSIZE;
> +
> +		err = sendmsg(fd, &msg, 0);
> +		if (err < 0)
> +			goto err_out;
> +		err = read(fd, (char *)buf + blk_offset * F2FS_BLKSIZE,
> +			   F2FS_BLKSIZE);
> +		if (err < 0)
> +			goto err_out;
> +	}
> +
> +	close(fd);
> +	close(sockfd);
> +
> +	return 0;
> +
> +err_out:
> +	err = errno;
> +	close(fd);
> +	close(sockfd);
> +
> +	return err;
> +}
> +
> +void *f2fs_metadata_crypt_blocks(void *buf, size_t len, __u64 blk_addr,
> +	bool encrypt)
> +{
> +	int err = 0;
> +	void *enc_buf;
> +
> +	if (!c.metadata_crypt_key)
> +		return buf;
> +
> +	enc_buf = malloc(len);
> +	memcpy(enc_buf, buf, len);
> +
> +	err = f2fs_metadata_crypt_block(enc_buf, len, blk_addr, encrypt);
> +	if (err) {
> +		MSG(0, "\tFailed to en/decrypt blocks. Errno %d\n", err);
> +		free(enc_buf);
> +		return NULL;
> +	}
> +
> +	return enc_buf;
> +}
> diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
> index 138285d..f117e1e 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)
> +int __dev_read(void *buf, __u64 offset, size_t len, bool unencrypted)
>  {
>  	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,29 @@ int dev_read(void *buf, __u64 offset, size_t len)
>  		return -1;
>  	if (read(fd, buf, len) < 0)
>  		return -1;
> +	if (!unencrypted) {
> +		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, false);
> +}
> +
> +int dev_read_unencrypted(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,13 +564,17 @@ int dev_readahead(__u64 offset, size_t UNUSED(len))
>  #endif
>  }
>  
> -int dev_write(void *buf, __u64 offset, size_t len)
> +int __dev_write(void *buf, __u64 offset, size_t len, bool unencrypted)
>  {
>  	int fd;
> +	__u64 blk_addr = offset >> F2FS_BLKSIZE_BITS;
> +	void *src_buf = buf;
> +	int err = -1;
>  
>  	if (c.dry_run)
>  		return 0;
>  
> +	/* TODO: handle sparse mode with metadata encryption */
>  	if (c.sparse_mode)
>  		return sparse_write_blk(offset / F2FS_BLKSIZE,
>  					len / F2FS_BLKSIZE, buf);
> @@ -562,11 +589,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 (!unencrypted) {
> +		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, false);
>  }
>  
>  int dev_write_block(void *buf, __u64 blk_addr)
> @@ -574,6 +616,16 @@ int dev_write_block(void *buf, __u64 blk_addr)
>  	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
>  }
>  
> +static int dev_write_unencrypted(void *buf, __u64 offset, size_t len)
> +{
> +	return __dev_write(buf, offset, len, true);
> +}
> +
> +int dev_write_block_unencrypted(void *buf, __u64 blk_addr)
> +{
> +	return dev_write_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
> +}
> +
>  int dev_write_dump(void *buf, __u64 offset, size_t len)
>  {
>  	if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
> @@ -586,7 +638,11 @@ 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;
>  
> +	/* TODO: handle sparse mode with metadata encryption */
>  	if (c.sparse_mode)
>  		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
>  						len / F2FS_BLKSIZE);
> @@ -598,11 +654,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 +681,11 @@ int dev_read_block(void *buf, __u64 blk_addr)
>  	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
>  }
>  
> +int dev_read_block_unencrypted(void *buf, __u64 blk_addr)
> +{
> +	return dev_read_unencrypted(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
> +}
> +
>  int dev_reada_block(__u64 blk_addr)
>  {
>  	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
> diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
> index a6c542e..bf587bf 100644
> --- a/mkfs/f2fs_format.c
> +++ b/mkfs/f2fs_format.c
> @@ -537,6 +537,9 @@ 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);
> +
>  	sb->feature = c.feature;
>  
>  	if (get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) {
> @@ -1046,7 +1049,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_unencrypted(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..8856850 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");
> @@ -97,6 +100,12 @@ 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_key)
> +		MSG(0, "Info: Metadata key is %s\n", c.metadata_crypt_key);
> +
> +	if (c.metadata_crypt_alg)
> +		MSG(0, "Info: Metadata alg is %d\n", c.metadata_crypt_alg);
>  }
>  
>  static void add_default_options(void)
> @@ -125,7 +134,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 +147,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 +195,12 @@ static void f2fs_parse_options(int argc, char *argv[])
>  		case 'm':
>  			c.zoned_mode = 1;
>  			break;
> +		case 'M':
> +			if (f2fs_metadata_process_key(optarg)) {
> +				MSG(0, "Error: Invalid metadata key\n");
> +				mkfs_usage();
> +			}
> +			break;
>  		case 'o':
>  			c.overprovision = atof(optarg);
>  			break;
> @@ -244,6 +267,14 @@ static void f2fs_parse_options(int argc, char *argv[])
>  		}
>  	}
>  
> +	if ((!!c.metadata_crypt_key) != (!!c.metadata_crypt_alg)) {
> +		MSG(0, "\tError: Both the metadata crypt key and crypt algorithm must be specified!");
> +		exit(1);
> +	}
> +
> +	if (f2fs_metadata_verify_args())
> +		exit(1);
> +
>  	add_default_options();

Need to check options after add_default_options()?

Thanks,

>  
>  	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
> -- 
> 2.28.0.806.g8561365e88-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] 18+ messages in thread

* Re: [PATCH 0/1] userspace support for F2FS metadata encryption
  2020-10-05  7:41 ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
@ 2020-10-07 21:39   ` Eric Biggers
  -1 siblings, 0 replies; 18+ messages in thread
From: Eric Biggers @ 2020-10-07 21:39 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Jaegeuk Kim, linux-f2fs-devel, linux-fscrypt

On Mon, Oct 05, 2020 at 07:41:32AM +0000, Satya Tangirala wrote:
> The kernel patches for F2FS metadata encryption are at:
> 
> https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> 
> This patch 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.
> 
> This patch introduces two new options for the userspace tools: '-A' to
> specify the encryption algorithm, and '-M' to specify the encryption key.
> mkfs.f2fs will store the encryption algorithm used for metadata encryption
> in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> of the tools only take the '-M' option, and will obtain the encryption
> algorithm from the superblock of the FS.

As I mentioned on the kernel patches, it might make sense to compute a
metadata_key_identifier and store it in the super_block so that it can be
automatically requested without needing to provide an option.

> 
> Limitations: 
> Metadata encryption with sparse storage has not been implemented yet in
> this patch.
> 
> 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.
> 
> Satya Tangirala (1):
>   f2fs-tools: Introduce metadata encryption support

A cover letter shouldn't be used for a 1-patch series.  Just include these
details in the patch instead.

- Eric

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

* Re: [f2fs-dev] [PATCH 0/1] userspace support for F2FS metadata encryption
@ 2020-10-07 21:39   ` Eric Biggers
  0 siblings, 0 replies; 18+ messages in thread
From: Eric Biggers @ 2020-10-07 21:39 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Jaegeuk Kim, linux-fscrypt, linux-f2fs-devel

On Mon, Oct 05, 2020 at 07:41:32AM +0000, Satya Tangirala wrote:
> The kernel patches for F2FS metadata encryption are at:
> 
> https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> 
> This patch 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.
> 
> This patch introduces two new options for the userspace tools: '-A' to
> specify the encryption algorithm, and '-M' to specify the encryption key.
> mkfs.f2fs will store the encryption algorithm used for metadata encryption
> in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> of the tools only take the '-M' option, and will obtain the encryption
> algorithm from the superblock of the FS.

As I mentioned on the kernel patches, it might make sense to compute a
metadata_key_identifier and store it in the super_block so that it can be
automatically requested without needing to provide an option.

> 
> Limitations: 
> Metadata encryption with sparse storage has not been implemented yet in
> this patch.
> 
> 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.
> 
> Satya Tangirala (1):
>   f2fs-tools: Introduce metadata encryption support

A cover letter shouldn't be used for a 1-patch series.  Just include these
details in the patch instead.

- Eric


_______________________________________________
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] 18+ messages in thread

* Re: [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
  2020-10-05  7:41   ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
@ 2020-10-07 21:52     ` Eric Biggers
  -1 siblings, 0 replies; 18+ messages in thread
From: Eric Biggers @ 2020-10-07 21:52 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Jaegeuk Kim, linux-f2fs-devel, linux-fscrypt

On Mon, Oct 05, 2020 at 07:41:33AM +0000, Satya Tangirala wrote:
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 871d773..a82d753 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 -version-info $(LIBF2FS_CURRENT):$(LIBF2FS_REVISION):$(LIBF2FS_AGE)

This introduces a dependency on libkeyutils.  Doesn't that need to be checked in
configure.ac?

> diff --git a/lib/f2fs_metadata_crypt.c b/lib/f2fs_metadata_crypt.c
> new file mode 100644
> index 0000000..faf399a
> --- /dev/null
> +++ b/lib/f2fs_metadata_crypt.c
> @@ -0,0 +1,226 @@
> +/**
> + * 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 <keyutils.h>
> +
> +#include "f2fs_fs.h"
> +#include "f2fs_metadata_crypt.h"
> +
> +extern struct f2fs_configuration c;
> +struct f2fs_crypt_mode {
> +	const char *friendly_name;
> +	const char *cipher_str;
> +	unsigned int keysize;
> +	unsigned int ivlen;
> +} f2fs_crypt_modes[] = {

Use 'const' for static or global data that isn't modified.

> +void f2fs_print_crypt_algs(void)
> +{
> +	int i;
> +
> +	for (i = 1; i <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
> +		if (f2fs_crypt_modes[i].friendly_name &&
> +		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
> +			return i;
> +		}
> +	}
> +
> +	return 0;
> +}

Although __FSCRYPT_MODE_MAX is defined in <linux/fscrypt.h>, it isn't intended
to be used in userspace programs, as its value will change depending on the
version of the kernel headers.  Just use ARRAY_SIZE(f2fs_crypt_modes) instead.

> +int f2fs_metadata_crypt_block(void *buf, size_t len, __u64 blk_addr,
> +			      bool encrypt)
> +{
> +	struct f2fs_crypt_mode *crypt_mode;
> +	int sockfd, fd;
> +	struct sockaddr_alg sa = {
> +		.salg_family = AF_ALG,
> +		.salg_type = "skcipher",
> +	};
> +	struct msghdr msg = {};
> +	struct cmsghdr *cmsg;
> +	char cbuf[CMSG_SPACE(4) + CMSG_SPACE(4 + MAX_IV_LEN)] = {0};
> +	int blk_offset;
> +	struct af_alg_iv *iv;
> +	struct iovec iov;
> +	int err;
> +
> +	crypt_mode = &f2fs_crypt_modes[c.metadata_crypt_alg];
> +	memcpy(sa.salg_name, crypt_mode->cipher_str,
> +	       strlen(crypt_mode->cipher_str));
> +
> +	sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
> +	if (sockfd < 0)
> +		return errno;

This will fail if AF_ALG isn't enabled in the kernel config, or if the process
isn't allowed to use AF_ALG by SELinux policy.  Can you show a proper error
message?

> +	err = bind(sockfd, (struct sockaddr *)&sa, sizeof(sa));
> +	if (err) {
> +		MSG(0, "\tCouldn't bind crypto socket. Maybe support for the crypto algorithm isn't enabled?\n");
> +		close(sockfd);
> +		return errno;
> +	}

This will fail if either CRYPTO_USER_API_SKCIPHER isn't enabled in the kernel
config, or if the required crypto algorithm isn't enabled in the kernel config.
Can you show a better error message?

Also, these new kernel config option dependencies should be documented in the
documentation for f2fs-tools.

> +	err = setsockopt(sockfd, SOL_ALG, ALG_SET_KEY, c.metadata_crypt_key,
> +			 crypt_mode->keysize);
> +	if (err) {
> +		MSG(0, "\tCouldn't set crypto socket options.\n");
> +		close(sockfd);
> +		return errno;
> +	}
> +	fd = accept(sockfd, NULL, 0);
> +	if (fd < 0)
> +		goto err_out;

It's a lot of work to allocate an AF_ALG algorithm socket, set the key, and
allocate a request socket for every block.  Can any of this be cached?  For
single threaded use, it seems the request socket can be cached; otherwise the
algorithm socket with a key set can be cached.

- Eric

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

* Re: [f2fs-dev] [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
@ 2020-10-07 21:52     ` Eric Biggers
  0 siblings, 0 replies; 18+ messages in thread
From: Eric Biggers @ 2020-10-07 21:52 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Jaegeuk Kim, linux-fscrypt, linux-f2fs-devel

On Mon, Oct 05, 2020 at 07:41:33AM +0000, Satya Tangirala wrote:
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 871d773..a82d753 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 -version-info $(LIBF2FS_CURRENT):$(LIBF2FS_REVISION):$(LIBF2FS_AGE)

This introduces a dependency on libkeyutils.  Doesn't that need to be checked in
configure.ac?

> diff --git a/lib/f2fs_metadata_crypt.c b/lib/f2fs_metadata_crypt.c
> new file mode 100644
> index 0000000..faf399a
> --- /dev/null
> +++ b/lib/f2fs_metadata_crypt.c
> @@ -0,0 +1,226 @@
> +/**
> + * 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 <keyutils.h>
> +
> +#include "f2fs_fs.h"
> +#include "f2fs_metadata_crypt.h"
> +
> +extern struct f2fs_configuration c;
> +struct f2fs_crypt_mode {
> +	const char *friendly_name;
> +	const char *cipher_str;
> +	unsigned int keysize;
> +	unsigned int ivlen;
> +} f2fs_crypt_modes[] = {

Use 'const' for static or global data that isn't modified.

> +void f2fs_print_crypt_algs(void)
> +{
> +	int i;
> +
> +	for (i = 1; i <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
> +		if (f2fs_crypt_modes[i].friendly_name &&
> +		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
> +			return i;
> +		}
> +	}
> +
> +	return 0;
> +}

Although __FSCRYPT_MODE_MAX is defined in <linux/fscrypt.h>, it isn't intended
to be used in userspace programs, as its value will change depending on the
version of the kernel headers.  Just use ARRAY_SIZE(f2fs_crypt_modes) instead.

> +int f2fs_metadata_crypt_block(void *buf, size_t len, __u64 blk_addr,
> +			      bool encrypt)
> +{
> +	struct f2fs_crypt_mode *crypt_mode;
> +	int sockfd, fd;
> +	struct sockaddr_alg sa = {
> +		.salg_family = AF_ALG,
> +		.salg_type = "skcipher",
> +	};
> +	struct msghdr msg = {};
> +	struct cmsghdr *cmsg;
> +	char cbuf[CMSG_SPACE(4) + CMSG_SPACE(4 + MAX_IV_LEN)] = {0};
> +	int blk_offset;
> +	struct af_alg_iv *iv;
> +	struct iovec iov;
> +	int err;
> +
> +	crypt_mode = &f2fs_crypt_modes[c.metadata_crypt_alg];
> +	memcpy(sa.salg_name, crypt_mode->cipher_str,
> +	       strlen(crypt_mode->cipher_str));
> +
> +	sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
> +	if (sockfd < 0)
> +		return errno;

This will fail if AF_ALG isn't enabled in the kernel config, or if the process
isn't allowed to use AF_ALG by SELinux policy.  Can you show a proper error
message?

> +	err = bind(sockfd, (struct sockaddr *)&sa, sizeof(sa));
> +	if (err) {
> +		MSG(0, "\tCouldn't bind crypto socket. Maybe support for the crypto algorithm isn't enabled?\n");
> +		close(sockfd);
> +		return errno;
> +	}

This will fail if either CRYPTO_USER_API_SKCIPHER isn't enabled in the kernel
config, or if the required crypto algorithm isn't enabled in the kernel config.
Can you show a better error message?

Also, these new kernel config option dependencies should be documented in the
documentation for f2fs-tools.

> +	err = setsockopt(sockfd, SOL_ALG, ALG_SET_KEY, c.metadata_crypt_key,
> +			 crypt_mode->keysize);
> +	if (err) {
> +		MSG(0, "\tCouldn't set crypto socket options.\n");
> +		close(sockfd);
> +		return errno;
> +	}
> +	fd = accept(sockfd, NULL, 0);
> +	if (fd < 0)
> +		goto err_out;

It's a lot of work to allocate an AF_ALG algorithm socket, set the key, and
allocate a request socket for every block.  Can any of this be cached?  For
single threaded use, it seems the request socket can be cached; otherwise the
algorithm socket with a key set can be cached.

- Eric


_______________________________________________
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] 18+ messages in thread

* Re: [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
  2020-10-07 19:42     ` [f2fs-dev] " jaegeuk
@ 2020-12-17 16:04       ` Satya Tangirala via Linux-f2fs-devel
  -1 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala @ 2020-12-17 16:04 UTC (permalink / raw)
  To: jaegeuk; +Cc: Eric Biggers, linux-f2fs-devel, linux-fscrypt

On Wed, Oct 07, 2020 at 12:42:09PM -0700, jaegeuk@kernel.org wrote:
> Hi Satya,
> 
> On 10/05, Satya Tangirala wrote:
> > This patch introduces two new options '-A' and '-M' for specifying metadata
> > crypt options. '-A' takes the desired metadata encryption algorithm as
> > argument. '-M' takes the linux key_serial of the metadata encryption key as
> > the argument. The keyring key provided must be of a key type that supports
> > reading the payload from userspace.
> 
> Could you please update manpages as well?
> 
Done
> > diff --git a/lib/f2fs_metadata_crypt.c b/lib/f2fs_metadata_crypt.c
> > new file mode 100644
> > index 0000000..faf399a
> > --- /dev/null
> > +++ b/lib/f2fs_metadata_crypt.c
> > @@ -0,0 +1,226 @@
> > +/**
> > + * 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 <keyutils.h>
> > +
> > +#include "f2fs_fs.h"
> > +#include "f2fs_metadata_crypt.h"
> > +
> > +extern struct f2fs_configuration c;
> > +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 <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
> > +		if (f2fs_crypt_modes[i].friendly_name &&
> > +		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
> > +			return i;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int f2fs_metadata_process_key(const char *key_serial_str)
> > +{
> > +	key_serial_t key_serial = strtol(key_serial_str, NULL, 10);
> > +
> > +	c.metadata_crypt_key_len =
> > +		keyctl_read_alloc(key_serial, (void **)&c.metadata_crypt_key);
> > +
> > +	if (c.metadata_crypt_key_len < 0)
> > +		return errno;
> > +
> > +	return 0;
> > +}
> > +
> > +int f2fs_metadata_verify_args(void)
> > +{
> > +	/* 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_key_len !=
> > +	    f2fs_crypt_modes[c.metadata_crypt_alg].keysize) {
> > +		MSG(0, "\tMetadata encryption key length %d didn't match required size %d\n",
> > +		    c.metadata_crypt_key_len,
> > +		    f2fs_crypt_modes[c.metadata_crypt_alg].keysize);
> > +
> > +		return -EINVAL;
> > +	}
> 
> Need to check sparse mode here?
> 
I tried to support sparse mode with metadata encryption in v2 (that I
just sent out), but I haven't been able to even compile or test it yet.
Would you happen to know where I might find some info on how to compile
and test sparse mode?
> And, what about multiple partition case?
> 
IIUC I think multiple devices are handled correctly by the code - is there
something I'm missing?
> > @@ -138,6 +147,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 +195,12 @@ static void f2fs_parse_options(int argc, char *argv[])
> >  		case 'm':
> >  			c.zoned_mode = 1;
> >  			break;
> > +		case 'M':
> > +			if (f2fs_metadata_process_key(optarg)) {
> > +				MSG(0, "Error: Invalid metadata key\n");
> > +				mkfs_usage();
> > +			}
> > +			break;
> >  		case 'o':
> >  			c.overprovision = atof(optarg);
> >  			break;
> > @@ -244,6 +267,14 @@ static void f2fs_parse_options(int argc, char *argv[])
> >  		}
> >  	}
> >  
> > +	if ((!!c.metadata_crypt_key) != (!!c.metadata_crypt_alg)) {
> > +		MSG(0, "\tError: Both the metadata crypt key and crypt algorithm must be specified!");
> > +		exit(1);
> > +	}
> > +
> > +	if (f2fs_metadata_verify_args())
> > +		exit(1);
> > +
> >  	add_default_options();
> 
> Need to check options after add_default_options()?
> 
As in, you're suggesting moving the metadata_crypt_key and
metadata_crypt_alg check and the 
+ if (f2fs_metadata_verify_args())
to below the add_default_options() call? If so, I'll do that in v3 of
this patch series
> Thanks,
> 
> >  
> >  	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
> > -- 
> > 2.28.0.806.g8561365e88-goog

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

* Re: [f2fs-dev] [PATCH 1/1] f2fs-tools: Introduce metadata encryption support
@ 2020-12-17 16:04       ` Satya Tangirala via Linux-f2fs-devel
  0 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-12-17 16:04 UTC (permalink / raw)
  To: jaegeuk; +Cc: Eric Biggers, linux-fscrypt, linux-f2fs-devel

On Wed, Oct 07, 2020 at 12:42:09PM -0700, jaegeuk@kernel.org wrote:
> Hi Satya,
> 
> On 10/05, Satya Tangirala wrote:
> > This patch introduces two new options '-A' and '-M' for specifying metadata
> > crypt options. '-A' takes the desired metadata encryption algorithm as
> > argument. '-M' takes the linux key_serial of the metadata encryption key as
> > the argument. The keyring key provided must be of a key type that supports
> > reading the payload from userspace.
> 
> Could you please update manpages as well?
> 
Done
> > diff --git a/lib/f2fs_metadata_crypt.c b/lib/f2fs_metadata_crypt.c
> > new file mode 100644
> > index 0000000..faf399a
> > --- /dev/null
> > +++ b/lib/f2fs_metadata_crypt.c
> > @@ -0,0 +1,226 @@
> > +/**
> > + * 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 <keyutils.h>
> > +
> > +#include "f2fs_fs.h"
> > +#include "f2fs_metadata_crypt.h"
> > +
> > +extern struct f2fs_configuration c;
> > +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 <= __FSCRYPT_MODE_MAX; 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 <= __FSCRYPT_MODE_MAX; i++) {
> > +		if (f2fs_crypt_modes[i].friendly_name &&
> > +		    !strcmp(f2fs_crypt_modes[i].friendly_name, optarg)) {
> > +			return i;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int f2fs_metadata_process_key(const char *key_serial_str)
> > +{
> > +	key_serial_t key_serial = strtol(key_serial_str, NULL, 10);
> > +
> > +	c.metadata_crypt_key_len =
> > +		keyctl_read_alloc(key_serial, (void **)&c.metadata_crypt_key);
> > +
> > +	if (c.metadata_crypt_key_len < 0)
> > +		return errno;
> > +
> > +	return 0;
> > +}
> > +
> > +int f2fs_metadata_verify_args(void)
> > +{
> > +	/* 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_key_len !=
> > +	    f2fs_crypt_modes[c.metadata_crypt_alg].keysize) {
> > +		MSG(0, "\tMetadata encryption key length %d didn't match required size %d\n",
> > +		    c.metadata_crypt_key_len,
> > +		    f2fs_crypt_modes[c.metadata_crypt_alg].keysize);
> > +
> > +		return -EINVAL;
> > +	}
> 
> Need to check sparse mode here?
> 
I tried to support sparse mode with metadata encryption in v2 (that I
just sent out), but I haven't been able to even compile or test it yet.
Would you happen to know where I might find some info on how to compile
and test sparse mode?
> And, what about multiple partition case?
> 
IIUC I think multiple devices are handled correctly by the code - is there
something I'm missing?
> > @@ -138,6 +147,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 +195,12 @@ static void f2fs_parse_options(int argc, char *argv[])
> >  		case 'm':
> >  			c.zoned_mode = 1;
> >  			break;
> > +		case 'M':
> > +			if (f2fs_metadata_process_key(optarg)) {
> > +				MSG(0, "Error: Invalid metadata key\n");
> > +				mkfs_usage();
> > +			}
> > +			break;
> >  		case 'o':
> >  			c.overprovision = atof(optarg);
> >  			break;
> > @@ -244,6 +267,14 @@ static void f2fs_parse_options(int argc, char *argv[])
> >  		}
> >  	}
> >  
> > +	if ((!!c.metadata_crypt_key) != (!!c.metadata_crypt_alg)) {
> > +		MSG(0, "\tError: Both the metadata crypt key and crypt algorithm must be specified!");
> > +		exit(1);
> > +	}
> > +
> > +	if (f2fs_metadata_verify_args())
> > +		exit(1);
> > +
> >  	add_default_options();
> 
> Need to check options after add_default_options()?
> 
As in, you're suggesting moving the metadata_crypt_key and
metadata_crypt_alg check and the 
+ if (f2fs_metadata_verify_args())
to below the add_default_options() call? If so, I'll do that in v3 of
this patch series
> Thanks,
> 
> >  
> >  	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
> > -- 
> > 2.28.0.806.g8561365e88-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] 18+ messages in thread

* Re: [PATCH 0/1] userspace support for F2FS metadata encryption
  2020-10-05  7:41 ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
@ 2020-12-17 16:23   ` Jaegeuk Kim
  -1 siblings, 0 replies; 18+ messages in thread
From: Jaegeuk Kim @ 2020-12-17 16:23 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Eric Biggers, linux-f2fs-devel, linux-fscrypt

Hi Satya,

Could you please consider to rebase the patches on f2fs-tools/dev branch?
I've applied compression support which will have some conflicts with this
series. And, could you check this works with multi-partition support?

Thanks,

On 10/05, Satya Tangirala wrote:
> The kernel patches for F2FS metadata encryption are at:
> 
> https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> 
> This patch 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.
> 
> This patch introduces two new options for the userspace tools: '-A' to
> specify the encryption algorithm, and '-M' to specify the encryption key.
> mkfs.f2fs will store the encryption algorithm used for metadata encryption
> in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> of the tools only take the '-M' option, and will obtain the encryption
> algorithm from the superblock of the FS.
> 
> Limitations: 
> Metadata encryption with sparse storage has not been implemented yet in
> this patch.
> 
> 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.
> 
> Satya Tangirala (1):
>   f2fs-tools: Introduce metadata encryption support
> 
>  fsck/main.c                   |  47 ++++++-
>  fsck/mount.c                  |  33 ++++-
>  include/f2fs_fs.h             |  10 +-
>  include/f2fs_metadata_crypt.h |  21 ++++
>  lib/Makefile.am               |   4 +-
>  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
>  lib/libf2fs_io.c              |  87 +++++++++++--
>  mkfs/f2fs_format.c            |   5 +-
>  mkfs/f2fs_format_main.c       |  33 ++++-
>  9 files changed, 446 insertions(+), 20 deletions(-)
>  create mode 100644 include/f2fs_metadata_crypt.h
>  create mode 100644 lib/f2fs_metadata_crypt.c
> 
> -- 
> 2.28.0.806.g8561365e88-goog

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

* Re: [f2fs-dev] [PATCH 0/1] userspace support for F2FS metadata encryption
@ 2020-12-17 16:23   ` Jaegeuk Kim
  0 siblings, 0 replies; 18+ messages in thread
From: Jaegeuk Kim @ 2020-12-17 16:23 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Eric Biggers, linux-fscrypt, linux-f2fs-devel

Hi Satya,

Could you please consider to rebase the patches on f2fs-tools/dev branch?
I've applied compression support which will have some conflicts with this
series. And, could you check this works with multi-partition support?

Thanks,

On 10/05, Satya Tangirala wrote:
> The kernel patches for F2FS metadata encryption are at:
> 
> https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> 
> This patch 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.
> 
> This patch introduces two new options for the userspace tools: '-A' to
> specify the encryption algorithm, and '-M' to specify the encryption key.
> mkfs.f2fs will store the encryption algorithm used for metadata encryption
> in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> of the tools only take the '-M' option, and will obtain the encryption
> algorithm from the superblock of the FS.
> 
> Limitations: 
> Metadata encryption with sparse storage has not been implemented yet in
> this patch.
> 
> 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.
> 
> Satya Tangirala (1):
>   f2fs-tools: Introduce metadata encryption support
> 
>  fsck/main.c                   |  47 ++++++-
>  fsck/mount.c                  |  33 ++++-
>  include/f2fs_fs.h             |  10 +-
>  include/f2fs_metadata_crypt.h |  21 ++++
>  lib/Makefile.am               |   4 +-
>  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
>  lib/libf2fs_io.c              |  87 +++++++++++--
>  mkfs/f2fs_format.c            |   5 +-
>  mkfs/f2fs_format_main.c       |  33 ++++-
>  9 files changed, 446 insertions(+), 20 deletions(-)
>  create mode 100644 include/f2fs_metadata_crypt.h
>  create mode 100644 lib/f2fs_metadata_crypt.c
> 
> -- 
> 2.28.0.806.g8561365e88-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] 18+ messages in thread

* Re: [PATCH 0/1] userspace support for F2FS metadata encryption
  2020-12-17 16:23   ` [f2fs-dev] " Jaegeuk Kim
@ 2020-12-18  6:41     ` Satya Tangirala via Linux-f2fs-devel
  -1 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala @ 2020-12-18  6:41 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: Eric Biggers, linux-f2fs-devel, linux-fscrypt

On Thu, Dec 17, 2020 at 08:23:18AM -0800, Jaegeuk Kim wrote:
> Hi Satya,
> 
> Could you please consider to rebase the patches on f2fs-tools/dev branch?
> I've applied compression support which will have some conflicts with this
> series. And, could you check this works with multi-partition support?
> 
Sure, I'll do that! I sent out v2 of this patch series earlier today,
so would you want me to send out a rebased version asap? or when
I send out v3?

Also, newbie question - multi-partition support is the same as
multi-device support, right?
> Thanks,
> 
> On 10/05, Satya Tangirala wrote:
> > The kernel patches for F2FS metadata encryption are at:
> > 
> > https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> > 
> > This patch 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.
> > 
> > This patch introduces two new options for the userspace tools: '-A' to
> > specify the encryption algorithm, and '-M' to specify the encryption key.
> > mkfs.f2fs will store the encryption algorithm used for metadata encryption
> > in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> > of the tools only take the '-M' option, and will obtain the encryption
> > algorithm from the superblock of the FS.
> > 
> > Limitations: 
> > Metadata encryption with sparse storage has not been implemented yet in
> > this patch.
> > 
> > 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.
> > 
> > Satya Tangirala (1):
> >   f2fs-tools: Introduce metadata encryption support
> > 
> >  fsck/main.c                   |  47 ++++++-
> >  fsck/mount.c                  |  33 ++++-
> >  include/f2fs_fs.h             |  10 +-
> >  include/f2fs_metadata_crypt.h |  21 ++++
> >  lib/Makefile.am               |   4 +-
> >  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
> >  lib/libf2fs_io.c              |  87 +++++++++++--
> >  mkfs/f2fs_format.c            |   5 +-
> >  mkfs/f2fs_format_main.c       |  33 ++++-
> >  9 files changed, 446 insertions(+), 20 deletions(-)
> >  create mode 100644 include/f2fs_metadata_crypt.h
> >  create mode 100644 lib/f2fs_metadata_crypt.c
> > 
> > -- 
> > 2.28.0.806.g8561365e88-goog

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

* Re: [f2fs-dev] [PATCH 0/1] userspace support for F2FS metadata encryption
@ 2020-12-18  6:41     ` Satya Tangirala via Linux-f2fs-devel
  0 siblings, 0 replies; 18+ messages in thread
From: Satya Tangirala via Linux-f2fs-devel @ 2020-12-18  6:41 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: Eric Biggers, linux-fscrypt, linux-f2fs-devel

On Thu, Dec 17, 2020 at 08:23:18AM -0800, Jaegeuk Kim wrote:
> Hi Satya,
> 
> Could you please consider to rebase the patches on f2fs-tools/dev branch?
> I've applied compression support which will have some conflicts with this
> series. And, could you check this works with multi-partition support?
> 
Sure, I'll do that! I sent out v2 of this patch series earlier today,
so would you want me to send out a rebased version asap? or when
I send out v3?

Also, newbie question - multi-partition support is the same as
multi-device support, right?
> Thanks,
> 
> On 10/05, Satya Tangirala wrote:
> > The kernel patches for F2FS metadata encryption are at:
> > 
> > https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> > 
> > This patch 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.
> > 
> > This patch introduces two new options for the userspace tools: '-A' to
> > specify the encryption algorithm, and '-M' to specify the encryption key.
> > mkfs.f2fs will store the encryption algorithm used for metadata encryption
> > in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> > of the tools only take the '-M' option, and will obtain the encryption
> > algorithm from the superblock of the FS.
> > 
> > Limitations: 
> > Metadata encryption with sparse storage has not been implemented yet in
> > this patch.
> > 
> > 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.
> > 
> > Satya Tangirala (1):
> >   f2fs-tools: Introduce metadata encryption support
> > 
> >  fsck/main.c                   |  47 ++++++-
> >  fsck/mount.c                  |  33 ++++-
> >  include/f2fs_fs.h             |  10 +-
> >  include/f2fs_metadata_crypt.h |  21 ++++
> >  lib/Makefile.am               |   4 +-
> >  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
> >  lib/libf2fs_io.c              |  87 +++++++++++--
> >  mkfs/f2fs_format.c            |   5 +-
> >  mkfs/f2fs_format_main.c       |  33 ++++-
> >  9 files changed, 446 insertions(+), 20 deletions(-)
> >  create mode 100644 include/f2fs_metadata_crypt.h
> >  create mode 100644 lib/f2fs_metadata_crypt.c
> > 
> > -- 
> > 2.28.0.806.g8561365e88-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] 18+ messages in thread

* Re: [PATCH 0/1] userspace support for F2FS metadata encryption
  2020-12-18  6:41     ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
@ 2020-12-18 16:19       ` Jaegeuk Kim
  -1 siblings, 0 replies; 18+ messages in thread
From: Jaegeuk Kim @ 2020-12-18 16:19 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Eric Biggers, linux-f2fs-devel, linux-fscrypt

On 12/18, Satya Tangirala wrote:
> On Thu, Dec 17, 2020 at 08:23:18AM -0800, Jaegeuk Kim wrote:
> > Hi Satya,
> > 
> > Could you please consider to rebase the patches on f2fs-tools/dev branch?
> > I've applied compression support which will have some conflicts with this
> > series. And, could you check this works with multi-partition support?
> > 
> Sure, I'll do that! I sent out v2 of this patch series earlier today,
> so would you want me to send out a rebased version asap? or when
> I send out v3?

Thank you. Please let me have the latest update like v3.

> 
> Also, newbie question - multi-partition support is the same as
> multi-device support, right?

Yes, right. :)

> > Thanks,
> > 
> > On 10/05, Satya Tangirala wrote:
> > > The kernel patches for F2FS metadata encryption are at:
> > > 
> > > https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> > > 
> > > This patch 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.
> > > 
> > > This patch introduces two new options for the userspace tools: '-A' to
> > > specify the encryption algorithm, and '-M' to specify the encryption key.
> > > mkfs.f2fs will store the encryption algorithm used for metadata encryption
> > > in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> > > of the tools only take the '-M' option, and will obtain the encryption
> > > algorithm from the superblock of the FS.
> > > 
> > > Limitations: 
> > > Metadata encryption with sparse storage has not been implemented yet in
> > > this patch.
> > > 
> > > 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.
> > > 
> > > Satya Tangirala (1):
> > >   f2fs-tools: Introduce metadata encryption support
> > > 
> > >  fsck/main.c                   |  47 ++++++-
> > >  fsck/mount.c                  |  33 ++++-
> > >  include/f2fs_fs.h             |  10 +-
> > >  include/f2fs_metadata_crypt.h |  21 ++++
> > >  lib/Makefile.am               |   4 +-
> > >  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
> > >  lib/libf2fs_io.c              |  87 +++++++++++--
> > >  mkfs/f2fs_format.c            |   5 +-
> > >  mkfs/f2fs_format_main.c       |  33 ++++-
> > >  9 files changed, 446 insertions(+), 20 deletions(-)
> > >  create mode 100644 include/f2fs_metadata_crypt.h
> > >  create mode 100644 lib/f2fs_metadata_crypt.c
> > > 
> > > -- 
> > > 2.28.0.806.g8561365e88-goog

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

* Re: [f2fs-dev] [PATCH 0/1] userspace support for F2FS metadata encryption
@ 2020-12-18 16:19       ` Jaegeuk Kim
  0 siblings, 0 replies; 18+ messages in thread
From: Jaegeuk Kim @ 2020-12-18 16:19 UTC (permalink / raw)
  To: Satya Tangirala; +Cc: Eric Biggers, linux-fscrypt, linux-f2fs-devel

On 12/18, Satya Tangirala wrote:
> On Thu, Dec 17, 2020 at 08:23:18AM -0800, Jaegeuk Kim wrote:
> > Hi Satya,
> > 
> > Could you please consider to rebase the patches on f2fs-tools/dev branch?
> > I've applied compression support which will have some conflicts with this
> > series. And, could you check this works with multi-partition support?
> > 
> Sure, I'll do that! I sent out v2 of this patch series earlier today,
> so would you want me to send out a rebased version asap? or when
> I send out v3?

Thank you. Please let me have the latest update like v3.

> 
> Also, newbie question - multi-partition support is the same as
> multi-device support, right?

Yes, right. :)

> > Thanks,
> > 
> > On 10/05, Satya Tangirala wrote:
> > > The kernel patches for F2FS metadata encryption are at:
> > > 
> > > https://lore.kernel.org/linux-fscrypt/20201005073606.1949772-4-satyat@google.com/
> > > 
> > > This patch 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.
> > > 
> > > This patch introduces two new options for the userspace tools: '-A' to
> > > specify the encryption algorithm, and '-M' to specify the encryption key.
> > > mkfs.f2fs will store the encryption algorithm used for metadata encryption
> > > in the superblock itself, so '-A' is only applicable to mkfs.f2fs. The rest
> > > of the tools only take the '-M' option, and will obtain the encryption
> > > algorithm from the superblock of the FS.
> > > 
> > > Limitations: 
> > > Metadata encryption with sparse storage has not been implemented yet in
> > > this patch.
> > > 
> > > 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.
> > > 
> > > Satya Tangirala (1):
> > >   f2fs-tools: Introduce metadata encryption support
> > > 
> > >  fsck/main.c                   |  47 ++++++-
> > >  fsck/mount.c                  |  33 ++++-
> > >  include/f2fs_fs.h             |  10 +-
> > >  include/f2fs_metadata_crypt.h |  21 ++++
> > >  lib/Makefile.am               |   4 +-
> > >  lib/f2fs_metadata_crypt.c     | 226 ++++++++++++++++++++++++++++++++++
> > >  lib/libf2fs_io.c              |  87 +++++++++++--
> > >  mkfs/f2fs_format.c            |   5 +-
> > >  mkfs/f2fs_format_main.c       |  33 ++++-
> > >  9 files changed, 446 insertions(+), 20 deletions(-)
> > >  create mode 100644 include/f2fs_metadata_crypt.h
> > >  create mode 100644 lib/f2fs_metadata_crypt.c
> > > 
> > > -- 
> > > 2.28.0.806.g8561365e88-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] 18+ messages in thread

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

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-05  7:41 [PATCH 0/1] userspace support for F2FS metadata encryption Satya Tangirala
2020-10-05  7:41 ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
2020-10-05  7:41 ` [PATCH 1/1] f2fs-tools: Introduce metadata encryption support Satya Tangirala
2020-10-05  7:41   ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
2020-10-07 19:42   ` jaegeuk
2020-10-07 19:42     ` [f2fs-dev] " jaegeuk
2020-12-17 16:04     ` Satya Tangirala
2020-12-17 16:04       ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
2020-10-07 21:52   ` Eric Biggers
2020-10-07 21:52     ` [f2fs-dev] " Eric Biggers
2020-10-07 21:39 ` [PATCH 0/1] userspace support for F2FS metadata encryption Eric Biggers
2020-10-07 21:39   ` [f2fs-dev] " Eric Biggers
2020-12-17 16:23 ` Jaegeuk Kim
2020-12-17 16:23   ` [f2fs-dev] " Jaegeuk Kim
2020-12-18  6:41   ` Satya Tangirala
2020-12-18  6:41     ` [f2fs-dev] " Satya Tangirala via Linux-f2fs-devel
2020-12-18 16:19     ` Jaegeuk Kim
2020-12-18 16:19       ` [f2fs-dev] " Jaegeuk Kim

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.