qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v6 02/14] qcrypto/luks: implement encryption key management


From: Max Reitz
Subject: Re: [PATCH v6 02/14] qcrypto/luks: implement encryption key management
Date: Thu, 14 May 2020 13:56:50 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0

On 10.05.20 15:40, Maxim Levitsky wrote:
> Next few patches will expose that functionality to the user.
> 
> Signed-off-by: Maxim Levitsky <address@hidden>
> Reviewed-by: Daniel P. Berrangé <address@hidden>
> ---
>  crypto/block-luks.c | 395 +++++++++++++++++++++++++++++++++++++++++++-
>  qapi/crypto.json    |  61 ++++++-
>  2 files changed, 452 insertions(+), 4 deletions(-)
> 
> diff --git a/crypto/block-luks.c b/crypto/block-luks.c
> index 4861db810c..967d382882 100644
> --- a/crypto/block-luks.c
> +++ b/crypto/block-luks.c

[...]

> @@ -1069,6 +1076,119 @@ qcrypto_block_luks_find_key(QCryptoBlock *block,
>      return -1;
>  }
>  
> +/*
> + * Returns true if a slot i is marked as active
> + * (contains encrypted copy of the master key)
> + */
> +static bool
> +qcrypto_block_luks_slot_active(const QCryptoBlockLUKS *luks,
> +                               unsigned int slot_idx)
> +{
> +    uint32_t val = luks->header.key_slots[slot_idx].active;
> +    return val ==  QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED;

One space too many after the ==.

[...]

> +/*
> + * Erases an keyslot given its index
> + * Returns:
> + *    0 if the keyslot was erased successfully
> + *   -1 if a error occurred while erasing the keyslot
> + *
> + */
> +static int
> +qcrypto_block_luks_erase_key(QCryptoBlock *block,
> +                             unsigned int slot_idx,
> +                             QCryptoBlockWriteFunc writefunc,
> +                             void *opaque,
> +                             Error **errp)
> +{
> +    QCryptoBlockLUKS *luks = block->opaque;
> +    QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx];
> +    g_autofree uint8_t *garbagesplitkey = NULL;
> +    size_t splitkeylen = luks->header.master_key_len * slot->stripes;

This accesses header.key_slots[slot_idx] before...

> +    size_t i;
> +    Error *local_err = NULL;
> +    int ret;
> +
> +    assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);

...we assert that slot_idx is in bounds.

I suppose that’s kind of fine, because assertions aren’t meant to fire
either, but this basically makes the assertion useless.

> +    assert(splitkeylen > 0);
> +    garbagesplitkey = g_new0(uint8_t, splitkeylen);
> +
> +    /* Reset the key slot header */
> +    memset(slot->salt, 0, QCRYPTO_BLOCK_LUKS_SALT_LEN);
> +    slot->iterations = 0;
> +    slot->active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED;
> +
> +    ret = qcrypto_block_luks_store_header(block,  writefunc,

Superfluous space after the comma.

> +                                          opaque, &local_err);
> +
> +    if (ret < 0) {
> +        error_propagate(errp, local_err);
> +    }

error_propagate() is a no-op with local_err == NULL, so you could do
without checking @ret (just calling error_propagate() unconditionally).

(But who cares, we need to set @ret anyway, so we might as well check it.)

[...]

> +static int
> +qcrypto_block_luks_amend_add_keyslot(QCryptoBlock *block,
> +                                     QCryptoBlockReadFunc readfunc,
> +                                     QCryptoBlockWriteFunc writefunc,
> +                                     void *opaque,
> +                                     QCryptoBlockAmendOptionsLUKS *opts_luks,
> +                                     bool force,
> +                                     Error **errp)
> +{
> +    QCryptoBlockLUKS *luks = block->opaque;
> +    uint64_t iter_time = opts_luks->has_iter_time ?
> +                         opts_luks->iter_time :
> +                         QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS;
> +    int keyslot;
> +    g_autofree char *old_password = NULL;
> +    g_autofree char *new_password = NULL;
> +    g_autofree uint8_t *master_key = NULL;

(I assume we don’t really care about purging secrets from memory after use)

[...]

> +static int
> +qcrypto_block_luks_amend_erase_keyslots(QCryptoBlock *block,
> +                                        QCryptoBlockReadFunc readfunc,
> +                                        QCryptoBlockWriteFunc writefunc,
> +                                        void *opaque,
> +                                        QCryptoBlockAmendOptionsLUKS 
> *opts_luks,
> +                                        bool force,
> +                                        Error **errp)
> +{

[...]

> +        for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
> +            int rv = qcrypto_block_luks_load_key(block,
> +                                                 i,
> +                                                 old_password,
> +                                                 tmpkey,
> +                                                 readfunc,
> +                                                 opaque,
> +                                                 errp);
> +            if (rv == -1) {
> +                return -1;
> +            } else if (rv == 1) {
> +                bitmap_set(&slots_to_erase_bitmap, i, 1);

We should assert that QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS <=
sizeof(slots_to_erase_bitmap) * 8.  As it is, this looks like a possible
out-of-bounds access on first glance.

[...]

> +static int
> +qcrypto_block_luks_amend_options(QCryptoBlock *block,
> +                                 QCryptoBlockReadFunc readfunc,
> +                                 QCryptoBlockWriteFunc writefunc,
> +                                 void *opaque,
> +                                 QCryptoBlockAmendOptions *options,
> +                                 bool force,
> +                                 Error **errp)
> +{
> +    QCryptoBlockAmendOptionsLUKS *opts_luks = &options->u.luks;
> +
> +    if (opts_luks->state == Q_CRYPTO_BLOCKLUKS_KEYSLOT_STATE_ACTIVE) {

switch { case } might be nicer to catch unhandled cases.  Or else if +
else { g_assert_not_reached() }.

> +        return qcrypto_block_luks_amend_add_keyslot(block, readfunc,
> +                                                    writefunc, opaque,
> +                                                    opts_luks, force, errp);
> +    } else {
> +        return qcrypto_block_luks_amend_erase_keyslots(block, readfunc,
> +                                                       writefunc, opaque,
> +                                                       opts_luks, force, 
> errp);
> +    }
> +}

[...]

> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index aeb6c7ef7b..29276e5e5e 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -1,6 +1,8 @@
>  # -*- Mode: Python -*-
>  #
>  
> +{ 'include': 'common.json' }
> +

Why?  Seems to compile without it just fine.

Max

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]