[RFC,4/8] xfs_io/encrypt: extend 'get_encpolicy' to support v2 policies
diff mbox series

Message ID 20190812175635.34186-5-ebiggers@kernel.org
State Superseded
Headers show
Series
  • xfsprogs: support fscrypt API additions in xfs_io
Related show

Commit Message

Eric Biggers Aug. 12, 2019, 5:56 p.m. UTC
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(-)

Comments

Eric Sandeen Sept. 25, 2019, 5:23 p.m. UTC | #1
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
>
Eric Biggers Sept. 25, 2019, 11:28 p.m. UTC | #2
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
Eric Sandeen Sept. 28, 2019, 12:13 a.m. UTC | #3
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

Patch
diff mbox series

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