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#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
  37
  38typedef struct BlockCrypto BlockCrypto;
  39
  40struct BlockCrypto {
  41    QCryptoBlock *block;
  42};
  43
  44
  45static int block_crypto_probe_generic(QCryptoBlockFormat format,
  46                                      const uint8_t *buf,
  47                                      int buf_size,
  48                                      const char *filename)
  49{
  50    if (qcrypto_block_has_format(format, buf, buf_size)) {
  51        return 100;
  52    } else {
  53        return 0;
  54    }
  55}
  56
  57
  58static ssize_t block_crypto_read_func(QCryptoBlock *block,
  59                                      size_t offset,
  60                                      uint8_t *buf,
  61                                      size_t buflen,
  62                                      Error **errp,
  63                                      void *opaque)
  64{
  65    BlockDriverState *bs = opaque;
  66    ssize_t ret;
  67
  68    ret = bdrv_pread(bs->file, offset, buf, buflen);
  69    if (ret < 0) {
  70        error_setg_errno(errp, -ret, "Could not read encryption header");
  71        return ret;
  72    }
  73    return ret;
  74}
  75
  76
  77struct BlockCryptoCreateData {
  78    const char *filename;
  79    QemuOpts *opts;
  80    BlockBackend *blk;
  81    uint64_t size;
  82};
  83
  84
  85static ssize_t block_crypto_write_func(QCryptoBlock *block,
  86                                       size_t offset,
  87                                       const uint8_t *buf,
  88                                       size_t buflen,
  89                                       Error **errp,
  90                                       void *opaque)
  91{
  92    struct BlockCryptoCreateData *data = opaque;
  93    ssize_t ret;
  94
  95    ret = blk_pwrite(data->blk, offset, buf, buflen, 0);
  96    if (ret < 0) {
  97        error_setg_errno(errp, -ret, "Could not write encryption header");
  98        return ret;
  99    }
 100    return ret;
 101}
 102
 103
 104static ssize_t block_crypto_init_func(QCryptoBlock *block,
 105                                      size_t headerlen,
 106                                      Error **errp,
 107                                      void *opaque)
 108{
 109    struct BlockCryptoCreateData *data = opaque;
 110    int ret;
 111
 112    /* User provided size should reflect amount of space made
 113     * available to the guest, so we must take account of that
 114     * which will be used by the crypto header
 115     */
 116    data->size += headerlen;
 117
 118    qemu_opt_set_number(data->opts, BLOCK_OPT_SIZE, data->size, &error_abort);
 119    ret = bdrv_create_file(data->filename, data->opts, errp);
 120    if (ret < 0) {
 121        return -1;
 122    }
 123
 124    data->blk = blk_new_open(data->filename, NULL, NULL,
 125                             BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
 126    if (!data->blk) {
 127        return -1;
 128    }
 129
 130    return 0;
 131}
 132
 133
 134static 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
 148static 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        {
 188            .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME,
 189            .type = QEMU_OPT_NUMBER,
 190            .help = "Time to spend in PBKDF in milliseconds",
 191        },
 192        { /* end of list */ }
 193    },
 194};
 195
 196
 197static QCryptoBlockOpenOptions *
 198block_crypto_open_opts_init(QCryptoBlockFormat format,
 199                            QemuOpts *opts,
 200                            Error **errp)
 201{
 202    Visitor *v;
 203    QCryptoBlockOpenOptions *ret = NULL;
 204    Error *local_err = NULL;
 205
 206    ret = g_new0(QCryptoBlockOpenOptions, 1);
 207    ret->format = format;
 208
 209    v = opts_visitor_new(opts);
 210
 211    visit_start_struct(v, NULL, NULL, 0, &local_err);
 212    if (local_err) {
 213        goto out;
 214    }
 215
 216    switch (format) {
 217    case Q_CRYPTO_BLOCK_FORMAT_LUKS:
 218        visit_type_QCryptoBlockOptionsLUKS_members(
 219            v, &ret->u.luks, &local_err);
 220        break;
 221
 222    default:
 223        error_setg(&local_err, "Unsupported block format %d", format);
 224        break;
 225    }
 226    if (!local_err) {
 227        visit_check_struct(v, &local_err);
 228    }
 229
 230    visit_end_struct(v, NULL);
 231
 232 out:
 233    if (local_err) {
 234        error_propagate(errp, local_err);
 235        qapi_free_QCryptoBlockOpenOptions(ret);
 236        ret = NULL;
 237    }
 238    visit_free(v);
 239    return ret;
 240}
 241
 242
 243static QCryptoBlockCreateOptions *
 244block_crypto_create_opts_init(QCryptoBlockFormat format,
 245                              QemuOpts *opts,
 246                              Error **errp)
 247{
 248    Visitor *v;
 249    QCryptoBlockCreateOptions *ret = NULL;
 250    Error *local_err = NULL;
 251
 252    ret = g_new0(QCryptoBlockCreateOptions, 1);
 253    ret->format = format;
 254
 255    v = opts_visitor_new(opts);
 256
 257    visit_start_struct(v, NULL, NULL, 0, &local_err);
 258    if (local_err) {
 259        goto out;
 260    }
 261
 262    switch (format) {
 263    case Q_CRYPTO_BLOCK_FORMAT_LUKS:
 264        visit_type_QCryptoBlockCreateOptionsLUKS_members(
 265            v, &ret->u.luks, &local_err);
 266        break;
 267
 268    default:
 269        error_setg(&local_err, "Unsupported block format %d", format);
 270        break;
 271    }
 272    if (!local_err) {
 273        visit_check_struct(v, &local_err);
 274    }
 275
 276    visit_end_struct(v, NULL);
 277
 278 out:
 279    if (local_err) {
 280        error_propagate(errp, local_err);
 281        qapi_free_QCryptoBlockCreateOptions(ret);
 282        ret = NULL;
 283    }
 284    visit_free(v);
 285    return ret;
 286}
 287
 288
 289static int block_crypto_open_generic(QCryptoBlockFormat format,
 290                                     QemuOptsList *opts_spec,
 291                                     BlockDriverState *bs,
 292                                     QDict *options,
 293                                     int flags,
 294                                     Error **errp)
 295{
 296    BlockCrypto *crypto = bs->opaque;
 297    QemuOpts *opts = NULL;
 298    Error *local_err = NULL;
 299    int ret = -EINVAL;
 300    QCryptoBlockOpenOptions *open_opts = NULL;
 301    unsigned int cflags = 0;
 302
 303    opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
 304    qemu_opts_absorb_qdict(opts, options, &local_err);
 305    if (local_err) {
 306        error_propagate(errp, local_err);
 307        goto cleanup;
 308    }
 309
 310    open_opts = block_crypto_open_opts_init(format, opts, errp);
 311    if (!open_opts) {
 312        goto cleanup;
 313    }
 314
 315    if (flags & BDRV_O_NO_IO) {
 316        cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
 317    }
 318    crypto->block = qcrypto_block_open(open_opts,
 319                                       block_crypto_read_func,
 320                                       bs,
 321                                       cflags,
 322                                       errp);
 323
 324    if (!crypto->block) {
 325        ret = -EIO;
 326        goto cleanup;
 327    }
 328
 329    bs->encrypted = true;
 330    bs->valid_key = true;
 331
 332    ret = 0;
 333 cleanup:
 334    qapi_free_QCryptoBlockOpenOptions(open_opts);
 335    return ret;
 336}
 337
 338
 339static int block_crypto_create_generic(QCryptoBlockFormat format,
 340                                       const char *filename,
 341                                       QemuOpts *opts,
 342                                       Error **errp)
 343{
 344    int ret = -EINVAL;
 345    QCryptoBlockCreateOptions *create_opts = NULL;
 346    QCryptoBlock *crypto = NULL;
 347    struct BlockCryptoCreateData data = {
 348        .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
 349                         BDRV_SECTOR_SIZE),
 350        .opts = opts,
 351        .filename = filename,
 352    };
 353
 354    create_opts = block_crypto_create_opts_init(format, opts, errp);
 355    if (!create_opts) {
 356        return -1;
 357    }
 358
 359    crypto = qcrypto_block_create(create_opts,
 360                                  block_crypto_init_func,
 361                                  block_crypto_write_func,
 362                                  &data,
 363                                  errp);
 364
 365    if (!crypto) {
 366        ret = -EIO;
 367        goto cleanup;
 368    }
 369
 370    ret = 0;
 371 cleanup:
 372    qcrypto_block_free(crypto);
 373    blk_unref(data.blk);
 374    qapi_free_QCryptoBlockCreateOptions(create_opts);
 375    return ret;
 376}
 377
 378static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
 379{
 380    BlockCrypto *crypto = bs->opaque;
 381    size_t payload_offset =
 382        qcrypto_block_get_payload_offset(crypto->block);
 383
 384    offset += payload_offset;
 385
 386    return bdrv_truncate(bs->file->bs, offset);
 387}
 388
 389static void block_crypto_close(BlockDriverState *bs)
 390{
 391    BlockCrypto *crypto = bs->opaque;
 392    qcrypto_block_free(crypto->block);
 393}
 394
 395
 396#define BLOCK_CRYPTO_MAX_SECTORS 32
 397
 398static coroutine_fn int
 399block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
 400                      int remaining_sectors, QEMUIOVector *qiov)
 401{
 402    BlockCrypto *crypto = bs->opaque;
 403    int cur_nr_sectors; /* number of sectors in current iteration */
 404    uint64_t bytes_done = 0;
 405    uint8_t *cipher_data = NULL;
 406    QEMUIOVector hd_qiov;
 407    int ret = 0;
 408    size_t payload_offset =
 409        qcrypto_block_get_payload_offset(crypto->block) / 512;
 410
 411    qemu_iovec_init(&hd_qiov, qiov->niov);
 412
 413    /* Bounce buffer so we have a linear mem region for
 414     * entire sector. XXX optimize so we avoid bounce
 415     * buffer in case that qiov->niov == 1
 416     */
 417    cipher_data =
 418        qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
 419                                              qiov->size));
 420    if (cipher_data == NULL) {
 421        ret = -ENOMEM;
 422        goto cleanup;
 423    }
 424
 425    while (remaining_sectors) {
 426        cur_nr_sectors = remaining_sectors;
 427
 428        if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
 429            cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
 430        }
 431
 432        qemu_iovec_reset(&hd_qiov);
 433        qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
 434
 435        ret = bdrv_co_readv(bs->file,
 436                            payload_offset + sector_num,
 437                            cur_nr_sectors, &hd_qiov);
 438        if (ret < 0) {
 439            goto cleanup;
 440        }
 441
 442        if (qcrypto_block_decrypt(crypto->block,
 443                                  sector_num,
 444                                  cipher_data, cur_nr_sectors * 512,
 445                                  NULL) < 0) {
 446            ret = -EIO;
 447            goto cleanup;
 448        }
 449
 450        qemu_iovec_from_buf(qiov, bytes_done,
 451                            cipher_data, cur_nr_sectors * 512);
 452
 453        remaining_sectors -= cur_nr_sectors;
 454        sector_num += cur_nr_sectors;
 455        bytes_done += cur_nr_sectors * 512;
 456    }
 457
 458 cleanup:
 459    qemu_iovec_destroy(&hd_qiov);
 460    qemu_vfree(cipher_data);
 461
 462    return ret;
 463}
 464
 465
 466static coroutine_fn int
 467block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
 468                       int remaining_sectors, QEMUIOVector *qiov)
 469{
 470    BlockCrypto *crypto = bs->opaque;
 471    int cur_nr_sectors; /* number of sectors in current iteration */
 472    uint64_t bytes_done = 0;
 473    uint8_t *cipher_data = NULL;
 474    QEMUIOVector hd_qiov;
 475    int ret = 0;
 476    size_t payload_offset =
 477        qcrypto_block_get_payload_offset(crypto->block) / 512;
 478
 479    qemu_iovec_init(&hd_qiov, qiov->niov);
 480
 481    /* Bounce buffer so we have a linear mem region for
 482     * entire sector. XXX optimize so we avoid bounce
 483     * buffer in case that qiov->niov == 1
 484     */
 485    cipher_data =
 486        qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
 487                                              qiov->size));
 488    if (cipher_data == NULL) {
 489        ret = -ENOMEM;
 490        goto cleanup;
 491    }
 492
 493    while (remaining_sectors) {
 494        cur_nr_sectors = remaining_sectors;
 495
 496        if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
 497            cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
 498        }
 499
 500        qemu_iovec_to_buf(qiov, bytes_done,
 501                          cipher_data, cur_nr_sectors * 512);
 502
 503        if (qcrypto_block_encrypt(crypto->block,
 504                                  sector_num,
 505                                  cipher_data, cur_nr_sectors * 512,
 506                                  NULL) < 0) {
 507            ret = -EIO;
 508            goto cleanup;
 509        }
 510
 511        qemu_iovec_reset(&hd_qiov);
 512        qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
 513
 514        ret = bdrv_co_writev(bs->file,
 515                             payload_offset + sector_num,
 516                             cur_nr_sectors, &hd_qiov);
 517        if (ret < 0) {
 518            goto cleanup;
 519        }
 520
 521        remaining_sectors -= cur_nr_sectors;
 522        sector_num += cur_nr_sectors;
 523        bytes_done += cur_nr_sectors * 512;
 524    }
 525
 526 cleanup:
 527    qemu_iovec_destroy(&hd_qiov);
 528    qemu_vfree(cipher_data);
 529
 530    return ret;
 531}
 532
 533
 534static int64_t block_crypto_getlength(BlockDriverState *bs)
 535{
 536    BlockCrypto *crypto = bs->opaque;
 537    int64_t len = bdrv_getlength(bs->file->bs);
 538
 539    ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
 540
 541    len -= offset;
 542
 543    return len;
 544}
 545
 546
 547static int block_crypto_probe_luks(const uint8_t *buf,
 548                                   int buf_size,
 549                                   const char *filename) {
 550    return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
 551                                      buf, buf_size, filename);
 552}
 553
 554static int block_crypto_open_luks(BlockDriverState *bs,
 555                                  QDict *options,
 556                                  int flags,
 557                                  Error **errp)
 558{
 559    return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
 560                                     &block_crypto_runtime_opts_luks,
 561                                     bs, options, flags, errp);
 562}
 563
 564static int block_crypto_create_luks(const char *filename,
 565                                    QemuOpts *opts,
 566                                    Error **errp)
 567{
 568    return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
 569                                       filename, opts, errp);
 570}
 571
 572static int block_crypto_get_info_luks(BlockDriverState *bs,
 573                                      BlockDriverInfo *bdi)
 574{
 575    BlockDriverInfo subbdi;
 576    int ret;
 577
 578    ret = bdrv_get_info(bs->file->bs, &subbdi);
 579    if (ret != 0) {
 580        return ret;
 581    }
 582
 583    bdi->unallocated_blocks_are_zero = false;
 584    bdi->can_write_zeroes_with_unmap = false;
 585    bdi->cluster_size = subbdi.cluster_size;
 586
 587    return 0;
 588}
 589
 590static ImageInfoSpecific *
 591block_crypto_get_specific_info_luks(BlockDriverState *bs)
 592{
 593    BlockCrypto *crypto = bs->opaque;
 594    ImageInfoSpecific *spec_info;
 595    QCryptoBlockInfo *info;
 596
 597    info = qcrypto_block_get_info(crypto->block, NULL);
 598    if (!info) {
 599        return NULL;
 600    }
 601    if (info->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) {
 602        qapi_free_QCryptoBlockInfo(info);
 603        return NULL;
 604    }
 605
 606    spec_info = g_new(ImageInfoSpecific, 1);
 607    spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS;
 608    spec_info->u.luks.data = g_new(QCryptoBlockInfoLUKS, 1);
 609    *spec_info->u.luks.data = info->u.luks;
 610
 611    /* Blank out pointers we've just stolen to avoid double free */
 612    memset(&info->u.luks, 0, sizeof(info->u.luks));
 613
 614    qapi_free_QCryptoBlockInfo(info);
 615
 616    return spec_info;
 617}
 618
 619BlockDriver bdrv_crypto_luks = {
 620    .format_name        = "luks",
 621    .instance_size      = sizeof(BlockCrypto),
 622    .bdrv_probe         = block_crypto_probe_luks,
 623    .bdrv_open          = block_crypto_open_luks,
 624    .bdrv_close         = block_crypto_close,
 625    .bdrv_create        = block_crypto_create_luks,
 626    .bdrv_truncate      = block_crypto_truncate,
 627    .create_opts        = &block_crypto_create_opts_luks,
 628
 629    .bdrv_co_readv      = block_crypto_co_readv,
 630    .bdrv_co_writev     = block_crypto_co_writev,
 631    .bdrv_getlength     = block_crypto_getlength,
 632    .bdrv_get_info      = block_crypto_get_info_luks,
 633    .bdrv_get_specific_info = block_crypto_get_specific_info_luks,
 634};
 635
 636static void block_crypto_init(void)
 637{
 638    bdrv_register(&bdrv_crypto_luks);
 639}
 640
 641block_init(block_crypto_init);
 642