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; dnode_end_t mdn;
grub_uint64_t obj; grub_uint64_t obj;
grub_uint64_t case_insensitive; 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 struct grub_zfs_data
@ -1503,9 +1508,37 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
if (!grub_zfs_decrypt) if (!grub_zfs_decrypt)
err = grub_error (GRUB_ERR_BAD_FS, "zfscrypt module not loaded"); err = grub_error (GRUB_ERR_BAD_FS, "zfscrypt module not loaded");
else else
err = grub_zfs_decrypt (data->subvol.cipher, &(bp)->blk_dva[encrypted], {
compbuf, psize, ((grub_uint32_t *) &zc + 5), unsigned i, besti = 0;
endian); 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) if (err)
{ {
grub_free (compbuf); grub_free (compbuf);
@ -1896,7 +1929,9 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
/* XXX */ /* XXX */
static int static int
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, 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, const void *val_in,
grub_size_t nelem, grub_size_t nelem,
grub_size_t elemsize), grub_size_t elemsize),
@ -1971,18 +2006,19 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
if (le->le_type != ZAP_CHUNK_ENTRY) if (le->le_type != ZAP_CHUNK_ENTRY)
continue; continue;
buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) 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, if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk, grub_zfs_to_cpu16 (le->le_name_chunk,
endian), endian),
grub_zfs_to_cpu16 (le->le_name_length, grub_zfs_to_cpu16 (le->le_name_length,
endian), buf)) endian)
* name_elem_length, buf))
{ {
grub_free (buf); grub_free (buf);
continue; continue;
} }
buf[le->le_name_length] = 0; buf[le->le_name_length * name_elem_length] = 0;
val_length = ((int) le->le_value_length val_length = ((int) le->le_value_length
* (int) le->le_int_size); * (int) le->le_int_size);
@ -1997,7 +2033,8 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
continue; 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; return 1;
grub_free (buf); grub_free (buf);
grub_free (val); grub_free (val);
@ -2069,12 +2106,14 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
int ret; int ret;
grub_zfs_endian_t endian; 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, const void *val_in,
grub_size_t nelem, grub_size_t nelem,
grub_size_t elemsize); 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, const void *val_in,
grub_size_t nelem, grub_size_t nelem,
grub_size_t elemsize) grub_size_t elemsize)
@ -2104,7 +2143,7 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
{ {
grub_dprintf ("zfs", "fat zap\n"); grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */ /* 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); grub_free (zapbuf);
return ret; return ret;
} }
@ -2114,7 +2153,9 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
static int static int
zap_iterate (dnode_end_t * zap_dnode, 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, const void *val_in,
grub_size_t nelem, grub_size_t nelem,
grub_size_t elemsize), grub_size_t elemsize),
@ -2145,7 +2186,7 @@ zap_iterate (dnode_end_t * zap_dnode,
{ {
grub_dprintf ("zfs", "fat zap\n"); grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */ /* 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); grub_free (zapbuf);
return ret; return ret;
} }
@ -2660,17 +2701,41 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_uint64_t keychainobj; grub_uint64_t keychainobj;
grub_uint64_t salt; grub_uint64_t salt;
grub_err_t err; grub_err_t err;
int keyn = 0;
auto int NESTED_FUNC_ATTR count_zap_keys (const void *name,
auto int NESTED_FUNC_ATTR iterate_zap_key (const char *name, grub_size_t namelen,
const void *val_in, const void *val_in,
grub_size_t nelem, grub_size_t nelem,
grub_size_t elemsize); grub_size_t elemsize);
int NESTED_FUNC_ATTR iterate_zap_key (const char *name __attribute__ ((unused)), int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)),
const void *val_in, grub_size_t namelen __attribute__ ((unused)),
grub_size_t nelem, const void *val_in __attribute__ ((unused)),
grub_size_t elemsize) 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) if (elemsize != 1)
{ {
grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n", 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; 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; return 0;
} }
@ -2782,7 +2849,16 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_free (snapname); grub_free (snapname);
return err; 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) if (snapname)
@ -3087,7 +3163,9 @@ zfs_unmount (struct grub_zfs_data *data)
grub_free (data->dnode_buf); grub_free (data->dnode_buf);
grub_free (data->dnode_mdn); grub_free (data->dnode_mdn);
grub_free (data->file_buf); 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); grub_free (data);
} }