xref: /openbmc/qemu/block/crypto.c (revision 63785678)
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);
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_CACHE_WB | BDRV_O_PROTOCOL,
125                              errp);
126     if (!data->blk) {
127         return -1;
128     }
129 
130     return 0;
131 }
132 
133 
134 static QemuOptsList block_crypto_runtime_opts_luks = {
135     .name = "crypto",
136     .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head),
137     .desc = {
138         {
139             .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
140             .type = QEMU_OPT_STRING,
141             .help = "ID of the secret that provides the encryption key",
142         },
143         { /* end of list */ }
144     },
145 };
146 
147 
148 static QemuOptsList block_crypto_create_opts_luks = {
149     .name = "crypto",
150     .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
151     .desc = {
152         {
153             .name = BLOCK_OPT_SIZE,
154             .type = QEMU_OPT_SIZE,
155             .help = "Virtual disk size"
156         },
157         {
158             .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
159             .type = QEMU_OPT_STRING,
160             .help = "ID of the secret that provides the encryption key",
161         },
162         {
163             .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG,
164             .type = QEMU_OPT_STRING,
165             .help = "Name of encryption cipher algorithm",
166         },
167         {
168             .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE,
169             .type = QEMU_OPT_STRING,
170             .help = "Name of encryption cipher mode",
171         },
172         {
173             .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG,
174             .type = QEMU_OPT_STRING,
175             .help = "Name of IV generator algorithm",
176         },
177         {
178             .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG,
179             .type = QEMU_OPT_STRING,
180             .help = "Name of IV generator hash algorithm",
181         },
182         {
183             .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG,
184             .type = QEMU_OPT_STRING,
185             .help = "Name of encryption hash algorithm",
186         },
187         { /* end of list */ }
188     },
189 };
190 
191 
192 static QCryptoBlockOpenOptions *
193 block_crypto_open_opts_init(QCryptoBlockFormat format,
194                             QemuOpts *opts,
195                             Error **errp)
196 {
197     OptsVisitor *ov;
198     QCryptoBlockOpenOptions *ret = NULL;
199     Error *local_err = NULL;
200 
201     ret = g_new0(QCryptoBlockOpenOptions, 1);
202     ret->format = format;
203 
204     ov = opts_visitor_new(opts);
205 
206     visit_start_struct(opts_get_visitor(ov),
207                        NULL, NULL, 0, &local_err);
208     if (local_err) {
209         goto out;
210     }
211 
212     switch (format) {
213     case Q_CRYPTO_BLOCK_FORMAT_LUKS:
214         visit_type_QCryptoBlockOptionsLUKS_members(
215             opts_get_visitor(ov), &ret->u.luks, &local_err);
216         break;
217 
218     default:
219         error_setg(&local_err, "Unsupported block format %d", format);
220         break;
221     }
222     error_propagate(errp, local_err);
223     local_err = NULL;
224 
225     visit_end_struct(opts_get_visitor(ov), &local_err);
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     error_propagate(errp, local_err);
269     local_err = NULL;
270 
271     visit_end_struct(opts_get_visitor(ov), &local_err);
272 
273  out:
274     if (local_err) {
275         error_propagate(errp, local_err);
276         qapi_free_QCryptoBlockCreateOptions(ret);
277         ret = NULL;
278     }
279     opts_visitor_cleanup(ov);
280     return ret;
281 }
282 
283 
284 static int block_crypto_open_generic(QCryptoBlockFormat format,
285                                      QemuOptsList *opts_spec,
286                                      BlockDriverState *bs,
287                                      QDict *options,
288                                      int flags,
289                                      Error **errp)
290 {
291     BlockCrypto *crypto = bs->opaque;
292     QemuOpts *opts = NULL;
293     Error *local_err = NULL;
294     int ret = -EINVAL;
295     QCryptoBlockOpenOptions *open_opts = NULL;
296     unsigned int cflags = 0;
297 
298     opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
299     qemu_opts_absorb_qdict(opts, options, &local_err);
300     if (local_err) {
301         error_propagate(errp, local_err);
302         goto cleanup;
303     }
304 
305     open_opts = block_crypto_open_opts_init(format, opts, errp);
306     if (!open_opts) {
307         goto cleanup;
308     }
309 
310     if (flags & BDRV_O_NO_IO) {
311         cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
312     }
313     crypto->block = qcrypto_block_open(open_opts,
314                                        block_crypto_read_func,
315                                        bs,
316                                        cflags,
317                                        errp);
318 
319     if (!crypto->block) {
320         ret = -EIO;
321         goto cleanup;
322     }
323 
324     bs->encrypted = 1;
325     bs->valid_key = 1;
326 
327     ret = 0;
328  cleanup:
329     qapi_free_QCryptoBlockOpenOptions(open_opts);
330     return ret;
331 }
332 
333 
334 static int block_crypto_create_generic(QCryptoBlockFormat format,
335                                        const char *filename,
336                                        QemuOpts *opts,
337                                        Error **errp)
338 {
339     int ret = -EINVAL;
340     QCryptoBlockCreateOptions *create_opts = NULL;
341     QCryptoBlock *crypto = NULL;
342     struct BlockCryptoCreateData data = {
343         .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
344                          BDRV_SECTOR_SIZE),
345         .opts = opts,
346         .filename = filename,
347     };
348 
349     create_opts = block_crypto_create_opts_init(format, opts, errp);
350     if (!create_opts) {
351         return -1;
352     }
353 
354     crypto = qcrypto_block_create(create_opts,
355                                   block_crypto_init_func,
356                                   block_crypto_write_func,
357                                   &data,
358                                   errp);
359 
360     if (!crypto) {
361         ret = -EIO;
362         goto cleanup;
363     }
364 
365     ret = 0;
366  cleanup:
367     qcrypto_block_free(crypto);
368     blk_unref(data.blk);
369     qapi_free_QCryptoBlockCreateOptions(create_opts);
370     return ret;
371 }
372 
373 static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
374 {
375     BlockCrypto *crypto = bs->opaque;
376     size_t payload_offset =
377         qcrypto_block_get_payload_offset(crypto->block);
378 
379     offset += payload_offset;
380 
381     return bdrv_truncate(bs->file->bs, offset);
382 }
383 
384 static void block_crypto_close(BlockDriverState *bs)
385 {
386     BlockCrypto *crypto = bs->opaque;
387     qcrypto_block_free(crypto->block);
388 }
389 
390 
391 #define BLOCK_CRYPTO_MAX_SECTORS 32
392 
393 static coroutine_fn int
394 block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
395                       int remaining_sectors, QEMUIOVector *qiov)
396 {
397     BlockCrypto *crypto = bs->opaque;
398     int cur_nr_sectors; /* number of sectors in current iteration */
399     uint64_t bytes_done = 0;
400     uint8_t *cipher_data = NULL;
401     QEMUIOVector hd_qiov;
402     int ret = 0;
403     size_t payload_offset =
404         qcrypto_block_get_payload_offset(crypto->block) / 512;
405 
406     qemu_iovec_init(&hd_qiov, qiov->niov);
407 
408     /* Bounce buffer so we have a linear mem region for
409      * entire sector. XXX optimize so we avoid bounce
410      * buffer in case that qiov->niov == 1
411      */
412     cipher_data =
413         qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
414                                               qiov->size));
415     if (cipher_data == NULL) {
416         ret = -ENOMEM;
417         goto cleanup;
418     }
419 
420     while (remaining_sectors) {
421         cur_nr_sectors = remaining_sectors;
422 
423         if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
424             cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
425         }
426 
427         qemu_iovec_reset(&hd_qiov);
428         qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
429 
430         ret = bdrv_co_readv(bs->file->bs,
431                             payload_offset + sector_num,
432                             cur_nr_sectors, &hd_qiov);
433         if (ret < 0) {
434             goto cleanup;
435         }
436 
437         if (qcrypto_block_decrypt(crypto->block,
438                                   sector_num,
439                                   cipher_data, cur_nr_sectors * 512,
440                                   NULL) < 0) {
441             ret = -EIO;
442             goto cleanup;
443         }
444 
445         qemu_iovec_from_buf(qiov, bytes_done,
446                             cipher_data, cur_nr_sectors * 512);
447 
448         remaining_sectors -= cur_nr_sectors;
449         sector_num += cur_nr_sectors;
450         bytes_done += cur_nr_sectors * 512;
451     }
452 
453  cleanup:
454     qemu_iovec_destroy(&hd_qiov);
455     qemu_vfree(cipher_data);
456 
457     return ret;
458 }
459 
460 
461 static coroutine_fn int
462 block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
463                        int remaining_sectors, QEMUIOVector *qiov)
464 {
465     BlockCrypto *crypto = bs->opaque;
466     int cur_nr_sectors; /* number of sectors in current iteration */
467     uint64_t bytes_done = 0;
468     uint8_t *cipher_data = NULL;
469     QEMUIOVector hd_qiov;
470     int ret = 0;
471     size_t payload_offset =
472         qcrypto_block_get_payload_offset(crypto->block) / 512;
473 
474     qemu_iovec_init(&hd_qiov, qiov->niov);
475 
476     /* Bounce buffer so we have a linear mem region for
477      * entire sector. XXX optimize so we avoid bounce
478      * buffer in case that qiov->niov == 1
479      */
480     cipher_data =
481         qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
482                                               qiov->size));
483     if (cipher_data == NULL) {
484         ret = -ENOMEM;
485         goto cleanup;
486     }
487 
488     while (remaining_sectors) {
489         cur_nr_sectors = remaining_sectors;
490 
491         if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
492             cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
493         }
494 
495         qemu_iovec_to_buf(qiov, bytes_done,
496                           cipher_data, cur_nr_sectors * 512);
497 
498         if (qcrypto_block_encrypt(crypto->block,
499                                   sector_num,
500                                   cipher_data, cur_nr_sectors * 512,
501                                   NULL) < 0) {
502             ret = -EIO;
503             goto cleanup;
504         }
505 
506         qemu_iovec_reset(&hd_qiov);
507         qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
508 
509         ret = bdrv_co_writev(bs->file->bs,
510                              payload_offset + sector_num,
511                              cur_nr_sectors, &hd_qiov);
512         if (ret < 0) {
513             goto cleanup;
514         }
515 
516         remaining_sectors -= cur_nr_sectors;
517         sector_num += cur_nr_sectors;
518         bytes_done += cur_nr_sectors * 512;
519     }
520 
521  cleanup:
522     qemu_iovec_destroy(&hd_qiov);
523     qemu_vfree(cipher_data);
524 
525     return ret;
526 }
527 
528 
529 static int64_t block_crypto_getlength(BlockDriverState *bs)
530 {
531     BlockCrypto *crypto = bs->opaque;
532     int64_t len = bdrv_getlength(bs->file->bs);
533 
534     ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
535 
536     len -= offset;
537 
538     return len;
539 }
540 
541 
542 static int block_crypto_probe_luks(const uint8_t *buf,
543                                    int buf_size,
544                                    const char *filename) {
545     return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
546                                       buf, buf_size, filename);
547 }
548 
549 static int block_crypto_open_luks(BlockDriverState *bs,
550                                   QDict *options,
551                                   int flags,
552                                   Error **errp)
553 {
554     return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
555                                      &block_crypto_runtime_opts_luks,
556                                      bs, options, flags, errp);
557 }
558 
559 static int block_crypto_create_luks(const char *filename,
560                                     QemuOpts *opts,
561                                     Error **errp)
562 {
563     return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
564                                        filename, opts, errp);
565 }
566 
567 BlockDriver bdrv_crypto_luks = {
568     .format_name        = "luks",
569     .instance_size      = sizeof(BlockCrypto),
570     .bdrv_probe         = block_crypto_probe_luks,
571     .bdrv_open          = block_crypto_open_luks,
572     .bdrv_close         = block_crypto_close,
573     .bdrv_create        = block_crypto_create_luks,
574     .bdrv_truncate      = block_crypto_truncate,
575     .create_opts        = &block_crypto_create_opts_luks,
576 
577     .bdrv_co_readv      = block_crypto_co_readv,
578     .bdrv_co_writev     = block_crypto_co_writev,
579     .bdrv_getlength     = block_crypto_getlength,
580 };
581 
582 static void block_crypto_init(void)
583 {
584     bdrv_register(&bdrv_crypto_luks);
585 }
586 
587 block_init(block_crypto_init);
588