cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

block.c (14437B)


      1/*
      2 * QEMU Crypto block device 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.1 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#include "qapi/error.h"
     23#include "blockpriv.h"
     24#include "block-qcow.h"
     25#include "block-luks.h"
     26
     27static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
     28    [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
     29    [Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
     30};
     31
     32
     33bool qcrypto_block_has_format(QCryptoBlockFormat format,
     34                              const uint8_t *buf,
     35                              size_t len)
     36{
     37    const QCryptoBlockDriver *driver;
     38
     39    if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
     40        !qcrypto_block_drivers[format]) {
     41        return false;
     42    }
     43
     44    driver = qcrypto_block_drivers[format];
     45
     46    return driver->has_format(buf, len);
     47}
     48
     49
     50QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
     51                                 const char *optprefix,
     52                                 QCryptoBlockReadFunc readfunc,
     53                                 void *opaque,
     54                                 unsigned int flags,
     55                                 size_t n_threads,
     56                                 Error **errp)
     57{
     58    QCryptoBlock *block = g_new0(QCryptoBlock, 1);
     59
     60    block->format = options->format;
     61
     62    if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
     63        !qcrypto_block_drivers[options->format]) {
     64        error_setg(errp, "Unsupported block driver %s",
     65                   QCryptoBlockFormat_str(options->format));
     66        g_free(block);
     67        return NULL;
     68    }
     69
     70    block->driver = qcrypto_block_drivers[options->format];
     71
     72    if (block->driver->open(block, options, optprefix,
     73                            readfunc, opaque, flags, n_threads, errp) < 0)
     74    {
     75        g_free(block);
     76        return NULL;
     77    }
     78
     79    qemu_mutex_init(&block->mutex);
     80
     81    return block;
     82}
     83
     84
     85QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
     86                                   const char *optprefix,
     87                                   QCryptoBlockInitFunc initfunc,
     88                                   QCryptoBlockWriteFunc writefunc,
     89                                   void *opaque,
     90                                   Error **errp)
     91{
     92    QCryptoBlock *block = g_new0(QCryptoBlock, 1);
     93
     94    block->format = options->format;
     95
     96    if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
     97        !qcrypto_block_drivers[options->format]) {
     98        error_setg(errp, "Unsupported block driver %s",
     99                   QCryptoBlockFormat_str(options->format));
    100        g_free(block);
    101        return NULL;
    102    }
    103
    104    block->driver = qcrypto_block_drivers[options->format];
    105
    106    if (block->driver->create(block, options, optprefix, initfunc,
    107                              writefunc, opaque, errp) < 0) {
    108        g_free(block);
    109        return NULL;
    110    }
    111
    112    qemu_mutex_init(&block->mutex);
    113
    114    return block;
    115}
    116
    117
    118static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block,
    119        size_t headerlen, void *opaque, Error **errp)
    120{
    121    size_t *headerlenp = opaque;
    122
    123    /* Stash away the payload size */
    124    *headerlenp = headerlen;
    125    return 0;
    126}
    127
    128
    129static ssize_t qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block,
    130        size_t offset, const uint8_t *buf, size_t buflen,
    131        void *opaque, Error **errp)
    132{
    133    /* Discard the bytes, we're not actually writing to an image */
    134    return buflen;
    135}
    136
    137
    138bool
    139qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
    140                                       const char *optprefix,
    141                                       size_t *len,
    142                                       Error **errp)
    143{
    144    /* Fake LUKS creation in order to determine the payload size */
    145    g_autoptr(QCryptoBlock) crypto =
    146        qcrypto_block_create(create_opts, optprefix,
    147                             qcrypto_block_headerlen_hdr_init_func,
    148                             qcrypto_block_headerlen_hdr_write_func,
    149                             len, errp);
    150    return crypto != NULL;
    151}
    152
    153int qcrypto_block_amend_options(QCryptoBlock *block,
    154                                QCryptoBlockReadFunc readfunc,
    155                                QCryptoBlockWriteFunc writefunc,
    156                                void *opaque,
    157                                QCryptoBlockAmendOptions *options,
    158                                bool force,
    159                                Error **errp)
    160{
    161    if (options->format != block->format) {
    162        error_setg(errp,
    163                   "Cannot amend encryption format");
    164        return -1;
    165    }
    166
    167    if (!block->driver->amend) {
    168        error_setg(errp,
    169                   "Crypto format %s doesn't support format options amendment",
    170                   QCryptoBlockFormat_str(block->format));
    171        return -1;
    172    }
    173
    174    return block->driver->amend(block,
    175                                readfunc,
    176                                writefunc,
    177                                opaque,
    178                                options,
    179                                force,
    180                                errp);
    181}
    182
    183QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
    184                                         Error **errp)
    185{
    186    QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
    187
    188    info->format = block->format;
    189
    190    if (block->driver->get_info &&
    191        block->driver->get_info(block, info, errp) < 0) {
    192        g_free(info);
    193        return NULL;
    194    }
    195
    196    return info;
    197}
    198
    199
    200int qcrypto_block_decrypt(QCryptoBlock *block,
    201                          uint64_t offset,
    202                          uint8_t *buf,
    203                          size_t len,
    204                          Error **errp)
    205{
    206    return block->driver->decrypt(block, offset, buf, len, errp);
    207}
    208
    209
    210int qcrypto_block_encrypt(QCryptoBlock *block,
    211                          uint64_t offset,
    212                          uint8_t *buf,
    213                          size_t len,
    214                          Error **errp)
    215{
    216    return block->driver->encrypt(block, offset, buf, len, errp);
    217}
    218
    219
    220QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
    221{
    222    /* Ciphers should be accessed through pop/push method to be thread-safe.
    223     * Better, they should not be accessed externally at all (note, that
    224     * pop/push are static functions)
    225     * This function is used only in test with one thread (it's safe to skip
    226     * pop/push interface), so it's enough to assert it here:
    227     */
    228    assert(block->n_ciphers <= 1);
    229    return block->ciphers ? block->ciphers[0] : NULL;
    230}
    231
    232
    233static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
    234{
    235    QCryptoCipher *cipher;
    236
    237    qemu_mutex_lock(&block->mutex);
    238
    239    assert(block->n_free_ciphers > 0);
    240    block->n_free_ciphers--;
    241    cipher = block->ciphers[block->n_free_ciphers];
    242
    243    qemu_mutex_unlock(&block->mutex);
    244
    245    return cipher;
    246}
    247
    248
    249static void qcrypto_block_push_cipher(QCryptoBlock *block,
    250                                      QCryptoCipher *cipher)
    251{
    252    qemu_mutex_lock(&block->mutex);
    253
    254    assert(block->n_free_ciphers < block->n_ciphers);
    255    block->ciphers[block->n_free_ciphers] = cipher;
    256    block->n_free_ciphers++;
    257
    258    qemu_mutex_unlock(&block->mutex);
    259}
    260
    261
    262int qcrypto_block_init_cipher(QCryptoBlock *block,
    263                              QCryptoCipherAlgorithm alg,
    264                              QCryptoCipherMode mode,
    265                              const uint8_t *key, size_t nkey,
    266                              size_t n_threads, Error **errp)
    267{
    268    size_t i;
    269
    270    assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
    271
    272    block->ciphers = g_new0(QCryptoCipher *, n_threads);
    273
    274    for (i = 0; i < n_threads; i++) {
    275        block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
    276        if (!block->ciphers[i]) {
    277            qcrypto_block_free_cipher(block);
    278            return -1;
    279        }
    280        block->n_ciphers++;
    281        block->n_free_ciphers++;
    282    }
    283
    284    return 0;
    285}
    286
    287
    288void qcrypto_block_free_cipher(QCryptoBlock *block)
    289{
    290    size_t i;
    291
    292    if (!block->ciphers) {
    293        return;
    294    }
    295
    296    assert(block->n_ciphers == block->n_free_ciphers);
    297
    298    for (i = 0; i < block->n_ciphers; i++) {
    299        qcrypto_cipher_free(block->ciphers[i]);
    300    }
    301
    302    g_free(block->ciphers);
    303    block->ciphers = NULL;
    304    block->n_ciphers = block->n_free_ciphers = 0;
    305}
    306
    307QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
    308{
    309    /* ivgen should be accessed under mutex. However, this function is used only
    310     * in test with one thread, so it's enough to assert it here:
    311     */
    312    assert(block->n_ciphers <= 1);
    313    return block->ivgen;
    314}
    315
    316
    317QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
    318{
    319    return block->kdfhash;
    320}
    321
    322
    323uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
    324{
    325    return block->payload_offset;
    326}
    327
    328
    329uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
    330{
    331    return block->sector_size;
    332}
    333
    334
    335void qcrypto_block_free(QCryptoBlock *block)
    336{
    337    if (!block) {
    338        return;
    339    }
    340
    341    block->driver->cleanup(block);
    342
    343    qcrypto_block_free_cipher(block);
    344    qcrypto_ivgen_free(block->ivgen);
    345    qemu_mutex_destroy(&block->mutex);
    346    g_free(block);
    347}
    348
    349
    350typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
    351                                        const void *in,
    352                                        void *out,
    353                                        size_t len,
    354                                        Error **errp);
    355
    356static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
    357                                          size_t niv,
    358                                          QCryptoIVGen *ivgen,
    359                                          QemuMutex *ivgen_mutex,
    360                                          int sectorsize,
    361                                          uint64_t offset,
    362                                          uint8_t *buf,
    363                                          size_t len,
    364                                          QCryptoCipherEncDecFunc func,
    365                                          Error **errp)
    366{
    367    g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL;
    368    int ret = -1;
    369    uint64_t startsector = offset / sectorsize;
    370
    371    assert(QEMU_IS_ALIGNED(offset, sectorsize));
    372    assert(QEMU_IS_ALIGNED(len, sectorsize));
    373
    374    while (len > 0) {
    375        size_t nbytes;
    376        if (niv) {
    377            if (ivgen_mutex) {
    378                qemu_mutex_lock(ivgen_mutex);
    379            }
    380            ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
    381            if (ivgen_mutex) {
    382                qemu_mutex_unlock(ivgen_mutex);
    383            }
    384
    385            if (ret < 0) {
    386                return -1;
    387            }
    388
    389            if (qcrypto_cipher_setiv(cipher,
    390                                     iv, niv,
    391                                     errp) < 0) {
    392                return -1;
    393            }
    394        }
    395
    396        nbytes = len > sectorsize ? sectorsize : len;
    397        if (func(cipher, buf, buf, nbytes, errp) < 0) {
    398            return -1;
    399        }
    400
    401        startsector++;
    402        buf += nbytes;
    403        len -= nbytes;
    404    }
    405
    406    return 0;
    407}
    408
    409
    410int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
    411                                        size_t niv,
    412                                        QCryptoIVGen *ivgen,
    413                                        int sectorsize,
    414                                        uint64_t offset,
    415                                        uint8_t *buf,
    416                                        size_t len,
    417                                        Error **errp)
    418{
    419    return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
    420                                          offset, buf, len,
    421                                          qcrypto_cipher_decrypt, errp);
    422}
    423
    424
    425int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
    426                                        size_t niv,
    427                                        QCryptoIVGen *ivgen,
    428                                        int sectorsize,
    429                                        uint64_t offset,
    430                                        uint8_t *buf,
    431                                        size_t len,
    432                                        Error **errp)
    433{
    434    return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
    435                                          offset, buf, len,
    436                                          qcrypto_cipher_encrypt, errp);
    437}
    438
    439int qcrypto_block_decrypt_helper(QCryptoBlock *block,
    440                                 int sectorsize,
    441                                 uint64_t offset,
    442                                 uint8_t *buf,
    443                                 size_t len,
    444                                 Error **errp)
    445{
    446    int ret;
    447    QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
    448
    449    ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
    450                                         &block->mutex, sectorsize, offset, buf,
    451                                         len, qcrypto_cipher_decrypt, errp);
    452
    453    qcrypto_block_push_cipher(block, cipher);
    454
    455    return ret;
    456}
    457
    458int qcrypto_block_encrypt_helper(QCryptoBlock *block,
    459                                 int sectorsize,
    460                                 uint64_t offset,
    461                                 uint8_t *buf,
    462                                 size_t len,
    463                                 Error **errp)
    464{
    465    int ret;
    466    QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
    467
    468    ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
    469                                         &block->mutex, sectorsize, offset, buf,
    470                                         len, qcrypto_cipher_encrypt, errp);
    471
    472    qcrypto_block_push_cipher(block, cipher);
    473
    474    return ret;
    475}