178368575SDaniel P. Berrange /* 278368575SDaniel P. Berrange * QEMU block full disk encryption 378368575SDaniel P. Berrange * 478368575SDaniel P. Berrange * Copyright (c) 2015-2016 Red Hat, Inc. 578368575SDaniel P. Berrange * 678368575SDaniel P. Berrange * This library is free software; you can redistribute it and/or 778368575SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public 878368575SDaniel P. Berrange * License as published by the Free Software Foundation; either 961f3c91aSChetan Pant * version 2.1 of the License, or (at your option) any later version. 1078368575SDaniel P. Berrange * 1178368575SDaniel P. Berrange * This library is distributed in the hope that it will be useful, 1278368575SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of 1378368575SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1478368575SDaniel P. Berrange * Lesser General Public License for more details. 1578368575SDaniel P. Berrange * 1678368575SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public 1778368575SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1878368575SDaniel P. Berrange * 1978368575SDaniel P. Berrange */ 2078368575SDaniel P. Berrange 2178368575SDaniel P. Berrange #include "qemu/osdep.h" 2278368575SDaniel P. Berrange 2378368575SDaniel P. Berrange #include "block/block_int.h" 24f853465aSMarkus Armbruster #include "block/qdict.h" 2578368575SDaniel P. Berrange #include "sysemu/block-backend.h" 2678368575SDaniel P. Berrange #include "crypto/block.h" 2778368575SDaniel P. Berrange #include "qapi/opts-visitor.h" 289af23989SMarkus Armbruster #include "qapi/qapi-visit-crypto.h" 29306a06e5SDaniel P. Berrange #include "qapi/qobject-input-visitor.h" 3078368575SDaniel P. Berrange #include "qapi/error.h" 310b8fa32fSMarkus Armbruster #include "qemu/module.h" 32922a01a0SMarkus Armbruster #include "qemu/option.h" 331bba30daSDaniel Henrique Barboza #include "qemu/cutils.h" 345df022cfSPeter Maydell #include "qemu/memalign.h" 350d8c41daSMichael S. Tsirkin #include "crypto.h" 3678368575SDaniel P. Berrange 3778368575SDaniel P. Berrange typedef struct BlockCrypto BlockCrypto; 3878368575SDaniel P. Berrange 3978368575SDaniel P. Berrange struct BlockCrypto { 4078368575SDaniel P. Berrange QCryptoBlock *block; 41bbfdae91SMaxim Levitsky bool updating_keys; 429ad5c4e7SHyman Huang BdrvChild *header; /* Reference to the detached LUKS header */ 4378368575SDaniel P. Berrange }; 4478368575SDaniel P. Berrange 4578368575SDaniel P. Berrange 4678368575SDaniel P. Berrange static int block_crypto_probe_generic(QCryptoBlockFormat format, 4778368575SDaniel P. Berrange const uint8_t *buf, 4878368575SDaniel P. Berrange int buf_size, 4978368575SDaniel P. Berrange const char *filename) 5078368575SDaniel P. Berrange { 5178368575SDaniel P. Berrange if (qcrypto_block_has_format(format, buf, buf_size)) { 5278368575SDaniel P. Berrange return 100; 5378368575SDaniel P. Berrange } else { 5478368575SDaniel P. Berrange return 0; 5578368575SDaniel P. Berrange } 5678368575SDaniel P. Berrange } 5778368575SDaniel P. Berrange 5878368575SDaniel P. Berrange 59757dda54SAlberto Faria static int block_crypto_read_func(QCryptoBlock *block, 6078368575SDaniel P. Berrange size_t offset, 6178368575SDaniel P. Berrange uint8_t *buf, 6278368575SDaniel P. Berrange size_t buflen, 63e4a3507eSDaniel P. Berrange void *opaque, 6437509233SFam Zheng Error **errp) 6578368575SDaniel P. Berrange { 6678368575SDaniel P. Berrange BlockDriverState *bs = opaque; 679ad5c4e7SHyman Huang BlockCrypto *crypto = bs->opaque; 6878368575SDaniel P. Berrange ssize_t ret; 6978368575SDaniel P. Berrange 701f051dcbSKevin Wolf GLOBAL_STATE_CODE(); 711f051dcbSKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP(); 721f051dcbSKevin Wolf 739ad5c4e7SHyman Huang ret = bdrv_pread(crypto->header ? crypto->header : bs->file, 749ad5c4e7SHyman Huang offset, buflen, buf, 0); 7578368575SDaniel P. Berrange if (ret < 0) { 7678368575SDaniel P. Berrange error_setg_errno(errp, -ret, "Could not read encryption header"); 7778368575SDaniel P. Berrange return ret; 7878368575SDaniel P. Berrange } 79757dda54SAlberto Faria return 0; 8078368575SDaniel P. Berrange } 8178368575SDaniel P. Berrange 82757dda54SAlberto Faria static int block_crypto_write_func(QCryptoBlock *block, 83bbfdae91SMaxim Levitsky size_t offset, 84bbfdae91SMaxim Levitsky const uint8_t *buf, 85bbfdae91SMaxim Levitsky size_t buflen, 86bbfdae91SMaxim Levitsky void *opaque, 87bbfdae91SMaxim Levitsky Error **errp) 88bbfdae91SMaxim Levitsky { 89bbfdae91SMaxim Levitsky BlockDriverState *bs = opaque; 909ad5c4e7SHyman Huang BlockCrypto *crypto = bs->opaque; 91bbfdae91SMaxim Levitsky ssize_t ret; 92bbfdae91SMaxim Levitsky 931f051dcbSKevin Wolf GLOBAL_STATE_CODE(); 941f051dcbSKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP(); 951f051dcbSKevin Wolf 969ad5c4e7SHyman Huang ret = bdrv_pwrite(crypto->header ? crypto->header : bs->file, 979ad5c4e7SHyman Huang offset, buflen, buf, 0); 98bbfdae91SMaxim Levitsky if (ret < 0) { 99bbfdae91SMaxim Levitsky error_setg_errno(errp, -ret, "Could not write encryption header"); 100bbfdae91SMaxim Levitsky return ret; 101bbfdae91SMaxim Levitsky } 102757dda54SAlberto Faria return 0; 103bbfdae91SMaxim Levitsky } 104bbfdae91SMaxim Levitsky 10578368575SDaniel P. Berrange 10678368575SDaniel P. Berrange struct BlockCryptoCreateData { 10778368575SDaniel P. Berrange BlockBackend *blk; 10878368575SDaniel P. Berrange uint64_t size; 109672de729SMaxim Levitsky PreallocMode prealloc; 11078368575SDaniel P. Berrange }; 11178368575SDaniel P. Berrange 11278368575SDaniel P. Berrange 1134db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED 1144db7ba3bSKevin Wolf block_crypto_create_write_func(QCryptoBlock *block, size_t offset, 1154db7ba3bSKevin Wolf const uint8_t *buf, size_t buflen, void *opaque, 11637509233SFam Zheng Error **errp) 11778368575SDaniel P. Berrange { 11878368575SDaniel P. Berrange struct BlockCryptoCreateData *data = opaque; 11978368575SDaniel P. Berrange ssize_t ret; 12078368575SDaniel P. Berrange 121a9262f55SAlberto Faria ret = blk_pwrite(data->blk, offset, buflen, buf, 0); 12278368575SDaniel P. Berrange if (ret < 0) { 12378368575SDaniel P. Berrange error_setg_errno(errp, -ret, "Could not write encryption header"); 12478368575SDaniel P. Berrange return ret; 12578368575SDaniel P. Berrange } 126757dda54SAlberto Faria return 0; 12778368575SDaniel P. Berrange } 12878368575SDaniel P. Berrange 1294db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED 1304db7ba3bSKevin Wolf block_crypto_create_init_func(QCryptoBlock *block, size_t headerlen, 1314db7ba3bSKevin Wolf void *opaque, Error **errp) 13278368575SDaniel P. Berrange { 13378368575SDaniel P. Berrange struct BlockCryptoCreateData *data = opaque; 1343d1900a4SMaxim Levitsky Error *local_error = NULL; 1353d1900a4SMaxim Levitsky int ret; 13678368575SDaniel P. Berrange 1373d7ed9c4SKevin Wolf if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) { 1383d1900a4SMaxim Levitsky ret = -EFBIG; 1393d1900a4SMaxim Levitsky goto error; 1403d7ed9c4SKevin Wolf } 1413d7ed9c4SKevin Wolf 14278368575SDaniel P. Berrange /* User provided size should reflect amount of space made 14378368575SDaniel P. Berrange * available to the guest, so we must take account of that 14478368575SDaniel P. Berrange * which will be used by the crypto header 14578368575SDaniel P. Berrange */ 1463d1900a4SMaxim Levitsky ret = blk_truncate(data->blk, data->size + headerlen, false, 1473d1900a4SMaxim Levitsky data->prealloc, 0, &local_error); 1483d1900a4SMaxim Levitsky 1493d1900a4SMaxim Levitsky if (ret >= 0) { 150757dda54SAlberto Faria return 0; 1513d1900a4SMaxim Levitsky } 1523d1900a4SMaxim Levitsky 1533d1900a4SMaxim Levitsky error: 1543d1900a4SMaxim Levitsky if (ret == -EFBIG) { 1553d1900a4SMaxim Levitsky /* Replace the error message with a better one */ 1563d1900a4SMaxim Levitsky error_free(local_error); 1573d1900a4SMaxim Levitsky error_setg(errp, "The requested file size is too large"); 1583d1900a4SMaxim Levitsky } else { 1593d1900a4SMaxim Levitsky error_propagate(errp, local_error); 1603d1900a4SMaxim Levitsky } 1613d1900a4SMaxim Levitsky 1623d1900a4SMaxim Levitsky return ret; 16378368575SDaniel P. Berrange } 16478368575SDaniel P. Berrange 165d0112eb4SHyman Huang static int coroutine_fn GRAPH_UNLOCKED 166d0112eb4SHyman Huang block_crypto_co_format_luks_payload(BlockdevCreateOptionsLUKS *luks_opts, 167d0112eb4SHyman Huang Error **errp) 168d0112eb4SHyman Huang { 169d0112eb4SHyman Huang BlockDriverState *bs = NULL; 170d0112eb4SHyman Huang BlockBackend *blk = NULL; 171d0112eb4SHyman Huang Error *local_error = NULL; 172d0112eb4SHyman Huang int ret; 173d0112eb4SHyman Huang 174d0112eb4SHyman Huang if (luks_opts->size > INT64_MAX) { 175d0112eb4SHyman Huang return -EFBIG; 176d0112eb4SHyman Huang } 177d0112eb4SHyman Huang 178d0112eb4SHyman Huang bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); 179d0112eb4SHyman Huang if (bs == NULL) { 180d0112eb4SHyman Huang return -EIO; 181d0112eb4SHyman Huang } 182d0112eb4SHyman Huang 183d0112eb4SHyman Huang blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, 184d0112eb4SHyman Huang BLK_PERM_ALL, errp); 185d0112eb4SHyman Huang if (!blk) { 186d0112eb4SHyman Huang ret = -EPERM; 187d0112eb4SHyman Huang goto fail; 188d0112eb4SHyman Huang } 189d0112eb4SHyman Huang 190d0112eb4SHyman Huang ret = blk_truncate(blk, luks_opts->size, true, 191d0112eb4SHyman Huang luks_opts->preallocation, 0, &local_error); 192d0112eb4SHyman Huang if (ret < 0) { 193d0112eb4SHyman Huang if (ret == -EFBIG) { 194d0112eb4SHyman Huang /* Replace the error message with a better one */ 195d0112eb4SHyman Huang error_free(local_error); 196d0112eb4SHyman Huang error_setg(errp, "The requested file size is too large"); 197d0112eb4SHyman Huang } 198d0112eb4SHyman Huang goto fail; 199d0112eb4SHyman Huang } 200d0112eb4SHyman Huang 201d0112eb4SHyman Huang ret = 0; 202d0112eb4SHyman Huang 203d0112eb4SHyman Huang fail: 204d0112eb4SHyman Huang bdrv_co_unref(bs); 205d0112eb4SHyman Huang return ret; 206d0112eb4SHyman Huang } 20778368575SDaniel P. Berrange 20878368575SDaniel P. Berrange static QemuOptsList block_crypto_runtime_opts_luks = { 20978368575SDaniel P. Berrange .name = "crypto", 21078368575SDaniel P. Berrange .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head), 21178368575SDaniel P. Berrange .desc = { 2124a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""), 21378368575SDaniel P. Berrange { /* end of list */ } 21478368575SDaniel P. Berrange }, 21578368575SDaniel P. Berrange }; 21678368575SDaniel P. Berrange 21778368575SDaniel P. Berrange 21878368575SDaniel P. Berrange static QemuOptsList block_crypto_create_opts_luks = { 21978368575SDaniel P. Berrange .name = "crypto", 22078368575SDaniel P. Berrange .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head), 22178368575SDaniel P. Berrange .desc = { 22278368575SDaniel P. Berrange { 22378368575SDaniel P. Berrange .name = BLOCK_OPT_SIZE, 22478368575SDaniel P. Berrange .type = QEMU_OPT_SIZE, 22578368575SDaniel P. Berrange .help = "Virtual disk size" 22678368575SDaniel P. Berrange }, 2274a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""), 2284a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(""), 2294a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(""), 2304a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(""), 2314a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""), 2324a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""), 2334a47f854SDaniel P. Berrange BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""), 234*35286daeSHyman Huang BLOCK_CRYPTO_OPT_DEF_LUKS_DETACHED_HEADER(""), 23578368575SDaniel P. Berrange { /* end of list */ } 23678368575SDaniel P. Berrange }, 23778368575SDaniel P. Berrange }; 23878368575SDaniel P. Berrange 23978368575SDaniel P. Berrange 240bbfdae91SMaxim Levitsky static QemuOptsList block_crypto_amend_opts_luks = { 241bbfdae91SMaxim Levitsky .name = "crypto", 242bbfdae91SMaxim Levitsky .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head), 243bbfdae91SMaxim Levitsky .desc = { 244bbfdae91SMaxim Levitsky BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(""), 245bbfdae91SMaxim Levitsky BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(""), 246bbfdae91SMaxim Levitsky BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(""), 247bbfdae91SMaxim Levitsky BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(""), 248bbfdae91SMaxim Levitsky BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""), 249bbfdae91SMaxim Levitsky { /* end of list */ } 250bbfdae91SMaxim Levitsky }, 251bbfdae91SMaxim Levitsky }; 252bbfdae91SMaxim Levitsky 253306a06e5SDaniel P. Berrange QCryptoBlockOpenOptions * 254796d3239SMarkus Armbruster block_crypto_open_opts_init(QDict *opts, Error **errp) 25578368575SDaniel P. Berrange { 25609204eacSEric Blake Visitor *v; 257796d3239SMarkus Armbruster QCryptoBlockOpenOptions *ret; 25878368575SDaniel P. Berrange 259796d3239SMarkus Armbruster v = qobject_input_visitor_new_flat_confused(opts, errp); 260e6af90f3SMarkus Armbruster if (!v) { 261796d3239SMarkus Armbruster return NULL; 262f853465aSMarkus Armbruster } 26378368575SDaniel P. Berrange 264796d3239SMarkus Armbruster visit_type_QCryptoBlockOpenOptions(v, NULL, &ret, errp); 26578368575SDaniel P. Berrange 26609204eacSEric Blake visit_free(v); 26778368575SDaniel P. Berrange return ret; 26878368575SDaniel P. Berrange } 26978368575SDaniel P. Berrange 27078368575SDaniel P. Berrange 271306a06e5SDaniel P. Berrange QCryptoBlockCreateOptions * 272796d3239SMarkus Armbruster block_crypto_create_opts_init(QDict *opts, Error **errp) 27378368575SDaniel P. Berrange { 27409204eacSEric Blake Visitor *v; 275796d3239SMarkus Armbruster QCryptoBlockCreateOptions *ret; 27678368575SDaniel P. Berrange 277796d3239SMarkus Armbruster v = qobject_input_visitor_new_flat_confused(opts, errp); 278e6af90f3SMarkus Armbruster if (!v) { 279796d3239SMarkus Armbruster return NULL; 280f853465aSMarkus Armbruster } 28178368575SDaniel P. Berrange 282796d3239SMarkus Armbruster visit_type_QCryptoBlockCreateOptions(v, NULL, &ret, errp); 28378368575SDaniel P. Berrange 28409204eacSEric Blake visit_free(v); 28578368575SDaniel P. Berrange return ret; 28678368575SDaniel P. Berrange } 28778368575SDaniel P. Berrange 28843cbd06dSMaxim Levitsky QCryptoBlockAmendOptions * 28943cbd06dSMaxim Levitsky block_crypto_amend_opts_init(QDict *opts, Error **errp) 29043cbd06dSMaxim Levitsky { 29143cbd06dSMaxim Levitsky Visitor *v; 29243cbd06dSMaxim Levitsky QCryptoBlockAmendOptions *ret; 29343cbd06dSMaxim Levitsky 29443cbd06dSMaxim Levitsky v = qobject_input_visitor_new_flat_confused(opts, errp); 29543cbd06dSMaxim Levitsky if (!v) { 29643cbd06dSMaxim Levitsky return NULL; 29743cbd06dSMaxim Levitsky } 29843cbd06dSMaxim Levitsky 29943cbd06dSMaxim Levitsky visit_type_QCryptoBlockAmendOptions(v, NULL, &ret, errp); 30043cbd06dSMaxim Levitsky 30143cbd06dSMaxim Levitsky visit_free(v); 30243cbd06dSMaxim Levitsky return ret; 30343cbd06dSMaxim Levitsky } 30443cbd06dSMaxim Levitsky 30578368575SDaniel P. Berrange 30678368575SDaniel P. Berrange static int block_crypto_open_generic(QCryptoBlockFormat format, 30778368575SDaniel P. Berrange QemuOptsList *opts_spec, 30878368575SDaniel P. Berrange BlockDriverState *bs, 30978368575SDaniel P. Berrange QDict *options, 31078368575SDaniel P. Berrange int flags, 31178368575SDaniel P. Berrange Error **errp) 31278368575SDaniel P. Berrange { 3139ad5c4e7SHyman Huang ERRP_GUARD(); 3149ad5c4e7SHyman Huang 31578368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 31678368575SDaniel P. Berrange QemuOpts *opts = NULL; 31783930780SVladimir Sementsov-Ogievskiy int ret; 31878368575SDaniel P. Berrange QCryptoBlockOpenOptions *open_opts = NULL; 31978368575SDaniel P. Berrange unsigned int cflags = 0; 320306a06e5SDaniel P. Berrange QDict *cryptoopts = NULL; 32178368575SDaniel P. Berrange 322a4b740dbSKevin Wolf GLOBAL_STATE_CODE(); 323a4b740dbSKevin Wolf 32483930780SVladimir Sementsov-Ogievskiy ret = bdrv_open_file_child(NULL, options, "file", bs, errp); 32583930780SVladimir Sementsov-Ogievskiy if (ret < 0) { 32683930780SVladimir Sementsov-Ogievskiy return ret; 3274e4bf5c4SKevin Wolf } 3284e4bf5c4SKevin Wolf 3299ad5c4e7SHyman Huang crypto->header = bdrv_open_child(NULL, options, "header", bs, 3309ad5c4e7SHyman Huang &child_of_bds, BDRV_CHILD_METADATA, 3319ad5c4e7SHyman Huang true, errp); 3329ad5c4e7SHyman Huang if (*errp != NULL) { 3339ad5c4e7SHyman Huang return -EINVAL; 3349ad5c4e7SHyman Huang } 3359ad5c4e7SHyman Huang 336a4b740dbSKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP(); 337a4b740dbSKevin Wolf 338d67a6b09SDaniel P. Berrange bs->supported_write_flags = BDRV_REQ_FUA & 339d67a6b09SDaniel P. Berrange bs->file->bs->supported_write_flags; 340d67a6b09SDaniel P. Berrange 34178368575SDaniel P. Berrange opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort); 342af175e85SMarkus Armbruster if (!qemu_opts_absorb_qdict(opts, options, errp)) { 34383930780SVladimir Sementsov-Ogievskiy ret = -EINVAL; 34478368575SDaniel P. Berrange goto cleanup; 34578368575SDaniel P. Berrange } 34678368575SDaniel P. Berrange 347306a06e5SDaniel P. Berrange cryptoopts = qemu_opts_to_qdict(opts, NULL); 348796d3239SMarkus Armbruster qdict_put_str(cryptoopts, "format", QCryptoBlockFormat_str(format)); 349306a06e5SDaniel P. Berrange 350796d3239SMarkus Armbruster open_opts = block_crypto_open_opts_init(cryptoopts, errp); 35178368575SDaniel P. Berrange if (!open_opts) { 35283930780SVladimir Sementsov-Ogievskiy ret = -EINVAL; 35378368575SDaniel P. Berrange goto cleanup; 35478368575SDaniel P. Berrange } 35578368575SDaniel P. Berrange 35678368575SDaniel P. Berrange if (flags & BDRV_O_NO_IO) { 35778368575SDaniel P. Berrange cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; 35878368575SDaniel P. Berrange } 3599ad5c4e7SHyman Huang if (crypto->header != NULL) { 3609ad5c4e7SHyman Huang cflags |= QCRYPTO_BLOCK_OPEN_DETACHED; 3619ad5c4e7SHyman Huang } 3621cd9a787SDaniel P. Berrange crypto->block = qcrypto_block_open(open_opts, NULL, 36378368575SDaniel P. Berrange block_crypto_read_func, 36478368575SDaniel P. Berrange bs, 36578368575SDaniel P. Berrange cflags, 366c972fa12SVladimir Sementsov-Ogievskiy 1, 36778368575SDaniel P. Berrange errp); 36878368575SDaniel P. Berrange 36978368575SDaniel P. Berrange if (!crypto->block) { 37078368575SDaniel P. Berrange ret = -EIO; 37178368575SDaniel P. Berrange goto cleanup; 37278368575SDaniel P. Berrange } 37378368575SDaniel P. Berrange 37454115412SEric Blake bs->encrypted = true; 37578368575SDaniel P. Berrange 37678368575SDaniel P. Berrange ret = 0; 37778368575SDaniel P. Berrange cleanup: 378cb3e7f08SMarc-André Lureau qobject_unref(cryptoopts); 37978368575SDaniel P. Berrange qapi_free_QCryptoBlockOpenOptions(open_opts); 38078368575SDaniel P. Berrange return ret; 38178368575SDaniel P. Berrange } 38278368575SDaniel P. Berrange 38378368575SDaniel P. Berrange 3844db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED 38591817e9cSKevin Wolf block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, 3861ec4f416SKevin Wolf QCryptoBlockCreateOptions *opts, 387d0112eb4SHyman Huang PreallocMode prealloc, 388d0112eb4SHyman Huang unsigned int flags, 389d0112eb4SHyman Huang Error **errp) 39078368575SDaniel P. Berrange { 3911ec4f416SKevin Wolf int ret; 3921ec4f416SKevin Wolf BlockBackend *blk; 39378368575SDaniel P. Berrange QCryptoBlock *crypto = NULL; 3941ec4f416SKevin Wolf struct BlockCryptoCreateData data; 39578368575SDaniel P. Berrange 39691817e9cSKevin Wolf blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, 397a3aeeab5SEric Blake errp); 398a3aeeab5SEric Blake if (!blk) { 399a3aeeab5SEric Blake ret = -EPERM; 4001ec4f416SKevin Wolf goto cleanup; 4013b5a1f6aSKevin Wolf } 4023b5a1f6aSKevin Wolf 403672de729SMaxim Levitsky if (prealloc == PREALLOC_MODE_METADATA) { 404672de729SMaxim Levitsky prealloc = PREALLOC_MODE_OFF; 405672de729SMaxim Levitsky } 406672de729SMaxim Levitsky 4071ec4f416SKevin Wolf data = (struct BlockCryptoCreateData) { 4081ec4f416SKevin Wolf .blk = blk, 409*35286daeSHyman Huang .size = flags & QCRYPTO_BLOCK_CREATE_DETACHED ? 0 : size, 410672de729SMaxim Levitsky .prealloc = prealloc, 4111ec4f416SKevin Wolf }; 4123b5a1f6aSKevin Wolf 4131ec4f416SKevin Wolf crypto = qcrypto_block_create(opts, NULL, 414e0d0ddc5SMaxim Levitsky block_crypto_create_init_func, 415e0d0ddc5SMaxim Levitsky block_crypto_create_write_func, 41678368575SDaniel P. Berrange &data, 417d0112eb4SHyman Huang flags, 41878368575SDaniel P. Berrange errp); 41978368575SDaniel P. Berrange 42078368575SDaniel P. Berrange if (!crypto) { 42178368575SDaniel P. Berrange ret = -EIO; 42278368575SDaniel P. Berrange goto cleanup; 42378368575SDaniel P. Berrange } 42478368575SDaniel P. Berrange 42578368575SDaniel P. Berrange ret = 0; 42678368575SDaniel P. Berrange cleanup: 42778368575SDaniel P. Berrange qcrypto_block_free(crypto); 428b2ab5f54SKevin Wolf blk_co_unref(blk); 42978368575SDaniel P. Berrange return ret; 43078368575SDaniel P. Berrange } 43178368575SDaniel P. Berrange 432c2b8e315SKevin Wolf static int coroutine_fn GRAPH_RDLOCK 433c80d8b06SMax Reitz block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, 43492b92799SKevin Wolf PreallocMode prealloc, BdrvRequestFlags flags, 43592b92799SKevin Wolf Error **errp) 43678368575SDaniel P. Berrange { 43778368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 43831376555SDaniel P. Berrange uint64_t payload_offset = 43978368575SDaniel P. Berrange qcrypto_block_get_payload_offset(crypto->block); 440120bc742SKevin Wolf 441120bc742SKevin Wolf if (payload_offset > INT64_MAX - offset) { 442120bc742SKevin Wolf error_setg(errp, "The requested file size is too large"); 443120bc742SKevin Wolf return -EFBIG; 444120bc742SKevin Wolf } 44578368575SDaniel P. Berrange 44678368575SDaniel P. Berrange offset += payload_offset; 44778368575SDaniel P. Berrange 4487b8e4857SKevin Wolf return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); 44978368575SDaniel P. Berrange } 45078368575SDaniel P. Berrange 45178368575SDaniel P. Berrange static void block_crypto_close(BlockDriverState *bs) 45278368575SDaniel P. Berrange { 45378368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 45478368575SDaniel P. Berrange qcrypto_block_free(crypto->block); 45578368575SDaniel P. Berrange } 45678368575SDaniel P. Berrange 457f87e08f9SDaniel P. Berrange static int block_crypto_reopen_prepare(BDRVReopenState *state, 458f87e08f9SDaniel P. Berrange BlockReopenQueue *queue, Error **errp) 459f87e08f9SDaniel P. Berrange { 460f87e08f9SDaniel P. Berrange /* nothing needs checking */ 461f87e08f9SDaniel P. Berrange return 0; 462f87e08f9SDaniel P. Berrange } 46378368575SDaniel P. Berrange 464161253e2SDaniel P. Berrange /* 465161253e2SDaniel P. Berrange * 1 MB bounce buffer gives good performance / memory tradeoff 466161253e2SDaniel P. Berrange * when using cache=none|directsync. 467161253e2SDaniel P. Berrange */ 468161253e2SDaniel P. Berrange #define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024) 46978368575SDaniel P. Berrange 470b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK 471f7ef38ddSVladimir Sementsov-Ogievskiy block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, 472f7ef38ddSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags) 47378368575SDaniel P. Berrange { 47478368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 475a73466fbSDaniel P. Berrange uint64_t cur_bytes; /* number of bytes in current iteration */ 47678368575SDaniel P. Berrange uint64_t bytes_done = 0; 47778368575SDaniel P. Berrange uint8_t *cipher_data = NULL; 47878368575SDaniel P. Berrange QEMUIOVector hd_qiov; 47978368575SDaniel P. Berrange int ret = 0; 480a73466fbSDaniel P. Berrange uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); 481a73466fbSDaniel P. Berrange uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); 482a73466fbSDaniel P. Berrange 483a73466fbSDaniel P. Berrange assert(payload_offset < INT64_MAX); 484a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(offset, sector_size)); 485a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(bytes, sector_size)); 48678368575SDaniel P. Berrange 48778368575SDaniel P. Berrange qemu_iovec_init(&hd_qiov, qiov->niov); 48878368575SDaniel P. Berrange 489161253e2SDaniel P. Berrange /* Bounce buffer because we don't wish to expose cipher text 490161253e2SDaniel P. Berrange * in qiov which points to guest memory. 49178368575SDaniel P. Berrange */ 49278368575SDaniel P. Berrange cipher_data = 493161253e2SDaniel P. Berrange qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE, 49478368575SDaniel P. Berrange qiov->size)); 49578368575SDaniel P. Berrange if (cipher_data == NULL) { 49678368575SDaniel P. Berrange ret = -ENOMEM; 49778368575SDaniel P. Berrange goto cleanup; 49878368575SDaniel P. Berrange } 49978368575SDaniel P. Berrange 500a73466fbSDaniel P. Berrange while (bytes) { 501a73466fbSDaniel P. Berrange cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE); 50278368575SDaniel P. Berrange 50378368575SDaniel P. Berrange qemu_iovec_reset(&hd_qiov); 504a73466fbSDaniel P. Berrange qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes); 50578368575SDaniel P. Berrange 506a73466fbSDaniel P. Berrange ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done, 507a73466fbSDaniel P. Berrange cur_bytes, &hd_qiov, 0); 50878368575SDaniel P. Berrange if (ret < 0) { 50978368575SDaniel P. Berrange goto cleanup; 51078368575SDaniel P. Berrange } 51178368575SDaniel P. Berrange 5124609742aSDaniel P. Berrange if (qcrypto_block_decrypt(crypto->block, offset + bytes_done, 5134609742aSDaniel P. Berrange cipher_data, cur_bytes, NULL) < 0) { 51478368575SDaniel P. Berrange ret = -EIO; 51578368575SDaniel P. Berrange goto cleanup; 51678368575SDaniel P. Berrange } 51778368575SDaniel P. Berrange 518a73466fbSDaniel P. Berrange qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes); 51978368575SDaniel P. Berrange 520a73466fbSDaniel P. Berrange bytes -= cur_bytes; 521a73466fbSDaniel P. Berrange bytes_done += cur_bytes; 52278368575SDaniel P. Berrange } 52378368575SDaniel P. Berrange 52478368575SDaniel P. Berrange cleanup: 52578368575SDaniel P. Berrange qemu_iovec_destroy(&hd_qiov); 52678368575SDaniel P. Berrange qemu_vfree(cipher_data); 52778368575SDaniel P. Berrange 52878368575SDaniel P. Berrange return ret; 52978368575SDaniel P. Berrange } 53078368575SDaniel P. Berrange 53178368575SDaniel P. Berrange 532b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK 533e75abedaSVladimir Sementsov-Ogievskiy block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, 534e75abedaSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags) 53578368575SDaniel P. Berrange { 53678368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 537a73466fbSDaniel P. Berrange uint64_t cur_bytes; /* number of bytes in current iteration */ 53878368575SDaniel P. Berrange uint64_t bytes_done = 0; 53978368575SDaniel P. Berrange uint8_t *cipher_data = NULL; 54078368575SDaniel P. Berrange QEMUIOVector hd_qiov; 54178368575SDaniel P. Berrange int ret = 0; 542a73466fbSDaniel P. Berrange uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); 543a73466fbSDaniel P. Berrange uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); 544a73466fbSDaniel P. Berrange 545e8b65355SStefan Hajnoczi flags &= ~BDRV_REQ_REGISTERED_BUF; 546e8b65355SStefan Hajnoczi 547a73466fbSDaniel P. Berrange assert(payload_offset < INT64_MAX); 548a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(offset, sector_size)); 549a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(bytes, sector_size)); 55078368575SDaniel P. Berrange 55178368575SDaniel P. Berrange qemu_iovec_init(&hd_qiov, qiov->niov); 55278368575SDaniel P. Berrange 553161253e2SDaniel P. Berrange /* Bounce buffer because we're not permitted to touch 554161253e2SDaniel P. Berrange * contents of qiov - it points to guest memory. 55578368575SDaniel P. Berrange */ 55678368575SDaniel P. Berrange cipher_data = 557161253e2SDaniel P. Berrange qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE, 55878368575SDaniel P. Berrange qiov->size)); 55978368575SDaniel P. Berrange if (cipher_data == NULL) { 56078368575SDaniel P. Berrange ret = -ENOMEM; 56178368575SDaniel P. Berrange goto cleanup; 56278368575SDaniel P. Berrange } 56378368575SDaniel P. Berrange 564a73466fbSDaniel P. Berrange while (bytes) { 565a73466fbSDaniel P. Berrange cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE); 56678368575SDaniel P. Berrange 567a73466fbSDaniel P. Berrange qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes); 56878368575SDaniel P. Berrange 5694609742aSDaniel P. Berrange if (qcrypto_block_encrypt(crypto->block, offset + bytes_done, 5704609742aSDaniel P. Berrange cipher_data, cur_bytes, NULL) < 0) { 57178368575SDaniel P. Berrange ret = -EIO; 57278368575SDaniel P. Berrange goto cleanup; 57378368575SDaniel P. Berrange } 57478368575SDaniel P. Berrange 57578368575SDaniel P. Berrange qemu_iovec_reset(&hd_qiov); 576a73466fbSDaniel P. Berrange qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes); 57778368575SDaniel P. Berrange 578a73466fbSDaniel P. Berrange ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done, 579d67a6b09SDaniel P. Berrange cur_bytes, &hd_qiov, flags); 58078368575SDaniel P. Berrange if (ret < 0) { 58178368575SDaniel P. Berrange goto cleanup; 58278368575SDaniel P. Berrange } 58378368575SDaniel P. Berrange 584a73466fbSDaniel P. Berrange bytes -= cur_bytes; 585a73466fbSDaniel P. Berrange bytes_done += cur_bytes; 58678368575SDaniel P. Berrange } 58778368575SDaniel P. Berrange 58878368575SDaniel P. Berrange cleanup: 58978368575SDaniel P. Berrange qemu_iovec_destroy(&hd_qiov); 59078368575SDaniel P. Berrange qemu_vfree(cipher_data); 59178368575SDaniel P. Berrange 59278368575SDaniel P. Berrange return ret; 59378368575SDaniel P. Berrange } 59478368575SDaniel P. Berrange 595a73466fbSDaniel P. Berrange static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp) 596a73466fbSDaniel P. Berrange { 597a73466fbSDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 598a73466fbSDaniel P. Berrange uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); 599a73466fbSDaniel P. Berrange bs->bl.request_alignment = sector_size; /* No sub-sector I/O */ 600a73466fbSDaniel P. Berrange } 601a73466fbSDaniel P. Berrange 60278368575SDaniel P. Berrange 6038ab8140aSKevin Wolf static int64_t coroutine_fn GRAPH_RDLOCK 6048ab8140aSKevin Wolf block_crypto_co_getlength(BlockDriverState *bs) 60578368575SDaniel P. Berrange { 60678368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 607c86422c5SEmanuele Giuseppe Esposito int64_t len = bdrv_co_getlength(bs->file->bs); 60878368575SDaniel P. Berrange 60931376555SDaniel P. Berrange uint64_t offset = qcrypto_block_get_payload_offset(crypto->block); 61031376555SDaniel P. Berrange assert(offset < INT64_MAX); 611e39e959eSKevin Wolf 612e39e959eSKevin Wolf if (offset > len) { 613e39e959eSKevin Wolf return -EIO; 614e39e959eSKevin Wolf } 61578368575SDaniel P. Berrange 61678368575SDaniel P. Berrange len -= offset; 61778368575SDaniel P. Berrange 61878368575SDaniel P. Berrange return len; 61978368575SDaniel P. Berrange } 62078368575SDaniel P. Berrange 62178368575SDaniel P. Berrange 622a9da6e49SStefan Hajnoczi static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts, 623a9da6e49SStefan Hajnoczi BlockDriverState *in_bs, 624a9da6e49SStefan Hajnoczi Error **errp) 625a9da6e49SStefan Hajnoczi { 626a9da6e49SStefan Hajnoczi g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL; 627a9da6e49SStefan Hajnoczi Error *local_err = NULL; 628a9da6e49SStefan Hajnoczi BlockMeasureInfo *info; 629a9da6e49SStefan Hajnoczi uint64_t size; 630a9da6e49SStefan Hajnoczi size_t luks_payload_size; 631a9da6e49SStefan Hajnoczi QDict *cryptoopts; 632a9da6e49SStefan Hajnoczi 633a9da6e49SStefan Hajnoczi /* 634a9da6e49SStefan Hajnoczi * Preallocation mode doesn't affect size requirements but we must consume 635a9da6e49SStefan Hajnoczi * the option. 636a9da6e49SStefan Hajnoczi */ 637a9da6e49SStefan Hajnoczi g_free(qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC)); 638a9da6e49SStefan Hajnoczi 639a9da6e49SStefan Hajnoczi size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); 640a9da6e49SStefan Hajnoczi 641a9da6e49SStefan Hajnoczi if (in_bs) { 642a9da6e49SStefan Hajnoczi int64_t ssize = bdrv_getlength(in_bs); 643a9da6e49SStefan Hajnoczi 644a9da6e49SStefan Hajnoczi if (ssize < 0) { 645a9da6e49SStefan Hajnoczi error_setg_errno(&local_err, -ssize, 646a9da6e49SStefan Hajnoczi "Unable to get image virtual_size"); 647a9da6e49SStefan Hajnoczi goto err; 648a9da6e49SStefan Hajnoczi } 649a9da6e49SStefan Hajnoczi 650a9da6e49SStefan Hajnoczi size = ssize; 651a9da6e49SStefan Hajnoczi } 652a9da6e49SStefan Hajnoczi 653a9da6e49SStefan Hajnoczi cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL, 654a9da6e49SStefan Hajnoczi &block_crypto_create_opts_luks, true); 655a9da6e49SStefan Hajnoczi qdict_put_str(cryptoopts, "format", "luks"); 656a9da6e49SStefan Hajnoczi create_opts = block_crypto_create_opts_init(cryptoopts, &local_err); 657a9da6e49SStefan Hajnoczi qobject_unref(cryptoopts); 658a9da6e49SStefan Hajnoczi if (!create_opts) { 659a9da6e49SStefan Hajnoczi goto err; 660a9da6e49SStefan Hajnoczi } 661a9da6e49SStefan Hajnoczi 662a9da6e49SStefan Hajnoczi if (!qcrypto_block_calculate_payload_offset(create_opts, NULL, 663a9da6e49SStefan Hajnoczi &luks_payload_size, 664a9da6e49SStefan Hajnoczi &local_err)) { 665a9da6e49SStefan Hajnoczi goto err; 666a9da6e49SStefan Hajnoczi } 667a9da6e49SStefan Hajnoczi 668a9da6e49SStefan Hajnoczi /* 669a9da6e49SStefan Hajnoczi * Unallocated blocks are still encrypted so allocation status makes no 670a9da6e49SStefan Hajnoczi * difference to the file size. 671a9da6e49SStefan Hajnoczi */ 6725d72c68bSEric Blake info = g_new0(BlockMeasureInfo, 1); 673a9da6e49SStefan Hajnoczi info->fully_allocated = luks_payload_size + size; 674a9da6e49SStefan Hajnoczi info->required = luks_payload_size + size; 675a9da6e49SStefan Hajnoczi return info; 676a9da6e49SStefan Hajnoczi 677a9da6e49SStefan Hajnoczi err: 678a9da6e49SStefan Hajnoczi error_propagate(errp, local_err); 679a9da6e49SStefan Hajnoczi return NULL; 680a9da6e49SStefan Hajnoczi } 681a9da6e49SStefan Hajnoczi 682a9da6e49SStefan Hajnoczi 68378368575SDaniel P. Berrange static int block_crypto_probe_luks(const uint8_t *buf, 68478368575SDaniel P. Berrange int buf_size, 68578368575SDaniel P. Berrange const char *filename) { 68678368575SDaniel P. Berrange return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS, 68778368575SDaniel P. Berrange buf, buf_size, filename); 68878368575SDaniel P. Berrange } 68978368575SDaniel P. Berrange 69078368575SDaniel P. Berrange static int block_crypto_open_luks(BlockDriverState *bs, 69178368575SDaniel P. Berrange QDict *options, 69278368575SDaniel P. Berrange int flags, 69378368575SDaniel P. Berrange Error **errp) 69478368575SDaniel P. Berrange { 69578368575SDaniel P. Berrange return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS, 69678368575SDaniel P. Berrange &block_crypto_runtime_opts_luks, 69778368575SDaniel P. Berrange bs, options, flags, errp); 69878368575SDaniel P. Berrange } 69978368575SDaniel P. Berrange 7004db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED 7011bedcaf1SKevin Wolf block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) 7021bedcaf1SKevin Wolf { 7031bedcaf1SKevin Wolf BlockdevCreateOptionsLUKS *luks_opts; 704d0112eb4SHyman Huang BlockDriverState *hdr_bs = NULL; 7051bedcaf1SKevin Wolf BlockDriverState *bs = NULL; 7061bedcaf1SKevin Wolf QCryptoBlockCreateOptions create_opts; 707672de729SMaxim Levitsky PreallocMode preallocation = PREALLOC_MODE_OFF; 708d0112eb4SHyman Huang unsigned int cflags = 0; 7091bedcaf1SKevin Wolf int ret; 7101bedcaf1SKevin Wolf 7111bedcaf1SKevin Wolf assert(create_options->driver == BLOCKDEV_DRIVER_LUKS); 7121bedcaf1SKevin Wolf luks_opts = &create_options->u.luks; 7131bedcaf1SKevin Wolf 714d0112eb4SHyman Huang if (luks_opts->header == NULL && luks_opts->file == NULL) { 715d0112eb4SHyman Huang error_setg(errp, "Either the parameter 'header' or 'file' must " 716d0112eb4SHyman Huang "be specified"); 717d0112eb4SHyman Huang return -EINVAL; 718d0112eb4SHyman Huang } 719d0112eb4SHyman Huang 720d0112eb4SHyman Huang if ((luks_opts->preallocation != PREALLOC_MODE_OFF) && 721d0112eb4SHyman Huang (luks_opts->file == NULL)) { 722d0112eb4SHyman Huang error_setg(errp, "Parameter 'preallocation' requires 'file' to be " 723d0112eb4SHyman Huang "specified for formatting LUKS disk"); 724433957bbSHyman Huang return -EINVAL; 7251bedcaf1SKevin Wolf } 7261bedcaf1SKevin Wolf 7271bedcaf1SKevin Wolf create_opts = (QCryptoBlockCreateOptions) { 7281bedcaf1SKevin Wolf .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, 7291bedcaf1SKevin Wolf .u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts), 7301bedcaf1SKevin Wolf }; 7311bedcaf1SKevin Wolf 732672de729SMaxim Levitsky if (luks_opts->has_preallocation) { 733672de729SMaxim Levitsky preallocation = luks_opts->preallocation; 734672de729SMaxim Levitsky } 735672de729SMaxim Levitsky 736d0112eb4SHyman Huang if (luks_opts->header) { 737d0112eb4SHyman Huang /* LUKS volume with detached header */ 738d0112eb4SHyman Huang hdr_bs = bdrv_co_open_blockdev_ref(luks_opts->header, errp); 739d0112eb4SHyman Huang if (hdr_bs == NULL) { 740d0112eb4SHyman Huang return -EIO; 741d0112eb4SHyman Huang } 742d0112eb4SHyman Huang 743d0112eb4SHyman Huang cflags |= QCRYPTO_BLOCK_CREATE_DETACHED; 744d0112eb4SHyman Huang 745d0112eb4SHyman Huang /* Format the LUKS header node */ 746d0112eb4SHyman Huang ret = block_crypto_co_create_generic(hdr_bs, 0, &create_opts, 747d0112eb4SHyman Huang PREALLOC_MODE_OFF, cflags, errp); 748d0112eb4SHyman Huang if (ret < 0) { 749d0112eb4SHyman Huang goto fail; 750d0112eb4SHyman Huang } 751d0112eb4SHyman Huang 752d0112eb4SHyman Huang /* Format the LUKS payload node */ 753433957bbSHyman Huang if (luks_opts->file) { 754d0112eb4SHyman Huang ret = block_crypto_co_format_luks_payload(luks_opts, errp); 755d0112eb4SHyman Huang if (ret < 0) { 756d0112eb4SHyman Huang goto fail; 757d0112eb4SHyman Huang } 758d0112eb4SHyman Huang } 759d0112eb4SHyman Huang } else if (luks_opts->file) { 760d0112eb4SHyman Huang /* LUKS volume with none-detached header */ 761433957bbSHyman Huang bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); 762433957bbSHyman Huang if (bs == NULL) { 763433957bbSHyman Huang return -EIO; 764433957bbSHyman Huang } 765433957bbSHyman Huang 7661bedcaf1SKevin Wolf ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts, 767d0112eb4SHyman Huang preallocation, cflags, errp); 7681bedcaf1SKevin Wolf if (ret < 0) { 7691bedcaf1SKevin Wolf goto fail; 7701bedcaf1SKevin Wolf } 771433957bbSHyman Huang } 7721bedcaf1SKevin Wolf 7731bedcaf1SKevin Wolf ret = 0; 7741bedcaf1SKevin Wolf fail: 775d0112eb4SHyman Huang if (hdr_bs != NULL) { 776d0112eb4SHyman Huang bdrv_co_unref(hdr_bs); 777d0112eb4SHyman Huang } 778d0112eb4SHyman Huang 779d0112eb4SHyman Huang if (bs != NULL) { 780b2ab5f54SKevin Wolf bdrv_co_unref(bs); 781d0112eb4SHyman Huang } 7821bedcaf1SKevin Wolf return ret; 7831bedcaf1SKevin Wolf } 7841bedcaf1SKevin Wolf 7854db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED 7864ec8df01SKevin Wolf block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename, 7874ec8df01SKevin Wolf QemuOpts *opts, Error **errp) 78878368575SDaniel P. Berrange { 7891ec4f416SKevin Wolf QCryptoBlockCreateOptions *create_opts = NULL; 7901ec4f416SKevin Wolf BlockDriverState *bs = NULL; 7911ec4f416SKevin Wolf QDict *cryptoopts; 792672de729SMaxim Levitsky PreallocMode prealloc; 793672de729SMaxim Levitsky char *buf = NULL; 7941ec4f416SKevin Wolf int64_t size; 795*35286daeSHyman Huang bool detached_hdr = 796*35286daeSHyman Huang qemu_opt_get_bool(opts, "detached-header", false); 797*35286daeSHyman Huang unsigned int cflags = 0; 7981ec4f416SKevin Wolf int ret; 799672de729SMaxim Levitsky Error *local_err = NULL; 8001ec4f416SKevin Wolf 8011ec4f416SKevin Wolf /* Parse options */ 8021ec4f416SKevin Wolf size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); 8031ec4f416SKevin Wolf 804672de729SMaxim Levitsky buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); 805672de729SMaxim Levitsky prealloc = qapi_enum_parse(&PreallocMode_lookup, buf, 806672de729SMaxim Levitsky PREALLOC_MODE_OFF, &local_err); 807672de729SMaxim Levitsky g_free(buf); 808672de729SMaxim Levitsky if (local_err) { 809672de729SMaxim Levitsky error_propagate(errp, local_err); 810672de729SMaxim Levitsky return -EINVAL; 811672de729SMaxim Levitsky } 812672de729SMaxim Levitsky 8131ec4f416SKevin Wolf cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL, 8141ec4f416SKevin Wolf &block_crypto_create_opts_luks, 8151ec4f416SKevin Wolf true); 8161ec4f416SKevin Wolf 817796d3239SMarkus Armbruster qdict_put_str(cryptoopts, "format", "luks"); 818796d3239SMarkus Armbruster create_opts = block_crypto_create_opts_init(cryptoopts, errp); 8191ec4f416SKevin Wolf if (!create_opts) { 8201ec4f416SKevin Wolf ret = -EINVAL; 8211ec4f416SKevin Wolf goto fail; 8221ec4f416SKevin Wolf } 8231ec4f416SKevin Wolf 8241ec4f416SKevin Wolf /* Create protocol layer */ 8252475a0d0SEmanuele Giuseppe Esposito ret = bdrv_co_create_file(filename, opts, errp); 8261ec4f416SKevin Wolf if (ret < 0) { 8270b68589dSKevin Wolf goto fail; 8281ec4f416SKevin Wolf } 8291ec4f416SKevin Wolf 83091817e9cSKevin Wolf bs = bdrv_co_open(filename, NULL, NULL, 8311ec4f416SKevin Wolf BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); 8321ec4f416SKevin Wolf if (!bs) { 8331ec4f416SKevin Wolf ret = -EINVAL; 8341ec4f416SKevin Wolf goto fail; 8351ec4f416SKevin Wolf } 8361ec4f416SKevin Wolf 837*35286daeSHyman Huang if (detached_hdr) { 838*35286daeSHyman Huang cflags |= QCRYPTO_BLOCK_CREATE_DETACHED; 839*35286daeSHyman Huang } 840*35286daeSHyman Huang 8411ec4f416SKevin Wolf /* Create format layer */ 842d0112eb4SHyman Huang ret = block_crypto_co_create_generic(bs, size, create_opts, 843*35286daeSHyman Huang prealloc, cflags, errp); 8441ec4f416SKevin Wolf if (ret < 0) { 8451ec4f416SKevin Wolf goto fail; 8461ec4f416SKevin Wolf } 8471ec4f416SKevin Wolf 8481ec4f416SKevin Wolf ret = 0; 8491ec4f416SKevin Wolf fail: 8501bba30daSDaniel Henrique Barboza /* 8511bba30daSDaniel Henrique Barboza * If an error occurred, delete 'filename'. Even if the file existed 8521bba30daSDaniel Henrique Barboza * beforehand, it has been truncated and corrupted in the process. 8531bba30daSDaniel Henrique Barboza */ 854a890f08eSMaxim Levitsky if (ret) { 8554db7ba3bSKevin Wolf bdrv_graph_co_rdlock(); 856a890f08eSMaxim Levitsky bdrv_co_delete_file_noerr(bs); 8574db7ba3bSKevin Wolf bdrv_graph_co_rdunlock(); 8581bba30daSDaniel Henrique Barboza } 8591bba30daSDaniel Henrique Barboza 860b2ab5f54SKevin Wolf bdrv_co_unref(bs); 8611ec4f416SKevin Wolf qapi_free_QCryptoBlockCreateOptions(create_opts); 862cb3e7f08SMarc-André Lureau qobject_unref(cryptoopts); 8631ec4f416SKevin Wolf return ret; 86478368575SDaniel P. Berrange } 86578368575SDaniel P. Berrange 866a00e70c0SEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK 8673d47eb0aSEmanuele Giuseppe Esposito block_crypto_co_get_info_luks(BlockDriverState *bs, BlockDriverInfo *bdi) 868c7c4cf49SDaniel P. Berrange { 869c7c4cf49SDaniel P. Berrange BlockDriverInfo subbdi; 870c7c4cf49SDaniel P. Berrange int ret; 871c7c4cf49SDaniel P. Berrange 8723d47eb0aSEmanuele Giuseppe Esposito ret = bdrv_co_get_info(bs->file->bs, &subbdi); 873c7c4cf49SDaniel P. Berrange if (ret != 0) { 874c7c4cf49SDaniel P. Berrange return ret; 875c7c4cf49SDaniel P. Berrange } 876c7c4cf49SDaniel P. Berrange 877c7c4cf49SDaniel P. Berrange bdi->cluster_size = subbdi.cluster_size; 878c7c4cf49SDaniel P. Berrange 879c7c4cf49SDaniel P. Berrange return 0; 880c7c4cf49SDaniel P. Berrange } 881c7c4cf49SDaniel P. Berrange 882c7c4cf49SDaniel P. Berrange static ImageInfoSpecific * 8831bf6e9caSAndrey Shinkevich block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) 884c7c4cf49SDaniel P. Berrange { 885c7c4cf49SDaniel P. Berrange BlockCrypto *crypto = bs->opaque; 886c7c4cf49SDaniel P. Berrange ImageInfoSpecific *spec_info; 887c7c4cf49SDaniel P. Berrange QCryptoBlockInfo *info; 888c7c4cf49SDaniel P. Berrange 8891bf6e9caSAndrey Shinkevich info = qcrypto_block_get_info(crypto->block, errp); 890c7c4cf49SDaniel P. Berrange if (!info) { 891c7c4cf49SDaniel P. Berrange return NULL; 892c7c4cf49SDaniel P. Berrange } 8931bf6e9caSAndrey Shinkevich assert(info->format == Q_CRYPTO_BLOCK_FORMAT_LUKS); 894c7c4cf49SDaniel P. Berrange 895c7c4cf49SDaniel P. Berrange spec_info = g_new(ImageInfoSpecific, 1); 896c7c4cf49SDaniel P. Berrange spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS; 897c7c4cf49SDaniel P. Berrange spec_info->u.luks.data = g_new(QCryptoBlockInfoLUKS, 1); 898c7c4cf49SDaniel P. Berrange *spec_info->u.luks.data = info->u.luks; 899c7c4cf49SDaniel P. Berrange 900c7c4cf49SDaniel P. Berrange /* Blank out pointers we've just stolen to avoid double free */ 901c7c4cf49SDaniel P. Berrange memset(&info->u.luks, 0, sizeof(info->u.luks)); 902c7c4cf49SDaniel P. Berrange 903c7c4cf49SDaniel P. Berrange qapi_free_QCryptoBlockInfo(info); 904c7c4cf49SDaniel P. Berrange 905c7c4cf49SDaniel P. Berrange return spec_info; 906c7c4cf49SDaniel P. Berrange } 907c7c4cf49SDaniel P. Berrange 9083804e3cfSKevin Wolf static int GRAPH_RDLOCK 909c1019d16SEmanuele Giuseppe Esposito block_crypto_amend_prepare(BlockDriverState *bs, Error **errp) 910c1019d16SEmanuele Giuseppe Esposito { 911c1019d16SEmanuele Giuseppe Esposito BlockCrypto *crypto = bs->opaque; 912c1019d16SEmanuele Giuseppe Esposito int ret; 913c1019d16SEmanuele Giuseppe Esposito 914c1019d16SEmanuele Giuseppe Esposito /* apply for exclusive read/write permissions to the underlying file */ 915c1019d16SEmanuele Giuseppe Esposito crypto->updating_keys = true; 916c1019d16SEmanuele Giuseppe Esposito ret = bdrv_child_refresh_perms(bs, bs->file, errp); 917c1019d16SEmanuele Giuseppe Esposito if (ret < 0) { 918c1019d16SEmanuele Giuseppe Esposito /* Well, in this case we will not be updating any keys */ 919c1019d16SEmanuele Giuseppe Esposito crypto->updating_keys = false; 920c1019d16SEmanuele Giuseppe Esposito } 921c1019d16SEmanuele Giuseppe Esposito return ret; 922c1019d16SEmanuele Giuseppe Esposito } 923c1019d16SEmanuele Giuseppe Esposito 9243804e3cfSKevin Wolf static void GRAPH_RDLOCK 925c1019d16SEmanuele Giuseppe Esposito block_crypto_amend_cleanup(BlockDriverState *bs) 926c1019d16SEmanuele Giuseppe Esposito { 927c1019d16SEmanuele Giuseppe Esposito BlockCrypto *crypto = bs->opaque; 928c1019d16SEmanuele Giuseppe Esposito Error *errp = NULL; 929c1019d16SEmanuele Giuseppe Esposito 930c1019d16SEmanuele Giuseppe Esposito /* release exclusive read/write permissions to the underlying file */ 931c1019d16SEmanuele Giuseppe Esposito crypto->updating_keys = false; 932c1019d16SEmanuele Giuseppe Esposito bdrv_child_refresh_perms(bs, bs->file, &errp); 933c1019d16SEmanuele Giuseppe Esposito 934c1019d16SEmanuele Giuseppe Esposito if (errp) { 935c1019d16SEmanuele Giuseppe Esposito error_report_err(errp); 936c1019d16SEmanuele Giuseppe Esposito } 937c1019d16SEmanuele Giuseppe Esposito } 938c1019d16SEmanuele Giuseppe Esposito 939c1019d16SEmanuele Giuseppe Esposito static int 94030da9dd8SMaxim Levitsky block_crypto_amend_options_generic_luks(BlockDriverState *bs, 94130da9dd8SMaxim Levitsky QCryptoBlockAmendOptions *amend_options, 942bbfdae91SMaxim Levitsky bool force, 943bbfdae91SMaxim Levitsky Error **errp) 944bbfdae91SMaxim Levitsky { 945bbfdae91SMaxim Levitsky BlockCrypto *crypto = bs->opaque; 946bbfdae91SMaxim Levitsky 947bbfdae91SMaxim Levitsky assert(crypto); 948bbfdae91SMaxim Levitsky assert(crypto->block); 94930da9dd8SMaxim Levitsky 950dae84929SEmanuele Giuseppe Esposito return qcrypto_block_amend_options(crypto->block, 951bbfdae91SMaxim Levitsky block_crypto_read_func, 952bbfdae91SMaxim Levitsky block_crypto_write_func, 953bbfdae91SMaxim Levitsky bs, 954bbfdae91SMaxim Levitsky amend_options, 955bbfdae91SMaxim Levitsky force, 956bbfdae91SMaxim Levitsky errp); 957bbfdae91SMaxim Levitsky } 958bbfdae91SMaxim Levitsky 959bd131d67SKevin Wolf static int GRAPH_RDLOCK 96030da9dd8SMaxim Levitsky block_crypto_amend_options_luks(BlockDriverState *bs, 96130da9dd8SMaxim Levitsky QemuOpts *opts, 96230da9dd8SMaxim Levitsky BlockDriverAmendStatusCB *status_cb, 96330da9dd8SMaxim Levitsky void *cb_opaque, 96430da9dd8SMaxim Levitsky bool force, 96530da9dd8SMaxim Levitsky Error **errp) 96630da9dd8SMaxim Levitsky { 96730da9dd8SMaxim Levitsky BlockCrypto *crypto = bs->opaque; 96830da9dd8SMaxim Levitsky QDict *cryptoopts = NULL; 96930da9dd8SMaxim Levitsky QCryptoBlockAmendOptions *amend_options = NULL; 97030da9dd8SMaxim Levitsky int ret = -EINVAL; 97130da9dd8SMaxim Levitsky 97230da9dd8SMaxim Levitsky assert(crypto); 97330da9dd8SMaxim Levitsky assert(crypto->block); 97430da9dd8SMaxim Levitsky 97530da9dd8SMaxim Levitsky cryptoopts = qemu_opts_to_qdict(opts, NULL); 97630da9dd8SMaxim Levitsky qdict_put_str(cryptoopts, "format", "luks"); 97730da9dd8SMaxim Levitsky amend_options = block_crypto_amend_opts_init(cryptoopts, errp); 97830da9dd8SMaxim Levitsky qobject_unref(cryptoopts); 97930da9dd8SMaxim Levitsky if (!amend_options) { 98030da9dd8SMaxim Levitsky goto cleanup; 98130da9dd8SMaxim Levitsky } 982dae84929SEmanuele Giuseppe Esposito 983dae84929SEmanuele Giuseppe Esposito ret = block_crypto_amend_prepare(bs, errp); 984dae84929SEmanuele Giuseppe Esposito if (ret) { 985dae84929SEmanuele Giuseppe Esposito goto perm_cleanup; 986dae84929SEmanuele Giuseppe Esposito } 98730da9dd8SMaxim Levitsky ret = block_crypto_amend_options_generic_luks(bs, amend_options, 98830da9dd8SMaxim Levitsky force, errp); 989dae84929SEmanuele Giuseppe Esposito 990dae84929SEmanuele Giuseppe Esposito perm_cleanup: 991dae84929SEmanuele Giuseppe Esposito block_crypto_amend_cleanup(bs); 99230da9dd8SMaxim Levitsky cleanup: 99330da9dd8SMaxim Levitsky qapi_free_QCryptoBlockAmendOptions(amend_options); 99430da9dd8SMaxim Levitsky return ret; 99530da9dd8SMaxim Levitsky } 99630da9dd8SMaxim Levitsky 99730da9dd8SMaxim Levitsky static int 99830da9dd8SMaxim Levitsky coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs, 99930da9dd8SMaxim Levitsky BlockdevAmendOptions *opts, 100030da9dd8SMaxim Levitsky bool force, 100130da9dd8SMaxim Levitsky Error **errp) 100230da9dd8SMaxim Levitsky { 100330da9dd8SMaxim Levitsky QCryptoBlockAmendOptions amend_opts; 100430da9dd8SMaxim Levitsky 100530da9dd8SMaxim Levitsky amend_opts = (QCryptoBlockAmendOptions) { 100630da9dd8SMaxim Levitsky .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, 100730da9dd8SMaxim Levitsky .u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks), 100830da9dd8SMaxim Levitsky }; 100930da9dd8SMaxim Levitsky return block_crypto_amend_options_generic_luks(bs, &amend_opts, 101030da9dd8SMaxim Levitsky force, errp); 101130da9dd8SMaxim Levitsky } 1012bbfdae91SMaxim Levitsky 1013bbfdae91SMaxim Levitsky static void 1014bbfdae91SMaxim Levitsky block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c, 1015bbfdae91SMaxim Levitsky const BdrvChildRole role, 1016bbfdae91SMaxim Levitsky BlockReopenQueue *reopen_queue, 1017bbfdae91SMaxim Levitsky uint64_t perm, uint64_t shared, 1018bbfdae91SMaxim Levitsky uint64_t *nperm, uint64_t *nshared) 1019bbfdae91SMaxim Levitsky { 1020bbfdae91SMaxim Levitsky 1021bbfdae91SMaxim Levitsky BlockCrypto *crypto = bs->opaque; 1022bbfdae91SMaxim Levitsky 1023bbfdae91SMaxim Levitsky bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); 1024bbfdae91SMaxim Levitsky 1025bbfdae91SMaxim Levitsky /* 1026bbfdae91SMaxim Levitsky * For backward compatibility, manually share the write 1027bbfdae91SMaxim Levitsky * and resize permission 1028bbfdae91SMaxim Levitsky */ 1029662d0c53SMaxim Levitsky *nshared |= shared & (BLK_PERM_WRITE | BLK_PERM_RESIZE); 1030bbfdae91SMaxim Levitsky /* 1031bbfdae91SMaxim Levitsky * Since we are not fully a format driver, don't always request 1032bbfdae91SMaxim Levitsky * the read/resize permission but only when explicitly 1033bbfdae91SMaxim Levitsky * requested 1034bbfdae91SMaxim Levitsky */ 1035bbfdae91SMaxim Levitsky *nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); 1036bbfdae91SMaxim Levitsky *nperm |= perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE); 1037bbfdae91SMaxim Levitsky 1038bbfdae91SMaxim Levitsky /* 1039bbfdae91SMaxim Levitsky * This driver doesn't modify LUKS metadata except 1040bbfdae91SMaxim Levitsky * when updating the encryption slots. 1041bbfdae91SMaxim Levitsky * Thus unlike a proper format driver we don't ask for 1042bbfdae91SMaxim Levitsky * shared write/read permission. However we need it 1043bbfdae91SMaxim Levitsky * when we are updating the keys, to ensure that only we 1044bbfdae91SMaxim Levitsky * have access to the device. 1045bbfdae91SMaxim Levitsky * 1046bbfdae91SMaxim Levitsky * Encryption update will set the crypto->updating_keys 1047bbfdae91SMaxim Levitsky * during that period and refresh permissions 1048bbfdae91SMaxim Levitsky * 1049bbfdae91SMaxim Levitsky */ 1050bbfdae91SMaxim Levitsky if (crypto->updating_keys) { 1051bbfdae91SMaxim Levitsky /* need exclusive write access for header update */ 1052bbfdae91SMaxim Levitsky *nperm |= BLK_PERM_WRITE; 1053bbfdae91SMaxim Levitsky /* unshare read and write permission */ 1054bbfdae91SMaxim Levitsky *nshared &= ~(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE); 1055bbfdae91SMaxim Levitsky } 1056bbfdae91SMaxim Levitsky } 1057bbfdae91SMaxim Levitsky 1058bbfdae91SMaxim Levitsky 10592654267cSMax Reitz static const char *const block_crypto_strong_runtime_opts[] = { 10602654267cSMax Reitz BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, 10612654267cSMax Reitz 10622654267cSMax Reitz NULL 10632654267cSMax Reitz }; 10642654267cSMax Reitz 1065782b9d06SAlberto Garcia static BlockDriver bdrv_crypto_luks = { 106678368575SDaniel P. Berrange .format_name = "luks", 106778368575SDaniel P. Berrange .instance_size = sizeof(BlockCrypto), 106878368575SDaniel P. Berrange .bdrv_probe = block_crypto_probe_luks, 106978368575SDaniel P. Berrange .bdrv_open = block_crypto_open_luks, 107078368575SDaniel P. Berrange .bdrv_close = block_crypto_close, 1071bbfdae91SMaxim Levitsky .bdrv_child_perm = block_crypto_child_perms, 10721bedcaf1SKevin Wolf .bdrv_co_create = block_crypto_co_create_luks, 1073efc75e2aSStefan Hajnoczi .bdrv_co_create_opts = block_crypto_co_create_opts_luks, 1074061ca8a3SKevin Wolf .bdrv_co_truncate = block_crypto_co_truncate, 107578368575SDaniel P. Berrange .create_opts = &block_crypto_create_opts_luks, 1076bbfdae91SMaxim Levitsky .amend_opts = &block_crypto_amend_opts_luks, 107778368575SDaniel P. Berrange 1078f87e08f9SDaniel P. Berrange .bdrv_reopen_prepare = block_crypto_reopen_prepare, 1079a73466fbSDaniel P. Berrange .bdrv_refresh_limits = block_crypto_refresh_limits, 1080a73466fbSDaniel P. Berrange .bdrv_co_preadv = block_crypto_co_preadv, 1081a73466fbSDaniel P. Berrange .bdrv_co_pwritev = block_crypto_co_pwritev, 1082c86422c5SEmanuele Giuseppe Esposito .bdrv_co_getlength = block_crypto_co_getlength, 1083a9da6e49SStefan Hajnoczi .bdrv_measure = block_crypto_measure, 10843d47eb0aSEmanuele Giuseppe Esposito .bdrv_co_get_info = block_crypto_co_get_info_luks, 1085c7c4cf49SDaniel P. Berrange .bdrv_get_specific_info = block_crypto_get_specific_info_luks, 1086bbfdae91SMaxim Levitsky .bdrv_amend_options = block_crypto_amend_options_luks, 108730da9dd8SMaxim Levitsky .bdrv_co_amend = block_crypto_co_amend_luks, 1088c1019d16SEmanuele Giuseppe Esposito .bdrv_amend_pre_run = block_crypto_amend_prepare, 1089c1019d16SEmanuele Giuseppe Esposito .bdrv_amend_clean = block_crypto_amend_cleanup, 10902654267cSMax Reitz 1091d67066d8SMax Reitz .is_format = true, 1092d67066d8SMax Reitz 10932654267cSMax Reitz .strong_runtime_opts = block_crypto_strong_runtime_opts, 109478368575SDaniel P. Berrange }; 109578368575SDaniel P. Berrange 109678368575SDaniel P. Berrange static void block_crypto_init(void) 109778368575SDaniel P. Berrange { 109878368575SDaniel P. Berrange bdrv_register(&bdrv_crypto_luks); 109978368575SDaniel P. Berrange } 110078368575SDaniel P. Berrange 110178368575SDaniel P. Berrange block_init(block_crypto_init); 1102