FSTests Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io
@ 2019-09-28  0:02 Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 1/9] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

Hello,

This patchset updates xfs_io to support the new fscrypt ioctls that were
merged for 5.4 (https://git.kernel.org/torvalds/c/734d1ed83e1f9b7b).

New commands are added to wrap the new ioctls to manage filesystem
encryption keys: 'add_enckey', 'rm_enckey', and 'enckey_status'.  Also,
the existing 'get_encpolicy' and 'set_encpolicy' commands are updated to
support getting/setting v2 encryption policies.

The purpose of all this is to allow xfstests to test these 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 xfstests directly
(https://marc.info/?l=fstests&m=147976255831951&w=2).

This patchset applies to the latest "for-next" branch of xfsprogs
(commit ac8b6c380865).  It can also be retrieved from tag
"fscrypt-key-mgmt-improvements_2019-09-27" of
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/xfsprogs-dev.git

Changes v2 => v3:
- Generate the encryption modes for 'help set_encpolicy'.
- Mention '-a' in all relevant places in the help for rm_enckey.
- Mark strings for translation.

No changes v1 => v2.

Eric Biggers (9):
  xfs_io/encrypt: remove unimplemented encryption modes
  xfs_io/encrypt: update to UAPI definitions from Linux v5.4
  xfs_io/encrypt: generate encryption modes for 'help set_encpolicy'
  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      | 816 ++++++++++++++++++++++++++++++++++++++++------
 man/man8/xfs_io.8 |  70 +++-
 2 files changed, 771 insertions(+), 115 deletions(-)

-- 
2.23.0.444.g18eeb5a265-goog

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

* [PATCH v3 1/9] xfs_io/encrypt: remove unimplemented encryption modes
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 2/9] xfs_io/encrypt: update to UAPI definitions from Linux v5.4 Eric Biggers
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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 7a0b2465..70c9e5eb 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.444.g18eeb5a265-goog

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

* [PATCH v3 2/9] xfs_io/encrypt: update to UAPI definitions from Linux v5.4
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 1/9] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 3/9] xfs_io/encrypt: generate encryption modes for 'help set_encpolicy' Eric Biggers
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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 70c9e5eb..011a6410 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.444.g18eeb5a265-goog

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

* [PATCH v3 3/9] xfs_io/encrypt: generate encryption modes for 'help set_encpolicy'
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 1/9] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 2/9] xfs_io/encrypt: update to UAPI definitions from Linux v5.4 Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 4/9] xfs_io/encrypt: add new encryption modes Eric Biggers
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 UTC (permalink / raw)
  To: linux-xfs; +Cc: fstests, linux-fscrypt

From: Eric Biggers <ebiggers@google.com>

Print all encryption modes that are defined in the code, rather than
hardcoding the modes in the help text.

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

