mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-24 03:08:51 +03:00
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
This commit is contained in:
committed by
Brian Behlendorf
parent
376994828f
commit
b525630342
+57
-15
@@ -71,6 +71,7 @@ struct nvlist;
|
||||
struct arc_buf;
|
||||
struct zio_prop;
|
||||
struct sa_handle;
|
||||
struct dsl_crypto_params;
|
||||
|
||||
typedef struct objset objset_t;
|
||||
typedef struct dmu_tx dmu_tx_t;
|
||||
@@ -100,16 +101,18 @@ typedef enum dmu_object_byteswap {
|
||||
|
||||
#define DMU_OT_NEWTYPE 0x80
|
||||
#define DMU_OT_METADATA 0x40
|
||||
#define DMU_OT_BYTESWAP_MASK 0x3f
|
||||
#define DMU_OT_ENCRYPTED 0x20
|
||||
#define DMU_OT_BYTESWAP_MASK 0x1f
|
||||
|
||||
/*
|
||||
* Defines a uint8_t object type. Object types specify if the data
|
||||
* in the object is metadata (boolean) and how to byteswap the data
|
||||
* (dmu_object_byteswap_t).
|
||||
*/
|
||||
#define DMU_OT(byteswap, metadata) \
|
||||
#define DMU_OT(byteswap, metadata, encrypted) \
|
||||
(DMU_OT_NEWTYPE | \
|
||||
((metadata) ? DMU_OT_METADATA : 0) | \
|
||||
((encrypted) ? DMU_OT_ENCRYPTED : 0) | \
|
||||
((byteswap) & DMU_OT_BYTESWAP_MASK))
|
||||
|
||||
#define DMU_OT_IS_VALID(ot) (((ot) & DMU_OT_NEWTYPE) ? \
|
||||
@@ -120,6 +123,10 @@ typedef enum dmu_object_byteswap {
|
||||
((ot) & DMU_OT_METADATA) : \
|
||||
dmu_ot[(int)(ot)].ot_metadata)
|
||||
|
||||
#define DMU_OT_IS_ENCRYPTED(ot) (((ot) & DMU_OT_NEWTYPE) ? \
|
||||
((ot) & DMU_OT_ENCRYPTED) : \
|
||||
dmu_ot[(int)(ot)].ot_encrypt)
|
||||
|
||||
/*
|
||||
* These object types use bp_fill != 1 for their L0 bp's. Therefore they can't
|
||||
* have their data embedded (i.e. use a BP_IS_EMBEDDED() bp), because bp_fill
|
||||
@@ -215,16 +222,27 @@ typedef enum dmu_object_type {
|
||||
/*
|
||||
* Names for valid types declared with DMU_OT().
|
||||
*/
|
||||
DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE),
|
||||
DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE),
|
||||
DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE),
|
||||
DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE),
|
||||
DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE),
|
||||
DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE),
|
||||
DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE),
|
||||
DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE),
|
||||
DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE),
|
||||
DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE),
|
||||
DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE, B_FALSE),
|
||||
DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE, B_FALSE),
|
||||
DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE, B_FALSE),
|
||||
DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE, B_FALSE),
|
||||
DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE, B_FALSE),
|
||||
DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE, B_FALSE),
|
||||
DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE, B_FALSE),
|
||||
DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE, B_FALSE),
|
||||
DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE, B_FALSE),
|
||||
DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE, B_FALSE),
|
||||
|
||||
DMU_OTN_UINT8_ENC_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE, B_TRUE),
|
||||
DMU_OTN_UINT8_ENC_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE, B_TRUE),
|
||||
DMU_OTN_UINT16_ENC_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE, B_TRUE),
|
||||
DMU_OTN_UINT16_ENC_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE, B_TRUE),
|
||||
DMU_OTN_UINT32_ENC_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE, B_TRUE),
|
||||
DMU_OTN_UINT32_ENC_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE, B_TRUE),
|
||||
DMU_OTN_UINT64_ENC_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE, B_TRUE),
|
||||
DMU_OTN_UINT64_ENC_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE, B_TRUE),
|
||||
DMU_OTN_ZAP_ENC_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE, B_TRUE),
|
||||
DMU_OTN_ZAP_ENC_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE, B_TRUE),
|
||||
} dmu_object_type_t;
|
||||
|
||||
typedef enum txg_how {
|
||||
@@ -267,19 +285,24 @@ void zfs_znode_byteswap(void *buf, size_t size);
|
||||
*/
|
||||
#define DMU_BONUS_BLKID (-1ULL)
|
||||
#define DMU_SPILL_BLKID (-2ULL)
|
||||
|
||||
/*
|
||||
* Public routines to create, destroy, open, and close objsets.
|
||||
*/
|
||||
typedef void dmu_objset_create_sync_func_t(objset_t *os, void *arg,
|
||||
cred_t *cr, dmu_tx_t *tx);
|
||||
|
||||
int dmu_objset_hold(const char *name, void *tag, objset_t **osp);
|
||||
int dmu_objset_own(const char *name, dmu_objset_type_t type,
|
||||
boolean_t readonly, void *tag, objset_t **osp);
|
||||
boolean_t readonly, boolean_t key_required, void *tag, objset_t **osp);
|
||||
void dmu_objset_rele(objset_t *os, void *tag);
|
||||
void dmu_objset_disown(objset_t *os, void *tag);
|
||||
void dmu_objset_disown(objset_t *os, boolean_t key_required, void *tag);
|
||||
int dmu_objset_open_ds(struct dsl_dataset *ds, objset_t **osp);
|
||||
|
||||
void dmu_objset_evict_dbufs(objset_t *os);
|
||||
int dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
|
||||
void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg);
|
||||
struct dsl_crypto_params *dcp, dmu_objset_create_sync_func_t func,
|
||||
void *arg);
|
||||
int dmu_objset_clone(const char *name, const char *origin);
|
||||
int dsl_destroy_snapshots_nvl(struct nvlist *snaps, boolean_t defer,
|
||||
struct nvlist *errlist);
|
||||
@@ -390,6 +413,13 @@ int dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx);
|
||||
int dmu_object_next(objset_t *os, uint64_t *objectp,
|
||||
boolean_t hole, uint64_t txg);
|
||||
|
||||
/*
|
||||
* Set the number of levels on a dnode. nlevels must be greater than the
|
||||
* current number of levels or an EINVAL will be returned.
|
||||
*/
|
||||
int dmu_object_set_nlevels(objset_t *os, uint64_t object, int nlevels,
|
||||
dmu_tx_t *tx);
|
||||
|
||||
/*
|
||||
* Set the data blocksize for an object.
|
||||
*
|
||||
@@ -432,6 +462,7 @@ dmu_write_embedded(objset_t *os, uint64_t object, uint64_t offset,
|
||||
|
||||
void dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp,
|
||||
struct zio_prop *zp);
|
||||
|
||||
/*
|
||||
* The bonus data is accessed more or less like a regular buffer.
|
||||
* You must dmu_bonus_hold() to get the buffer, which will give you a
|
||||
@@ -444,6 +475,8 @@ void dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp,
|
||||
*
|
||||
* Returns ENOENT, EIO, or 0.
|
||||
*/
|
||||
int dmu_bonus_hold_impl(objset_t *os, uint64_t object, void *tag,
|
||||
uint32_t flags, dmu_buf_t **dbp);
|
||||
int dmu_bonus_hold(objset_t *os, uint64_t object, void *tag, dmu_buf_t **);
|
||||
int dmu_bonus_max(void);
|
||||
int dmu_set_bonus(dmu_buf_t *, int, dmu_tx_t *);
|
||||
@@ -655,6 +688,7 @@ struct blkptr *dmu_buf_get_blkptr(dmu_buf_t *db);
|
||||
* (ie. you've called dmu_tx_hold_object(tx, db->db_object)).
|
||||
*/
|
||||
void dmu_buf_will_dirty(dmu_buf_t *db, dmu_tx_t *tx);
|
||||
void dmu_buf_will_change_crypt_params(dmu_buf_t *db, dmu_tx_t *tx);
|
||||
|
||||
/*
|
||||
* You must create a transaction, then hold the objects which you will
|
||||
@@ -737,6 +771,7 @@ int dmu_free_long_object(objset_t *os, uint64_t object);
|
||||
*/
|
||||
#define DMU_READ_PREFETCH 0 /* prefetch */
|
||||
#define DMU_READ_NO_PREFETCH 1 /* don't prefetch */
|
||||
#define DMU_READ_NO_DECRYPT 2 /* don't decrypt */
|
||||
int dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
|
||||
void *buf, uint32_t flags);
|
||||
int dmu_read_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, void *buf,
|
||||
@@ -763,6 +798,12 @@ struct arc_buf *dmu_request_arcbuf(dmu_buf_t *handle, int size);
|
||||
void dmu_return_arcbuf(struct arc_buf *buf);
|
||||
void dmu_assign_arcbuf(dmu_buf_t *handle, uint64_t offset, struct arc_buf *buf,
|
||||
dmu_tx_t *tx);
|
||||
void dmu_assign_arcbuf_impl(dmu_buf_t *handle, struct arc_buf *buf,
|
||||
dmu_tx_t *tx);
|
||||
void dmu_convert_to_raw(dmu_buf_t *handle, boolean_t byteorder,
|
||||
const uint8_t *salt, const uint8_t *iv, const uint8_t *mac, dmu_tx_t *tx);
|
||||
void dmu_copy_from_buf(objset_t *os, uint64_t object, uint64_t offset,
|
||||
dmu_buf_t *handle, dmu_tx_t *tx);
|
||||
#ifdef HAVE_UIO_ZEROCOPY
|
||||
int dmu_xuio_init(struct xuio *uio, int niov);
|
||||
void dmu_xuio_fini(struct xuio *uio);
|
||||
@@ -807,6 +848,7 @@ typedef void (*const arc_byteswap_func_t)(void *buf, size_t size);
|
||||
typedef struct dmu_object_type_info {
|
||||
dmu_object_byteswap_t ot_byteswap;
|
||||
boolean_t ot_metadata;
|
||||
boolean_t ot_encrypt;
|
||||
char *ot_name;
|
||||
} dmu_object_type_info_t;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user