From 635603a1c2a4ee510671e422f4ccef22cf695320 Mon Sep 17 00:00:00 2001 From: Tom Caputi Date: Thu, 24 Oct 2019 13:51:01 -0400 Subject: [PATCH] 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 Reviewed-by: Brian Behlendorf Reviewed-by: Igor Kozhukhov Signed-off-by: Tom Caputi Closes #9494 --- lib/libzfs/libzfs_sendrecv.c | 22 ++++++++++++++----- .../functional/rsend/send_encrypted_props.ksh | 18 ++++++++++++++- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 20a59ef6c..a93235798 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -3659,11 +3659,21 @@ zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type, /* raw streams can't override encryption properties */ 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, "encryption property '%s' cannot " - "be set or excluded for raw or incremental " - "streams."), name); + "be set or excluded for raw 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); goto error; } @@ -3681,10 +3691,12 @@ zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type, */ if (nvlist_exists(origprops, name)) { nvlist_t *attrs; + char *source = NULL; attrs = fnvlist_lookup_nvlist(origprops, name); - if (strcmp(fnvlist_lookup_string(attrs, - ZPROP_SOURCE), ZPROP_SOURCE_VAL_RECVD) != 0) + if (nvlist_lookup_string(attrs, + ZPROP_SOURCE, &source) == 0 && + strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0) continue; } /* diff --git a/tests/zfs-tests/tests/functional/rsend/send_encrypted_props.ksh b/tests/zfs-tests/tests/functional/rsend/send_encrypted_props.ksh index 4c90ba95b..8e21acd99 100755 --- a/tests/zfs-tests/tests/functional/rsend/send_encrypted_props.ksh +++ b/tests/zfs-tests/tests/functional/rsend/send_encrypted_props.ksh @@ -58,7 +58,8 @@ log_assert "'zfs recv' must properly handle encryption properties" typeset keyfile=/$TESTPOOL/pkey 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 esnap2=$TESTPOOL/crypt@snap2 @@ -78,6 +79,7 @@ log_must cp /$TESTPOOL/ds/$TESTFILE0 /$TESTPOOL/crypt/$TESTFILE0 typeset cksum=$(md5digest /$TESTPOOL/ds/$TESTFILE0) log_must zfs snap -r $snap +log_must zfs snap -r $snap2 log_must zfs snap -r $esnap log_must zfs snap -r $esnap2 @@ -193,6 +195,20 @@ recv_cksum=$(md5digest /$ds/$TESTFILE0) log_must test "$recv_cksum" == "$cksum" 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 log_mustnot eval "zpool history -i | grep -q 'wkeydata'"