* [PATCH 1/2] zfs: Rewrite endianness handling
2025-08-01 14:30 [PATCH 0/2] zfs: Support datto encryption and fix endianness handling Vladimir Serbinenko
@ 2025-08-01 14:30 ` Vladimir Serbinenko
2025-08-01 14:30 ` [PATCH 2/2] zfs: Support datto encryption Vladimir Serbinenko
2025-08-11 13:23 ` [PATCH 0/2] zfs: Support datto encryption and fix endianness handling Neal Gompa
2 siblings, 0 replies; 8+ messages in thread
From: Vladimir Serbinenko @ 2025-08-01 14:30 UTC (permalink / raw)
To: grub-devel; +Cc: Vladimir Serbinenko
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
---
grub-core/fs/zfs/zfs.c | 917 ++++++++++++++++++--------------
grub-core/fs/zfs/zfs_fletcher.c | 18 +-
grub-core/fs/zfs/zfs_sha256.c | 14 +-
grub-core/fs/zfs/zfscrypt.c | 2 +-
include/grub/zfs/sa_impl.h | 1 +
include/grub/zfs/spa.h | 9 +
include/grub/zfs/zfs.h | 10 +-
7 files changed, 551 insertions(+), 420 deletions(-)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index afe821f9b..b88a2b032 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -193,12 +193,6 @@ typedef struct zio_checksum_info {
const char *ci_name; /* descriptive name */
} zio_checksum_info_t;
-typedef struct dnode_end
-{
- dnode_phys_t dn;
- grub_zfs_endian_t endian;
-} dnode_end_t;
-
struct grub_zfs_device_desc
{
enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type;
@@ -223,7 +217,7 @@ struct grub_zfs_device_desc
struct subvolume
{
- dnode_end_t mdn;
+ dnode_phys_t mdn;
grub_uint64_t obj;
grub_uint64_t case_insensitive;
grub_size_t nkeys;
@@ -247,10 +241,9 @@ struct grub_zfs_data
dnode_phys_t *dnode_mdn;
grub_uint64_t dnode_start;
grub_uint64_t dnode_end;
- grub_zfs_endian_t dnode_endian;
- dnode_end_t mos;
- dnode_end_t dnode;
+ dnode_phys_t mos;
+ dnode_phys_t dnode;
struct subvolume subvol;
struct grub_zfs_device_desc *devices_attached;
@@ -273,7 +266,7 @@ struct grub_zfs_dir_ctx
grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
grub_uint64_t algo,
- void *nonce,
+ const void *nonce,
char *buf, grub_size_t size,
const grub_uint32_t *expected_mac,
grub_zfs_endian_t endian) = NULL;
@@ -302,7 +295,7 @@ static const char *spa_feature_names[] = {
static int
check_feature(const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx);
static grub_err_t
-check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data );
+check_mos_features(dnode_phys_t *mosmdn_phys, struct grub_zfs_data* data );
static grub_err_t
zlib_decompress (void *s, void *d,
@@ -404,7 +397,7 @@ static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
{"zstd", zstd_decompress}, /* ZIO_COMPRESS_ZSTD */
};
-static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian,
+static grub_err_t zio_read_data (const blkptr_t * bp,
void *buf, struct grub_zfs_data *data);
/*
@@ -449,6 +442,245 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
{zio_checksum_SHA256, 1, 0, "SHA256+MAC"},
};
+static inline void
+grub_zfs_byteswap_u64(grub_uint64_t *val)
+{
+ *val = grub_swap_bytes64(*val);
+}
+
+static inline void
+grub_zfs_byteswap_u32(grub_uint32_t *val)
+{
+ *val = grub_swap_bytes32(*val);
+}
+
+static inline void
+grub_zfs_byteswap_u16(grub_uint16_t *val)
+{
+ *val = grub_swap_bytes16(*val);
+}
+
+static void
+grub_zfs_byteswap_checksum(zio_cksum_t *csum)
+{
+ for (int i = 0; i < 4; i++)
+ grub_zfs_byteswap_u64(&csum->zc_word[i]);
+}
+
+static void
+grub_zfs_byteswap_blkptr(blkptr_t *bp)
+{
+ for (int i = 0; i < SPA_DVAS_PER_BP; i++)
+ {
+ grub_zfs_byteswap_u64(&bp->blk_dva[i].dva_word[0]);
+ grub_zfs_byteswap_u64(&bp->blk_dva[i].dva_word[1]);
+ }
+ grub_zfs_byteswap_u64(&bp->blk_prop);
+ grub_zfs_byteswap_u64(&bp->blk_pad[0]);
+ grub_zfs_byteswap_u64(&bp->blk_pad[1]);
+ grub_zfs_byteswap_u64(&bp->blk_phys_birth);
+ grub_zfs_byteswap_u64(&bp->blk_birth);
+ grub_zfs_byteswap_u64(&bp->blk_fill);
+
+ grub_zfs_byteswap_checksum(&bp->blk_cksum);
+}
+
+static void
+grub_zfs_byteswap_uberblock(uberblock_t *ub)
+{
+ grub_zfs_byteswap_u64(&ub->ub_magic);
+ grub_zfs_byteswap_u64(&ub->ub_version);
+ grub_zfs_byteswap_u64(&ub->ub_txg);
+ grub_zfs_byteswap_u64(&ub->ub_guid_sum);
+ grub_zfs_byteswap_u64(&ub->ub_timestamp);
+ grub_zfs_byteswap_blkptr(&ub->ub_rootbp);
+}
+
+static void
+grub_zfs_byteswap_type(void *buf, grub_size_t len, grub_uint8_t type);
+
+static void
+grub_zfs_byteswap_dnode_proper(dnode_phys_t *dn)
+{
+ grub_zfs_byteswap_u16(&dn->dn_datablkszsec);
+ grub_zfs_byteswap_u16(&dn->dn_bonuslen);
+ grub_zfs_byteswap_u64(&dn->dn_maxblkid);
+ grub_zfs_byteswap_u64(&dn->dn_used);
+ grub_zfs_byteswap_u64(&dn->dn_pad3[0]);
+ grub_zfs_byteswap_u64(&dn->dn_pad3[1]);
+ grub_zfs_byteswap_u64(&dn->dn_pad3[2]);
+ grub_zfs_byteswap_u64(&dn->dn_pad3[3]);
+
+ for (unsigned i = 0; i < dn->dn_nblkptr; i++)
+ grub_zfs_byteswap_blkptr(&dn->dn_blkptr[i]);
+
+ if (dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR)
+ grub_zfs_byteswap_blkptr(&dn->dn_spill);
+}
+
+static void
+grub_zfs_byteswap_dnode(dnode_phys_t *dn)
+{
+ grub_zfs_byteswap_dnode_proper(dn);
+ grub_zfs_byteswap_type(dn->dn_bonus, dn->dn_bonuslen, dn->dn_bonustype);
+}
+
+static void
+grub_zfs_byteswap_objset(objset_phys_t *os)
+{
+ grub_zfs_byteswap_dnode(&os->os_meta_dnode);
+ /* We ignore ZIL header. */
+ grub_zfs_byteswap_u64(&os->os_type);
+ grub_zfs_byteswap_u64(&os->os_flags);
+ grub_zfs_byteswap_dnode(&os->os_userused_dnode);
+ grub_zfs_byteswap_dnode(&os->os_groupused_dnode);
+}
+
+static void
+grub_zfs_byteswap_u64_array(grub_uint64_t *arr, grub_size_t len)
+{
+ for (unsigned i = 0; i < len / 8; i++)
+ grub_zfs_byteswap_u64(arr + i);
+}
+
+static void
+grub_zfs_byteswap_mzap(mzap_phys_t *mz, grub_size_t objsize)
+{
+ grub_zfs_byteswap_u64(&mz->mz_block_type);
+ grub_zfs_byteswap_u64(&mz->mz_salt);
+ for (unsigned i = 0; i < 6; i++)
+ grub_zfs_byteswap_u64(&mz->mz_pad[i]);
+ for (unsigned i = 0; i < objsize / MZAP_ENT_LEN - 1; i++)
+ {
+ grub_zfs_byteswap_u64(&mz->mz_chunk[i].mze_value);
+ grub_zfs_byteswap_u32(&mz->mz_chunk[i].mze_cd);
+ grub_zfs_byteswap_u16(&mz->mz_chunk[i].mze_pad);
+ }
+}
+
+static void
+grub_zfs_byteswap_zap_leaf(zap_leaf_phys_t *lf, grub_size_t len)
+{
+ int blksft = zfs_log2 (len);
+
+ grub_zfs_byteswap_u64(&lf->l_hdr.lh_block_type);
+ grub_zfs_byteswap_u64(&lf->l_hdr.lh_prefix);
+ grub_zfs_byteswap_u32(&lf->l_hdr.lh_magic);
+ grub_zfs_byteswap_u16(&lf->l_hdr.lh_nfree);
+ grub_zfs_byteswap_u16(&lf->l_hdr.lh_nentries);
+ grub_zfs_byteswap_u16(&lf->l_hdr.lh_prefix_len);
+ grub_zfs_byteswap_u16(&lf->l_hdr.lh_freelist);
+
+ for (int i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(blksft); i++)
+ grub_zfs_byteswap_u16(&lf->l_hash[i]);
+
+ for (int i = 0; i < ZAP_LEAF_NUMCHUNKS (blksft); i++) {
+ zap_leaf_chunk_t *lc = ZAP_LEAF_CHUNK(lf, blksft, i);
+ struct zap_leaf_entry *le;
+
+ switch (lc->l_free.lf_type) {
+ case ZAP_CHUNK_ENTRY:
+ le = &lc->l_entry;
+
+ grub_zfs_byteswap_u16(&le->le_next);
+ grub_zfs_byteswap_u16(&le->le_name_chunk);
+ grub_zfs_byteswap_u16(&le->le_name_length);
+ grub_zfs_byteswap_u16(&le->le_value_chunk);
+ grub_zfs_byteswap_u16(&le->le_value_length);
+ grub_zfs_byteswap_u32(&le->le_cd);
+ grub_zfs_byteswap_u64(&le->le_hash);
+ break;
+ case ZAP_CHUNK_FREE:
+ grub_zfs_byteswap_u16(&lc->l_free.lf_next);
+ break;
+ case ZAP_CHUNK_ARRAY:
+ grub_zfs_byteswap_u16(&lc->l_array.la_next);
+ break;
+ default:
+ grub_dprintf("zfs", "Unknown leaf type %d\n", lc->l_free.lf_type);
+ }
+ }
+}
+
+static void
+grub_zfs_byteswap_zap(void *zp, grub_size_t len)
+{
+ grub_uint64_t block_type = *(grub_uint64_t *) zp;
+ if (block_type == grub_swap_bytes64_compile_time(ZBT_MICRO))
+ grub_zfs_byteswap_mzap(zp, len);
+ else if (block_type == grub_swap_bytes64_compile_time(ZBT_HEADER))
+ grub_zfs_byteswap_u64_array(zp, len);
+ else if (block_type == grub_swap_bytes64_compile_time(ZBT_LEAF))
+ grub_zfs_byteswap_zap_leaf(zp, len);
+ else
+ grub_dprintf ("zfs", "unknown ZAP type");
+}
+
+static const dmu_object_byteswap_t byteswap_table[] = {
+ DMU_BSWAP_UINT8, DMU_BSWAP_ZAP, DMU_BSWAP_UINT64, DMU_BSWAP_UINT8,
+ DMU_BSWAP_UINT64, DMU_BSWAP_UINT64, DMU_BSWAP_UINT64, DMU_BSWAP_UINT64,
+ DMU_BSWAP_UINT64, DMU_BSWAP_UINT64, DMU_BSWAP_DNODE, DMU_BSWAP_OBJSET,
+ DMU_BSWAP_UINT64, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP,
+
+ DMU_BSWAP_UINT64, DMU_BSWAP_ZNODE, DMU_BSWAP_OLDACL, DMU_BSWAP_UINT8,
+ DMU_BSWAP_ZAP, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP, DMU_BSWAP_UINT8,
+ DMU_BSWAP_ZAP, DMU_BSWAP_UINT8, DMU_BSWAP_UINT64, DMU_BSWAP_ZAP,
+ DMU_BSWAP_ZAP, DMU_BSWAP_UINT8, DMU_BSWAP_UINT64, DMU_BSWAP_ZAP,
+
+ DMU_BSWAP_ZAP, DMU_BSWAP_ACL, DMU_BSWAP_UINT8, DMU_BSWAP_UINT8,
+ DMU_BSWAP_UINT64, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP,
+ DMU_BSWAP_ZAP, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP,
+ DMU_BSWAP_UINT8, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP, DMU_BSWAP_ZAP,
+
+ DMU_BSWAP_ZAP, DMU_BSWAP_UINT8, DMU_BSWAP_ZAP, DMU_BSWAP_UINT64,
+ DMU_BSWAP_ZAP, DMU_BSWAP_UINT64,
+};
+
+static dmu_object_byteswap_t
+get_byteswap_type(grub_uint8_t type)
+{
+ if (type & 0x80)
+ return type & DMU_OT_BYTESWAP_MASK;
+
+ if (type < ARRAY_SIZE (byteswap_table))
+ return byteswap_table[type];
+ grub_fatal("Unknown type %d", type);
+}
+
+static void
+grub_zfs_byteswap_type(void *buf, grub_size_t len, grub_uint8_t type)
+{
+ /*
+ DMU_BSWAP_UINT16,
+ DMU_BSWAP_UINT32,
+ DMU_BSWAP_ZNODE,
+ DMU_BSWAP_OLDACL,
+ DMU_BSWAP_ACL,
+
+ */
+ switch (get_byteswap_type(type))
+ {
+ case DMU_BSWAP_UINT8:
+ break;
+ case DMU_BSWAP_DNODE:
+ for (unsigned i = 0; i < len / sizeof(dnode_phys_t); i++)
+ grub_zfs_byteswap_dnode((dnode_phys_t *)buf + i);
+ break;
+ case DMU_BSWAP_OBJSET:
+ for (unsigned i = 0; i < len / sizeof(objset_phys_t); i++)
+ grub_zfs_byteswap_objset((objset_phys_t *)buf + i);
+ break;
+ case DMU_BSWAP_ZAP:
+ grub_zfs_byteswap_zap(buf, len);
+ break;
+ case DMU_BSWAP_UINT64:
+ grub_zfs_byteswap_u64_array(buf, len);
+ break;
+ default:
+ grub_fatal("Unknown type %d", type);
+ }
+}
+
/*
* zio_checksum_verify: Provides support for checksum verification.
*
@@ -482,8 +714,12 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
else
ci->ci_func (buf, size, endian, &actual_cksum);
- if (grub_memcmp (&actual_cksum, &zc,
- checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20) != 0)
+ int cksumlen = checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20;
+
+ if (ci->ci_eck && !GRUB_ZFS_IS_NATIVE_BYTEORDER(endian))
+ grub_zfs_byteswap_checksum(&actual_cksum);
+
+ if (grub_memcmp (&actual_cksum, &zc, cksumlen) != 0)
{
grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name);
grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n",
@@ -515,30 +751,14 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
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, GRUB_ZFS_LITTLE_ENDIAN)
- == UBERBLOCK_MAGIC)
- ub1_endian = GRUB_ZFS_LITTLE_ENDIAN;
- else
- 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 = GRUB_ZFS_BIG_ENDIAN;
-
- if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian)
- < grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian))
+ if (ub1->ub_txg < ub2->ub_txg)
return -1;
- if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian)
- > grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian))
+ if (ub1->ub_txg > ub2->ub_txg)
return 1;
- if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian)
- < grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian))
+ if (ub1->ub_timestamp < ub2->ub_timestamp)
return -1;
- if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian)
- > grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian))
+ if (ub1->ub_timestamp > ub2->ub_timestamp)
return 1;
return 0;
@@ -615,34 +835,27 @@ find_bestub (uberblock_phys_t * ub_array,
grub_errno = GRUB_ERR_NONE;
continue;
}
+
+ if (ubptr->ubp_uberblock.ub_magic == grub_swap_bytes64_compile_time(UBERBLOCK_MAGIC))
+ grub_zfs_byteswap_uberblock(&ubptr->ubp_uberblock);
+
if (ubbest == NULL
|| vdev_uberblock_compare (&(ubptr->ubp_uberblock),
&(ubbest->ubp_uberblock)) > 0)
ubbest = ubptr;
}
- if (!ubbest)
+ if (!ubbest) {
grub_errno = err;
+ grub_dprintf("zfs", "no valid ub found. vdev_pys_sector=%lld\n",
+ (long long)desc->vdev_phys_sector);
+ } else {
+ grub_dprintf("zfs", "valid ub found. vdev_pys_sector=%lld\n",
+ (long long)desc->vdev_phys_sector);
+ }
return ubbest;
}
-static inline grub_size_t
-get_psize (blkptr_t * bp, grub_zfs_endian_t endian)
-{
- return ((((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) >> 16) & 0xffff) + 1)
- << SPA_MINBLOCKSHIFT);
-}
-
-static grub_uint64_t
-dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian)
-{
- grub_dprintf ("zfs", "dva=%llx, %llx\n",
- (unsigned long long) dva->dva_word[0],
- (unsigned long long) dva->dva_word[1]);
- return grub_zfs_to_cpu64 ((dva)->dva_word[1],
- endian) << SPA_MINBLOCKSHIFT;
-}
-
static grub_err_t
zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist)
{
@@ -1054,7 +1267,7 @@ check_pool_label (struct grub_zfs_data *data,
"bad vdev_phys_t.vp_zbt.zec_magic number");
}
/* Now check the integrity of the vdev_phys_t structure though checksum. */
- ZIO_SET_CHECKSUM(&emptycksum, diskdesc->vdev_phys_sector << 9, 0, 0, 0);
+ ZIO_SET_CHECKSUM(&emptycksum, grub_cpu_to_zfs64(diskdesc->vdev_phys_sector << 9, endian), 0, 0, 0);
err = zio_checksum_verify (emptycksum, ZIO_CHECKSUM_LABEL, endian,
nvlist, VDEV_PHYS_SIZE);
if (err) {
@@ -1743,14 +1956,14 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
static grub_err_t
read_dva (const dva_t *dva,
- grub_zfs_endian_t endian, struct grub_zfs_data *data,
+ struct grub_zfs_data *data,
void *buf, grub_size_t len)
{
grub_uint64_t offset;
unsigned i;
grub_err_t err = 0;
int try = 0;
- offset = dva_get_offset (dva, endian);
+ offset = DVA_GET_OFFSET(dva);
for (try = 0; try < 2; try++)
{
@@ -1780,7 +1993,7 @@ read_dva (const dva_t *dva,
*
*/
static grub_err_t
-zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
+zio_read_gang (const blkptr_t * bp, const dva_t * dva, void *buf,
struct grub_zfs_data *data)
{
zio_gbh_phys_t *zio_gb;
@@ -1793,10 +2006,8 @@ 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 == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n"
- :"big-endian gang\n");
- err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE);
+ err = read_dva (dva, data, zio_gb, SPA_GANGBLOCKSIZE);
if (err)
{
grub_free (zio_gb);
@@ -1806,8 +2017,8 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
/* XXX */
/* self checksuming the gang block header */
ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV (dva),
- dva_get_offset (dva, endian), bp->blk_birth, 0);
- err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER, endian,
+ DVA_GET_OFFSET (dva), bp->blk_birth, 0);
+ err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER, BP_GET_BYTEORDER(bp),
(char *) zio_gb, SPA_GANGBLOCKSIZE);
if (err)
{
@@ -1815,20 +2026,22 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
return err;
}
- endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(BP_GET_BYTEORDER(bp)))
+ for (i = 0; i < SPA_GBH_NBLKPTRS; i++)
+ grub_zfs_byteswap_blkptr(&zio_gb->zg_blkptr[i]);
for (i = 0; i < SPA_GBH_NBLKPTRS; i++)
{
if (BP_IS_HOLE(&zio_gb->zg_blkptr[i]))
continue;
- err = zio_read_data (&zio_gb->zg_blkptr[i], endian, buf, data);
+ err = zio_read_data (&zio_gb->zg_blkptr[i], buf, data);
if (err)
{
grub_free (zio_gb);
return err;
}
- buf = (char *) buf + get_psize (&zio_gb->zg_blkptr[i], endian);
+ buf = (char *) buf + BP_GET_PSIZE(&zio_gb->zg_blkptr[i]);
}
grub_free (zio_gb);
return GRUB_ERR_NONE;
@@ -1838,13 +2051,12 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
* Read in a block of raw data to buf.
*/
static grub_err_t
-zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf,
- struct grub_zfs_data *data)
+zio_read_data (const blkptr_t * bp, void *buf, struct grub_zfs_data *data)
{
int i, psize;
grub_err_t err = GRUB_ERR_NONE;
- psize = get_psize (bp, endian);
+ psize = BP_GET_PSIZE (bp);
/* pick a good dva from the block pointer */
for (i = 0; i < SPA_DVAS_PER_BP; i++)
@@ -1852,10 +2064,10 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf,
if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0)
continue;
- if ((grub_zfs_to_cpu64 (bp->blk_dva[i].dva_word[1], endian)>>63) & 1)
- err = zio_read_gang (bp, endian, &bp->blk_dva[i], buf, data);
+ if (DVA_GET_GANG(&bp->blk_dva[i]))
+ err = zio_read_gang (bp, &bp->blk_dva[i], buf, data);
else
- err = read_dva (&bp->blk_dva[i], endian, data, buf, psize);
+ err = read_dva (&bp->blk_dva[i], data, buf, psize);
if (!err)
return GRUB_ERR_NONE;
grub_errno = GRUB_ERR_NONE;
@@ -1906,7 +2118,7 @@ decode_embedded_bp_compressed(const blkptr_t *bp, 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 (const blkptr_t *bp, void **buf,
grub_size_t *size, struct grub_zfs_data *data)
{
grub_size_t lsize, psize;
@@ -1918,9 +2130,9 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
*buf = NULL;
- checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff;
- comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0x7f;
- encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3);
+ checksum = BP_GET_CHECKSUM(bp);
+ comp = BP_GET_COMPRESS(bp);
+ encrypted = BP_GET_PROP_BIT_61(bp);
if (BP_IS_EMBEDDED(bp))
{
if (BPE_GET_ETYPE(bp) != BP_EMBEDDED_TYPE_DATA)
@@ -1929,14 +2141,12 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
PRIuGRUB_UINT64_T ")\n",
BPE_GET_ETYPE (bp));
lsize = BPE_GET_LSIZE(bp);
- psize = BF64_GET_SB(grub_zfs_to_cpu64 ((bp)->blk_prop, endian), 25, 7, 0, 1);
+ psize = BPE_GET_PSIZE(bp);
}
else
{
- lsize = (BP_IS_HOLE(bp) ? 0 :
- (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
- << SPA_MINBLOCKSHIFT));
- psize = get_psize (bp, endian);
+ lsize = (BP_IS_HOLE(bp) ? 0 : BP_GET_LSIZE(bp));
+ psize = BP_GET_PSIZE(bp);
}
grub_dprintf("zfs", "zio_read: E %d: size %" PRIdGRUB_SSIZE "/%"
PRIdGRUB_SSIZE "\n", (int)BP_IS_EMBEDDED(bp), lsize, psize);
@@ -1960,12 +2170,11 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
if (! compbuf)
return grub_errno;
- grub_dprintf ("zfs", "endian = %d\n", endian);
if (BP_IS_EMBEDDED(bp))
err = decode_embedded_bp_compressed(bp, compbuf);
else
{
- err = zio_read_data (bp, endian, compbuf, data);
+ err = zio_read_data (bp, compbuf, data);
/* FIXME is it really necessary? */
if (comp != ZIO_COMPRESS_OFF)
grub_memset (compbuf + psize, 0, ALIGN_UP (psize, 16) - psize);
@@ -1979,7 +2188,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
if (!BP_IS_EMBEDDED(bp))
{
- err = zio_checksum_verify (zc, checksum, endian,
+ err = zio_checksum_verify (zc, checksum, BP_GET_BYTEORDER(bp),
compbuf, psize);
if (err)
{
@@ -2001,8 +2210,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
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)
+ if (data->subvol.keyring[i].txg <= bp->blk_birth
&& data->subvol.keyring[i].txg > bestval)
{
besti = i;
@@ -2013,21 +2221,19 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
grub_free (compbuf);
*buf = NULL;
grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
- grub_zfs_to_cpu64 (bp->blk_birth,
- endian));
+ bp->blk_birth);
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));
+ bp->blk_birth);
err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
data->subvol.keyring[besti].algo,
- &(bp)->blk_dva[encrypted],
+ &(bp)->blk_dva[2],
compbuf, psize, zc.zc_mac,
- endian);
+ BP_GET_BYTEORDER(bp));
}
if (err)
{
@@ -2056,6 +2262,17 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
}
}
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(BP_GET_BYTEORDER(bp)))
+ {
+ if (BP_GET_LEVEL(bp) > 0)
+ {
+ for (unsigned i = 0; i < lsize / sizeof(blkptr_t); i++)
+ grub_zfs_byteswap_blkptr((blkptr_t *)*buf + i);
+ }
+ else
+ grub_zfs_byteswap_type(*buf, lsize, BP_GET_TYPE(bp));
+ }
+
return GRUB_ERR_NONE;
}
@@ -2065,29 +2282,28 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
*
*/
static grub_err_t
-dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
- grub_zfs_endian_t *endian_out, struct grub_zfs_data *data)
+dmu_read (dnode_phys_t * dn, grub_uint64_t blkid, void **buf,
+ struct grub_zfs_data *data)
{
int level;
grub_off_t idx;
- blkptr_t *bp_array = dn->dn.dn_blkptr;
- int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT;
+ blkptr_t *bp_array = dn->dn_blkptr;
+ int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
blkptr_t *bp;
void *tmpbuf = 0;
- grub_zfs_endian_t endian;
grub_err_t err = GRUB_ERR_NONE;
bp = grub_malloc (sizeof (blkptr_t));
if (!bp)
return grub_errno;
- endian = dn->endian;
- for (level = dn->dn.dn_nlevels - 1; level >= 0; level--)
+ *buf = NULL;
+
+ for (level = dn->dn_nlevels - 1; level >= 0; level--)
{
- grub_dprintf ("zfs", "endian = %d\n", endian);
idx = (blkid >> (epbs * level)) & ((1 << epbs) - 1);
*bp = bp_array[idx];
- if (bp_array != dn->dn.dn_blkptr)
+ if (bp_array != dn->dn_blkptr)
{
grub_free (bp_array);
bp_array = 0;
@@ -2095,8 +2311,7 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
if (BP_IS_HOLE (bp))
{
- grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec,
- dn->endian)
+ grub_size_t size = dn->dn_datablkszsec
<< SPA_MINBLOCKSHIFT;
*buf = grub_malloc (size);
if (!*buf)
@@ -2105,27 +2320,20 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
break;
}
grub_memset (*buf, 0, size);
- endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
break;
}
if (level == 0)
{
- grub_dprintf ("zfs", "endian = %d\n", endian);
- err = zio_read (bp, endian, buf, 0, data);
- endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
+ err = zio_read (bp, buf, 0, data);
break;
}
- grub_dprintf ("zfs", "endian = %d\n", endian);
- err = zio_read (bp, endian, &tmpbuf, 0, data);
- endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
+ err = zio_read (bp, &tmpbuf, 0, data);
if (err)
break;
bp_array = tmpbuf;
}
- if (bp_array != dn->dn.dn_blkptr)
+ if (bp_array != dn->dn_blkptr)
grub_free (bp_array);
- if (endian_out)
- *endian_out = endian;
grub_free (bp);
return err;
@@ -2136,7 +2344,7 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
* in "value".
*/
static grub_err_t
-mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
+mzap_lookup (mzap_phys_t * zapobj,
grub_uint32_t objsize, const char *name, grub_uint64_t * value,
int case_insensitive)
{
@@ -2151,7 +2359,7 @@ mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
if (case_insensitive ? (grub_strcasecmp (mzap_ent[i].mze_name, name) == 0)
: (grub_strcmp (mzap_ent[i].mze_name, name) == 0))
{
- *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
+ *value = mzap_ent[i].mze_value;
return GRUB_ERR_NONE;
}
}
@@ -2160,7 +2368,7 @@ mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
}
static int
-mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize,
+mzap_iterate (mzap_phys_t * zapobj, int objsize,
int (*hook) (const char *name, grub_uint64_t val,
struct grub_zfs_dir_ctx *ctx),
struct grub_zfs_dir_ctx *ctx)
@@ -2174,8 +2382,7 @@ mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize,
grub_dprintf ("zfs", "zap: name = %s, value = %llx, cd = %x\n",
mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value,
(int)mzap_ent[i].mze_cd);
- if (hook (mzap_ent[i].mze_name,
- grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian), ctx))
+ if (hook (mzap_ent[i].mze_name, mzap_ent[i].mze_value, ctx))
return 1;
}
@@ -2250,7 +2457,7 @@ name_cmp (const char *s1, const char *s2, grub_size_t n,
/* XXX */
static int
-zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
+zap_leaf_array_equal (zap_leaf_phys_t * l,
int blksft, int chunk, grub_size_t array_len,
const char *buf, int case_insensitive)
{
@@ -2270,7 +2477,7 @@ zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
if (name_cmp ((char *) la->la_array, buf + bseen, toread,
case_insensitive) != 0)
break;
- chunk = grub_zfs_to_cpu16 (la->la_next, endian);
+ chunk = la->la_next;
bseen += toread;
}
return (bseen == array_len);
@@ -2278,7 +2485,7 @@ zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
/* XXX */
static grub_err_t
-zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft,
+zap_leaf_array_get (zap_leaf_phys_t * l, int blksft,
int chunk, grub_size_t array_len, char *buf)
{
grub_size_t bseen = 0;
@@ -2297,7 +2504,7 @@ zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft,
la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array;
grub_memcpy (buf + bseen,la->la_array, toread);
- chunk = grub_zfs_to_cpu16 (la->la_next, endian);
+ chunk = la->la_next;
bseen += toread;
}
return GRUB_ERR_NONE;
@@ -2311,7 +2518,7 @@ zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft,
*/
/* XXX */
static grub_err_t
-zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
+zap_leaf_lookup (zap_leaf_phys_t * l,
int blksft, grub_uint64_t h,
const char *name, grub_uint64_t * value,
int case_insensitive)
@@ -2320,13 +2527,13 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
struct zap_leaf_entry *le;
/* Verify if this is a valid leaf block */
- if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF)
+ if (l->l_hdr.lh_block_type != ZBT_LEAF)
return grub_error (GRUB_ERR_BAD_FS, "invalid leaf type");
- if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC)
+ if (l->l_hdr.lh_magic != ZAP_LEAF_MAGIC)
return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic");
- for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h, l)], endian);
- chunk != CHAIN_END; chunk = grub_zfs_to_cpu16 (le->le_next, endian))
+ for (chunk = l->l_hash[LEAF_HASH (blksft, h, l)];
+ chunk != CHAIN_END; chunk = le->le_next)
{
if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
@@ -2338,20 +2545,19 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
if (le->le_type != ZAP_CHUNK_ENTRY)
return grub_error (GRUB_ERR_BAD_FS, "invalid chunk entry");
- if (grub_zfs_to_cpu64 (le->le_hash,endian) != h)
+ if (le->le_hash != h)
continue;
grub_dprintf ("zfs", "fzap: length %d\n", (int) le->le_name_length);
- if (zap_leaf_array_equal (l, endian, blksft,
- grub_zfs_to_cpu16 (le->le_name_chunk,endian),
- grub_zfs_to_cpu16 (le->le_name_length, endian),
+ if (zap_leaf_array_equal (l, blksft,
+ le->le_name_chunk,
+ le->le_name_length,
name, case_insensitive))
{
struct zap_leaf_array *la;
- if (le->le_int_size != 8 || grub_zfs_to_cpu16 (le->le_value_length,
- endian) != 1)
+ if (le->le_int_size != 8 || le->le_value_length != 1)
return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry");
/* get the uint64_t property value */
@@ -2369,9 +2575,9 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
/* Verify if this is a fat zap header block */
static grub_err_t
-zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
+zap_verify (zap_phys_t *zap)
{
- if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC)
+ if (zap->zap_magic != (grub_uint64_t) ZAP_MAGIC)
return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic");
if (zap->zap_salt == 0)
@@ -2386,18 +2592,16 @@ zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
*/
/* XXX */
static grub_err_t
-fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
+fzap_lookup (dnode_phys_t * zap_dnode, zap_phys_t * zap,
const char *name, grub_uint64_t * value,
struct grub_zfs_data *data, int case_insensitive)
{
void *l;
grub_uint64_t hash, idx, blkid;
- int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
- zap_dnode->endian) << DNODE_SHIFT);
+ int blksft = zfs_log2 (zap_dnode->dn_datablkszsec) + DNODE_SHIFT;
grub_err_t err;
- grub_zfs_endian_t leafendian;
- err = zap_verify (zap, zap_dnode->endian);
+ err = zap_verify (zap);
if (err)
return err;
@@ -2408,16 +2612,16 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"external pointer tables not supported");
idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift);
- blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian);
+ blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))];
/* Get the leaf block */
if ((1U << blksft) < sizeof (zap_leaf_phys_t))
return grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
- err = dmu_read (zap_dnode, blkid, &l, &leafendian, data);
+ err = dmu_read (zap_dnode, blkid, &l, data);
if (err)
return err;
- err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value,
+ err = zap_leaf_lookup (l, blksft, hash, name, value,
case_insensitive);
grub_free (l);
return err;
@@ -2425,7 +2629,7 @@ 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,
+fzap_iterate (dnode_phys_t * zap_dnode, zap_phys_t * zap,
grub_size_t name_elem_length,
int (*hook) (const void *name, grub_size_t name_length,
const void *val_in,
@@ -2437,13 +2641,11 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
void *l_in;
grub_uint64_t idx, idx2, blkid;
grub_uint16_t chunk;
- int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
- zap_dnode->endian) << DNODE_SHIFT);
+ int blksft = zfs_log2 (zap_dnode->dn_datablkszsec) + DNODE_SHIFT;
grub_err_t err;
- grub_zfs_endian_t endian;
grub_size_t sz;
- if (zap_verify (zap, zap_dnode->endian))
+ if (zap_verify (zap))
return 0;
/* get block id from index */
@@ -2461,17 +2663,15 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
}
for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++)
{
- blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))],
- zap_dnode->endian);
+ blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))];
for (idx2 = 0; idx2 < idx; idx2++)
- if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))],
- zap_dnode->endian))
+ if (blkid == ((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))])
break;
if (idx2 != idx)
continue;
- err = dmu_read (zap_dnode, blkid, &l_in, &endian, data);
+ err = dmu_read (zap_dnode, blkid, &l_in, data);
l = l_in;
if (err)
{
@@ -2480,12 +2680,12 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
}
/* Verify if this is a valid leaf block */
- if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF)
+ if (l->l_hdr.lh_block_type != ZBT_LEAF)
{
grub_free (l);
continue;
}
- if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC)
+ if (l->l_hdr.lh_magic != ZAP_LEAF_MAGIC)
{
grub_free (l);
continue;
@@ -2503,7 +2703,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
if (le->le_type != ZAP_CHUNK_ENTRY)
continue;
- if (grub_mul (grub_zfs_to_cpu16 (le->le_name_length, endian), name_elem_length, &sz) ||
+ if (grub_mul (le->le_name_length, name_elem_length, &sz) ||
grub_add (sz, 1, &sz))
{
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow"));
@@ -2516,11 +2716,9 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
grub_free (l);
return grub_errno;
}
- 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)
+ if (zap_leaf_array_get (l, blksft,
+ le->le_name_chunk,
+ le->le_name_length
* name_elem_length, buf))
{
grub_free (buf);
@@ -2530,16 +2728,15 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
val_length = ((int) le->le_value_length
* (int) le->le_int_size);
- val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian));
+ val = grub_malloc (val_length);
if (!val)
{
grub_free (l);
grub_free (buf);
return grub_errno;
}
- if (zap_leaf_array_get (l, endian, blksft,
- grub_zfs_to_cpu16 (le->le_value_chunk,
- endian),
+ if (zap_leaf_array_get (l, blksft,
+ le->le_value_chunk,
val_length, val))
{
grub_free (buf);
@@ -2567,32 +2764,29 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
*
*/
static grub_err_t
-zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val,
+zap_lookup (dnode_phys_t * zap_dnode, const char *name, grub_uint64_t *val,
struct grub_zfs_data *data, int case_insensitive)
{
grub_uint64_t block_type;
grub_uint32_t size;
void *zapbuf;
grub_err_t err;
- grub_zfs_endian_t endian;
grub_dprintf ("zfs", "looking for '%s'\n", name);
/* Read in the first block of the zap object data. */
- size = (grub_uint32_t) grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
- zap_dnode->endian) << SPA_MINBLOCKSHIFT;
- err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
+ size = (grub_uint32_t) zap_dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
+ err = dmu_read (zap_dnode, 0, &zapbuf, data);
if (err)
return err;
- block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
+ block_type = *((grub_uint64_t *) zapbuf);
grub_dprintf ("zfs", "zap read\n");
if (block_type == ZBT_MICRO)
{
grub_dprintf ("zfs", "micro zap\n");
- err = mzap_lookup (zapbuf, endian, size, name, val,
- case_insensitive);
+ err = mzap_lookup (zapbuf, size, name, val, case_insensitive);
grub_dprintf ("zfs", "returned %d\n", err);
grub_free (zapbuf);
return err;
@@ -2637,7 +2831,7 @@ zap_iterate_u64_transform (const void *name,
}
static int
-zap_iterate_u64 (dnode_end_t * zap_dnode,
+zap_iterate_u64 (dnode_phys_t * zap_dnode,
int (*hook) (const char *name, grub_uint64_t val,
struct grub_zfs_dir_ctx *ctx),
struct grub_zfs_data *data, struct grub_zfs_dir_ctx *ctx)
@@ -2647,21 +2841,20 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
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);
+ size = zap_dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
+ err = dmu_read (zap_dnode, 0, &zapbuf, data);
if (err)
return 0;
- block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
+ block_type = *((grub_uint64_t *) zapbuf);
grub_dprintf ("zfs", "zap iterate\n");
if (block_type == ZBT_MICRO)
{
grub_dprintf ("zfs", "micro zap\n");
- ret = mzap_iterate (zapbuf, endian, size, hook, ctx);
+ ret = mzap_iterate (zapbuf, size, hook, ctx);
grub_free (zapbuf);
return ret;
}
@@ -2685,7 +2878,7 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
}
static int
-zap_iterate (dnode_end_t * zap_dnode,
+zap_iterate (dnode_phys_t * zap_dnode,
grub_size_t nameelemlen,
int (*hook) (const void *name, grub_size_t namelen,
const void *val_in,
@@ -2697,13 +2890,12 @@ zap_iterate (dnode_end_t * zap_dnode,
void *zapbuf;
grub_err_t err;
int ret;
- grub_zfs_endian_t endian;
/* Read in the first block of the zap object data. */
- err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
+ err = dmu_read (zap_dnode, 0, &zapbuf, data);
if (err)
return 0;
- block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
+ block_type = *((grub_uint64_t *) zapbuf);
grub_dprintf ("zfs", "zap iterate\n");
@@ -2737,20 +2929,18 @@ zap_iterate (dnode_end_t * zap_dnode,
* buf - data buffer that holds the returning dnode
*/
static grub_err_t
-dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
- dnode_end_t * buf, struct grub_zfs_data *data)
+dnode_get (dnode_phys_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
+ dnode_phys_t * buf, struct grub_zfs_data *data)
{
grub_uint64_t blkid, blksz; /* the block id this object dnode is in */
int epbs; /* shift of number of dnodes in a block */
int idx; /* index within a block */
void *dnbuf;
grub_err_t err;
- grub_zfs_endian_t endian;
objnum &= DNODE_NUM_MASK;
- blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec,
- mdn->endian) << SPA_MINBLOCKSHIFT;
+ blksz = mdn->dn_datablkszsec << SPA_MINBLOCKSHIFT;
epbs = zfs_log2 (blksz) - DNODE_SHIFT;
/* While this should never happen, we should check that epbs is not negative. */
@@ -2760,22 +2950,23 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
blkid = objnum >> epbs;
idx = objnum & ((1 << epbs) - 1);
- if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, &mdn->dn,
- sizeof (mdn->dn)) == 0
+ if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn,
+ sizeof (*mdn)) == 0
&& objnum >= data->dnode_start && objnum < data->dnode_end)
{
- grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE);
- buf->endian = data->dnode_endian;
- if (type && buf->dn.dn_type != type)
+ *buf = (data->dnode_buf)[idx];
+ if (type && buf->dn_type != type)
return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type");
return GRUB_ERR_NONE;
}
- grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian,
+ grub_dprintf ("zfs", "blkid=%llx\n",
(unsigned long long) blkid);
- err = dmu_read (mdn, blkid, &dnbuf, &endian, data);
+ err = dmu_read (mdn, blkid, &dnbuf, data);
if (err)
return err;
+ if (dnbuf == NULL)
+ return grub_error(GRUB_ERR_BAD_FS, "invalid or unavailable dnode");
grub_dprintf ("zfs", "alive\n");
grub_free (data->dnode_buf);
@@ -2792,15 +2983,10 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
data->dnode_buf = dnbuf;
data->dnode_start = blkid << epbs;
data->dnode_end = (blkid + 1) << epbs;
- data->dnode_endian = endian;
}
- grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE);
- if (data->dnode_buf == 0)
- /* dnbuf not used anymore if data->dnode_mdn malloc failed */
- grub_free (dnbuf);
- buf->endian = endian;
- if (type && buf->dn.dn_type != type)
+ *buf = ((dnode_phys_t *) dnbuf)[idx];
+ if (type && buf->dn_type != type)
return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type");
return GRUB_ERR_NONE;
@@ -2815,7 +3001,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
*
*/
static grub_err_t
-dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
+dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_phys_t *dn,
struct grub_zfs_data *data)
{
grub_uint64_t objnum, version;
@@ -2825,7 +3011,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
struct dnode_chain
{
struct dnode_chain *next;
- dnode_end_t dn;
+ dnode_phys_t dn;
};
struct dnode_chain *dnode_path = 0, *dn_new, *root;
@@ -2922,7 +3108,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
ch = *path;
*path = 0; /* ensure null termination */
- if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
+ if (dnode_path->dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
break;
@@ -2947,25 +3133,23 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
break;
*path = ch;
- if (dnode_path->dn.dn.dn_bonustype == DMU_OT_ZNODE
- && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
+ if (dnode_path->dn.dn_bonustype == DMU_OT_ZNODE
+ && (((((znode_phys_t *) DN_BONUS (&dnode_path->dn))->zp_mode) >> 12) & 0xf) == 0xa)
{
char *sym_value;
grub_size_t sz;
grub_size_t sym_sz;
int free_symval = 0;
char *oldpath = path, *oldpathbuf = path_buf;
- sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys));
+ sym_value = ((char *) DN_BONUS (&dnode_path->dn) + sizeof (struct znode_phys));
- sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian);
+ sym_sz = ((znode_phys_t *) DN_BONUS (&dnode_path->dn))->zp_size;
- if (dnode_path->dn.dn.dn_flags & 1)
+ if (dnode_path->dn.dn_flags & 1)
{
grub_size_t block;
grub_size_t blksz;
- blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec,
- dnode_path->dn.endian)
- << SPA_MINBLOCKSHIFT);
+ blksz = dnode_path->dn.dn_datablkszsec << SPA_MINBLOCKSHIFT;
if (blksz == 0)
{
@@ -2985,7 +3169,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
void *t;
grub_size_t movesize;
- err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
+ err = dmu_read (&(dnode_path->dn), block, &t, data);
if (err)
{
grub_free (sym_value);
@@ -3047,22 +3231,22 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
}
dn_new = dnode_path;
}
- if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA)
+ if (dnode_path->dn.dn_bonustype == DMU_OT_SA)
{
void *sahdrp;
int hdrsize;
grub_size_t sz;
bool free_sahdrp = false;
- if (dnode_path->dn.dn.dn_bonuslen != 0)
+ if (dnode_path->dn.dn_bonuslen != 0)
{
- sahdrp = DN_BONUS (&dnode_path->dn.dn);
+ sahdrp = DN_BONUS (&dnode_path->dn);
}
- else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
+ else if (dnode_path->dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
{
- blkptr_t *bp = &dnode_path->dn.dn.dn_spill;
+ blkptr_t *bp = &dnode_path->dn.dn_spill;
- err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data);
+ err = zio_read (bp, &sahdrp, NULL, data);
if (err)
break;
free_sahdrp = true;
@@ -3075,17 +3259,14 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
- if (((grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp
- + hdrsize
- + SA_TYPE_OFFSET),
- dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
+ if (((grub_get_unaligned64 ((char *) sahdrp
+ + hdrsize
+ + SA_TYPE_OFFSET) >> 12) & 0xf) == 0xa)
{
char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET;
- grub_size_t sym_sz =
- grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp
+ grub_size_t sym_sz = grub_get_unaligned64 ((char *) sahdrp
+ hdrsize
- + SA_SIZE_OFFSET),
- dnode_path->dn.endian);
+ + SA_SIZE_OFFSET);
char *oldpath = path, *oldpathbuf = path_buf;
if (grub_add (sym_sz, grub_strlen (oldpath), &sz) ||
grub_add (sz, 1, &sz))
@@ -3205,14 +3386,12 @@ get_default_bootfsobj (dnode_phys_t * mosmdn, grub_uint64_t * obj,
*
*/
static grub_err_t
-get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
- dnode_end_t * mdn, struct grub_zfs_data *data)
+get_filesystem_dnode (dnode_phys_t * mosmdn, char *fsname,
+ dnode_phys_t * mdn, struct grub_zfs_data *data)
{
grub_uint64_t objnum;
grub_err_t err;
- grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian);
-
err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
DMU_OT_OBJECT_DIRECTORY, mdn, data);
if (err)
@@ -3249,7 +3428,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
ch = *fsname;
*fsname = 0;
- childobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) DN_BONUS (&mdn->dn)))->dd_child_dir_zapobj, mdn->endian);
+ childobj = (((dsl_dir_phys_t *) DN_BONUS (mdn)))->dd_child_dir_zapobj;
err = dnode_get (mosmdn, childobj,
DMU_OT_DSL_DIR_CHILD_MAP, mdn, data);
if (err)
@@ -3269,17 +3448,15 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
}
static grub_err_t
-make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
+make_mdn (dnode_phys_t * mdn, struct grub_zfs_data *data)
{
objset_phys_t *osp;
blkptr_t *bp;
grub_size_t ospsize = 0;
grub_err_t err;
- grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
-
- bp = &(((dsl_dataset_phys_t *) DN_BONUS (&mdn->dn))->ds_bp);
- err = zio_read (bp, mdn->endian, (void **) &osp, &ospsize, data);
+ bp = &(((dsl_dataset_phys_t *) DN_BONUS (mdn))->ds_bp);
+ err = zio_read (bp, (void **) &osp, &ospsize, data);
if (err)
return err;
if (ospsize < OBJSET_PHYS_SIZE_V14)
@@ -3288,9 +3465,7 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
return grub_error (GRUB_ERR_BAD_FS, "too small osp");
}
- mdn->endian = (grub_zfs_to_cpu64 (bp->blk_prop, mdn->endian)>>63) & 1;
- grub_memmove ((char *) &(mdn->dn),
- (char *) &(osp)->os_meta_dnode, DNODE_SIZE);
+ *mdn = (osp)->os_meta_dnode;
grub_free (osp);
return GRUB_ERR_NONE;
}
@@ -3352,7 +3527,7 @@ load_zap_key (const void *name, grub_size_t namelen, const void *val_in,
static grub_err_t
dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
- dnode_end_t * dn, int *isfs,
+ dnode_phys_t * dn, int *isfs,
struct grub_zfs_data *data)
{
char *fsname, *snapname;
@@ -3412,9 +3587,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_dprintf ("zfs", "alive\n");
- 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", subvol->mdn.endian);
+ headobj = ((dsl_dir_phys_t *) DN_BONUS (dn))->dd_head_dataset_obj;
err = dnode_get (&(data->mos), headobj, 0, &subvol->mdn, data);
if (err)
@@ -3423,18 +3596,19 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_free (snapname);
return err;
}
- grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
+ keychainobj = ((dsl_dir_phys_t *) DN_BONUS (dn))->keychain;
+
+ grub_dprintf("zfs", "keychain obj = %lld\n", (long long) keychainobj);
- keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian);
- if (grub_zfs_load_key && keychainobj)
+ if (grub_zfs_decrypt && keychainobj)
{
struct dnode_get_fullpath_ctx ctx = {
.subvol = subvol,
.keyn = 0
};
- dnode_end_t keychain_dn, props_dn;
+ dnode_phys_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);
+ propsobj = ((dsl_dir_phys_t *) DN_BONUS (dn))->dd_props_zapobj;
err = dnode_get (&(data->mos), propsobj, DMU_OT_DSL_PROPS,
&props_dn, data);
@@ -3484,7 +3658,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
{
grub_uint64_t snapobj;
- snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian);
+ snapobj = ((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn))->ds_snapnames_zapobj;
err = dnode_get (&(data->mos), snapobj,
DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data);
@@ -3493,7 +3667,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
if (!err)
err = dnode_get (&(data->mos), headobj, 0,
&subvol->mdn, data);
- if (!err && subvol->mdn.dn.dn_type != DMU_OT_DSL_DATASET && subvol->mdn.dn.dn_bonustype != DMU_OT_DSL_DATASET) {
+ if (!err && subvol->mdn.dn_type != DMU_OT_DSL_DATASET && subvol->mdn.dn_bonustype != DMU_OT_DSL_DATASET) {
grub_free (fsname);
grub_free (snapname);
return grub_error(GRUB_ERR_BAD_FS, "incorrect dataset dnode type");
@@ -3511,8 +3685,6 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
make_mdn (&subvol->mdn, data);
- grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
-
if (*isfs)
{
grub_free (fsname);
@@ -3776,7 +3948,6 @@ 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 = GRUB_ZFS_UNKNOWN_ENDIAN;
uberblock_t *ub;
int inserted;
@@ -3812,11 +3983,8 @@ zfs_mount (grub_device_t dev)
}
ub = &(data->current_uberblock);
- ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
- GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
- ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
- err = zio_read (&ub->ub_rootbp, ub_endian,
+ err = zio_read (&ub->ub_rootbp,
(void **) &osp, &ospsize, data);
if (err)
{
@@ -3833,7 +4001,7 @@ zfs_mount (grub_device_t dev)
}
if (ub->ub_version >= SPA_VERSION_FEATURES &&
- check_mos_features(&osp->os_meta_dnode, ub_endian, data) != 0)
+ check_mos_features(&osp->os_meta_dnode, data) != 0)
{
grub_error (GRUB_ERR_BAD_FS, "Unsupported features in pool");
grub_free (osp);
@@ -3842,9 +4010,7 @@ zfs_mount (grub_device_t dev)
}
/* Got the MOS. Save it at the memory addr MOS. */
- grub_memmove (&(data->mos.dn), &osp->os_meta_dnode, DNODE_SIZE);
- data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop,
- ub_endian) >> 63) & 1;
+ grub_memmove (&(data->mos), &osp->os_meta_dnode, DNODE_SIZE);
grub_free (osp);
return data;
@@ -3910,8 +4076,6 @@ static grub_err_t
zfs_mtime (grub_device_t device, grub_int64_t *mt)
{
struct grub_zfs_data *data;
- grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
- uberblock_t *ub;
*mt = 0;
@@ -3919,16 +4083,48 @@ zfs_mtime (grub_device_t device, grub_int64_t *mt)
if (! data)
return grub_errno;
- ub = &(data->current_uberblock);
- ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
- GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
- ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
-
- *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian);
+ *mt = data->current_uberblock.ub_timestamp;
zfs_unmount (data);
return GRUB_ERR_NONE;
}
+static grub_err_t
+parse_sa(const dnode_phys_t *dn, grub_int64_t *mtime, grub_uint64_t *sz,
+ struct grub_zfs_data *data)
+{
+ void *sahdrp;
+ int hdrsize;
+ grub_zfs_endian_t sa_endian;
+
+ if (dn->dn_bonuslen != 0)
+ sahdrp = (sa_hdr_phys_t *) DN_BONUS (dn);
+ else if (dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR)
+ {
+ const blkptr_t *bp = &dn->dn_spill;
+
+ grub_err_t err = zio_read (bp, &sahdrp, NULL, data);
+ if (err)
+ return err;
+ }
+ else
+ return GRUB_ERR_NONE;
+
+ if (grub_zfs_to_cpu32(((sa_hdr_phys_t *) sahdrp)->sa_magic, GRUB_ZFS_LITTLE_ENDIAN) == SA_MAGIC)
+ sa_endian = GRUB_ZFS_LITTLE_ENDIAN;
+ else if (grub_zfs_to_cpu32(((sa_hdr_phys_t *) sahdrp)->sa_magic, GRUB_ZFS_BIG_ENDIAN) == SA_MAGIC)
+ sa_endian = GRUB_ZFS_BIG_ENDIAN;
+ else
+ return GRUB_ERR_NONE;
+
+ hdrsize = (grub_zfs_to_cpu16(((sa_hdr_phys_t *) sahdrp)->sa_layout_info, sa_endian) >> 10) << 3;
+ if (mtime)
+ *mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), sa_endian);
+ if (sz)
+ *sz = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), sa_endian);
+
+ return GRUB_ERR_NONE;
+}
+
/*
* zfs_open() locates a file in the rootpool by following the
* MOS and places the dnode of the file in the memory address DNODE.
@@ -3959,7 +4155,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename)
}
/* We found the dnode for this file. Verify if it is a plain file. */
- if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS)
+ if (data->dnode.dn_type != DMU_OT_PLAIN_FILE_CONTENTS)
{
zfs_unmount (data);
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
@@ -3972,38 +4168,17 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename)
* attribute, which could be either in the bonus buffer
* or the "spill" block.
*/
- if (data->dnode.dn.dn_bonustype == DMU_OT_SA)
+ if (data->dnode.dn_bonustype == DMU_OT_SA)
{
- void *sahdrp;
- int hdrsize;
- bool free_sahdrp = false;
-
- if (data->dnode.dn.dn_bonuslen != 0)
- {
- sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
- }
- else if (data->dnode.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
- {
- blkptr_t *bp = &data->dnode.dn.dn_spill;
-
- err = zio_read (bp, data->dnode.endian, &sahdrp, NULL, data);
- if (err)
- return err;
- free_sahdrp = true;
- }
- else
- {
- return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
- }
-
- hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
- file->size = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian);
- if (free_sahdrp)
- grub_free(sahdrp);
+ grub_uint64_t fsize;
+ err = parse_sa(&data->dnode, NULL, &fsize, data);
+ if (err)
+ return err;
+ file->size = fsize;
}
- else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE)
+ else if (data->dnode.dn_bonustype == DMU_OT_ZNODE)
{
- file->size = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&data->dnode.dn))->zp_size, data->dnode.endian);
+ file->size = ((znode_phys_t *) DN_BONUS (&data->dnode))->zp_size;
}
else
return grub_error (GRUB_ERR_BAD_FS, "bad bonus type");
@@ -4038,8 +4213,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
return len;
}
- blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec,
- data->dnode.endian) << SPA_MINBLOCKSHIFT;
+ blksz = data->dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT;
if (blksz == 0)
{
@@ -4065,8 +4239,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
grub_free (data->file_buf);
data->file_buf = 0;
- err = dmu_read (&(data->dnode), blkid, &t,
- 0, data);
+ err = dmu_read (&(data->dnode), blkid, &t, data);
data->file_buf = t;
if (err)
{
@@ -4125,19 +4298,19 @@ grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename,
/*
* Note: fill_fs_info() uses functions such as make_mdn() that modify
- * the input dnode_end_t parameter. However, we should not allow it.
+ * the input dnode_phys_t parameter. However, we should not allow it.
* Therefore, we are making mdn_in constant - fill_fs_info() makes
* a local copy of it.
*/
static grub_err_t
fill_fs_info (struct grub_dirhook_info *info,
- const dnode_end_t *mdn_in, struct grub_zfs_data *data)
+ const dnode_phys_t *mdn_in, struct grub_zfs_data *data)
{
grub_err_t err;
- dnode_end_t dn;
+ dnode_phys_t dn;
grub_uint64_t objnum;
grub_uint64_t headobj;
- dnode_end_t mdn;
+ dnode_phys_t mdn;
grub_memcpy (&mdn, mdn_in, sizeof (*mdn_in));
@@ -4145,9 +4318,9 @@ fill_fs_info (struct grub_dirhook_info *info,
info->dir = 1;
- if (mdn.dn.dn_type == DMU_OT_DSL_DIR || mdn.dn.dn_bonustype == DMU_OT_DSL_DIR)
+ if (mdn.dn_type == DMU_OT_DSL_DIR || mdn.dn_bonustype == DMU_OT_DSL_DIR)
{
- headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&mdn.dn))->dd_head_dataset_obj, mdn.endian);
+ headobj = ((dsl_dir_phys_t *) DN_BONUS (&mdn))->dd_head_dataset_obj;
err = dnode_get (&(data->mos), headobj, 0, &mdn, data);
if (err)
@@ -4181,42 +4354,18 @@ fill_fs_info (struct grub_dirhook_info *info,
return err;
}
- if (dn.dn.dn_bonustype == DMU_OT_SA)
+ if (dn.dn_bonustype == DMU_OT_SA)
{
- void *sahdrp;
- int hdrsize;
- bool free_sahdrp = false;
-
- if (dn.dn.dn_bonuslen != 0)
- {
- sahdrp = (sa_hdr_phys_t *) DN_BONUS (&dn.dn);
- }
- else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
- {
- blkptr_t *bp = &dn.dn.dn_spill;
-
- err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
- if (err)
- return err;
- free_sahdrp = true;
- }
- else
- {
- grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
- return grub_errno;
- }
-
- hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
+ err = parse_sa(&dn, &info->mtime, NULL, data);
+ if (err)
+ return err;
info->mtimeset = 1;
- info->mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
- if (free_sahdrp)
- grub_free (sahdrp);
}
- if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
+ if (dn.dn_bonustype == DMU_OT_ZNODE)
{
info->mtimeset = 1;
- info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian);
+ info->mtime = ((znode_phys_t *) DN_BONUS (&dn))->zp_mtime[0];
}
return 0;
}
@@ -4228,7 +4377,7 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx)
grub_err_t err;
struct grub_dirhook_info info;
- dnode_end_t dn;
+ dnode_phys_t dn;
grub_memset (&info, 0, sizeof (info));
err = dnode_get (&(ctx->data->subvol.mdn), val, 0, &dn, ctx->data);
@@ -4238,52 +4387,22 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx)
return 0;
}
- if (dn.dn.dn_bonustype == DMU_OT_SA)
+ if (dn.dn_bonustype == DMU_OT_SA)
{
- void *sahdrp;
- int hdrsize;
- bool free_sahdrp = false;
-
- if (dn.dn.dn_bonuslen != 0)
- {
- sahdrp = (sa_hdr_phys_t *) DN_BONUS (&ctx->data->dnode.dn);
- }
- else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
- {
- blkptr_t *bp = &dn.dn.dn_spill;
-
- err = zio_read (bp, dn.endian, &sahdrp, NULL, ctx->data);
- if (err)
- {
- grub_print_error ();
- return 0;
- }
- free_sahdrp = true;
- }
- else
- {
- grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
- grub_print_error ();
- return 0;
- }
-
- hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
+ err = parse_sa(&dn, &info.mtime, NULL, ctx->data);
+ if (err)
+ return err;
info.mtimeset = 1;
- info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
- info.case_insensitive = ctx->data->subvol.case_insensitive;
- if (free_sahdrp)
- grub_free (sahdrp);
}
- if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
+ if (dn.dn_bonustype == DMU_OT_ZNODE)
{
info.mtimeset = 1;
- info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0],
- dn.endian);
+ info.mtime = ((znode_phys_t *) DN_BONUS (&dn))->zp_mtime[0];
}
- info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
+ info.dir = (dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
grub_dprintf ("zfs", "type=%d, name=%s\n",
- (int)dn.dn.dn_type, (char *)name);
+ (int)dn.dn_type, (char *)name);
return ctx->hook (name, &info, ctx->hook_data);
}
@@ -4298,15 +4417,15 @@ iterate_zap_fs (const char *name, grub_uint64_t val,
if (name[0] == 0 && val == 0)
return 0;
- dnode_end_t mdn;
+ dnode_phys_t mdn;
err = dnode_get (&(ctx->data->mos), val, 0, &mdn, ctx->data);
if (err)
{
grub_errno = 0;
return 0;
}
- if (mdn.dn.dn_type != DMU_OT_DSL_DIR && mdn.dn.dn_bonustype != DMU_OT_DSL_DIR) {
- grub_dprintf ("zfs", "type = 0x%x, val = 0x%llx\n", mdn.dn.dn_type, (long long)val);
+ if (mdn.dn_type != DMU_OT_DSL_DIR && mdn.dn_bonustype != DMU_OT_DSL_DIR) {
+ grub_dprintf ("zfs", "type = 0x%x, val = 0x%llx\n", mdn.dn_type, (long long)val);
return 0;
}
@@ -4330,7 +4449,7 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
int ret;
grub_size_t sz;
- dnode_end_t mdn;
+ dnode_phys_t mdn;
err = dnode_get (&(ctx->data->mos), val, 0, &mdn, ctx->data);
if (err)
@@ -4339,7 +4458,7 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
return 0;
}
- if (mdn.dn.dn_type != DMU_OT_DSL_DATASET && mdn.dn.dn_bonustype != DMU_OT_DSL_DATASET)
+ if (mdn.dn_type != DMU_OT_DSL_DATASET && mdn.dn_bonustype != DMU_OT_DSL_DATASET)
return 0;
err = fill_fs_info (&info, &mdn, ctx->data);
@@ -4390,7 +4509,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
{
grub_uint64_t childobj, headobj;
grub_uint64_t snapobj;
- dnode_end_t dn;
+ dnode_phys_t dn;
struct grub_dirhook_info info;
err = fill_fs_info (&info, &data->dnode, data);
@@ -4405,8 +4524,8 @@ grub_zfs_dir (grub_device_t device, const char *path,
return GRUB_ERR_NONE;
}
- childobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, data->dnode.endian);
- headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, data->dnode.endian);
+ childobj = ((dsl_dir_phys_t *) DN_BONUS (&data->dnode))->dd_child_dir_zapobj;
+ headobj = ((dsl_dir_phys_t *) DN_BONUS (&data->dnode))->dd_head_dataset_obj;
err = dnode_get (&(data->mos), childobj,
DMU_OT_DSL_DIR_CHILD_MAP, &dn, data);
if (err)
@@ -4418,7 +4537,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
zap_iterate_u64 (&dn, iterate_zap_fs, data, &ctx);
err = dnode_get (&(data->mos), headobj, 0, &dn, data);
- if (!err && dn.dn.dn_type != DMU_OT_DSL_DATASET && dn.dn.dn_bonustype != DMU_OT_DSL_DATASET)
+ if (!err && dn.dn_type != DMU_OT_DSL_DATASET && dn.dn_bonustype != DMU_OT_DSL_DATASET)
return grub_error(GRUB_ERR_BAD_FS, "incorrect dataset dnode type");
if (err)
@@ -4427,7 +4546,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
return err;
}
- snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&dn.dn))->ds_snapnames_zapobj, dn.endian);
+ snapobj = ((dsl_dataset_phys_t *) DN_BONUS (&dn))->ds_snapnames_zapobj;
err = dnode_get (&(data->mos), snapobj,
DMU_OT_DSL_DS_SNAP_MAP, &dn, data);
@@ -4441,7 +4560,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
}
else
{
- if (data->dnode.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
+ if (data->dnode.dn_type != DMU_OT_DIRECTORY_CONTENTS)
{
zfs_unmount (data);
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
@@ -4477,16 +4596,14 @@ check_feature (const char *name, grub_uint64_t val,
*/
static grub_err_t
-check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data )
+check_mos_features(dnode_phys_t *mosmdn_phys, struct grub_zfs_data* data )
{
grub_uint64_t objnum;
- grub_err_t errnum = 0;
- dnode_end_t dn,mosmdn;
+ grub_err_t errnum = 0, ret = 0;
+ dnode_phys_t dn,mosmdn;
mzap_phys_t* mzp;
- grub_zfs_endian_t endianzap;
- int size, ret;
- grub_memmove(&(mosmdn.dn),mosmdn_phys,sizeof(dnode_phys_t));
- mosmdn.endian=endian;
+ int size;
+ grub_memmove(&mosmdn,mosmdn_phys,sizeof(dnode_phys_t));
errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT,
DMU_OT_OBJECT_DIRECTORY, &dn,data);
if (errnum != 0)
@@ -4505,12 +4622,12 @@ check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct gru
if (errnum != 0)
return errnum;
- errnum = dmu_read(&dn, 0, (void**)&mzp, &endianzap,data);
+ errnum = dmu_read(&dn, 0, (void**)&mzp, data);
if (errnum != 0)
return errnum;
- size = grub_zfs_to_cpu16 (dn.dn.dn_datablkszsec, dn.endian) << SPA_MINBLOCKSHIFT;
- ret = mzap_iterate (mzp,endianzap, size, check_feature,NULL);
+ size = dn.dn_datablkszsec << SPA_MINBLOCKSHIFT;
+ ret = mzap_iterate (mzp, size, check_feature,NULL);
grub_free(mzp);
return ret;
}
diff --git a/grub-core/fs/zfs/zfs_fletcher.c b/grub-core/fs/zfs/zfs_fletcher.c
index ad3be6705..deac0b45b 100644
--- a/grub-core/fs/zfs/zfs_fletcher.c
+++ b/grub-core/fs/zfs/zfs_fletcher.c
@@ -54,10 +54,10 @@ fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian,
b1 += a1;
}
- zcp->zc_word[0] = grub_cpu_to_zfs64 (a0, endian);
- zcp->zc_word[1] = grub_cpu_to_zfs64 (a1, endian);
- zcp->zc_word[2] = grub_cpu_to_zfs64 (b0, endian);
- zcp->zc_word[3] = grub_cpu_to_zfs64 (b1, endian);
+ zcp->zc_word[0] = a0;
+ zcp->zc_word[1] = a1;
+ zcp->zc_word[2] = b0;
+ zcp->zc_word[3] = b1;
}
void
@@ -70,15 +70,15 @@ fletcher_4 (const void *buf, grub_uint64_t size, grub_zfs_endian_t endian,
for (a = b = c = d = 0; ip < ipend; ip++)
{
- a += grub_zfs_to_cpu32 (ip[0], endian);;
+ a += grub_zfs_to_cpu32 (ip[0], endian);
b += a;
c += b;
d += c;
}
- zcp->zc_word[0] = grub_cpu_to_zfs64 (a, endian);
- zcp->zc_word[1] = grub_cpu_to_zfs64 (b, endian);
- zcp->zc_word[2] = grub_cpu_to_zfs64 (c, endian);
- zcp->zc_word[3] = grub_cpu_to_zfs64 (d, endian);
+ zcp->zc_word[0] = a;
+ zcp->zc_word[1] = b;
+ zcp->zc_word[2] = c;
+ zcp->zc_word[3] = d;
}
diff --git a/grub-core/fs/zfs/zfs_sha256.c b/grub-core/fs/zfs/zfs_sha256.c
index f042fa61a..69f1bd9d9 100644
--- a/grub-core/fs/zfs/zfs_sha256.c
+++ b/grub-core/fs/zfs/zfs_sha256.c
@@ -109,7 +109,7 @@ SHA256Transform(grub_uint32_t *H, const grub_uint8_t *cp)
void
zio_checksum_SHA256(const void *buf, grub_uint64_t size,
- grub_zfs_endian_t endian, zio_cksum_t *zcp)
+ grub_zfs_endian_t endian __attribute__((unused)), zio_cksum_t *zcp)
{
grub_uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
@@ -132,12 +132,8 @@ zio_checksum_SHA256(const void *buf, grub_uint64_t size,
for (i = 0; i < padsize && i <= 64; i += 64)
SHA256Transform(H, pad + i);
- zcp->zc_word[0] = grub_cpu_to_zfs64 ((grub_uint64_t)H[0] << 32 | H[1],
- endian);
- zcp->zc_word[1] = grub_cpu_to_zfs64 ((grub_uint64_t)H[2] << 32 | H[3],
- endian);
- zcp->zc_word[2] = grub_cpu_to_zfs64 ((grub_uint64_t)H[4] << 32 | H[5],
- endian);
- zcp->zc_word[3] = grub_cpu_to_zfs64 ((grub_uint64_t)H[6] << 32 | H[7],
- endian);
+ zcp->zc_word[0] = (grub_uint64_t)H[0] << 32 | H[1];
+ zcp->zc_word[1] = (grub_uint64_t)H[2] << 32 | H[3];
+ zcp->zc_word[2] = (grub_uint64_t)H[4] << 32 | H[5];
+ zcp->zc_word[3] = (grub_uint64_t)H[6] << 32 | H[7];
}
diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c
index da30e9ab3..535fd4065 100644
--- a/grub-core/fs/zfs/zfscrypt.c
+++ b/grub-core/fs/zfs/zfscrypt.c
@@ -277,7 +277,7 @@ algo_decrypt (grub_crypto_cipher_handle_t cipher, grub_uint64_t algo,
static grub_err_t
grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
grub_uint64_t algo,
- void *nonce,
+ const void *nonce,
char *buf, grub_size_t size,
const grub_uint32_t *expected_mac,
grub_zfs_endian_t endian)
diff --git a/include/grub/zfs/sa_impl.h b/include/grub/zfs/sa_impl.h
index 0845d1290..b92c458a4 100644
--- a/include/grub/zfs/sa_impl.h
+++ b/include/grub/zfs/sa_impl.h
@@ -29,6 +29,7 @@ typedef struct sa_hdr_phys {
} sa_hdr_phys_t;
#define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0)
+#define SA_MAGIC 0x2F505A
#define SA_TYPE_OFFSET 0x0
#define SA_SIZE_OFFSET 0x8
#define SA_MTIME_OFFSET 0x38
diff --git a/include/grub/zfs/spa.h b/include/grub/zfs/spa.h
index 5afbe4ecd..da44d1864 100644
--- a/include/grub/zfs/spa.h
+++ b/include/grub/zfs/spa.h
@@ -196,9 +196,18 @@ typedef struct blkptr {
#define DVA_GET_VDEV(dva) BF64_GET((dva)->dva_word[0], 32, 32)
#define DVA_SET_VDEV(dva, x) BF64_SET((dva)->dva_word[0], 32, 32, x)
+#define DVA_GET_OFFSET(dva) \
+ BF64_GET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0)
+#define DVA_SET_OFFSET(dva, x) \
+ BF64_SET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0, x)
+
#define DVA_GET_GANG(dva) BF64_GET((dva)->dva_word[1], 63, 1)
#define DVA_SET_GANG(dva, x) BF64_SET((dva)->dva_word[1], 63, 1, x)
+#define BP_GET_PSIZE(bp) \
+ BF64_GET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1)
+#define BP_SET_PSIZE(bp, x) \
+ BF64_SET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1, x)
#define BP_GET_LSIZE(bp) \
BF64_GET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1)
#define BP_SET_LSIZE(bp, x) \
diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h
index 4ee513887..0c5c40a73 100644
--- a/include/grub/zfs/zfs.h
+++ b/include/grub/zfs/zfs.h
@@ -33,6 +33,14 @@ typedef enum grub_zfs_endian
GRUB_ZFS_BIG_ENDIAN = 0
} grub_zfs_endian_t;
+#ifdef GRUB_CPU_WORDS_BIGENDIAN
+#define GRUB_ZFS_IS_NATIVE_BYTEORDER(x) ((x) == GRUB_ZFS_BIG_ENDIAN)
+#define GRUB_ZFS_NATIVE_ENDIAN GRUB_ZFS_BIG_ENDIAN
+#else
+#define GRUB_ZFS_IS_NATIVE_BYTEORDER(x) ((x) != GRUB_ZFS_BIG_ENDIAN)
+#define GRUB_ZFS_NATIVE_ENDIAN GRUB_ZFS_LITTLE_ENDIAN
+#endif
+
/*
* On-disk version number.
*/
@@ -141,7 +149,7 @@ grub_zfs_add_key (grub_uint8_t *key_in,
extern grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
grub_uint64_t algo,
- void *nonce,
+ const void *nonce,
char *buf, grub_size_t size,
const grub_uint32_t *expected_mac,
grub_zfs_endian_t endian);
--
2.49.0
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 2/2] zfs: Support datto encryption
2025-08-01 14:30 [PATCH 0/2] zfs: Support datto encryption and fix endianness handling Vladimir Serbinenko
2025-08-01 14:30 ` [PATCH 1/2] zfs: Rewrite " Vladimir Serbinenko
@ 2025-08-01 14:30 ` Vladimir Serbinenko
2025-08-11 13:48 ` Neal Gompa
2025-08-11 13:23 ` [PATCH 0/2] zfs: Support datto encryption and fix endianness handling Neal Gompa
2 siblings, 1 reply; 8+ messages in thread
From: Vladimir Serbinenko @ 2025-08-01 14:30 UTC (permalink / raw)
To: grub-devel; +Cc: Vladimir Serbinenko
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
---
grub-core/fs/zfs/zfs.c | 502 ++++++++++++++++++++++++++++++++----
grub-core/fs/zfs/zfscrypt.c | 335 +++++++++++++++++++++---
include/grub/zfs/zfs.h | 54 +++-
3 files changed, 793 insertions(+), 98 deletions(-)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index b88a2b032..da1661680 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -227,6 +227,10 @@ struct subvolume
grub_uint64_t txg;
grub_uint64_t algo;
} *keyring;
+
+ struct grub_zfs_datto_key key_datto;
+
+ int is_datto_encrypted;
};
struct grub_zfs_data
@@ -264,16 +268,19 @@ struct grub_zfs_dir_ctx
struct grub_zfs_data *data;
};
-grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
- grub_uint64_t algo,
- const 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;
+struct grub_zfs_decryptor *grub_zfs_decrypt = NULL;
+
+struct grub_zfs_crypt_datto_data
+{
+ grub_uint8_t *iv;
+ grub_size_t ivlen;
+ grub_uint8_t *mac;
+ grub_size_t maclen;
+ grub_uint8_t *master;
+ grub_size_t masterlen;
+ grub_uint8_t *hmac;
+ grub_size_t hmaclen;
+};
/*
* List of pool features that the grub implementation of ZFS supports for
* read. Note that features that are only required for write do not need
@@ -289,6 +296,7 @@ static const char *spa_feature_names[] = {
"com.klarasystems:vdev_zaps_v2",
"com.delphix:head_errlog",
"org.freebsd:zstd_compress",
+ "com.datto:encryption",
NULL
};
@@ -400,6 +408,47 @@ static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
static grub_err_t zio_read_data (const blkptr_t * bp,
void *buf, struct grub_zfs_data *data);
+static int
+fill_crypt_datto_data (const void *name,
+ grub_size_t namelen __attribute__ ((unused)),
+ const void *val_in,
+ grub_size_t nelem,
+ grub_size_t elemsize,
+ void *data_in)
+{
+ struct grub_zfs_crypt_datto_data *data = data_in;
+ if (grub_strcmp(name, "DSL_CRYPTO_IV") == 0 && elemsize == 1)
+ {
+ data->ivlen = nelem;
+ data->iv = grub_malloc(nelem);
+ if (data->iv)
+ grub_memcpy(data->iv, val_in, nelem);
+ }
+ else if (grub_strcmp(name, "DSL_CRYPTO_MAC") == 0 && elemsize == 1)
+ {
+ data->maclen = nelem;
+ data->mac = grub_malloc(nelem);
+ if (data->mac)
+ grub_memcpy(data->mac, val_in, nelem);
+ }
+ else if (grub_strcmp(name, "DSL_CRYPTO_MASTER_KEY_1") == 0 && elemsize == 1)
+ {
+ data->masterlen = nelem;
+ data->master = grub_malloc(nelem);
+ if (data->master)
+ grub_memcpy(data->master, val_in, nelem);
+ }
+ else if (grub_strcmp(name, "DSL_CRYPTO_HMAC_KEY_1") == 0 && elemsize == 1)
+ {
+ data->hmaclen = nelem;
+ data->hmac = grub_malloc(nelem);
+ if (data->hmac)
+ grub_memcpy(data->hmac, val_in, nelem);
+ }
+
+ return 0;
+}
+
/*
* Our own version of log2(). Same thing as highbit()-1.
*/
@@ -690,7 +739,7 @@ grub_zfs_byteswap_type(void *buf, grub_size_t len, grub_uint8_t type)
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)
+ char *buf, grub_size_t size, int datto_crypt)
{
zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
zio_checksum_info_t *ci = &zio_checksum_table[checksum];
@@ -715,6 +764,12 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
ci->ci_func (buf, size, endian, &actual_cksum);
int cksumlen = checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20;
+ if (datto_crypt)
+ {
+ actual_cksum.zc_word[0] ^= actual_cksum.zc_word[2];
+ actual_cksum.zc_word[1] ^= actual_cksum.zc_word[3];
+ cksumlen = 16;
+ }
if (ci->ci_eck && !GRUB_ZFS_IS_NATIVE_BYTEORDER(endian))
grub_zfs_byteswap_checksum(&actual_cksum);
@@ -796,7 +851,7 @@ uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian);
err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian,
- (char *) ub, s);
+ (char *) ub, s, 0);
return err;
}
@@ -1269,7 +1324,7 @@ check_pool_label (struct grub_zfs_data *data,
/* Now check the integrity of the vdev_phys_t structure though checksum. */
ZIO_SET_CHECKSUM(&emptycksum, grub_cpu_to_zfs64(diskdesc->vdev_phys_sector << 9, endian), 0, 0, 0);
err = zio_checksum_verify (emptycksum, ZIO_CHECKSUM_LABEL, endian,
- nvlist, VDEV_PHYS_SIZE);
+ nvlist, VDEV_PHYS_SIZE, 0);
if (err) {
grub_free (nvlist);
return err;
@@ -2019,7 +2074,7 @@ zio_read_gang (const blkptr_t * bp, const dva_t * dva, void *buf,
ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV (dva),
DVA_GET_OFFSET (dva), bp->blk_birth, 0);
err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER, BP_GET_BYTEORDER(bp),
- (char *) zio_gb, SPA_GANGBLOCKSIZE);
+ (char *) zio_gb, SPA_GANGBLOCKSIZE, 0);
if (err)
{
grub_free (zio_gb);
@@ -2113,6 +2168,57 @@ decode_embedded_bp_compressed(const blkptr_t *bp, void *buf)
return GRUB_ERR_NONE;
}
+static int
+datto_is_encrypted_type(grub_uint8_t dn_type)
+{
+ /* New structred types. */
+ if (dn_type & 0x80)
+ return !!(dn_type & 0x20);
+ switch(dn_type) {
+ case DMU_OT_NONE ... DMU_OT_SPACE_MAP:
+ case DMU_OT_OBJSET ... DMU_OT_ZNODE:
+ case DMU_OT_MASTER_NODE:
+ case DMU_OT_ZVOL_PROP:
+ case DMU_OT_ZAP_OTHER ... DMU_OT_DSL_PERMS:
+ case DMU_OT_FUID_SIZE ... DMU_OT_SCRUB_QUEUE:
+ case DMU_OT_USERREFS ... DMU_OT_DDT_STATS:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static void
+add_blkptr_to_aad (char *aad, grub_size_t *aad_offset, blkptr_t bp, grub_zfs_endian_t endian, int preswapped)
+{
+ if (!preswapped && !GRUB_ZFS_IS_NATIVE_BYTEORDER(endian))
+ grub_zfs_byteswap_blkptr(&bp);
+
+ grub_uint64_t blk_prop = BP_IS_HOLE(&bp) ? 0 : bp.blk_prop;
+
+ if (BP_GET_LEVEL(&bp) != 0) {
+ blk_prop &= ~0x8000007fffff0000ULL;
+ }
+
+ blk_prop &= ~0x4000ff0000000000ULL;
+
+ grub_set_unaligned64(&aad[*aad_offset], grub_cpu_to_le64(blk_prop));
+ *aad_offset += 8;
+
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(endian))
+ {
+ grub_set_unaligned64(&aad[*aad_offset], grub_swap_bytes64(bp.blk_cksum.zc_word[2]));
+ grub_set_unaligned64(&aad[*aad_offset+8], grub_swap_bytes64(bp.blk_cksum.zc_word[3]));
+ }
+ else
+ grub_memcpy(&aad[*aad_offset], &bp.blk_cksum.zc_word[2], 16);
+
+ *aad_offset += 16;
+
+ grub_memset(&aad[*aad_offset], 0, 8);
+ *aad_offset += 8;
+}
+
/*
* Read in a block of data, verify its checksum, decompress if needed,
* and put the uncompressed data in buf.
@@ -2122,17 +2228,44 @@ zio_read (const blkptr_t *bp, void **buf,
grub_size_t *size, struct grub_zfs_data *data)
{
grub_size_t lsize, psize;
- unsigned int comp, encrypted;
+ unsigned int comp;
char *compbuf = NULL;
grub_err_t err;
zio_cksum_t zc = bp->blk_cksum;
grub_uint32_t checksum;
+ int datto_encrypted = 0, datto_authenticated = 0, datto_dnode_encryption = 0, oracle_encrypted = 0;
*buf = NULL;
checksum = BP_GET_CHECKSUM(bp);
comp = BP_GET_COMPRESS(bp);
- encrypted = BP_GET_PROP_BIT_61(bp);
+ if (BP_GET_PROP_BIT_61(bp))
+ {
+ if (data->subvol.is_datto_encrypted)
+ {
+ grub_uint8_t type = BP_GET_TYPE(bp);
+ if (BP_GET_LEVEL(bp) > 0)
+ datto_authenticated = 1;
+ else if (type == DMU_OT_DNODE)
+ {
+ datto_encrypted = 1;
+ datto_authenticated = 0;
+ datto_dnode_encryption = 1;
+ }
+ else if (type == DMU_OT_OBJSET)
+ {
+ /* Objset uses inner hmacs that we don't suport yet.
+ Normal checksum is unaffected . */
+ }
+ else
+ {
+ datto_encrypted = datto_is_encrypted_type(type);
+ datto_authenticated = !datto_encrypted;
+ }
+ }
+ else
+ oracle_encrypted = 1;
+ }
if (BP_IS_EMBEDDED(bp))
{
if (BPE_GET_ETYPE(bp) != BP_EMBEDDED_TYPE_DATA)
@@ -2186,10 +2319,11 @@ zio_read (const blkptr_t *bp, void **buf,
return err;
}
- if (!BP_IS_EMBEDDED(bp))
+ if (!BP_IS_EMBEDDED(bp) && !datto_encrypted)
{
err = zio_checksum_verify (zc, checksum, BP_GET_BYTEORDER(bp),
- compbuf, psize);
+ compbuf, psize,
+ datto_authenticated);
if (err)
{
grub_dprintf ("zfs", "incorrect checksum\n");
@@ -2199,48 +2333,190 @@ zio_read (const blkptr_t *bp, void **buf,
}
}
- if (encrypted)
+ if (!BP_IS_EMBEDDED(bp) && datto_authenticated && data->subvol.key_datto.hmac_key && BP_GET_LEVEL(bp) == 0)
{
- if (!grub_zfs_decrypt)
- err = grub_error (GRUB_ERR_BAD_FS,
- N_("module `%s' isn't loaded"),
- "zfscrypt");
- else
+ grub_uint64_t hmac[8];
+ gcry_error_t err_gcry;
+ err_gcry = grub_crypto_hmac_buffer (GRUB_MD_SHA512,
+ data->subvol.key_datto.hmac_key, 64,
+ compbuf, psize,
+ hmac);
+ if (err_gcry)
{
- unsigned i, besti = 0;
- grub_uint64_t bestval = 0;
- for (i = 0; i < data->subvol.nkeys; i++)
- if (data->subvol.keyring[i].txg <= bp->blk_birth
- && data->subvol.keyring[i].txg > bestval)
- {
- besti = i;
- bestval = data->subvol.keyring[i].txg;
- }
- if (bestval == 0)
+ grub_free (compbuf);
+ *buf = NULL;
+ return grub_crypto_gcry_error (err_gcry);
+ }
+
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(BP_GET_BYTEORDER(bp)))
+ {
+ grub_zfs_byteswap_u64(&hmac[0]);
+ grub_zfs_byteswap_u64(&hmac[1]);
+ }
+
+ if (grub_crypto_memcmp(&zc.zc_word[2], hmac, 8) != 0)
+ {
+ grub_free (compbuf);
+ *buf = NULL;
+ grub_dprintf ("zfs", "actual hmac "
+ "%016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx \n",
+ (unsigned long long) hmac[0],
+ (unsigned long long) hmac[1],
+ (unsigned long long) hmac[2],
+ (unsigned long long) hmac[3],
+ (unsigned long long) hmac[4],
+ (unsigned long long) hmac[5],
+ (unsigned long long) hmac[6],
+ (unsigned long long) hmac[7]);
+ grub_dprintf ("zfs", "expected hmac %016llx %016llx %016llx %016llx\n",
+ (unsigned long long) zc.zc_word[0],
+ (unsigned long long) zc.zc_word[1],
+ (unsigned long long) zc.zc_word[2],
+ (unsigned long long) zc.zc_word[3]);
+ return grub_error (GRUB_ERR_BAD_FS, N_("HMAC verification failed"));
+ }
+ }
+
+ if (datto_dnode_encryption && (!grub_zfs_decrypt || !data->subvol.key_datto.master_key))
+ {
+ grub_dprintf("zfs", "Skipping decrypt of bonus because of missing zfscrypt module or key\n");
+ datto_encrypted = 0;
+ datto_dnode_encryption = 0;
+ }
+ if ((oracle_encrypted || datto_encrypted) && !grub_zfs_decrypt)
+ err = grub_error (GRUB_ERR_BAD_FS,
+ N_("module `%s' isn't loaded"),
+ "zfscrypt");
+ else if (datto_encrypted)
+ {
+ grub_uint32_t iv[3];
+
+ if (!data->subvol.key_datto.master_key)
+ {
+ grub_free (compbuf);
+ *buf = NULL;
+ grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
+ bp->blk_birth);
+ return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
+ }
+
+ grub_set_unaligned64(iv, grub_cpu_to_zfs64((bp)->blk_dva[2].dva_word[1], BP_GET_BYTEORDER(bp)));
+ iv[2] = grub_cpu_to_zfs32((bp)->blk_fill >> 32, BP_GET_BYTEORDER(bp));
+
+ if (datto_dnode_encryption)
+ {
+ grub_size_t offset = 0, crypt_offset = 0, aad_offset = 0;
+ char *crypt = grub_malloc(psize), *aad = grub_malloc(psize);
+ grub_zfs_endian_t endian = BP_GET_BYTEORDER(bp);
+ if (!crypt || !aad)
{
grub_free (compbuf);
+ grub_free (crypt);
+ grub_free (aad);
*buf = NULL;
- grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
- bp->blk_birth);
- return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
+ return grub_errno;
}
- 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,
- bp->blk_birth);
- err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
- data->subvol.keyring[besti].algo,
- &(bp)->blk_dva[2],
- compbuf, psize, zc.zc_mac,
- BP_GET_BYTEORDER(bp));
+ for (offset = 0; offset + sizeof (dnode_phys_t) <= psize; offset += sizeof(dnode_phys_t))
+ {
+ dnode_phys_t *dnp = (dnode_phys_t *) (void *) (compbuf + offset);
+ dnode_phys_t *dno = (dnode_phys_t *) (aad + aad_offset);
+ grub_memcpy(aad + aad_offset, dnp, 64);
+ dno->dn_used = 0;
+ dno->dn_flags &= DNODE_FLAG_SPILL_BLKPTR;
+ int has_spill = dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR;
+ unsigned i;
+
+ aad_offset += 64;
+
+ for (i = 0; i < dnp->dn_nblkptr; i++) {
+ add_blkptr_to_aad (aad, &aad_offset, dnp->dn_blkptr[i], endian, 0);
+ }
+
+ if (has_spill)
+ add_blkptr_to_aad (aad, &aad_offset, dnp->dn_spill, endian, 0);
+
+ char *bonus = DN_BONUS(dnp);
+ char *bonusmaxptr = (char *) (dnp + 1);
+ if (has_spill)
+ bonusmaxptr -= sizeof(blkptr_t);
+ grub_size_t bonusmaxlen = bonusmaxptr - bonus;
+ if (datto_is_encrypted_type(dnp->dn_bonustype))
+ {
+ grub_memcpy(crypt + crypt_offset, bonus, bonusmaxlen);
+ crypt_offset += bonusmaxlen;
+ }
+ else
+ {
+ grub_memcpy(aad + aad_offset, bonus, bonusmaxlen);
+ grub_zfs_byteswap_type((aad + aad_offset), bonusmaxlen, dnp->dn_bonustype);
+ aad_offset += bonusmaxlen;
+ }
+ }
+ err = grub_zfs_decrypt->decrypt_datto (&data->subvol.key_datto,
+ iv, (bp)->blk_dva[2].dva_word[0],
+ crypt, crypt_offset, aad, aad_offset,
+ &zc.zc_word[2],
+ endian);
+ grub_size_t out_offset = 0;
+ for (offset = 0; offset + sizeof (dnode_phys_t) <= psize; offset += sizeof(dnode_phys_t))
+ {
+ dnode_phys_t *dnp = (dnode_phys_t *) (void *) (compbuf + offset);
+ int has_spill = dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR;
+ if (!datto_is_encrypted_type(dnp->dn_bonustype))
+ continue;
+ char * bonus = DN_BONUS(dnp);
+ char *bonusmaxptr = (char *) (dnp + 1);
+ if (has_spill)
+ bonusmaxptr -= sizeof(blkptr_t);
+ grub_size_t bonusmaxlen = bonusmaxptr - bonus;
+ grub_memcpy(bonus, crypt + out_offset, bonusmaxlen);
+ out_offset += bonusmaxlen;
+ }
+
}
- if (err)
+ else
+ err = grub_zfs_decrypt->decrypt_datto (&data->subvol.key_datto,
+ iv, (bp)->blk_dva[2].dva_word[0],
+ compbuf, psize, NULL, 0,
+ &zc.zc_word[2],
+ BP_GET_BYTEORDER(bp));
+ }
+ else if (oracle_encrypted)
+ {
+ unsigned i, besti = 0;
+ grub_uint64_t bestval = 0;
+ grub_dprintf("zfs", "Subvol has %d keys\n", (int) data->subvol.nkeys);
+ for (i = 0; i < data->subvol.nkeys; i++)
+ if (data->subvol.keyring[i].txg <= bp->blk_birth
+ && data->subvol.keyring[i].txg > bestval)
+ {
+ besti = i;
+ bestval = data->subvol.keyring[i].txg;
+ }
+ if (bestval == 0)
{
grub_free (compbuf);
*buf = NULL;
- return err;
+ grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
+ bp->blk_birth);
+ 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,
+ bp->blk_birth);
+ err = grub_zfs_decrypt->decrypt_oracle (data->subvol.keyring[besti].cipher,
+ data->subvol.keyring[besti].algo,
+ &(bp)->blk_dva[2],
+ compbuf, psize, zc.zc_mac,
+ BP_GET_BYTEORDER(bp));
+ }
+ if (err)
+ {
+ grub_free (compbuf);
+ *buf = NULL;
+ return err;
}
if (comp != ZIO_COMPRESS_OFF)
@@ -2254,6 +2530,7 @@ zio_read (const blkptr_t *bp, void **buf,
err = decomp_table[comp].decomp_func (compbuf, *buf, psize, lsize);
grub_free (compbuf);
+ compbuf = NULL;
if (err)
{
grub_free (*buf);
@@ -2273,6 +2550,51 @@ zio_read (const blkptr_t *bp, void **buf,
grub_zfs_byteswap_type(*buf, lsize, BP_GET_TYPE(bp));
}
+ if (!BP_IS_EMBEDDED(bp) && datto_authenticated && BP_GET_LEVEL(bp) > 0)
+ {
+ grub_uint64_t hash[8];
+ char *aad = grub_malloc(lsize);
+ grub_size_t aad_offset = 0;
+ if (!aad)
+ {
+ grub_free (*buf);
+ *buf = NULL;
+ return grub_errno;
+ }
+ for (unsigned i = 0; i < lsize / sizeof(blkptr_t); i++)
+ add_blkptr_to_aad (aad, &aad_offset, ((blkptr_t *)*buf)[i], BP_GET_BYTEORDER(bp), 1);
+ grub_crypto_hash(GRUB_MD_SHA512, hash, aad, aad_offset);
+ grub_free(aad);
+
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(BP_GET_BYTEORDER(bp)))
+ {
+ grub_zfs_byteswap_u64(&hash[0]);
+ grub_zfs_byteswap_u64(&hash[1]);
+ }
+
+ if (grub_crypto_memcmp(&zc.zc_word[2], hash, 8) != 0)
+ {
+ grub_free (*buf);
+ *buf = NULL;
+ grub_dprintf ("zfs", "actual hash "
+ "%016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx \n",
+ (unsigned long long) hash[0],
+ (unsigned long long) hash[1],
+ (unsigned long long) hash[2],
+ (unsigned long long) hash[3],
+ (unsigned long long) hash[4],
+ (unsigned long long) hash[5],
+ (unsigned long long) hash[6],
+ (unsigned long long) hash[7]);
+ grub_dprintf ("zfs", "expected hash %016llx %016llx %016llx %016llx\n",
+ (unsigned long long) zc.zc_word[0],
+ (unsigned long long) zc.zc_word[1],
+ (unsigned long long) zc.zc_word[2],
+ (unsigned long long) zc.zc_word[3]);
+ return grub_error (GRUB_ERR_BAD_FS, N_("hash verification failed"));
+ }
+ }
+
return GRUB_ERR_NONE;
}
@@ -3519,8 +3841,8 @@ load_zap_key (const void *name, grub_size_t namelen, const void *val_in,
ctx->subvol->keyring[ctx->keyn].algo =
grub_le_to_cpu64 (*(grub_uint64_t *) val_in);
ctx->subvol->keyring[ctx->keyn].cipher =
- grub_zfs_load_key (val_in, nelem, ctx->salt,
- ctx->subvol->keyring[ctx->keyn].algo);
+ grub_zfs_decrypt->load_key_oracle (val_in, nelem, ctx->salt,
+ ctx->subvol->keyring[ctx->keyn].algo);
ctx->keyn++;
return 0;
}
@@ -3587,6 +3909,82 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_dprintf ("zfs", "alive\n");
+ grub_uint64_t crypt_obj;
+
+ err = zap_lookup (dn, "com.datto:crypto_key_obj", &crypt_obj, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ crypt_obj = 0;
+ }
+
+ grub_dprintf("zfs", "crypt obj = %lld\n", (long long) crypt_obj);
+ subvol->is_datto_encrypted = crypt_obj != 0;
+
+ if (grub_zfs_decrypt && crypt_obj)
+ {
+ dnode_phys_t crypt_dn;
+ err = dnode_get (&(data->mos), crypt_obj, 0xc4,
+ &crypt_dn, data);
+ if (err)
+ {
+ grub_free (fsname);
+ grub_free (snapname);
+ return err;
+ }
+
+ err = dnode_get (&(data->mos), crypt_obj, 0 /* ?? */,
+ &crypt_dn, data);
+ struct grub_zfs_crypt_datto_data crypt_datto_data = { 0 };
+ grub_uint64_t pbkdf2iters = 0, pbkdf2salt = 0, guid = 0, algo = 0, version = 0;
+ zap_iterate (&crypt_dn, 1, fill_crypt_datto_data, &crypt_datto_data, data);
+
+ err = zap_lookup (&crypt_dn, "pbkdf2iters", &pbkdf2iters, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ pbkdf2iters = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "DSL_CRYPTO_GUID", &guid, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ guid = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "DSL_CRYPTO_SUITE", &algo, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ algo = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "DSL_CRYPTO_VERSION", &version, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ version = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "pbkdf2salt", &pbkdf2salt, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ pbkdf2salt = 0;
+ }
+
+ pbkdf2salt = grub_cpu_to_le64(pbkdf2salt);
+
+ subvol->key_datto = grub_zfs_decrypt->load_key_datto(crypt_datto_data.iv, crypt_datto_data.ivlen,
+ crypt_datto_data.mac, crypt_datto_data.maclen,
+ crypt_datto_data.master, crypt_datto_data.masterlen,
+ crypt_datto_data.hmac, crypt_datto_data.hmaclen,
+ (const grub_uint8_t *) &pbkdf2salt, sizeof (pbkdf2salt),
+ pbkdf2iters, guid, algo, version);
+ }
+
+
headobj = ((dsl_dir_phys_t *) DN_BONUS (dn))->dd_head_dataset_obj;
err = dnode_get (&(data->mos), headobj, 0, &subvol->mdn, data);
@@ -3600,7 +3998,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_dprintf("zfs", "keychain obj = %lld\n", (long long) keychainobj);
- if (grub_zfs_decrypt && keychainobj)
+ if (grub_zfs_decrypt && !subvol->is_datto_encrypted && keychainobj)
{
struct dnode_get_fullpath_ctx ctx = {
.subvol = subvol,
diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c
index 535fd4065..e202f4265 100644
--- a/grub-core/fs/zfs/zfscrypt.c
+++ b/grub-core/fs/zfs/zfscrypt.c
@@ -46,8 +46,9 @@
GRUB_MOD_LICENSE ("GPLv3+");
/*
- Mostly based on following article:
+ Oracle part is mostly based on following article:
https://blogs.oracle.com/darren/entry/zfs_encryption_what_is_on
+ Datto part is based on comments in OpenZFS. No actal code has been used
*/
enum grub_zfs_algo
@@ -56,7 +57,26 @@ enum grub_zfs_algo
GRUB_ZFS_ALGO_GCM,
};
-struct grub_zfs_key
+struct datto_algo {
+ grub_size_t wrapkeylen;
+ grub_size_t cryptkeylen;
+ grub_size_t masterkeylen;
+ enum grub_zfs_algo used_algo;
+} datto_algos[] = {
+ { 0 },
+ { 0 },
+ { 0 },
+ { 32, 16, 16, GRUB_ZFS_ALGO_CCM },
+ { 32, 24, 24, GRUB_ZFS_ALGO_CCM },
+ { 32, 32, 32, GRUB_ZFS_ALGO_CCM },
+ { 32, 16, 16, GRUB_ZFS_ALGO_GCM },
+ { 32, 24, 24, GRUB_ZFS_ALGO_GCM },
+ { 32, 32, 32, GRUB_ZFS_ALGO_GCM },
+};
+#define MAX_WRAPCIPHERTEXTLEN 96
+#define MAX_MACLEN 16
+
+struct grub_zfs_key_oracle
{
grub_uint64_t algo;
grub_uint8_t enc_nonce[13];
@@ -102,26 +122,81 @@ grub_zfs_add_key (grub_uint8_t *key_in,
static gcry_err_code_t
grub_ccm_decrypt (grub_crypto_cipher_handle_t cipher,
- grub_uint8_t *out, const grub_uint8_t *in,
- grub_size_t psize,
+ grub_uint8_t *out,
+ const grub_uint8_t *in, grub_size_t psize,
+ const grub_uint8_t *aad, grub_size_t aadsize,
void *mac_out, const void *nonce,
- unsigned l, unsigned m)
+ unsigned noncelen, unsigned m)
{
grub_uint8_t iv[16];
grub_uint8_t mul[16];
grub_uint32_t mac[4];
- unsigned i, j;
+ unsigned i, j, l = 15 - noncelen, aprefixlen = 0;
gcry_err_code_t err;
+ grub_uint8_t aprefix[16] = { 0 };
- grub_memcpy (iv + 1, nonce, 15 - l);
+ grub_memcpy (iv + 1, nonce, noncelen);
- iv[0] = (l - 1) | (((m-2) / 2) << 3);
+ iv[0] = (l - 1) | (((m-2) / 2) << 3) | ((aadsize != 0) << 6);
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;
+ if (aadsize == 0)
+ aprefixlen = 0;
+ else if (aadsize <= 0xFEFF)
+ {
+ aprefixlen = 2;
+ aprefix[0] = aadsize >> 8;
+ aprefix[1] = aadsize;
+ }
+#if GRUB_CPU_SIZEOF_VOID_P == 8
+ else if ((aadsize >> 32) == 0)
+#endif
+ {
+ aprefixlen = 6;
+ aprefix[0] = 0xff;
+ aprefix[1] = 0xfe;
+ grub_set_unaligned32(aprefix + 2, grub_cpu_to_be32(aadsize));
+ }
+#if GRUB_CPU_SIZEOF_VOID_P == 8
+ else
+ {
+ aprefixlen = 10;
+ aprefix[0] = 0xff;
+ aprefix[1] = 0xff;
+ grub_set_unaligned64(aprefix + 2, grub_cpu_to_be64(aadsize));
+ }
+#endif
+
+ if (aadsize != 0)
+ {
+ grub_size_t ablocks = (aadsize + aprefixlen + 15) / 16;
+ grub_size_t first_block_datalen = 16 - aprefixlen;
+ if (first_block_datalen > aadsize)
+ first_block_datalen = aadsize;
+ grub_memcpy (aprefix + aprefixlen, aad, first_block_datalen);
+
+ grub_crypto_xor (mac, mac, aprefix, 16);
+ err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16);
+ if (err)
+ return err;
+
+ for (i = 1; i < ablocks; i++)
+ {
+ grub_size_t csize, instart = (i - 1) * 16 + first_block_datalen;
+ csize = 16;
+ if (csize > aadsize - instart)
+ csize = aadsize - instart;
+ grub_crypto_xor (mac, mac, aad + instart, csize);
+ err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16);
+ if (err)
+ return err;
+ }
+ }
+
iv[0] = l - 1;
for (i = 0; i < (psize + 15) / 16; i++)
@@ -187,6 +262,8 @@ static gcry_err_code_t
grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
grub_uint8_t *out, const grub_uint8_t *in,
grub_size_t psize,
+ const grub_uint8_t *aad,
+ grub_size_t aadsize,
void *mac_out, const void *nonce,
unsigned nonce_len, unsigned m)
{
@@ -213,7 +290,7 @@ grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
else
{
grub_memset (iv, 0, sizeof (iv));
- grub_memcpy (iv, nonce, nonce_len);
+ grub_memcpy (iv, nonce, nonce_len > sizeof (iv) ? sizeof (iv) : nonce_len);
grub_gcm_mul (iv, h);
iv[15] ^= nonce_len * 8;
grub_gcm_mul (iv, h);
@@ -223,6 +300,16 @@ grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
if (err)
return err;
+ for (i = 0; i < (aadsize + 15) / 16; i++)
+ {
+ grub_size_t csize;
+ csize = 16;
+ if (csize > aadsize - 16 * i)
+ csize = aadsize - 16 * i;
+ grub_crypto_xor (mac, mac, aad + 16 * i, csize);
+ grub_gcm_mul (mac, h);
+ }
+
for (i = 0; i < (psize + 15) / 16; i++)
{
grub_size_t csize;
@@ -244,6 +331,8 @@ grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
}
for (j = 0; j < 8; j++)
mac[15 - j] ^= ((((grub_uint64_t) psize) * 8) >> (8 * j));
+ for (j = 0; j < 8; j++)
+ mac[7 - j] ^= ((((grub_uint64_t) aadsize) * 8) >> (8 * j));
grub_gcm_mul (mac, h);
if (mac_out)
@@ -257,30 +346,33 @@ static gcry_err_code_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,
+ const grub_uint8_t *aad,
+ grub_size_t aadsize,
void *mac_out, const void *nonce,
unsigned l, unsigned m)
{
switch (algo)
{
- case 0:
+ case GRUB_ZFS_ALGO_CCM:
return grub_ccm_decrypt (cipher, out, in, psize,
- mac_out, nonce, l, m);
- case 1:
+ aad, aadsize, mac_out, nonce,
+ l <= 15 ? l : 0, m);
+ case GRUB_ZFS_ALGO_GCM:
return grub_gcm_decrypt (cipher, out, in, psize,
- mac_out, nonce,
- 15 - l, m);
+ aad, aadsize, mac_out, nonce,
+ l <= 15 ? l : 0, m);
default:
return GPG_ERR_CIPHER_ALGO;
}
}
static grub_err_t
-grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
- grub_uint64_t algo,
- const void *nonce,
- char *buf, grub_size_t size,
- const grub_uint32_t *expected_mac,
- grub_zfs_endian_t endian)
+grub_zfs_decrypt_oracle (grub_crypto_cipher_handle_t cipher,
+ grub_uint64_t algo,
+ const 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;
@@ -298,8 +390,8 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
err = algo_decrypt (cipher, algo,
(grub_uint8_t *) buf,
(grub_uint8_t *) buf,
- size, mac,
- sw + 1, 3, 12);
+ size, NULL, 0, mac,
+ sw, 12, 12);
if (err)
return grub_crypto_gcry_error (err);
@@ -310,11 +402,73 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
return GRUB_ERR_NONE;
}
+static grub_err_t
+grub_zfs_decrypt_datto (const struct grub_zfs_datto_key *key,
+ const grub_uint32_t *nonce, grub_uint64_t salt,
+ char *buf, grub_size_t size,
+ const char *aadbuf, grub_size_t aadsize,
+ const grub_uint64_t *expected_mac,
+ grub_zfs_endian_t endian)
+{
+ grub_uint64_t mac[2];
+ unsigned i;
+ grub_uint8_t extractkey[64];
+ grub_uint8_t expandkey[64];
+ grub_uint8_t t[9];
+ gcry_err_code_t err;
+ grub_crypto_cipher_handle_t cipher;
+
+ if (!key)
+ return grub_error (GRUB_ERR_ACCESS_DENIED,
+ N_("no decryption key available"));
+
+ /* A special case of HKDF with 512 > keylen. */
+ err = grub_crypto_hmac_buffer (GRUB_MD_SHA512,
+ "", 0,
+ key->master_key, key->master_keylen,
+ extractkey);
+ if (err)
+ return grub_crypto_gcry_error (err);
+
+ grub_set_unaligned64(t, grub_cpu_to_zfs64(salt, endian));
+ t[8] = 1;
+ err = grub_crypto_hmac_buffer (GRUB_MD_SHA512,
+ extractkey, 64,
+ t, 9, expandkey);
+ if (err)
+ return grub_crypto_gcry_error (err);
+
+ cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
+ if (!cipher)
+ return grub_crypto_gcry_error (err);
+ err = grub_crypto_cipher_set_key (cipher, expandkey, datto_algos[key->algo].cryptkeylen);
+ if (err)
+ {
+ grub_crypto_cipher_close (cipher);
+ return grub_crypto_gcry_error (err);
+ }
+
+ err = algo_decrypt (cipher, datto_algos[key->algo].used_algo,
+ (grub_uint8_t *) buf,
+ (grub_uint8_t *) buf,
+ size, (grub_uint8_t *) aadbuf, aadsize, mac,
+ nonce, 12, 16);
+ grub_crypto_cipher_close (cipher);
+ if (err)
+ return grub_crypto_gcry_error (err);
+
+ for (i = 0; i < 2; i++)
+ if (grub_zfs_to_cpu64 (expected_mac[i], endian)
+ != grub_le_to_cpu64 (mac[i]))
+ grub_dprintf("zfs", N_("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)
+grub_zfs_load_key_oracle (const struct grub_zfs_key_oracle *key,
+ grub_size_t keysize,
+ grub_uint64_t salt,
+ grub_uint64_t algo)
{
unsigned keylen;
struct grub_zfs_wrap_key *wrap_key;
@@ -373,7 +527,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
}
err = algo_decrypt (cipher, algo, decrypted, key->unknown_purpose_key, 32,
- mac, key->unknown_purpose_nonce, 2, 16);
+ NULL, 0, mac, key->unknown_purpose_nonce, 13, 16);
if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16)
!= 0))
{
@@ -383,8 +537,8 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
continue;
}
- err = algo_decrypt (cipher, algo, decrypted, key->enc_key, keylen, mac,
- key->enc_nonce, 2, 16);
+ err = algo_decrypt (cipher, algo, decrypted, key->enc_key, keylen, NULL, 0,
+ mac, key->enc_nonce, 13, 16);
if (err || grub_crypto_memcmp (mac, key->enc_key + keylen, 16) != 0)
{
grub_dprintf ("zfs", "key loading failed\n");
@@ -413,6 +567,119 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
return NULL;
}
+static struct grub_zfs_datto_key
+grub_zfs_load_key_datto (const grub_uint8_t *iv, grub_size_t ivlen,
+ const grub_uint8_t *mac_in, grub_size_t mac_inlen,
+ const grub_uint8_t *master, grub_size_t masterlen,
+ const grub_uint8_t *hmac, grub_size_t hmaclen,
+ const grub_uint8_t *pbkdf2salt, grub_size_t pbkdf2saltlen,
+ grub_uint64_t pbkdf2iters, grub_uint64_t guid, grub_uint64_t algo, grub_uint64_t version)
+{
+ struct grub_zfs_wrap_key *wrap_key;
+ struct grub_zfs_datto_key ret = { 0 };
+
+ if (algo <= 2 || algo >= ARRAY_SIZE(datto_algos))
+ {
+ grub_error(GRUB_ERR_BAD_FS, "unsupported crypto algo");
+ return ret;
+ }
+
+ /* Note: if last two ever become variable they need to be checkecked as matching algo. Especially mac_inlen. */
+ if (masterlen < datto_algos[algo].masterkeylen || hmaclen != 64 || mac_inlen != 16)
+ {
+ grub_error(GRUB_ERR_BAD_FS, "crypto keys are invalid");
+ return ret;
+ }
+
+ masterlen = datto_algos[algo].masterkeylen;
+
+ grub_uint8_t ciphertext[MAX_WRAPCIPHERTEXTLEN];
+ grub_uint8_t plaintext[MAX_WRAPCIPHERTEXTLEN];
+ grub_uint8_t mac_computed[MAX_MACLEN];
+ struct {
+ grub_uint64_t guid;
+ grub_uint64_t algo;
+ grub_uint64_t version;
+ } aad = {
+ grub_cpu_to_le64(guid),
+ grub_cpu_to_le64(algo),
+ grub_cpu_to_le64(version)
+ };
+
+ grub_memcpy(ciphertext, master, masterlen);
+ grub_memcpy(ciphertext + masterlen, hmac, hmaclen);
+
+ for (wrap_key = zfs_wrap_keys; wrap_key; wrap_key = wrap_key->next)
+ {
+ grub_crypto_cipher_handle_t cipher;
+ grub_uint8_t wrap_key_real[32] = { 0 };
+ gcry_err_code_t err = 0;
+
+ cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
+ if (!cipher)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return ret;
+ }
+ 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 < datto_algos[algo].wrapkeylen ? wrap_key->keylen : datto_algos[algo].wrapkeylen);
+ else
+ // TODO: PBKDF2
+ err = grub_crypto_pbkdf2 (GRUB_MD_SHA1,
+ (const grub_uint8_t *) wrap_key->key,
+ wrap_key->keylen,
+ pbkdf2salt, pbkdf2saltlen,
+ pbkdf2iters, wrap_key_real, datto_algos[algo].wrapkeylen);
+
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_crypto_cipher_close (cipher);
+ continue;
+ }
+
+ err = grub_crypto_cipher_set_key (cipher, wrap_key_real, datto_algos[algo].wrapkeylen);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_crypto_cipher_close (cipher);
+ continue;
+ }
+
+ err = algo_decrypt (cipher, datto_algos[algo].used_algo,
+ plaintext, ciphertext, masterlen + hmaclen,
+ (grub_uint8_t *) &aad, sizeof(aad),
+ mac_computed, iv, ivlen, mac_inlen);
+ if (err || (grub_crypto_memcmp (mac_computed, mac_in, mac_inlen) != 0))
+ {
+ grub_dprintf ("zfs", "key loading failed\n");
+ grub_errno = GRUB_ERR_NONE;
+ grub_crypto_cipher_close (cipher);
+ continue;
+ }
+
+ ret.master_keylen = masterlen;
+ ret.master_key = grub_malloc(ret.master_keylen);
+ if (!ret.master_key)
+ return ret;
+ grub_memcpy(ret.master_key, plaintext, masterlen);
+ ret.hmac_key = grub_malloc(hmaclen);
+ if (!ret.hmac_key)
+ {
+ grub_free(ret.master_key);
+ ret.master_key = NULL;
+ return ret;
+ }
+ ret.algo = algo;
+ grub_memcpy(ret.hmac_key, plaintext + masterlen, hmaclen);
+ return ret;
+ }
+ return ret;
+}
+
static const struct grub_arg_option options[] =
{
{"raw", 'r', 0, N_("Assume input is raw."), 0, 0},
@@ -471,12 +738,17 @@ grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args)
&& !ctxt->state[1].set));
}
+struct grub_zfs_decryptor grub_zfs_decrypt_real = {
+ .decrypt_oracle = grub_zfs_decrypt_oracle,
+ .decrypt_datto = grub_zfs_decrypt_datto,
+ .load_key_oracle = grub_zfs_load_key_oracle,
+ .load_key_datto = grub_zfs_load_key_datto,
+};
static grub_extcmd_t cmd_key;
GRUB_MOD_INIT(zfscrypt)
{
- grub_zfs_decrypt = grub_zfs_decrypt_real;
- grub_zfs_load_key = grub_zfs_load_key_real;
+ grub_zfs_decrypt = &grub_zfs_decrypt_real;
cmd_key = grub_register_extcmd ("zfskey", grub_cmd_zfs_key, 0,
N_("[-h|-p|-r] [FILE]"),
N_("Import ZFS wrapping key stored in FILE."),
@@ -486,6 +758,5 @@ GRUB_MOD_INIT(zfscrypt)
GRUB_MOD_FINI(zfscrypt)
{
grub_zfs_decrypt = 0;
- grub_zfs_load_key = 0;
grub_unregister_extcmd (cmd_key);
}
diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h
index 0c5c40a73..fbac368b0 100644
--- a/include/grub/zfs/zfs.h
+++ b/include/grub/zfs/zfs.h
@@ -147,20 +147,46 @@ 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,
- const 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);
-
+struct grub_zfs_key_oracle;
+
+struct grub_zfs_datto_key
+{
+ grub_uint8_t *master_key;
+ grub_size_t master_keylen;
+ grub_uint8_t *hmac_key;
+ grub_uint64_t algo;
+};
+
+struct grub_zfs_decryptor
+{
+ grub_err_t (*decrypt_oracle) (grub_crypto_cipher_handle_t cipher,
+ grub_uint64_t algo,
+ const void *nonce,
+ char *buf, grub_size_t size,
+ const grub_uint32_t *expected_mac,
+ grub_zfs_endian_t endian);
+
+ grub_crypto_cipher_handle_t (*load_key_oracle) (const struct grub_zfs_key_oracle *key,
+ grub_size_t keysize,
+ grub_uint64_t salt,
+ grub_uint64_t algo);
+
+ grub_err_t (*decrypt_datto) (const struct grub_zfs_datto_key *key,
+ const grub_uint32_t *nonce, grub_uint64_t salt,
+ char *buf, grub_size_t size,
+ const char *aadbuf, grub_size_t aadsize,
+ const grub_uint64_t *expected_mac,
+ grub_zfs_endian_t endian);
+
+ struct grub_zfs_datto_key (*load_key_datto) (const grub_uint8_t *iv, grub_size_t ivlen,
+ const grub_uint8_t *mac, grub_size_t maclen,
+ const grub_uint8_t *master, grub_size_t masterlen,
+ const grub_uint8_t *hmac, grub_size_t hmaclen,
+ const grub_uint8_t *pbkdf2salt, grub_size_t pbkdf2saltlen,
+ grub_uint64_t pbkdf2iters, grub_uint64_t guid, grub_uint64_t algo, grub_uint64_t version);
+};
+
+extern struct grub_zfs_decryptor *grub_zfs_decrypt;
#endif /* ! GRUB_ZFS_HEADER */
--
2.49.0
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 8+ messages in thread