Skip to content

Commit d1d4769

Browse files
authored
Fix raw sends on encrypted datasets when copying back snapshots
When sending raw encrypted datasets the user space accounting is present when it's not expected to be. This leads to the subsequent mount failure due a checksum error when verifying the local mac. Fix this by clearing the OBJSET_FLAG_USERACCOUNTING_COMPLETE and reset the local mac. This allows the user accounting to be correctly updated on first mount using the normal upgrade process. Reviewed-By: Brian Behlendorf <[email protected]> Reviewed-By: Tom Caputi <[email protected]> Signed-off-by: George Amanakis <[email protected]> Closes openzfs#10523 Closes openzfs#11221
1 parent 0cb40fa commit d1d4769

File tree

5 files changed

+141
-11
lines changed

5 files changed

+141
-11
lines changed

module/os/freebsd/zfs/zio_crypt.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,16 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
10701070

10711071
bcopy(raw_portable_mac, portable_mac, ZIO_OBJSET_MAC_LEN);
10721072

1073+
/*
1074+
* This is necessary here as we check next whether
1075+
* OBJSET_FLAG_USERACCOUNTING_COMPLETE or
1076+
* OBJSET_FLAG_USEROBJACCOUNTING are set in order to
1077+
* decide if the local_mac should be zeroed out.
1078+
*/
1079+
intval = osp->os_flags;
1080+
if (should_bswap)
1081+
intval = BSWAP_64(intval);
1082+
10731083
/*
10741084
* The local MAC protects the user, group and project accounting.
10751085
* If these objects are not present, the local MAC is zeroed out.
@@ -1081,7 +1091,10 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
10811091
(datalen >= OBJSET_PHYS_SIZE_V2 &&
10821092
osp->os_userused_dnode.dn_type == DMU_OT_NONE &&
10831093
osp->os_groupused_dnode.dn_type == DMU_OT_NONE) ||
1084-
(datalen <= OBJSET_PHYS_SIZE_V1)) {
1094+
(datalen <= OBJSET_PHYS_SIZE_V1) ||
1095+
(((intval & OBJSET_FLAG_USERACCOUNTING_COMPLETE) == 0 ||
1096+
(intval & OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE) == 0) &&
1097+
key->zk_version > 0)) {
10851098
bzero(local_mac, ZIO_OBJSET_MAC_LEN);
10861099
return (0);
10871100
}

module/os/linux/zfs/zio_crypt.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,16 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
11971197

11981198
bcopy(raw_portable_mac, portable_mac, ZIO_OBJSET_MAC_LEN);
11991199

1200+
/*
1201+
* This is necessary here as we check next whether
1202+
* OBJSET_FLAG_USERACCOUNTING_COMPLETE or
1203+
* OBJSET_FLAG_USEROBJACCOUNTING are set in order to
1204+
* decide if the local_mac should be zeroed out.
1205+
*/
1206+
intval = osp->os_flags;
1207+
if (should_bswap)
1208+
intval = BSWAP_64(intval);
1209+
12001210
/*
12011211
* The local MAC protects the user, group and project accounting.
12021212
* If these objects are not present, the local MAC is zeroed out.
@@ -1208,7 +1218,10 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
12081218
(datalen >= OBJSET_PHYS_SIZE_V2 &&
12091219
osp->os_userused_dnode.dn_type == DMU_OT_NONE &&
12101220
osp->os_groupused_dnode.dn_type == DMU_OT_NONE) ||
1211-
(datalen <= OBJSET_PHYS_SIZE_V1)) {
1221+
(datalen <= OBJSET_PHYS_SIZE_V1) ||
1222+
(((intval & OBJSET_FLAG_USERACCOUNTING_COMPLETE) == 0 ||
1223+
(intval & OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE) == 0) &&
1224+
key->zk_version > 0)) {
12121225
bzero(local_mac, ZIO_OBJSET_MAC_LEN);
12131226
return (0);
12141227
}

module/zfs/dsl_crypt.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,14 +2007,6 @@ dsl_crypto_recv_raw_objset_check(dsl_dataset_t *ds, dsl_dataset_t *fromds,
20072007
if (ret != 0)
20082008
return (ret);
20092009

2010-
/*
2011-
* Useraccounting is not portable and must be done with the keys loaded.
2012-
* Therefore, whenever we do any kind of receive the useraccounting
2013-
* must not be present.
2014-
*/
2015-
ASSERT0(os->os_flags & OBJSET_FLAG_USERACCOUNTING_COMPLETE);
2016-
ASSERT0(os->os_flags & OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE);
2017-
20182010
mdn = DMU_META_DNODE(os);
20192011

20202012
/*
@@ -2105,6 +2097,9 @@ dsl_crypto_recv_raw_objset_sync(dsl_dataset_t *ds, dmu_objset_type_t ostype,
21052097
*/
21062098
arc_release(os->os_phys_buf, &os->os_phys_buf);
21072099
bcopy(portable_mac, os->os_phys->os_portable_mac, ZIO_OBJSET_MAC_LEN);
2100+
os->os_phys->os_flags &= ~OBJSET_FLAG_USERACCOUNTING_COMPLETE;
2101+
os->os_phys->os_flags &= ~OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
2102+
os->os_flags = os->os_phys->os_flags;
21082103
bzero(os->os_phys->os_local_mac, ZIO_OBJSET_MAC_LEN);
21092104
os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE;
21102105

