Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZFS Encryption #4329

Closed
wants to merge 10 commits into from
Copy path View file
@@ -60,6 +60,7 @@
#include <sys/ddt.h>
#include <sys/zfeature.h>
#include <sys/abd.h>
#include <sys/dsl_crypt.h>
#include <zfs_comutil.h>
#include <libzfs.h>

@@ -1887,6 +1888,7 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
dmu_buf_t *db = NULL;
dmu_object_info_t doi;
dnode_t *dn;
boolean_t dnode_held = B_FALSE;
void *bonus = NULL;
size_t bsize = 0;
char iblk[32], dblk[32], lsize[32], asize[32], fill[32], dnsize[32];
@@ -1903,16 +1905,33 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)

if (object == 0) {
dn = DMU_META_DNODE(os);
dmu_object_info_from_dnode(dn, &doi);
} else {
error = dmu_bonus_hold(os, object, FTAG, &db);
/*
* Encrypted datasets will have sensitive bonus buffers
* encrypted. Therefore we cannot hold the bonus buffer and
* must get the dnode itself instead.
*/
error = dmu_object_info(os, object, &doi);
if (error)
fatal("dmu_bonus_hold(%llu) failed, errno %u",
object, error);
bonus = db->db_data;
bsize = db->db_size;
dn = DB_DNODE((dmu_buf_impl_t *)db);
fatal("dmu_object_info() failed, errno %u", error);

if (os->os_encrypted &&
DMU_OT_IS_ENCRYPTED(doi.doi_bonus_type)) {
error = dnode_hold(os, object, FTAG, &dn);
if (error)
fatal("dnode_hold() failed, errno %u", error);
dnode_held = B_TRUE;
} else {
error = dmu_bonus_hold(os, object, FTAG, &db);
if (error)
fatal("dmu_bonus_hold(%llu) failed, errno %u",
object, error);
bonus = db->db_data;
bsize = db->db_size;
dn = DB_DNODE((dmu_buf_impl_t *)db);
}
}
dmu_object_info_from_dnode(dn, &doi);

zdb_nicenum(doi.doi_metadata_block_size, iblk);
zdb_nicenum(doi.doi_data_block_size, dblk);
@@ -1959,8 +1978,13 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
(void) printf("\tdnode maxblkid: %llu\n",
(longlong_t)dn->dn_phys->dn_maxblkid);

object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os, object,
bonus, bsize);
if (!dnode_held) {
object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os,
object, bonus, bsize);
} else {
(void) printf("\t\t(bonus encrypted)\n");
}

object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object, NULL, 0);
*print_header = 1;
}
@@ -2003,6 +2027,8 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)

if (db != NULL)
dmu_buf_rele(db, FTAG);
if (dnode_held)
dnode_rele(dn, FTAG);
}

static char *objset_types[DMU_OST_NUMTYPES] = {
@@ -2299,7 +2325,7 @@ dump_one_dir(const char *dsname, void *arg)
objset_t *os;
spa_feature_t f;

error = dmu_objset_own(dsname, DMU_OST_ANY, B_TRUE, FTAG, &os);
error = dmu_objset_own(dsname, DMU_OST_ANY, B_TRUE, B_FALSE, FTAG, &os);
if (error) {
(void) printf("Could not open %s, error %d\n", dsname, error);
return (0);
@@ -2747,7 +2773,8 @@ dump_block_stats(spa_t *spa)
zdb_cb_t zcb;
zdb_blkstats_t *zb, *tzb;
uint64_t norm_alloc, norm_space, total_alloc, total_found;
int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_HARD;
int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA |
TRAVERSE_NO_DECRYPT | TRAVERSE_HARD;
boolean_t leaks = B_FALSE;
int e, c;
bp_embedded_type_t i;
@@ -3052,8 +3079,8 @@ dump_simulated_ddt(spa_t *spa)

spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);

(void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA,
zdb_ddt_add_cb, &t);
(void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA |
TRAVERSE_NO_DECRYPT, zdb_ddt_add_cb, &t);

spa_config_exit(spa, SCL_CONFIG, FTAG);

@@ -3875,7 +3902,7 @@ main(int argc, char **argv)
}
} else {
error = dmu_objset_own(target, DMU_OST_ANY,
B_TRUE, FTAG, &os);
B_TRUE, B_FALSE, FTAG, &os);
}
}
nvlist_free(policy);
Copy path View file
@@ -311,8 +311,13 @@ print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
(u_longlong_t)lr->lrc_txg,
(u_longlong_t)lr->lrc_seq);

