($INBOX_DIR/description missing)
 help / color / Atom feed
* [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io
@ 2019-08-12 17:56 Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 1/8] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

Hello,

This patchset updates xfs_io to support the API additions from the
kernel patchset "[PATCH v8 00/20] fscrypt: key management improvements"
https://lkml.kernel.org/linux-fsdevel/20190805162521.90882-1-ebiggers@kernel.org/T/#u

Commands are added to wrap the new ioctls for managing filesystem
encryption keys.  Also, the existing 'get_encpolicy' and 'set_encpolicy'
commands are updated to support v2 encryption policies.

The purpose of all this is to allow xfstests to test the new APIs.

Note: currently only ext4, f2fs, and ubifs support encryption.  But I
was told previously that since the fscrypt API is generic and may be
supported by XFS in the future, the command-line wrappers for the
fscrypt ioctls should be in xfs_io rather than in fstests directly
(https://marc.info/?l=fstests&m=147976255831951&w=2).

We'll want to wait for the kernel patches to be mainlined before merging
this, but I'm making it available now for any early feedback.

This patchset applies to xfsprogs v5.2.0.  It can also be retrieved from tag
"fscrypt-key-mgmt-improvements_2019-08-12" of
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/xfsprogs-dev.git

Eric Biggers (8):
  xfs_io/encrypt: remove unimplemented encryption modes
  xfs_io/encrypt: update to UAPI definitions from Linux v5.4
  xfs_io/encrypt: add new encryption modes
  xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies
  xfs_io/encrypt: extend 'set_encpolicy' to support v2 policies
  xfs_io/encrypt: add 'add_enckey' command
  xfs_io/encrypt: add 'rm_enckey' command
  xfs_io/encrypt: add 'enckey_status' command

 io/encrypt.c      | 786 ++++++++++++++++++++++++++++++++++++++++------
 man/man8/xfs_io.8 |  70 ++++-
 2 files changed, 750 insertions(+), 106 deletions(-)

-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 1/8] xfs_io/encrypt: remove unimplemented encryption modes
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
@ 2019-08-12 17:56 ` Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 2/8] xfs_io/encrypt: update to UAPI definitions from Linux v5.4 Eric Biggers
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Although mode numbers were originally reserved for AES-256-GCM and
AES-256-CBC, these were never implemented in the kernel, and there are
no plans to do so anymore.  These mode numbers may be used for something
else in the future.  Also, xfstests (the only known user of the xfs_io
encryption commands) doesn't try to use them.  Finally, most of the
fscrypt constants have been given new names in the UAPI header, but the
unused constants have not been given new names since userspace should
just stop referencing them instead.

So remove them from xfs_io.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/io/encrypt.c b/io/encrypt.c
index 8db35259..e8766dc1 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -49,8 +49,6 @@ struct fscrypt_policy {
 
 #define FS_ENCRYPTION_MODE_INVALID	0
 #define FS_ENCRYPTION_MODE_AES_256_XTS	1
-#define FS_ENCRYPTION_MODE_AES_256_GCM	2
-#define FS_ENCRYPTION_MODE_AES_256_CBC	3
 #define FS_ENCRYPTION_MODE_AES_256_CTS	4
 #endif /* FS_ENCRYPTION_MODE_AES_256_XTS */
 
@@ -74,7 +72,7 @@ set_encpolicy_help(void)
 " -v VERSION -- version of policy structure\n"
 "\n"
 " MODE can be numeric or one of the following predefined values:\n"
-"    AES-256-XTS, AES-256-CTS, AES-256-GCM, AES-256-CBC\n"
+"    AES-256-XTS, AES-256-CTS\n"
 " FLAGS and VERSION must be numeric.\n"
 "\n"
 " Note that it's only possible to set an encryption policy on an empty\n"
@@ -88,8 +86,6 @@ static const struct {
 } available_modes[] = {
 	{FS_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"},
 	{FS_ENCRYPTION_MODE_AES_256_CTS, "AES-256-CTS"},
-	{FS_ENCRYPTION_MODE_AES_256_GCM, "AES-256-GCM"},
-	{FS_ENCRYPTION_MODE_AES_256_CBC, "AES-256-CBC"},
 };
 
 static bool
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 2/8] xfs_io/encrypt: update to UAPI definitions from Linux v5.4
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 1/8] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
@ 2019-08-12 17:56 ` Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 3/8] xfs_io/encrypt: add new encryption modes Eric Biggers
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Update to the latest fscrypt UAPI definitions, including:

- New names for some existing definitions (FSCRYPT_ instead of FS_).
- New ioctls.
- New encryption mode numbers and flags.

This patch doesn't make any change to the program logic itself.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c | 160 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 122 insertions(+), 38 deletions(-)

diff --git a/io/encrypt.c b/io/encrypt.c
index e8766dc1..ac473ed7 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -15,42 +15,126 @@
 #endif
 
 /*
- * We may have to declare the fscrypt ioctls ourselves because someone may be
- * compiling xfsprogs with old kernel headers.  And since some old versions of
- * <linux/fs.h> declared the policy struct and ioctl numbers but not the flags
- * and modes, our declarations must be split into two conditional blocks.
+ * Declare the fscrypt ioctls if needed, since someone may be compiling xfsprogs
+ * with old kernel headers.  But <linux/fs.h> has already been included, so be
+ * careful not to declare things twice.
  */
 
-/* Policy struct and ioctl numbers */
+/* first batch of ioctls (Linux headers v4.6+) */
 #ifndef FS_IOC_SET_ENCRYPTION_POLICY
-#define FS_KEY_DESCRIPTOR_SIZE  8
+#define fscrypt_policy fscrypt_policy_v1
+#define FS_IOC_SET_ENCRYPTION_POLICY		_IOR('f', 19, struct fscrypt_policy)
+#define FS_IOC_GET_ENCRYPTION_PWSALT		_IOW('f', 20, __u8[16])
+#define FS_IOC_GET_ENCRYPTION_POLICY		_IOW('f', 21, struct fscrypt_policy)
+#endif
+
+/*
+ * Second batch of ioctls (Linux headers v5.4+), plus some renamings from FS_ to
+ * FSCRYPT_.  We don't bother defining the old names here.
+ */
+#ifndef FS_IOC_GET_ENCRYPTION_POLICY_EX
+
+#define FSCRYPT_POLICY_FLAGS_PAD_4		0x00
+#define FSCRYPT_POLICY_FLAGS_PAD_8		0x01
+#define FSCRYPT_POLICY_FLAGS_PAD_16		0x02
+#define FSCRYPT_POLICY_FLAGS_PAD_32		0x03
+#define FSCRYPT_POLICY_FLAGS_PAD_MASK		0x03
+#define FSCRYPT_POLICY_FLAG_DIRECT_KEY		0x04
+
+#define FSCRYPT_MODE_AES_256_XTS		1
+#define FSCRYPT_MODE_AES_256_CTS		4
+#define FSCRYPT_MODE_AES_128_CBC		5
+#define FSCRYPT_MODE_AES_128_CTS		6
+#define FSCRYPT_MODE_ADIANTUM			9
+
+/*
+ * In the headers for Linux v4.6 through v5.3, 'struct fscrypt_policy_v1' is
+ * already defined under its old name, 'struct fscrypt_policy'.  But it's fine
+ * to define it under its new name too.
+ *
+ * Note: "v1" policies really are version "0" in the API.
+ */
+#define FSCRYPT_POLICY_V1		0
+#define FSCRYPT_KEY_DESCRIPTOR_SIZE	8
+struct fscrypt_policy_v1 {
+	__u8 version;
+	__u8 contents_encryption_mode;
+	__u8 filenames_encryption_mode;
+	__u8 flags;
+	__u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
+};
 