tests/runfiles/common.run

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,8 @@ tests = [
865865
'userquota_004_pos', 'userquota_005_neg', 'userquota_006_pos',
866866
'userquota_007_pos', 'userquota_008_pos', 'userquota_009_pos',
867867
'userquota_010_pos', 'userquota_011_pos', 'userquota_012_neg',
868-
'userspace_001_pos', 'userspace_002_pos', 'userspace_encrypted']
868+
'userspace_001_pos', 'userspace_002_pos', 'userspace_encrypted',
869+
'userspace_send_encrypted']
869870
tags = ['functional', 'userquota']
870871

871872
[tests/functional/vdev_zaps]
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/bin/ksh -p
2+
#
3+
# This file and its contents are supplied under the terms of the
4+
# Common Development and Distribution License ("CDDL"), version 1.0.
5+
# You may only use this file in accordance with the terms of version
6+
# 1.0 of the CDDL.
7+
#
8+
# A full copy of the text of the CDDL should have accompanied this
9+
# source. A copy of the CDDL is also available via the Internet at
10+
# http://www.illumos.org/license/CDDL.
11+
#
12+
13+
#
14+
# Copyright 2020, George Amanakis <[email protected]>. All rights reserved.
15+
#
16+
17+
. $STF_SUITE/include/libtest.shlib
18+
. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
19+
20+
#
21+
# DESCRIPTION:
22+
# Sending raw encrypted datasets back to the source dataset succeeds.
23+
#
24+
#
25+
# STRATEGY:
26+
# 1. Create encrypted source dataset, set userquota and write a file
27+
# 2. Create base and an additional snapshot (s1)
28+
# 3. Unmount the source dataset
29+
# 4. Raw send the base snapshot to a new target dataset
30+
# 5. Raw send incrementally the s1 snapshot to the new target dataset
31+
# 6. Mount both source and target datasets
32+
# 7. Verify encrypted datasets support 'zfs userspace' and 'zfs groupspace'
33+
# and the accounting is done correctly
34+
#
35+
36+
function cleanup
37+
{
38+
destroy_pool $POOLNAME
39+
rm -f $FILEDEV
40+
}
41+
42+
function log_must_unsupported
43+
{
44+
log_must_retry "unsupported" 3 "$@"
45+
(( $? != 0 )) && log_fail
46+
}
47+
48+
log_onexit cleanup
49+
50+
FILEDEV="$TEST_BASE_DIR/userspace_encrypted"
51+
POOLNAME="testpool$$"
52+
ENC_SOURCE="$POOLNAME/source"
53+
ENC_TARGET="$POOLNAME/target"
54+
55+
log_assert "Sending raw encrypted datasets back to the source dataset succeeds."
56+
57+
# Setup
58+
truncate -s 200m $FILEDEV
59+
log_must zpool create -o feature@encryption=enabled $POOLNAME \
60+
$FILEDEV
61+
62+
# Create encrypted source dataset
63+
log_must eval "echo 'password' | zfs create -o encryption=on" \
64+
"-o keyformat=passphrase -o keylocation=prompt " \
65+
"$ENC_SOURCE"
66+
67+
# Set user quota and write file
68+
log_must zfs set userquota@$QUSER1=50m $ENC_SOURCE
69+
mkmount_writable $ENC_SOURCE
70+
mntpnt=$(get_prop mountpoint $ENC_SOURCE)
71+
log_must user_run $QUSER1 mkfile 20m /$mntpnt/file
72+
sync
73+
74+
# Snapshot, raw send to new dataset
75+
log_must zfs snap $ENC_SOURCE@base
76+
log_must zfs snap $ENC_SOURCE@s1
77+
log_must zfs umount $ENC_SOURCE
78+
log_must eval "zfs send -w $ENC_SOURCE@base | zfs recv " \
79+
"$ENC_TARGET"
80+
81+
log_must eval "zfs send -w -i @base $ENC_SOURCE@s1 | zfs recv " \
82+
"$ENC_TARGET"
83+
84+
log_must zfs destroy $ENC_SOURCE@s1
85+
log_must eval "zfs send -w -i @base $ENC_TARGET@s1 | zfs recv " \
86+
"$ENC_SOURCE"
87+
88+
# Mount encrypted datasets and verify they support 'zfs userspace' and
89+
# 'zfs groupspace' and the accounting is done correctly
90+
log_must zfs mount $ENC_SOURCE
91+
log_must eval "echo password | zfs load-key $ENC_TARGET"
92+
log_must zfs mount $ENC_TARGET
93+
sync
94+
95+
src_uspace=$(( $(zfs userspace -Hp $ENC_SOURCE | grep $QUSER1 | \
96+
awk '{print $4}')/1024/1024))
97+
tgt_uspace=$(( $(zfs userspace -Hp $ENC_TARGET | grep $QUSER1 | \
98+
awk '{print $4}')/1024/1024))
99+
log_must test "$src_uspace" -eq "$tgt_uspace"
100+
101+
src_uquota=$(zfs userspace -Hp $ENC_SOURCE | grep $QUSER1 | awk '{print $5}')
102+
tgt_uquota=$(zfs userspace -Hp $ENC_TARGET | grep $QUSER1 | awk '{print $5}')
103+
log_must test "$src_uquota" -eq "$tgt_uquota"
104+
105+
# Cleanup
106+
cleanup
107+
108+
log_pass "Sending raw encrypted datasets back to the source dataset succeeds."

0 commit comments

Comments
 (0)