if (txtype && verbose >= 3)
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
if (txtype && verbose >= 3) {
if (!zilog->zl_os->os_encrypted) {
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
} else {
(void) printf("%s(encrypted)\n", prefix);
}
}

zil_rec_info[txtype].zri_count++;
zil_rec_info[0].zri_count++;
@@ -399,7 +404,7 @@ dump_intent_log(zilog_t *zilog)
if (verbose >= 2) {
(void) printf("\n");
(void) zil_parse(zilog, print_log_block, print_log_record, NULL,
zh->zh_claim_txg);
zh->zh_claim_txg, B_FALSE);
print_log_stats(verbose);
}
}
Copy path View file
@@ -506,7 +506,7 @@ zfs_enable_ds(void *arg)

assert(pool->uap_enable_tid = pthread_self());

(void) zpool_enable_datasets(pool->uap_zhp, NULL, 0);
(void) zpool_enable_datasets(pool->uap_zhp, NULL, 0, B_FALSE);
zpool_close(pool->uap_zhp);
pool->uap_zhp = NULL;

Copy path View file
@@ -103,6 +103,7 @@ static int zfs_do_holds(int argc, char **argv);
static int zfs_do_release(int argc, char **argv);
static int zfs_do_diff(int argc, char **argv);
static int zfs_do_bookmark(int argc, char **argv);
static int zfs_do_key(int argc, char **argv);

