Permalink
Browse files

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
  • Loading branch information...
tcaputi authored and behlendorf committed Aug 14, 2017
1 parent 3769948 commit b52563034230b35f0562b6f40ad1a00f02bd9a05
Showing with 16,090 additions and 1,203 deletions.
  1. +51 −18 cmd/zdb/zdb.c
  2. +8 −3 cmd/zdb/zdb_il.c
  3. +274 −8 cmd/zfs/zfs_main.c
  4. +4 −4 cmd/zinject/translate.c
  5. +56 −10 cmd/zpool/zpool_main.c
  6. +105 −16 cmd/zstreamdump/zstreamdump.c
  7. +27 −22 cmd/ztest/ztest.c
  8. +3 −0 configure.ac
  9. +2 −2 include/libuutil.h
  10. +20 −2 include/libzfs.h
  11. +16 −9 include/libzfs_core.h
  12. +2 −0 include/sys/Makefile.am
  13. +55 −14 include/sys/arc.h
  14. +45 −7 include/sys/arc_impl.h
  15. +2 −0 include/sys/dbuf.h
  16. +11 −4 include/sys/ddt.h
  17. +57 −15 include/sys/dmu.h
  18. +24 −5 include/sys/dmu_objset.h
  19. +3 −2 include/sys/dmu_send.h
  20. +9 −0 include/sys/dmu_traverse.h
  21. +8 −3 include/sys/dnode.h
  22. +218 −0 include/sys/dsl_crypt.h
  23. +23 −6 include/sys/dsl_dataset.h
  24. +2 −0 include/sys/dsl_deleg.h
  25. +3 −0 include/sys/dsl_dir.h
  26. +3 −1 include/sys/dsl_pool.h
  27. +1 −0 include/sys/fm/fs/zfs.h
  28. +44 −0 include/sys/fs/zfs.h
  29. +143 −14 include/sys/spa.h
  30. +2 −0 include/sys/spa_impl.h
  31. +49 −9 include/sys/zfs_ioctl.h
  32. +3 −1 include/sys/zil.h
  33. +44 −13 include/sys/zio.h
  34. +147 −0 include/sys/zio_crypt.h
  35. +34 −18 include/sys/zio_impl.h
  36. +1 −0 include/zfeature_common.h
  37. +2 −0 include/zfs_deleg.h
  38. +5 −2 include/zfs_prop.h
  39. +2 −2 lib/libicp/Makefile.am
  40. +7 −0 lib/libspl/include/sys/mount.h
  41. +3 −1 lib/libzfs/Makefile.am
  42. +5 −1 lib/libzfs/libzfs_changelist.c
  43. +1,612 −0 lib/libzfs/libzfs_crypto.c
  44. +125 −11 lib/libzfs/libzfs_dataset.c
  45. +5 −0 lib/libzfs/libzfs_diff.c
  46. +49 −0 lib/libzfs/libzfs_mount.c
  47. +27 −1 lib/libzfs/libzfs_pool.c
  48. +455 −44 lib/libzfs/libzfs_sendrecv.c
  49. +2 −0 lib/libzfs/libzfs_util.c
  50. +110 −28 lib/libzfs_core/libzfs_core.c
  51. +2 −0 lib/libzpool/Makefile.am
  52. +21 −0 man/man5/zpool-features.5
  53. +370 −5 man/man8/zfs.8
  54. +33 −6 man/man8/zpool.8
  55. +6 −6 module/icp/algs/sha2/sha2.c
  56. +2 −2 module/icp/core/kcf_prov_lib.c
  57. +1 −1 module/icp/illumos-crypto.c
  58. +11 −0 module/zcommon/zfeature_common.c
  59. +2 −0 module/zcommon/zfs_deleg.c
  60. +96 −3 module/zcommon/zfs_prop.c
  61. +2 −0 module/zfs/Makefile.in
  62. +1,352 −259 module/zfs/arc.c
  63. +2 −1 module/zfs/bptree.c
  64. +173 −36 module/zfs/dbuf.c
  65. +19 −4 module/zfs/ddt.c
  66. +206 −62 module/zfs/dmu.c
  67. +239 −57 module/zfs/dmu_objset.c
  68. +681 −172 module/zfs/dmu_send.c
  69. +35 −8 module/zfs/dmu_traverse.c
  70. +73 −38 module/zfs/dnode.c
  71. +10 −3 module/zfs/dnode_sync.c
  72. +2,611 −0 module/zfs/dsl_crypt.c
  73. +93 −30 module/zfs/dsl_dataset.c
  74. +10 −4 module/zfs/dsl_destroy.c
  75. +30 −13 module/zfs/dsl_dir.c
  76. +16 −3 module/zfs/dsl_pool.c
  77. +2 −1 module/zfs/dsl_prop.c
  78. +14 −3 module/zfs/dsl_scan.c
  79. +65 −18 module/zfs/spa.c
  80. +1 −1 module/zfs/spa_config.c
  81. +1 −2 module/zfs/spa_errlog.c
  82. +6 −1 module/zfs/spa_history.c
  83. +11 −1 module/zfs/spa_misc.c
  84. +5 −4 module/zfs/vdev.c
  85. +5 −4 module/zfs/vdev_raidz.c
  86. +2 −2 module/zfs/zfeature.c
  87. +1 −1 module/zfs/zfs_acl.c
  88. +25 −29 module/zfs/zfs_fm.c
  89. +235 −33 module/zfs/zfs_ioctl.c
  90. +7 −5 module/zfs/zfs_vfsops.c
  91. +45 −21 module/zfs/zil.c
  92. +330 −25 module/zfs/zio.c
  93. +56 −9 module/zfs/zio_checksum.c
  94. +2,037 −0 module/zfs/zio_crypt.c
  95. +10 −10 module/zfs/zvol.c
  96. +3 −3 module/zpios/pios.c
  97. +1 −0 rpm/generic/zfs.spec.in
  98. +31 −11 tests/runfiles/linux.run
  99. +3 −0 tests/zfs-tests/tests/functional/cli_root/Makefile.am
  100. +11 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/Makefile.am
  101. +30 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/cleanup.ksh
  102. +32 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/setup.ksh
  103. +62 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key.ksh
  104. +86 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_child.ksh
  105. +71 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_format.ksh
  106. +78 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_inherit.ksh
  107. +58 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_load.ksh
  108. +65 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_location.ksh
  109. +75 −0 tests/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_pbkdf2iters.ksh
  110. +2 −1 tests/zfs-tests/tests/functional/cli_root/zfs_clone/Makefile.am
  111. +83 −0 tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_encrypted.ksh
  112. +3 −1 tests/zfs-tests/tests/functional/cli_root/zfs_create/Makefile.am
  113. +98 −0 tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_crypt_combos.ksh
  114. +134 −0 tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_encrypted.ksh
  115. +12 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/Makefile.am
  116. +30 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/cleanup.ksh
  117. +32 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/setup.ksh
  118. +26 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key.cfg
  119. +85 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key.ksh
  120. +77 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_all.ksh
  121. +102 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib
  122. +58 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_file.ksh
  123. +73 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_location.ksh
  124. +54 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_noop.ksh
  125. +66 −0 tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_recursive.ksh
  126. +1 −0 tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am
  127. +62 −0 tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_encrypted.ksh
  128. +2 −1 tests/zfs-tests/tests/functional/cli_root/zfs_promote/Makefile.am
  129. +80 −0 tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_encryptionroot.ksh
  130. +5 −1 tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
  131. +1 −0 tests/zfs-tests/tests/functional/cli_root/zfs_receive/setup.ksh
  132. +83 −0 tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_from_encrypted.ksh
  133. +93 −0 tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh
  134. +75 −0 tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_incremental.ksh
  135. +75 −0 tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh
  136. +3 −1 tests/zfs-tests/tests/functional/cli_root/zfs_rename/Makefile.am
  137. +78 −0 tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_encrypted_child.ksh
  138. +51 −0 tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_to_encrypted.ksh
  139. +3 −1 tests/zfs-tests/tests/functional/cli_root/zfs_send/Makefile.am
  140. +76 −0 tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted.ksh
  141. +59 −0 tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded.ksh
  142. +79 −0 tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh
  143. +2 −1 tests/zfs-tests/tests/functional/cli_root/zfs_set/Makefile.am
  144. +1 −0 tests/zfs-tests/tests/functional/cli_root/zfs_set/setup.ksh
  145. +93 −0 tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_keylocation.ksh
  146. +7 −0 tests/zfs-tests/tests/functional/cli_root/zfs_unload-key/Makefile.am
  147. +30 −0 tests/zfs-tests/tests/functional/cli_root/zfs_unload-key/cleanup.ksh
  148. +32 −0 tests/zfs-tests/tests/functional/cli_root/zfs_unload-key/setup.ksh
  149. +69 −0 tests/zfs-tests/tests/functional/cli_root/zfs_unload-key/zfs_unload-key.ksh
  150. +76 −0 tests/zfs-tests/tests/functional/cli_root/zfs_unload-key/zfs_unload-key_all.ksh
  151. +72 −0 tests/zfs-tests/tests/functional/cli_root/zfs_unload-key/zfs_unload-key_recursive.ksh
  152. +2 −0 tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am
  153. +89 −0 tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_crypt_combos.ksh
  154. +95 −0 tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_encrypted.ksh
  155. +1 −0 tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
  156. +3 −1 tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am
  157. +59 −0 tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_encrypted.ksh
  158. +59 −0 tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_encrypted_load.ksh
  159. +2 −1 tests/zfs-tests/tests/functional/cli_root/zpool_scrub/Makefile.am
  160. +71 −0 tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_encrypted_unloaded.ksh
  161. +1 −0 tests/zfs-tests/tests/functional/rsend/Makefile.am
  162. +1 −1 tests/zfs-tests/tests/functional/rsend/rsend.kshlib
  163. +96 −0 tests/zfs-tests/tests/functional/rsend/send_encrypted_heirarchy.ksh
