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

test-io-channel-socket.c (18832B)


      1/*
      2 * QEMU I/O channel sockets test
      3 *
      4 * Copyright (c) 2015-2016 Red Hat, Inc.
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 *
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "io/channel-socket.h"
     23#include "io/channel-util.h"
     24#include "io-channel-helpers.h"
     25#include "socket-helpers.h"
     26#include "qapi/error.h"
     27#include "qemu/module.h"
     28#include "qemu/main-loop.h"
     29
     30
     31static void test_io_channel_set_socket_bufs(QIOChannel *src,
     32                                            QIOChannel *dst)
     33{
     34    int buflen = 64 * 1024;
     35
     36    /*
     37     * Make the socket buffers small so that we see
     38     * the effects of partial reads/writes
     39     */
     40    setsockopt(((QIOChannelSocket *)src)->fd,
     41               SOL_SOCKET, SO_SNDBUF,
     42               (char *)&buflen,
     43               sizeof(buflen));
     44
     45    setsockopt(((QIOChannelSocket *)dst)->fd,
     46               SOL_SOCKET, SO_SNDBUF,
     47               (char *)&buflen,
     48               sizeof(buflen));
     49}
     50
     51
     52static void test_io_channel_setup_sync(SocketAddress *listen_addr,
     53                                       SocketAddress *connect_addr,
     54                                       QIOChannel **srv,
     55                                       QIOChannel **src,
     56                                       QIOChannel **dst)
     57{
     58    QIOChannelSocket *lioc;
     59
     60    lioc = qio_channel_socket_new();
     61    qio_channel_socket_listen_sync(lioc, listen_addr, 1, &error_abort);
     62
     63    if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
     64        SocketAddress *laddr = qio_channel_socket_get_local_address(
     65            lioc, &error_abort);
     66
     67        g_free(connect_addr->u.inet.port);
     68        connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
     69
     70        qapi_free_SocketAddress(laddr);
     71    }
     72
     73    *src = QIO_CHANNEL(qio_channel_socket_new());
     74    qio_channel_socket_connect_sync(
     75        QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
     76    qio_channel_set_delay(*src, false);
     77
     78    qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
     79    *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
     80    g_assert(*dst);
     81
     82    test_io_channel_set_socket_bufs(*src, *dst);
     83
     84    *srv = QIO_CHANNEL(lioc);
     85}
     86
     87
     88struct TestIOChannelData {
     89    bool err;
     90    GMainLoop *loop;
     91};
     92
     93
     94static void test_io_channel_complete(QIOTask *task,
     95                                     gpointer opaque)
     96{
     97    struct TestIOChannelData *data = opaque;
     98    data->err = qio_task_propagate_error(task, NULL);
     99    g_main_loop_quit(data->loop);
    100}
    101
    102
    103static void test_io_channel_setup_async(SocketAddress *listen_addr,
    104                                        SocketAddress *connect_addr,
    105                                        QIOChannel **srv,
    106                                        QIOChannel **src,
    107                                        QIOChannel **dst)
    108{
    109    QIOChannelSocket *lioc;
    110    struct TestIOChannelData data;
    111
    112    data.loop = g_main_loop_new(g_main_context_default(),
    113                                TRUE);
    114
    115    lioc = qio_channel_socket_new();
    116    qio_channel_socket_listen_async(
    117        lioc, listen_addr, 1,
    118        test_io_channel_complete, &data, NULL, NULL);
    119
    120    g_main_loop_run(data.loop);
    121    g_main_context_iteration(g_main_context_default(), FALSE);
    122
    123    g_assert(!data.err);
    124
    125    if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
    126        SocketAddress *laddr = qio_channel_socket_get_local_address(
    127            lioc, &error_abort);
    128
    129        g_free(connect_addr->u.inet.port);
    130        connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
    131
    132        qapi_free_SocketAddress(laddr);
    133    }
    134
    135    *src = QIO_CHANNEL(qio_channel_socket_new());
    136
    137    qio_channel_socket_connect_async(
    138        QIO_CHANNEL_SOCKET(*src), connect_addr,
    139        test_io_channel_complete, &data, NULL, NULL);
    140
    141    g_main_loop_run(data.loop);
    142    g_main_context_iteration(g_main_context_default(), FALSE);
    143
    144    g_assert(!data.err);
    145
    146    qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
    147    *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
    148    g_assert(*dst);
    149
    150    qio_channel_set_delay(*src, false);
    151    test_io_channel_set_socket_bufs(*src, *dst);
    152
    153    *srv = QIO_CHANNEL(lioc);
    154
    155    g_main_loop_unref(data.loop);
    156}
    157
    158
    159static void test_io_channel_socket_path_exists(SocketAddress *addr,
    160                                               bool expectExists)
    161{
    162    if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
    163        return;
    164    }
    165
    166    g_assert(g_file_test(addr->u.q_unix.path,
    167                         G_FILE_TEST_EXISTS) == expectExists);
    168}
    169
    170
    171static void test_io_channel(bool async,
    172                            SocketAddress *listen_addr,
    173                            SocketAddress *connect_addr,
    174                            bool passFD)
    175{
    176    QIOChannel *src, *dst, *srv;
    177    QIOChannelTest *test;
    178    if (async) {
    179        test_io_channel_setup_async(listen_addr, connect_addr,
    180                                    &srv, &src, &dst);
    181
    182        g_assert(!passFD ||
    183                 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
    184        g_assert(!passFD ||
    185                 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
    186        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
    187        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
    188
    189        test_io_channel_socket_path_exists(listen_addr, true);
    190
    191        test = qio_channel_test_new();
    192        qio_channel_test_run_threads(test, true, src, dst);
    193        qio_channel_test_validate(test);
    194
    195        test_io_channel_socket_path_exists(listen_addr, true);
    196
    197        /* unref without close, to ensure finalize() cleans up */
    198
    199        object_unref(OBJECT(src));
    200        object_unref(OBJECT(dst));
    201        test_io_channel_socket_path_exists(listen_addr, true);
    202
    203        object_unref(OBJECT(srv));
    204        test_io_channel_socket_path_exists(listen_addr, false);
    205
    206        test_io_channel_setup_async(listen_addr, connect_addr,
    207                                    &srv, &src, &dst);
    208
    209        g_assert(!passFD ||
    210                 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
    211        g_assert(!passFD ||
    212                 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
    213        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
    214        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
    215
    216        test = qio_channel_test_new();
    217        qio_channel_test_run_threads(test, false, src, dst);
    218        qio_channel_test_validate(test);
    219
    220        /* close before unref, to ensure finalize copes with already closed */
    221
    222        qio_channel_close(src, &error_abort);
    223        qio_channel_close(dst, &error_abort);
    224        test_io_channel_socket_path_exists(listen_addr, true);
    225
    226        object_unref(OBJECT(src));
    227        object_unref(OBJECT(dst));
    228        test_io_channel_socket_path_exists(listen_addr, true);
    229
    230        qio_channel_close(srv, &error_abort);
    231        test_io_channel_socket_path_exists(listen_addr, false);
    232
    233        object_unref(OBJECT(srv));
    234        test_io_channel_socket_path_exists(listen_addr, false);
    235    } else {
    236        test_io_channel_setup_sync(listen_addr, connect_addr,
    237                                   &srv, &src, &dst);
    238
    239        g_assert(!passFD ||
    240                 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
    241        g_assert(!passFD ||
    242                 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
    243        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
    244        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
    245
    246        test_io_channel_socket_path_exists(listen_addr, true);
    247
    248        test = qio_channel_test_new();
    249        qio_channel_test_run_threads(test, true, src, dst);
    250        qio_channel_test_validate(test);
    251
    252        test_io_channel_socket_path_exists(listen_addr, true);
    253
    254        /* unref without close, to ensure finalize() cleans up */
    255
    256        object_unref(OBJECT(src));
    257        object_unref(OBJECT(dst));
    258        test_io_channel_socket_path_exists(listen_addr, true);
    259
    260        object_unref(OBJECT(srv));
    261        test_io_channel_socket_path_exists(listen_addr, false);
    262
    263        test_io_channel_setup_sync(listen_addr, connect_addr,
    264                                   &srv, &src, &dst);
    265
    266        g_assert(!passFD ||
    267                 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
    268        g_assert(!passFD ||
    269                 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
    270        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
    271        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
    272
    273        test = qio_channel_test_new();
    274        qio_channel_test_run_threads(test, false, src, dst);
    275        qio_channel_test_validate(test);
    276
    277        test_io_channel_socket_path_exists(listen_addr, true);
    278
    279        /* close before unref, to ensure finalize copes with already closed */
    280
    281        qio_channel_close(src, &error_abort);
    282        qio_channel_close(dst, &error_abort);
    283        test_io_channel_socket_path_exists(listen_addr, true);
    284
    285        object_unref(OBJECT(src));
    286        object_unref(OBJECT(dst));
    287        test_io_channel_socket_path_exists(listen_addr, true);
    288
    289        qio_channel_close(srv, &error_abort);
    290        test_io_channel_socket_path_exists(listen_addr, false);
    291
    292        object_unref(OBJECT(srv));
    293        test_io_channel_socket_path_exists(listen_addr, false);
    294    }
    295}
    296
    297
    298static void test_io_channel_ipv4(bool async)
    299{
    300    SocketAddress *listen_addr = g_new0(SocketAddress, 1);
    301    SocketAddress *connect_addr = g_new0(SocketAddress, 1);
    302
    303    listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
    304    listen_addr->u.inet = (InetSocketAddress) {
    305        .host = g_strdup("127.0.0.1"),
    306        .port = NULL, /* Auto-select */
    307    };
    308
    309    connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
    310    connect_addr->u.inet = (InetSocketAddress) {
    311        .host = g_strdup("127.0.0.1"),
    312        .port = NULL, /* Filled in later */
    313    };
    314
    315    test_io_channel(async, listen_addr, connect_addr, false);
    316
    317    qapi_free_SocketAddress(listen_addr);
    318    qapi_free_SocketAddress(connect_addr);
    319}
    320
    321
    322static void test_io_channel_ipv4_sync(void)
    323{
    324    return test_io_channel_ipv4(false);
    325}
    326
    327
    328static void test_io_channel_ipv4_async(void)
    329{
    330    return test_io_channel_ipv4(true);
    331}
    332
    333
    334static void test_io_channel_ipv6(bool async)
    335{
    336    SocketAddress *listen_addr = g_new0(SocketAddress, 1);
    337    SocketAddress *connect_addr = g_new0(SocketAddress, 1);
    338
    339    listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
    340    listen_addr->u.inet = (InetSocketAddress) {
    341        .host = g_strdup("::1"),
    342        .port = NULL, /* Auto-select */
    343    };
    344
    345    connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
    346    connect_addr->u.inet = (InetSocketAddress) {
    347        .host = g_strdup("::1"),
    348        .port = NULL, /* Filled in later */
    349    };
    350
    351    test_io_channel(async, listen_addr, connect_addr, false);
    352
    353    qapi_free_SocketAddress(listen_addr);
    354    qapi_free_SocketAddress(connect_addr);
    355}
    356
    357
    358static void test_io_channel_ipv6_sync(void)
    359{
    360    return test_io_channel_ipv6(false);
    361}
    362
    363
    364static void test_io_channel_ipv6_async(void)
    365{
    366    return test_io_channel_ipv6(true);
    367}
    368
    369
    370#ifndef _WIN32
    371static void test_io_channel_unix(bool async)
    372{
    373    SocketAddress *listen_addr = g_new0(SocketAddress, 1);
    374    SocketAddress *connect_addr = g_new0(SocketAddress, 1);
    375
    376#define TEST_SOCKET "test-io-channel-socket.sock"
    377    listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
    378    listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
    379
    380    connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
    381    connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
    382
    383    test_io_channel(async, listen_addr, connect_addr, true);
    384
    385    qapi_free_SocketAddress(listen_addr);
    386    qapi_free_SocketAddress(connect_addr);
    387}
    388
    389
    390static void test_io_channel_unix_sync(void)
    391{
    392    return test_io_channel_unix(false);
    393}
    394
    395
    396static void test_io_channel_unix_async(void)
    397{
    398    return test_io_channel_unix(true);
    399}
    400
    401static void test_io_channel_unix_fd_pass(void)
    402{
    403    SocketAddress *listen_addr = g_new0(SocketAddress, 1);
    404    SocketAddress *connect_addr = g_new0(SocketAddress, 1);
    405    QIOChannel *src, *dst, *srv;
    406    int testfd;
    407    int fdsend[3];
    408    int *fdrecv = NULL;
    409    size_t nfdrecv = 0;
    410    size_t i;
    411    char bufsend[12], bufrecv[12];
    412    struct iovec iosend[1], iorecv[1];
    413
    414#define TEST_SOCKET "test-io-channel-socket.sock"
    415#define TEST_FILE "test-io-channel-socket.txt"
    416
    417    testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700);
    418    g_assert(testfd != -1);
    419    fdsend[0] = testfd;
    420    fdsend[1] = testfd;
    421    fdsend[2] = testfd;
    422
    423    listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
    424    listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
    425
    426    connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
    427    connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
    428
    429    test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst);
    430
    431    memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend));
    432
    433    iosend[0].iov_base = bufsend;
    434    iosend[0].iov_len = G_N_ELEMENTS(bufsend);
    435
    436    iorecv[0].iov_base = bufrecv;
    437    iorecv[0].iov_len = G_N_ELEMENTS(bufrecv);
    438
    439    g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
    440    g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
    441
    442    qio_channel_writev_full(src,
    443                            iosend,
    444                            G_N_ELEMENTS(iosend),
    445                            fdsend,
    446                            G_N_ELEMENTS(fdsend),
    447                            &error_abort);
    448
    449    qio_channel_readv_full(dst,
    450                           iorecv,
    451                           G_N_ELEMENTS(iorecv),
    452                           &fdrecv,
    453                           &nfdrecv,
    454                           &error_abort);
    455
    456    g_assert(nfdrecv == G_N_ELEMENTS(fdsend));
    457    /* Each recvd FD should be different from sent FD */
    458    for (i = 0; i < nfdrecv; i++) {
    459        g_assert_cmpint(fdrecv[i], !=, testfd);
    460    }
    461    /* Each recvd FD should be different from each other */
    462    g_assert_cmpint(fdrecv[0], !=, fdrecv[1]);
    463    g_assert_cmpint(fdrecv[0], !=, fdrecv[2]);
    464    g_assert_cmpint(fdrecv[1], !=, fdrecv[2]);
    465
    466    /* Check the I/O buf we sent at the same time matches */
    467    g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
    468
    469    /* Write some data into the FD we received */
    470    g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) ==
    471             G_N_ELEMENTS(bufsend));
    472
    473    /* Read data from the original FD and make sure it matches */
    474    memset(bufrecv, 0, G_N_ELEMENTS(bufrecv));
    475    g_assert(lseek(testfd, 0, SEEK_SET) == 0);
    476    g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) ==
    477             G_N_ELEMENTS(bufrecv));
    478    g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
    479
    480    object_unref(OBJECT(src));
    481    object_unref(OBJECT(dst));
    482    object_unref(OBJECT(srv));
    483    qapi_free_SocketAddress(listen_addr);
    484    qapi_free_SocketAddress(connect_addr);
    485    unlink(TEST_SOCKET);
    486    unlink(TEST_FILE);
    487    close(testfd);
    488    for (i = 0; i < nfdrecv; i++) {
    489        close(fdrecv[i]);
    490    }
    491    g_free(fdrecv);
    492}
    493
    494static void test_io_channel_unix_listen_cleanup(void)
    495{
    496    QIOChannelSocket *ioc;
    497    struct sockaddr_un un;
    498    int sock;
    499
    500#define TEST_SOCKET "test-io-channel-socket.sock"
    501
    502    ioc = qio_channel_socket_new();
    503
    504    /* Manually bind ioc without calling the qio api to avoid setting
    505     * the LISTEN feature */
    506    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
    507    memset(&un, 0, sizeof(un));
    508    un.sun_family = AF_UNIX;
    509    snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
    510    unlink(TEST_SOCKET);
    511    bind(sock, (struct sockaddr *)&un, sizeof(un));
    512    ioc->fd = sock;
    513    ioc->localAddrLen = sizeof(ioc->localAddr);
    514    getsockname(sock, (struct sockaddr *)&ioc->localAddr,
    515                &ioc->localAddrLen);
    516
    517    g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
    518    object_unref(OBJECT(ioc));
    519    g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
    520
    521    unlink(TEST_SOCKET);
    522}
    523
    524#endif /* _WIN32 */
    525
    526
    527static void test_io_channel_ipv4_fd(void)
    528{
    529    QIOChannel *ioc;
    530    int fd = -1;
    531    struct sockaddr_in sa = {
    532        .sin_family = AF_INET,
    533        .sin_addr = {
    534            .s_addr =  htonl(INADDR_LOOPBACK),
    535        }
    536        /* Leave port unset for auto-assign */
    537    };
    538    socklen_t salen = sizeof(sa);
    539
    540    fd = socket(AF_INET, SOCK_STREAM, 0);
    541    g_assert_cmpint(fd, >, -1);
    542
    543    g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0);
    544
    545    ioc = qio_channel_new_fd(fd, &error_abort);
    546
    547    g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
    548                    ==,
    549                    TYPE_QIO_CHANNEL_SOCKET);
    550
    551    object_unref(OBJECT(ioc));
    552}
    553
    554
    555int main(int argc, char **argv)
    556{
    557    bool has_ipv4, has_ipv6;
    558
    559    module_call_init(MODULE_INIT_QOM);
    560    qemu_init_main_loop(&error_abort);
    561    socket_init();
    562
    563    g_test_init(&argc, &argv, NULL);
    564
    565    /* We're creating actual IPv4/6 sockets, so we should
    566     * check if the host running tests actually supports
    567     * each protocol to avoid breaking tests on machines
    568     * with either IPv4 or IPv6 disabled.
    569     */
    570    if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
    571        g_printerr("socket_check_protocol_support() failed\n");
    572        goto end;
    573    }
    574
    575    if (has_ipv4) {
    576        g_test_add_func("/io/channel/socket/ipv4-sync",
    577                        test_io_channel_ipv4_sync);
    578        g_test_add_func("/io/channel/socket/ipv4-async",
    579                        test_io_channel_ipv4_async);
    580        g_test_add_func("/io/channel/socket/ipv4-fd",
    581                        test_io_channel_ipv4_fd);
    582    }
    583    if (has_ipv6) {
    584        g_test_add_func("/io/channel/socket/ipv6-sync",
    585                        test_io_channel_ipv6_sync);
    586        g_test_add_func("/io/channel/socket/ipv6-async",
    587                        test_io_channel_ipv6_async);
    588    }
    589
    590#ifndef _WIN32
    591    g_test_add_func("/io/channel/socket/unix-sync",
    592                    test_io_channel_unix_sync);
    593    g_test_add_func("/io/channel/socket/unix-async",
    594                    test_io_channel_unix_async);
    595    g_test_add_func("/io/channel/socket/unix-fd-pass",
    596                    test_io_channel_unix_fd_pass);
    597    g_test_add_func("/io/channel/socket/unix-listen-cleanup",
    598                    test_io_channel_unix_listen_cleanup);
    599#endif /* _WIN32 */
    600
    601end:
    602    return g_test_run();
    603}