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

tpm-util.c (8900B)


      1/*
      2 * QTest TPM utilities
      3 *
      4 * Copyright (c) 2018 IBM Corporation
      5 * Copyright (c) 2018 Red Hat, Inc.
      6 *
      7 * Authors:
      8 *   Stefan Berger <stefanb@linux.vnet.ibm.com>
      9 *   Marc-André Lureau <marcandre.lureau@redhat.com>
     10 *
     11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     12 * See the COPYING file in the top-level directory.
     13 */
     14
     15#include "qemu/osdep.h"
     16
     17#include "hw/acpi/tpm.h"
     18#include "libqos/libqtest.h"
     19#include "tpm-util.h"
     20#include "qapi/qmp/qdict.h"
     21
     22void tpm_util_crb_transfer(QTestState *s,
     23                           const unsigned char *req, size_t req_size,
     24                           unsigned char *rsp, size_t rsp_size)
     25{
     26    uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
     27    uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
     28
     29    qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
     30
     31    qtest_memwrite(s, caddr, req, req_size);
     32
     33    uint32_t sts, start = 1;
     34    uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
     35    qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
     36    while (true) {
     37        start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
     38        if ((start & 1) == 0) {
     39            break;
     40        }
     41        if (g_get_monotonic_time() >= end_time) {
     42            break;
     43        }
     44    };
     45    start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
     46    g_assert_cmpint(start & 1, ==, 0);
     47    sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
     48    g_assert_cmpint(sts & 1, ==, 0);
     49
     50    qtest_memread(s, raddr, rsp, rsp_size);
     51}
     52
     53void tpm_util_tis_transfer(QTestState *s,
     54                           const unsigned char *req, size_t req_size,
     55                           unsigned char *rsp, size_t rsp_size)
     56{
     57    uint32_t sts;
     58    uint16_t bcount;
     59    size_t i;
     60
     61    /* request use of locality 0 */
     62    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
     63    qtest_writel(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
     64
     65    sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
     66    bcount = (sts >> 8) & 0xffff;
     67    g_assert_cmpint(bcount, >=, req_size);
     68
     69    /* transmit command */
     70    for (i = 0; i < req_size; i++) {
     71        qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO), req[i]);
     72    }
     73
     74    /* start processing */
     75    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
     76
     77    uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
     78    do {
     79        sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
     80        if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
     81            break;
     82        }
     83    } while (g_get_monotonic_time() < end_time);
     84
     85    sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
     86    bcount = (sts >> 8) & 0xffff;
     87
     88    memset(rsp, 0, rsp_size);
     89    for (i = 0; i < bcount; i++) {
     90        rsp[i] = qtest_readb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
     91    }
     92
     93    /* relinquish use of locality 0 */
     94    qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS),
     95                 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
     96}
     97
     98void tpm_util_startup(QTestState *s, tx_func *tx)
     99{
    100    unsigned char buffer[1024];
    101    static const unsigned char tpm_startup[] =
    102        "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
    103    static const unsigned char tpm_startup_resp[] =
    104        "\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
    105
    106    tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
    107
    108    g_assert_cmpmem(buffer, sizeof(tpm_startup_resp),
    109                    tpm_startup_resp, sizeof(tpm_startup_resp));
    110}
    111
    112void tpm_util_pcrextend(QTestState *s, tx_func *tx)
    113{
    114    unsigned char buffer[1024];
    115    static const unsigned char tpm_pcrextend[] =
    116        "\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
    117        "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
    118        "\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    119        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    120        "\x00";
    121
    122    static const unsigned char tpm_pcrextend_resp[] =
    123        "\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    124        "\x01\x00\x00";
    125
    126    tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
    127
    128    g_assert_cmpmem(buffer, sizeof(tpm_pcrextend_resp),
    129                    tpm_pcrextend_resp, sizeof(tpm_pcrextend_resp));
    130}
    131
    132void tpm_util_pcrread(QTestState *s, tx_func *tx,
    133                      const unsigned char *exp_resp, size_t exp_resp_size)
    134{
    135    unsigned char buffer[1024];
    136    static const unsigned char tpm_pcrread[] =
    137        "\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
    138        "\x03\x00\x04\x00";
    139
    140    tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
    141
    142    /* skip pcrUpdateCounter (14th byte) in comparison */
    143    g_assert(exp_resp_size >= 15);
    144    g_assert_cmpmem(buffer, 13, exp_resp, 13);
    145    g_assert_cmpmem(&buffer[14], exp_resp_size - 14,
    146                    &exp_resp[14], exp_resp_size - 14);
    147}
    148
    149bool tpm_util_swtpm_has_tpm2(void)
    150{
    151    bool has_tpm2 = false;
    152    char *out = NULL;
    153    static const char *argv[] = {
    154        "swtpm", "socket", "--help", NULL
    155    };
    156
    157    if (!g_spawn_sync(NULL /* working_dir */,
    158                      (char **)argv,
    159                      NULL /* envp */,
    160                      G_SPAWN_SEARCH_PATH,
    161                      NULL /* child_setup */,
    162                      NULL /* user_data */,
    163                      &out,
    164                      NULL /* err */,
    165                      NULL /* exit_status */,
    166                      NULL)) {
    167        return false;
    168    }
    169
    170    if (strstr(out, "--tpm2")) {
    171        has_tpm2 = true;
    172    }
    173
    174    g_free(out);
    175    return has_tpm2;
    176}
    177
    178gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
    179                              SocketAddress **addr, GError **error)
    180{
    181    char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
    182    char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
    183                                            path);
    184    gchar *swtpm_argv[] = {
    185        g_strdup("swtpm"), g_strdup("socket"),
    186        g_strdup("--tpmstate"), swtpm_argv_tpmstate,
    187        g_strdup("--ctrl"), swtpm_argv_ctrl,
    188        g_strdup("--tpm2"),
    189        NULL
    190    };
    191    gboolean succ;
    192    unsigned i;
    193
    194    *addr = g_new0(SocketAddress, 1);
    195    (*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
    196    (*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
    197
    198    succ = g_spawn_async(NULL, swtpm_argv, NULL, G_SPAWN_SEARCH_PATH,
    199                         NULL, NULL, pid, error);
    200
    201    for (i = 0; swtpm_argv[i]; i++) {
    202        g_free(swtpm_argv[i]);
    203    }
    204
    205    return succ;
    206}
    207
    208void tpm_util_swtpm_kill(GPid pid)
    209{
    210    int n;
    211
    212    if (!pid) {
    213        return;
    214    }
    215
    216    g_spawn_close_pid(pid);
    217
    218    n = kill(pid, 0);
    219    if (n < 0) {
    220        return;
    221    }
    222
    223    kill(pid, SIGKILL);
    224}
    225
    226void tpm_util_migrate(QTestState *who, const char *uri)
    227{
    228    QDict *rsp;
    229
    230    rsp = qtest_qmp(who,
    231                    "{ 'execute': 'migrate', 'arguments': { 'uri': %s } }",
    232                    uri);
    233    g_assert(qdict_haskey(rsp, "return"));
    234    qobject_unref(rsp);
    235}
    236
    237void tpm_util_wait_for_migration_complete(QTestState *who)
    238{
    239    while (true) {
    240        QDict *rsp;
    241        QDict *rsp_return;
    242        bool completed;
    243        const char *status;
    244
    245        rsp = qtest_qmp(who, "{ 'execute': 'query-migrate' }");
    246        g_assert(qdict_haskey(rsp, "return"));
    247        rsp_return = qdict_get_qdict(rsp, "return");
    248
    249        g_assert(!qdict_haskey(rsp_return, "error"));
    250        status = qdict_get_str(rsp_return, "status");
    251        completed = strcmp(status, "completed") == 0;
    252        g_assert_cmpstr(status, !=,  "failed");
    253        qobject_unref(rsp);
    254        if (completed) {
    255            return;
    256        }
    257        usleep(1000);
    258    }
    259}
    260
    261void tpm_util_migration_start_qemu(QTestState **src_qemu,
    262                                   QTestState **dst_qemu,
    263                                   SocketAddress *src_tpm_addr,
    264                                   SocketAddress *dst_tpm_addr,
    265                                   const char *miguri,
    266                                   const char *ifmodel,
    267                                   const char *machine_options)
    268{
    269    char *src_qemu_args, *dst_qemu_args;
    270
    271    src_qemu_args = g_strdup_printf(
    272        "%s "
    273        "-chardev socket,id=chr,path=%s "
    274        "-tpmdev emulator,id=dev,chardev=chr "
    275        "-device %s,tpmdev=dev ",
    276        machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel);
    277
    278    *src_qemu = qtest_init(src_qemu_args);
    279
    280    dst_qemu_args = g_strdup_printf(
    281        "%s "
    282        "-chardev socket,id=chr,path=%s "
    283        "-tpmdev emulator,id=dev,chardev=chr "
    284        "-device %s,tpmdev=dev "
    285        "-incoming %s",
    286        machine_options ? : "",
    287        dst_tpm_addr->u.q_unix.path,
    288        ifmodel, miguri);
    289
    290    *dst_qemu = qtest_init(dst_qemu_args);
    291
    292    g_free(src_qemu_args);
    293    g_free(dst_qemu_args);
    294}