This commit is contained in:
andy 2024-09-07 13:14:44 +02:00 committed by GitHub
commit 5b8db3ac0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 124 additions and 12 deletions

View File

@ -425,7 +425,7 @@ get_usage(zfs_help_t idx)
return (gettext("\tchange-key [-l] [-o keyformat=<value>]\n" return (gettext("\tchange-key [-l] [-o keyformat=<value>]\n"
"\t [-o keylocation=<value>] [-o pbkdf2iters=<value>]\n" "\t [-o keylocation=<value>] [-o pbkdf2iters=<value>]\n"
"\t <filesystem|volume>\n" "\t <filesystem|volume>\n"
"\tchange-key -i [-l] <filesystem|volume>\n")); "\tchange-key -i [-lf] <filesystem|volume>\n"));
case HELP_VERSION: case HELP_VERSION:
return (gettext("\tversion [-j]\n")); return (gettext("\tversion [-j]\n"));
case HELP_REDACT: case HELP_REDACT:
@ -8711,11 +8711,11 @@ zfs_do_change_key(int argc, char **argv)
{ {
int c, ret; int c, ret;
uint64_t keystatus; uint64_t keystatus;
boolean_t loadkey = B_FALSE, inheritkey = B_FALSE; boolean_t loadkey = B_FALSE, inheritkey = B_FALSE, force = B_FALSE;
zfs_handle_t *zhp = NULL; zfs_handle_t *zhp = NULL;
nvlist_t *props = fnvlist_alloc(); nvlist_t *props = fnvlist_alloc();
while ((c = getopt(argc, argv, "lio:")) != -1) { while ((c = getopt(argc, argv, "lifo:")) != -1) {
switch (c) { switch (c) {
case 'l': case 'l':
loadkey = B_TRUE; loadkey = B_TRUE;
@ -8723,6 +8723,9 @@ zfs_do_change_key(int argc, char **argv)
case 'i': case 'i':
inheritkey = B_TRUE; inheritkey = B_TRUE;
break; break;
case 'f':
force = B_TRUE;
break;
case 'o': case 'o':
if (!parseprop(props, optarg)) { if (!parseprop(props, optarg)) {
nvlist_free(props); nvlist_free(props);
@ -8742,6 +8745,12 @@ zfs_do_change_key(int argc, char **argv)
usage(B_FALSE); usage(B_FALSE);
} }
if (force && !inheritkey) {
(void) fprintf(stderr,
gettext("Force option only applies to inherit\n"));
usage(B_FALSE);
}
argc -= optind; argc -= optind;
argv += optind; argv += optind;
@ -8775,7 +8784,7 @@ zfs_do_change_key(int argc, char **argv)
zfs_refresh_properties(zhp); zfs_refresh_properties(zhp);
} }
ret = zfs_crypto_rewrap(zhp, props, inheritkey); ret = zfs_crypto_rewrap(zhp, props, inheritkey, force);
if (ret != 0) { if (ret != 0) {
nvlist_free(props); nvlist_free(props);
zfs_close(zhp); zfs_close(zhp);

View File

@ -589,7 +589,8 @@ _LIBZFS_H int zfs_crypto_clone_check(libzfs_handle_t *, zfs_handle_t *, char *,
_LIBZFS_H int zfs_crypto_attempt_load_keys(libzfs_handle_t *, const char *); _LIBZFS_H int zfs_crypto_attempt_load_keys(libzfs_handle_t *, const char *);
_LIBZFS_H int zfs_crypto_load_key(zfs_handle_t *, boolean_t, const char *); _LIBZFS_H int zfs_crypto_load_key(zfs_handle_t *, boolean_t, const char *);
_LIBZFS_H int zfs_crypto_unload_key(zfs_handle_t *); _LIBZFS_H int zfs_crypto_unload_key(zfs_handle_t *);
_LIBZFS_H int zfs_crypto_rewrap(zfs_handle_t *, nvlist_t *, boolean_t); _LIBZFS_H int zfs_crypto_rewrap(zfs_handle_t *, nvlist_t *, boolean_t,
boolean_t);
typedef struct zprop_list { typedef struct zprop_list {
int pl_prop; int pl_prop;

View File

@ -3643,6 +3643,7 @@
<parameter type-id='9200a744' name='zhp'/> <parameter type-id='9200a744' name='zhp'/>
<parameter type-id='5ce45b60' name='raw_props'/> <parameter type-id='5ce45b60' name='raw_props'/>
<parameter type-id='c19b74c3' name='inheritkey'/> <parameter type-id='c19b74c3' name='inheritkey'/>
<parameter type-id='c19b74c3' name='forceinherit'/>
<return type-id='95e97e5e'/> <return type-id='95e97e5e'/>
</function-decl> </function-decl>
<function-decl name='zfs_error_aux' visibility='default' binding='global' size-in-bits='64'> <function-decl name='zfs_error_aux' visibility='default' binding='global' size-in-bits='64'>

View File

@ -1584,7 +1584,8 @@ error:
} }
int int
zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey) zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey,
boolean_t forceinherit)
{ {
int ret; int ret;
char errbuf[ERRBUFLEN]; char errbuf[ERRBUFLEN];
@ -1601,6 +1602,9 @@ zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)
char prop_keylocation[MAXNAMELEN]; char prop_keylocation[MAXNAMELEN];
char parent_name[ZFS_MAX_DATASET_NAME_LEN]; char parent_name[ZFS_MAX_DATASET_NAME_LEN];
if (inheritkey && forceinherit)
cmd = DCP_CMD_FORCE_INHERIT;
(void) snprintf(errbuf, sizeof (errbuf), (void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "Key change error")); dgettext(TEXT_DOMAIN, "Key change error"));
@ -1760,7 +1764,7 @@ zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)
/* check that the parent's key is loaded */ /* check that the parent's key is loaded */
pkeystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS); pkeystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS);
if (pkeystatus == ZFS_KEYSTATUS_UNAVAILABLE) { if (!forceinherit && pkeystatus == ZFS_KEYSTATUS_UNAVAILABLE) {
zfs_error_aux(pzhp->zfs_hdl, dgettext(TEXT_DOMAIN, zfs_error_aux(pzhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"Parent key must be loaded.")); "Parent key must be loaded."));
ret = EACCES; ret = EACCES;
@ -1770,7 +1774,7 @@ zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)
/* check that the key is loaded */ /* check that the key is loaded */
keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS); keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);
if (keystatus == ZFS_KEYSTATUS_UNAVAILABLE) { if (!forceinherit && keystatus == ZFS_KEYSTATUS_UNAVAILABLE) {
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"Key must be loaded.")); "Key must be loaded."));
ret = EACCES; ret = EACCES;