View
@@ -64,6 +64,7 @@
#include <sys/zfeature.h>
#include <sys/abd.h>
#include <sys/blkptr.h>
#include <sys/dsl_crypt.h>
#include <zfs_comutil.h>
#include <libzfs.h>
@@ -1631,14 +1632,14 @@ open_objset(const char *path, dmu_objset_type_t type, void *tag, objset_t **osp)
uint64_t version = 0;
VERIFY3P(sa_os, ==, NULL);
err = dmu_objset_own(path, type, B_TRUE, tag, osp);
err = dmu_objset_own(path, type, B_TRUE, B_FALSE, tag, osp);
if (err != 0) {
(void) fprintf(stderr, "failed to own dataset '%s': %s\n", path,
strerror(err));
return (err);
}
if (dmu_objset_type(*osp) == DMU_OST_ZFS) {
if (dmu_objset_type(*osp) == DMU_OST_ZFS && !(*osp)->os_encrypted) {
(void) zap_lookup(*osp, MASTER_NODE_OBJ, ZPL_VERSION_STR,
8, 1, &version);
if (version >= ZPL_VERSION_SA) {
@@ -1650,7 +1651,7 @@ open_objset(const char *path, dmu_objset_type_t type, void *tag, objset_t **osp)
if (err != 0) {
(void) fprintf(stderr, "sa_setup failed: %s\n",
strerror(err));
dmu_objset_disown(*osp, tag);
dmu_objset_disown(*osp, B_FALSE, tag);
*osp = NULL;
}
}
@@ -1665,7 +1666,7 @@ close_objset(objset_t *os, void *tag)
VERIFY3P(os, ==, sa_os);
if (os->os_sa != NULL)
sa_tear_down(os);
dmu_objset_disown(os, tag);
dmu_objset_disown(os, B_FALSE, tag);
sa_attr_table = NULL;
sa_os = NULL;
}
@@ -1938,6 +1939,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];
@@ -1954,16 +1956,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 hold 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);
@@ -2010,9 +2029,20 @@ 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);
object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object, NULL, 0);
if (!dnode_held) {
object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os,
object, bonus, bsize);
} else {
(void) printf("\t\t(bonus encrypted)\n");
}
if (!os->os_encrypted || !DMU_OT_IS_ENCRYPTED(doi.doi_type)) {
object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object,
NULL, 0);
} else {
(void) printf("\t\t(object encrypted)\n");
}
*print_header = 1;
}
@@ -2054,6 +2084,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] = {
@@ -2639,7 +2671,7 @@ dump_path(char *ds, char *path)
if (err != 0) {
(void) fprintf(stderr, "can't lookup root znode: %s\n",
strerror(err));
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_FALSE, FTAG);
return (EINVAL);
}
@@ -3289,7 +3321,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;
@@ -3594,8 +3627,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);
View
@@ -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);
}
}
Oops, something went wrong.

1 comment on commit b525630

@justinlynn

This comment has been minimized.

Show comment
Hide comment
@justinlynn

justinlynn Aug 15, 2017

Congratulations! Native encryption support is a huge step forward. Many thanks to everyone that contributed and especially to @tcaputi for seeing it through to master!

justinlynn commented on b525630 Aug 15, 2017

Congratulations! Native encryption support is a huge step forward. Many thanks to everyone that contributed and especially to @tcaputi for seeing it through to master!

Please sign in to comment.