]> git.proxmox.com Git - mirror_qemu.git/blame - block/crypto.c
block: Convert bdrv_pread(v) to BdrvChild
[mirror_qemu.git] / block / crypto.c
CommitLineData
78368575
DB
1/*
2 * QEMU block full disk encryption
3 *
4 * Copyright (c) 2015-2016 Red Hat, Inc.
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 */
20
21#include "qemu/osdep.h"
22
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"
29
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"
36
37typedef struct BlockCrypto BlockCrypto;
38
39struct BlockCrypto {
40 QCryptoBlock *block;
41};
42
43
44static int block_crypto_probe_generic(QCryptoBlockFormat format,
45 const uint8_t *buf,
46 int buf_size,
47 const char *filename)
48{
49 if (qcrypto_block_has_format(format, buf, buf_size)) {
50 return 100;
51 } else {
52 return 0;
53 }
54}
55
56
57static 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)
63{
64 BlockDriverState *bs = opaque;
65 ssize_t ret;
66
cf2ab8fc 67 ret = bdrv_pread(bs->file, offset, buf, buflen);
78368575
DB
68 if (ret < 0) {
69 error_setg_errno(errp, -ret, "Could not read encryption header");
70 return ret;
71 }
72 return ret;
73}
74
75
76struct BlockCryptoCreateData {
77 const char *filename;
78 QemuOpts *opts;
79 BlockBackend *blk;
80 uint64_t size;
81};
82
83
84static 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)
90{
91 struct BlockCryptoCreateData *data = opaque;
92 ssize_t ret;
93
8341f00d 94 ret = blk_pwrite(data->blk, offset, buf, buflen, 0);
78368575
DB
95 if (ret < 0) {
96 error_setg_errno(errp, -ret, "Could not write encryption header");
97 return ret;
98 }
99 return ret;
100}
101
102
103static ssize_t block_crypto_init_func(QCryptoBlock *block,
104 size_t headerlen,
105 Error **errp,
106 void *opaque)
107{
108 struct BlockCryptoCreateData *data = opaque;
109 int ret;
110
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
114 */
115 data->size += headerlen;
116
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;
121 }
122
123 data->blk = blk_new_open(data->filename, NULL, NULL,
72e775c7 124 BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
78368575
DB
125 if (!data->blk) {
126 return -1;
127 }
128
129 return 0;
130}
131
132
133static QemuOptsList block_crypto_runtime_opts_luks = {
134 .name = "crypto",
135 .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head),
136 .desc = {
137 {
138 .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
139 .type = QEMU_OPT_STRING,
140 .help = "ID of the secret that provides the encryption key",
141 },
142 { /* end of list */ }
143 },
144};
145
146
147static QemuOptsList block_crypto_create_opts_luks = {
148 .name = "crypto",
149 .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
150 .desc = {
151 {
152 .name = BLOCK_OPT_SIZE,
153 .type = QEMU_OPT_SIZE,
154 .help = "Virtual disk size"
155 },
156 {
157 .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
158 .type = QEMU_OPT_STRING,
159 .help = "ID of the secret that provides the encryption key",
160 },
161 {
162 .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG,
163 .type = QEMU_OPT_STRING,
164 .help = "Name of encryption cipher algorithm",
165 },
166 {
167 .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE,
168 .type = QEMU_OPT_STRING,
169 .help = "Name of encryption cipher mode",
170 },
171 {
172 .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG,
173 .type = QEMU_OPT_STRING,
174 .help = "Name of IV generator algorithm",
175 },
176 {
177 .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG,
178 .type = QEMU_OPT_STRING,
179 .help = "Name of IV generator hash algorithm",
180 },
181 {
182 .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG,
183 .type = QEMU_OPT_STRING,
184 .help = "Name of encryption hash algorithm",
185 },
186 { /* end of list */ }
187 },
188};
189
190
191static QCryptoBlockOpenOptions *
192block_crypto_open_opts_init(QCryptoBlockFormat format,
193 QemuOpts *opts,
194 Error **errp)
195{
196 OptsVisitor *ov;
197 QCryptoBlockOpenOptions *ret = NULL;
198 Error *local_err = NULL;
199
200 ret = g_new0(QCryptoBlockOpenOptions, 1);
201 ret->format = format;
202
203 ov = opts_visitor_new(opts);
204
205 visit_start_struct(opts_get_visitor(ov),
206 NULL, NULL, 0, &local_err);
207 if (local_err) {
208 goto out;
209 }
210
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;
216
217 default:
218 error_setg(&local_err, "Unsupported block format %d", format);
219 break;
220 }
15c2f669
EB
221 if (!local_err) {
222 visit_check_struct(opts_get_visitor(ov), &local_err);
223 }
78368575 224
15c2f669 225 visit_end_struct(opts_get_visitor(ov));
78368575
DB
226
227 out:
228 if (local_err) {
229 error_propagate(errp, local_err);
230 qapi_free_QCryptoBlockOpenOptions(ret);
231 ret = NULL;
232 }
233 opts_visitor_cleanup(ov);
234 return ret;
235}
236
237
238static QCryptoBlockCreateOptions *
239block_crypto_create_opts_init(QCryptoBlockFormat format,
240 QemuOpts *opts,
241 Error **errp)
242{
243 OptsVisitor *ov;
244 QCryptoBlockCreateOptions *ret = NULL;
245 Error *local_err = NULL;
246
247 ret = g_new0(QCryptoBlockCreateOptions, 1);
248 ret->format = format;
249
250 ov = opts_visitor_new(opts);
251
252 visit_start_struct(opts_get_visitor(ov),
253 NULL, NULL, 0, &local_err);
254 if (local_err) {
255 goto out;
256 }
257
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;
263
264 default:
265 error_setg(&local_err, "Unsupported block format %d", format);
266 break;
267 }
15c2f669
EB
268 if (!local_err) {
269 visit_check_struct(opts_get_visitor(ov), &local_err);
270 }
78368575 271
15c2f669 272 visit_end_struct(opts_get_visitor(ov));
78368575
DB
273
274 out:
275 if (local_err) {
276 error_propagate(errp, local_err);
277 qapi_free_QCryptoBlockCreateOptions(ret);
278 ret = NULL;
279 }
280 opts_visitor_cleanup(ov);
281 return ret;
282}
283
284
285static int block_crypto_open_generic(QCryptoBlockFormat format,
286 QemuOptsList *opts_spec,
287 BlockDriverState *bs,
288 QDict *options,
289 int flags,
290 Error **errp)
291{
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;
298
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;
304 }
305
306 open_opts = block_crypto_open_opts_init(format, opts, errp);
307 if (!open_opts) {
308 goto cleanup;
309 }
310
311 if (flags & BDRV_O_NO_IO) {
312 cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
313 }
314 crypto->block = qcrypto_block_open(open_opts,
315 block_crypto_read_func,
316 bs,
317 cflags,
318 errp);
319
320 if (!crypto->block) {
321 ret = -EIO;
322 goto cleanup;
323 }
324
54115412
EB
325 bs->encrypted = true;
326 bs->valid_key = true;
78368575
DB
327
328 ret = 0;
329 cleanup:
330 qapi_free_QCryptoBlockOpenOptions(open_opts);
331 return ret;
332}
333
334
335static int block_crypto_create_generic(QCryptoBlockFormat format,
336 const char *filename,
337 QemuOpts *opts,
338 Error **errp)
339{
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,
348 };
349
350 create_opts = block_crypto_create_opts_init(format, opts, errp);
351 if (!create_opts) {
352 return -1;
353 }
354
355 crypto = qcrypto_block_create(create_opts,
356 block_crypto_init_func,
357 block_crypto_write_func,
358 &data,
359 errp);
360
361 if (!crypto) {
362 ret = -EIO;
363 goto cleanup;
364 }
365
366 ret = 0;
367 cleanup:
368 qcrypto_block_free(crypto);
369 blk_unref(data.blk);
370 qapi_free_QCryptoBlockCreateOptions(create_opts);
371 return ret;
372}
373
374static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
375{
376 BlockCrypto *crypto = bs->opaque;
377 size_t payload_offset =
378 qcrypto_block_get_payload_offset(crypto->block);
379
380 offset += payload_offset;
381
382 return bdrv_truncate(bs->file->bs, offset);
383}
384
385static void block_crypto_close(BlockDriverState *bs)
386{
387 BlockCrypto *crypto = bs->opaque;
388 qcrypto_block_free(crypto->block);
389}
390
391
392#define BLOCK_CRYPTO_MAX_SECTORS 32
393
394static coroutine_fn int
395block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
396 int remaining_sectors, QEMUIOVector *qiov)
397{
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;
406
407 qemu_iovec_init(&hd_qiov, qiov->niov);
408
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
412 */
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;
419 }
420
421 while (remaining_sectors) {
422 cur_nr_sectors = remaining_sectors;
423
424 if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
425 cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
426 }
427
428 qemu_iovec_reset(&hd_qiov);
429 qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
430
28b04a8f 431 ret = bdrv_co_readv(bs->file,
78368575
DB
432 payload_offset + sector_num,
433 cur_nr_sectors, &hd_qiov);
434 if (ret < 0) {
435 goto cleanup;
436 }
437
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;
444 }
445
446 qemu_iovec_from_buf(qiov, bytes_done,
447 cipher_data, cur_nr_sectors * 512);
448
449 remaining_sectors -= cur_nr_sectors;
450 sector_num += cur_nr_sectors;
451 bytes_done += cur_nr_sectors * 512;
452 }
453
454 cleanup:
455 qemu_iovec_destroy(&hd_qiov);
456 qemu_vfree(cipher_data);
457
458 return ret;
459}
460
461
462static coroutine_fn int
463block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
464 int remaining_sectors, QEMUIOVector *qiov)
465{
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;
474
475 qemu_iovec_init(&hd_qiov, qiov->niov);
476
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
480 */
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;
487 }
488
489 while (remaining_sectors) {
490 cur_nr_sectors = remaining_sectors;
491
492 if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
493 cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
494 }
495
496 qemu_iovec_to_buf(qiov, bytes_done,
497 cipher_data, cur_nr_sectors * 512);
498
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;
505 }
506
507 qemu_iovec_reset(&hd_qiov);
508 qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
509
25ec177d 510 ret = bdrv_co_writev(bs->file,
78368575
DB
511 payload_offset + sector_num,
512 cur_nr_sectors, &hd_qiov);
513 if (ret < 0) {
514 goto cleanup;
515 }
516
517 remaining_sectors -= cur_nr_sectors;
518 sector_num += cur_nr_sectors;
519 bytes_done += cur_nr_sectors * 512;
520 }
521
522 cleanup:
523 qemu_iovec_destroy(&hd_qiov);
524 qemu_vfree(cipher_data);
525
526 return ret;
527}
528
529
530static int64_t block_crypto_getlength(BlockDriverState *bs)
531{
532 BlockCrypto *crypto = bs->opaque;
533 int64_t len = bdrv_getlength(bs->file->bs);
534
535 ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
536
537 len -= offset;
538
539 return len;
540}
541
542
543static 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);
548}
549
550static int block_crypto_open_luks(BlockDriverState *bs,
551 QDict *options,
552 int flags,
553 Error **errp)
554{
555 return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
556 &block_crypto_runtime_opts_luks,
557 bs, options, flags, errp);
558}
559
560static int block_crypto_create_luks(const char *filename,
561 QemuOpts *opts,
562 Error **errp)
563{
564 return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
565 filename, opts, errp);
566}
567
568BlockDriver 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,
577
578 .bdrv_co_readv = block_crypto_co_readv,
579 .bdrv_co_writev = block_crypto_co_writev,
580 .bdrv_getlength = block_crypto_getlength,
581};
582
583static void block_crypto_init(void)
584{
585 bdrv_register(&bdrv_crypto_luks);
586}
587
588block_init(block_crypto_init);