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@xxxxxxxxxx> > --- > 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