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