-struct fscrypt_policy {
+#define FSCRYPT_POLICY_V2		2
+#define FSCRYPT_KEY_IDENTIFIER_SIZE	16
+struct fscrypt_policy_v2 {
 	__u8 version;
 	__u8 contents_encryption_mode;
 	__u8 filenames_encryption_mode;
 	__u8 flags;
-	__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
-} __attribute__((packed));
-
-#define FS_IOC_SET_ENCRYPTION_POLICY	_IOR('f', 19, struct fscrypt_policy)
-#define FS_IOC_GET_ENCRYPTION_PWSALT	_IOW('f', 20, __u8[16])
-#define FS_IOC_GET_ENCRYPTION_POLICY	_IOW('f', 21, struct fscrypt_policy)
-#endif /* FS_IOC_SET_ENCRYPTION_POLICY */
-
-/* Policy flags and encryption modes */
-#ifndef FS_ENCRYPTION_MODE_AES_256_XTS
-#define FS_POLICY_FLAGS_PAD_4		0x00
-#define FS_POLICY_FLAGS_PAD_8		0x01
-#define FS_POLICY_FLAGS_PAD_16		0x02
-#define FS_POLICY_FLAGS_PAD_32		0x03
-#define FS_POLICY_FLAGS_PAD_MASK	0x03
-#define FS_POLICY_FLAGS_VALID		0x03
-
-#define FS_ENCRYPTION_MODE_INVALID	0
-#define FS_ENCRYPTION_MODE_AES_256_XTS	1
-#define FS_ENCRYPTION_MODE_AES_256_CTS	4
-#endif /* FS_ENCRYPTION_MODE_AES_256_XTS */
+	__u8 __reserved[4];
+	__u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
+};
+
+#define FSCRYPT_MAX_KEY_SIZE		64
+
+#define FS_IOC_GET_ENCRYPTION_POLICY_EX		_IOWR('f', 22, __u8[9]) /* size + version */
+struct fscrypt_get_policy_ex_arg {
+	__u64 policy_size; /* input/output */
+	union {
+		__u8 version;
+		struct fscrypt_policy_v1 v1;
+		struct fscrypt_policy_v2 v2;
+	} policy; /* output */
+};
+
+#define FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR	1
+#define FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER	2
+struct fscrypt_key_specifier {
+	__u32 type;	/* one of FSCRYPT_KEY_SPEC_TYPE_* */
+	__u32 __reserved;
+	union {
+		__u8 __reserved[32]; /* reserve some extra space */
+		__u8 descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
+		__u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
+	} u;
+};
+
+#define FS_IOC_ADD_ENCRYPTION_KEY		_IOWR('f', 23, struct fscrypt_add_key_arg)
+struct fscrypt_add_key_arg {
+	struct fscrypt_key_specifier key_spec;
+	__u32 raw_size;
+	__u32 __reserved[9];
+	__u8 raw[];
+};
+
+#define FS_IOC_REMOVE_ENCRYPTION_KEY		_IOWR('f', 24, struct fscrypt_remove_key_arg)
+#define FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS	_IOWR('f', 25, struct fscrypt_remove_key_arg)
+struct fscrypt_remove_key_arg {
+	struct fscrypt_key_specifier key_spec;
+#define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY	0x00000001
+#define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS	0x00000002
+	__u32 removal_status_flags;	/* output */
+	__u32 __reserved[5];
+};
+
+#define FS_IOC_GET_ENCRYPTION_KEY_STATUS	_IOWR('f', 26, struct fscrypt_get_key_status_arg)
+struct fscrypt_get_key_status_arg {
+	/* input */
+	struct fscrypt_key_specifier key_spec;
+	__u32 __reserved[6];
+
+	/* output */
+#define FSCRYPT_KEY_STATUS_ABSENT		1
+#define FSCRYPT_KEY_STATUS_PRESENT		2
+#define FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED	3
+	__u32 status;
+#define FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF   0x00000001
+	__u32 status_flags;
+	__u32 user_count;
+	__u32 __out_reserved[13];
+};
+
+#endif /* !FS_IOC_GET_ENCRYPTION_POLICY_EX */
 
 static cmdinfo_t get_encpolicy_cmd;
 static cmdinfo_t set_encpolicy_cmd;
@@ -84,8 +168,8 @@ static const struct {
 	__u8 mode;
 	const char *name;
 } available_modes[] = {
-	{FS_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"},
-	{FS_ENCRYPTION_MODE_AES_256_CTS, "AES-256-CTS"},
+	{FSCRYPT_MODE_AES_256_XTS, "AES-256-XTS"},
+	{FSCRYPT_MODE_AES_256_CTS, "AES-256-CTS"},
 };
 
 static bool
@@ -131,12 +215,12 @@ mode2str(__u8 mode)
 }
 
 static const char *