diff --git a/io/encrypt.c b/io/encrypt.c
index 011a6410..7d3e3b73 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -136,12 +136,22 @@ struct fscrypt_get_key_status_arg {
 
 #endif /* !FS_IOC_GET_ENCRYPTION_POLICY_EX */
 
+static const struct {
+	__u8 mode;
+	const char *name;
+} available_modes[] = {
+	{FSCRYPT_MODE_AES_256_XTS, "AES-256-XTS"},
+	{FSCRYPT_MODE_AES_256_CTS, "AES-256-CTS"},
+};
+
 static cmdinfo_t get_encpolicy_cmd;
 static cmdinfo_t set_encpolicy_cmd;
 
 static void
 set_encpolicy_help(void)
 {
+	int i;
+
 	printf(_(
 "\n"
 " assign an encryption policy to the currently open file\n"
@@ -155,8 +165,15 @@ set_encpolicy_help(void)
 " -f FLAGS -- policy flags\n"
 " -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"
+" MODE can be numeric or one of the following predefined values:\n"));
+	printf("    ");
+	for (i = 0; i < ARRAY_SIZE(available_modes); i++) {
+		printf("%s", available_modes[i].name);
+		if (i != ARRAY_SIZE(available_modes) - 1)
+			printf(", ");
+	}
+	printf("\n");
+	printf(_(
 " FLAGS and VERSION must be numeric.\n"
 "\n"
 " Note that it's only possible to set an encryption policy on an empty\n"
@@ -164,14 +181,6 @@ set_encpolicy_help(void)
 "\n"));
 }
 
-static const struct {
-	__u8 mode;
-	const char *name;
-} available_modes[] = {
-	{FSCRYPT_MODE_AES_256_XTS, "AES-256-XTS"},
-	{FSCRYPT_MODE_AES_256_CTS, "AES-256-CTS"},
-};
-
 static bool
 parse_byte_value(const char *arg, __u8 *value_ret)
 {
-- 
2.23.0.444.g18eeb5a265-goog

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

* [PATCH v3 4/9] xfs_io/encrypt: add new encryption modes
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (2 preceding siblings ...)
  2019-09-28  0:02 ` [PATCH v3 3/9] xfs_io/encrypt: generate encryption modes for 'help set_encpolicy' Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 5/9] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies Eric Biggers
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/io/encrypt.c b/io/encrypt.c
index 7d3e3b73..8a511379 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -142,6 +142,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 cmdinfo_t get_encpolicy_cmd;
-- 
2.23.0.444.g18eeb5a265-goog

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

* [PATCH v3 5/9] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (3 preceding siblings ...)
  2019-09-28  0:02 ` [PATCH v3 4/9] xfs_io/encrypt: add new encryption modes Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 6/9] xfs_io/encrypt: extend 'set_encpolicy' " Eric Biggers
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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      | 153 ++++++++++++++++++++++++++++++++++++++++------
 man/man8/xfs_io.8 |  15 ++++-
 2 files changed, 149 insertions(+), 19 deletions(-)

diff --git a/io/encrypt.c b/io/encrypt.c
index 8a511379..0b45e93f 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>
  */
 
@@ -150,6 +150,20 @@ static const struct {
 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)
 {
@@ -227,7 +241,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;
@@ -238,29 +252,132 @@ 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;
+
+	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 (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) < 0) {
-		fprintf(stderr, "%s: failed to get encryption policy: %s\n",
+	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;
 }
 
@@ -360,11 +477,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.444.g18eeb5a265-goog

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

* [PATCH v3 6/9] xfs_io/encrypt: extend 'set_encpolicy' to support v2 policies
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (4 preceding siblings ...)
  2019-09-28  0:02 ` [PATCH v3 5/9] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies Eric Biggers
@ 2019-09-28  0:02 ` " Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 7/9] xfs_io/encrypt: add 'add_enckey' command Eric Biggers
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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      | 236 ++++++++++++++++++++++++++++++++++++----------
 man/man8/xfs_io.8 |  19 +++-
 2 files changed, 199 insertions(+), 56 deletions(-)

diff --git a/io/encrypt.c b/io/encrypt.c
index 0b45e93f..603d569b 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -174,13 +174,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"));
 	printf("    ");
@@ -240,6 +245,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])
 {
@@ -264,6 +298,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)
 {
@@ -385,46 +505,56 @@ 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)) {
-				fprintf(stderr, "invalid flags: %s\n", optarg);
+			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)) {
-				fprintf(stderr, "invalid policy version: %s\n",
+		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);
 		}
