Skip to content

Commit b525630

Browse files
Tom Caputibehlendorf
authored andcommitted
Native Encryption for ZFS on Linux
This change incorporates three major pieces: The first change is a keystore that manages wrapping and encryption keys for encrypted datasets. These commands mostly involve manipulating the new DSL Crypto Key ZAP Objects that live in the MOS. Each encrypted dataset has its own DSL Crypto Key that is protected with a user's key. This level of indirection allows users to change their keys without re-encrypting their entire datasets. The change implements the new subcommands "zfs load-key", "zfs unload-key" and "zfs change-key" which allow the user to manage their encryption keys and settings. In addition, several new flags and properties have been added to allow dataset creation and to make mounting and unmounting more convenient. The second piece of this patch provides the ability to encrypt, decyrpt, and authenticate protected datasets. Each object set maintains a Merkel tree of Message Authentication Codes that protect the lower layers, similarly to how checksums are maintained. This part impacts the zio layer, which handles the actual encryption and generation of MACs, as well as the ARC and DMU, which need to be able to handle encrypted buffers and protected data. The last addition is the ability to do raw, encrypted sends and receives. The idea here is to send raw encrypted and compressed data and receive it exactly as is on a backup system. This means that the dataset on the receiving system is protected using the same user key that is in use on the sending side. By doing so, datasets can be efficiently backed up to an untrusted system without fear of data being compromised. Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Jorgen Lundman <lundman@lundman.net> Signed-off-by: Tom Caputi <tcaputi@datto.com> Closes #494 Closes #5769
1 parent 3769948 commit b525630

File tree

163 files changed

+16090
-1203
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

163 files changed

+16090
-1203
lines changed

cmd/zdb/zdb.c

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include <sys/zfeature.h>
6565
#include <sys/abd.h>
6666
#include <sys/blkptr.h>
67+
#include <sys/dsl_crypt.h>
6768
#include <zfs_comutil.h>
6869
#include <libzfs.h>
6970

@@ -1631,14 +1632,14 @@ open_objset(const char *path, dmu_objset_type_t type, void *tag, objset_t **osp)
16311632
uint64_t version = 0;
16321633

16331634
VERIFY3P(sa_os, ==, NULL);
1634-
err = dmu_objset_own(path, type, B_TRUE, tag, osp);
1635+
err = dmu_objset_own(path, type, B_TRUE, B_FALSE, tag, osp);
16351636
if (err != 0) {
16361637
(void) fprintf(stderr, "failed to own dataset '%s': %s\n", path,
16371638
strerror(err));
16381639
return (err);
16391640
}
16401641

1641-
if (dmu_objset_type(*osp) == DMU_OST_ZFS) {
1642+
if (dmu_objset_type(*osp) == DMU_OST_ZFS && !(*osp)->os_encrypted) {
16421643
(void) zap_lookup(*osp, MASTER_NODE_OBJ, ZPL_VERSION_STR,
16431644
8, 1, &version);
16441645
if (version >= ZPL_VERSION_SA) {
@@ -1650,7 +1651,7 @@ open_objset(const char *path, dmu_objset_type_t type, void *tag, objset_t **osp)
16501651
if (err != 0) {
16511652
(void) fprintf(stderr, "sa_setup failed: %s\n",
16521653
strerror(err));
1653-
dmu_objset_disown(*osp, tag);
1654+
dmu_objset_disown(*osp, B_FALSE, tag);
16541655
*osp = NULL;
16551656
}
16561657
}
@@ -1665,7 +1666,7 @@ close_objset(objset_t *os, void *tag)
16651666
VERIFY3P(os, ==, sa_os);
16661667
if (os->os_sa != NULL)
16671668
sa_tear_down(os);
1668-
dmu_objset_disown(os, tag);
1669+
dmu_objset_disown(os, B_FALSE, tag);
16691670
sa_attr_table = NULL;
16701671
sa_os = NULL;
16711672
}
@@ -1938,6 +1939,7 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
19381939
dmu_buf_t *db = NULL;
19391940
dmu_object_info_t doi;
19401941
dnode_t *dn;
1942+
boolean_t dnode_held = B_FALSE;
19411943
void *bonus = NULL;
19421944
size_t bsize = 0;
19431945
char iblk[32], dblk[32], lsize[32], asize[32], fill[32], dnsize[32];
@@ -1954,16 +1956,33 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
19541956

19551957
if (object == 0) {
19561958
dn = DMU_META_DNODE(os);
1959+
dmu_object_info_from_dnode(dn, &doi);
19571960
} else {
1958-
error = dmu_bonus_hold(os, object, FTAG, &db);
1961+
/*
1962+
* Encrypted datasets will have sensitive bonus buffers
1963+
* encrypted. Therefore we cannot hold the bonus buffer and
1964+
* must hold the dnode itself instead.
1965+
*/
1966+
error = dmu_object_info(os, object, &doi);
19591967
if (error)
1960-
fatal("dmu_bonus_hold(%llu) failed, errno %u",
1961-
object, error);
1962-
bonus = db->db_data;
1963-
bsize = db->db_size;
1964-
dn = DB_DNODE((dmu_buf_impl_t *)db);
1968+
fatal("dmu_object_info() failed, errno %u", error);
1969+
1970+
if (os->os_encrypted &&
1971+
DMU_OT_IS_ENCRYPTED(doi.doi_bonus_type)) {
1972+
error = dnode_hold(os, object, FTAG, &dn);
1973+
if (error)
1974+
fatal("dnode_hold() failed, errno %u", error);
1975+
dnode_held = B_TRUE;
1976+
} else {
1977+
error = dmu_bonus_hold(os, object, FTAG, &db);
1978+
if (error)
1979+
fatal("dmu_bonus_hold(%llu) failed, errno %u",
1980+
object, error);
1981+
bonus = db->db_data;
1982+
bsize = db->db_size;
1983+
dn = DB_DNODE((dmu_buf_impl_t *)db);
1984+
}
19651985
}
1966-
dmu_object_info_from_dnode(dn, &doi);
19671986

19681987
zdb_nicenum(doi.doi_metadata_block_size, iblk);
19691988
zdb_nicenum(doi.doi_data_block_size, dblk);
@@ -2010,9 +2029,20 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
20102029
(void) printf("\tdnode maxblkid: %llu\n",
20112030
(longlong_t)dn->dn_phys->dn_maxblkid);
20122031

2013-
object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os, object,
2014-
bonus, bsize);
2015-
object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object, NULL, 0);
2032+
if (!dnode_held) {
2033+
object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os,
2034+
object, bonus, bsize);
2035+
} else {
2036+
(void) printf("\t\t(bonus encrypted)\n");
2037+
}
2038+
2039+
if (!os->os_encrypted || !DMU_OT_IS_ENCRYPTED(doi.doi_type)) {
2040+
object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object,
2041+
NULL, 0);
2042+
} else {
2043+
(void) printf("\t\t(object encrypted)\n");
2044+
}
2045+
20162046
*print_header = 1;
20172047
}
20182048