-keydesc2str(__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE])
+keydesc2str(__u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE])
 {
-	static char buf[2 * FS_KEY_DESCRIPTOR_SIZE + 1];
+	static char buf[2 * FSCRYPT_KEY_DESCRIPTOR_SIZE + 1];
 	int i;
 
-	for (i = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++)
+	for (i = 0; i < FSCRYPT_KEY_DESCRIPTOR_SIZE; i++)
 		sprintf(&buf[2 * i], "%02x", master_key_descriptor[i]);
 
 	return buf;
@@ -176,9 +260,9 @@ set_encpolicy_f(int argc, char **argv)
 
 	/* Initialize the policy structure with default values */
 	memset(&policy, 0, sizeof(policy));
-	policy.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
-	policy.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
-	policy.flags = FS_POLICY_FLAGS_PAD_16;
+	policy.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+	policy.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+	policy.flags = FSCRYPT_POLICY_FLAGS_PAD_16;
 
 	/* Parse options */
 	while ((c = getopt(argc, argv, "c:n:f:v:")) != EOF) {
@@ -229,7 +313,7 @@ set_encpolicy_f(int argc, char **argv)
 		unsigned long long x;
 		int i;
 
-		if (strlen(keydesc) != FS_KEY_DESCRIPTOR_SIZE * 2) {
+		if (strlen(keydesc) != FSCRYPT_KEY_DESCRIPTOR_SIZE * 2) {
 			fprintf(stderr, "invalid key descriptor: %s\n",
 				keydesc);
 			return 0;
@@ -242,7 +326,7 @@ set_encpolicy_f(int argc, char **argv)
 			return 0;
 		}
 
-		for (i = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++) {
+		for (i = 0; i < FSCRYPT_KEY_DESCRIPTOR_SIZE; i++) {
 			policy.master_key_descriptor[i] = x >> 56;
 			x <<= 8;
 		}
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 3/8] xfs_io/encrypt: add new encryption modes
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 1/8] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 2/8] xfs_io/encrypt: update to UAPI definitions from Linux v5.4 Eric Biggers
@ 2019-08-12 17:56 ` Eric Biggers
  2019-09-24 22:47   ` Darrick J. Wong
  2019-08-12 17:56 ` [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies Eric Biggers
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Add new encryption modes: AES-128-CBC and AES-128-CTS (supported since
Linux v4.11), and Adiantum (supported since Linux v5.0).

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/io/encrypt.c b/io/encrypt.c
index ac473ed7..11eb4a3e 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -156,7 +156,7 @@ set_encpolicy_help(void)
 " -v VERSION -- version of policy structure\n"
 "\n"
 " MODE can be numeric or one of the following predefined values:\n"
-"    AES-256-XTS, AES-256-CTS\n"
+"    AES-256-XTS, AES-256-CTS, AES-128-CBC, AES-128-CTS, Adiantum\n"
 " FLAGS and VERSION must be numeric.\n"
 "\n"
 " Note that it's only possible to set an encryption policy on an empty\n"
@@ -170,6 +170,9 @@ static const struct {
 } available_modes[] = {
 	{FSCRYPT_MODE_AES_256_XTS, "AES-256-XTS"},
 	{FSCRYPT_MODE_AES_256_CTS, "AES-256-CTS"},
+	{FSCRYPT_MODE_AES_128_CBC, "AES-128-CBC"},
+	{FSCRYPT_MODE_AES_128_CTS, "AES-128-CTS"},
+	{FSCRYPT_MODE_ADIANTUM, "Adiantum"},
 };
 
 static bool
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (2 preceding siblings ...)
  2019-08-12 17:56 ` [RFC PATCH 3/8] xfs_io/encrypt: add new encryption modes Eric Biggers
@ 2019-08-12 17:56 ` Eric Biggers
  2019-09-25 17:23   ` Eric Sandeen
  2019-08-12 17:56 ` [RFC PATCH 5/8] xfs_io/encrypt: extend 'set_encpolicy' " Eric Biggers
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

get_encpolicy uses the FS_IOC_GET_ENCRYPTION_POLICY ioctl to retrieve
the file's encryption policy, then displays it.  But that only works for
v1 encryption policies.  A new ioctl, FS_IOC_GET_ENCRYPTION_POLICY_EX,
has been introduced which is more flexible and can retrieve both v1 and
v2 encryption policies.

Make get_encpolicy use the new ioctl if the kernel supports it and
display the resulting the v1 or v2 encryption policy.  Otherwise, fall
back to the old ioctl and display the v1 policy.

Also add new options:

  -1: Use the old ioctl only.  This will be used to test the old ioctl
      even when the kernel supports the new one.

  -t: Test whether the new ioctl is supported.  This will be useful to
      determine whether v2 policies should be tested or not.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c      | 150 +++++++++++++++++++++++++++++++++++++++++-----
 man/man8/xfs_io.8 |  15 ++++-
 2 files changed, 147 insertions(+), 18 deletions(-)

diff --git a/io/encrypt.c b/io/encrypt.c
index 11eb4a3e..5b92cfae 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2016 Google, Inc.  All Rights Reserved.
+ * Copyright 2016, 2019 Google LLC
  * Author: Eric Biggers <ebiggers@google.com>
  */
 
@@ -139,6 +139,20 @@ struct fscrypt_get_key_status_arg {
 static cmdinfo_t get_encpolicy_cmd;
 static cmdinfo_t set_encpolicy_cmd;
 
+static void
+get_encpolicy_help(void)
+{
+	printf(_(
+"\n"
+" display the encryption policy of the current file\n"
+"\n"
+" -1 -- Use only the old ioctl to get the encryption policy.\n"
+"       This only works if the file has a v1 encryption policy.\n"
+" -t -- Test whether v2 encryption policies are supported.\n"
+"       Prints \"supported\", \"unsupported\", or an error message.\n"
+"\n"));
+}
+
 static void
 set_encpolicy_help(void)
 {
@@ -218,7 +232,7 @@ mode2str(__u8 mode)
 }
 
 static const char *
-keydesc2str(__u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE])
+keydesc2str(const __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE])
 {
 	static char buf[2 * FSCRYPT_KEY_DESCRIPTOR_SIZE + 1];
 	int i;
@@ -229,29 +243,131 @@ keydesc2str(__u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE])
 	return buf;
 }
 
+static const char *
+keyid2str(const __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+{
+	static char buf[2 * FSCRYPT_KEY_IDENTIFIER_SIZE + 1];
+	int i;
+
+	for (i = 0; i < FSCRYPT_KEY_IDENTIFIER_SIZE; i++)
+		sprintf(&buf[2 * i], "%02x", master_key_identifier[i]);
+
+	return buf;
+}
+
+static void
+test_for_v2_policy_support(void)
+{
+	struct fscrypt_get_policy_ex_arg arg;
+
+	arg.policy_size = sizeof(arg.policy);
+
+	if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg) == 0 ||
+	    errno == ENODATA /* file unencrypted */) {
+		printf("supported\n");
+		return;
+	}
+	if (errno == ENOTTY) {
+		printf("unsupported\n");
+		return;
+	}
+	fprintf(stderr,
+		"%s: unexpected error checking for FS_IOC_GET_ENCRYPTION_POLICY_EX support: %s\n",
+		file->name, strerror(errno));
+	exitcode = 1;
+}
+
+static void
+show_v1_encryption_policy(const struct fscrypt_policy_v1 *policy)
+{
+	printf("Encryption policy for %s:\n", file->name);
+	printf("\tPolicy version: %u\n", policy->version);
+	printf("\tMaster key descriptor: %s\n",
+	       keydesc2str(policy->master_key_descriptor));
+	printf("\tContents encryption mode: %u (%s)\n",
+	       policy->contents_encryption_mode,
+	       mode2str(policy->contents_encryption_mode));
+	printf("\tFilenames encryption mode: %u (%s)\n",
+	       policy->filenames_encryption_mode,
+	       mode2str(policy->filenames_encryption_mode));
+	printf("\tFlags: 0x%02x\n", policy->flags);
+}
+
+static void
+show_v2_encryption_policy(const struct fscrypt_policy_v2 *policy)
+{
+	printf("Encryption policy for %s:\n", file->name);
+	printf("\tPolicy version: %u\n", policy->version);
+	printf("\tMaster key identifier: %s\n",
+	       keyid2str(policy->master_key_identifier));
+	printf("\tContents encryption mode: %u (%s)\n",
+	       policy->contents_encryption_mode,
+	       mode2str(policy->contents_encryption_mode));
+	printf("\tFilenames encryption mode: %u (%s)\n",
+	       policy->filenames_encryption_mode,
+	       mode2str(policy->filenames_encryption_mode));
+	printf("\tFlags: 0x%02x\n", policy->flags);
+}
+
 static int
 get_encpolicy_f(int argc, char **argv)
 {
-	struct fscrypt_policy policy;
+	int c;
+	struct fscrypt_get_policy_ex_arg arg;
+	bool only_use_v1_ioctl = false;
+	int res;
 
-	if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) < 0) {
+	while ((c = getopt(argc, argv, "1t")) != EOF) {
+		switch (c) {
+		case '1':
+			only_use_v1_ioctl = true;
+			break;
+		case 't':
+			test_for_v2_policy_support();
+			return 0;
+		default:
+			return command_usage(&get_encpolicy_cmd);
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 0)
+		return command_usage(&get_encpolicy_cmd);
+
+	/* first try the new ioctl */
+	if (only_use_v1_ioctl) {
+		res = -1;
+		errno = ENOTTY;
+	} else {
+		arg.policy_size = sizeof(arg.policy);
+		res = ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
+	}
+
+	/* fall back to the old ioctl */
+	if (res != 0 && errno == ENOTTY)
+		res = ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY,
+			    &arg.policy.v1);
+
+	if (res != 0) {
 		fprintf(stderr, "%s: failed to get encryption policy: %s\n",
 			file->name, strerror(errno));
 		exitcode = 1;
 		return 0;
 	}
 
-	printf("Encryption policy for %s:\n", file->name);
-	printf("\tPolicy version: %u\n", policy.version);
-	printf("\tMaster key descriptor: %s\n",
-	       keydesc2str(policy.master_key_descriptor));
-	printf("\tContents encryption mode: %u (%s)\n",
-	       policy.contents_encryption_mode,
-	       mode2str(policy.contents_encryption_mode));
-	printf("\tFilenames encryption mode: %u (%s)\n",
-	       policy.filenames_encryption_mode,
-	       mode2str(policy.filenames_encryption_mode));
-	printf("\tFlags: 0x%02x\n", policy.flags);
+	switch (arg.policy.version) {
+	case FSCRYPT_POLICY_V1:
+		show_v1_encryption_policy(&arg.policy.v1);
+		break;
+	case FSCRYPT_POLICY_V2:
+		show_v2_encryption_policy(&arg.policy.v2);
+		break;
+	default:
+		printf("Encryption policy for %s:\n", file->name);
+		printf("\tPolicy version: %u (unknown)\n", arg.policy.version);
+		break;
+	}
 	return 0;
 }
 
@@ -351,11 +467,13 @@ encrypt_init(void)
 {
 	get_encpolicy_cmd.name = "get_encpolicy";
 	get_encpolicy_cmd.cfunc = get_encpolicy_f;
+	get_encpolicy_cmd.args = _("[-1] [-t]");
 	get_encpolicy_cmd.argmin = 0;
-	get_encpolicy_cmd.argmax = 0;
+	get_encpolicy_cmd.argmax = -1;
 	get_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
 	get_encpolicy_cmd.oneline =
 		_("display the encryption policy of the current file");
+	get_encpolicy_cmd.help = get_encpolicy_help;
 
 	set_encpolicy_cmd.name = "set_encpolicy";
 	set_encpolicy_cmd.cfunc = set_encpolicy_f;
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 6e064bdd..3dd34a0c 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -724,10 +724,21 @@ version of policy structure (numeric)
 .RE
 .PD
 .TP
-.BR get_encpolicy
+.BI "get_encpolicy [ \-1 ] [ \-t ]"
 On filesystems that support encryption, display the encryption policy of the
 current file.
-
+.RS 1.0i
+.PD 0
+.TP 0.4i
+.BI \-1
+Use only the old ioctl to get the encryption policy.  This only works if the
+file has a v1 encryption policy.
+.TP
+.BI \-t
+Test whether v2 encryption policies are supported.  Prints "supported",
+"unsupported", or an error message.
+.RE
+.PD
 .TP
 .BR lsattr " [ " \-R " | " \-D " | " \-a " | " \-v " ]"
 List extended inode flags on the currently open file. If the
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 5/8] xfs_io/encrypt: extend 'set_encpolicy' to support v2 policies
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (3 preceding siblings ...)
  2019-08-12 17:56 ` [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies Eric Biggers
@ 2019-08-12 17:56 ` " Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 6/8] xfs_io/encrypt: add 'add_enckey' command Eric Biggers
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Extend the 'set_encpolicy' xfs_io command to support setting v2
encryption policies, in addition to v1 encryption policies which it
currently supports.  This uses the same ioctl, where the 'version' field
at the beginning of the struct is used to determine whether the struct
is fscrypt_policy_v1 or fscrypt_policy_v2.

The command sets a v2 policy when the user either gave the longer key
specification used in such policies (a 16-byte master_key_identifier
rather than an 8-byte master_key_descriptor), or passed '-v 2'.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c      | 228 ++++++++++++++++++++++++++++++++++++----------
 man/man8/xfs_io.8 |  19 +++-
 2 files changed, 194 insertions(+), 53 deletions(-)

diff --git a/io/encrypt.c b/io/encrypt.c
index 5b92cfae..f982cd17 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -161,13 +161,18 @@ set_encpolicy_help(void)
 " assign an encryption policy to the currently open file\n"
 "\n"
 " Examples:\n"
-" 'set_encpolicy' - assign policy with default key [0000000000000000]\n"
-" 'set_encpolicy 0000111122223333' - assign policy with specified key\n"
+" 'set_encpolicy' - assign v1 policy with default key descriptor\n"
+"                   (0000000000000000)\n"
+" 'set_encpolicy -v 2' - assign v2 policy with default key identifier\n"
+"                        (00000000000000000000000000000000)\n"
+" 'set_encpolicy 0000111122223333' - assign v1 policy with given key descriptor\n"
+" 'set_encpolicy 00001111222233334444555566667777' - assign v2 policy with given\n"
+"                                                    key identifier\n"
 "\n"
 " -c MODE -- contents encryption mode\n"
 " -n MODE -- filenames encryption mode\n"
 " -f FLAGS -- policy flags\n"
-" -v VERSION -- version of policy structure\n"
+" -v VERSION -- policy version\n"
 "\n"
 " MODE can be numeric or one of the following predefined values:\n"
 "    AES-256-XTS, AES-256-CTS, AES-128-CBC, AES-128-CTS, Adiantum\n"
@@ -231,6 +236,35 @@ mode2str(__u8 mode)
 	return buf;
 }
 
+static int
+hexchar2bin(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return 10 + (c - 'a');
+	if (c >= 'A' && c <= 'F')
+		return 10 + (c - 'A');
+	return -1;
+}
+
+static bool
+hex2bin(const char *hex, __u8 *bin, size_t bin_len)
+{
+	if (strlen(hex) != 2 * bin_len)
+		return false;
+
+	while (bin_len--) {
+		int hi = hexchar2bin(*hex++);
+		int lo = hexchar2bin(*hex++);
+
+		if (hi < 0 || lo < 0)
+			return false;
+		*bin++ = (hi << 4) | lo;
+	}
+	return true;
+}
+
 static const char *
 keydesc2str(const __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE])
 {
@@ -255,6 +289,92 @@ keyid2str(const __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
 	return buf;
 }
 
+static const char *
+keyspectype(const struct fscrypt_key_specifier *key_spec)
+{
+	switch (key_spec->type) {
+	case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
+		return "descriptor";
+	case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
+		return "identifier";
+	}
+	return "[unknown]";
+}
+
+static const char *
+keyspec2str(const struct fscrypt_key_specifier *key_spec)
+{
+	switch (key_spec->type) {
+	case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
+		return keydesc2str(key_spec->u.descriptor);
+	case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
+		return keyid2str(key_spec->u.identifier);
+	}
+	return "[unknown]";
+}
+
+static bool
+str2keydesc(const char *str,
+	    __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE])
+{
+	if (!hex2bin(str, master_key_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE)) {
+		fprintf(stderr, "invalid key descriptor: %s\n", str);
+		return false;
+	}
+	return true;
+}
+
+static bool
+str2keyid(const char *str,
+	  __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+{
+	if (!hex2bin(str, master_key_identifier, FSCRYPT_KEY_IDENTIFIER_SIZE)) {
+		fprintf(stderr, "invalid key identifier: %s\n", str);
+		return false;
+	}
+	return true;
+}
+
+/*
+ * Parse a key specifier (descriptor or identifier) given as a hex string.
+ *
+ *  8 bytes (16 hex chars) == key descriptor == v1 encryption policy.
+ * 16 bytes (32 hex chars) == key identifier == v2 encryption policy.
+ *
+ * If a policy_version is given (>= 0), then the corresponding type of key
+ * specifier is required.  Otherwise the specifier type and policy_version are
+ * determined based on the length of the given hex string.
+ *
+ * Returns the policy version, or -1 on error.
+ */
+static int
+str2keyspec(const char *str, int policy_version,
+	    struct fscrypt_key_specifier *key_spec)
+{
+	if (policy_version < 0) { /* version unspecified? */
+		size_t len = strlen(str);
+
+		if (len == 2 * FSCRYPT_KEY_DESCRIPTOR_SIZE) {
+			policy_version = FSCRYPT_POLICY_V1;
+		} else if (len == 2 * FSCRYPT_KEY_IDENTIFIER_SIZE) {
+			policy_version = FSCRYPT_POLICY_V2;
+		} else {
+			fprintf(stderr, "invalid key specifier: %s\n", str);
+			return -1;
+		}
+	}
+	if (policy_version == FSCRYPT_POLICY_V2) {
+		if (!str2keyid(str, key_spec->u.identifier))
+			return -1;
+		key_spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
+	} else {
+		if (!str2keydesc(str, key_spec->u.descriptor))
+			return -1;
+		key_spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
+	}
+	return policy_version;
+}
+
 static void
 test_for_v2_policy_support(void)
 {
@@ -375,46 +495,54 @@ static int
 set_encpolicy_f(int argc, char **argv)
 {
 	int c;
-	struct fscrypt_policy policy;
-
-	/* Initialize the policy structure with default values */
-	memset(&policy, 0, sizeof(policy));
-	policy.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
-	policy.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
-	policy.flags = FSCRYPT_POLICY_FLAGS_PAD_16;
+	__u8 contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+	__u8 filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+	__u8 flags = FSCRYPT_POLICY_FLAGS_PAD_16;
+	int version = -1; /* unspecified */
+	struct fscrypt_key_specifier key_spec;
+	union {
+		__u8 version;
+		struct fscrypt_policy_v1 v1;
+		struct fscrypt_policy_v2 v2;
+	} policy;
 
-	/* Parse options */
 	while ((c = getopt(argc, argv, "c:n:f:v:")) != EOF) {
 		switch (c) {
 		case 'c':
-			if (!parse_mode(optarg,
-					&policy.contents_encryption_mode)) {
-				fprintf(stderr, "invalid contents encryption "
-					"mode: %s\n", optarg);
+			if (!parse_mode(optarg, &contents_encryption_mode)) {
+				fprintf(stderr,
+					"invalid contents encryption mode: %s\n",
+					optarg);
 				return 0;
 			}
 			break;
 		case 'n':
-			if (!parse_mode(optarg,
-					&policy.filenames_encryption_mode)) {
-				fprintf(stderr, "invalid filenames encryption "
-					"mode: %s\n", optarg);
+			if (!parse_mode(optarg, &filenames_encryption_mode)) {
+				fprintf(stderr,
+					"invalid filenames encryption mode: %s\n",
+					optarg);
 				return 0;
 			}
 			break;
 		case 'f':
-			if (!parse_byte_value(optarg, &policy.flags)) {
+			if (!parse_byte_value(optarg, &flags)) {
 				fprintf(stderr, "invalid flags: %s\n", optarg);
 				return 0;
 			}
 			break;
-		case 'v':
-			if (!parse_byte_value(optarg, &policy.version)) {
+		case 'v': {
+			__u8 val;
+
+			if (!parse_byte_value(optarg, &val)) {
 				fprintf(stderr, "invalid policy version: %s\n",
 					optarg);
 				return 0;
 			}
+			if (val == 1) /* Just to avoid annoying people... */
+				val = FSCRYPT_POLICY_V1;
+			version = val;
 			break;
+		}
 		default:
 			return command_usage(&set_encpolicy_cmd);
 		}
@@ -425,40 +553,44 @@ set_encpolicy_f(int argc, char **argv)
 	if (argc > 1)
 		return command_usage(&set_encpolicy_cmd);
 
-	/* Parse key descriptor if specified */
+	/*
+	 * If unspecified, the key descriptor or identifier defaults to all 0's.
+	 * If the policy version is additionally unspecified, it defaults to v1.
+	 */
+	memset(&key_spec, 0, sizeof(key_spec));
 	if (argc > 0) {
-		const char *keydesc = argv[0];
-		char *tmp;
-		unsigned long long x;
-		int i;
-
-		if (strlen(keydesc) != FSCRYPT_KEY_DESCRIPTOR_SIZE * 2) {
-			fprintf(stderr, "invalid key descriptor: %s\n",
-				keydesc);
+		version = str2keyspec(argv[0], version, &key_spec);
+		if (version < 0)
 			return 0;
-		}
-
-		x = strtoull(keydesc, &tmp, 16);
-		if (tmp == keydesc || *tmp != '\0') {
-			fprintf(stderr, "invalid key descriptor: %s\n",
-				keydesc);
-			return 0;
-		}
+	}
+	if (version < 0) /* version unspecified? */
+		version = FSCRYPT_POLICY_V1;
 
-		for (i = 0; i < FSCRYPT_KEY_DESCRIPTOR_SIZE; i++) {
-			policy.master_key_descriptor[i] = x >> 56;
-			x <<= 8;
-		}
+	memset(&policy, 0, sizeof(policy));
+	policy.version = version;
+	if (version == FSCRYPT_POLICY_V2) {
+		policy.v2.contents_encryption_mode = contents_encryption_mode;
+		policy.v2.filenames_encryption_mode = filenames_encryption_mode;
+		policy.v2.flags = flags;
+		memcpy(policy.v2.master_key_identifier, key_spec.u.identifier,
+		       FSCRYPT_KEY_IDENTIFIER_SIZE);
+	} else {
+		/*
+		 * xfstests passes .version = 255 for testing.  Just use
+		 * 'struct fscrypt_policy_v1' for both v1 and unknown versions.
+		 */
+		policy.v1.contents_encryption_mode = contents_encryption_mode;
+		policy.v1.filenames_encryption_mode = filenames_encryption_mode;
+		policy.v1.flags = flags;
+		memcpy(policy.v1.master_key_descriptor, key_spec.u.descriptor,
+		       FSCRYPT_KEY_DESCRIPTOR_SIZE);
 	}
 
-	/* Set the encryption policy */
-	if (ioctl(file->fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) < 0) {
+	if (ioctl(file->fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) != 0) {
 		fprintf(stderr, "%s: failed to set encryption policy: %s\n",
 			file->name, strerror(errno));
 		exitcode = 1;
-		return 0;
 	}
-
 	return 0;
 }
 
@@ -478,7 +610,7 @@ encrypt_init(void)
 	set_encpolicy_cmd.name = "set_encpolicy";
 	set_encpolicy_cmd.cfunc = set_encpolicy_f;
 	set_encpolicy_cmd.args =
-		_("[-c mode] [-n mode] [-f flags] [-v version] [keydesc]");
+		_("[-c mode] [-n mode] [-f flags] [-v version] [keyspec]");
 	set_encpolicy_cmd.argmin = 0;
 	set_encpolicy_cmd.argmax = -1;
 	set_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 3dd34a0c..18fcde0f 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -701,12 +701,17 @@ Swaps extent forks between files. The current open file is the target. The donor
 file is specified by path. Note that file data is not copied (file content moves
 with the fork(s)).
 .TP
-.BI "set_encpolicy [ \-c " mode " ] [ \-n " mode " ] [ \-f " flags " ] [ \-v " version " ] [ " keydesc " ]"
+.BI "set_encpolicy [ \-c " mode " ] [ \-n " mode " ] [ \-f " flags " ] [ \-v " version " ] [ " keyspec " ]"
 On filesystems that support encryption, assign an encryption policy to the
 current file.
-.I keydesc
-is a 16-byte hex string which identifies the encryption key to use.
-If not specified, a "default" key descriptor of all 0's will be used.
+.I keyspec
+is a hex string which specifies the encryption key to use.  For v1 encryption
+policies,
+.I keyspec
+must be a 16-character hex string (8 bytes).  For v2 policies,
+.I keyspec
+must be a 32-character hex string (16 bytes).  If unspecified, an all-zeroes
+value is used.
 .RS 1.0i
 .PD 0
 .TP 0.4i
@@ -720,7 +725,11 @@ filenames encryption mode (e.g. AES-256-CTS)
 policy flags (numeric)
 .TP
 .BI \-v " version"
-version of policy structure (numeric)
+policy version.  Defaults to 1 or 2 depending on the length of
+.IR keyspec ;
+or to 1 if
+.I keyspec
+is unspecified.
 .RE
 .PD
 .TP
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 6/8] xfs_io/encrypt: add 'add_enckey' command
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (4 preceding siblings ...)
  2019-08-12 17:56 ` [RFC PATCH 5/8] xfs_io/encrypt: extend 'set_encpolicy' " Eric Biggers
@ 2019-08-12 17:56 ` Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 7/8] xfs_io/encrypt: add 'rm_enckey' command Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 8/8] xfs_io/encrypt: add 'enckey_status' command Eric Biggers
  7 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Add an 'add_enckey' command to xfs_io, to provide a command-line
interface to the FS_IOC_ADD_ENCRYPTION_KEY ioctl.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c      | 109 ++++++++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_io.8 |  15 +++++++
 2 files changed, 124 insertions(+)

diff --git a/io/encrypt.c b/io/encrypt.c
index f982cd17..038c4cce 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -138,6 +138,7 @@ struct fscrypt_get_key_status_arg {
 
 static cmdinfo_t get_encpolicy_cmd;
 static cmdinfo_t set_encpolicy_cmd;
+static cmdinfo_t add_enckey_cmd;
 
 static void
 get_encpolicy_help(void)
@@ -183,6 +184,22 @@ set_encpolicy_help(void)
 "\n"));
 }
 
+static void
+add_enckey_help(void)
+{
+	printf(_(
+"\n"
+" add an encryption key to the filesystem\n"
+"\n"
+" Examples:\n"
+" 'add_enckey' - add key for v2 policies\n"
+" 'add_enckey -d 0000111122223333' - add key for v1 policies w/ given descriptor\n"
+"\n"
+"The key in binary is read from standard input.\n"
+" -d DESCRIPTOR -- master_key_descriptor\n"
+"\n"));
+}
+
 static const struct {
 	__u8 mode;
 	const char *name;
@@ -594,6 +611,88 @@ set_encpolicy_f(int argc, char **argv)
 	return 0;
 }
 
+static ssize_t
+read_until_limit_or_eof(int fd, void *buf, size_t limit)
+{
+	size_t bytes_read = 0;
+	ssize_t res;
+
+	while (limit) {
+		res = read(fd, buf, limit);
+		if (res < 0)
+			return res;
+		if (res == 0)
+			break;
+		buf += res;
+		bytes_read += res;
+		limit -= res;
+	}
+	return bytes_read;
+}
+
+static int
+add_enckey_f(int argc, char **argv)
+{
+	int c;
+	struct fscrypt_add_key_arg *arg;
+	ssize_t raw_size;
+
+	arg = calloc(1, sizeof(*arg) + FSCRYPT_MAX_KEY_SIZE + 1);
+	if (!arg) {
+		fprintf(stderr, "calloc failed\n");
+		exitcode = 1;
+		return 0;
+	}
+
+	arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
+
+	while ((c = getopt(argc, argv, "d:")) != EOF) {
+		switch (c) {
+		case 'd':
+			arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
+			if (!str2keydesc(optarg, arg->key_spec.u.descriptor))
+				goto out;
+			break;
+		default:
+			return command_usage(&add_enckey_cmd);
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 0)
+		return command_usage(&add_enckey_cmd);
+
+	raw_size = read_until_limit_or_eof(STDIN_FILENO, arg->raw,
+					   FSCRYPT_MAX_KEY_SIZE + 1);
+	if (raw_size < 0) {
+		fprintf(stderr, "Error reading key from stdin: %s\n",
+			strerror(errno));
+		exitcode = 1;
+		goto out;
+	}
+	if (raw_size > FSCRYPT_MAX_KEY_SIZE) {
+		fprintf(stderr,
+			"Invalid key; got > FSCRYPT_MAX_KEY_SIZE (%d) bytes on stdin!\n",
+			FSCRYPT_MAX_KEY_SIZE);
+		goto out;
+	}
+	arg->raw_size = raw_size;
+
+	if (ioctl(file->fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) {
+		fprintf(stderr, "Error adding encryption key: %s\n",
+			strerror(errno));
+		exitcode = 1;
+		goto out;
+	}
+	printf("Added encryption key with %s %s\n",
+	       keyspectype(&arg->key_spec), keyspec2str(&arg->key_spec));
+out:
+	memset(arg->raw, 0, FSCRYPT_MAX_KEY_SIZE + 1);
+	free(arg);
+	return 0;
+}
+
 void
 encrypt_init(void)
 {
@@ -618,6 +717,16 @@ encrypt_init(void)
 		_("assign an encryption policy to the current file");
 	set_encpolicy_cmd.help = set_encpolicy_help;
 
+	add_enckey_cmd.name = "add_enckey";
+	add_enckey_cmd.cfunc = add_enckey_f;
+	add_enckey_cmd.args = _("[-d descriptor]");
+	add_enckey_cmd.argmin = 0;
+	add_enckey_cmd.argmax = -1;
+	add_enckey_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+	add_enckey_cmd.oneline = _("add an encryption key to the filesystem");
+	add_enckey_cmd.help = add_enckey_help;
+
 	add_command(&get_encpolicy_cmd);
 	add_command(&set_encpolicy_cmd);
+	add_command(&add_enckey_cmd);
 }
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 18fcde0f..7d6a23fe 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -749,6 +749,21 @@ Test whether v2 encryption policies are supported.  Prints "supported",
 .RE
 .PD
 .TP
+.BI "add_enckey [ \-d " descriptor " ]"
+On filesystems that support encryption, add an encryption key to the filesystem
+containing the currently open file.  The key in binary (typically 64 bytes long)
+is read from standard input.
+.RS 1.0i
+.PD 0
+.TP 0.4i
+.BI \-d " descriptor"
+key descriptor, as a 16-character hex string (8 bytes).  If given, the key will
+be available for use by v1 encryption policies that use this descriptor.
+Otherwise, the key is added as a v2 policy key, and on success the resulting
+"key identifier" will be printed.
+.RE
+.PD
+.TP
 .BR lsattr " [ " \-R " | " \-D " | " \-a " | " \-v " ]"
 List extended inode flags on the currently open file. If the
 .B \-R
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 7/8] xfs_io/encrypt: add 'rm_enckey' command
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (5 preceding siblings ...)
  2019-08-12 17:56 ` [RFC PATCH 6/8] xfs_io/encrypt: add 'add_enckey' command Eric Biggers
@ 2019-08-12 17:56 ` Eric Biggers
  2019-08-12 17:56 ` [RFC PATCH 8/8] xfs_io/encrypt: add 'enckey_status' command Eric Biggers
  7 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Add a 'rm_enckey' command to xfs_io, to provide a command-line interface
to the FS_IOC_REMOVE_ENCRYPTION_KEY and
FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS ioctls.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c      | 75 +++++++++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_io.8 | 15 ++++++++++
 2 files changed, 90 insertions(+)

diff --git a/io/encrypt.c b/io/encrypt.c
index 038c4cce..213c9c53 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -139,6 +139,7 @@ struct fscrypt_get_key_status_arg {
 static cmdinfo_t get_encpolicy_cmd;
 static cmdinfo_t set_encpolicy_cmd;
 static cmdinfo_t add_enckey_cmd;
+static cmdinfo_t rm_enckey_cmd;
 
 static void
 get_encpolicy_help(void)
@@ -200,6 +201,21 @@ add_enckey_help(void)
 "\n"));
 }
 
