ZFS crypto support.
* Makefile.util.def (libgrubmods): Add grub-core/fs/zfs/zfscrypt.c. * grub-core/Makefile.core.def (zfscrypt): New module. * grub-core/fs/zfs/zfs.c (subvolume): New structure. (grub_zfs_data): Replace mdn with subvol. Put case_insensitivity inside it. All users updated. (grub_zfs_decrypt): New var. (grub_zfs_load_key): Likewise. (zio_checksum_functions): Add SHA256+MAC. (zio_checksum_verify): Handle incomplete comparison due to MAC. (zio_read): Handle encrypted blocks. (zap_verify): Remove incorrect check. (fzap_iterate): Handle non-standard fzap. (zap_iterate): Likewise. (zap_iterate_u64): New function. (dnode_get_fullpath): Load keys. * grub-core/fs/zfs/zfscrypt.c: New file. * grub-core/lib/crypto.c (grub_crypto_cipher_close): Removed. (grub_crypto_ecb_encrypt): Make input const. * include/grub/crypto.h (grub_crypto_cipher_close): Inline. (grub_crypto_ecb_encrypt): Make input const. (GRUB_CIPHER_AES): New macro. * include/grub/zfs/dmu.h (dmu_object_type): Add DMU_OT_DSL_KEYCHAIN. * include/grub/zfs/dsl_dir.h (dsl_dir_phys): Add keychain. * include/grub/zfs/spa.h (grub_zfs_endian): Moved from here ... * include/grub/zfs/zfs.h (grub_zfs_endian): ... here. Added GURB_ZFS_ prefix. All users updated. (grub_zfs_add_key): New proto. (grub_zfs_decrypt): Likewise. (grub_zfs_load_key): Likewise. * include/grub/zfs/zio.h (zio_checksum): Add SHA256+MAC. * util/grub-fstest.c (options): Add -K option. (argp_parser): Likewise.
This commit is contained in:
commit
3084ede4c7
13 changed files with 950 additions and 127 deletions
37
ChangeLog
37
ChangeLog
|
@ -1,3 +1,40 @@
|
|||
2011-11-06 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
ZFS crypto support.
|
||||
|
||||
* Makefile.util.def (libgrubmods): Add grub-core/fs/zfs/zfscrypt.c.
|
||||
* grub-core/Makefile.core.def (zfscrypt): New module.
|
||||
* grub-core/fs/zfs/zfs.c (subvolume): New structure.
|
||||
(grub_zfs_data): Replace mdn with subvol. Put case_insensitivity inside
|
||||
it. All users updated.
|
||||
(grub_zfs_decrypt): New var.
|
||||
(grub_zfs_load_key): Likewise.
|
||||
(zio_checksum_functions): Add SHA256+MAC.
|
||||
(zio_checksum_verify): Handle incomplete comparison due to MAC.
|
||||
(zio_read): Handle encrypted blocks.
|
||||
(zap_verify): Remove incorrect check.
|
||||
(fzap_iterate): Handle non-standard fzap.
|
||||
(zap_iterate): Likewise.
|
||||
(zap_iterate_u64): New function.
|
||||
(dnode_get_fullpath): Load keys.
|
||||
* grub-core/fs/zfs/zfscrypt.c: New file.
|
||||
* grub-core/lib/crypto.c (grub_crypto_cipher_close): Removed.
|
||||
(grub_crypto_ecb_encrypt): Make input const.
|
||||
* include/grub/crypto.h (grub_crypto_cipher_close): Inline.
|
||||
(grub_crypto_ecb_encrypt): Make input const.
|
||||
(GRUB_CIPHER_AES): New macro.
|
||||
* include/grub/zfs/dmu.h (dmu_object_type): Add DMU_OT_DSL_KEYCHAIN.
|
||||
* include/grub/zfs/dsl_dir.h (dsl_dir_phys): Add keychain.
|
||||
* include/grub/zfs/spa.h (grub_zfs_endian): Moved from here ...
|
||||
* include/grub/zfs/zfs.h (grub_zfs_endian): ... here. Added GURB_ZFS_
|
||||
prefix. All users updated.
|
||||
(grub_zfs_add_key): New proto.
|
||||
(grub_zfs_decrypt): Likewise.
|
||||
(grub_zfs_load_key): Likewise.
|
||||
* include/grub/zfs/zio.h (zio_checksum): Add SHA256+MAC.
|
||||
* util/grub-fstest.c (options): Add -K option.
|
||||
(argp_parser): Likewise.
|
||||
|
||||
2011-11-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Support zle compression on ZFS.
|
||||
|
|
|
@ -82,6 +82,7 @@ library = {
|
|||
common = grub-core/fs/ufs2.c;
|
||||
common = grub-core/fs/ufs.c;
|
||||
common = grub-core/fs/xfs.c;
|
||||
common = grub-core/fs/zfs/zfscrypt.c;
|
||||
common = grub-core/fs/zfs/zfs.c;
|
||||
common = grub-core/fs/zfs/zfsinfo.c;
|
||||
common = grub-core/fs/zfs/zfs_lzjb.c;
|
||||
|
|
|
@ -1116,6 +1116,11 @@ module = {
|
|||
common = fs/zfs/zfs_fletcher.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = zfscrypt;
|
||||
common = fs/zfs/zfscrypt.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = zfsinfo;
|
||||
common = fs/zfs/zfsinfo.c;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010 Free Software Foundation, Inc.
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc.
|
||||
* Copyright 2010 Sun Microsystems, Inc.
|
||||
*
|
||||
* GRUB is free software; you can redistribute it and/or modify
|
||||
|
@ -52,6 +52,7 @@
|
|||
#include <grub/zfs/dsl_dir.h>
|
||||
#include <grub/zfs/dsl_dataset.h>
|
||||
#include <grub/deflate.h>
|
||||
#include <grub/crypto.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -161,6 +162,20 @@ struct grub_zfs_device_desc
|
|||
int original;
|
||||
};
|
||||
|
||||
struct subvolume
|
||||
{
|
||||
dnode_end_t mdn;
|
||||
grub_uint64_t obj;
|
||||
grub_uint64_t case_insensitive;
|
||||
grub_size_t nkeys;
|
||||
struct
|
||||
{
|
||||
grub_crypto_cipher_handle_t cipher;
|
||||
grub_uint64_t txg;
|
||||
grub_uint64_t algo;
|
||||
} *keyring;
|
||||
};
|
||||
|
||||
struct grub_zfs_data
|
||||
{
|
||||
/* cache for a file block of the currently zfs_open()-ed file */
|
||||
|
@ -176,8 +191,8 @@ struct grub_zfs_data
|
|||
grub_zfs_endian_t dnode_endian;
|
||||
|
||||
dnode_end_t mos;
|
||||
dnode_end_t mdn;
|
||||
dnode_end_t dnode;
|
||||
struct subvolume subvol;
|
||||
|
||||
struct grub_zfs_device_desc *devices_attached;
|
||||
unsigned n_devices_attached;
|
||||
|
@ -190,6 +205,17 @@ struct grub_zfs_data
|
|||
grub_uint64_t guid;
|
||||
};
|
||||
|
||||
grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
|
||||
grub_uint64_t algo,
|
||||
void *nonce,
|
||||
char *buf, grub_size_t size,
|
||||
const grub_uint32_t *expected_mac,
|
||||
grub_zfs_endian_t endian) = NULL;
|
||||
grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key,
|
||||
grub_size_t keysize,
|
||||
grub_uint64_t salt,
|
||||
grub_uint64_t algo) = NULL;
|
||||
|
||||
static grub_err_t
|
||||
zlib_decompress (void *s, void *d,
|
||||
grub_size_t slen, grub_size_t dlen)
|
||||
|
@ -292,6 +318,7 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
|
|||
{fletcher_4, 1, 0, "fletcher4"},
|
||||
{zio_checksum_SHA256, 1, 0, "SHA256"},
|
||||
{NULL, 0, 0, "zilog2"},
|
||||
{zio_checksum_SHA256, 1, 0, "SHA256+MAC"},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -302,7 +329,8 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
|
|||
*/
|
||||
static grub_err_t
|
||||
zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
|
||||
grub_zfs_endian_t endian, char *buf, grub_size_t size)
|
||||
grub_zfs_endian_t endian,
|
||||
char *buf, grub_size_t size)
|
||||
{
|
||||
zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
|
||||
zio_checksum_info_t *ci = &zio_checksum_table[checksum];
|
||||
|
@ -312,7 +340,7 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
|
|||
{
|
||||
grub_dprintf ("zfs", "unknown checksum function %d\n", checksum);
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unknown checksum function %d", checksum);
|
||||
"unknown checksum function %d", checksum);
|
||||
}
|
||||
|
||||
if (ci->ci_eck)
|
||||
|
@ -326,10 +354,8 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
|
|||
else
|
||||
ci->ci_func (buf, size, endian, &actual_cksum);
|
||||
|
||||
if ((actual_cksum.zc_word[0] != zc.zc_word[0])
|
||||
|| (actual_cksum.zc_word[1] != zc.zc_word[1])
|
||||
|| (actual_cksum.zc_word[2] != zc.zc_word[2])
|
||||
|| (actual_cksum.zc_word[3] != zc.zc_word[3]))
|
||||
if (grub_memcmp (&actual_cksum, &zc,
|
||||
checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20) != 0)
|
||||
{
|
||||
grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name);
|
||||
grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n",
|
||||
|
@ -362,14 +388,16 @@ static int
|
|||
vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2)
|
||||
{
|
||||
grub_zfs_endian_t ub1_endian, ub2_endian;
|
||||
if (grub_zfs_to_cpu64 (ub1->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC)
|
||||
ub1_endian = LITTLE_ENDIAN;
|
||||
if (grub_zfs_to_cpu64 (ub1->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
|
||||
== UBERBLOCK_MAGIC)
|
||||
ub1_endian = GRUB_ZFS_LITTLE_ENDIAN;
|
||||
else
|
||||
ub1_endian = BIG_ENDIAN;
|
||||
if (grub_zfs_to_cpu64 (ub2->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC)
|
||||
ub2_endian = LITTLE_ENDIAN;
|
||||
ub1_endian = GRUB_ZFS_BIG_ENDIAN;
|
||||
if (grub_zfs_to_cpu64 (ub2->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
|
||||
== UBERBLOCK_MAGIC)
|
||||
ub2_endian = GRUB_ZFS_LITTLE_ENDIAN;
|
||||
else
|
||||
ub2_endian = BIG_ENDIAN;
|
||||
ub2_endian = GRUB_ZFS_BIG_ENDIAN;
|
||||
|
||||
if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian)
|
||||
< grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian))
|
||||
|
@ -401,20 +429,23 @@ uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset)
|
|||
{
|
||||
uberblock_t *uber = &ub->ubp_uberblock;
|
||||
grub_err_t err;
|
||||
grub_zfs_endian_t endian = UNKNOWN_ENDIAN;
|
||||
grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN;
|
||||
zio_cksum_t zc;
|
||||
|
||||
if (grub_zfs_to_cpu64 (uber->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, LITTLE_ENDIAN) > 0
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, LITTLE_ENDIAN) <= SPA_VERSION)
|
||||
endian = LITTLE_ENDIAN;
|
||||
if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
|
||||
== UBERBLOCK_MAGIC
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)
|
||||
<= SPA_VERSION)
|
||||
endian = GRUB_ZFS_LITTLE_ENDIAN;
|
||||
|
||||
if (grub_zfs_to_cpu64 (uber->ub_magic, BIG_ENDIAN) == UBERBLOCK_MAGIC
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, BIG_ENDIAN) > 0
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, BIG_ENDIAN) <= SPA_VERSION)
|
||||
endian = BIG_ENDIAN;
|
||||
if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0
|
||||
&& grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)
|
||||
<= SPA_VERSION)
|
||||
endian = GRUB_ZFS_BIG_ENDIAN;
|
||||
|
||||
if (endian == UNKNOWN_ENDIAN)
|
||||
if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic");
|
||||
|
||||
grub_memset (&zc, 0, sizeof (zc));
|
||||
|
@ -1335,7 +1366,7 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
|
|||
zio_gb = grub_malloc (SPA_GANGBLOCKSIZE);
|
||||
if (!zio_gb)
|
||||
return grub_errno;
|
||||
grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n"
|
||||
grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n"
|
||||
:"big-endian gang\n");
|
||||
|
||||
err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE);
|
||||
|
@ -1415,11 +1446,11 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf,
|
|||
* and put the uncompressed data in buf.
|
||||
*/
|
||||
static grub_err_t
|
||||
zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
|
||||
zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
|
||||
grub_size_t *size, struct grub_zfs_data *data)
|
||||
{
|
||||
grub_size_t lsize, psize;
|
||||
unsigned int comp;
|
||||
unsigned int comp, encrypted;
|
||||
char *compbuf = NULL;
|
||||
grub_err_t err;
|
||||
zio_cksum_t zc = bp->blk_cksum;
|
||||
|
@ -1429,6 +1460,7 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
|
|||
|
||||
checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff;
|
||||
comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff;
|
||||
encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3);
|
||||
lsize = (BP_IS_HOLE(bp) ? 0 :
|
||||
(((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
|
||||
<< SPA_MINBLOCKSHIFT));
|
||||
|
@ -1447,7 +1479,8 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
|
|||
|
||||
if (comp != ZIO_COMPRESS_OFF)
|
||||
{
|
||||
compbuf = grub_malloc (psize);
|
||||
/* It's not really necessary to align to 16, just for safety. */
|
||||
compbuf = grub_malloc (ALIGN_UP (psize, 16));
|
||||
if (! compbuf)
|
||||
return grub_errno;
|
||||
}
|
||||
|
@ -1462,8 +1495,10 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
|
|||
*buf = NULL;
|
||||
return err;
|
||||
}
|
||||
grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize);
|
||||
|
||||
err = zio_checksum_verify (zc, checksum, endian, compbuf, psize);
|
||||
err = zio_checksum_verify (zc, checksum, endian,
|
||||
compbuf, psize);
|
||||
if (err)
|
||||
{
|
||||
grub_dprintf ("zfs", "incorrect checksum\n");
|
||||
|
@ -1472,6 +1507,51 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (encrypted)
|
||||
{
|
||||
if (!grub_zfs_decrypt)
|
||||
err = grub_error (GRUB_ERR_BAD_FS, "zfscrypt module not loaded");
|
||||
else
|
||||
{
|
||||
unsigned i, besti = 0;
|
||||
grub_uint64_t bestval = 0;
|
||||
for (i = 0; i < data->subvol.nkeys; i++)
|
||||
if (data->subvol.keyring[i].txg <= grub_zfs_to_cpu64 (bp->blk_birth,
|
||||
endian)
|
||||
&& data->subvol.keyring[i].txg > bestval)
|
||||
{
|
||||
besti = i;
|
||||
bestval = data->subvol.keyring[i].txg;
|
||||
}
|
||||
if (bestval == 0)
|
||||
{
|
||||
grub_free (compbuf);
|
||||
*buf = NULL;
|
||||
grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
|
||||
grub_zfs_to_cpu64 (bp->blk_birth,
|
||||
endian));
|
||||
return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
|
||||
}
|
||||
grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T
|
||||
", %p) for txg %" PRIxGRUB_UINT64_T "\n",
|
||||
besti, data->subvol.keyring[besti].txg,
|
||||
data->subvol.keyring[besti].cipher,
|
||||
grub_zfs_to_cpu64 (bp->blk_birth,
|
||||
endian));
|
||||
err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
|
||||
data->subvol.keyring[besti].algo,
|
||||
&(bp)->blk_dva[encrypted],
|
||||
compbuf, psize, ((grub_uint32_t *) &zc + 5),
|
||||
endian);
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
grub_free (compbuf);
|
||||
*buf = NULL;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (comp != ZIO_COMPRESS_OFF)
|
||||
{
|
||||
*buf = grub_malloc (lsize);
|
||||
|
@ -1572,7 +1652,7 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
|
|||
*/
|
||||
static grub_err_t
|
||||
mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
|
||||
int objsize, char *name, grub_uint64_t * value,
|
||||
int objsize, const char *name, grub_uint64_t * value,
|
||||
int case_insensitive)
|
||||
{
|
||||
int i, chunks;
|
||||
|
@ -1799,9 +1879,6 @@ zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
|
|||
if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic");
|
||||
|
||||
if (zap->zap_flags != 0)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "bad ZAP flags");
|
||||
|
||||
if (zap->zap_salt == 0)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "bad ZAP salt");
|
||||
|
||||
|
@ -1854,9 +1931,13 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
|||
/* XXX */
|
||||
static int
|
||||
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
||||
int NESTED_FUNC_ATTR (*hook) (const char *name,
|
||||
grub_uint64_t val),
|
||||
struct grub_zfs_data *data)
|
||||
grub_size_t name_elem_length,
|
||||
int NESTED_FUNC_ATTR (*hook) (const void *name,
|
||||
grub_size_t name_length,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize),
|
||||
struct grub_zfs_data *data)
|
||||
{
|
||||
zap_leaf_phys_t *l;
|
||||
void *l_in;
|
||||
|
@ -1918,46 +1999,52 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
|||
for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++)
|
||||
{
|
||||
char *buf;
|
||||
struct zap_leaf_array *la;
|
||||
struct zap_leaf_entry *le;
|
||||
grub_uint64_t val;
|
||||
char *val;
|
||||
grub_size_t val_length;
|
||||
le = ZAP_LEAF_ENTRY (l, blksft, chunk);
|
||||
|
||||
/* Verify the chunk entry */
|
||||
if (le->le_type != ZAP_CHUNK_ENTRY)
|
||||
continue;
|
||||
|
||||
buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
|
||||
+ 1);
|
||||
buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
|
||||
* name_elem_length + 1);
|
||||
if (zap_leaf_array_get (l, endian, blksft,
|
||||
grub_zfs_to_cpu16 (le->le_name_chunk,
|
||||
endian),
|
||||
grub_zfs_to_cpu16 (le->le_name_length,
|
||||
endian), buf))
|
||||
endian)
|
||||
* name_elem_length, buf))
|
||||
{
|
||||
grub_free (buf);
|
||||
continue;
|
||||
}
|
||||
buf[le->le_name_length] = 0;
|
||||
buf[le->le_name_length * name_elem_length] = 0;
|
||||
|
||||
if (le->le_int_size != 8
|
||||
|| grub_zfs_to_cpu16 (le->le_value_length, endian) != 1)
|
||||
continue;
|
||||
val_length = ((int) le->le_value_length
|
||||
* (int) le->le_int_size);
|
||||
val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian));
|
||||
if (zap_leaf_array_get (l, endian, blksft,
|
||||
grub_zfs_to_cpu16 (le->le_value_chunk,
|
||||
endian),
|
||||
val_length, val))
|
||||
{
|
||||
grub_free (buf);
|
||||
grub_free (val);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get the uint64_t property value */
|
||||
la = &ZAP_LEAF_CHUNK (l, blksft,
|
||||
grub_zfs_to_cpu16 (le->le_value_chunk,
|
||||
endian)).l_array;
|
||||
val = grub_be_to_cpu64 (la->la_array64);
|
||||
if (hook (buf, val))
|
||||
if (hook (buf, le->le_name_length,
|
||||
val, le->le_value_length, le->le_int_size))
|
||||
return 1;
|
||||
grub_free (buf);
|
||||
grub_free (val);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read in the data of a zap object and find the value for a matching
|
||||
* property name.
|
||||
|
@ -2009,9 +2096,10 @@ zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val,
|
|||
}
|
||||
|
||||
static int
|
||||
zap_iterate (dnode_end_t * zap_dnode,
|
||||
int NESTED_FUNC_ATTR (*hook) (const char *name, grub_uint64_t val),
|
||||
struct grub_zfs_data *data)
|
||||
zap_iterate_u64 (dnode_end_t * zap_dnode,
|
||||
int NESTED_FUNC_ATTR (*hook) (const char *name,
|
||||
grub_uint64_t val),
|
||||
struct grub_zfs_data *data)
|
||||
{
|
||||
grub_uint64_t block_type;
|
||||
int size;
|
||||
|
@ -2020,6 +2108,23 @@ zap_iterate (dnode_end_t * zap_dnode,
|
|||
int ret;
|
||||
grub_zfs_endian_t endian;
|
||||
|
||||
auto int NESTED_FUNC_ATTR transform (const void *name,
|
||||
grub_size_t namelen,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize);
|
||||
|
||||
int NESTED_FUNC_ATTR transform (const void *name,
|
||||
grub_size_t namelen __attribute__ ((unused)),
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize)
|
||||
{
|
||||
if (elemsize != sizeof (grub_uint64_t) || nelem != 1)
|
||||
return 0;
|
||||
return hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in));
|
||||
}
|
||||
|
||||
/* Read in the first block of the zap object data. */
|
||||
size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
|
||||
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
|
||||
|
@ -2040,7 +2145,50 @@ zap_iterate (dnode_end_t * zap_dnode,
|
|||
{
|
||||
grub_dprintf ("zfs", "fat zap\n");
|
||||
/* this is a fat zap */
|
||||
ret = fzap_iterate (zap_dnode, zapbuf, hook, data);
|
||||
ret = fzap_iterate (zap_dnode, zapbuf, 1, transform, data);
|
||||
grub_free (zapbuf);
|
||||
return ret;
|
||||
}
|
||||
grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
zap_iterate (dnode_end_t * zap_dnode,
|
||||
grub_size_t nameelemlen,
|
||||
int NESTED_FUNC_ATTR (*hook) (const void *name,
|
||||
grub_size_t namelen,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize),
|
||||
struct grub_zfs_data *data)
|
||||
{
|
||||
grub_uint64_t block_type;
|
||||
int size;
|
||||
void *zapbuf;
|
||||
grub_err_t err;
|
||||
int ret;
|
||||
grub_zfs_endian_t endian;
|
||||
|
||||
/* Read in the first block of the zap object data. */
|
||||
size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
|
||||
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
|
||||
if (err)
|
||||
return 0;
|
||||
block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
|
||||
|
||||
grub_dprintf ("zfs", "zap iterate\n");
|
||||
|
||||
if (block_type == ZBT_MICRO)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected");
|
||||
return 0;
|
||||
}
|
||||
if (block_type == ZBT_HEADER)
|
||||
{
|
||||
grub_dprintf ("zfs", "fat zap\n");
|
||||
/* this is a fat zap */
|
||||
ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, data);
|
||||
grub_free (zapbuf);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2124,10 +2272,10 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
|
|||
*
|
||||
*/
|
||||
static grub_err_t
|
||||
dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
|
||||
struct grub_zfs_data *data, int *case_insensitive)
|
||||
dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
|
||||
struct grub_zfs_data *data)
|
||||
{
|
||||
grub_uint64_t objnum, version, insensitivity;
|
||||
grub_uint64_t objnum, version;
|
||||
char *cname, ch;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
char *path, *path_buf;
|
||||
|
@ -2144,7 +2292,7 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
|
|||
dn_new->next = 0;
|
||||
dnode_path = root = dn_new;
|
||||
|
||||
err = dnode_get (mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE,
|
||||
err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE,
|
||||
&(dnode_path->dn), data);
|
||||
if (err)
|
||||
{
|
||||
|
@ -2166,15 +2314,14 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
|
|||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version");
|
||||
}
|
||||
|
||||
err = zap_lookup (&(dnode_path->dn), "casesensitivity", &insensitivity,
|
||||
err = zap_lookup (&(dnode_path->dn), "casesensitivity",
|
||||
&subvol->case_insensitive,
|
||||
data, 0);
|
||||
if (err == GRUB_ERR_FILE_NOT_FOUND)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
insensitivity = 0;
|
||||
subvol->case_insensitive = 0;
|
||||
}
|
||||
if (case_insensitive)
|
||||
*case_insensitive = insensitivity;
|
||||
|
||||
err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0);
|
||||
if (err)
|
||||
|
@ -2183,7 +2330,7 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
|
|||
return err;
|
||||
}
|
||||
|
||||
err = dnode_get (mdn, objnum, 0, &(dnode_path->dn), data);
|
||||
err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
|
||||
if (err)
|
||||
{
|
||||
grub_free (dn_new);
|
||||
|
@ -2237,7 +2384,8 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
|
|||
grub_free (path_buf);
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
||||
}
|
||||
err = zap_lookup (&(dnode_path->dn), cname, &objnum, data, insensitivity);
|
||||
err = zap_lookup (&(dnode_path->dn), cname, &objnum,
|
||||
data, subvol->case_insensitive);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
|
@ -2251,7 +2399,7 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
|
|||
dnode_path = dn_new;
|
||||
|
||||
objnum = ZFS_DIRENT_OBJ (objnum);
|
||||
err = dnode_get (mdn, objnum, 0, &(dnode_path->dn), data);
|
||||
err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
|
@ -2545,14 +2693,65 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
|
||||
grub_uint64_t *mdnobj, dnode_end_t * dn, int *isfs,
|
||||
struct grub_zfs_data *data, int *case_insensitive)
|
||||
dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
||||
dnode_end_t * dn, int *isfs,
|
||||
struct grub_zfs_data *data)
|
||||
{
|
||||
char *fsname, *snapname;
|
||||
const char *ptr_at, *filename;
|
||||
grub_uint64_t headobj;
|
||||
grub_uint64_t keychainobj;
|
||||
grub_uint64_t salt;
|
||||
grub_err_t err;
|
||||
int keyn = 0;
|
||||
|
||||
auto int NESTED_FUNC_ATTR count_zap_keys (const void *name,
|
||||
grub_size_t namelen,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize);
|
||||
int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)),
|
||||
grub_size_t namelen __attribute__ ((unused)),
|
||||
const void *val_in __attribute__ ((unused)),
|
||||
grub_size_t nelem __attribute__ ((unused)),
|
||||
grub_size_t elemsize __attribute__ ((unused)))
|
||||
{
|
||||
subvol->nkeys++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto int NESTED_FUNC_ATTR load_zap_key (const void *name,
|
||||
grub_size_t namelen,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize);
|
||||
int NESTED_FUNC_ATTR load_zap_key (const void *name,
|
||||
grub_size_t namelen,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize)
|
||||
{
|
||||
if (namelen != 1)
|
||||
{
|
||||
grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n",
|
||||
namelen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (elemsize != 1)
|
||||
{
|
||||
grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n",
|
||||
elemsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subvol->keyring[keyn].txg = grub_be_to_cpu64 (*(grub_uint64_t *) name);
|
||||
subvol->keyring[keyn].algo = grub_le_to_cpu64 (*(grub_uint64_t *) val_in);
|
||||
subvol->keyring[keyn].cipher = grub_zfs_load_key (val_in, nelem, salt,
|
||||
subvol->keyring[keyn].algo);
|
||||
keyn++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr_at = grub_strchr (fullpath, '@');
|
||||
if (! ptr_at)
|
||||
|
@ -2605,29 +2804,80 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
|
|||
|
||||
headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_head_dataset_obj, dn->endian);
|
||||
|
||||
grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
|
||||
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
|
||||
|
||||
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data);
|
||||
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &subvol->mdn,
|
||||
data);
|
||||
if (err)
|
||||
{
|
||||
grub_free (fsname);
|
||||
grub_free (snapname);
|
||||
return err;
|
||||
}
|
||||
grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
|
||||
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
|
||||
|
||||
keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian);
|
||||
if (grub_zfs_load_key && keychainobj)
|
||||
{
|
||||
dnode_end_t keychain_dn, props_dn;
|
||||
grub_uint64_t propsobj;
|
||||
propsobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_props_zapobj, dn->endian);
|
||||
|
||||
err = dnode_get (&(data->mos), propsobj, DMU_OT_DSL_PROPS,
|
||||
&props_dn, data);
|
||||
if (err)
|
||||
{
|
||||
grub_free (fsname);
|
||||
grub_free (snapname);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = zap_lookup (&props_dn, "salt", &salt, data, 0);
|
||||
if (err == GRUB_ERR_FILE_NOT_FOUND)
|
||||
{
|
||||
err = 0;
|
||||
grub_errno = 0;
|
||||
salt = 0;
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
grub_dprintf ("zfs", "failed here\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = dnode_get (&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN,
|
||||
&keychain_dn, data);
|
||||
if (err)
|
||||
{
|
||||
grub_free (fsname);
|
||||
grub_free (snapname);
|
||||
return err;
|
||||
}
|
||||
subvol->nkeys = 0;
|
||||
zap_iterate (&keychain_dn, 8, count_zap_keys, data);
|
||||
subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0]));
|
||||
if (!subvol->keyring)
|
||||
{
|
||||
grub_free (fsname);
|
||||
grub_free (snapname);
|
||||
return err;
|
||||
}
|
||||
zap_iterate (&keychain_dn, 8, load_zap_key, data);
|
||||
}
|
||||
|
||||
if (snapname)
|
||||
{
|
||||
grub_uint64_t snapobj;
|
||||
|
||||
snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&mdn->dn))->ds_snapnames_zapobj, mdn->endian);
|
||||
snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian);
|
||||
|
||||
err = dnode_get (&(data->mos), snapobj,
|
||||
DMU_OT_DSL_DS_SNAP_MAP, mdn, data);
|
||||
DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data);
|
||||
if (!err)
|
||||
err = zap_lookup (mdn, snapname, &headobj, data, 0);
|
||||
err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0);
|
||||
if (!err)
|
||||
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data);
|
||||
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET,
|
||||
&subvol->mdn, data);
|
||||
if (err)
|
||||
{
|
||||
grub_free (fsname);
|
||||
|
@ -2636,12 +2886,11 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
|
|||
}
|
||||
}
|
||||
|
||||
if (mdnobj)
|
||||
*mdnobj = headobj;
|
||||
subvol->obj = headobj;
|
||||
|
||||
make_mdn (mdn, data);
|
||||
make_mdn (&subvol->mdn, data);
|
||||
|
||||
grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
|
||||
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
|
||||
|
||||
if (*isfs)
|
||||
{
|
||||
|
@ -2649,7 +2898,7 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
|
|||
grub_free (snapname);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
err = dnode_get_path (mdn, filename, dn, data, case_insensitive);
|
||||
err = dnode_get_path (subvol, filename, dn, data);
|
||||
grub_free (fsname);
|
||||
grub_free (snapname);
|
||||
return err;
|
||||
|
@ -2918,6 +3167,9 @@ zfs_unmount (struct grub_zfs_data *data)
|
|||
grub_free (data->dnode_buf);
|
||||
grub_free (data->dnode_mdn);
|
||||
grub_free (data->file_buf);
|
||||
for (i = 0; i < data->subvol.nkeys; i++)
|
||||
grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
|
||||
grub_free (data->subvol.keyring);
|
||||
grub_free (data);
|
||||
}
|
||||
|
||||
|
@ -2933,7 +3185,7 @@ zfs_mount (grub_device_t dev)
|
|||
grub_err_t err;
|
||||
objset_phys_t *osp = 0;
|
||||
grub_size_t ospsize;
|
||||
grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
|
||||
grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
|
||||
uberblock_t *ub;
|
||||
|
||||
if (! dev->disk)
|
||||
|
@ -2964,8 +3216,8 @@ zfs_mount (grub_device_t dev)
|
|||
|
||||
ub = &(data->current_uberblock);
|
||||
ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
|
||||
LITTLE_ENDIAN) == UBERBLOCK_MAGIC
|
||||
? LITTLE_ENDIAN : BIG_ENDIAN);
|
||||
GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
|
||||
? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
|
||||
|
||||
err = zio_read (&ub->ub_rootbp, ub_endian,
|
||||
(void **) &osp, &ospsize, data);
|
||||
|
@ -3054,7 +3306,7 @@ static grub_err_t
|
|||
zfs_mtime (grub_device_t device, grub_int32_t *mt)
|
||||
{
|
||||
struct grub_zfs_data *data;
|
||||
grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
|
||||
grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
|
||||
uberblock_t *ub;
|
||||
|
||||
*mt = 0;
|
||||
|
@ -3065,8 +3317,8 @@ zfs_mtime (grub_device_t device, grub_int32_t *mt)
|
|||
|
||||
ub = &(data->current_uberblock);
|
||||
ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
|
||||
LITTLE_ENDIAN) == UBERBLOCK_MAGIC
|
||||
? LITTLE_ENDIAN : BIG_ENDIAN);
|
||||
GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
|
||||
? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
|
||||
|
||||
*mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian);
|
||||
zfs_unmount (data);
|
||||
|
@ -3088,8 +3340,8 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename)
|
|||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
err = dnode_get_fullpath (fsfilename, &(data->mdn), 0,
|
||||
&(data->dnode), &isfs, data, NULL);
|
||||
err = dnode_get_fullpath (fsfilename, &(data->subvol),
|
||||
&(data->dnode), &isfs, data);
|
||||
if (err)
|
||||
{
|
||||
zfs_unmount (data);
|
||||
|
@ -3252,8 +3504,9 @@ grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename,
|
|||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
err = dnode_get_fullpath (fsfilename, &(data->mdn), mdnobj,
|
||||
&(data->dnode), &isfs, data, NULL);
|
||||
err = dnode_get_fullpath (fsfilename, &(data->subvol),
|
||||
&(data->dnode), &isfs, data);
|
||||
*mdnobj = data->subvol.obj;
|
||||
zfs_unmount (data);
|
||||
return err;
|
||||
}
|
||||
|
@ -3348,7 +3601,6 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
struct grub_zfs_data *data;
|
||||
grub_err_t err;
|
||||
int isfs;
|
||||
int case_insensitive = 0;
|
||||
auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val);
|
||||
auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name,
|
||||
grub_uint64_t val);
|
||||
|
@ -3361,7 +3613,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
dnode_end_t dn;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
|
||||
dnode_get (&(data->mdn), val, 0, &dn, data);
|
||||
dnode_get (&(data->subvol.mdn), val, 0, &dn, data);
|
||||
|
||||
if (dn.dn.dn_bonustype == DMU_OT_SA)
|
||||
{
|
||||
|
@ -3393,7 +3645,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
|
||||
info.case_insensitive = case_insensitive;
|
||||
info.case_insensitive = data->subvol.case_insensitive;
|
||||
}
|
||||
|
||||
if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
|
||||
|
@ -3448,8 +3700,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
data = zfs_mount (device);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
err = dnode_get_fullpath (path, &(data->mdn), 0, &(data->dnode), &isfs, data,
|
||||
&case_insensitive);
|
||||
err = dnode_get_fullpath (path, &(data->subvol), &(data->dnode), &isfs, data);
|
||||
if (err)
|
||||
{
|
||||
zfs_unmount (data);
|
||||
|
@ -3475,7 +3726,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
return err;
|
||||
}
|
||||
|
||||
zap_iterate (&dn, iterate_zap_fs, data);
|
||||
zap_iterate_u64 (&dn, iterate_zap_fs, data);
|
||||
|
||||
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data);
|
||||
if (err)
|
||||
|
@ -3494,7 +3745,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
return err;
|
||||
}
|
||||
|
||||
zap_iterate (&dn, iterate_zap_snap, data);
|
||||
zap_iterate_u64 (&dn, iterate_zap_snap, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3503,7 +3754,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
zfs_unmount (data);
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
||||
}
|
||||
zap_iterate (&(data->dnode), iterate_zap, data);
|
||||
zap_iterate_u64 (&(data->dnode), iterate_zap, data);
|
||||
}
|
||||
zfs_unmount (data);
|
||||
return grub_errno;
|
||||
|
|
466
grub-core/fs/zfs/zfscrypt.c
Normal file
466
grub-core/fs/zfs/zfscrypt.c
Normal file
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/err.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/partition.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/zfs/zfs.h>
|
||||
#include <grub/zfs/zio.h>
|
||||
#include <grub/zfs/dnode.h>
|
||||
#include <grub/zfs/uberblock_impl.h>
|
||||
#include <grub/zfs/vdev_impl.h>
|
||||
#include <grub/zfs/zio_checksum.h>
|
||||
#include <grub/zfs/zap_impl.h>
|
||||
#include <grub/zfs/zap_leaf.h>
|
||||
#include <grub/zfs/zfs_znode.h>
|
||||
#include <grub/zfs/dmu.h>
|
||||
#include <grub/zfs/dmu_objset.h>
|
||||
#include <grub/zfs/sa_impl.h>
|
||||
#include <grub/zfs/dsl_dir.h>
|
||||
#include <grub/zfs/dsl_dataset.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
enum grub_zfs_algo
|
||||
{
|
||||
GRUB_ZFS_ALGO_CCM,
|
||||
GRUB_ZFS_ALGO_GCM,
|
||||
};
|
||||
|
||||
struct grub_zfs_key
|
||||
{
|
||||
grub_uint64_t algo;
|
||||
grub_uint8_t enc_nonce[13];
|
||||
grub_uint8_t unused[3];
|
||||
grub_uint8_t enc_key[48];
|
||||
grub_uint8_t unknown_purpose_nonce[13];
|
||||
grub_uint8_t unused2[3];
|
||||
grub_uint8_t unknown_purpose_key[48];
|
||||
};
|
||||
|
||||
struct grub_zfs_wrap_key
|
||||
{
|
||||
struct grub_zfs_wrap_key *next;
|
||||
grub_size_t keylen;
|
||||
int is_passphrase;
|
||||
grub_uint64_t key[0];
|
||||
};
|
||||
|
||||
static struct grub_zfs_wrap_key *zfs_wrap_keys;
|
||||
|
||||
grub_err_t
|
||||
grub_zfs_add_key (grub_uint8_t *key_in,
|
||||
grub_size_t keylen,
|
||||
int passphrase)
|
||||
{
|
||||
struct grub_zfs_wrap_key *key;
|
||||
if (!passphrase && keylen > 32)
|
||||
keylen = 32;
|
||||
key = grub_malloc (sizeof (*key) + keylen);
|
||||
if (!key)
|
||||
return grub_errno;
|
||||
key->is_passphrase = passphrase;
|
||||
key->keylen = keylen;
|
||||
grub_memcpy (key->key, key_in, keylen);
|
||||
key->next = zfs_wrap_keys;
|
||||
zfs_wrap_keys = key;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ccm_decrypt (grub_crypto_cipher_handle_t cipher,
|
||||
grub_uint8_t *out, const grub_uint8_t *in,
|
||||
grub_size_t psize,
|
||||
void *mac_out, const void *nonce,
|
||||
unsigned l, unsigned m)
|
||||
{
|
||||
grub_uint8_t iv[16];
|
||||
grub_uint8_t mul[16];
|
||||
grub_uint32_t mac[4];
|
||||
unsigned i, j;
|
||||
grub_err_t err;
|
||||
|
||||
grub_memcpy (iv + 1, nonce, 15 - l);
|
||||
|
||||
iv[0] = (l - 1) | (((m-2) / 2) << 3);
|
||||
for (j = 0; j < l; j++)
|
||||
iv[15 - j] = psize >> (8 * j);
|
||||
err = grub_crypto_ecb_encrypt (cipher, mac, iv, 16);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
iv[0] = l - 1;
|
||||
|
||||
for (i = 0; i < (psize + 15) / 16; i++)
|
||||
{
|
||||
grub_size_t csize;
|
||||
csize = 16;
|
||||
if (csize > psize - 16 * i)
|
||||
csize = psize - 16 * i;
|
||||
for (j = 0; j < l; j++)
|
||||
iv[15 - j] = (i + 1) >> (8 * j);
|
||||
err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16);
|
||||
if (err)
|
||||
return err;
|
||||
grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize);
|
||||
grub_crypto_xor (mac, mac, out + 16 * i, csize);
|
||||
err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
for (j = 0; j < l; j++)
|
||||
iv[15 - j] = 0;
|
||||
err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16);
|
||||
if (err)
|
||||
return err;
|
||||
if (mac_out)
|
||||
grub_crypto_xor (mac_out, mac, mul, m);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_gcm_mul_x (grub_uint8_t *a)
|
||||
{
|
||||
int i;
|
||||
int c = 0, d = 0;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
c = a[i] & 0x1;
|
||||
a[i] = (a[i] >> 1) | (d << 7);
|
||||
d = c;
|
||||
}
|
||||
if (d)
|
||||
a[0] ^= 0xe1;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_gcm_mul (grub_uint8_t *a, const grub_uint8_t *b)
|
||||
{
|
||||
grub_uint8_t res[16], bs[16];
|
||||
int i;
|
||||
grub_memcpy (bs, b, 16);
|
||||
grub_memset (res, 0, 16);
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
if ((a[i / 8] << (i % 8)) & 0x80)
|
||||
grub_crypto_xor (res, res, bs, 16);
|
||||
grub_gcm_mul_x (bs);
|
||||
}
|
||||
|
||||
grub_memcpy (a, res, 16);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
|
||||
grub_uint8_t *out, const grub_uint8_t *in,
|
||||
grub_size_t psize,
|
||||
void *mac_out, const void *nonce,
|
||||
unsigned nonce_len, unsigned m)
|
||||
{
|
||||
grub_uint8_t iv[16];
|
||||
grub_uint8_t mul[16];
|
||||
grub_uint8_t mac[16], h[16], mac_xor[16];
|
||||
unsigned i, j;
|
||||
grub_err_t err;
|
||||
|
||||
grub_memset (mac, 0, sizeof (mac));
|
||||
|
||||
err = grub_crypto_ecb_encrypt (cipher, h, mac, 16);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (nonce_len == 12)
|
||||
{
|
||||
grub_memcpy (iv, nonce, 12);
|
||||
iv[12] = 0;
|
||||
iv[13] = 0;
|
||||
iv[14] = 0;
|
||||
iv[15] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_memset (iv, 0, sizeof (iv));
|
||||
grub_memcpy (iv, nonce, nonce_len);
|
||||
grub_gcm_mul (iv, h);
|
||||
iv[15] ^= nonce_len * 8;
|
||||
grub_gcm_mul (iv, h);
|
||||
}
|
||||
|
||||
err = grub_crypto_ecb_encrypt (cipher, mac_xor, iv, 16);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < (psize + 15) / 16; i++)
|
||||
{
|
||||
grub_size_t csize;
|
||||
csize = 16;
|
||||
if (csize > psize - 16 * i)
|
||||
csize = psize - 16 * i;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
iv[15 - j]++;
|
||||
if (iv[15 - j] != 0)
|
||||
break;
|
||||
}
|
||||
grub_crypto_xor (mac, mac, in + 16 * i, csize);
|
||||
grub_gcm_mul (mac, h);
|
||||
err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16);
|
||||
if (err)
|
||||
return err;
|
||||
grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize);
|
||||
}
|
||||
for (j = 0; j < 8; j++)
|
||||
mac[15 - j] ^= ((psize * 8) >> (8 * j));
|
||||
grub_gcm_mul (mac, h);
|
||||
|
||||
if (mac_out)
|
||||
grub_crypto_xor (mac_out, mac, mac_xor, m);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
algo_decrypt (grub_crypto_cipher_handle_t cipher, grub_uint64_t algo,
|
||||
grub_uint8_t *out, const grub_uint8_t *in,
|
||||
grub_size_t psize,
|
||||
void *mac_out, const void *nonce,
|
||||
unsigned l, unsigned m)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 0:
|
||||
return grub_ccm_decrypt (cipher, out, in, psize, mac_out, nonce, l, m);
|
||||
case 1:
|
||||
return grub_gcm_decrypt (cipher, out, in, psize, mac_out, nonce,
|
||||
15 - l, m);
|
||||
default:
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "algorithm %"
|
||||
PRIuGRUB_UINT64_T " is not supported yet", algo);
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
|
||||
grub_uint64_t algo,
|
||||
void *nonce,
|
||||
char *buf, grub_size_t size,
|
||||
const grub_uint32_t *expected_mac,
|
||||
grub_zfs_endian_t endian)
|
||||
{
|
||||
grub_uint32_t mac[4];
|
||||
unsigned i;
|
||||
grub_uint32_t sw[4];
|
||||
grub_err_t err;
|
||||
|
||||
grub_memcpy (sw, nonce, 16);
|
||||
for (i = 0; i < 4; i++)
|
||||
sw[i] = grub_cpu_to_be32 (grub_zfs_to_cpu32 (sw[i], endian));
|
||||
|
||||
if (!cipher)
|
||||
return grub_error (GRUB_ERR_ACCESS_DENIED,
|
||||
"no decryption key available");;
|
||||
err = algo_decrypt (cipher, algo,
|
||||
(grub_uint8_t *) buf,
|
||||
(grub_uint8_t *) buf,
|
||||
size, mac,
|
||||
sw + 1, 3, 12);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (grub_zfs_to_cpu32 (expected_mac[i], endian)
|
||||
!= grub_be_to_cpu32 (mac[i]))
|
||||
return grub_error (GRUB_ERR_BAD_FS, "MAC verification failed");
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_crypto_cipher_handle_t
|
||||
grub_zfs_load_key_real (const struct grub_zfs_key *key,
|
||||
grub_size_t keysize,
|
||||
grub_uint64_t salt,
|
||||
grub_uint64_t algo)
|
||||
{
|
||||
unsigned keylen;
|
||||
struct grub_zfs_wrap_key *wrap_key;
|
||||
grub_crypto_cipher_handle_t ret = NULL;
|
||||
grub_err_t err;
|
||||
|
||||
if (keysize != sizeof (*key))
|
||||
{
|
||||
grub_dprintf ("zfs", "Unexpected key size %" PRIuGRUB_SIZE "\n", keysize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (grub_memcmp (key->enc_key + 32, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)
|
||||
== 0)
|
||||
keylen = 16;
|
||||
else if (grub_memcmp (key->enc_key + 40, "\0\0\0\0\0\0\0\0", 8) == 0)
|
||||
keylen = 24;
|
||||
else
|
||||
keylen = 32;
|
||||
|
||||
for (wrap_key = zfs_wrap_keys; wrap_key; wrap_key = wrap_key->next)
|
||||
{
|
||||
grub_crypto_cipher_handle_t cipher;
|
||||
grub_uint8_t decrypted[32], mac[32], wrap_key_real[32];
|
||||
cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
|
||||
if (!cipher)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
grub_memset (wrap_key_real, 0, sizeof (wrap_key_real));
|
||||
if (!wrap_key->is_passphrase)
|
||||
grub_memcpy(wrap_key_real, wrap_key->key,
|
||||
wrap_key->keylen < keylen ? wrap_key->keylen : keylen);
|
||||
else
|
||||
grub_crypto_pbkdf2 (GRUB_MD_SHA1,
|
||||
(const grub_uint8_t *) wrap_key->key,
|
||||
wrap_key->keylen,
|
||||
(const grub_uint8_t *) &salt, sizeof (salt),
|
||||
1000, wrap_key_real, keylen);
|
||||
|
||||
err = grub_crypto_cipher_set_key (cipher, wrap_key_real,
|
||||
keylen);
|
||||
if (err)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
err = algo_decrypt (cipher, algo, decrypted, key->unknown_purpose_key, 32,
|
||||
mac, key->unknown_purpose_nonce, 2, 16);
|
||||
if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16)
|
||||
!= 0))
|
||||
{
|
||||
grub_dprintf ("zfs", "key loading failed\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
err = algo_decrypt (cipher, algo, decrypted, key->enc_key, keylen, mac,
|
||||
key->enc_nonce, 2, 16);
|
||||
if (err || grub_crypto_memcmp (mac, key->enc_key + keylen, 16) != 0)
|
||||
{
|
||||
grub_dprintf ("zfs", "key loading failed\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
ret = grub_crypto_cipher_open (GRUB_CIPHER_AES);
|
||||
if (!ret)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
err = grub_crypto_cipher_set_key (ret, decrypted, keylen);
|
||||
if (err)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_crypto_cipher_close (ret);
|
||||
continue;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{"raw", 'r', 0, N_("Assume input is raw."), 0, 0},
|
||||
{"hex", 'h', 0, N_("Assume input is hex."), 0, 0},
|
||||
{"passphrase", 'p', 0, N_("Assume input is passphrase."), 0, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
grub_uint8_t buf[1024];
|
||||
grub_ssize_t real_size;
|
||||
|
||||
if (argc > 0)
|
||||
{
|
||||
grub_file_t file;
|
||||
file = grub_file_open (args[0]);
|
||||
if (!file)
|
||||
return grub_errno;
|
||||
real_size = grub_file_read (file, buf, 1024);
|
||||
if (real_size < 0)
|
||||
return grub_errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_printf ("Enter ZFS password: ");
|
||||
if (!grub_password_get ((char *) buf, 1023))
|
||||
return grub_errno;
|
||||
real_size = grub_strlen ((char *) buf);
|
||||
}
|
||||
|
||||
if (ctxt->state[1].set)
|
||||
{
|
||||
int i;
|
||||
grub_err_t err;
|
||||
for (i = 0; i < real_size / 2; i++)
|
||||
{
|
||||
char c1 = grub_tolower (buf[2 * i]) - '0';
|
||||
char c2 = grub_tolower (buf[2 * i + 1]) - '0';
|
||||
if (c1 > 9)
|
||||
c1 += '0' - 'a' + 10;
|
||||
if (c2 > 9)
|
||||
c2 += '0' - 'a' + 10;
|
||||
buf[i] = (c1 << 4) | c2;
|
||||
}
|
||||
err = grub_zfs_add_key (buf, real_size / 2, 0);
|
||||
if (err)
|
||||
return err;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
return grub_zfs_add_key (buf, real_size,
|
||||
ctxt->state[2].set
|
||||
|| (argc == 0 && !ctxt->state[0].set
|
||||
&& !ctxt->state[1].set));
|
||||
}
|
||||
|
||||
static grub_extcmd_t cmd_key;
|
||||
|
||||
GRUB_MOD_INIT(zfscrypto)
|
||||
{
|
||||
grub_zfs_decrypt = grub_zfs_decrypt_real;
|
||||
grub_zfs_load_key = grub_zfs_load_key_real;
|
||||
cmd_key = grub_register_extcmd ("zfskey", grub_cmd_zfs_key, 0,
|
||||
"zfskey [-h|-p|-r] [FILE]",
|
||||
"Import ZFS wrapping key stored in FILE.",
|
||||
options);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(zfscrypto)
|
||||
{
|
||||
grub_zfs_decrypt = 0;
|
||||
grub_zfs_load_key = 0;
|
||||
grub_unregister_extcmd (cmd_key);
|
||||
}
|
|
@ -169,14 +169,6 @@ grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher,
|
|||
return cipher->cipher->setkey (cipher->ctx, key, keylen);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher)
|
||||
{
|
||||
grub_free (cipher);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size)
|
||||
{
|
||||
|
@ -210,9 +202,10 @@ grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
|
|||
|
||||
gcry_err_code_t
|
||||
grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
|
||||
void *out, void *in, grub_size_t size)
|
||||
void *out, const void *in, grub_size_t size)
|
||||
{
|
||||
grub_uint8_t *inptr, *outptr, *end;
|
||||
const grub_uint8_t *inptr;
|
||||
grub_uint8_t *outptr, *end;
|
||||
if (!cipher->cipher->encrypt)
|
||||
return GPG_ERR_NOT_SUPPORTED;
|
||||
if (size % cipher->cipher->blocksize != 0)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <grub/symbol.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -191,8 +192,11 @@ grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher,
|
|||
const unsigned char *key,
|
||||
unsigned keylen);
|
||||
|
||||
void
|
||||
grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher);
|
||||
static inline void
|
||||
grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher)
|
||||
{
|
||||
grub_free (cipher);
|
||||
}
|
||||
|
||||
void
|
||||
grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size);
|
||||
|
@ -203,7 +207,7 @@ grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
|
|||
|
||||
gcry_err_code_t
|
||||
grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
|
||||
void *out, void *in, grub_size_t size);
|
||||
void *out, const void *in, grub_size_t size);
|
||||
gcry_err_code_t
|
||||
grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher,
|
||||
void *out, void *in, grub_size_t size,
|
||||
|
@ -251,11 +255,13 @@ extern gcry_md_spec_t _gcry_digest_spec_sha1;
|
|||
extern gcry_md_spec_t _gcry_digest_spec_sha256;
|
||||
extern gcry_md_spec_t _gcry_digest_spec_sha512;
|
||||
extern gcry_md_spec_t _gcry_digest_spec_crc32;
|
||||
extern gcry_cipher_spec_t _gcry_cipher_spec_aes;
|
||||
#define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5)
|
||||
#define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1)
|
||||
#define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256)
|
||||
#define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512)
|
||||
#define GRUB_MD_CRC32 ((const gcry_md_spec_t *) &_gcry_digest_spec_crc32)
|
||||
#define GRUB_CIPHER_AES ((const gcry_cipher_spec_t *) &_gcry_cipher_spec_aes)
|
||||
|
||||
/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant
|
||||
of digest supplied by MD. Inputs are the password P of length PLEN,
|
||||
|
|
|
@ -88,6 +88,7 @@ typedef enum dmu_object_type {
|
|||
DMU_OT_SA_MASTER_NODE, /* ZAP */
|
||||
DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */
|
||||
DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */
|
||||
DMU_OT_DSL_KEYCHAIN = 54,
|
||||
DMU_OT_NUMTYPES
|
||||
} dmu_object_type_t;
|
||||
|
||||
|
|
|
@ -42,7 +42,9 @@ typedef struct dsl_dir_phys {
|
|||
grub_uint64_t dd_reserved;
|
||||
grub_uint64_t dd_props_zapobj;
|
||||
grub_uint64_t dd_deleg_zapobj; /* dataset permissions */
|
||||
grub_uint64_t dd_pad[20]; /* pad out to 256 bytes for good measure */
|
||||
grub_uint64_t unused[7];
|
||||
grub_uint64_t keychain;
|
||||
grub_uint64_t unused2[12];
|
||||
} dsl_dir_phys_t;
|
||||
|
||||
#endif /* _SYS_DSL_DIR_H */
|
||||
|
|
|
@ -20,26 +20,24 @@
|
|||
#ifndef GRUB_ZFS_SPA_HEADER
|
||||
#define GRUB_ZFS_SPA_HEADER 1
|
||||
|
||||
typedef enum grub_zfs_endian
|
||||
{
|
||||
UNKNOWN_ENDIAN = -2,
|
||||
LITTLE_ENDIAN = -1,
|
||||
BIG_ENDIAN = 0
|
||||
} grub_zfs_endian_t;
|
||||
|
||||
#define grub_zfs_to_cpu16(x,a) (((a) == BIG_ENDIAN) ? grub_be_to_cpu16(x) \
|
||||
#define grub_zfs_to_cpu16(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \
|
||||
grub_be_to_cpu16(x) \
|
||||
: grub_le_to_cpu16(x))
|
||||
#define grub_cpu_to_zfs16(x,a) (((a) == BIG_ENDIAN) ? grub_cpu_to_be16(x) \
|
||||
#define grub_cpu_to_zfs16(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \
|
||||
grub_cpu_to_be16(x) \
|
||||
: grub_cpu_to_le16(x))
|
||||
|
||||
#define grub_zfs_to_cpu32(x,a) (((a) == BIG_ENDIAN) ? grub_be_to_cpu32(x) \
|
||||
#define grub_zfs_to_cpu32(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \
|
||||
grub_be_to_cpu32(x) \
|
||||
: grub_le_to_cpu32(x))
|
||||
#define grub_cpu_to_zfs32(x,a) (((a) == BIG_ENDIAN) ? grub_cpu_to_be32(x) \
|
||||
#define grub_cpu_to_zfs32(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \
|
||||
grub_cpu_to_be32(x) \
|
||||
: grub_cpu_to_le32(x))
|
||||
|
||||
#define grub_zfs_to_cpu64(x,a) (((a) == BIG_ENDIAN) ? grub_be_to_cpu64(x) \
|
||||
#define grub_zfs_to_cpu64(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) \
|
||||
? grub_be_to_cpu64(x) \
|
||||
: grub_le_to_cpu64(x))
|
||||
#define grub_cpu_to_zfs64(x,a) (((a) == BIG_ENDIAN) ? grub_cpu_to_be64(x) \
|
||||
#define grub_cpu_to_zfs64(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? grub_cpu_to_be64(x) \
|
||||
: grub_cpu_to_le64(x))
|
||||
|
||||
/*
|
||||
|
|
|
@ -24,6 +24,14 @@
|
|||
|
||||
#include <grub/err.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/crypto.h>
|
||||
|
||||
typedef enum grub_zfs_endian
|
||||
{
|
||||
GRUB_ZFS_UNKNOWN_ENDIAN = -2,
|
||||
GRUB_ZFS_LITTLE_ENDIAN = -1,
|
||||
GRUB_ZFS_BIG_ENDIAN = 0
|
||||
} grub_zfs_endian_t;
|
||||
|
||||
/*
|
||||
* On-disk version number.
|
||||
|
@ -121,5 +129,25 @@ char *grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist,
|
|||
grub_size_t index);
|
||||
int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
|
||||
const char *name);
|
||||
grub_err_t
|
||||
grub_zfs_add_key (grub_uint8_t *key_in,
|
||||
grub_size_t keylen,
|
||||
int passphrase);
|
||||
|
||||
extern grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
|
||||
grub_uint64_t algo,
|
||||
void *nonce,
|
||||
char *buf, grub_size_t size,
|
||||
const grub_uint32_t *expected_mac,
|
||||
grub_zfs_endian_t endian);
|
||||
|
||||
struct grub_zfs_key;
|
||||
|
||||
extern grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key,
|
||||
grub_size_t keysize,
|
||||
grub_uint64_t salt,
|
||||
grub_uint64_t algo);
|
||||
|
||||
|
||||
|
||||
#endif /* ! GRUB_ZFS_HEADER */
|
||||
|
|
|
@ -65,6 +65,7 @@ enum zio_checksum {
|
|||
ZIO_CHECKSUM_FLETCHER_4,
|
||||
ZIO_CHECKSUM_SHA256,
|
||||
ZIO_CHECKSUM_ZILOG2,
|
||||
ZIO_CHECKSUM_SHA256_MAC,
|
||||
ZIO_CHECKSUM_FUNCTIONS
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <grub/crypto.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/zfs/zfs.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
@ -438,6 +439,7 @@ static struct argp_option options[] = {
|
|||
{"diskcount", 'c', "N", 0, N_("N input files."), 2},
|
||||
{"debug", 'd', "S", 0, N_("Set debug environment variable."), 2},
|
||||
{"crypto", 'C', NULL, OPTION_ARG_OPTIONAL, N_("Mount crypto devices."), 2},
|
||||
{"zfs-key", 'K', N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2},
|
||||
{"verbose", 'v', NULL, OPTION_ARG_OPTIONAL, N_("Print verbose messages."), 2},
|
||||
{"uncompress", 'u', NULL, OPTION_ARG_OPTIONAL, N_("Uncompress data."), 2},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
|
@ -462,6 +464,38 @@ argp_parser (int key, char *arg, struct argp_state *state)
|
|||
root = arg;
|
||||
return 0;
|
||||
|
||||
case 'K':
|
||||
if (strcmp (arg, "prompt") == 0)
|
||||
{
|
||||
char buf[1024];
|
||||
grub_printf ("Enter ZFS password: ");
|
||||
if (grub_password_get (buf, 1023))
|
||||
{
|
||||
grub_zfs_add_key ((grub_uint8_t *) buf, grub_strlen (buf), 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *f;
|
||||
ssize_t real_size;
|
||||
grub_uint8_t buf[1024];
|
||||
f = fopen (arg, "rb");
|
||||
if (!f)
|
||||
{
|
||||
printf ("Error loading file %s: %s\n", arg, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
real_size = fread (buf, 1, 1024, f);
|
||||
if (real_size < 0)
|
||||
{
|
||||
printf ("Error loading file %s: %s\n", arg, strerror (errno));
|
||||
fclose (f);
|
||||
return 0;
|
||||
}
|
||||
grub_zfs_add_key (buf, real_size, 0);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'C':
|
||||
mount_crypt = 1;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue