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
block_crypto_probe_generic(QCryptoBlockFormat format,const uint8_t * buf,int buf_size,const char * filename)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
block_crypto_read_func(QCryptoBlock * block,size_t offset,uint8_t * buf,size_t buflen,void * opaque,Error ** errp)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
block_crypto_write_func(QCryptoBlock * block,size_t offset,const uint8_t * buf,size_t buflen,void * opaque,Error ** errp)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
block_crypto_create_write_func(QCryptoBlock * block,size_t offset,const uint8_t * buf,size_t buflen,void * opaque,Error ** errp)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
block_crypto_create_init_func(QCryptoBlock * block,size_t headerlen,void * opaque,Error ** errp)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
block_crypto_co_format_luks_payload(BlockdevCreateOptionsLUKS * luks_opts,Error ** errp)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(""),
23435286daeSHyman 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 *
block_crypto_open_opts_init(QDict * opts,Error ** errp)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 *
block_crypto_create_opts_init(QDict * opts,Error ** errp)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 *
block_crypto_amend_opts_init(QDict * opts,Error ** errp)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
block_crypto_open_generic(QCryptoBlockFormat format,QemuOptsList * opts_spec,BlockDriverState * bs,QDict * options,int flags,Error ** errp)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,
36678368575SDaniel P. Berrange errp);
36778368575SDaniel P. Berrange
36878368575SDaniel P. Berrange if (!crypto->block) {
36978368575SDaniel P. Berrange ret = -EIO;
37078368575SDaniel P. Berrange goto cleanup;
37178368575SDaniel P. Berrange }
37278368575SDaniel P. Berrange
37354115412SEric Blake bs->encrypted = true;
37478368575SDaniel P. Berrange
37578368575SDaniel P. Berrange ret = 0;
37678368575SDaniel P. Berrange cleanup:
377cb3e7f08SMarc-André Lureau qobject_unref(cryptoopts);
37878368575SDaniel P. Berrange qapi_free_QCryptoBlockOpenOptions(open_opts);
37978368575SDaniel P. Berrange return ret;
38078368575SDaniel P. Berrange }
38178368575SDaniel P. Berrange
38278368575SDaniel P. Berrange
3834db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED
block_crypto_co_create_generic(BlockDriverState * bs,int64_t size,QCryptoBlockCreateOptions * opts,PreallocMode prealloc,unsigned int flags,Error ** errp)38491817e9cSKevin Wolf block_crypto_co_create_generic(BlockDriverState *bs, int64_t size,
3851ec4f416SKevin Wolf QCryptoBlockCreateOptions *opts,
386d0112eb4SHyman Huang PreallocMode prealloc,
387d0112eb4SHyman Huang unsigned int flags,
388d0112eb4SHyman Huang Error **errp)
38978368575SDaniel P. Berrange {
3901ec4f416SKevin Wolf int ret;
3911ec4f416SKevin Wolf BlockBackend *blk;
39278368575SDaniel P. Berrange QCryptoBlock *crypto = NULL;
3931ec4f416SKevin Wolf struct BlockCryptoCreateData data;
39478368575SDaniel P. Berrange
39591817e9cSKevin Wolf blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL,
396a3aeeab5SEric Blake errp);
397a3aeeab5SEric Blake if (!blk) {
398a3aeeab5SEric Blake ret = -EPERM;
3991ec4f416SKevin Wolf goto cleanup;
4003b5a1f6aSKevin Wolf }
4013b5a1f6aSKevin Wolf
402672de729SMaxim Levitsky if (prealloc == PREALLOC_MODE_METADATA) {
403672de729SMaxim Levitsky prealloc = PREALLOC_MODE_OFF;
404672de729SMaxim Levitsky }
405672de729SMaxim Levitsky
4061ec4f416SKevin Wolf data = (struct BlockCryptoCreateData) {
4071ec4f416SKevin Wolf .blk = blk,
40835286daeSHyman Huang .size = flags & QCRYPTO_BLOCK_CREATE_DETACHED ? 0 : size,
409672de729SMaxim Levitsky .prealloc = prealloc,
4101ec4f416SKevin Wolf };
4113b5a1f6aSKevin Wolf
4121ec4f416SKevin Wolf crypto = qcrypto_block_create(opts, NULL,
413e0d0ddc5SMaxim Levitsky block_crypto_create_init_func,
414e0d0ddc5SMaxim Levitsky block_crypto_create_write_func,
41578368575SDaniel P. Berrange &data,
416d0112eb4SHyman Huang flags,
41778368575SDaniel P. Berrange errp);
41878368575SDaniel P. Berrange
41978368575SDaniel P. Berrange if (!crypto) {
42078368575SDaniel P. Berrange ret = -EIO;
42178368575SDaniel P. Berrange goto cleanup;
42278368575SDaniel P. Berrange }
42378368575SDaniel P. Berrange
42478368575SDaniel P. Berrange ret = 0;
42578368575SDaniel P. Berrange cleanup:
42678368575SDaniel P. Berrange qcrypto_block_free(crypto);
427b2ab5f54SKevin Wolf blk_co_unref(blk);
42878368575SDaniel P. Berrange return ret;
42978368575SDaniel P. Berrange }
43078368575SDaniel P. Berrange
431c2b8e315SKevin Wolf static int coroutine_fn GRAPH_RDLOCK
block_crypto_co_truncate(BlockDriverState * bs,int64_t offset,bool exact,PreallocMode prealloc,BdrvRequestFlags flags,Error ** errp)432c80d8b06SMax Reitz block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
43392b92799SKevin Wolf PreallocMode prealloc, BdrvRequestFlags flags,
43492b92799SKevin Wolf Error **errp)
43578368575SDaniel P. Berrange {
43678368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque;
43731376555SDaniel P. Berrange uint64_t payload_offset =
43878368575SDaniel P. Berrange qcrypto_block_get_payload_offset(crypto->block);
439120bc742SKevin Wolf
440120bc742SKevin Wolf if (payload_offset > INT64_MAX - offset) {
441120bc742SKevin Wolf error_setg(errp, "The requested file size is too large");
442120bc742SKevin Wolf return -EFBIG;
443120bc742SKevin Wolf }
44478368575SDaniel P. Berrange
44578368575SDaniel P. Berrange offset += payload_offset;
44678368575SDaniel P. Berrange
4477b8e4857SKevin Wolf return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
44878368575SDaniel P. Berrange }
44978368575SDaniel P. Berrange
block_crypto_close(BlockDriverState * bs)45078368575SDaniel P. Berrange static void block_crypto_close(BlockDriverState *bs)
45178368575SDaniel P. Berrange {
45278368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque;
45378368575SDaniel P. Berrange qcrypto_block_free(crypto->block);
45478368575SDaniel P. Berrange }
45578368575SDaniel P. Berrange
block_crypto_reopen_prepare(BDRVReopenState * state,BlockReopenQueue * queue,Error ** errp)456f87e08f9SDaniel P. Berrange static int block_crypto_reopen_prepare(BDRVReopenState *state,
457f87e08f9SDaniel P. Berrange BlockReopenQueue *queue, Error **errp)
458f87e08f9SDaniel P. Berrange {
459f87e08f9SDaniel P. Berrange /* nothing needs checking */
460f87e08f9SDaniel P. Berrange return 0;
461f87e08f9SDaniel P. Berrange }
46278368575SDaniel P. Berrange
463161253e2SDaniel P. Berrange /*
464161253e2SDaniel P. Berrange * 1 MB bounce buffer gives good performance / memory tradeoff
465161253e2SDaniel P. Berrange * when using cache=none|directsync.
466161253e2SDaniel P. Berrange */
467161253e2SDaniel P. Berrange #define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
46878368575SDaniel P. Berrange
469b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK
block_crypto_co_preadv(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)470f7ef38ddSVladimir Sementsov-Ogievskiy block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
471f7ef38ddSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags)
47278368575SDaniel P. Berrange {
47378368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque;
474a73466fbSDaniel P. Berrange uint64_t cur_bytes; /* number of bytes in current iteration */
47578368575SDaniel P. Berrange uint64_t bytes_done = 0;
47678368575SDaniel P. Berrange uint8_t *cipher_data = NULL;
47778368575SDaniel P. Berrange QEMUIOVector hd_qiov;
47878368575SDaniel P. Berrange int ret = 0;
479a73466fbSDaniel P. Berrange uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
480a73466fbSDaniel P. Berrange uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
481a73466fbSDaniel P. Berrange
482a73466fbSDaniel P. Berrange assert(payload_offset < INT64_MAX);
483a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(offset, sector_size));
484a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(bytes, sector_size));
48578368575SDaniel P. Berrange
48678368575SDaniel P. Berrange qemu_iovec_init(&hd_qiov, qiov->niov);
48778368575SDaniel P. Berrange
488161253e2SDaniel P. Berrange /* Bounce buffer because we don't wish to expose cipher text
489161253e2SDaniel P. Berrange * in qiov which points to guest memory.
49078368575SDaniel P. Berrange */
49178368575SDaniel P. Berrange cipher_data =
492161253e2SDaniel P. Berrange qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
49378368575SDaniel P. Berrange qiov->size));
49478368575SDaniel P. Berrange if (cipher_data == NULL) {
49578368575SDaniel P. Berrange ret = -ENOMEM;
49678368575SDaniel P. Berrange goto cleanup;
49778368575SDaniel P. Berrange }
49878368575SDaniel P. Berrange
499a73466fbSDaniel P. Berrange while (bytes) {
500a73466fbSDaniel P. Berrange cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
50178368575SDaniel P. Berrange
50278368575SDaniel P. Berrange qemu_iovec_reset(&hd_qiov);
503a73466fbSDaniel P. Berrange qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
50478368575SDaniel P. Berrange
505a73466fbSDaniel P. Berrange ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done,
506a73466fbSDaniel P. Berrange cur_bytes, &hd_qiov, 0);
50778368575SDaniel P. Berrange if (ret < 0) {
50878368575SDaniel P. Berrange goto cleanup;
50978368575SDaniel P. Berrange }
51078368575SDaniel P. Berrange
5114609742aSDaniel P. Berrange if (qcrypto_block_decrypt(crypto->block, offset + bytes_done,
5124609742aSDaniel P. Berrange cipher_data, cur_bytes, NULL) < 0) {
51378368575SDaniel P. Berrange ret = -EIO;
51478368575SDaniel P. Berrange goto cleanup;
51578368575SDaniel P. Berrange }
51678368575SDaniel P. Berrange
517a73466fbSDaniel P. Berrange qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
51878368575SDaniel P. Berrange
519a73466fbSDaniel P. Berrange bytes -= cur_bytes;
520a73466fbSDaniel P. Berrange bytes_done += cur_bytes;
52178368575SDaniel P. Berrange }
52278368575SDaniel P. Berrange
52378368575SDaniel P. Berrange cleanup:
52478368575SDaniel P. Berrange qemu_iovec_destroy(&hd_qiov);
52578368575SDaniel P. Berrange qemu_vfree(cipher_data);
52678368575SDaniel P. Berrange
52778368575SDaniel P. Berrange return ret;
52878368575SDaniel P. Berrange }
52978368575SDaniel P. Berrange
53078368575SDaniel P. Berrange
531b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK
block_crypto_co_pwritev(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)532e75abedaSVladimir Sementsov-Ogievskiy block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
533e75abedaSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags)
53478368575SDaniel P. Berrange {
53578368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque;
536a73466fbSDaniel P. Berrange uint64_t cur_bytes; /* number of bytes in current iteration */
53778368575SDaniel P. Berrange uint64_t bytes_done = 0;
53878368575SDaniel P. Berrange uint8_t *cipher_data = NULL;
53978368575SDaniel P. Berrange QEMUIOVector hd_qiov;
54078368575SDaniel P. Berrange int ret = 0;
541a73466fbSDaniel P. Berrange uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
542a73466fbSDaniel P. Berrange uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
543a73466fbSDaniel P. Berrange
544e8b65355SStefan Hajnoczi flags &= ~BDRV_REQ_REGISTERED_BUF;
545e8b65355SStefan Hajnoczi
546a73466fbSDaniel P. Berrange assert(payload_offset < INT64_MAX);
547a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(offset, sector_size));
548a73466fbSDaniel P. Berrange assert(QEMU_IS_ALIGNED(bytes, sector_size));
54978368575SDaniel P. Berrange
55078368575SDaniel P. Berrange qemu_iovec_init(&hd_qiov, qiov->niov);
55178368575SDaniel P. Berrange
552161253e2SDaniel P. Berrange /* Bounce buffer because we're not permitted to touch
553161253e2SDaniel P. Berrange * contents of qiov - it points to guest memory.
55478368575SDaniel P. Berrange */
55578368575SDaniel P. Berrange cipher_data =
556161253e2SDaniel P. Berrange qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
55778368575SDaniel P. Berrange qiov->size));
55878368575SDaniel P. Berrange if (cipher_data == NULL) {
55978368575SDaniel P. Berrange ret = -ENOMEM;
56078368575SDaniel P. Berrange goto cleanup;
56178368575SDaniel P. Berrange }
56278368575SDaniel P. Berrange
563a73466fbSDaniel P. Berrange while (bytes) {
564a73466fbSDaniel P. Berrange cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
56578368575SDaniel P. Berrange
566a73466fbSDaniel P. Berrange qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
56778368575SDaniel P. Berrange
5684609742aSDaniel P. Berrange if (qcrypto_block_encrypt(crypto->block, offset + bytes_done,
5694609742aSDaniel P. Berrange cipher_data, cur_bytes, NULL) < 0) {
57078368575SDaniel P. Berrange ret = -EIO;
57178368575SDaniel P. Berrange goto cleanup;
57278368575SDaniel P. Berrange }
57378368575SDaniel P. Berrange
57478368575SDaniel P. Berrange qemu_iovec_reset(&hd_qiov);
575a73466fbSDaniel P. Berrange qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
57678368575SDaniel P. Berrange
577a73466fbSDaniel P. Berrange ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
578d67a6b09SDaniel P. Berrange cur_bytes, &hd_qiov, flags);
57978368575SDaniel P. Berrange if (ret < 0) {
58078368575SDaniel P. Berrange goto cleanup;
58178368575SDaniel P. Berrange }
58278368575SDaniel P. Berrange
583a73466fbSDaniel P. Berrange bytes -= cur_bytes;
584a73466fbSDaniel P. Berrange bytes_done += cur_bytes;
58578368575SDaniel P. Berrange }
58678368575SDaniel P. Berrange
58778368575SDaniel P. Berrange cleanup:
58878368575SDaniel P. Berrange qemu_iovec_destroy(&hd_qiov);
58978368575SDaniel P. Berrange qemu_vfree(cipher_data);
59078368575SDaniel P. Berrange
59178368575SDaniel P. Berrange return ret;
59278368575SDaniel P. Berrange }
59378368575SDaniel P. Berrange
block_crypto_refresh_limits(BlockDriverState * bs,Error ** errp)594a73466fbSDaniel P. Berrange static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp)
595a73466fbSDaniel P. Berrange {
596a73466fbSDaniel P. Berrange BlockCrypto *crypto = bs->opaque;
597a73466fbSDaniel P. Berrange uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
598a73466fbSDaniel P. Berrange bs->bl.request_alignment = sector_size; /* No sub-sector I/O */
599a73466fbSDaniel P. Berrange }
600a73466fbSDaniel P. Berrange
60178368575SDaniel P. Berrange
6028ab8140aSKevin Wolf static int64_t coroutine_fn GRAPH_RDLOCK
block_crypto_co_getlength(BlockDriverState * bs)6038ab8140aSKevin Wolf block_crypto_co_getlength(BlockDriverState *bs)
60478368575SDaniel P. Berrange {
60578368575SDaniel P. Berrange BlockCrypto *crypto = bs->opaque;
606c86422c5SEmanuele Giuseppe Esposito int64_t len = bdrv_co_getlength(bs->file->bs);
60778368575SDaniel P. Berrange
60831376555SDaniel P. Berrange uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
60931376555SDaniel P. Berrange assert(offset < INT64_MAX);
610e39e959eSKevin Wolf
611e39e959eSKevin Wolf if (offset > len) {
612e39e959eSKevin Wolf return -EIO;
613e39e959eSKevin Wolf }
61478368575SDaniel P. Berrange
61578368575SDaniel P. Berrange len -= offset;
61678368575SDaniel P. Berrange
61778368575SDaniel P. Berrange return len;
61878368575SDaniel P. Berrange }
61978368575SDaniel P. Berrange
62078368575SDaniel P. Berrange
block_crypto_measure(QemuOpts * opts,BlockDriverState * in_bs,Error ** errp)621a9da6e49SStefan Hajnoczi static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts,
622a9da6e49SStefan Hajnoczi BlockDriverState *in_bs,
623a9da6e49SStefan Hajnoczi Error **errp)
624a9da6e49SStefan Hajnoczi {
625a9da6e49SStefan Hajnoczi g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
626a9da6e49SStefan Hajnoczi Error *local_err = NULL;
627a9da6e49SStefan Hajnoczi BlockMeasureInfo *info;
628a9da6e49SStefan Hajnoczi uint64_t size;
629a9da6e49SStefan Hajnoczi size_t luks_payload_size;
630a9da6e49SStefan Hajnoczi QDict *cryptoopts;
631a9da6e49SStefan Hajnoczi
632a9da6e49SStefan Hajnoczi /*
633a9da6e49SStefan Hajnoczi * Preallocation mode doesn't affect size requirements but we must consume
634a9da6e49SStefan Hajnoczi * the option.
635a9da6e49SStefan Hajnoczi */
636a9da6e49SStefan Hajnoczi g_free(qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC));
637a9da6e49SStefan Hajnoczi
638a9da6e49SStefan Hajnoczi size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
639a9da6e49SStefan Hajnoczi
640a9da6e49SStefan Hajnoczi if (in_bs) {
641a9da6e49SStefan Hajnoczi int64_t ssize = bdrv_getlength(in_bs);
642a9da6e49SStefan Hajnoczi
643a9da6e49SStefan Hajnoczi if (ssize < 0) {
644a9da6e49SStefan Hajnoczi error_setg_errno(&local_err, -ssize,
645a9da6e49SStefan Hajnoczi "Unable to get image virtual_size");
646a9da6e49SStefan Hajnoczi goto err;
647a9da6e49SStefan Hajnoczi }
648a9da6e49SStefan Hajnoczi
649a9da6e49SStefan Hajnoczi size = ssize;
650a9da6e49SStefan Hajnoczi }
651a9da6e49SStefan Hajnoczi
652a9da6e49SStefan Hajnoczi cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
653a9da6e49SStefan Hajnoczi &block_crypto_create_opts_luks, true);
654a9da6e49SStefan Hajnoczi qdict_put_str(cryptoopts, "format", "luks");
655a9da6e49SStefan Hajnoczi create_opts = block_crypto_create_opts_init(cryptoopts, &local_err);
656a9da6e49SStefan Hajnoczi qobject_unref(cryptoopts);
657a9da6e49SStefan Hajnoczi if (!create_opts) {
658a9da6e49SStefan Hajnoczi goto err;
659a9da6e49SStefan Hajnoczi }
660a9da6e49SStefan Hajnoczi
661a9da6e49SStefan Hajnoczi if (!qcrypto_block_calculate_payload_offset(create_opts, NULL,
662a9da6e49SStefan Hajnoczi &luks_payload_size,
663a9da6e49SStefan Hajnoczi &local_err)) {
664a9da6e49SStefan Hajnoczi goto err;
665a9da6e49SStefan Hajnoczi }
666a9da6e49SStefan Hajnoczi
667a9da6e49SStefan Hajnoczi /*
668a9da6e49SStefan Hajnoczi * Unallocated blocks are still encrypted so allocation status makes no
669a9da6e49SStefan Hajnoczi * difference to the file size.
670a9da6e49SStefan Hajnoczi */
6715d72c68bSEric Blake info = g_new0(BlockMeasureInfo, 1);
672a9da6e49SStefan Hajnoczi info->fully_allocated = luks_payload_size + size;
673a9da6e49SStefan Hajnoczi info->required = luks_payload_size + size;
674a9da6e49SStefan Hajnoczi return info;
675a9da6e49SStefan Hajnoczi
676a9da6e49SStefan Hajnoczi err:
677a9da6e49SStefan Hajnoczi error_propagate(errp, local_err);
678a9da6e49SStefan Hajnoczi return NULL;
679a9da6e49SStefan Hajnoczi }
680a9da6e49SStefan Hajnoczi
681a9da6e49SStefan Hajnoczi
block_crypto_probe_luks(const uint8_t * buf,int buf_size,const char * filename)68278368575SDaniel P. Berrange static int block_crypto_probe_luks(const uint8_t *buf,
68378368575SDaniel P. Berrange int buf_size,
68478368575SDaniel P. Berrange const char *filename) {
685*d23d2ef3SMarkus Armbruster return block_crypto_probe_generic(QCRYPTO_BLOCK_FORMAT_LUKS,
68678368575SDaniel P. Berrange buf, buf_size, filename);
68778368575SDaniel P. Berrange }
68878368575SDaniel P. Berrange
block_crypto_open_luks(BlockDriverState * bs,QDict * options,int flags,Error ** errp)68978368575SDaniel P. Berrange static int block_crypto_open_luks(BlockDriverState *bs,
69078368575SDaniel P. Berrange QDict *options,
69178368575SDaniel P. Berrange int flags,
69278368575SDaniel P. Berrange Error **errp)
69378368575SDaniel P. Berrange {
694*d23d2ef3SMarkus Armbruster return block_crypto_open_generic(QCRYPTO_BLOCK_FORMAT_LUKS,
69578368575SDaniel P. Berrange &block_crypto_runtime_opts_luks,
69678368575SDaniel P. Berrange bs, options, flags, errp);
69778368575SDaniel P. Berrange }
69878368575SDaniel P. Berrange
6994db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED
block_crypto_co_create_luks(BlockdevCreateOptions * create_options,Error ** errp)7001bedcaf1SKevin Wolf block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
7011bedcaf1SKevin Wolf {
7021bedcaf1SKevin Wolf BlockdevCreateOptionsLUKS *luks_opts;
703d0112eb4SHyman Huang BlockDriverState *hdr_bs = NULL;
7041bedcaf1SKevin Wolf BlockDriverState *bs = NULL;
7051bedcaf1SKevin Wolf QCryptoBlockCreateOptions create_opts;
706672de729SMaxim Levitsky PreallocMode preallocation = PREALLOC_MODE_OFF;
707d0112eb4SHyman Huang unsigned int cflags = 0;
7081bedcaf1SKevin Wolf int ret;
7091bedcaf1SKevin Wolf
7101bedcaf1SKevin Wolf assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
7111bedcaf1SKevin Wolf luks_opts = &create_options->u.luks;
7121bedcaf1SKevin Wolf
713d0112eb4SHyman Huang if (luks_opts->header == NULL && luks_opts->file == NULL) {
714d0112eb4SHyman Huang error_setg(errp, "Either the parameter 'header' or 'file' must "
715d0112eb4SHyman Huang "be specified");
716d0112eb4SHyman Huang return -EINVAL;
717d0112eb4SHyman Huang }
718d0112eb4SHyman Huang
719d0112eb4SHyman Huang if ((luks_opts->preallocation != PREALLOC_MODE_OFF) &&
720d0112eb4SHyman Huang (luks_opts->file == NULL)) {
721d0112eb4SHyman Huang error_setg(errp, "Parameter 'preallocation' requires 'file' to be "
722d0112eb4SHyman Huang "specified for formatting LUKS disk");
723433957bbSHyman Huang return -EINVAL;
7241bedcaf1SKevin Wolf }
7251bedcaf1SKevin Wolf
7261bedcaf1SKevin Wolf create_opts = (QCryptoBlockCreateOptions) {
727*d23d2ef3SMarkus Armbruster .format = QCRYPTO_BLOCK_FORMAT_LUKS,
7281bedcaf1SKevin Wolf .u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
7291bedcaf1SKevin Wolf };
7301bedcaf1SKevin Wolf
731672de729SMaxim Levitsky if (luks_opts->has_preallocation) {
732672de729SMaxim Levitsky preallocation = luks_opts->preallocation;
733672de729SMaxim Levitsky }
734672de729SMaxim Levitsky
735d0112eb4SHyman Huang if (luks_opts->header) {
736d0112eb4SHyman Huang /* LUKS volume with detached header */
737d0112eb4SHyman Huang hdr_bs = bdrv_co_open_blockdev_ref(luks_opts->header, errp);
738d0112eb4SHyman Huang if (hdr_bs == NULL) {
739d0112eb4SHyman Huang return -EIO;
740d0112eb4SHyman Huang }
741d0112eb4SHyman Huang
742d0112eb4SHyman Huang cflags |= QCRYPTO_BLOCK_CREATE_DETACHED;
743d0112eb4SHyman Huang
744d0112eb4SHyman Huang /* Format the LUKS header node */
745d0112eb4SHyman Huang ret = block_crypto_co_create_generic(hdr_bs, 0, &create_opts,
746d0112eb4SHyman Huang PREALLOC_MODE_OFF, cflags, errp);
747d0112eb4SHyman Huang if (ret < 0) {
748d0112eb4SHyman Huang goto fail;
749d0112eb4SHyman Huang }
750d0112eb4SHyman Huang
751d0112eb4SHyman Huang /* Format the LUKS payload node */
752433957bbSHyman Huang if (luks_opts->file) {
753d0112eb4SHyman Huang ret = block_crypto_co_format_luks_payload(luks_opts, errp);
754d0112eb4SHyman Huang if (ret < 0) {
755d0112eb4SHyman Huang goto fail;
756d0112eb4SHyman Huang }
757d0112eb4SHyman Huang }
758d0112eb4SHyman Huang } else if (luks_opts->file) {
759d0112eb4SHyman Huang /* LUKS volume with none-detached header */
760433957bbSHyman Huang bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp);
761433957bbSHyman Huang if (bs == NULL) {
762433957bbSHyman Huang return -EIO;
763433957bbSHyman Huang }
764433957bbSHyman Huang
7651bedcaf1SKevin Wolf ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
766d0112eb4SHyman Huang preallocation, cflags, errp);
7671bedcaf1SKevin Wolf if (ret < 0) {
7681bedcaf1SKevin Wolf goto fail;
7691bedcaf1SKevin Wolf }
770433957bbSHyman Huang }
7711bedcaf1SKevin Wolf
7721bedcaf1SKevin Wolf ret = 0;
7731bedcaf1SKevin Wolf fail:
774d0112eb4SHyman Huang if (hdr_bs != NULL) {
775d0112eb4SHyman Huang bdrv_co_unref(hdr_bs);
776d0112eb4SHyman Huang }
777d0112eb4SHyman Huang
778d0112eb4SHyman Huang if (bs != NULL) {
779b2ab5f54SKevin Wolf bdrv_co_unref(bs);
780d0112eb4SHyman Huang }
7811bedcaf1SKevin Wolf return ret;
7821bedcaf1SKevin Wolf }
7831bedcaf1SKevin Wolf
7844db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED
block_crypto_co_create_opts_luks(BlockDriver * drv,const char * filename,QemuOpts * opts,Error ** errp)7854ec8df01SKevin Wolf block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
7864ec8df01SKevin Wolf QemuOpts *opts, Error **errp)
78778368575SDaniel P. Berrange {
7881ec4f416SKevin Wolf QCryptoBlockCreateOptions *create_opts = NULL;
7891ec4f416SKevin Wolf BlockDriverState *bs = NULL;
7901ec4f416SKevin Wolf QDict *cryptoopts;
791672de729SMaxim Levitsky PreallocMode prealloc;
792672de729SMaxim Levitsky char *buf = NULL;
7931ec4f416SKevin Wolf int64_t size;
79435286daeSHyman Huang bool detached_hdr =
79535286daeSHyman Huang qemu_opt_get_bool(opts, "detached-header", false);
79635286daeSHyman Huang unsigned int cflags = 0;
7971ec4f416SKevin Wolf int ret;
798672de729SMaxim Levitsky Error *local_err = NULL;
7991ec4f416SKevin Wolf
8001ec4f416SKevin Wolf /* Parse options */
8011ec4f416SKevin Wolf size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
8021ec4f416SKevin Wolf
803672de729SMaxim Levitsky buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
804672de729SMaxim Levitsky prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
805672de729SMaxim Levitsky PREALLOC_MODE_OFF, &local_err);
806672de729SMaxim Levitsky g_free(buf);
807672de729SMaxim Levitsky if (local_err) {
808672de729SMaxim Levitsky error_propagate(errp, local_err);
809672de729SMaxim Levitsky return -EINVAL;
810672de729SMaxim Levitsky }
811672de729SMaxim Levitsky
8121ec4f416SKevin Wolf cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
8131ec4f416SKevin Wolf &block_crypto_create_opts_luks,
8141ec4f416SKevin Wolf true);
8151ec4f416SKevin Wolf
816796d3239SMarkus Armbruster qdict_put_str(cryptoopts, "format", "luks");
817796d3239SMarkus Armbruster create_opts = block_crypto_create_opts_init(cryptoopts, errp);
8181ec4f416SKevin Wolf if (!create_opts) {
8191ec4f416SKevin Wolf ret = -EINVAL;
8201ec4f416SKevin Wolf goto fail;
8211ec4f416SKevin Wolf }
8221ec4f416SKevin Wolf
8231ec4f416SKevin Wolf /* Create protocol layer */
8242475a0d0SEmanuele Giuseppe Esposito ret = bdrv_co_create_file(filename, opts, errp);
8251ec4f416SKevin Wolf if (ret < 0) {
8260b68589dSKevin Wolf goto fail;
8271ec4f416SKevin Wolf }
8281ec4f416SKevin Wolf
82991817e9cSKevin Wolf bs = bdrv_co_open(filename, NULL, NULL,
8301ec4f416SKevin Wolf BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
8311ec4f416SKevin Wolf if (!bs) {
8321ec4f416SKevin Wolf ret = -EINVAL;
8331ec4f416SKevin Wolf goto fail;
8341ec4f416SKevin Wolf }
8351ec4f416SKevin Wolf
83635286daeSHyman Huang if (detached_hdr) {
83735286daeSHyman Huang cflags |= QCRYPTO_BLOCK_CREATE_DETACHED;
83835286daeSHyman Huang }
83935286daeSHyman Huang
8401ec4f416SKevin Wolf /* Create format layer */
841d0112eb4SHyman Huang ret = block_crypto_co_create_generic(bs, size, create_opts,
84235286daeSHyman Huang prealloc, cflags, errp);
8431ec4f416SKevin Wolf if (ret < 0) {
8441ec4f416SKevin Wolf goto fail;
8451ec4f416SKevin Wolf }
8461ec4f416SKevin Wolf
8471ec4f416SKevin Wolf ret = 0;
8481ec4f416SKevin Wolf fail:
8491bba30daSDaniel Henrique Barboza /*
8501bba30daSDaniel Henrique Barboza * If an error occurred, delete 'filename'. Even if the file existed
8511bba30daSDaniel Henrique Barboza * beforehand, it has been truncated and corrupted in the process.
8521bba30daSDaniel Henrique Barboza */
853a890f08eSMaxim Levitsky if (ret) {
8544db7ba3bSKevin Wolf bdrv_graph_co_rdlock();
855a890f08eSMaxim Levitsky bdrv_co_delete_file_noerr(bs);
8564db7ba3bSKevin Wolf bdrv_graph_co_rdunlock();
8571bba30daSDaniel Henrique Barboza }
8581bba30daSDaniel Henrique Barboza
859b2ab5f54SKevin Wolf bdrv_co_unref(bs);
8601ec4f416SKevin Wolf qapi_free_QCryptoBlockCreateOptions(create_opts);
861cb3e7f08SMarc-André Lureau qobject_unref(cryptoopts);
8621ec4f416SKevin Wolf return ret;
86378368575SDaniel P. Berrange }
86478368575SDaniel P. Berrange
865a00e70c0SEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK
block_crypto_co_get_info_luks(BlockDriverState * bs,BlockDriverInfo * bdi)8663d47eb0aSEmanuele Giuseppe Esposito block_crypto_co_get_info_luks(BlockDriverState *bs, BlockDriverInfo *bdi)
867c7c4cf49SDaniel P. Berrange {
868c7c4cf49SDaniel P. Berrange BlockDriverInfo subbdi;
869c7c4cf49SDaniel P. Berrange int ret;
870c7c4cf49SDaniel P. Berrange
8713d47eb0aSEmanuele Giuseppe Esposito ret = bdrv_co_get_info(bs->file->bs, &subbdi);
872c7c4cf49SDaniel P. Berrange if (ret != 0) {
873c7c4cf49SDaniel P. Berrange return ret;
874c7c4cf49SDaniel P. Berrange }
875c7c4cf49SDaniel P. Berrange
876c7c4cf49SDaniel P. Berrange bdi->cluster_size = subbdi.cluster_size;
877c7c4cf49SDaniel P. Berrange
878c7c4cf49SDaniel P. Berrange return 0;
879c7c4cf49SDaniel P. Berrange }
880c7c4cf49SDaniel P. Berrange
881c7c4cf49SDaniel P. Berrange static ImageInfoSpecific *
block_crypto_get_specific_info_luks(BlockDriverState * bs,Error ** errp)8821bf6e9caSAndrey Shinkevich block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
883c7c4cf49SDaniel P. Berrange {
884c7c4cf49SDaniel P. Berrange BlockCrypto *crypto = bs->opaque;
885c7c4cf49SDaniel P. Berrange ImageInfoSpecific *spec_info;
886c7c4cf49SDaniel P. Berrange QCryptoBlockInfo *info;
887c7c4cf49SDaniel P. Berrange
8881bf6e9caSAndrey Shinkevich info = qcrypto_block_get_info(crypto->block, errp);
889c7c4cf49SDaniel P. Berrange if (!info) {
890c7c4cf49SDaniel P. Berrange return NULL;
891c7c4cf49SDaniel P. Berrange }
892*d23d2ef3SMarkus Armbruster assert(info->format == QCRYPTO_BLOCK_FORMAT_LUKS);
893c7c4cf49SDaniel P. Berrange
894c7c4cf49SDaniel P. Berrange spec_info = g_new(ImageInfoSpecific, 1);
895c7c4cf49SDaniel P. Berrange spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS;
896c7c4cf49SDaniel P. Berrange spec_info->u.luks.data = g_new(QCryptoBlockInfoLUKS, 1);
897c7c4cf49SDaniel P. Berrange *spec_info->u.luks.data = info->u.luks;
898c7c4cf49SDaniel P. Berrange
899c7c4cf49SDaniel P. Berrange /* Blank out pointers we've just stolen to avoid double free */
900c7c4cf49SDaniel P. Berrange memset(&info->u.luks, 0, sizeof(info->u.luks));
901c7c4cf49SDaniel P. Berrange
902c7c4cf49SDaniel P. Berrange qapi_free_QCryptoBlockInfo(info);
903c7c4cf49SDaniel P. Berrange
904c7c4cf49SDaniel P. Berrange return spec_info;
905c7c4cf49SDaniel P. Berrange }
906c7c4cf49SDaniel P. Berrange
9073804e3cfSKevin Wolf static int GRAPH_RDLOCK
block_crypto_amend_prepare(BlockDriverState * bs,Error ** errp)908c1019d16SEmanuele Giuseppe Esposito block_crypto_amend_prepare(BlockDriverState *bs, Error **errp)
909c1019d16SEmanuele Giuseppe Esposito {
910c1019d16SEmanuele Giuseppe Esposito BlockCrypto *crypto = bs->opaque;
911c1019d16SEmanuele Giuseppe Esposito int ret;
912c1019d16SEmanuele Giuseppe Esposito
913c1019d16SEmanuele Giuseppe Esposito /* apply for exclusive read/write permissions to the underlying file */
914c1019d16SEmanuele Giuseppe Esposito crypto->updating_keys = true;
915c1019d16SEmanuele Giuseppe Esposito ret = bdrv_child_refresh_perms(bs, bs->file, errp);
916c1019d16SEmanuele Giuseppe Esposito if (ret < 0) {
917c1019d16SEmanuele Giuseppe Esposito /* Well, in this case we will not be updating any keys */
918c1019d16SEmanuele Giuseppe Esposito crypto->updating_keys = false;
919c1019d16SEmanuele Giuseppe Esposito }
920c1019d16SEmanuele Giuseppe Esposito return ret;
921c1019d16SEmanuele Giuseppe Esposito }
922c1019d16SEmanuele Giuseppe Esposito
9233804e3cfSKevin Wolf static void GRAPH_RDLOCK
block_crypto_amend_cleanup(BlockDriverState * bs)924c1019d16SEmanuele Giuseppe Esposito block_crypto_amend_cleanup(BlockDriverState *bs)
925c1019d16SEmanuele Giuseppe Esposito {
926c1019d16SEmanuele Giuseppe Esposito BlockCrypto *crypto = bs->opaque;
927c1019d16SEmanuele Giuseppe Esposito Error *errp = NULL;
928c1019d16SEmanuele Giuseppe Esposito
929c1019d16SEmanuele Giuseppe Esposito /* release exclusive read/write permissions to the underlying file */
930c1019d16SEmanuele Giuseppe Esposito crypto->updating_keys = false;
931c1019d16SEmanuele Giuseppe Esposito bdrv_child_refresh_perms(bs, bs->file, &errp);
932c1019d16SEmanuele Giuseppe Esposito
933c1019d16SEmanuele Giuseppe Esposito if (errp) {
934c1019d16SEmanuele Giuseppe Esposito error_report_err(errp);
935c1019d16SEmanuele Giuseppe Esposito }
936c1019d16SEmanuele Giuseppe Esposito }
937c1019d16SEmanuele Giuseppe Esposito
938c1019d16SEmanuele Giuseppe Esposito static int
block_crypto_amend_options_generic_luks(BlockDriverState * bs,QCryptoBlockAmendOptions * amend_options,bool force,Error ** errp)93930da9dd8SMaxim Levitsky block_crypto_amend_options_generic_luks(BlockDriverState *bs,
94030da9dd8SMaxim Levitsky QCryptoBlockAmendOptions *amend_options,
941bbfdae91SMaxim Levitsky bool force,
942bbfdae91SMaxim Levitsky Error **errp)
943bbfdae91SMaxim Levitsky {
944bbfdae91SMaxim Levitsky BlockCrypto *crypto = bs->opaque;
945bbfdae91SMaxim Levitsky
946bbfdae91SMaxim Levitsky assert(crypto);
947bbfdae91SMaxim Levitsky assert(crypto->block);
94830da9dd8SMaxim Levitsky
949dae84929SEmanuele Giuseppe Esposito return qcrypto_block_amend_options(crypto->block,
950bbfdae91SMaxim Levitsky block_crypto_read_func,
951bbfdae91SMaxim Levitsky block_crypto_write_func,
952bbfdae91SMaxim Levitsky bs,
953bbfdae91SMaxim Levitsky amend_options,
954bbfdae91SMaxim Levitsky force,
955bbfdae91SMaxim Levitsky errp);
956bbfdae91SMaxim Levitsky }
957bbfdae91SMaxim Levitsky
958bd131d67SKevin Wolf static int GRAPH_RDLOCK
block_crypto_amend_options_luks(BlockDriverState * bs,QemuOpts * opts,BlockDriverAmendStatusCB * status_cb,void * cb_opaque,bool force,Error ** errp)95930da9dd8SMaxim Levitsky block_crypto_amend_options_luks(BlockDriverState *bs,
96030da9dd8SMaxim Levitsky QemuOpts *opts,
96130da9dd8SMaxim Levitsky BlockDriverAmendStatusCB *status_cb,
96230da9dd8SMaxim Levitsky void *cb_opaque,
96330da9dd8SMaxim Levitsky bool force,
96430da9dd8SMaxim Levitsky Error **errp)
96530da9dd8SMaxim Levitsky {
96630da9dd8SMaxim Levitsky BlockCrypto *crypto = bs->opaque;
96730da9dd8SMaxim Levitsky QDict *cryptoopts = NULL;
96830da9dd8SMaxim Levitsky QCryptoBlockAmendOptions *amend_options = NULL;
96930da9dd8SMaxim Levitsky int ret = -EINVAL;
97030da9dd8SMaxim Levitsky
97130da9dd8SMaxim Levitsky assert(crypto);
97230da9dd8SMaxim Levitsky assert(crypto->block);
97330da9dd8SMaxim Levitsky
97430da9dd8SMaxim Levitsky cryptoopts = qemu_opts_to_qdict(opts, NULL);
97530da9dd8SMaxim Levitsky qdict_put_str(cryptoopts, "format", "luks");
97630da9dd8SMaxim Levitsky amend_options = block_crypto_amend_opts_init(cryptoopts, errp);
97730da9dd8SMaxim Levitsky qobject_unref(cryptoopts);
97830da9dd8SMaxim Levitsky if (!amend_options) {
97930da9dd8SMaxim Levitsky goto cleanup;
98030da9dd8SMaxim Levitsky }
981dae84929SEmanuele Giuseppe Esposito
982dae84929SEmanuele Giuseppe Esposito ret = block_crypto_amend_prepare(bs, errp);
983dae84929SEmanuele Giuseppe Esposito if (ret) {
984dae84929SEmanuele Giuseppe Esposito goto perm_cleanup;
985dae84929SEmanuele Giuseppe Esposito }
98630da9dd8SMaxim Levitsky ret = block_crypto_amend_options_generic_luks(bs, amend_options,
98730da9dd8SMaxim Levitsky force, errp);
988dae84929SEmanuele Giuseppe Esposito
989dae84929SEmanuele Giuseppe Esposito perm_cleanup:
990dae84929SEmanuele Giuseppe Esposito block_crypto_amend_cleanup(bs);
99130da9dd8SMaxim Levitsky cleanup:
99230da9dd8SMaxim Levitsky qapi_free_QCryptoBlockAmendOptions(amend_options);
99330da9dd8SMaxim Levitsky return ret;
99430da9dd8SMaxim Levitsky }
99530da9dd8SMaxim Levitsky
99630da9dd8SMaxim Levitsky static int
block_crypto_co_amend_luks(BlockDriverState * bs,BlockdevAmendOptions * opts,bool force,Error ** errp)99730da9dd8SMaxim Levitsky coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs,
99830da9dd8SMaxim Levitsky BlockdevAmendOptions *opts,
99930da9dd8SMaxim Levitsky bool force,
100030da9dd8SMaxim Levitsky Error **errp)
100130da9dd8SMaxim Levitsky {
100230da9dd8SMaxim Levitsky QCryptoBlockAmendOptions amend_opts;
100330da9dd8SMaxim Levitsky
100430da9dd8SMaxim Levitsky amend_opts = (QCryptoBlockAmendOptions) {
1005*d23d2ef3SMarkus Armbruster .format = QCRYPTO_BLOCK_FORMAT_LUKS,
100630da9dd8SMaxim Levitsky .u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks),
100730da9dd8SMaxim Levitsky };
100830da9dd8SMaxim Levitsky return block_crypto_amend_options_generic_luks(bs, &amend_opts,
100930da9dd8SMaxim Levitsky force, errp);
101030da9dd8SMaxim Levitsky }
1011bbfdae91SMaxim Levitsky
1012bbfdae91SMaxim Levitsky static void
block_crypto_child_perms(BlockDriverState * bs,BdrvChild * c,const BdrvChildRole role,BlockReopenQueue * reopen_queue,uint64_t perm,uint64_t shared,uint64_t * nperm,uint64_t * nshared)1013bbfdae91SMaxim Levitsky block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c,
1014bbfdae91SMaxim Levitsky const BdrvChildRole role,
1015bbfdae91SMaxim Levitsky BlockReopenQueue *reopen_queue,
1016bbfdae91SMaxim Levitsky uint64_t perm, uint64_t shared,
1017bbfdae91SMaxim Levitsky uint64_t *nperm, uint64_t *nshared)
1018bbfdae91SMaxim Levitsky {
1019bbfdae91SMaxim Levitsky
1020bbfdae91SMaxim Levitsky BlockCrypto *crypto = bs->opaque;
1021bbfdae91SMaxim Levitsky
1022bbfdae91SMaxim Levitsky bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared);
1023bbfdae91SMaxim Levitsky
1024bbfdae91SMaxim Levitsky /*
1025bbfdae91SMaxim Levitsky * For backward compatibility, manually share the write
1026bbfdae91SMaxim Levitsky * and resize permission
1027bbfdae91SMaxim Levitsky */
1028662d0c53SMaxim Levitsky *nshared |= shared & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
1029bbfdae91SMaxim Levitsky /*
1030bbfdae91SMaxim Levitsky * Since we are not fully a format driver, don't always request
1031bbfdae91SMaxim Levitsky * the read/resize permission but only when explicitly
1032bbfdae91SMaxim Levitsky * requested
1033bbfdae91SMaxim Levitsky */
1034bbfdae91SMaxim Levitsky *nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
1035bbfdae91SMaxim Levitsky *nperm |= perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
1036bbfdae91SMaxim Levitsky
1037bbfdae91SMaxim Levitsky /*
1038bbfdae91SMaxim Levitsky * This driver doesn't modify LUKS metadata except
1039bbfdae91SMaxim Levitsky * when updating the encryption slots.
1040bbfdae91SMaxim Levitsky * Thus unlike a proper format driver we don't ask for
1041bbfdae91SMaxim Levitsky * shared write/read permission. However we need it
1042bbfdae91SMaxim Levitsky * when we are updating the keys, to ensure that only we
1043bbfdae91SMaxim Levitsky * have access to the device.
1044bbfdae91SMaxim Levitsky *
1045bbfdae91SMaxim Levitsky * Encryption update will set the crypto->updating_keys
1046bbfdae91SMaxim Levitsky * during that period and refresh permissions
1047bbfdae91SMaxim Levitsky *
1048bbfdae91SMaxim Levitsky */
1049bbfdae91SMaxim Levitsky if (crypto->updating_keys) {
1050bbfdae91SMaxim Levitsky /* need exclusive write access for header update */
1051bbfdae91SMaxim Levitsky *nperm |= BLK_PERM_WRITE;
1052bbfdae91SMaxim Levitsky /* unshare read and write permission */
1053bbfdae91SMaxim Levitsky *nshared &= ~(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE);
1054bbfdae91SMaxim Levitsky }
1055bbfdae91SMaxim Levitsky }
1056bbfdae91SMaxim Levitsky
1057bbfdae91SMaxim Levitsky
10582654267cSMax Reitz static const char *const block_crypto_strong_runtime_opts[] = {
10592654267cSMax Reitz BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
10602654267cSMax Reitz
10612654267cSMax Reitz NULL
10622654267cSMax Reitz };
10632654267cSMax Reitz
1064782b9d06SAlberto Garcia static BlockDriver bdrv_crypto_luks = {
106578368575SDaniel P. Berrange .format_name = "luks",
106678368575SDaniel P. Berrange .instance_size = sizeof(BlockCrypto),
106778368575SDaniel P. Berrange .bdrv_probe = block_crypto_probe_luks,
106878368575SDaniel P. Berrange .bdrv_open = block_crypto_open_luks,
106978368575SDaniel P. Berrange .bdrv_close = block_crypto_close,
1070bbfdae91SMaxim Levitsky .bdrv_child_perm = block_crypto_child_perms,
10711bedcaf1SKevin Wolf .bdrv_co_create = block_crypto_co_create_luks,
1072efc75e2aSStefan Hajnoczi .bdrv_co_create_opts = block_crypto_co_create_opts_luks,
1073061ca8a3SKevin Wolf .bdrv_co_truncate = block_crypto_co_truncate,
107478368575SDaniel P. Berrange .create_opts = &block_crypto_create_opts_luks,
1075bbfdae91SMaxim Levitsky .amend_opts = &block_crypto_amend_opts_luks,
107678368575SDaniel P. Berrange
1077f87e08f9SDaniel P. Berrange .bdrv_reopen_prepare = block_crypto_reopen_prepare,
1078a73466fbSDaniel P. Berrange .bdrv_refresh_limits = block_crypto_refresh_limits,
1079a73466fbSDaniel P. Berrange .bdrv_co_preadv = block_crypto_co_preadv,
1080a73466fbSDaniel P. Berrange .bdrv_co_pwritev = block_crypto_co_pwritev,
1081c86422c5SEmanuele Giuseppe Esposito .bdrv_co_getlength = block_crypto_co_getlength,
1082a9da6e49SStefan Hajnoczi .bdrv_measure = block_crypto_measure,
10833d47eb0aSEmanuele Giuseppe Esposito .bdrv_co_get_info = block_crypto_co_get_info_luks,
1084c7c4cf49SDaniel P. Berrange .bdrv_get_specific_info = block_crypto_get_specific_info_luks,
1085bbfdae91SMaxim Levitsky .bdrv_amend_options = block_crypto_amend_options_luks,
108630da9dd8SMaxim Levitsky .bdrv_co_amend = block_crypto_co_amend_luks,
1087c1019d16SEmanuele Giuseppe Esposito .bdrv_amend_pre_run = block_crypto_amend_prepare,
1088c1019d16SEmanuele Giuseppe Esposito .bdrv_amend_clean = block_crypto_amend_cleanup,
10892654267cSMax Reitz
1090d67066d8SMax Reitz .is_format = true,
1091d67066d8SMax Reitz
10922654267cSMax Reitz .strong_runtime_opts = block_crypto_strong_runtime_opts,
109378368575SDaniel P. Berrange };
109478368575SDaniel P. Berrange
block_crypto_init(void)109578368575SDaniel P. Berrange static void block_crypto_init(void)
109678368575SDaniel P. Berrange {
109778368575SDaniel P. Berrange bdrv_register(&bdrv_crypto_luks);
109878368575SDaniel P. Berrange }
109978368575SDaniel P. Berrange
110078368575SDaniel P. Berrange block_init(block_crypto_init);
1101