Skip to content

Commit

Permalink
Fix raw sends on encrypted datasets when copying back snapshots
Browse files Browse the repository at this point in the history
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.

Closes #10523.

Signed-off-by: George Amanakis <gamanakis@gmail.com>
  • Loading branch information
gamanakis committed Nov 19, 2020
1 parent 85703f6 commit bb5884a
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 27 deletions.
25 changes: 15 additions & 10 deletions module/os/freebsd/zfs/zio_crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,19 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,

bcopy(raw_portable_mac, portable_mac, ZIO_OBJSET_MAC_LEN);

/*
* Add in the non-portable os_flags. This is necessary here as we check
* whether OBJSET_FLAG_USERACCOUNTING_COMPLETE is set in order to
* decide if the local_mac should be zeroed out.
*/
intval = osp->os_flags;
if (should_bswap)
intval = BSWAP_64(intval);
intval &= ~OBJSET_CRYPT_PORTABLE_FLAGS_MASK;
/* CONSTCOND */
if (!ZFS_HOST_BYTEORDER)
intval = BSWAP_64(intval);

/*
* The local MAC protects the user, group and project accounting.
* If these objects are not present, the local MAC is zeroed out.
Expand All @@ -1081,23 +1094,15 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
(datalen >= OBJSET_PHYS_SIZE_V2 &&
osp->os_userused_dnode.dn_type == DMU_OT_NONE &&
osp->os_groupused_dnode.dn_type == DMU_OT_NONE) ||
(datalen <= OBJSET_PHYS_SIZE_V1)) {
(datalen <= OBJSET_PHYS_SIZE_V1) ||
(intval & OBJSET_FLAG_USERACCOUNTING_COMPLETE) == 0) {
bzero(local_mac, ZIO_OBJSET_MAC_LEN);
return (0);
}

/* calculate the local MAC from the userused and groupused dnodes */
crypto_mac_init(ctx, &key->zk_hmac_key);

/* add in the non-portable os_flags */
intval = osp->os_flags;
if (should_bswap)
intval = BSWAP_64(intval);
intval &= ~OBJSET_CRYPT_PORTABLE_FLAGS_MASK;
/* CONSTCOND */
if (!ZFS_HOST_BYTEORDER)
intval = BSWAP_64(intval);

crypto_mac_update(ctx, &intval, sizeof (uint64_t));

/* XXX check dnode type ... */
Expand Down
23 changes: 14 additions & 9 deletions module/os/linux/zfs/zio_crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,18 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,

bcopy(raw_portable_mac, portable_mac, ZIO_OBJSET_MAC_LEN);

/*
* Add in the non-portable os_flags. This is necessary here as we check
* whether OBJSET_FLAG_USERACCOUNTING_COMPLETE is set in order to
* decide if the local_mac should be zeroed out.
*/
intval = osp->os_flags;
if (should_bswap)
intval = BSWAP_64(intval);
intval &= ~OBJSET_CRYPT_PORTABLE_FLAGS_MASK;
if (!ZFS_HOST_BYTEORDER)
intval = BSWAP_64(intval);

/*
* The local MAC protects the user, group and project accounting.
* If these objects are not present, the local MAC is zeroed out.
Expand All @@ -1208,7 +1220,8 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
(datalen >= OBJSET_PHYS_SIZE_V2 &&
osp->os_userused_dnode.dn_type == DMU_OT_NONE &&
osp->os_groupused_dnode.dn_type == DMU_OT_NONE) ||
(datalen <= OBJSET_PHYS_SIZE_V1)) {
(datalen <= OBJSET_PHYS_SIZE_V1) ||
(intval & OBJSET_FLAG_USERACCOUNTING_COMPLETE) == 0) {
bzero(local_mac, ZIO_OBJSET_MAC_LEN);
return (0);
}
Expand All @@ -1220,14 +1233,6 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
goto error;
}

/* add in the non-portable os_flags */
intval = osp->os_flags;
if (should_bswap)
intval = BSWAP_64(intval);
intval &= ~OBJSET_CRYPT_PORTABLE_FLAGS_MASK;
if (!ZFS_HOST_BYTEORDER)
intval = BSWAP_64(intval);

cd.cd_length = sizeof (uint64_t);
cd.cd_raw.iov_base = (char *)&intval;
cd.cd_raw.iov_len = cd.cd_length;
Expand Down
10 changes: 2 additions & 8 deletions module/zfs/dsl_crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2007,14 +2007,6 @@ dsl_crypto_recv_raw_objset_check(dsl_dataset_t *ds, dsl_dataset_t *fromds,
if (ret != 0)
return (ret);

/*
* Useraccounting is not portable and must be done with the keys loaded.
* Therefore, whenever we do any kind of receive the useraccounting
* must not be present.
*/
ASSERT0(os->os_flags & OBJSET_FLAG_USERACCOUNTING_COMPLETE);
ASSERT0(os->os_flags & OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE);

mdn = DMU_META_DNODE(os);

/*
Expand Down Expand Up @@ -2105,6 +2097,8 @@ dsl_crypto_recv_raw_objset_sync(dsl_dataset_t *ds, dmu_objset_type_t ostype,
*/
arc_release(os->os_phys_buf, &os->os_phys_buf);
bcopy(portable_mac, os->os_phys->os_portable_mac, ZIO_OBJSET_MAC_LEN);
os->os_phys->os_flags &= ~OBJSET_FLAG_USERACCOUNTING_COMPLETE;
os->os_flags = os->os_phys->os_flags;
bzero(os->os_phys->os_local_mac, ZIO_OBJSET_MAC_LEN);
os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE;

Expand Down

0 comments on commit bb5884a

Please sign in to comment.