Support ZFS subvolumes with multiple keys

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-11-06 17:13:38 +01:00
parent ed746949af
commit d99b3726e5

View file

@ -167,7 +167,12 @@ struct subvolume
dnode_end_t mdn;
grub_uint64_t obj;
grub_uint64_t case_insensitive;
grub_crypto_cipher_handle_t cipher;
grub_size_t nkeys;
struct
{
grub_crypto_cipher_handle_t cipher;
grub_uint64_t txg;
} *keyring;
};
struct grub_zfs_data
@ -1503,9 +1508,37 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
if (!grub_zfs_decrypt)
err = grub_error (GRUB_ERR_BAD_FS, "zfscrypt module not loaded");
else
err = grub_zfs_decrypt (data->subvol.cipher, &(bp)->blk_dva[encrypted],
compbuf, psize, ((grub_uint32_t *) &zc + 5),
endian);
{
unsigned i, besti = 0;
grub_uint64_t bestval = 0;
for (i = 0; i < data->subvol.nkeys; i++)
if (data->subvol.keyring[i].txg <= grub_zfs_to_cpu64 (bp->blk_birth,
endian)
&& data->subvol.keyring[i].txg > bestval)
{
besti = i;
bestval = data->subvol.keyring[i].txg;
}
if (bestval == 0)
{
grub_free (compbuf);
*buf = NULL;
grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
grub_zfs_to_cpu64 (bp->blk_birth,
endian));
return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
}
grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T
", %p) for txg %" PRIxGRUB_UINT64_T "\n",
besti, data->subvol.keyring[besti].txg,
data->subvol.keyring[besti].cipher,
grub_zfs_to_cpu64 (bp->blk_birth,
endian));
err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
&(bp)->blk_dva[encrypted],
compbuf, psize, ((grub_uint32_t *) &zc + 5),
endian);
}
if (err)
{
grub_free (compbuf);
@ -1896,7 +1929,9 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
/* XXX */
static int
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
int NESTED_FUNC_ATTR (*hook) (const char *name,
grub_size_t name_elem_length,
int NESTED_FUNC_ATTR (*hook) (const void *name,
grub_size_t name_length,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize),
@ -1972,17 +2007,18 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
continue;
buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
+ 1);
* name_elem_length + 1);
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk,
endian),
grub_zfs_to_cpu16 (le->le_name_length,
endian), buf))
endian)
* name_elem_length, buf))
{
grub_free (buf);
continue;
}
buf[le->le_name_length] = 0;
buf[le->le_name_length * name_elem_length] = 0;
val_length = ((int) le->le_value_length
* (int) le->le_int_size);
@ -1997,7 +2033,8 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
continue;
}
if (hook (buf, val, le->le_value_length, le->le_int_size))
if (hook (buf, le->le_name_length,
val, le->le_value_length, le->le_int_size))
return 1;
grub_free (buf);
grub_free (val);
@ -2069,12 +2106,14 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
int ret;
grub_zfs_endian_t endian;
auto int NESTED_FUNC_ATTR transform (const char *name,
auto int NESTED_FUNC_ATTR transform (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
int NESTED_FUNC_ATTR transform (const char *name,
int NESTED_FUNC_ATTR transform (const void *name,
grub_size_t namelen __attribute__ ((unused)),
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize)
@ -2104,7 +2143,7 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
{
grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */
ret = fzap_iterate (zap_dnode, zapbuf, transform, data);
ret = fzap_iterate (zap_dnode, zapbuf, 1, transform, data);
grub_free (zapbuf);
return ret;
}
@ -2114,7 +2153,9 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
static int
zap_iterate (dnode_end_t * zap_dnode,
int NESTED_FUNC_ATTR (*hook) (const char *name,
grub_size_t nameelemlen,
int NESTED_FUNC_ATTR (*hook) (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize),
@ -2145,7 +2186,7 @@ zap_iterate (dnode_end_t * zap_dnode,
{
grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */
ret = fzap_iterate (zap_dnode, zapbuf, hook, data);
ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, data);
grub_free (zapbuf);
return ret;
}
@ -2660,17 +2701,41 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_uint64_t keychainobj;
grub_uint64_t salt;
grub_err_t err;
int keyn = 0;
auto int NESTED_FUNC_ATTR iterate_zap_key (const char *name,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
int NESTED_FUNC_ATTR iterate_zap_key (const char *name __attribute__ ((unused)),
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize)
auto int NESTED_FUNC_ATTR count_zap_keys (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)),
grub_size_t namelen __attribute__ ((unused)),
const void *val_in __attribute__ ((unused)),
grub_size_t nelem __attribute__ ((unused)),
grub_size_t elemsize __attribute__ ((unused)))
{
subvol->nkeys++;
return 0;
}
auto int NESTED_FUNC_ATTR load_zap_key (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
int NESTED_FUNC_ATTR load_zap_key (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize)
{
if (namelen != 1)
{
grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n",
namelen);
return 0;
}
if (elemsize != 1)
{
grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n",
@ -2678,7 +2743,9 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
return 0;
}
subvol->cipher = grub_zfs_load_key (val_in, nelem, salt);
subvol->keyring[keyn].txg = grub_be_to_cpu64 (*(grub_uint64_t *) name);
subvol->keyring[keyn].cipher = grub_zfs_load_key (val_in, nelem, salt);
keyn++;
return 0;
}
@ -2782,7 +2849,16 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_free (snapname);
return err;
}
zap_iterate (&keychain_dn, iterate_zap_key, data);
subvol->nkeys = 0;
zap_iterate (&keychain_dn, 8, count_zap_keys, data);
subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0]));
if (!subvol->keyring)
{
grub_free (fsname);
grub_free (snapname);
return err;
}
zap_iterate (&keychain_dn, 8, load_zap_key, data);
}
if (snapname)
@ -3087,7 +3163,9 @@ zfs_unmount (struct grub_zfs_data *data)
grub_free (data->dnode_buf);
grub_free (data->dnode_mdn);
grub_free (data->file_buf);
grub_crypto_cipher_close (data->subvol.cipher);
for (i = 0; i < data->subvol.nkeys; i++)
grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
grub_free (data->subvol.keyring);
grub_free (data);
}