qemu/block/crypto.c
<<
>>
Prefs
   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
  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
  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
  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
 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,
 124                             BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
 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    Error *end_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
 223    visit_end_struct(opts_get_visitor(ov), &end_err);
 224    error_propagate(&local_err, end_err);
 225
 226 out:
 227    if (local_err) {
 228        error_propagate(errp, local_err);
 229        qapi_free_QCryptoBlockOpenOptions(ret);
 230        ret = NULL;
 231    }
 232    opts_visitor_cleanup(ov);
 233    return ret;
 234}
 235
 236
 237static QCryptoBlockCreateOptions *
 238block_crypto_create_opts_init(QCryptoBlockFormat format,
 239                              QemuOpts *opts,
 240                              Error **errp)
 241{
 242    OptsVisitor *ov;
 243    QCryptoBlockCreateOptions *ret = NULL;
 244    Error *local_err = NULL;
 245    Error *end_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
 269    visit_end_struct(opts_get_visitor(ov), &end_err);
 270    error_propagate(&local_err, end_err);
 271
 272 out:
 273    if (local_err) {
 274        error_propagate(errp, local_err);
 275        qapi_free_QCryptoBlockCreateOptions(ret);
 276        ret = NULL;
 277    }
 278    opts_visitor_cleanup(ov);
 279    return ret;
 280}
 281
 282
 283static int block_crypto_open_generic(QCryptoBlockFormat format,
 284                                     QemuOptsList *opts_spec,
 285                                     BlockDriverState *bs,
 286                                     QDict *options,
 287                                     int flags,
 288                                     Error **errp)
 289{
 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;
 296
 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;
 302    }
 303
 304    open_opts = block_crypto_open_opts_init(format, opts, errp);
 305    if (!open_opts) {
 306        goto cleanup;
 307    }
 308
 309    if (flags & BDRV_O_NO_IO) {
 310        cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
 311    }
 312    crypto->block = qcrypto_block_open(open_opts,
 313                                       block_crypto_read_func,
 314                                       bs,
 315                                       cflags,
 316                                       errp);
 317
 318    if (!crypto->block) {
 319        ret = -EIO;
 320        goto cleanup;
 321    }
 322
 323    bs->encrypted = 1;
 324    bs->valid_key = 1;
 325
 326    ret = 0;
 327 cleanup:
 328    qapi_free_QCryptoBlockOpenOptions(open_opts);
 329    return ret;
 330}
 331
 332
 333static int block_crypto_create_generic(QCryptoBlockFormat format,
 334                                       const char *filename,
 335                                       QemuOpts *opts,
 336                                       Error **errp)
 337{
 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,
 346    };
 347
 348    create_opts = block_crypto_create_opts_init(format, opts, errp);
 349    if (!create_opts) {
 350        return -1;
 351    }
 352
 353    crypto = qcrypto_block_create(create_opts,
 354                                  block_crypto_init_func,
 355                                  block_crypto_write_func,
 356                                  &data,
 357                                  errp);
 358
 359    if (!crypto) {
 360        ret = -EIO;
 361        goto cleanup;
 362    }
 363
 364    ret = 0;
 365 cleanup:
 366    qcrypto_block_free(crypto);
 367    blk_unref(data.blk);
 368    qapi_free_QCryptoBlockCreateOptions(create_opts);
 369    return ret;
 370}
 371
 372static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
 373{
 374    BlockCrypto *crypto = bs->opaque;
 375    size_t payload_offset =
 376        qcrypto_block_get_payload_offset(crypto->block);
 377
 378    offset += payload_offset;
 379
 380    return bdrv_truncate(bs->file->bs, offset);
 381}
 382
 383static void block_crypto_close(BlockDriverState *bs)
 384{
 385    BlockCrypto *crypto = bs->opaque;
 386    qcrypto_block_free(crypto->block);
 387}
 388
 389
 390#define BLOCK_CRYPTO_MAX_SECTORS 32
 391
 392static coroutine_fn int
 393block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
 394                      int remaining_sectors, QEMUIOVector *qiov)
 395{
 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;
 404
 405    qemu_iovec_init(&hd_qiov, qiov->niov);
 406
 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
 410     */
 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;
 417    }
 418
 419    while (remaining_sectors) {
 420        cur_nr_sectors = remaining_sectors;
 421
 422        if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
 423            cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
 424        }
 425
 426        qemu_iovec_reset(&hd_qiov);
 427        qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
 428
 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;
 434        }
 435
 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;
 442        }
 443
 444        qemu_iovec_from_buf(qiov, bytes_done,
 445                            cipher_data, cur_nr_sectors * 512);
 446
 447        remaining_sectors -= cur_nr_sectors;
 448        sector_num += cur_nr_sectors;
 449        bytes_done += cur_nr_sectors * 512;
 450    }
 451
 452 cleanup:
 453    qemu_iovec_destroy(&hd_qiov);
 454    qemu_vfree(cipher_data);
 455
 456    return ret;
 457}
 458
 459
 460static coroutine_fn int
 461block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
 462                       int remaining_sectors, QEMUIOVector *qiov)
 463{
 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;
 472
 473    qemu_iovec_init(&hd_qiov, qiov->niov);
 474
 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
 478     */
 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;
 485    }
 486
 487    while (remaining_sectors) {
 488        cur_nr_sectors = remaining_sectors;
 489
 490        if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
 491            cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
 492        }
 493
 494        qemu_iovec_to_buf(qiov, bytes_done,
 495                          cipher_data, cur_nr_sectors * 512);
 496
 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;
 503        }
 504
 505        qemu_iovec_reset(&hd_qiov);
 506        qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
 507
 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;
 513        }
 514
 515        remaining_sectors -= cur_nr_sectors;
 516        sector_num += cur_nr_sectors;
 517        bytes_done += cur_nr_sectors * 512;
 518    }
 519
 520 cleanup:
 521    qemu_iovec_destroy(&hd_qiov);
 522    qemu_vfree(cipher_data);
 523
 524    return ret;
 525}
 526
 527
 528static int64_t block_crypto_getlength(BlockDriverState *bs)
 529{
 530    BlockCrypto *crypto = bs->opaque;
 531    int64_t len = bdrv_getlength(bs->file->bs);
 532
 533    ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
 534
 535    len -= offset;
 536
 537    return len;
 538}
 539
 540
 541static 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);
 546}
 547
 548static int block_crypto_open_luks(BlockDriverState *bs,
 549                                  QDict *options,
 550                                  int flags,
 551                                  Error **errp)
 552{
 553    return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
 554                                     &block_crypto_runtime_opts_luks,
 555                                     bs, options, flags, errp);
 556}
 557
 558static int block_crypto_create_luks(const char *filename,
 559                                    QemuOpts *opts,
 560                                    Error **errp)
 561{
 562    return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
 563                                       filename, opts, errp);
 564}
 565
 566BlockDriver 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,
 575
 576    .bdrv_co_readv      = block_crypto_co_readv,
 577    .bdrv_co_writev     = block_crypto_co_writev,
 578    .bdrv_getlength     = block_crypto_getlength,
 579};
 580
 581static void block_crypto_init(void)
 582{
 583    bdrv_register(&bdrv_crypto_luks);
 584}
 585
 586block_init(block_crypto_init);
 587