Fix incremental recursive encrypted receive

Currently, incremental recursive encrypted receives fail to work
for any snapshot after the first. The reason for this is because
the check in zfs_setup_cmdline_props() did not properly realize
that when the user attempts to use '-x encryption' in this
situation, they are not really overriding the existing encryption
property and instead are attempting to prevent it from changing.
This resulted in an error message stating: "encryption property
'encryption' cannot be set or excluded for raw or incremental
streams".

This problem is fixed by updating the logic to expect this use
case.

Reviewed-by: loli10K <ezomori.nozomu@gmail.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Igor Kozhukhov <igor@dilos.org>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Closes #9494
This commit is contained in:
Tom Caputi 2019-10-24 13:51:01 -04:00 committed by Tony Hutter
parent 635bf1c37c
commit 635603a1c2
2 changed files with 34 additions and 6 deletions

View File

@ -3659,11 +3659,21 @@ zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type,
/* raw streams can't override encryption properties */ /* raw streams can't override encryption properties */
if ((zfs_prop_encryption_key_param(prop) || if ((zfs_prop_encryption_key_param(prop) ||
prop == ZFS_PROP_ENCRYPTION) && (raw || !newfs)) { prop == ZFS_PROP_ENCRYPTION) && raw) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"encryption property '%s' cannot " "encryption property '%s' cannot "
"be set or excluded for raw or incremental " "be set or excluded for raw streams."), name);
"streams."), name); ret = zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}
/* incremental streams can only exclude encryption properties */
if ((zfs_prop_encryption_key_param(prop) ||
prop == ZFS_PROP_ENCRYPTION) && !newfs &&
nvpair_type(nvp) != DATA_TYPE_BOOLEAN) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"encryption property '%s' cannot "
"be set for incremental streams."), name);
ret = zfs_error(hdl, EZFS_BADPROP, errbuf); ret = zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error; goto error;
} }
@ -3681,10 +3691,12 @@ zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type,
*/ */
if (nvlist_exists(origprops, name)) { if (nvlist_exists(origprops, name)) {
nvlist_t *attrs; nvlist_t *attrs;
char *source = NULL;
attrs = fnvlist_lookup_nvlist(origprops, name); attrs = fnvlist_lookup_nvlist(origprops, name);
if (strcmp(fnvlist_lookup_string(attrs, if (nvlist_lookup_string(attrs,
ZPROP_SOURCE), ZPROP_SOURCE_VAL_RECVD) != 0) ZPROP_SOURCE, &source) == 0 &&
strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0)
continue; continue;
} }
/* /*

View File

@ -58,7 +58,8 @@ log_assert "'zfs recv' must properly handle encryption properties"
typeset keyfile=/$TESTPOOL/pkey typeset keyfile=/$TESTPOOL/pkey
typeset sendfile=/$TESTPOOL/sendfile typeset sendfile=/$TESTPOOL/sendfile
typeset snap=$TESTPOOL/ds@snap typeset snap=$TESTPOOL/ds@snap1
typeset snap2=$TESTPOOL/ds@snap2
typeset esnap=$TESTPOOL/crypt@snap1 typeset esnap=$TESTPOOL/crypt@snap1
typeset esnap2=$TESTPOOL/crypt@snap2 typeset esnap2=$TESTPOOL/crypt@snap2
@ -78,6 +79,7 @@ log_must cp /$TESTPOOL/ds/$TESTFILE0 /$TESTPOOL/crypt/$TESTFILE0
typeset cksum=$(md5digest /$TESTPOOL/ds/$TESTFILE0) typeset cksum=$(md5digest /$TESTPOOL/ds/$TESTFILE0)
log_must zfs snap -r $snap log_must zfs snap -r $snap
log_must zfs snap -r $snap2
log_must zfs snap -r $esnap log_must zfs snap -r $esnap
log_must zfs snap -r $esnap2 log_must zfs snap -r $esnap2
@ -193,6 +195,20 @@ recv_cksum=$(md5digest /$ds/$TESTFILE0)
log_must test "$recv_cksum" == "$cksum" log_must test "$recv_cksum" == "$cksum"
log_must zfs destroy -r $ds log_must zfs destroy -r $ds
# Test that we can override an unencrypted, incremental, recursive stream's
# encryption settings, receiving all datasets as encrypted children.
log_note "Must be able to receive recursive stream to encrypted child"
ds=$TESTPOOL/crypt/recv
log_must eval "zfs send -R $snap2 > $sendfile"
log_must eval "zfs recv -x encryption $ds < $sendfile"
log_must test "$(get_prop 'encryptionroot' $ds)" == "$TESTPOOL/crypt"
log_must test "$(get_prop 'encryption' $ds)" == "aes-256-ccm"
log_must test "$(get_prop 'keyformat' $ds)" == "passphrase"
log_must test "$(get_prop 'mounted' $ds)" == "yes"
recv_cksum=$(md5digest /$ds/$TESTFILE0)
log_must test "$recv_cksum" == "$cksum"
log_must zfs destroy -r $ds
# Check that we haven't printed the key to the zpool history log # Check that we haven't printed the key to the zpool history log
log_mustnot eval "zpool history -i | grep -q 'wkeydata'" log_mustnot eval "zpool history -i | grep -q 'wkeydata'"