xref: /qemu/block/crypto.c (revision 35286dae)
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