@@ -2054,6 +2084,8 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
20542084

20552085
if (db != NULL)
20562086
dmu_buf_rele(db, FTAG);
2087+
if (dnode_held)
2088+
dnode_rele(dn, FTAG);
20572089
}
20582090

20592091
static char *objset_types[DMU_OST_NUMTYPES] = {
@@ -2639,7 +2671,7 @@ dump_path(char *ds, char *path)
26392671
if (err != 0) {
26402672
(void) fprintf(stderr, "can't lookup root znode: %s\n",
26412673
strerror(err));
2642-
dmu_objset_disown(os, FTAG);
2674+
dmu_objset_disown(os, B_FALSE, FTAG);
26432675
return (EINVAL);
26442676
}
26452677

@@ -3289,7 +3321,8 @@ dump_block_stats(spa_t *spa)
32893321
zdb_cb_t zcb;
32903322
zdb_blkstats_t *zb, *tzb;
32913323
uint64_t norm_alloc, norm_space, total_alloc, total_found;
3292-
int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_HARD;
3324+
int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA |
3325+
TRAVERSE_NO_DECRYPT | TRAVERSE_HARD;
32933326
boolean_t leaks = B_FALSE;
32943327
int e, c;
32953328
bp_embedded_type_t i;
@@ -3594,8 +3627,8 @@ dump_simulated_ddt(spa_t *spa)
35943627

35953628
spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
35963629

3597-
(void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA,
3598-
zdb_ddt_add_cb, &t);
3630+
(void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA |
3631+
TRAVERSE_NO_DECRYPT, zdb_ddt_add_cb, &t);
35993632

36003633
spa_config_exit(spa, SCL_CONFIG, FTAG);
36013634

cmd/zdb/zdb_il.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,13 @@ print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
311311
(u_longlong_t)lr->lrc_txg,
312312
(u_longlong_t)lr->lrc_seq);
313313

314-
if (txtype && verbose >= 3)
315-
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
314+
if (txtype && verbose >= 3) {
315+
if (!zilog->zl_os->os_encrypted) {
316+
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
317+
} else {
318+
(void) printf("%s(encrypted)\n", prefix);
319+
}
320+
}
316321

317322
zil_rec_info[txtype].zri_count++;
318323
zil_rec_info[0].zri_count++;
@@ -399,7 +404,7 @@ dump_intent_log(zilog_t *zilog)
399404
if (verbose >= 2) {
400405
(void) printf("\n");
401406
(void) zil_parse(zilog, print_log_block, print_log_record, NULL,
402-
zh->zh_claim_txg);
407+
zh->zh_claim_txg, B_FALSE);
403408
print_log_stats(verbose);
404409
}
405410
}

0 commit comments

Comments
 (0)