aboutsummaryrefslogtreecommitdiff
path: root/block/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/crypto.c')
-rw-r--r--block/crypto.c150
1 files changed, 108 insertions, 42 deletions
diff --git a/block/crypto.c b/block/crypto.c
index e6095e7807..e0b8856f74 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -71,8 +71,6 @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
struct BlockCryptoCreateData {
- const char *filename;
- QemuOpts *opts;
BlockBackend *blk;
uint64_t size;
};
@@ -103,27 +101,18 @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
Error **errp)
{
struct BlockCryptoCreateData *data = opaque;
- int ret;
+
+ if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) {
+ error_setg(errp, "The requested file size is too large");
+ return -EFBIG;
+ }
/* User provided size should reflect amount of space made
* available to the guest, so we must take account of that
* which will be used by the crypto header
*/
- data->size += headerlen;
-
- qemu_opt_set_number(data->opts, BLOCK_OPT_SIZE, data->size, &error_abort);
- ret = bdrv_create_file(data->filename, data->opts, errp);
- if (ret < 0) {
- return -1;
- }
-
- data->blk = blk_new_open(data->filename, NULL, NULL,
- BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
- if (!data->blk) {
- return -1;
- }
-
- return 0;
+ return blk_truncate(data->blk, data->size + headerlen, PREALLOC_MODE_OFF,
+ errp);
}
@@ -322,30 +311,29 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
}
-static int block_crypto_create_generic(QCryptoBlockFormat format,
- const char *filename,
- QemuOpts *opts,
- Error **errp)
+static int block_crypto_co_create_generic(BlockDriverState *bs,
+ int64_t size,
+ QCryptoBlockCreateOptions *opts,
+ Error **errp)
{
- int ret = -EINVAL;
- QCryptoBlockCreateOptions *create_opts = NULL;
+ int ret;
+ BlockBackend *blk;
QCryptoBlock *crypto = NULL;
- struct BlockCryptoCreateData data = {
- .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
- BDRV_SECTOR_SIZE),
- .opts = opts,
- .filename = filename,
- };
- QDict *cryptoopts;
+ struct BlockCryptoCreateData data;
- cryptoopts = qemu_opts_to_qdict(opts, NULL);
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
- create_opts = block_crypto_create_opts_init(format, cryptoopts, errp);
- if (!create_opts) {
- return -1;
+ ret = blk_insert_bs(blk, bs, errp);
+ if (ret < 0) {
+ goto cleanup;
}
- crypto = qcrypto_block_create(create_opts, NULL,
+ data = (struct BlockCryptoCreateData) {
+ .blk = blk,
+ .size = size,
+ };
+
+ crypto = qcrypto_block_create(opts, NULL,
block_crypto_init_func,
block_crypto_write_func,
&data,
@@ -358,10 +346,8 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
ret = 0;
cleanup:
- QDECREF(cryptoopts);
qcrypto_block_free(crypto);
- blk_unref(data.blk);
- qapi_free_QCryptoBlockCreateOptions(create_opts);
+ blk_unref(blk);
return ret;
}
@@ -537,7 +523,10 @@ static int64_t block_crypto_getlength(BlockDriverState *bs)
uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
assert(offset < INT64_MAX);
- assert(offset < len);
+
+ if (offset > len) {
+ return -EIO;
+ }
len -= offset;
@@ -562,12 +551,88 @@ static int block_crypto_open_luks(BlockDriverState *bs,
bs, options, flags, errp);
}
+static int coroutine_fn
+block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
+{
+ BlockdevCreateOptionsLUKS *luks_opts;
+ BlockDriverState *bs = NULL;
+ QCryptoBlockCreateOptions create_opts;
+ int ret;
+
+ assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
+ luks_opts = &create_options->u.luks;
+
+ bs = bdrv_open_blockdev_ref(luks_opts->file, errp);
+ if (bs == NULL) {
+ return -EIO;
+ }
+
+ create_opts = (QCryptoBlockCreateOptions) {
+ .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
+ };
+
+ ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
+ errp);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ bdrv_unref(bs);
+ return ret;
+}
+
static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
QemuOpts *opts,
Error **errp)
{
- return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
- filename, opts, errp);
+ QCryptoBlockCreateOptions *create_opts = NULL;
+ BlockDriverState *bs = NULL;
+ QDict *cryptoopts;
+ int64_t size;
+ int ret;
+
+ /* Parse options */
+ size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
+
+ cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
+ &block_crypto_create_opts_luks,
+ true);
+
+ create_opts = block_crypto_create_opts_init(Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ cryptoopts, errp);
+ if (!create_opts) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* Create protocol layer */
+ ret = bdrv_create_file(filename, opts, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ bs = bdrv_open(filename, NULL, NULL,
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
+ if (!bs) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* Create format layer */
+ ret = block_crypto_co_create_generic(bs, size, create_opts, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ bdrv_unref(bs);
+ qapi_free_QCryptoBlockCreateOptions(create_opts);
+ QDECREF(cryptoopts);
+ return ret;
}
static int block_crypto_get_info_luks(BlockDriverState *bs,
@@ -623,6 +688,7 @@ BlockDriver bdrv_crypto_luks = {
.bdrv_open = block_crypto_open_luks,
.bdrv_close = block_crypto_close,
.bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_co_create = block_crypto_co_create_luks,
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
.bdrv_truncate = block_crypto_truncate,
.create_opts = &block_crypto_create_opts_luks,