+static void
+rm_enckey_help(void)
+{
+	printf(_(
+"\n"
+" remove an encryption key from the filesystem\n"
+"\n"
+" Examples:\n"
+" 'rm_enckey 0000111122223333' - remove key for v1 policies w/ given descriptor\n"
+" 'rm_enckey 00001111222233334444555566667777' - remove key for v2 policies w/ given identifier\n"
+"\n"
+" -a -- remove key for all users who have added it (privileged operation)\n"
+"\n"));
+}
+
 static const struct {
 	__u8 mode;
 	const char *name;
@@ -693,6 +709,54 @@ out:
 	return 0;
 }
 
+static int
+rm_enckey_f(int argc, char **argv)
+{
+	int c;
+	struct fscrypt_remove_key_arg arg;
+	int ioc = FS_IOC_REMOVE_ENCRYPTION_KEY;
+
+	memset(&arg, 0, sizeof(arg));
+
+	while ((c = getopt(argc, argv, "a")) != EOF) {
+		switch (c) {
+		case 'a':
+			ioc = FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS;
+			break;
+		default:
+			return command_usage(&rm_enckey_cmd);
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1)
+		return command_usage(&rm_enckey_cmd);
+
+	if (str2keyspec(argv[0], -1, &arg.key_spec) < 0)
+		return 0;
+
+	if (ioctl(file->fd, ioc, &arg) != 0) {
+		fprintf(stderr, "Error removing encryption key: %s\n",
+			strerror(errno));
+		exitcode = 1;
+		return 0;
+	}
+	if (arg.removal_status_flags &
+	    FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
+		printf("Removed user's claim to encryption key with %s %s\n",
+		       keyspectype(&arg.key_spec), keyspec2str(&arg.key_spec));
+	} else if (arg.removal_status_flags &
+		   FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
+		printf("Removed encryption key with %s %s, but files still busy\n",
+		       keyspectype(&arg.key_spec), keyspec2str(&arg.key_spec));
+	} else {
+		printf("Removed encryption key with %s %s\n",
+		       keyspectype(&arg.key_spec), keyspec2str(&arg.key_spec));
+	}
+	return 0;
+}
+
 void
 encrypt_init(void)
 {
@@ -726,7 +790,18 @@ encrypt_init(void)
 	add_enckey_cmd.oneline = _("add an encryption key to the filesystem");
 	add_enckey_cmd.help = add_enckey_help;
 
+	rm_enckey_cmd.name = "rm_enckey";
+	rm_enckey_cmd.cfunc = rm_enckey_f;
+	rm_enckey_cmd.args = _("keyspec");
+	rm_enckey_cmd.argmin = 0;
+	rm_enckey_cmd.argmax = -1;
+	rm_enckey_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+	rm_enckey_cmd.oneline =
+		_("remove an encryption key from the filesystem");
+	rm_enckey_cmd.help = rm_enckey_help;
+
 	add_command(&get_encpolicy_cmd);
 	add_command(&set_encpolicy_cmd);
 	add_command(&add_enckey_cmd);
+	add_command(&rm_enckey_cmd);
 }
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 7d6a23fe..a6894778 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -764,6 +764,21 @@ Otherwise, the key is added as a v2 policy key, and on success the resulting
 .RE
 .PD
 .TP
+.BI "rm_enckey " keyspec
+On filesystems that support encryption, remove an encryption key from the
+filesystem containing the currently open file.
+.I keyspec
+is a hex string specifying the key to remove, as a 16-character "key descriptor"
+or a 32-character "key identifier".
+.RS 1.0i
+.PD 0
+.TP 0.4i
+.BI \-a
+Remove the key for all users who have added it, not just the current user.  This
+is a privileged operation.
+.RE
+.PD
+.TP
 .BR lsattr " [ " \-R " | " \-D " | " \-a " | " \-v " ]"
 List extended inode flags on the currently open file. If the
 .B \-R
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* [RFC PATCH 8/8] xfs_io/encrypt: add 'enckey_status' command
  2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (6 preceding siblings ...)
  2019-08-12 17:56 ` [RFC PATCH 7/8] xfs_io/encrypt: add 'rm_enckey' command Eric Biggers
@ 2019-08-12 17:56 ` Eric Biggers
  7 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2019-08-12 17:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Add an 'enckey_status' command to xfs_io, to provide a command-line
interface to the FS_IOC_GET_ENCRYPTION_KEY_STATUS ioctl.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 io/encrypt.c      | 71 +++++++++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_io.8 |  6 ++++
 2 files changed, 77 insertions(+)

diff --git a/io/encrypt.c b/io/encrypt.c
index 213c9c53..19c74983 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -140,6 +140,7 @@ static cmdinfo_t get_encpolicy_cmd;
 static cmdinfo_t set_encpolicy_cmd;
 static cmdinfo_t add_enckey_cmd;
 static cmdinfo_t rm_enckey_cmd;
+static cmdinfo_t enckey_status_cmd;
 
 static void
 get_encpolicy_help(void)
@@ -216,6 +217,19 @@ rm_enckey_help(void)
 "\n"));
 }
 
