mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Encryption patch follow-up
* PBKDF2 implementation changed to OpenSSL implementation. * HKDF implementation moved to its own file and tests added to ensure correctness. * Removed libzfs's now unnecessary dependency on libzpool and libicp. * Ztest can now create and test encrypted datasets. This is currently disabled until issue #6526 is resolved, but otherwise functions as advertised. * Several small bug fixes discovered after enabling ztest to run on encrypted datasets. * Fixed coverity defects added by the encryption patch. * Updated man pages for encrypted send / receive behavior. * Fixed a bug where encrypted datasets could receive DRR_WRITE_EMBEDDED records. * Minor code cleanups / consolidation. Signed-off-by: Tom Caputi <tcaputi@datto.com>
This commit is contained in:
+11
-12
@@ -7267,28 +7267,27 @@ zfs_do_change_key(int argc, char **argv)
|
||||
keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);
|
||||
if (keystatus != ZFS_KEYSTATUS_AVAILABLE) {
|
||||
ret = zfs_crypto_load_key(zhp, B_FALSE, NULL);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
if (ret != 0) {
|
||||
nvlist_free(props);
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* refresh the properties so the new keystatus is visable */
|
||||
/* refresh the properties so the new keystatus is visible */
|
||||
zfs_refresh_properties(zhp);
|
||||
}
|
||||
|
||||
ret = zfs_crypto_rewrap(zhp, props, inheritkey);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
if (ret != 0) {
|
||||
nvlist_free(props);
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
nvlist_free(props);
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
|
||||
error:
|
||||
if (props != NULL)
|
||||
nvlist_free(props);
|
||||
if (zhp != NULL)
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
+11
-4
@@ -8049,10 +8049,17 @@ main(int argc, char **argv)
|
||||
* 'freeze' is a vile debugging abomination, so we treat
|
||||
* it as such.
|
||||
*/
|
||||
char buf[16384];
|
||||
int fd = open(ZFS_DEV, O_RDWR);
|
||||
(void) strlcpy((void *)buf, argv[2], sizeof (buf));
|
||||
return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
|
||||
zfs_cmd_t zc = {"\0"};
|
||||
|
||||
(void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name));
|
||||
ret = zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc);
|
||||
if (ret != 0) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("failed to freeze pool: %d\n"), errno);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
log_history = 0;
|
||||
} else {
|
||||
(void) fprintf(stderr, gettext("unrecognized "
|
||||
"command '%s'\n"), cmdname);
|
||||
|
||||
+103
-16
@@ -201,6 +201,7 @@ extern int zfs_abd_scatter_enabled;
|
||||
|
||||
static ztest_shared_opts_t *ztest_shared_opts;
|
||||
static ztest_shared_opts_t ztest_opts;
|
||||
static char *ztest_wkeydata = "abcdefghijklmnopqrstuvwxyz012345";
|
||||
|
||||
typedef struct ztest_shared_ds {
|
||||
uint64_t zd_seq;
|
||||
@@ -1180,6 +1181,42 @@ ztest_spa_prop_set_uint64(zpool_prop_t prop, uint64_t value)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ztest_dmu_objset_own(const char *name, dmu_objset_type_t type,
|
||||
boolean_t readonly, boolean_t decrypt, void *tag, objset_t **osp)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dmu_objset_own(name, type, readonly, decrypt, tag, osp);
|
||||
if (decrypt && err == EACCES) {
|
||||
char ddname[ZFS_MAX_DATASET_NAME_LEN];
|
||||
dsl_crypto_params_t *dcp;
|
||||
nvlist_t *crypto_args = fnvlist_alloc();
|
||||
char *cp = NULL;
|
||||
|
||||
/* spa_keystore_load_wkey() expects a dsl dir name */
|
||||
strcpy(ddname, name);
|
||||
cp = strchr(ddname, '@');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
|
||||
fnvlist_add_uint8_array(crypto_args, "wkeydata",
|
||||
(uint8_t *)ztest_wkeydata, WRAPPING_KEY_LEN);
|
||||
VERIFY0(dsl_crypto_params_create_nvlist(DCP_CMD_NONE, NULL,
|
||||
crypto_args, &dcp));
|
||||
err = spa_keystore_load_wkey(ddname, dcp, B_FALSE);
|
||||
dsl_crypto_params_free(dcp, B_FALSE);
|
||||
fnvlist_free(crypto_args);
|
||||
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
err = dmu_objset_own(name, type, readonly, decrypt, tag, osp);
|
||||
}
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Object and range lock mechanics
|
||||
@@ -3532,11 +3569,57 @@ ztest_objset_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
|
||||
static int
|
||||
ztest_dataset_create(char *dsname)
|
||||
{
|
||||
uint64_t zilset = ztest_random(100);
|
||||
int err = dmu_objset_create(dsname, DMU_OST_OTHER, 0, NULL,
|
||||
ztest_objset_create_cb, NULL);
|
||||
int err;
|
||||
uint64_t rand;
|
||||
dsl_crypto_params_t *dcp = NULL;
|
||||
|
||||
if (err || zilset < 80)
|
||||
/*
|
||||
* 50% of the time, we create encrypted datasets
|
||||
* using a random cipher suite and a hard-coded
|
||||
* wrapping key.
|
||||
*/
|
||||
rand = ztest_random(2);
|
||||
if (rand != 0) {
|
||||
nvlist_t *crypto_args = fnvlist_alloc();
|
||||
nvlist_t *props = fnvlist_alloc();
|
||||
|
||||
/* slight bias towards the default cipher suite */
|
||||
rand = ztest_random(ZIO_CRYPT_FUNCTIONS);
|
||||
if (rand < ZIO_CRYPT_AES_128_CCM)
|
||||
rand = ZIO_CRYPT_ON;
|
||||
|
||||
fnvlist_add_uint64(props,
|
||||
zfs_prop_to_name(ZFS_PROP_ENCRYPTION), rand);
|
||||
fnvlist_add_uint8_array(crypto_args, "wkeydata",
|
||||
(uint8_t *)ztest_wkeydata, WRAPPING_KEY_LEN);
|
||||
|
||||
/*
|
||||
* These parameters aren't really used by the kernel. They
|
||||
* are simply stored so that userspace knows how to load
|
||||
* the wrapping key.
|
||||
*/
|
||||
fnvlist_add_uint64(props,
|
||||
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), ZFS_KEYFORMAT_RAW);
|
||||
fnvlist_add_string(props,
|
||||
zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt");
|
||||
fnvlist_add_uint64(props,
|
||||
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 0ULL);
|
||||
fnvlist_add_uint64(props,
|
||||
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), 0ULL);
|
||||
|
||||
VERIFY0(dsl_crypto_params_create_nvlist(DCP_CMD_NONE, props,
|
||||
crypto_args, &dcp));
|
||||
|
||||
fnvlist_free(crypto_args);
|
||||
fnvlist_free(props);
|
||||
}
|
||||
|
||||
err = dmu_objset_create(dsname, DMU_OST_OTHER, 0, dcp,
|
||||
ztest_objset_create_cb, NULL);
|
||||
dsl_crypto_params_free(dcp, !!err);
|
||||
|
||||
rand = ztest_random(100);
|
||||
if (err || rand < 80)
|
||||
return (err);
|
||||
|
||||
if (ztest_opts.zo_verbose >= 5)
|
||||
@@ -3556,7 +3639,8 @@ ztest_objset_destroy_cb(const char *name, void *arg)
|
||||
/*
|
||||
* Verify that the dataset contains a directory object.
|
||||
*/
|
||||
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, B_TRUE, FTAG, &os));
|
||||
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
|
||||
B_TRUE, FTAG, &os));
|
||||
error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
|
||||
if (error != ENOENT) {
|
||||
/* We could have crashed in the middle of destroying it */
|
||||
@@ -3640,11 +3724,12 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
* (invoked from ztest_objset_destroy_cb()) should just throw it away.
|
||||
*/
|
||||
if (ztest_random(2) == 0 &&
|
||||
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
|
||||
ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
|
||||
B_TRUE, FTAG, &os) == 0) {
|
||||
ztest_zd_init(zdtmp, NULL, os);
|
||||
zil_replay(os, zdtmp, ztest_replay_vector);
|
||||
ztest_zd_fini(zdtmp);
|
||||
txg_wait_synced(dmu_objset_pool(os), 0);
|
||||
dmu_objset_disown(os, B_TRUE, FTAG);
|
||||
}
|
||||
|
||||
@@ -3659,8 +3744,8 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
/*
|
||||
* Verify that the destroyed dataset is no longer in the namespace.
|
||||
*/
|
||||
VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, B_TRUE,
|
||||
FTAG, &os));
|
||||
VERIFY3U(ENOENT, ==, ztest_dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
|
||||
B_TRUE, FTAG, &os));
|
||||
|
||||
/*
|
||||
* Verify that we can create a new dataset.
|
||||
@@ -3674,7 +3759,7 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_create(%s) = %d", name, error);
|
||||
}
|
||||
|
||||
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE,
|
||||
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE,
|
||||
FTAG, &os));
|
||||
|
||||
ztest_zd_init(zdtmp, NULL, os);
|
||||
@@ -3710,10 +3795,11 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
/*
|
||||
* Verify that we cannot own an objset that is already owned.
|
||||
*/
|
||||
VERIFY3U(EBUSY, ==,
|
||||
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE, FTAG, &os2));
|
||||
VERIFY3U(EBUSY, ==, ztest_dmu_objset_own(name, DMU_OST_OTHER,
|
||||
B_FALSE, B_TRUE, FTAG, &os2));
|
||||
|
||||
zil_close(zilog);
|
||||
txg_wait_synced(spa_get_dsl(os->os_spa), 0);
|
||||
dmu_objset_disown(os, B_TRUE, FTAG);
|
||||
ztest_zd_fini(zdtmp);
|
||||
out:
|
||||
@@ -3868,7 +3954,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, B_TRUE,
|
||||
error = ztest_dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, B_TRUE,
|
||||
FTAG, &os);
|
||||
if (error)
|
||||
fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
|
||||
@@ -6262,7 +6348,8 @@ ztest_dataset_open(int d)
|
||||
}
|
||||
ASSERT(error == 0 || error == EEXIST);
|
||||
|
||||
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE, zd, &os));
|
||||
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
|
||||
B_TRUE, zd, &os));
|
||||
(void) rw_unlock(&ztest_name_lock);
|
||||
|
||||
ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
|
||||
@@ -6303,6 +6390,7 @@ ztest_dataset_close(int d)
|
||||
ztest_ds_t *zd = &ztest_ds[d];
|
||||
|
||||
zil_close(zd->zd_zilog);
|
||||
txg_wait_synced(spa_get_dsl(zd->zd_os->os_spa), 0);
|
||||
dmu_objset_disown(zd->zd_os, B_TRUE, zd);
|
||||
|
||||
ztest_zd_fini(zd);
|
||||
@@ -6355,7 +6443,7 @@ ztest_run(ztest_shared_t *zs)
|
||||
ztest_spa = spa;
|
||||
|
||||
dmu_objset_stats_t dds;
|
||||
VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
|
||||
VERIFY0(ztest_dmu_objset_own(ztest_opts.zo_pool,
|
||||
DMU_OST_ANY, B_TRUE, B_TRUE, FTAG, &os));
|
||||
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
|
||||
dmu_objset_fast_stat(os, &dds);
|
||||
@@ -6582,11 +6670,10 @@ ztest_freeze(void)
|
||||
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
|
||||
ASSERT(spa_freeze_txg(spa) == UINT64_MAX);
|
||||
VERIFY3U(0, ==, ztest_dataset_open(0));
|
||||
ztest_dataset_close(0);
|
||||
|
||||
spa->spa_debug = B_TRUE;
|
||||
ztest_spa = spa;
|
||||
txg_wait_synced(spa_get_dsl(spa), 0);
|
||||
ztest_dataset_close(0);
|
||||
ztest_reguid(NULL, 0);
|
||||
|
||||
spa_close(spa, FTAG);
|
||||
|
||||
Reference in New Issue
Block a user