Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into staging
[qemu/ar7.git] / block / crypto.c
blob7f61e126868aa8ae410189814723779a77bbf895
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, 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 Visitor *v;
197 QCryptoBlockOpenOptions *ret = NULL;
198 Error *local_err = NULL;
200 ret = g_new0(QCryptoBlockOpenOptions, 1);
201 ret->format = format;
203 v = opts_visitor_new(opts);
205 visit_start_struct(v, NULL, NULL, 0, &local_err);
206 if (local_err) {
207 goto out;
210 switch (format) {
211 case Q_CRYPTO_BLOCK_FORMAT_LUKS:
212 visit_type_QCryptoBlockOptionsLUKS_members(
213 v, &ret->u.luks, &local_err);
214 break;
216 default:
217 error_setg(&local_err, "Unsupported block format %d", format);
218 break;
220 if (!local_err) {
221 visit_check_struct(v, &local_err);
224 visit_end_struct(v, NULL);
226 out:
227 if (local_err) {
228 error_propagate(errp, local_err);
229 qapi_free_QCryptoBlockOpenOptions(ret);
230 ret = NULL;
232 visit_free(v);
233 return ret;
237 static QCryptoBlockCreateOptions *
238 block_crypto_create_opts_init(QCryptoBlockFormat format,
239 QemuOpts *opts,
240 Error **errp)
242 Visitor *v;
243 QCryptoBlockCreateOptions *ret = NULL;
244 Error *local_err = NULL;
246 ret = g_new0(QCryptoBlockCreateOptions, 1);
247 ret->format = format;
249 v = opts_visitor_new(opts);
251 visit_start_struct(v, NULL, NULL, 0, &local_err);
252 if (local_err) {
253 goto out;
256 switch (format) {
257 case Q_CRYPTO_BLOCK_FORMAT_LUKS:
258 visit_type_QCryptoBlockCreateOptionsLUKS_members(
259 v, &ret->u.luks, &local_err);
260 break;
262 default:
263 error_setg(&local_err, "Unsupported block format %d", format);
264 break;
266 if (!local_err) {
267 visit_check_struct(v, &local_err);
270 visit_end_struct(v, NULL);
272 out:
273 if (local_err) {
274 error_propagate(errp, local_err);
275 qapi_free_QCryptoBlockCreateOptions(ret);
276 ret = NULL;
278 visit_free(v);
279 return ret;
283 static int block_crypto_open_generic(QCryptoBlockFormat format,
284 QemuOptsList *opts_spec,
285 BlockDriverState *bs,
286 QDict *options,
287 int flags,
288 Error **errp)
290 BlockCrypto *crypto = bs->opaque;
291 QemuOpts *opts = NULL;
292 Error *local_err = NULL;
293 int ret = -EINVAL;
294 QCryptoBlockOpenOptions *open_opts = NULL;
295 unsigned int cflags = 0;
297 opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
298 qemu_opts_absorb_qdict(opts, options, &local_err);
299 if (local_err) {
300 error_propagate(errp, local_err);
301 goto cleanup;
304 open_opts = block_crypto_open_opts_init(format, opts, errp);
305 if (!open_opts) {
306 goto cleanup;
309 if (flags & BDRV_O_NO_IO) {
310 cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
312 crypto->block = qcrypto_block_open(open_opts,
313 block_crypto_read_func,
315 cflags,
316 errp);
318 if (!crypto->block) {
319 ret = -EIO;
320 goto cleanup;
323 bs->encrypted = true;
324 bs->valid_key = true;
326 ret = 0;
327 cleanup:
328 qapi_free_QCryptoBlockOpenOptions(open_opts);
329 return ret;
333 static int block_crypto_create_generic(QCryptoBlockFormat format,
334 const char *filename,
335 QemuOpts *opts,
336 Error **errp)
338 int ret = -EINVAL;
339 QCryptoBlockCreateOptions *create_opts = NULL;
340 QCryptoBlock *crypto = NULL;
341 struct BlockCryptoCreateData data = {
342 .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
343 BDRV_SECTOR_SIZE),
344 .opts = opts,
345 .filename = filename,
348 create_opts = block_crypto_create_opts_init(format, opts, errp);
349 if (!create_opts) {
350 return -1;
353 crypto = qcrypto_block_create(create_opts,
354 block_crypto_init_func,
355 block_crypto_write_func,
356 &data,
357 errp);
359 if (!crypto) {
360 ret = -EIO;
361 goto cleanup;
364 ret = 0;
365 cleanup:
366 qcrypto_block_free(crypto);
367 blk_unref(data.blk);
368 qapi_free_QCryptoBlockCreateOptions(create_opts);
369 return ret;
372 static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
374 BlockCrypto *crypto = bs->opaque;
375 size_t payload_offset =
376 qcrypto_block_get_payload_offset(crypto->block);
378 offset += payload_offset;
380 return bdrv_truncate(bs->file->bs, offset);
383 static void block_crypto_close(BlockDriverState *bs)
385 BlockCrypto *crypto = bs->opaque;
386 qcrypto_block_free(crypto->block);
390 #define BLOCK_CRYPTO_MAX_SECTORS 32
392 static coroutine_fn int
393 block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
394 int remaining_sectors, QEMUIOVector *qiov)
396 BlockCrypto *crypto = bs->opaque;
397 int cur_nr_sectors; /* number of sectors in current iteration */
398 uint64_t bytes_done = 0;
399 uint8_t *cipher_data = NULL;
400 QEMUIOVector hd_qiov;
401 int ret = 0;
402 size_t payload_offset =
403 qcrypto_block_get_payload_offset(crypto->block) / 512;
405 qemu_iovec_init(&hd_qiov, qiov->niov);
407 /* Bounce buffer so we have a linear mem region for
408 * entire sector. XXX optimize so we avoid bounce
409 * buffer in case that qiov->niov == 1
411 cipher_data =
412 qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
413 qiov->size));
414 if (cipher_data == NULL) {
415 ret = -ENOMEM;
416 goto cleanup;
419 while (remaining_sectors) {
420 cur_nr_sectors = remaining_sectors;
422 if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
423 cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
426 qemu_iovec_reset(&hd_qiov);
427 qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
429 ret = bdrv_co_readv(bs->file,
430 payload_offset + sector_num,
431 cur_nr_sectors, &hd_qiov);
432 if (ret < 0) {
433 goto cleanup;
436 if (qcrypto_block_decrypt(crypto->block,
437 sector_num,
438 cipher_data, cur_nr_sectors * 512,
439 NULL) < 0) {
440 ret = -EIO;
441 goto cleanup;
444 qemu_iovec_from_buf(qiov, bytes_done,
445 cipher_data, cur_nr_sectors * 512);
447 remaining_sectors -= cur_nr_sectors;
448 sector_num += cur_nr_sectors;
449 bytes_done += cur_nr_sectors * 512;
452 cleanup:
453 qemu_iovec_destroy(&hd_qiov);
454 qemu_vfree(cipher_data);
456 return ret;
460 static coroutine_fn int
461 block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
462 int remaining_sectors, QEMUIOVector *qiov)
464 BlockCrypto *crypto = bs->opaque;
465 int cur_nr_sectors; /* number of sectors in current iteration */
466 uint64_t bytes_done = 0;
467 uint8_t *cipher_data = NULL;
468 QEMUIOVector hd_qiov;
469 int ret = 0;
470 size_t payload_offset =
471 qcrypto_block_get_payload_offset(crypto->block) / 512;
473 qemu_iovec_init(&hd_qiov, qiov->niov);
475 /* Bounce buffer so we have a linear mem region for
476 * entire sector. XXX optimize so we avoid bounce
477 * buffer in case that qiov->niov == 1
479 cipher_data =
480 qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
481 qiov->size));
482 if (cipher_data == NULL) {
483 ret = -ENOMEM;
484 goto cleanup;
487 while (remaining_sectors) {
488 cur_nr_sectors = remaining_sectors;
490 if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
491 cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
494 qemu_iovec_to_buf(qiov, bytes_done,
495 cipher_data, cur_nr_sectors * 512);
497 if (qcrypto_block_encrypt(crypto->block,
498 sector_num,
499 cipher_data, cur_nr_sectors * 512,
500 NULL) < 0) {
501 ret = -EIO;
502 goto cleanup;
505 qemu_iovec_reset(&hd_qiov);
506 qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
508 ret = bdrv_co_writev(bs->file,
509 payload_offset + sector_num,
510 cur_nr_sectors, &hd_qiov);
511 if (ret < 0) {
512 goto cleanup;
515 remaining_sectors -= cur_nr_sectors;
516 sector_num += cur_nr_sectors;
517 bytes_done += cur_nr_sectors * 512;
520 cleanup:
521 qemu_iovec_destroy(&hd_qiov);
522 qemu_vfree(cipher_data);
524 return ret;
528 static int64_t block_crypto_getlength(BlockDriverState *bs)
530 BlockCrypto *crypto = bs->opaque;
531 int64_t len = bdrv_getlength(bs->file->bs);
533 ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
535 len -= offset;
537 return len;
541 static int block_crypto_probe_luks(const uint8_t *buf,
542 int buf_size,
543 const char *filename) {
544 return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
545 buf, buf_size, filename);
548 static int block_crypto_open_luks(BlockDriverState *bs,
549 QDict *options,
550 int flags,
551 Error **errp)
553 return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
554 &block_crypto_runtime_opts_luks,
555 bs, options, flags, errp);
558 static int block_crypto_create_luks(const char *filename,
559 QemuOpts *opts,
560 Error **errp)
562 return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
563 filename, opts, errp);
566 static int block_crypto_get_info_luks(BlockDriverState *bs,
567 BlockDriverInfo *bdi)
569 BlockDriverInfo subbdi;
570 int ret;
572 ret = bdrv_get_info(bs->file->bs, &subbdi);
573 if (ret != 0) {
574 return ret;
577 bdi->unallocated_blocks_are_zero = false;
578 bdi->can_write_zeroes_with_unmap = false;
579 bdi->cluster_size = subbdi.cluster_size;
581 return 0;
584 static ImageInfoSpecific *
585 block_crypto_get_specific_info_luks(BlockDriverState *bs)
587 BlockCrypto *crypto = bs->opaque;
588 ImageInfoSpecific *spec_info;
589 QCryptoBlockInfo *info;
591 info = qcrypto_block_get_info(crypto->block, NULL);
592 if (!info) {
593 return NULL;
595 if (info->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) {
596 qapi_free_QCryptoBlockInfo(info);
597 return NULL;
600 spec_info = g_new(ImageInfoSpecific, 1);
601 spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS;
602 spec_info->u.luks.data = g_new(QCryptoBlockInfoLUKS, 1);
603 *spec_info->u.luks.data = info->u.luks;
605 /* Blank out pointers we've just stolen to avoid double free */
606 memset(&info->u.luks, 0, sizeof(info->u.luks));
608 qapi_free_QCryptoBlockInfo(info);
610 return spec_info;
613 BlockDriver bdrv_crypto_luks = {
614 .format_name = "luks",
615 .instance_size = sizeof(BlockCrypto),
616 .bdrv_probe = block_crypto_probe_luks,
617 .bdrv_open = block_crypto_open_luks,
618 .bdrv_close = block_crypto_close,
619 .bdrv_create = block_crypto_create_luks,
620 .bdrv_truncate = block_crypto_truncate,
621 .create_opts = &block_crypto_create_opts_luks,
623 .bdrv_co_readv = block_crypto_co_readv,
624 .bdrv_co_writev = block_crypto_co_writev,
625 .bdrv_getlength = block_crypto_getlength,
626 .bdrv_get_info = block_crypto_get_info_luks,
627 .bdrv_get_specific_info = block_crypto_get_specific_info_luks,
630 static void block_crypto_init(void)
632 bdrv_register(&bdrv_crypto_luks);
635 block_init(block_crypto_init);