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

char-pty.c (6983B)


      1/*
      2 * QEMU System Emulator
      3 *
      4 * Copyright (c) 2003-2008 Fabrice Bellard
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "qemu-common.h"
     27#include "qapi/error.h"
     28#include "chardev/char.h"
     29#include "io/channel-file.h"
     30#include "qemu/sockets.h"
     31#include "qemu/error-report.h"
     32#include "qemu/module.h"
     33#include "qemu/qemu-print.h"
     34
     35#include "chardev/char-io.h"
     36#include "qom/object.h"
     37
     38struct PtyChardev {
     39    Chardev parent;
     40    QIOChannel *ioc;
     41    int read_bytes;
     42
     43    int connected;
     44    GSource *timer_src;
     45};
     46typedef struct PtyChardev PtyChardev;
     47
     48DECLARE_INSTANCE_CHECKER(PtyChardev, PTY_CHARDEV,
     49                         TYPE_CHARDEV_PTY)
     50
     51static void pty_chr_state(Chardev *chr, int connected);
     52
     53static void pty_chr_timer_cancel(PtyChardev *s)
     54{
     55    if (s->timer_src) {
     56        g_source_destroy(s->timer_src);
     57        g_source_unref(s->timer_src);
     58        s->timer_src = NULL;
     59    }
     60}
     61
     62static gboolean pty_chr_timer(gpointer opaque)
     63{
     64    struct Chardev *chr = CHARDEV(opaque);
     65    PtyChardev *s = PTY_CHARDEV(opaque);
     66
     67    pty_chr_timer_cancel(s);
     68    if (!s->connected) {
     69        /* Next poll ... */
     70        qemu_chr_be_update_read_handlers(chr, chr->gcontext);
     71    }
     72    return FALSE;
     73}
     74
     75static void pty_chr_rearm_timer(Chardev *chr, int ms)
     76{
     77    PtyChardev *s = PTY_CHARDEV(chr);
     78    char *name;
     79
     80    pty_chr_timer_cancel(s);
     81    name = g_strdup_printf("pty-timer-%s", chr->label);
     82    s->timer_src = qemu_chr_timeout_add_ms(chr, ms, pty_chr_timer, chr);
     83    g_source_set_name(s->timer_src, name);
     84    g_free(name);
     85}
     86
     87static void pty_chr_update_read_handler(Chardev *chr)
     88{
     89    PtyChardev *s = PTY_CHARDEV(chr);
     90    GPollFD pfd;
     91    int rc;
     92    QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
     93
     94    pfd.fd = fioc->fd;
     95    pfd.events = G_IO_OUT;
     96    pfd.revents = 0;
     97    do {
     98        rc = g_poll(&pfd, 1, 0);
     99    } while (rc == -1 && errno == EINTR);
    100    assert(rc >= 0);
    101
    102    if (pfd.revents & G_IO_HUP) {
    103        pty_chr_state(chr, 0);
    104    } else {
    105        pty_chr_state(chr, 1);
    106    }
    107}
    108
    109static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
    110{
    111    PtyChardev *s = PTY_CHARDEV(chr);
    112
    113    if (!s->connected) {
    114        return len;
    115    }
    116    return io_channel_send(s->ioc, buf, len);
    117}
    118
    119static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
    120{
    121    PtyChardev *s = PTY_CHARDEV(chr);
    122    if (!s->connected) {
    123        return NULL;
    124    }
    125    return qio_channel_create_watch(s->ioc, cond);
    126}
    127
    128static int pty_chr_read_poll(void *opaque)
    129{
    130    Chardev *chr = CHARDEV(opaque);
    131    PtyChardev *s = PTY_CHARDEV(opaque);
    132
    133    s->read_bytes = qemu_chr_be_can_write(chr);
    134    return s->read_bytes;
    135}
    136
    137static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
    138{
    139    Chardev *chr = CHARDEV(opaque);
    140    PtyChardev *s = PTY_CHARDEV(opaque);
    141    gsize len;
    142    uint8_t buf[CHR_READ_BUF_LEN];
    143    ssize_t ret;
    144
    145    len = sizeof(buf);
    146    if (len > s->read_bytes) {
    147        len = s->read_bytes;
    148    }
    149    if (len == 0) {
    150        return TRUE;
    151    }
    152    ret = qio_channel_read(s->ioc, (char *)buf, len, NULL);
    153    if (ret <= 0) {
    154        pty_chr_state(chr, 0);
    155        return FALSE;
    156    } else {
    157        pty_chr_state(chr, 1);
    158        qemu_chr_be_write(chr, buf, ret);
    159    }
    160    return TRUE;
    161}
    162
    163static void pty_chr_state(Chardev *chr, int connected)
    164{
    165    PtyChardev *s = PTY_CHARDEV(chr);
    166
    167    if (!connected) {
    168        remove_fd_in_watch(chr);
    169        s->connected = 0;
    170        /* (re-)connect poll interval for idle guests: once per second.
    171         * We check more frequently in case the guests sends data to
    172         * the virtual device linked to our pty. */
    173        pty_chr_rearm_timer(chr, 1000);
    174    } else {
    175        pty_chr_timer_cancel(s);
    176        if (!s->connected) {
    177            s->connected = 1;
    178            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
    179        }
    180        if (!chr->gsource) {
    181            chr->gsource = io_add_watch_poll(chr, s->ioc,
    182                                               pty_chr_read_poll,
    183                                               pty_chr_read,
    184                                               chr, chr->gcontext);
    185        }
    186    }
    187}
    188
    189static void char_pty_finalize(Object *obj)
    190{
    191    Chardev *chr = CHARDEV(obj);
    192    PtyChardev *s = PTY_CHARDEV(obj);
    193
    194    pty_chr_state(chr, 0);
    195    object_unref(OBJECT(s->ioc));
    196    pty_chr_timer_cancel(s);
    197    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
    198}
    199
    200static void char_pty_open(Chardev *chr,
    201                          ChardevBackend *backend,
    202                          bool *be_opened,
    203                          Error **errp)
    204{
    205    PtyChardev *s;
    206    int master_fd, slave_fd;
    207    char pty_name[PATH_MAX];
    208    char *name;
    209
    210    master_fd = qemu_openpty_raw(&slave_fd, pty_name);
    211    if (master_fd < 0) {
    212        error_setg_errno(errp, errno, "Failed to create PTY");
    213        return;
    214    }
    215
    216    close(slave_fd);
    217    qemu_set_nonblock(master_fd);
    218
    219    chr->filename = g_strdup_printf("pty:%s", pty_name);
    220    qemu_printf("char device redirected to %s (label %s)\n",
    221                pty_name, chr->label);
    222
    223    s = PTY_CHARDEV(chr);
    224    s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
    225    name = g_strdup_printf("chardev-pty-%s", chr->label);
    226    qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
    227    g_free(name);
    228    s->timer_src = NULL;
    229    *be_opened = false;
    230}
    231
    232static void char_pty_class_init(ObjectClass *oc, void *data)
    233{
    234    ChardevClass *cc = CHARDEV_CLASS(oc);
    235
    236    cc->open = char_pty_open;
    237    cc->chr_write = char_pty_chr_write;
    238    cc->chr_update_read_handler = pty_chr_update_read_handler;
    239    cc->chr_add_watch = pty_chr_add_watch;
    240}
    241
    242static const TypeInfo char_pty_type_info = {
    243    .name = TYPE_CHARDEV_PTY,
    244    .parent = TYPE_CHARDEV,
    245    .instance_size = sizeof(PtyChardev),
    246    .instance_finalize = char_pty_finalize,
    247    .class_init = char_pty_class_init,
    248};
    249
    250static void register_types(void)
    251{
    252    type_register_static(&char_pty_type_info);
    253}
    254
    255type_init(register_types);