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

announce.c (5921B)


      1/*
      2 *  Self-announce
      3 *  (c) 2017-2019 Red Hat, Inc.
      4 *
      5 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      6 * See the COPYING file in the top-level directory.
      7 */
      8
      9#include "qemu/osdep.h"
     10#include "qemu-common.h"
     11#include "net/announce.h"
     12#include "net/net.h"
     13#include "qapi/clone-visitor.h"
     14#include "qapi/qapi-visit-net.h"
     15#include "qapi/qapi-commands-net.h"
     16#include "trace.h"
     17
     18static GData *named_timers;
     19
     20int64_t qemu_announce_timer_step(AnnounceTimer *timer)
     21{
     22    int64_t step;
     23
     24    step =  timer->params.initial +
     25            (timer->params.rounds - timer->round - 1) *
     26            timer->params.step;
     27
     28    if (step < 0 || step > timer->params.max) {
     29        step = timer->params.max;
     30    }
     31    timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step);
     32
     33    return step;
     34}
     35
     36/*
     37 * If 'free_named' is true, then remove the timer from the list
     38 * and free the timer itself.
     39 */
     40void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named)
     41{
     42    bool free_timer = false;
     43    if (timer->tm) {
     44        timer_free(timer->tm);
     45        timer->tm = NULL;
     46    }
     47    qapi_free_strList(timer->params.interfaces);
     48    timer->params.interfaces = NULL;
     49    if (free_named && timer->params.has_id) {
     50        AnnounceTimer *list_timer;
     51        /*
     52         * Sanity check: There should only be one timer on the list with
     53         * the id.
     54         */
     55        list_timer = g_datalist_get_data(&named_timers, timer->params.id);
     56        assert(timer == list_timer);
     57        free_timer = true;
     58        g_datalist_remove_data(&named_timers, timer->params.id);
     59    }
     60    trace_qemu_announce_timer_del(free_named, free_timer, timer->params.id);
     61    g_free(timer->params.id);
     62    timer->params.id = NULL;
     63
     64    if (free_timer) {
     65        g_free(timer);
     66    }
     67}
     68
     69/*
     70 * Under BQL/main thread
     71 * Reset the timer to the given parameters/type/notifier.
     72 */
     73void qemu_announce_timer_reset(AnnounceTimer *timer,
     74                               AnnounceParameters *params,
     75                               QEMUClockType type,
     76                               QEMUTimerCB *cb,
     77                               void *opaque)
     78{
     79    /*
     80     * We're under the BQL, so the current timer can't
     81     * be firing, so we should be able to delete it.
     82     */
     83    qemu_announce_timer_del(timer, false);
     84
     85    QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
     86    timer->round = params->rounds;
     87    timer->type = type;
     88    timer->tm = timer_new_ms(type, cb, opaque);
     89}
     90
     91#ifndef ETH_P_RARP
     92#define ETH_P_RARP 0x8035
     93#endif
     94#define ARP_HTYPE_ETH 0x0001
     95#define ARP_PTYPE_IP 0x0800
     96#define ARP_OP_REQUEST_REV 0x3
     97
     98static int announce_self_create(uint8_t *buf,
     99                                uint8_t *mac_addr)
    100{
    101    /* Ethernet header. */
    102    memset(buf, 0xff, 6);         /* destination MAC addr */
    103    memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
    104    *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
    105
    106    /* RARP header. */
    107    *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
    108    *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
    109    *(buf + 18) = 6; /* hardware addr length (ethernet) */
    110    *(buf + 19) = 4; /* protocol addr length (IPv4) */
    111    *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
    112    memcpy(buf + 22, mac_addr, 6); /* source hw addr */
    113    memset(buf + 28, 0x00, 4);     /* source protocol addr */
    114    memcpy(buf + 32, mac_addr, 6); /* target hw addr */
    115    memset(buf + 38, 0x00, 4);     /* target protocol addr */
    116
    117    /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
    118    memset(buf + 42, 0x00, 18);
    119
    120    return 60; /* len (FCS will be added by hardware) */
    121}
    122
    123static void qemu_announce_self_iter(NICState *nic, void *opaque)
    124{
    125    AnnounceTimer *timer = opaque;
    126    uint8_t buf[60];
    127    int len;
    128    bool skip;
    129
    130    if (timer->params.has_interfaces) {
    131        strList *entry = timer->params.interfaces;
    132        /* Skip unless we find our name in the requested list */
    133        skip = true;
    134
    135        while (entry) {
    136            if (!strcmp(entry->value, nic->ncs->name)) {
    137                /* Found us */
    138                skip = false;
    139                break;
    140            }
    141            entry = entry->next;
    142        }
    143    } else {
    144        skip = false;
    145    }
    146
    147    trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_",
    148                                  nic->ncs->name,
    149                                  qemu_ether_ntoa(&nic->conf->macaddr), skip);
    150
    151    if (!skip) {
    152        len = announce_self_create(buf, nic->conf->macaddr.a);
    153
    154        qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
    155
    156        /* if the NIC provides it's own announcement support, use it as well */
    157        if (nic->ncs->info->announce) {
    158            nic->ncs->info->announce(nic->ncs);
    159        }
    160    }
    161}
    162static void qemu_announce_self_once(void *opaque)
    163{
    164    AnnounceTimer *timer = (AnnounceTimer *)opaque;
    165
    166    qemu_foreach_nic(qemu_announce_self_iter, timer);
    167
    168    if (--timer->round) {
    169        qemu_announce_timer_step(timer);
    170    } else {
    171        qemu_announce_timer_del(timer, true);
    172    }
    173}
    174
    175void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
    176{
    177    qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
    178                              qemu_announce_self_once, timer);
    179    if (params->rounds) {
    180        qemu_announce_self_once(timer);
    181    } else {
    182        qemu_announce_timer_del(timer, true);
    183    }
    184}
    185
    186void qmp_announce_self(AnnounceParameters *params, Error **errp)
    187{
    188    AnnounceTimer *named_timer;
    189    if (!params->has_id) {
    190        params->id = g_strdup("");
    191        params->has_id = true;
    192    }
    193
    194    named_timer = g_datalist_get_data(&named_timers, params->id);
    195
    196    if (!named_timer) {
    197        named_timer = g_new0(AnnounceTimer, 1);
    198        g_datalist_set_data(&named_timers, params->id, named_timer);
    199    }
    200
    201    qemu_announce_self(named_timer, params);
    202}