+static void
+enckey_status_help(void)
+{
+	printf(_(
+"\n"
+" get the status of a filesystem encryption key\n"
+"\n"
+" Examples:\n"
+" 'enckey_status 0000111122223333' - get status of v1 policy key\n"
+" 'enckey_status 00001111222233334444555566667777' - get status of v2 policy key\n"
+"\n"));
+}
+
 static const struct {
 	__u8 mode;
 	const char *name;
@@ -757,6 +771,52 @@ rm_enckey_f(int argc, char **argv)
 	return 0;
 }
 
+static int
+enckey_status_f(int argc, char **argv)
+{
+	struct fscrypt_get_key_status_arg arg;
+
+	memset(&arg, 0, sizeof(arg));
+
+	if (str2keyspec(argv[1], -1, &arg.key_spec) < 0)
+		return 0;
+
+	if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_KEY_STATUS, &arg) != 0) {
+		fprintf(stderr, "Error getting encryption key status: %s\n",
+			strerror(errno));
+		exitcode = 1;
+		return 0;
+	}
+
+	switch (arg.status) {
+	case FSCRYPT_KEY_STATUS_PRESENT:
+		printf("Present");
+		if (arg.user_count || arg.status_flags) {
+			printf(" (user_count=%u", arg.user_count);
+			if (arg.status_flags &
+			    FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF)
+				printf(", added_by_self");
+			arg.status_flags &=
+				~FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF;
+			if (arg.status_flags)
+				printf(", unknown_flags=0x%08x",
+				       arg.status_flags);
+			printf(")");
+		}
+		printf("\n");
+		return 0;
+	case FSCRYPT_KEY_STATUS_ABSENT:
+		printf("Absent\n");
+		return 0;
+	case FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED:
+		printf("Incompletely removed\n");
+		return 0;
+	default:
+		printf("Unknown status (%u)\n", arg.status);
+		return 0;
+	}
+}
+
 void
 encrypt_init(void)
 {
@@ -800,8 +860,19 @@ encrypt_init(void)
 		_("remove an encryption key from the filesystem");
 	rm_enckey_cmd.help = rm_enckey_help;
 
+	enckey_status_cmd.name = "enckey_status";
+	enckey_status_cmd.cfunc = enckey_status_f;
+	enckey_status_cmd.args = _("keyspec");
+	enckey_status_cmd.argmin = 1;
+	enckey_status_cmd.argmax = 1;
+	enckey_status_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+	enckey_status_cmd.oneline =
+		_("get the status of a filesystem encryption key");
+	enckey_status_cmd.help = enckey_status_help;
+
 	add_command(&get_encpolicy_cmd);
 	add_command(&set_encpolicy_cmd);
 	add_command(&add_enckey_cmd);
 	add_command(&rm_enckey_cmd);
+	add_command(&enckey_status_cmd);
 }
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index a6894778..9af6e542 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -779,6 +779,12 @@ is a privileged operation.
 .RE
 .PD
 .TP
