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

loader.c (12316B)


      1/*
      2 * QEMU Plugin Core Loader Code
      3 *
      4 * This is the code responsible for loading and unloading the plugins.
      5 * Aside from the basic housekeeping tasks we also need to ensure any
      6 * generated code is flushed when we remove a plugin so we cannot end
      7 * up calling and unloaded helper function.
      8 *
      9 * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
     10 * Copyright (C) 2019, Linaro
     11 *
     12 * License: GNU GPL, version 2 or later.
     13 *   See the COPYING file in the top-level directory.
     14 *
     15 * SPDX-License-Identifier: GPL-2.0-or-later
     16 */
     17
     18#include "qemu/osdep.h"
     19#include "qemu/error-report.h"
     20#include "qemu/config-file.h"
     21#include "qapi/error.h"
     22#include "qemu/lockable.h"
     23#include "qemu/option.h"
     24#include "qemu/rcu_queue.h"
     25#include "qemu/qht.h"
     26#include "qemu/bitmap.h"
     27#include "qemu/xxhash.h"
     28#include "qemu/plugin.h"
     29#include "hw/core/cpu.h"
     30#include "exec/exec-all.h"
     31#ifndef CONFIG_USER_ONLY
     32#include "hw/boards.h"
     33#endif
     34#include "qemu/compiler.h"
     35
     36#include "plugin.h"
     37
     38/*
     39 * For convenience we use a bitmap for plugin.mask, but really all we need is a
     40 * u32, which is what we store in TranslationBlock.
     41 */
     42QEMU_BUILD_BUG_ON(QEMU_PLUGIN_EV_MAX > 32);
     43
     44struct qemu_plugin_desc {
     45    char *path;
     46    char **argv;
     47    QTAILQ_ENTRY(qemu_plugin_desc) entry;
     48    int argc;
     49};
     50
     51struct qemu_plugin_parse_arg {
     52    QemuPluginList *head;
     53    struct qemu_plugin_desc *curr;
     54};
     55
     56QemuOptsList qemu_plugin_opts = {
     57    .name = "plugin",
     58    .implied_opt_name = "file",
     59    .head = QTAILQ_HEAD_INITIALIZER(qemu_plugin_opts.head),
     60    .desc = {
     61        /* do our own parsing to support multiple plugins */
     62        { /* end of list */ }
     63    },
     64};
     65
     66typedef int (*qemu_plugin_install_func_t)(qemu_plugin_id_t, const qemu_info_t *, int, char **);
     67
     68extern struct qemu_plugin_state plugin;
     69
     70void qemu_plugin_add_dyn_cb_arr(GArray *arr)
     71{
     72    uint32_t hash = qemu_xxhash2((uint64_t)(uintptr_t)arr);
     73    bool inserted;
     74
     75    inserted = qht_insert(&plugin.dyn_cb_arr_ht, arr, hash, NULL);
     76    g_assert(inserted);
     77}
     78
     79static struct qemu_plugin_desc *plugin_find_desc(QemuPluginList *head,
     80                                                 const char *path)
     81{
     82    struct qemu_plugin_desc *desc;
     83
     84    QTAILQ_FOREACH(desc, head, entry) {
     85        if (strcmp(desc->path, path) == 0) {
     86            return desc;
     87        }
     88    }
     89    return NULL;
     90}
     91
     92static int plugin_add(void *opaque, const char *name, const char *value,
     93                      Error **errp)
     94{
     95    struct qemu_plugin_parse_arg *arg = opaque;
     96    struct qemu_plugin_desc *p;
     97    bool is_on;
     98    char *fullarg;
     99
    100    if (strcmp(name, "file") == 0) {
    101        if (strcmp(value, "") == 0) {
    102            error_setg(errp, "requires a non-empty argument");
    103            return 1;
    104        }
    105        p = plugin_find_desc(arg->head, value);
    106        if (p == NULL) {
    107            p = g_new0(struct qemu_plugin_desc, 1);
    108            p->path = g_strdup(value);
    109            QTAILQ_INSERT_TAIL(arg->head, p, entry);
    110        }
    111        arg->curr = p;
    112    } else {
    113        if (arg->curr == NULL) {
    114            error_setg(errp, "missing earlier '-plugin file=' option");
    115            return 1;
    116        }
    117
    118        if (g_strcmp0(name, "arg") == 0 &&
    119                !qapi_bool_parse(name, value, &is_on, NULL)) {
    120            if (strchr(value, '=') == NULL) {
    121                /* Will treat arg="argname" as "argname=on" */
    122                fullarg = g_strdup_printf("%s=%s", value, "on");
    123            } else {
    124                fullarg = g_strdup_printf("%s", value);
    125            }
    126            warn_report("using 'arg=%s' is deprecated", value);
    127            error_printf("Please use '%s' directly\n", fullarg);
    128        } else {
    129            fullarg = g_strdup_printf("%s=%s", name, value);
    130        }
    131
    132        p = arg->curr;
    133        p->argc++;
    134        p->argv = g_realloc_n(p->argv, p->argc, sizeof(char *));
    135        p->argv[p->argc - 1] = fullarg;
    136    }
    137
    138    return 0;
    139}
    140
    141void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head)
    142{
    143    struct qemu_plugin_parse_arg arg;
    144    QemuOpts *opts;
    145
    146    opts = qemu_opts_parse_noisily(qemu_find_opts("plugin"), optarg, true);
    147    if (opts == NULL) {
    148        exit(1);
    149    }
    150    arg.head = head;
    151    arg.curr = NULL;
    152    qemu_opt_foreach(opts, plugin_add, &arg, &error_fatal);
    153    qemu_opts_del(opts);
    154}
    155
    156/*
    157 * From: https://en.wikipedia.org/wiki/Xorshift
    158 * This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
    159 * guaranteed to be >= INT_MAX).
    160 */
    161static uint64_t xorshift64star(uint64_t x)
    162{
    163    x ^= x >> 12; /* a */
    164    x ^= x << 25; /* b */
    165    x ^= x >> 27; /* c */
    166    return x * UINT64_C(2685821657736338717);
    167}
    168
    169/*
    170 * Disable CFI checks.
    171 * The install and version functions have been loaded from an external library
    172 * so we do not have type information
    173 */
    174QEMU_DISABLE_CFI
    175static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info, Error **errp)
    176{
    177    qemu_plugin_install_func_t install;
    178    struct qemu_plugin_ctx *ctx;
    179    gpointer sym;
    180    int rc;
    181
    182    ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));
    183    memset(ctx, 0, sizeof(*ctx));
    184    ctx->desc = desc;
    185
    186    ctx->handle = g_module_open(desc->path, G_MODULE_BIND_LOCAL);
    187    if (ctx->handle == NULL) {
    188        error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error());
    189        goto err_dlopen;
    190    }
    191
    192    if (!g_module_symbol(ctx->handle, "qemu_plugin_install", &sym)) {
    193        error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error());
    194        goto err_symbol;
    195    }
    196    install = (qemu_plugin_install_func_t) sym;
    197    /* symbol was found; it could be NULL though */
    198    if (install == NULL) {
    199        error_setg(errp, "Could not load plugin %s: qemu_plugin_install is NULL",
    200                   desc->path);
    201        goto err_symbol;
    202    }
    203
    204    if (!g_module_symbol(ctx->handle, "qemu_plugin_version", &sym)) {
    205        error_setg(errp, "Could not load plugin %s: plugin does not declare API version %s",
    206                   desc->path, g_module_error());
    207        goto err_symbol;
    208    } else {
    209        int version = *(int *)sym;
    210        if (version < QEMU_PLUGIN_MIN_VERSION) {
    211            error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but "
    212                       "this QEMU supports only a minimum version of %d",
    213                       desc->path, version, QEMU_PLUGIN_MIN_VERSION);
    214            goto err_symbol;
    215        } else if (version > QEMU_PLUGIN_VERSION) {
    216            error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but "
    217                       "this QEMU supports only up to version %d",
    218                       desc->path, version, QEMU_PLUGIN_VERSION);
    219            goto err_symbol;
    220        }
    221    }
    222
    223    qemu_rec_mutex_lock(&plugin.lock);
    224
    225    /* find an unused random id with &ctx as the seed */
    226    ctx->id = (uint64_t)(uintptr_t)ctx;
    227    for (;;) {
    228        void *existing;
    229
    230        ctx->id = xorshift64star(ctx->id);
    231        existing = g_hash_table_lookup(plugin.id_ht, &ctx->id);
    232        if (likely(existing == NULL)) {
    233            bool success;
    234
    235            success = g_hash_table_insert(plugin.id_ht, &ctx->id, &ctx->id);
    236            g_assert(success);
    237            break;
    238        }
    239    }
    240    QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry);
    241    ctx->installing = true;
    242    rc = install(ctx->id, info, desc->argc, desc->argv);
    243    ctx->installing = false;
    244    if (rc) {
    245        error_setg(errp, "Could not load plugin %s: qemu_plugin_install returned error code %d",
    246                   desc->path, rc);
    247        /*
    248         * we cannot rely on the plugin doing its own cleanup, so
    249         * call a full uninstall if the plugin did not yet call it.
    250         */
    251        if (!ctx->uninstalling) {
    252            plugin_reset_uninstall(ctx->id, NULL, false);
    253        }
    254    }
    255
    256    qemu_rec_mutex_unlock(&plugin.lock);
    257    return rc;
    258
    259 err_symbol:
    260    g_module_close(ctx->handle);
    261 err_dlopen:
    262    qemu_vfree(ctx);
    263    return 1;
    264}
    265
    266/* call after having removed @desc from the list */
    267static void plugin_desc_free(struct qemu_plugin_desc *desc)
    268{
    269    int i;
    270
    271    for (i = 0; i < desc->argc; i++) {
    272        g_free(desc->argv[i]);
    273    }
    274    g_free(desc->argv);
    275    g_free(desc->path);
    276    g_free(desc);
    277}
    278
    279/**
    280 * qemu_plugin_load_list - load a list of plugins
    281 * @head: head of the list of descriptors of the plugins to be loaded
    282 *
    283 * Returns 0 if all plugins in the list are installed, !0 otherwise.
    284 *
    285 * Note: the descriptor of each successfully installed plugin is removed
    286 * from the list given by @head.
    287 */
    288int qemu_plugin_load_list(QemuPluginList *head, Error **errp)
    289{
    290    struct qemu_plugin_desc *desc, *next;
    291    g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1);
    292
    293    info->target_name = TARGET_NAME;
    294    info->version.min = QEMU_PLUGIN_MIN_VERSION;
    295    info->version.cur = QEMU_PLUGIN_VERSION;
    296#ifndef CONFIG_USER_ONLY
    297    MachineState *ms = MACHINE(qdev_get_machine());
    298    info->system_emulation = true;
    299    info->system.smp_vcpus = ms->smp.cpus;
    300    info->system.max_vcpus = ms->smp.max_cpus;
    301#else
    302    info->system_emulation = false;
    303#endif
    304
    305    QTAILQ_FOREACH_SAFE(desc, head, entry, next) {
    306        int err;
    307
    308        err = plugin_load(desc, info, errp);
    309        if (err) {
    310            return err;
    311        }
    312        QTAILQ_REMOVE(head, desc, entry);
    313    }
    314    return 0;
    315}
    316
    317struct qemu_plugin_reset_data {
    318    struct qemu_plugin_ctx *ctx;
    319    qemu_plugin_simple_cb_t cb;
    320    bool reset;
    321};
    322
    323static void plugin_reset_destroy__locked(struct qemu_plugin_reset_data *data)
    324{
    325    struct qemu_plugin_ctx *ctx = data->ctx;
    326    enum qemu_plugin_event ev;
    327    bool success;
    328
    329    /*
    330     * After updating the subscription lists there is no need to wait for an RCU
    331     * grace period to elapse, because right now we either are in a "safe async"
    332     * work environment (i.e. all vCPUs are asleep), or no vCPUs have yet been
    333     * created.
    334     */
    335    for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) {
    336        plugin_unregister_cb__locked(ctx, ev);
    337    }
    338
    339    if (data->reset) {
    340        g_assert(ctx->resetting);
    341        if (data->cb) {
    342            data->cb(ctx->id);
    343        }
    344        ctx->resetting = false;
    345        g_free(data);
    346        return;
    347    }
    348
    349    g_assert(ctx->uninstalling);
    350    /* we cannot dlclose if we are going to return to plugin code */
    351    if (ctx->installing) {
    352        error_report("Calling qemu_plugin_uninstall from the install function "
    353                     "is a bug. Instead, return !0 from the install function.");
    354        abort();
    355    }
    356
    357    success = g_hash_table_remove(plugin.id_ht, &ctx->id);
    358    g_assert(success);
    359    QTAILQ_REMOVE(&plugin.ctxs, ctx, entry);
    360    if (data->cb) {
    361        data->cb(ctx->id);
    362    }
    363    if (!g_module_close(ctx->handle)) {
    364        warn_report("%s: %s", __func__, g_module_error());
    365    }
    366    plugin_desc_free(ctx->desc);
    367    qemu_vfree(ctx);
    368    g_free(data);
    369}
    370
    371static void plugin_reset_destroy(struct qemu_plugin_reset_data *data)
    372{
    373    qemu_rec_mutex_lock(&plugin.lock);
    374    plugin_reset_destroy__locked(data);
    375    qemu_rec_mutex_lock(&plugin.lock);
    376}
    377
    378static void plugin_flush_destroy(CPUState *cpu, run_on_cpu_data arg)
    379{
    380    struct qemu_plugin_reset_data *data = arg.host_ptr;
    381
    382    g_assert(cpu_in_exclusive_context(cpu));
    383    tb_flush(cpu);
    384    plugin_reset_destroy(data);
    385}
    386
    387void plugin_reset_uninstall(qemu_plugin_id_t id,
    388                            qemu_plugin_simple_cb_t cb,
    389                            bool reset)
    390{
    391    struct qemu_plugin_reset_data *data;
    392    struct qemu_plugin_ctx *ctx;
    393
    394    WITH_QEMU_LOCK_GUARD(&plugin.lock) {
    395        ctx = plugin_id_to_ctx_locked(id);
    396        if (ctx->uninstalling || (reset && ctx->resetting)) {
    397            return;
    398        }
    399        ctx->resetting = reset;
    400        ctx->uninstalling = !reset;
    401    }
    402
    403    data = g_new(struct qemu_plugin_reset_data, 1);
    404    data->ctx = ctx;
    405    data->cb = cb;
    406    data->reset = reset;
    407    /*
    408     * Only flush the code cache if the vCPUs have been created. If so,
    409     * current_cpu must be non-NULL.
    410     */
    411    if (current_cpu) {
    412        async_safe_run_on_cpu(current_cpu, plugin_flush_destroy,
    413                              RUN_ON_CPU_HOST_PTR(data));
    414    } else {
    415        /*
    416         * If current_cpu isn't set, then we don't have yet any vCPU threads
    417         * and we therefore can remove the callbacks synchronously.
    418         */
    419        plugin_reset_destroy(data);
    420    }
    421}