/*
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
@@ -150,6 +151,7 @@ typedef enum {
HELP_RELEASE,
HELP_DIFF,
HELP_BOOKMARK,
HELP_KEY,
} zfs_help_t;

typedef struct zfs_command {
@@ -203,6 +205,7 @@ static zfs_command_t command_table[] = {
{ "holds", zfs_do_holds, HELP_HOLDS },
{ "release", zfs_do_release, HELP_RELEASE },
{ "diff", zfs_do_diff, HELP_DIFF },
{ "key", zfs_do_key, HELP_KEY },
};

#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -321,6 +324,10 @@ get_usage(zfs_help_t idx)
"[snapshot|filesystem]\n"));
case HELP_BOOKMARK:
return (gettext("\tbookmark <snapshot> <bookmark>\n"));
case HELP_KEY:
return (gettext("\tkey [-lu] <filesystem|volume>\n"
"\tkey -c [-o keysource=<value>] [-o pbkfd2iters=<value>] "
"<filesystem|volume>\n"));
}

abort();
@@ -874,7 +881,7 @@ zfs_do_create(int argc, char **argv)
(void) snprintf(msg, sizeof (msg),
gettext("cannot create '%s'"), argv[0]);
if (props && (real_props = zfs_valid_proplist(g_zfs, type,
props, 0, NULL, zpool_handle, msg)) == NULL) {
props, 0, NULL, zpool_handle, B_TRUE, msg)) == NULL) {
zpool_close(zpool_handle);
goto error;
}
@@ -4145,6 +4152,8 @@ zfs_do_receive(int argc, char **argv)
#define ZFS_DELEG_PERM_RELEASE "release"
#define ZFS_DELEG_PERM_DIFF "diff"
#define ZFS_DELEG_PERM_BOOKMARK "bookmark"
#define ZFS_DELEG_PERM_LOAD_KEY "keyuse"
#define ZFS_DELEG_PERM_CHANGE_KEY "keychange"

#define ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE

@@ -4165,6 +4174,8 @@ static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
{ ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
{ ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
{ ZFS_DELEG_PERM_BOOKMARK, ZFS_DELEG_NOTE_BOOKMARK },
{ ZFS_DELEG_PERM_LOAD_KEY, ZFS_DELEG_NOTE_LOAD_KEY },
{ ZFS_DELEG_PERM_CHANGE_KEY, ZFS_DELEG_NOTE_CHANGE_KEY },

{ ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
{ ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
@@ -4738,6 +4749,12 @@ deleg_perm_comment(zfs_deleg_note_t note)
case ZFS_DELEG_NOTE_SNAPSHOT:
str = gettext("");
break;
case ZFS_DELEG_NOTE_LOAD_KEY:
str = gettext("Allows loading or unloading an encryption key");
break;
case ZFS_DELEG_NOTE_CHANGE_KEY:
str = gettext("Allows changing or adding an encryption key");
break;
/*
* case ZFS_DELEG_NOTE_VSCAN:
* str = gettext("");
@@ -6914,6 +6931,106 @@ zfs_do_bookmark(int argc, char **argv)
return (-1);
}

static int
zfs_do_key(int argc, char **argv)
{
int c, ret = -1;
boolean_t load = B_FALSE, unload = B_FALSE, rewrap = B_FALSE;
zfs_handle_t *zhp = NULL;
nvlist_t *props = fnvlist_alloc();

while ((c = getopt(argc, argv, "ulco:")) != -1) {
switch (c) {
case 'u':
if (ret == 0) {
(void) fprintf(stderr, gettext(
"multiple actions specified\n"));
usage(B_FALSE);
}
unload = B_TRUE;
ret = 0;
break;
case 'l':
if (ret == 0) {
(void) fprintf(stderr, gettext(
"multiple actions specified\n"));
usage(B_FALSE);
}
load = B_TRUE;
ret = 0;
break;
case 'c':
if (ret == 0) {
(void) fprintf(stderr, gettext(
"multiple actions specified\n"));
usage(B_FALSE);
}
rewrap = B_TRUE;
ret = 0;
break;
case 'o':
if (parseprop(props, optarg) != 0)
return (1);
break;
default:
(void) fprintf(stderr,
gettext("invalid option '%c'\n"), optopt);
usage(B_FALSE);
}
}

if (ret) {
(void) fprintf(stderr,
gettext("No action specified\n"));
usage(B_FALSE);
}

if (!rewrap && !nvlist_empty(props)) {
(void) fprintf(stderr,
gettext("Properties not allowed for specified command\n"));
usage(B_FALSE);
}

argc -= optind;
argv += optind;

if (argc < 1) {
(void) fprintf(stderr, gettext("Missing dataset argument\n"));
usage(B_FALSE);
}

if (argc > 1) {
(void) fprintf(stderr, gettext("Too many arguments\n"));
usage(B_FALSE);
}

zhp = zfs_open(g_zfs, argv[argc - 1],
ZFS_TYPE_FILESYSTEM|ZFS_TYPE_VOLUME);
if (zhp == NULL)
usage(B_FALSE);

if (load)
ret = zfs_crypto_load_key(zhp);
else if (unload)
ret = zfs_crypto_unload_key(zhp);
else
ret = zfs_crypto_rewrap(zhp, props);

if (ret)
goto error;

nvlist_free(props);
zfs_close(zhp);
return (0);

error:
if (props)
nvlist_free(props);
if (zhp)
zfs_close(zhp);
return (-1);
}

int
main(int argc, char **argv)
{
Copy path View file
@@ -179,7 +179,7 @@ object_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
*/
sync();

err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, FTAG, &os);
err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, B_TRUE, FTAG, &os);

This comment has been minimized.

Copy link
@ahrens

ahrens Jan 14, 2017

Contributor

I'm not sure that we actually need any decrypted data here. If we do require it to be decrypted, how does zinject get the keys?

This comment has been minimized.

Copy link
@tcaputi

tcaputi Jan 14, 2017

Author Contributor

I tried to err on the side of caution here, and so anything I wasn't sure of required the keys be loaded. I will change this to B_FALSE. (same with the other instance in zinject).

if (err != 0) {
(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
dataset, strerror(err));
@@ -267,7 +267,7 @@ calculate_range(const char *dataset, err_type_t type, int level, char *range,
* size.
*/
if ((err = dmu_objset_own(dataset, DMU_OST_ANY,
B_TRUE, FTAG, &os)) != 0) {
B_TRUE, B_TRUE, FTAG, &os)) != 0) {

This comment has been minimized.

Copy link
@ahrens

ahrens Jan 14, 2017

Contributor

I'm not sure that we actually need any decrypted data here. If we do require it to be decrypted, how does zinject get the keys?

(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
dataset, strerror(err));
goto out;
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.