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-posix.c (8514B)


      1#include "qemu/osdep.h"
      2#include <termios.h>
      3#include "qapi/error.h"
      4#include "qemu/sockets.h"
      5#include "channel.h"
      6
      7#ifdef CONFIG_SOLARIS
      8#include <stropts.h>
      9#endif
     10
     11#define GA_CHANNEL_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
     12
     13struct GAChannel {
     14    GIOChannel *listen_channel;
     15    GIOChannel *client_channel;
     16    GAChannelMethod method;
     17    GAChannelCallback event_cb;
     18    gpointer user_data;
     19};
     20
     21static int ga_channel_client_add(GAChannel *c, int fd);
     22
     23static gboolean ga_channel_listen_accept(GIOChannel *channel,
     24                                         GIOCondition condition, gpointer data)
     25{
     26    GAChannel *c = data;
     27    int ret, client_fd;
     28    bool accepted = false;
     29
     30    g_assert(channel != NULL);
     31
     32    client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), NULL, NULL);
     33    if (client_fd == -1) {
     34        g_warning("error converting fd to gsocket: %s", strerror(errno));
     35        goto out;
     36    }
     37    qemu_set_nonblock(client_fd);
     38    ret = ga_channel_client_add(c, client_fd);
     39    if (ret) {
     40        g_warning("error setting up connection");
     41        close(client_fd);
     42        goto out;
     43    }
     44    accepted = true;
     45
     46out:
     47    /* only accept 1 connection at a time */
     48    return !accepted;
     49}
     50
     51/* start polling for readable events on listen fd, new==true
     52 * indicates we should use the existing s->listen_channel
     53 */
     54static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
     55{
     56    if (create) {
     57        c->listen_channel = g_io_channel_unix_new(listen_fd);
     58    }
     59    g_io_add_watch(c->listen_channel, G_IO_IN, ga_channel_listen_accept, c);
     60}
     61
     62static void ga_channel_listen_close(GAChannel *c)
     63{
     64    g_assert(c->listen_channel);
     65    g_io_channel_shutdown(c->listen_channel, true, NULL);
     66    g_io_channel_unref(c->listen_channel);
     67    c->listen_channel = NULL;
     68}
     69
     70/* cleanup state for closed connection/session, start accepting new
     71 * connections if we're in listening mode
     72 */
     73static void ga_channel_client_close(GAChannel *c)
     74{
     75    g_assert(c->client_channel);
     76    g_io_channel_shutdown(c->client_channel, true, NULL);
     77    g_io_channel_unref(c->client_channel);
     78    c->client_channel = NULL;
     79    if (c->listen_channel) {
     80        ga_channel_listen_add(c, 0, false);
     81    }
     82}
     83
     84static gboolean ga_channel_client_event(GIOChannel *channel,
     85                                        GIOCondition condition, gpointer data)
     86{
     87    GAChannel *c = data;
     88    gboolean client_cont;
     89
     90    g_assert(c);
     91    if (c->event_cb) {
     92        client_cont = c->event_cb(condition, c->user_data);
     93        if (!client_cont) {
     94            ga_channel_client_close(c);
     95            return false;
     96        }
     97    }
     98    return true;
     99}
    100
    101static int ga_channel_client_add(GAChannel *c, int fd)
    102{
    103    GIOChannel *client_channel;
    104    GError *err = NULL;
    105
    106    g_assert(c && !c->client_channel);
    107    client_channel = g_io_channel_unix_new(fd);
    108    g_assert(client_channel);
    109    g_io_channel_set_encoding(client_channel, NULL, &err);
    110    if (err != NULL) {
    111        g_warning("error setting channel encoding to binary");
    112        g_error_free(err);
    113        return -1;
    114    }
    115    g_io_add_watch(client_channel, G_IO_IN | G_IO_HUP,
    116                   ga_channel_client_event, c);
    117    c->client_channel = client_channel;
    118    return 0;
    119}
    120
    121static gboolean ga_channel_open(GAChannel *c, const gchar *path,
    122                                GAChannelMethod method, int fd)
    123{
    124    int ret;
    125    c->method = method;
    126
    127    switch (c->method) {
    128    case GA_CHANNEL_VIRTIO_SERIAL: {
    129        assert(fd < 0);
    130        fd = qemu_open_old(path, O_RDWR | O_NONBLOCK
    131#ifndef CONFIG_SOLARIS
    132                           | O_ASYNC
    133#endif
    134                           );
    135        if (fd == -1) {
    136            g_critical("error opening channel: %s", strerror(errno));
    137            return false;
    138        }
    139#ifdef CONFIG_SOLARIS
    140        ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
    141        if (ret == -1) {
    142            g_critical("error setting event mask for channel: %s",
    143                       strerror(errno));
    144            close(fd);
    145            return false;
    146        }
    147#endif
    148        ret = ga_channel_client_add(c, fd);
    149        if (ret) {
    150            g_critical("error adding channel to main loop");
    151            close(fd);
    152            return false;
    153        }
    154        break;
    155    }
    156    case GA_CHANNEL_ISA_SERIAL: {
    157        struct termios tio;
    158
    159        assert(fd < 0);
    160        fd = qemu_open_old(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
    161        if (fd == -1) {
    162            g_critical("error opening channel: %s", strerror(errno));
    163            return false;
    164        }
    165        tcgetattr(fd, &tio);
    166        /* set up serial port for non-canonical, dumb byte streaming */
    167        tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
    168                         INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
    169                         IMAXBEL);
    170        tio.c_oflag = 0;
    171        tio.c_lflag = 0;
    172        tio.c_cflag |= GA_CHANNEL_BAUDRATE_DEFAULT;
    173        /* 1 available byte min or reads will block (we'll set non-blocking
    174         * elsewhere, else we have to deal with read()=0 instead)
    175         */
    176        tio.c_cc[VMIN] = 1;
    177        tio.c_cc[VTIME] = 0;
    178        /* flush everything waiting for read/xmit, it's garbage at this point */
    179        tcflush(fd, TCIFLUSH);
    180        tcsetattr(fd, TCSANOW, &tio);
    181        ret = ga_channel_client_add(c, fd);
    182        if (ret) {
    183            g_critical("error adding channel to main loop");
    184            close(fd);
    185            return false;
    186        }
    187        break;
    188    }
    189    case GA_CHANNEL_UNIX_LISTEN: {
    190        if (fd < 0) {
    191            Error *local_err = NULL;
    192
    193            fd = unix_listen(path, &local_err);
    194            if (local_err != NULL) {
    195                g_critical("%s", error_get_pretty(local_err));
    196                error_free(local_err);
    197                return false;
    198            }
    199        }
    200        ga_channel_listen_add(c, fd, true);
    201        break;
    202    }
    203    case GA_CHANNEL_VSOCK_LISTEN: {
    204        if (fd < 0) {
    205            Error *local_err = NULL;
    206            SocketAddress *addr;
    207            char *addr_str;
    208
    209            addr_str = g_strdup_printf("vsock:%s", path);
    210            addr = socket_parse(addr_str, &local_err);
    211            g_free(addr_str);
    212            if (local_err != NULL) {
    213                g_critical("%s", error_get_pretty(local_err));
    214                error_free(local_err);
    215                return false;
    216            }
    217
    218            fd = socket_listen(addr, 1, &local_err);
    219            qapi_free_SocketAddress(addr);
    220            if (local_err != NULL) {
    221                g_critical("%s", error_get_pretty(local_err));
    222                error_free(local_err);
    223                return false;
    224            }
    225        }
    226        ga_channel_listen_add(c, fd, true);
    227        break;
    228    }
    229    default:
    230        g_critical("error binding/listening to specified socket");
    231        return false;
    232    }
    233
    234    return true;
    235}
    236
    237GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
    238{
    239    GError *err = NULL;
    240    gsize written = 0;
    241    GIOStatus status = G_IO_STATUS_NORMAL;
    242
    243    while (size) {
    244        g_debug("sending data, count: %d", (int)size);
    245        status = g_io_channel_write_chars(c->client_channel, buf, size,
    246                                          &written, &err);
    247        if (status == G_IO_STATUS_NORMAL) {
    248            size -= written;
    249            buf += written;
    250        } else if (status != G_IO_STATUS_AGAIN) {
    251            g_warning("error writing to channel: %s", err->message);
    252            return status;
    253        }
    254    }
    255
    256    do {
    257        status = g_io_channel_flush(c->client_channel, &err);
    258    } while (status == G_IO_STATUS_AGAIN);
    259
    260    if (status != G_IO_STATUS_NORMAL) {
    261        g_warning("error flushing channel: %s", err->message);
    262    }
    263
    264    return status;
    265}
    266
    267GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
    268{
    269    return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
    270}
    271
    272GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
    273                          int listen_fd, GAChannelCallback cb, gpointer opaque)
    274{
    275    GAChannel *c = g_new0(GAChannel, 1);
    276    c->event_cb = cb;
    277    c->user_data = opaque;
    278
    279    if (!ga_channel_open(c, path, method, listen_fd)) {
    280        g_critical("error opening channel");
    281        ga_channel_free(c);
    282        return NULL;
    283    }
    284
    285    return c;
    286}
    287
    288void ga_channel_free(GAChannel *c)
    289{
    290    if (c->listen_channel) {
    291        ga_channel_listen_close(c);
    292    }
    293    if (c->client_channel) {
    294        ga_channel_client_close(c);
    295    }
    296    g_free(c);
    297}