View File

@ -56,7 +56,7 @@
.Nm zfs .Nm zfs
.Cm change-key .Cm change-key
.Fl i .Fl i
.Op Fl l .Op Fl lf
.Ar filesystem .Ar filesystem
. .
.Sh DESCRIPTION .Sh DESCRIPTION
@ -159,7 +159,7 @@ Unloads the keys for all encryption roots in all imported pools.
.Nm zfs .Nm zfs
.Cm change-key .Cm change-key
.Fl i .Fl i
.Op Fl l .Op Fl lf
.Ar filesystem .Ar filesystem
.Xc .Xc
Changes the user's key (e.g. a passphrase) used to access a dataset. Changes the user's key (e.g. a passphrase) used to access a dataset.
@ -217,6 +217,12 @@ Indicates that zfs should make
inherit the key of its parent. inherit the key of its parent.
Note that this command can only be run on an encryption root Note that this command can only be run on an encryption root
that has an encrypted parent. that has an encrypted parent.
.It Fl f
When used with
.Fl i
the key will be force-inherited.
This should only be used when it is known that the parent is a replica of the
original encryptionroot and has the same key.
.El .El
.El .El
.Ss Encryption .Ss Encryption

View File

@ -187,7 +187,8 @@ tags = ['functional', 'cli_root', 'zfs_bookmark']
[tests/functional/cli_root/zfs_change-key] [tests/functional/cli_root/zfs_change-key]
tests = ['zfs_change-key', 'zfs_change-key_child', 'zfs_change-key_format', tests = ['zfs_change-key', 'zfs_change-key_child', 'zfs_change-key_format',
'zfs_change-key_inherit', 'zfs_change-key_load', 'zfs_change-key_location', 'zfs_change-key_inherit', 'zfs_change-key_load', 'zfs_change-key_location',
'zfs_change-key_pbkdf2iters', 'zfs_change-key_clones'] 'zfs_change-key_pbkdf2iters', 'zfs_change-key_clones',
'zfs_change-key_inherit-force']
tags = ['functional', 'cli_root', 'zfs_change-key'] tags = ['functional', 'cli_root', 'zfs_change-key']
[tests/functional/cli_root/zfs_clone] [tests/functional/cli_root/zfs_clone]

View File