+.BI "enckey_status " keyspec
+On filesystems that support encryption, display the status of an encryption key.
+.I keyspec
+is a hex string specifying the key for which to display the status, as a
+16-character "key descriptor" or a 32-character "key identifier".
+.TP
 .BR lsattr " [ " \-R " | " \-D " | " \-a " | " \-v " ]"
 List extended inode flags on the currently open file. If the
 .B \-R
-- 
2.23.0.rc1.153.gdeed80330f-goog

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

* Re: [RFC PATCH 3/8] xfs_io/encrypt: add new encryption modes
  2019-08-12 17:56 ` [RFC PATCH 3/8] xfs_io/encrypt: add new encryption modes Eric Biggers
@ 2019-09-24 22:47   ` Darrick J. Wong
  2019-09-25 23:11     ` Eric Biggers
  0 siblings, 1 reply; 14+ messages in thread
From: Darrick J. Wong @ 2019-09-24 22:47 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-xfs, fstests, linux-fscrypt

On Mon, Aug 12, 2019 at 10:56:29AM -0700, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
> 
> Add new encryption modes: AES-128-CBC and AES-128-CTS (supported since
> Linux v4.11), and Adiantum (supported since Linux v5.0).
> 
> Signed-off-by: Eric Biggers <ebiggers@google.com>
> ---
>  io/encrypt.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/io/encrypt.c b/io/encrypt.c
> index ac473ed7..11eb4a3e 100644
> --- a/io/encrypt.c
> +++ b/io/encrypt.c
> @@ -156,7 +156,7 @@ set_encpolicy_help(void)
>  " -v VERSION -- version of policy structure\n"
>  "\n"
>  " MODE can be numeric or one of the following predefined values:\n"
> -"    AES-256-XTS, AES-256-CTS\n"
> +"    AES-256-XTS, AES-256-CTS, AES-128-CBC, AES-128-CTS, Adiantum\n"

What do you think of generating the list of predefined values from
the available_modes[] array?  Then you wouldn't have to keep the help
text in sync with the C definitions, since it's not like there's a
meaningful translation for them anyway.

--D

>  " FLAGS and VERSION must be numeric.\n"
>  "\n"
>  " Note that it's only possible to set an encryption policy on an empty\n"
> @@ -170,6 +170,9 @@ static const struct {
>  } available_modes[] = {
>  	{FSCRYPT_MODE_AES_256_XTS, "AES-256-XTS"},
>  	{FSCRYPT_MODE_AES_256_CTS, "AES-256-CTS"},
> +	{FSCRYPT_MODE_AES_128_CBC, "AES-128-CBC"},
> +	{FSCRYPT_MODE_AES_128_CTS, "AES-128-CTS"},
> +	{FSCRYPT_MODE_ADIANTUM, "Adiantum"},
>  };
>  
>  static bool
> -- 
> 2.23.0.rc1.153.gdeed80330f-goog
> 

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

* Re: [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies
  2019-08-12 17:56 ` [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies Eric Biggers
@ 2019-09-25 17:23   ` Eric Sandeen
  2019-09-25 23:28     ` Eric Biggers
  0 siblings, 1 reply; 14+ messages in thread
From: Eric Sandeen @ 2019-09-25 17:23 UTC (permalink / raw)
  To: Eric Biggers, linux-xfs; +Cc: fstests, linux-fscrypt

On 8/12/19 12:56 PM, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
> 
> get_encpolicy uses the FS_IOC_GET_ENCRYPTION_POLICY ioctl to retrieve
> the file's encryption policy, then displays it.  But that only works for
> v1 encryption policies.  A new ioctl, FS_IOC_GET_ENCRYPTION_POLICY_EX,
> has been introduced which is more flexible and can retrieve both v1 and
> v2 encryption policies.

...

> +static void
> +test_for_v2_policy_support(void)
> +{
> +	struct fscrypt_get_policy_ex_arg arg;
> +
> +	arg.policy_size = sizeof(arg.policy);
> +
> +	if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg) == 0 ||
> +	    errno == ENODATA /* file unencrypted */) {
> +		printf("supported\n");
> +		return;
> +	}
> +	if (errno == ENOTTY) {
> +		printf("unsupported\n");
> +		return;
> +	}
> +	fprintf(stderr,
> +		"%s: unexpected error checking for FS_IOC_GET_ENCRYPTION_POLICY_EX support: %s\n",

Darrick also mentioned to me off-list that the io/encrypt.c code is chock full of
strings that really need to be _("translatable")

-Eric

> +		file->name, strerror(errno));
> +	exitcode = 1;
> +}
> +
> +static void
> +show_v1_encryption_policy(const struct fscrypt_policy_v1 *policy)
> +{
> +	printf("Encryption policy for %s:\n", file->name);
> +	printf("\tPolicy version: %u\n", policy->version);
> +	printf("\tMaster key descriptor: %s\n",
> +	       keydesc2str(policy->master_key_descriptor));
> +	printf("\tContents encryption mode: %u (%s)\n",
> +	       policy->contents_encryption_mode,
> +	       mode2str(policy->contents_encryption_mode));
> +	printf("\tFilenames encryption mode: %u (%s)\n",
> +	       policy->filenames_encryption_mode,
> +	       mode2str(policy->filenames_encryption_mode));
> +	printf("\tFlags: 0x%02x\n", policy->flags);
> +}
> +
> +static void
> +show_v2_encryption_policy(const struct fscrypt_policy_v2 *policy)
> +{
> +	printf("Encryption policy for %s:\n", file->name);
> +	printf("\tPolicy version: %u\n", policy->version);
> +	printf("\tMaster key identifier: %s\n",
> +	       keyid2str(policy->master_key_identifier));
> +	printf("\tContents encryption mode: %u (%s)\n",
> +	       policy->contents_encryption_mode,
> +	       mode2str(policy->contents_encryption_mode));
> +	printf("\tFilenames encryption mode: %u (%s)\n",
> +	       policy->filenames_encryption_mode,
> +	       mode2str(policy->filenames_encryption_mode));
> +	printf("\tFlags: 0x%02x\n", policy->flags);
> +}
> +
>  static int
>  get_encpolicy_f(int argc, char **argv)
>  {
> -	struct fscrypt_policy policy;
> +	int c;
> +	struct fscrypt_get_policy_ex_arg arg;
> +	bool only_use_v1_ioctl = false;
> +	int res;
>  
> -	if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) < 0) {
> +	while ((c = getopt(argc, argv, "1t")) != EOF) {
> +		switch (c) {
> +		case '1':
> +			only_use_v1_ioctl = true;
> +			break;
> +		case 't':
> +			test_for_v2_policy_support();
> +			return 0;
> +		default:
> +			return command_usage(&get_encpolicy_cmd);
> +		}
> +	}
> +	argc -= optind;
> +	argv += optind;
> +
> +	if (argc != 0)
> +		return command_usage(&get_encpolicy_cmd);
> +
> +	/* first try the new ioctl */
> +	if (only_use_v1_ioctl) {
> +		res = -1;
> +		errno = ENOTTY;
> +	} else {
> +		arg.policy_size = sizeof(arg.policy);
> +		res = ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
> +	}
> +
> +	/* fall back to the old ioctl */
> +	if (res != 0 && errno == ENOTTY)
> +		res = ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY,
> +			    &arg.policy.v1);
> +
> +	if (res != 0) {
>  		fprintf(stderr, "%s: failed to get encryption policy: %s\n",
>  			file->name, strerror(errno));
>  		exitcode = 1;
>  		return 0;
>  	}
>  
> -	printf("Encryption policy for %s:\n", file->name);
> -	printf("\tPolicy version: %u\n", policy.version);
> -	printf("\tMaster key descriptor: %s\n",
> -	       keydesc2str(policy.master_key_descriptor));
> -	printf("\tContents encryption mode: %u (%s)\n",
> -	       policy.contents_encryption_mode,
> -	       mode2str(policy.contents_encryption_mode));
> -	printf("\tFilenames encryption mode: %u (%s)\n",
> -	       policy.filenames_encryption_mode,
> -	       mode2str(policy.filenames_encryption_mode));
> -	printf("\tFlags: 0x%02x\n", policy.flags);
> +	switch (arg.policy.version) {
> +	case FSCRYPT_POLICY_V1:
> +		show_v1_encryption_policy(&arg.policy.v1);
> +		break;
> +	case FSCRYPT_POLICY_V2:
> +		show_v2_encryption_policy(&arg.policy.v2);
> +		break;
> +	default:
> +		printf("Encryption policy for %s:\n", file->name);
> +		printf("\tPolicy version: %u (unknown)\n", arg.policy.version);
> +		break;
> +	}
>  	return 0;
>  }
>  
> @@ -351,11 +467,13 @@ encrypt_init(void)
>  {
>  	get_encpolicy_cmd.name = "get_encpolicy";
>  	get_encpolicy_cmd.cfunc = get_encpolicy_f;
> +	get_encpolicy_cmd.args = _("[-1] [-t]");
>  	get_encpolicy_cmd.argmin = 0;
> -	get_encpolicy_cmd.argmax = 0;
> +	get_encpolicy_cmd.argmax = -1;
>  	get_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
>  	get_encpolicy_cmd.oneline =
>  		_("display the encryption policy of the current file");
> +	get_encpolicy_cmd.help = get_encpolicy_help;
>  
>  	set_encpolicy_cmd.name = "set_encpolicy";
>  	set_encpolicy_cmd.cfunc = set_encpolicy_f;
> diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
> index 6e064bdd..3dd34a0c 100644
> --- a/man/man8/xfs_io.8
> +++ b/man/man8/xfs_io.8
> @@ -724,10 +724,21 @@ version of policy structure (numeric)
>  .RE
>  .PD
>  .TP
> -.BR get_encpolicy
> +.BI "get_encpolicy [ \-1 ] [ \-t ]"
>  On filesystems that support encryption, display the encryption policy of the
>  current file.
> -
> +.RS 1.0i
> +.PD 0
> +.TP 0.4i
> +.BI \-1
> +Use only the old ioctl to get the encryption policy.  This only works if the
> +file has a v1 encryption policy.
> +.TP
> +.BI \-t
> +Test whether v2 encryption policies are supported.  Prints "supported",
> +"unsupported", or an error message.
> +.RE
> +.PD
>  .TP
>  .BR lsattr " [ " \-R " | " \-D " | " \-a " | " \-v " ]"
>  List extended inode flags on the currently open file. If the
> 

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

* Re: [RFC PATCH 3/8] xfs_io/encrypt: add new encryption modes
  2019-09-24 22:47   ` Darrick J. Wong
@ 2019-09-25 23:11     ` Eric Biggers
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2019-09-25 23:11 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, fstests, linux-fscrypt

On Tue, Sep 24, 2019 at 03:47:44PM -0700, Darrick J. Wong wrote:
> On Mon, Aug 12, 2019 at 10:56:29AM -0700, Eric Biggers wrote:
> > From: Eric Biggers <ebiggers@google.com>
> > 
> > Add new encryption modes: AES-128-CBC and AES-128-CTS (supported since
> > Linux v4.11), and Adiantum (supported since Linux v5.0).
> > 
> > Signed-off-by: Eric Biggers <ebiggers@google.com>
> > ---
> >  io/encrypt.c | 5 ++++-
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> > 
> > diff --git a/io/encrypt.c b/io/encrypt.c
> > index ac473ed7..11eb4a3e 100644
> > --- a/io/encrypt.c
> > +++ b/io/encrypt.c
> > @@ -156,7 +156,7 @@ set_encpolicy_help(void)
> >  " -v VERSION -- version of policy structure\n"
> >  "\n"
> >  " MODE can be numeric or one of the following predefined values:\n"
> > -"    AES-256-XTS, AES-256-CTS\n"
> > +"    AES-256-XTS, AES-256-CTS, AES-128-CBC, AES-128-CTS, Adiantum\n"
> 
> What do you think of generating the list of predefined values from
> the available_modes[] array?  Then you wouldn't have to keep the help
> text in sync with the C definitions, since it's not like there's a
> meaningful translation for them anyway.
> 

Yes, good idea.  I'll do that.

- Eric

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

* Re: [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies
  2019-09-25 17:23   ` Eric Sandeen
@ 2019-09-25 23:28     ` Eric Biggers
  2019-09-28  0:13       ` Eric Sandeen
  0 siblings, 1 reply; 14+ messages in thread
From: Eric Biggers @ 2019-09-25 23:28 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs, fstests, linux-fscrypt

On Wed, Sep 25, 2019 at 12:23:25PM -0500, Eric Sandeen wrote:
> On 8/12/19 12:56 PM, Eric Biggers wrote:
> > From: Eric Biggers <ebiggers@google.com>
> > 
> > get_encpolicy uses the FS_IOC_GET_ENCRYPTION_POLICY ioctl to retrieve
> > the file's encryption policy, then displays it.  But that only works for
> > v1 encryption policies.  A new ioctl, FS_IOC_GET_ENCRYPTION_POLICY_EX,
> > has been introduced which is more flexible and can retrieve both v1 and
> > v2 encryption policies.
> 
> ...
> 
> > +static void
> > +test_for_v2_policy_support(void)
> > +{
> > +	struct fscrypt_get_policy_ex_arg arg;
> > +
> > +	arg.policy_size = sizeof(arg.policy);
> > +
> > +	if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg) == 0 ||
> > +	    errno == ENODATA /* file unencrypted */) {
> > +		printf("supported\n");
> > +		return;
> > +	}
> > +	if (errno == ENOTTY) {
> > +		printf("unsupported\n");
> > +		return;
> > +	}
> > +	fprintf(stderr,
> > +		"%s: unexpected error checking for FS_IOC_GET_ENCRYPTION_POLICY_EX support: %s\n",
> 
> Darrick also mentioned to me off-list that the io/encrypt.c code is chock full of
> strings that really need to be _("translatable")
> 

Sure, I can do that, though is this really something that people want?  These
commands are only intended for testing, and the xfsprogs translations don't seem
actively maintained (only 1 language was updated in the last 10 years?).

- Eric

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

* Re: [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies
  2019-09-25 23:28     ` Eric Biggers
@ 2019-09-28  0:13       ` Eric Sandeen
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Sandeen @ 2019-09-28  0:13 UTC (permalink / raw)
  To: linux-xfs, fstests, linux-fscrypt

On 9/25/19 6:28 PM, Eric Biggers wrote:
> On Wed, Sep 25, 2019 at 12:23:25PM -0500, Eric Sandeen wrote:
>> On 8/12/19 12:56 PM, Eric Biggers wrote:
>>> From: Eric Biggers <ebiggers@google.com>
>>>
>>> get_encpolicy uses the FS_IOC_GET_ENCRYPTION_POLICY ioctl to retrieve
>>> the file's encryption policy, then displays it.  But that only works for
>>> v1 encryption policies.  A new ioctl, FS_IOC_GET_ENCRYPTION_POLICY_EX,
>>> has been introduced which is more flexible and can retrieve both v1 and
>>> v2 encryption policies.
>>
>> ...
>>
...

>>> +	fprintf(stderr,
>>> +		"%s: unexpected error checking for FS_IOC_GET_ENCRYPTION_POLICY_EX support: %s\n",
>>
>> Darrick also mentioned to me off-list that the io/encrypt.c code is chock full of
>> strings that really need to be _("translatable")
>>
> 
> Sure, I can do that, though is this really something that people want?  These
> commands are only intended for testing, and the xfsprogs translations don't seem
> actively maintained (only 1 language was updated in the last 10 years?).

True that there's not a ton of translation going on now, but it's easy enough
to toss in _("foo") and keep the possibility open, and be consistent.

So thanks  :)

-Eric

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

end of thread, back to index

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-12 17:56 [RFC PATCH 0/8] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
2019-08-12 17:56 ` [RFC PATCH 1/8] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
2019-08-12 17:56 ` [RFC PATCH 2/8] xfs_io/encrypt: update to UAPI definitions from Linux v5.4 Eric Biggers
2019-08-12 17:56 ` [RFC PATCH 3/8] xfs_io/encrypt: add new encryption modes Eric Biggers
2019-09-24 22:47   ` Darrick J. Wong
2019-09-25 23:11     ` Eric Biggers
2019-08-12 17:56 ` [RFC PATCH 4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies Eric Biggers
2019-09-25 17:23   ` Eric Sandeen
2019-09-25 23:28     ` Eric Biggers
2019-09-28  0:13       ` Eric Sandeen
2019-08-12 17:56 ` [RFC PATCH 5/8] xfs_io/encrypt: extend 'set_encpolicy' " Eric Biggers
2019-08-12 17:56 ` [RFC PATCH 6/8] xfs_io/encrypt: add 'add_enckey' command Eric Biggers
2019-08-12 17:56 ` [RFC PATCH 7/8] xfs_io/encrypt: add 'rm_enckey' command Eric Biggers
2019-08-12 17:56 ` [RFC PATCH 8/8] xfs_io/encrypt: add 'enckey_status' command Eric Biggers

($INBOX_DIR/description missing)

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-fscrypt/0 linux-fscrypt/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-fscrypt linux-fscrypt/ https://lore.kernel.org/linux-fscrypt \
		linux-fscrypt@vger.kernel.org
	public-inbox-index linux-fscrypt

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-fscrypt


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git