xref: /qemu/block/crypto.c (revision 52ea63de)
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 
37 typedef struct BlockCrypto BlockCrypto;
38 
39 struct BlockCrypto {
40     QCryptoBlock *block;
41 };
42 
43 
44 static 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 
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)
63 {
64     BlockDriverState *bs = opaque;
65     ssize_t ret;
66 
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;
71     }
72     return ret;
73 }
74 
75 
76 struct BlockCryptoCreateData {
77     const char *filename;
78     QemuOpts *opts;
79     BlockBackend *blk;
80     uint64_t size;
81 };
82 
83 
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)
90 {
91     struct BlockCryptoCreateData *data = opaque;
92     ssize_t ret;
93 
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;
98     }
99     return ret;
100 }
101 
102 
103 static 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,
124                              BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
125     if (!data->blk) {
126         return -1;
127     }
128 
129     return 0;
130 }
131 
132 
133 static 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 
147 static 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 
191 static QCryptoBlockOpenOptions *
192 block_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     }
221     if (!local_err) {
222         visit_check_struct(opts_get_visitor(ov), &local_err);
223     }
224 
225     visit_end_struct(opts_get_visitor(ov));
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 
238 static QCryptoBlockCreateOptions *
239 block_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     }
268     if (!local_err) {
269         visit_check_struct(opts_get_visitor(ov), &local_err);
270     }
271 
272     visit_end_struct(opts_get_visitor(ov));
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 
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)
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 
325     bs->encrypted = 1;
326     bs->valid_key = 1;
327 
328     ret = 0;
329  cleanup:
330     qapi_free_QCryptoBlockOpenOptions(open_opts);
331     return ret;
332 }
333 
334 
335 static 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 
374 static 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 
385 static 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 
394 static coroutine_fn int
395 block_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 
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;
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 
462 static coroutine_fn int
463 block_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 
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;
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 
530 static 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 
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);
548 }
549 
550 static 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 
560 static 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 
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,
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 
583 static void block_crypto_init(void)
584 {
585     bdrv_register(&bdrv_crypto_luks);
586 }
587 
588 block_init(block_crypto_init);
589