block: Document supported flags during bdrv_aligned_preadv()
[qemu/ar7.git] / block / crypto.c
blob758e14e032944484f0e7924996e0984f470ace45
1 /*
2 * QEMU block full disk encryption
4 * Copyright (c) 2015-2016 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
23 #include "block/block_int.h"
24 #include "sysemu/block-backend.h"
25 #include "crypto/block.h"
26 #include "qapi/opts-visitor.h"
27 #include "qapi-visit.h"
28 #include "qapi/error.h"
30 #define BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET "key-secret"
31 #define BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG "cipher-alg"
32 #define BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE "cipher-mode"
33 #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
34 #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
35 #define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
37 typedef struct BlockCrypto BlockCrypto;
39 struct BlockCrypto {
40 QCryptoBlock *block;
44 static int block_crypto_probe_generic(QCryptoBlockFormat format,
45 const uint8_t *buf,
46 int buf_size,
47 const char *filename)
49 if (qcrypto_block_has_format(format, buf, buf_size)) {
50 return 100;
51 } else {
52 return 0;
57 static ssize_t block_crypto_read_func(QCryptoBlock *block,
58 size_t offset,
59 uint8_t *buf,
60 size_t buflen,
61 Error **errp,
62 void *opaque)
64 BlockDriverState *bs = opaque;
65 ssize_t ret;
67 ret = bdrv_pread(bs->file->bs, offset, buf, buflen);
68 if (ret < 0) {
69 error_setg_errno(errp, -ret, "Could not read encryption header");
70 return ret;
72 return ret;
76 struct BlockCryptoCreateData {
77 const char *filename;
78 QemuOpts *opts;
79 BlockBackend *blk;
80 uint64_t size;
84 static ssize_t block_crypto_write_func(QCryptoBlock *block,
85 size_t offset,
86 const uint8_t *buf,
87 size_t buflen,
88 Error **errp,
89 void *opaque)
91 struct BlockCryptoCreateData *data = opaque;
92 ssize_t ret;
94 ret = blk_pwrite(data->blk, offset, buf, buflen, 0);
95 if (ret < 0) {
96 error_setg_errno(errp, -ret, "Could not write encryption header");
97 return ret;
99 return ret;
103 static ssize_t block_crypto_init_func(QCryptoBlock *block,
104 size_t headerlen,
105 Error **errp,
106 void *opaque)
108 struct BlockCryptoCreateData *data = opaque;
109 int ret;
111 /* User provided size should reflect amount of space made
112 * available to the guest, so we must take account of that
113 * which will be used by the crypto header
115 data->size += headerlen;
117 qemu_opt_set_number(data->opts, BLOCK_OPT_SIZE, data->size, &error_abort);
118 ret = bdrv_create_file(data->filename, data->opts, errp);
119 if (ret < 0) {
120 return -1;
123 data->blk = blk_new_open(data->filename, NULL, NULL,
124 BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
125 if (!data->blk) {
126 return -1;
129 return 0;
133 static QemuOptsList block_crypto_runtime_opts_luks = {
134 .name = "crypto",
135 .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head),
136 .desc = {
138 .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
139 .type = QEMU_OPT_STRING,
140 .help = "ID of the secret that provides the encryption key",
142 { /* end of list */ }
147 static QemuOptsList block_crypto_create_opts_luks = {
148 .name = "crypto",
149 .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
150 .desc = {
152 .name = BLOCK_OPT_SIZE,
153 .type = QEMU_OPT_SIZE,
154 .help = "Virtual disk size"
157 .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
158 .type = QEMU_OPT_STRING,
159 .help = "ID of the secret that provides the encryption key",
162 .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG,
163 .type = QEMU_OPT_STRING,
164 .help = "Name of encryption cipher algorithm",
167 .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE,
168 .type = QEMU_OPT_STRING,
169 .help = "Name of encryption cipher mode",
172 .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG,
173 .type = QEMU_OPT_STRING,
174 .help = "Name of IV generator algorithm",
177 .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG,
178 .type = QEMU_OPT_STRING,
179 .help = "Name of IV generator hash algorithm",
182 .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG,
183 .type = QEMU_OPT_STRING,
184 .help = "Name of encryption hash algorithm",
186 { /* end of list */ }
191 static QCryptoBlockOpenOptions *
192 block_crypto_open_opts_init(QCryptoBlockFormat format,
193 QemuOpts *opts,
194 Error **errp)
196 OptsVisitor *ov;
197 QCryptoBlockOpenOptions *ret = NULL;
198 Error *local_err = NULL;
200 ret = g_new0(QCryptoBlockOpenOptions, 1);
201 ret->format = format;
203 ov = opts_visitor_new(opts);
205 visit_start_struct(opts_get_visitor(ov),
206 NULL, NULL, 0, &local_err);
207 if (local_err) {
208 goto out;
211 switch (format) {
212 case Q_CRYPTO_BLOCK_FORMAT_LUKS:
213 visit_type_QCryptoBlockOptionsLUKS_members(
214 opts_get_visitor(ov), &ret->u.luks, &local_err);
215 break;
217 default:
218 error_setg(&local_err, "Unsupported block format %d", format);
219 break;
221 if (!local_err) {
222 visit_check_struct(opts_get_visitor(ov), &local_err);
225 visit_end_struct(opts_get_visitor(ov));
227 out:
228 if (local_err) {
229 error_propagate(errp, local_err);
230 qapi_free_QCryptoBlockOpenOptions(ret);
231 ret = NULL;
233 opts_visitor_cleanup(ov);
234 return ret;
238 static QCryptoBlockCreateOptions *
239 block_crypto_create_opts_init(QCryptoBlockFormat format,
240 QemuOpts *opts,
241 Error **errp)
243 OptsVisitor *ov;
244 QCryptoBlockCreateOptions *ret = NULL;
245 Error *local_err = NULL;
247 ret = g_new0(QCryptoBlockCreateOptions, 1);
248 ret->format = format;
250 ov = opts_visitor_new(opts);
252 visit_start_struct(opts_get_visitor(ov),
253 NULL, NULL, 0, &local_err);
254 if (local_err) {
255 goto out;
258 switch (format) {
259 case Q_CRYPTO_BLOCK_FORMAT_LUKS:
260 visit_type_QCryptoBlockCreateOptionsLUKS_members(
261 opts_get_visitor(ov), &ret->u.luks, &local_err);
262 break;
264 default:
265 error_setg(&local_err, "Unsupported block format %d", format);
266 break;
268 if (!local_err) {
269 visit_check_struct(opts_get_visitor(ov), &local_err);
272 visit_end_struct(opts_get_visitor(ov));
274 out:
275 if (local_err) {
276 error_propagate(errp, local_err);
277 qapi_free_QCryptoBlockCreateOptions(ret);
278 ret = NULL;
280 opts_visitor_cleanup(ov);
281 return ret;
285 static int block_crypto_open_generic(QCryptoBlockFormat format,
286 QemuOptsList *opts_spec,
287 BlockDriverState *bs,
288 QDict *options,
289 int flags,
290 Error **errp)
292 BlockCrypto *crypto = bs->opaque;
293 QemuOpts *opts = NULL;
294 Error *local_err = NULL;
295 int ret = -EINVAL;
296 QCryptoBlockOpenOptions *open_opts = NULL;
297 unsigned int cflags = 0;
299 opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
300 qemu_opts_absorb_qdict(opts, options, &local_err);
301 if (local_err) {
302 error_propagate(errp, local_err);
303 goto cleanup;
306 open_opts = block_crypto_open_opts_init(format, opts, errp);
307 if (!open_opts) {
308 goto cleanup;
311 if (flags & BDRV_O_NO_IO) {
312 cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
314 crypto->block = qcrypto_block_open(open_opts,
315 block_crypto_read_func,
317 cflags,
318 errp);
320 if (!crypto->block) {
321 ret = -EIO;
322 goto cleanup;
325 bs->encrypted = 1;
326 bs->valid_key = 1;
328 ret = 0;
329 cleanup:
330 qapi_free_QCryptoBlockOpenOptions(open_opts);
331 return ret;
335 static int block_crypto_create_generic(QCryptoBlockFormat format,
336 const char *filename,
337 QemuOpts *opts,
338 Error **errp)
340 int ret = -EINVAL;
341 QCryptoBlockCreateOptions *create_opts = NULL;
342 QCryptoBlock *crypto = NULL;
343 struct BlockCryptoCreateData data = {
344 .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
345 BDRV_SECTOR_SIZE),
346 .opts = opts,
347 .filename = filename,
350 create_opts = block_crypto_create_opts_init(format, opts, errp);
351 if (!create_opts) {
352 return -1;
355 crypto = qcrypto_block_create(create_opts,
356 block_crypto_init_func,
357 block_crypto_write_func,
358 &data,
359 errp);
361 if (!crypto) {
362 ret = -EIO;
363 goto cleanup;
366 ret = 0;
367 cleanup:
368 qcrypto_block_free(crypto);
369 blk_unref(data.blk);
370 qapi_free_QCryptoBlockCreateOptions(create_opts);
371 return ret;
374 static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
376 BlockCrypto *crypto = bs->opaque;
377 size_t payload_offset =
378 qcrypto_block_get_payload_offset(crypto->block);
380 offset += payload_offset;
382 return bdrv_truncate(bs->file->bs, offset);
385 static void block_crypto_close(BlockDriverState *bs)
387 BlockCrypto *crypto = bs->opaque;
388 qcrypto_block_free(crypto->block);
392 #define BLOCK_CRYPTO_MAX_SECTORS 32
394 static coroutine_fn int
395 block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
396 int remaining_sectors, QEMUIOVector *qiov)
398 BlockCrypto *crypto = bs->opaque;
399 int cur_nr_sectors; /* number of sectors in current iteration */
400 uint64_t bytes_done = 0;
401 uint8_t *cipher_data = NULL;
402 QEMUIOVector hd_qiov;
403 int ret = 0;
404 size_t payload_offset =
405 qcrypto_block_get_payload_offset(crypto->block) / 512;
407 qemu_iovec_init(&hd_qiov, qiov->niov);
409 /* Bounce buffer so we have a linear mem region for
410 * entire sector. XXX optimize so we avoid bounce
411 * buffer in case that qiov->niov == 1
413 cipher_data =
414 qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
415 qiov->size));
416 if (cipher_data == NULL) {
417 ret = -ENOMEM;
418 goto cleanup;
421 while (remaining_sectors) {
422 cur_nr_sectors = remaining_sectors;
424 if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
425 cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
428 qemu_iovec_reset(&hd_qiov);
429 qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
431 ret = bdrv_co_readv(bs->file->bs,
432 payload_offset + sector_num,
433 cur_nr_sectors, &hd_qiov);
434 if (ret < 0) {
435 goto cleanup;
438 if (qcrypto_block_decrypt(crypto->block,
439 sector_num,
440 cipher_data, cur_nr_sectors * 512,
441 NULL) < 0) {
442 ret = -EIO;
443 goto cleanup;
446 qemu_iovec_from_buf(qiov, bytes_done,
447 cipher_data, cur_nr_sectors * 512);
449 remaining_sectors -= cur_nr_sectors;
450 sector_num += cur_nr_sectors;
451 bytes_done += cur_nr_sectors * 512;
454 cleanup:
455 qemu_iovec_destroy(&hd_qiov);
456 qemu_vfree(cipher_data);
458 return ret;
462 static coroutine_fn int
463 block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
464 int remaining_sectors, QEMUIOVector *qiov)
466 BlockCrypto *crypto = bs->opaque;
467 int cur_nr_sectors; /* number of sectors in current iteration */
468 uint64_t bytes_done = 0;
469 uint8_t *cipher_data = NULL;
470 QEMUIOVector hd_qiov;
471 int ret = 0;
472 size_t payload_offset =
473 qcrypto_block_get_payload_offset(crypto->block) / 512;
475 qemu_iovec_init(&hd_qiov, qiov->niov);
477 /* Bounce buffer so we have a linear mem region for
478 * entire sector. XXX optimize so we avoid bounce
479 * buffer in case that qiov->niov == 1
481 cipher_data =
482 qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
483 qiov->size));
484 if (cipher_data == NULL) {
485 ret = -ENOMEM;
486 goto cleanup;
489 while (remaining_sectors) {
490 cur_nr_sectors = remaining_sectors;
492 if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
493 cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
496 qemu_iovec_to_buf(qiov, bytes_done,
497 cipher_data, cur_nr_sectors * 512);
499 if (qcrypto_block_encrypt(crypto->block,
500 sector_num,
501 cipher_data, cur_nr_sectors * 512,
502 NULL) < 0) {
503 ret = -EIO;
504 goto cleanup;
507 qemu_iovec_reset(&hd_qiov);
508 qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
510 ret = bdrv_co_writev(bs->file->bs,
511 payload_offset + sector_num,
512 cur_nr_sectors, &hd_qiov);
513 if (ret < 0) {
514 goto cleanup;
517 remaining_sectors -= cur_nr_sectors;
518 sector_num += cur_nr_sectors;
519 bytes_done += cur_nr_sectors * 512;
522 cleanup:
523 qemu_iovec_destroy(&hd_qiov);
524 qemu_vfree(cipher_data);
526 return ret;
530 static int64_t block_crypto_getlength(BlockDriverState *bs)
532 BlockCrypto *crypto = bs->opaque;
533 int64_t len = bdrv_getlength(bs->file->bs);
535 ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
537 len -= offset;
539 return len;
543 static int block_crypto_probe_luks(const uint8_t *buf,
544 int buf_size,
545 const char *filename) {
546 return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
547 buf, buf_size, filename);
550 static int block_crypto_open_luks(BlockDriverState *bs,
551 QDict *options,
552 int flags,
553 Error **errp)
555 return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
556 &block_crypto_runtime_opts_luks,
557 bs, options, flags, errp);
560 static int block_crypto_create_luks(const char *filename,
561 QemuOpts *opts,
562 Error **errp)
564 return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
565 filename, opts, errp);
568 BlockDriver bdrv_crypto_luks = {
569 .format_name = "luks",
570 .instance_size = sizeof(BlockCrypto),
571 .bdrv_probe = block_crypto_probe_luks,
572 .bdrv_open = block_crypto_open_luks,
573 .bdrv_close = block_crypto_close,
574 .bdrv_create = block_crypto_create_luks,
575 .bdrv_truncate = block_crypto_truncate,
576 .create_opts = &block_crypto_create_opts_luks,
578 .bdrv_co_readv = block_crypto_co_readv,
579 .bdrv_co_writev = block_crypto_co_writev,
580 .bdrv_getlength = block_crypto_getlength,
583 static void block_crypto_init(void)
585 bdrv_register(&bdrv_crypto_luks);
588 block_init(block_crypto_init);