@ -104,7 +104,8 @@ tags = ['functional', 'cli_root', 'zfs_bookmark']
[tests/functional/cli_root/zfs_change-key] [tests/functional/cli_root/zfs_change-key]
tests = ['zfs_change-key', 'zfs_change-key_child', 'zfs_change-key_format', tests = ['zfs_change-key', 'zfs_change-key_child', 'zfs_change-key_format',
'zfs_change-key_inherit', 'zfs_change-key_load', 'zfs_change-key_location', 'zfs_change-key_inherit', 'zfs_change-key_load', 'zfs_change-key_location',
'zfs_change-key_pbkdf2iters', 'zfs_change-key_clones'] 'zfs_change-key_pbkdf2iters', 'zfs_change-key_clones',
'zfs_change-key_inherit-force']
tags = ['functional', 'cli_root', 'zfs_change-key'] tags = ['functional', 'cli_root', 'zfs_change-key']
[tests/functional/cli_root/zfs_clone] [tests/functional/cli_root/zfs_clone]

View File

@ -639,6 +639,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zfs_change-key/zfs_change-key_child.ksh \ functional/cli_root/zfs_change-key/zfs_change-key_child.ksh \
functional/cli_root/zfs_change-key/zfs_change-key_clones.ksh \ functional/cli_root/zfs_change-key/zfs_change-key_clones.ksh \
functional/cli_root/zfs_change-key/zfs_change-key_format.ksh \ functional/cli_root/zfs_change-key/zfs_change-key_format.ksh \
functional/cli_root/zfs_change-key/zfs_change-key_inherit-force.ksh \
functional/cli_root/zfs_change-key/zfs_change-key_inherit.ksh \ functional/cli_root/zfs_change-key/zfs_change-key_inherit.ksh \
functional/cli_root/zfs_change-key/zfs_change-key.ksh \ functional/cli_root/zfs_change-key/zfs_change-key.ksh \
functional/cli_root/zfs_change-key/zfs_change-key_load.ksh \ functional/cli_root/zfs_change-key/zfs_change-key_load.ksh \

View File

@ -0,0 +1,88 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
# CDDL HEADER END
#
#
# Copyright (c) 2017 Datto, Inc. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib
#
# DESCRIPTION:
# 'zfs change-key -if' should cause a dataset to inherit its parent key
# without the key being loaded
#
# STRATEGY:
# 1. Create a parent encrypted dataset
# 2. Create a child dataset
# 3. Create a copy of the parent dataset
# 4. Send a copy of the child to the copy of the parent
# 5. Attempt to force inherit the parent key without the keys being loaded
# 6. Verify the key is inherited
# 7. Load the parent key
# 8. Verify the key is available for parent and child
# 9. Attempt to mount the datasets
#
verify_runnable "both"
function cleanup
{
datasetexists $TESTPOOL/$TESTFS1 && \
destroy_dataset $TESTPOOL/$TESTFS1 -r
datasetexists $TESTPOOL/$TESTFS2 && \
destroy_dataset $TESTPOOL/$TESTFS2 -r
}
log_onexit cleanup
log_assert "'zfs change-key -if' should cause a dataset to inherit its" \
"parent key"
log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \
"-o keyformat=passphrase -o keylocation=prompt $TESTPOOL/$TESTFS1"
log_must eval "echo $PASSPHRASE1 | zfs create $TESTPOOL/$TESTFS1/child"
log_must verify_encryption_root $TESTPOOL/$TESTFS1/child "$TESTPOOL/$TESTFS1"
log_must zfs snapshot -r $TESTPOOL/$TESTFS1@snap
log_must eval "zfs send -w $TESTPOOL/$TESTFS1@snap | zfs receive $TESTPOOL/$TESTFS2"
log_must verify_encryption_root $TESTPOOL/$TESTFS2 $TESTPOOL/$TESTFS2
log_must key_unavailable $TESTPOOL/$TESTFS2
log_must eval "zfs send -w $TESTPOOL/$TESTFS1/child@snap | zfs receive $TESTPOOL/$TESTFS2/child"
log_must verify_encryption_root $TESTPOOL/$TESTFS2/child $TESTPOOL/$TESTFS2/child
log_must key_unavailable $TESTPOOL/$TESTFS2/child
log_must_not zfs change-key -i $TESTPOOL/$TESTFS2/child
log_must_not zfs change-key -f $TESTPOOL/$TESTFS2/child
log_must zfs change-key -if $TESTPOOL/$TESTFS2/child
log_must verify_encryption_root $TESTPOOL/$TESTFS2/child "$TESTPOOL/$TESTFS2"
log_must key_unavailable $TESTPOOL/$TESTFS2
log_must key_unavailable $TESTPOOL/$TESTFS2/child
log_must eval "echo $PASSPHRASE | zfs load-key $TESTPOOL/$TESTFS2"
log_must key_available $TESTPOOL/$TESTFS2
log_must key_available $TESTPOOL/$TESTFS2/child
log_must zfs mount $TESTPOOL/$TESTFS2
log_must zfs mount $TESTPOOL/$TESTFS2/child
log_pass "'zfs change-key -if' causes a dataset to inherit its parent key"