Commit 90766d9d authored by Maxim Levitsky's avatar Maxim Levitsky Committed by Max Reitz
Browse files

block/qcow2: extend qemu-img amend interface with crypto options



Now that we have all the infrastructure in place,
wire it in the qcow2 driver and expose this to the user.

Signed-off-by: default avatarMaxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: default avatarDaniel P. Berrangé <berrange@redhat.com>
Reviewed-by: default avatarMax Reitz <mreitz@redhat.com>
Message-Id: <20200608094030.670121-9-mlevitsk@redhat.com>
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent bbfdae91
Loading
Loading
Loading
Loading
+62 −9
Original line number Diff line number Diff line
@@ -176,6 +176,19 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
    return ret;
}

static QDict*
qcow2_extract_crypto_opts(QemuOpts *opts, const char *fmt, Error **errp)
{
    QDict *cryptoopts_qdict;
    QDict *opts_qdict;

    /* Extract "encrypt." options into a qdict */
    opts_qdict = qemu_opts_to_qdict(opts, NULL);
    qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
    qobject_unref(opts_qdict);
    qdict_put_str(cryptoopts_qdict, "format", fmt);
    return cryptoopts_qdict;
}

/*
 * read qcow2 extension and fill bs
@@ -4860,16 +4873,9 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,

    if (has_luks) {
        g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
        QDict *opts_qdict;
        QDict *cryptoopts;
        QDict *cryptoopts = qcow2_extract_crypto_opts(opts, "luks", errp);
        size_t headerlen;

        opts_qdict = qemu_opts_to_qdict(opts, NULL);
        qdict_extract_subqdict(opts_qdict, &cryptoopts, "encrypt.");
        qobject_unref(opts_qdict);

        qdict_put_str(cryptoopts, "format", "luks");

        create_opts = block_crypto_create_opts_init(cryptoopts, errp);
        qobject_unref(cryptoopts);
        if (!create_opts) {
@@ -5273,6 +5279,7 @@ typedef enum Qcow2AmendOperation {
    QCOW2_NO_OPERATION = 0,

    QCOW2_UPGRADING,
    QCOW2_UPDATING_ENCRYPTION,
    QCOW2_CHANGING_REFCOUNT_ORDER,
    QCOW2_DOWNGRADING,
} Qcow2AmendOperation;
@@ -5354,6 +5361,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
    int ret;
    QemuOptDesc *desc = opts->list->desc;
    Qcow2AmendHelperCBInfo helper_cb_info;
    bool encryption_update = false;

    while (desc && desc->name) {
        if (!qemu_opt_find(opts, desc->name)) {
@@ -5380,6 +5388,18 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
            backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
        } else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FMT)) {
            backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
        } else if (g_str_has_prefix(desc->name, "encrypt.")) {
            if (!s->crypto) {
                error_setg(errp,
                           "Can't amend encryption options - encryption not present");
                return -EINVAL;
            }
            if (s->crypt_method_header != QCOW_CRYPT_LUKS) {
                error_setg(errp,
                           "Only LUKS encryption options can be amended");
                return -ENOTSUP;
            }
            encryption_update = true;
        } else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
            lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS,
                                               lazy_refcounts);
@@ -5422,7 +5442,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
        .original_status_cb = status_cb,
        .original_cb_opaque = cb_opaque,
        .total_operations = (new_version != old_version)
                          + (s->refcount_bits != refcount_bits)
                          + (s->refcount_bits != refcount_bits) +
                            (encryption_update == true)
    };

    /* Upgrade first (some features may require compat=1.1) */
@@ -5435,6 +5456,33 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
        }
    }

    if (encryption_update) {
        QDict *amend_opts_dict;
        QCryptoBlockAmendOptions *amend_opts;

        helper_cb_info.current_operation = QCOW2_UPDATING_ENCRYPTION;
        amend_opts_dict = qcow2_extract_crypto_opts(opts, "luks", errp);
        if (!amend_opts_dict) {
            return -EINVAL;
        }
        amend_opts = block_crypto_amend_opts_init(amend_opts_dict, errp);
        qobject_unref(amend_opts_dict);
        if (!amend_opts) {
            return -EINVAL;
        }
        ret = qcrypto_block_amend_options(s->crypto,
                                          qcow2_crypto_hdr_read_func,
                                          qcow2_crypto_hdr_write_func,
                                          bs,
                                          amend_opts,
                                          force,
                                          errp);
        qapi_free_QCryptoBlockAmendOptions(amend_opts);
        if (ret < 0) {
            return ret;
        }
    }

    if (s->refcount_bits != refcount_bits) {
        int refcount_order = ctz32(refcount_bits);

@@ -5694,6 +5742,11 @@ static QemuOptsList qcow2_amend_opts = {
    .name = "qcow2-amend-opts",
    .head = QTAILQ_HEAD_INITIALIZER(qcow2_amend_opts.head),
    .desc = {
        BLOCK_CRYPTO_OPT_DEF_LUKS_STATE("encrypt."),
        BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT("encrypt."),
        BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET("encrypt."),
        BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET("encrypt."),
        BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."),
        QCOW_COMMON_OPTIONS,
        { /* end of list */ }
    }
+45 −0
Original line number Diff line number Diff line
@@ -645,6 +645,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -656,6 +661,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -667,6 +677,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -678,6 +693,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -689,6 +709,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -700,6 +725,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -711,6 +741,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -722,6 +757,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size
@@ -750,6 +790,11 @@ Amend options for 'qcow2':
  compat=<str>           - Compatibility level (v2 [0.10] or v3 [1.1])
  data_file=<str>        - File name of an external data file
  data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
  encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
  encrypt.keyslot=<num>  - Select a single keyslot to modify explicitly
  encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
  encrypt.old-secret=<str> - Select all keyslots that match this password
  encrypt.state=<str>    - Select new state of affected keyslots (active/inactive)
  lazy_refcounts=<bool (on/off)> - Postpone refcount updates
  refcount_bits=<num>    - Width of a reference count entry in bits
  size=<size>            - Virtual disk size