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

channel-win32.c (10334B)


      1#include "qemu/osdep.h"
      2#include <windows.h>
      3#include <io.h>
      4#include "guest-agent-core.h"
      5#include "channel.h"
      6
      7typedef struct GAChannelReadState {
      8    guint thread_id;
      9    uint8_t *buf;
     10    size_t buf_size;
     11    size_t cur; /* current buffer start */
     12    size_t pending; /* pending buffered bytes to read */
     13    OVERLAPPED ov;
     14    bool ov_pending; /* whether on async read is outstanding */
     15} GAChannelReadState;
     16
     17struct GAChannel {
     18    HANDLE handle;
     19    GAChannelCallback cb;
     20    gpointer user_data;
     21    GAChannelReadState rstate;
     22    GIOCondition pending_events; /* TODO: use GAWatch.pollfd.revents */
     23    GSource *source;
     24};
     25
     26typedef struct GAWatch {
     27    GSource source;
     28    GPollFD pollfd;
     29    GAChannel *channel;
     30    GIOCondition events_mask;
     31} GAWatch;
     32
     33/*
     34 * Called by glib prior to polling to set up poll events if polling is needed.
     35 *
     36 */
     37static gboolean ga_channel_prepare(GSource *source, gint *timeout_ms)
     38{
     39    GAWatch *watch = (GAWatch *)source;
     40    GAChannel *c = (GAChannel *)watch->channel;
     41    GAChannelReadState *rs = &c->rstate;
     42    DWORD count_read, count_to_read = 0;
     43    bool success;
     44    GIOCondition new_events = 0;
     45
     46    g_debug("prepare");
     47    /* go ahead and submit another read if there's room in the buffer
     48     * and no previous reads are outstanding
     49     */
     50    if (!rs->ov_pending) {
     51        if (rs->cur + rs->pending >= rs->buf_size) {
     52            if (rs->cur) {
     53                memmove(rs->buf, rs->buf + rs->cur, rs->pending);
     54                rs->cur = 0;
     55            }
     56        }
     57        count_to_read = rs->buf_size - rs->cur - rs->pending;
     58    }
     59
     60    if (rs->ov_pending || count_to_read <= 0) {
     61            goto out;
     62    }
     63
     64    /* submit the read */
     65    success = ReadFile(c->handle, rs->buf + rs->cur + rs->pending,
     66                       count_to_read, &count_read, &rs->ov);
     67    if (success) {
     68        rs->pending += count_read;
     69        rs->ov_pending = false;
     70    } else {
     71        if (GetLastError() == ERROR_IO_PENDING) {
     72            rs->ov_pending = true;
     73        } else {
     74            new_events |= G_IO_ERR;
     75        }
     76    }
     77
     78out:
     79    /* don't block forever, iterate the main loop every once in a while */
     80    *timeout_ms = 500;
     81    /* if there's data in the read buffer, or another event is pending,
     82     * skip polling and issue user cb.
     83     */
     84    if (rs->pending) {
     85        new_events |= G_IO_IN;
     86    }
     87    c->pending_events |= new_events;
     88    return !!c->pending_events;
     89}
     90
     91/*
     92 * Called by glib after an outstanding read request is completed.
     93 */
     94static gboolean ga_channel_check(GSource *source)
     95{
     96    GAWatch *watch = (GAWatch *)source;
     97    GAChannel *c = (GAChannel *)watch->channel;
     98    GAChannelReadState *rs = &c->rstate;
     99    DWORD count_read, error;
    100    BOOL success;
    101
    102    GIOCondition new_events = 0;
    103
    104    g_debug("check");
    105
    106    /* failing this implies we issued a read that completed immediately,
    107     * yet no data was placed into the buffer (and thus we did not skip
    108     * polling). but since EOF is not obtainable until we retrieve an
    109     * overlapped result, it must be the case that there was data placed
    110     * into the buffer, or an error was generated by Readfile(). in either
    111     * case, we should've skipped the polling for this round.
    112     */
    113    g_assert(rs->ov_pending);
    114
    115    success = GetOverlappedResult(c->handle, &rs->ov, &count_read, FALSE);
    116    if (success) {
    117        g_debug("thread: overlapped result, count_read: %d", (int)count_read);
    118        rs->pending += count_read;
    119        new_events |= G_IO_IN;
    120    } else {
    121        error = GetLastError();
    122        if (error == 0 || error == ERROR_HANDLE_EOF ||
    123            error == ERROR_NO_SYSTEM_RESOURCES ||
    124            error == ERROR_OPERATION_ABORTED) {
    125            /* note: On WinXP SP3 with rhel6ga virtio-win-1.1.16 vioser drivers,
    126             * ENSR seems to be synonymous with when we'd normally expect
    127             * ERROR_HANDLE_EOF. So treat it as such. Microsoft's
    128             * recommendation for ERROR_NO_SYSTEM_RESOURCES is to
    129             * retry the read, so this happens to work out anyway. On newer
    130             * virtio-win driver, this seems to be replaced with EOA, so
    131             * handle that in the same fashion.
    132             */
    133            new_events |= G_IO_HUP;
    134        } else if (error != ERROR_IO_INCOMPLETE) {
    135            g_critical("error retrieving overlapped result: %d", (int)error);
    136            new_events |= G_IO_ERR;
    137        }
    138    }
    139
    140    if (new_events) {
    141        rs->ov_pending = 0;
    142    }
    143    c->pending_events |= new_events;
    144
    145    return !!c->pending_events;
    146}
    147
    148/*
    149 * Called by glib after either prepare or check routines signal readiness
    150 */
    151static gboolean ga_channel_dispatch(GSource *source, GSourceFunc unused,
    152                                    gpointer user_data)
    153{
    154    GAWatch *watch = (GAWatch *)source;
    155    GAChannel *c = (GAChannel *)watch->channel;
    156    GAChannelReadState *rs = &c->rstate;
    157    gboolean success;
    158
    159    g_debug("dispatch");
    160    success = c->cb(watch->pollfd.revents, c->user_data);
    161
    162    if (c->pending_events & G_IO_ERR) {
    163        g_critical("channel error, removing source");
    164        return false;
    165    }
    166
    167    /* TODO: replace rs->pending with watch->revents */
    168    c->pending_events &= ~G_IO_HUP;
    169    if (!rs->pending) {
    170        c->pending_events &= ~G_IO_IN;
    171    } else {
    172        c->pending_events = 0;
    173    }
    174    return success;
    175}
    176
    177static void ga_channel_finalize(GSource *source)
    178{
    179    g_debug("finalize");
    180}
    181
    182GSourceFuncs ga_channel_watch_funcs = {
    183    ga_channel_prepare,
    184    ga_channel_check,
    185    ga_channel_dispatch,
    186    ga_channel_finalize
    187};
    188
    189static GSource *ga_channel_create_watch(GAChannel *c)
    190{
    191    GSource *source = g_source_new(&ga_channel_watch_funcs, sizeof(GAWatch));
    192    GAWatch *watch = (GAWatch *)source;
    193
    194    watch->channel = c;
    195    watch->pollfd.fd = (gintptr) c->rstate.ov.hEvent;
    196    g_source_add_poll(source, &watch->pollfd);
    197
    198    return source;
    199}
    200
    201GIOStatus ga_channel_read(GAChannel *c, char *buf, size_t size, gsize *count)
    202{
    203    GAChannelReadState *rs = &c->rstate;
    204    GIOStatus status;
    205    size_t to_read = 0;
    206
    207    if (c->pending_events & G_IO_ERR) {
    208        return G_IO_STATUS_ERROR;
    209    }
    210
    211    *count = to_read = MIN(size, rs->pending);
    212    if (to_read) {
    213        memcpy(buf, rs->buf + rs->cur, to_read);
    214        rs->cur += to_read;
    215        rs->pending -= to_read;
    216        status = G_IO_STATUS_NORMAL;
    217    } else {
    218        status = G_IO_STATUS_AGAIN;
    219    }
    220
    221    return status;
    222}
    223
    224static GIOStatus ga_channel_write(GAChannel *c, const char *buf, size_t size,
    225                                  size_t *count)
    226{
    227    GIOStatus status;
    228    OVERLAPPED ov = {0};
    229    BOOL ret;
    230    DWORD written;
    231
    232    ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    233    ret = WriteFile(c->handle, buf, size, &written, &ov);
    234    if (!ret) {
    235        if (GetLastError() == ERROR_IO_PENDING) {
    236            /* write is pending */
    237            ret = GetOverlappedResult(c->handle, &ov, &written, TRUE);
    238            if (!ret) {
    239                if (!GetLastError()) {
    240                    status = G_IO_STATUS_AGAIN;
    241                } else {
    242                    status = G_IO_STATUS_ERROR;
    243                }
    244            } else {
    245                /* write is complete */
    246                status = G_IO_STATUS_NORMAL;
    247                *count = written;
    248            }
    249        } else {
    250            status = G_IO_STATUS_ERROR;
    251        }
    252    } else {
    253        /* write returned immediately */
    254        status = G_IO_STATUS_NORMAL;
    255        *count = written;
    256    }
    257
    258    if (ov.hEvent) {
    259        CloseHandle(ov.hEvent);
    260        ov.hEvent = NULL;
    261    }
    262    return status;
    263}
    264
    265GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size)
    266{
    267    GIOStatus status = G_IO_STATUS_NORMAL;
    268    size_t count = 0;
    269
    270    while (size) {
    271        status = ga_channel_write(c, buf, size, &count);
    272        if (status == G_IO_STATUS_NORMAL) {
    273            size -= count;
    274            buf += count;
    275        } else if (status != G_IO_STATUS_AGAIN) {
    276            break;
    277        }
    278    }
    279
    280    return status;
    281}
    282
    283static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
    284                                const gchar *path)
    285{
    286    COMMTIMEOUTS comTimeOut = {0};
    287    gchar newpath[MAXPATHLEN] = {0};
    288    comTimeOut.ReadIntervalTimeout = 1;
    289
    290    if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) {
    291        g_critical("unsupported communication method");
    292        return false;
    293    }
    294
    295    if (method == GA_CHANNEL_ISA_SERIAL) {
    296        snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path);
    297    } else {
    298        g_strlcpy(newpath, path, sizeof(newpath));
    299    }
    300
    301    c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
    302                           OPEN_EXISTING,
    303                           FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
    304    if (c->handle == INVALID_HANDLE_VALUE) {
    305        g_autofree gchar *emsg = g_win32_error_message(GetLastError());
    306        g_critical("error opening path %s: %s", newpath, emsg);
    307        return false;
    308    }
    309
    310    if (method == GA_CHANNEL_ISA_SERIAL
    311            && !SetCommTimeouts(c->handle, &comTimeOut)) {
    312        g_autofree gchar *emsg = g_win32_error_message(GetLastError());
    313        g_critical("error setting timeout for com port: %s", emsg);
    314        CloseHandle(c->handle);
    315        return false;
    316    }
    317
    318    return true;
    319}
    320
    321GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
    322                          int listen_fd, GAChannelCallback cb, gpointer opaque)
    323{
    324    GAChannel *c = g_new0(GAChannel, 1);
    325    SECURITY_ATTRIBUTES sec_attrs;
    326
    327    if (!ga_channel_open(c, method, path)) {
    328        g_critical("error opening channel");
    329        g_free(c);
    330        return NULL;
    331    }
    332
    333    c->cb = cb;
    334    c->user_data = opaque;
    335
    336    sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
    337    sec_attrs.lpSecurityDescriptor = NULL;
    338    sec_attrs.bInheritHandle = false;
    339
    340    c->rstate.buf_size = QGA_READ_COUNT_DEFAULT;
    341    c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT);
    342    c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL);
    343
    344    c->source = ga_channel_create_watch(c);
    345    g_source_attach(c->source, NULL);
    346    return c;
    347}
    348
    349void ga_channel_free(GAChannel *c)
    350{
    351    if (c->source) {
    352        g_source_destroy(c->source);
    353    }
    354    if (c->rstate.ov.hEvent) {
    355        CloseHandle(c->rstate.ov.hEvent);
    356    }
    357    g_free(c->rstate.buf);
    358    g_free(c);
    359}