@@ -435,40 +565,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);
-			return 0;
-		}
-
-		x = strtoull(keydesc, &tmp, 16);
-		if (tmp == keydesc || *tmp != '\0') {
-			fprintf(stderr, "invalid key descriptor: %s\n",
-				keydesc);
+		version = str2keyspec(argv[0], version, &key_spec);
+		if (version < 0)
 			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) {
-		fprintf(stderr, "%s: failed to set encryption policy: %s\n",
+	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;
 }
 
@@ -488,7 +622,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.444.g18eeb5a265-goog

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

* [PATCH v3 7/9] xfs_io/encrypt: add 'add_enckey' command
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (5 preceding siblings ...)
  2019-09-28  0:02 ` [PATCH v3 6/9] xfs_io/encrypt: extend 'set_encpolicy' " Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 8/9] xfs_io/encrypt: add 'rm_enckey' command Eric Biggers
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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 603d569b..056f15bc 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -149,6 +149,7 @@ static const struct {
 
 static cmdinfo_t get_encpolicy_cmd;
 static cmdinfo_t set_encpolicy_cmd;
+static cmdinfo_t add_enckey_cmd;
 
 static void
 get_encpolicy_help(void)
@@ -203,6 +204,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 bool
 parse_byte_value(const char *arg, __u8 *value_ret)
 {
@@ -606,6 +623,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) {
+		perror("calloc");
+		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)
 {
@@ -630,6 +729,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.444.g18eeb5a265-goog

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

* [PATCH v3 8/9] xfs_io/encrypt: add 'rm_enckey' command
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (6 preceding siblings ...)
  2019-09-28  0:02 ` [PATCH v3 7/9] xfs_io/encrypt: add 'add_enckey' command Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-28  0:02 ` [PATCH v3 9/9] xfs_io/encrypt: add 'enckey_status' command Eric Biggers
  2019-09-30 19:29 ` [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Sandeen
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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 056f15bc..e87ac393 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -150,6 +150,7 @@ static const struct {
 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)
@@ -220,6 +221,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 bool
 parse_byte_value(const char *arg, __u8 *value_ret)
 {
@@ -705,6 +721,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)
 {
@@ -738,7 +802,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 = _("[-a] 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..be90905a 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 [ -a ] " 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.444.g18eeb5a265-goog

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

* [PATCH v3 9/9] xfs_io/encrypt: add 'enckey_status' command
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (7 preceding siblings ...)
  2019-09-28  0:02 ` [PATCH v3 8/9] xfs_io/encrypt: add 'rm_enckey' command Eric Biggers
@ 2019-09-28  0:02 ` Eric Biggers
  2019-09-30 19:29 ` [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Sandeen
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2019-09-28  0:02 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 e87ac393..17d61cfb 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -151,6 +151,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)
@@ -236,6 +237,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 bool
 parse_byte_value(const char *arg, __u8 *value_ret)
 {
@@ -769,6 +783,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)
 {
@@ -812,8 +872,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 be90905a..2db071e9 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.444.g18eeb5a265-goog

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

* Re: [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io
  2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
                   ` (8 preceding siblings ...)
  2019-09-28  0:02 ` [PATCH v3 9/9] xfs_io/encrypt: add 'enckey_status' command Eric Biggers
@ 2019-09-30 19:29 ` Eric Sandeen
  9 siblings, 0 replies; 11+ messages in thread
From: Eric Sandeen @ 2019-09-30 19:29 UTC (permalink / raw)
  To: Eric Biggers, linux-xfs; +Cc: fstests, linux-fscrypt



On 9/27/19 7:02 PM, Eric Biggers wrote:
> Hello,
> 
> This patchset updates xfs_io to support the new fscrypt ioctls that were
> merged for 5.4 (https://git.kernel.org/torvalds/c/734d1ed83e1f9b7b).
> 
> New commands are added to wrap the new ioctls to manage filesystem
> encryption keys: 'add_enckey', 'rm_enckey', and 'enckey_status'.  Also,
> the existing 'get_encpolicy' and 'set_encpolicy' commands are updated to
> support getting/setting v2 encryption policies.
> 
> The purpose of all this is to allow xfstests to test these 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 xfstests directly
> (https://marc.info/?l=fstests&m=147976255831951&w=2).
> 
> This patchset applies to the latest "for-next" branch of xfsprogs
> (commit ac8b6c380865).  It can also be retrieved from tag
> "fscrypt-key-mgmt-improvements_2019-09-27" of
> https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/xfsprogs-dev.git
> 
> Changes v2 => v3:
> - Generate the encryption modes for 'help set_encpolicy'.
> - Mention '-a' in all relevant places in the help for rm_enckey.
> - Mark strings for translation.

Thanks for the updates.

For the whole series,

Reviewed-by: Eric Sandeen <sandeen@redhat.com>

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

end of thread, back to index

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-28  0:02 [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Biggers
2019-09-28  0:02 ` [PATCH v3 1/9] xfs_io/encrypt: remove unimplemented encryption modes Eric Biggers
2019-09-28  0:02 ` [PATCH v3 2/9] xfs_io/encrypt: update to UAPI definitions from Linux v5.4 Eric Biggers
2019-09-28  0:02 ` [PATCH v3 3/9] xfs_io/encrypt: generate encryption modes for 'help set_encpolicy' Eric Biggers
2019-09-28  0:02 ` [PATCH v3 4/9] xfs_io/encrypt: add new encryption modes Eric Biggers
2019-09-28  0:02 ` [PATCH v3 5/9] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies Eric Biggers
2019-09-28  0:02 ` [PATCH v3 6/9] xfs_io/encrypt: extend 'set_encpolicy' " Eric Biggers
2019-09-28  0:02 ` [PATCH v3 7/9] xfs_io/encrypt: add 'add_enckey' command Eric Biggers
2019-09-28  0:02 ` [PATCH v3 8/9] xfs_io/encrypt: add 'rm_enckey' command Eric Biggers
2019-09-28  0:02 ` [PATCH v3 9/9] xfs_io/encrypt: add 'enckey_status' command Eric Biggers
2019-09-30 19:29 ` [PATCH v3 0/9] xfsprogs: support fscrypt API additions in xfs_io Eric Sandeen

FSTests Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/fstests/0 fstests/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 fstests fstests/ https://lore.kernel.org/fstests \
		fstests@vger.kernel.org linux-fstests@archiver.kernel.org
	public-inbox-index fstests

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.fstests


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