block: Always set writeback mode in blk_new_open()
[qemu/ar7.git] / block / crypto.c
blobbe3498581c5530d10fd8531c978893491cfad260
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);
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 error_propagate(errp, local_err);
222 local_err = NULL;
224 visit_end_struct(opts_get_visitor(ov), &local_err);
226 out:
227 if (local_err) {
228 error_propagate(errp, local_err);
229 qapi_free_QCryptoBlockOpenOptions(ret);
230 ret = NULL;
232 opts_visitor_cleanup(ov);
233 return ret;
237 static QCryptoBlockCreateOptions *
238 block_crypto_create_opts_init(QCryptoBlockFormat format,
239 QemuOpts *opts,
240 Error **errp)
242 OptsVisitor *ov;
243 QCryptoBlockCreateOptions *ret = NULL;
244 Error *local_err = NULL;
246 ret = g_new0(QCryptoBlockCreateOptions, 1);
247 ret->format = format;
249 ov = opts_visitor_new(opts);
251 visit_start_struct(opts_get_visitor(ov),
252 NULL, NULL, 0, &local_err);
253 if (local_err) {
254 goto out;
257 switch (format) {
258 case Q_CRYPTO_BLOCK_FORMAT_LUKS:
259 visit_type_QCryptoBlockCreateOptionsLUKS_members(
260 opts_get_visitor(ov), &ret->u.luks, &local_err);
261 break;
263 default:
264 error_setg(&local_err, "Unsupported block format %d", format);
265 break;
267 error_propagate(errp, local_err);
268 local_err = NULL;
270 visit_end_struct(opts_get_visitor(ov), &local_err);
272 out:
273 if (local_err) {
274 error_propagate(errp, local_err);
275 qapi_free_QCryptoBlockCreateOptions(ret);
276 ret = NULL;
278 opts_visitor_cleanup(ov);
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 = 1;
324 bs->valid_key = 1;
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->bs,
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->bs,
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 BlockDriver bdrv_crypto_luks = {
567 .format_name = "luks",
568 .instance_size = sizeof(BlockCrypto),
569 .bdrv_probe = block_crypto_probe_luks,
570 .bdrv_open = block_crypto_open_luks,
571 .bdrv_close = block_crypto_close,
572 .bdrv_create = block_crypto_create_luks,
573 .bdrv_truncate = block_crypto_truncate,
574 .create_opts = &block_crypto_create_opts_luks,
576 .bdrv_co_readv = block_crypto_co_readv,
577 .bdrv_co_writev = block_crypto_co_writev,
578 .bdrv_getlength = block_crypto_getlength,
581 static void block_crypto_init(void)
583 bdrv_register(&bdrv_crypto_luks);
586 block_init(block_crypto_init);