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-util-sockets.c (10027B)


      1/*
      2 * Tests for util/qemu-sockets.c
      3 *
      4 * Copyright 2018 Red Hat, Inc.
      5 *
      6 * This program is free software; you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program 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
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 *
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "qemu-common.h"
     23#include "qemu/sockets.h"
     24#include "qapi/error.h"
     25#include "socket-helpers.h"
     26#include "monitor/monitor.h"
     27
     28static void test_fd_is_socket_bad(void)
     29{
     30    char *tmp = g_strdup("qemu-test-util-sockets-XXXXXX");
     31    int fd = mkstemp(tmp);
     32    if (fd != 0) {
     33        unlink(tmp);
     34    }
     35    g_free(tmp);
     36
     37    g_assert(fd >= 0);
     38
     39    g_assert(!fd_is_socket(fd));
     40    close(fd);
     41}
     42
     43static void test_fd_is_socket_good(void)
     44{
     45    int fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
     46
     47    g_assert(fd >= 0);
     48
     49    g_assert(fd_is_socket(fd));
     50    close(fd);
     51}
     52
     53static int mon_fd = -1;
     54static const char *mon_fdname;
     55__thread Monitor *cur_mon;
     56
     57int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
     58{
     59    g_assert(cur_mon);
     60    g_assert(mon == cur_mon);
     61    if (mon_fd == -1 || !g_str_equal(mon_fdname, fdname)) {
     62        error_setg(errp, "No fd named %s", fdname);
     63        return -1;
     64    }
     65    return dup(mon_fd);
     66}
     67
     68/*
     69 * Syms of stubs in libqemuutil.a are discarded at .o file
     70 * granularity.  To replace monitor_get_fd() and monitor_cur(), we
     71 * must ensure that we also replace any other symbol that is used in
     72 * the binary and would be taken from the same stub object file,
     73 * otherwise we get duplicate syms at link time.
     74 */
     75Monitor *monitor_cur(void) { return cur_mon; }
     76Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); }
     77int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); }
     78
     79#ifndef _WIN32
     80static void test_socket_fd_pass_name_good(void)
     81{
     82    SocketAddress addr;
     83    int fd;
     84
     85    cur_mon = g_malloc(1); /* Fake a monitor */
     86    mon_fdname = "myfd";
     87    mon_fd = qemu_socket(AF_INET, SOCK_STREAM, 0);
     88    g_assert_cmpint(mon_fd, >, STDERR_FILENO);
     89
     90    addr.type = SOCKET_ADDRESS_TYPE_FD;
     91    addr.u.fd.str = g_strdup(mon_fdname);
     92
     93    fd = socket_connect(&addr, &error_abort);
     94    g_assert_cmpint(fd, !=, -1);
     95    g_assert_cmpint(fd, !=, mon_fd);
     96    close(fd);
     97
     98    fd = socket_listen(&addr, 1, &error_abort);
     99    g_assert_cmpint(fd, !=, -1);
    100    g_assert_cmpint(fd, !=, mon_fd);
    101    close(fd);
    102
    103    g_free(addr.u.fd.str);
    104    mon_fdname = NULL;
    105    close(mon_fd);
    106    mon_fd = -1;
    107    g_free(cur_mon);
    108    cur_mon = NULL;
    109}
    110
    111static void test_socket_fd_pass_name_bad(void)
    112{
    113    SocketAddress addr;
    114    Error *err = NULL;
    115    int fd;
    116
    117    cur_mon = g_malloc(1); /* Fake a monitor */
    118    mon_fdname = "myfd";
    119    mon_fd = dup(STDOUT_FILENO);
    120    g_assert_cmpint(mon_fd, >, STDERR_FILENO);
    121
    122    addr.type = SOCKET_ADDRESS_TYPE_FD;
    123    addr.u.fd.str = g_strdup(mon_fdname);
    124
    125    fd = socket_connect(&addr, &err);
    126    g_assert_cmpint(fd, ==, -1);
    127    error_free_or_abort(&err);
    128
    129    fd = socket_listen(&addr, 1, &err);
    130    g_assert_cmpint(fd, ==, -1);
    131    error_free_or_abort(&err);
    132
    133    g_free(addr.u.fd.str);
    134    mon_fdname = NULL;
    135    close(mon_fd);
    136    mon_fd = -1;
    137    g_free(cur_mon);
    138    cur_mon = NULL;
    139}
    140
    141static void test_socket_fd_pass_name_nomon(void)
    142{
    143    SocketAddress addr;
    144    Error *err = NULL;
    145    int fd;
    146
    147    g_assert(cur_mon == NULL);
    148
    149    addr.type = SOCKET_ADDRESS_TYPE_FD;
    150    addr.u.fd.str = g_strdup("myfd");
    151
    152    fd = socket_connect(&addr, &err);
    153    g_assert_cmpint(fd, ==, -1);
    154    error_free_or_abort(&err);
    155
    156    fd = socket_listen(&addr, 1, &err);
    157    g_assert_cmpint(fd, ==, -1);
    158    error_free_or_abort(&err);
    159
    160    g_free(addr.u.fd.str);
    161}
    162
    163
    164static void test_socket_fd_pass_num_good(void)
    165{
    166    SocketAddress addr;
    167    int fd, sfd;
    168
    169    g_assert(cur_mon == NULL);
    170    sfd = qemu_socket(AF_INET, SOCK_STREAM, 0);
    171    g_assert_cmpint(sfd, >, STDERR_FILENO);
    172
    173    addr.type = SOCKET_ADDRESS_TYPE_FD;
    174    addr.u.fd.str = g_strdup_printf("%d", sfd);
    175
    176    fd = socket_connect(&addr, &error_abort);
    177    g_assert_cmpint(fd, ==, sfd);
    178
    179    fd = socket_listen(&addr, 1, &error_abort);
    180    g_assert_cmpint(fd, ==, sfd);
    181
    182    g_free(addr.u.fd.str);
    183    close(sfd);
    184}
    185
    186static void test_socket_fd_pass_num_bad(void)
    187{
    188    SocketAddress addr;
    189    Error *err = NULL;
    190    int fd, sfd;
    191
    192    g_assert(cur_mon == NULL);
    193    sfd = dup(STDOUT_FILENO);
    194
    195    addr.type = SOCKET_ADDRESS_TYPE_FD;
    196    addr.u.fd.str = g_strdup_printf("%d", sfd);
    197
    198    fd = socket_connect(&addr, &err);
    199    g_assert_cmpint(fd, ==, -1);
    200    error_free_or_abort(&err);
    201
    202    fd = socket_listen(&addr, 1, &err);
    203    g_assert_cmpint(fd, ==, -1);
    204    error_free_or_abort(&err);
    205
    206    g_free(addr.u.fd.str);
    207    close(sfd);
    208}
    209
    210static void test_socket_fd_pass_num_nocli(void)
    211{
    212    SocketAddress addr;
    213    Error *err = NULL;
    214    int fd;
    215
    216    cur_mon = g_malloc(1); /* Fake a monitor */
    217
    218    addr.type = SOCKET_ADDRESS_TYPE_FD;
    219    addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO);
    220
    221    fd = socket_connect(&addr, &err);
    222    g_assert_cmpint(fd, ==, -1);
    223    error_free_or_abort(&err);
    224
    225    fd = socket_listen(&addr, 1, &err);
    226    g_assert_cmpint(fd, ==, -1);
    227    error_free_or_abort(&err);
    228
    229    g_free(addr.u.fd.str);
    230}
    231#endif
    232
    233#ifdef CONFIG_LINUX
    234
    235#define ABSTRACT_SOCKET_VARIANTS 3
    236
    237typedef struct {
    238    SocketAddress *server, *client[ABSTRACT_SOCKET_VARIANTS];
    239    bool expect_connect[ABSTRACT_SOCKET_VARIANTS];
    240} abstract_socket_matrix_row;
    241
    242static gpointer unix_client_thread_func(gpointer user_data)
    243{
    244    abstract_socket_matrix_row *row = user_data;
    245    Error *err = NULL;
    246    int i, fd;
    247
    248    for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
    249        if (row->expect_connect[i]) {
    250            fd = socket_connect(row->client[i], &error_abort);
    251            g_assert_cmpint(fd, >=, 0);
    252        } else {
    253            fd = socket_connect(row->client[i], &err);
    254            g_assert_cmpint(fd, ==, -1);
    255            error_free_or_abort(&err);
    256        }
    257        close(fd);
    258    }
    259    return NULL;
    260}
    261
    262static void test_socket_unix_abstract_row(abstract_socket_matrix_row *test)
    263{
    264    int fd, connfd, i;
    265    GThread *cli;
    266    struct sockaddr_un un;
    267    socklen_t len = sizeof(un);
    268
    269    /* Last one must connect, or else accept() below hangs */
    270    assert(test->expect_connect[ABSTRACT_SOCKET_VARIANTS - 1]);
    271
    272    fd = socket_listen(test->server, 1, &error_abort);
    273    g_assert_cmpint(fd, >=, 0);
    274    g_assert(fd_is_socket(fd));
    275
    276    cli = g_thread_new("abstract_unix_client",
    277                       unix_client_thread_func,
    278                       test);
    279
    280    for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
    281        if (test->expect_connect[i]) {
    282            connfd = accept(fd, (struct sockaddr *)&un, &len);
    283            g_assert_cmpint(connfd, !=, -1);
    284            close(connfd);
    285        }
    286    }
    287
    288    close(fd);
    289    g_thread_join(cli);
    290}
    291
    292static void test_socket_unix_abstract(void)
    293{
    294    SocketAddress addr, addr_tight, addr_padded;
    295    abstract_socket_matrix_row matrix[ABSTRACT_SOCKET_VARIANTS] = {
    296        { &addr,
    297          { &addr_tight, &addr_padded, &addr },
    298          { true, false, true } },
    299        { &addr_tight,
    300          { &addr_padded, &addr, &addr_tight },
    301          { false, true, true } },
    302        { &addr_padded,
    303          { &addr, &addr_tight, &addr_padded },
    304          { false, false, true } }
    305    };
    306    int i;
    307
    308    addr.type = SOCKET_ADDRESS_TYPE_UNIX;
    309    addr.u.q_unix.path = g_strdup_printf("unix-%d-%u",
    310                                         getpid(), g_random_int());
    311    addr.u.q_unix.has_abstract = true;
    312    addr.u.q_unix.abstract = true;
    313    addr.u.q_unix.has_tight = false;
    314    addr.u.q_unix.tight = false;
    315
    316    addr_tight = addr;
    317    addr_tight.u.q_unix.has_tight = true;
    318    addr_tight.u.q_unix.tight = true;
    319
    320    addr_padded = addr;
    321    addr_padded.u.q_unix.has_tight = true;
    322    addr_padded.u.q_unix.tight = false;
    323
    324    for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
    325        test_socket_unix_abstract_row(&matrix[i]);
    326    }
    327
    328    g_free(addr.u.q_unix.path);
    329}
    330
    331#endif  /* CONFIG_LINUX */
    332
    333int main(int argc, char **argv)
    334{
    335    bool has_ipv4, has_ipv6;
    336
    337    qemu_init_main_loop(&error_abort);
    338    socket_init();
    339
    340    g_test_init(&argc, &argv, NULL);
    341
    342    /* We're creating actual IPv4/6 sockets, so we should
    343     * check if the host running tests actually supports
    344     * each protocol to avoid breaking tests on machines
    345     * with either IPv4 or IPv6 disabled.
    346     */
    347    if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
    348        g_printerr("socket_check_protocol_support() failed\n");
    349        goto end;
    350    }
    351
    352    if (has_ipv4) {
    353        g_test_add_func("/util/socket/is-socket/bad",
    354                        test_fd_is_socket_bad);
    355        g_test_add_func("/util/socket/is-socket/good",
    356                        test_fd_is_socket_good);
    357#ifndef _WIN32
    358        g_test_add_func("/socket/fd-pass/name/good",
    359                        test_socket_fd_pass_name_good);
    360        g_test_add_func("/socket/fd-pass/name/bad",
    361                        test_socket_fd_pass_name_bad);
    362        g_test_add_func("/socket/fd-pass/name/nomon",
    363                        test_socket_fd_pass_name_nomon);
    364        g_test_add_func("/socket/fd-pass/num/good",
    365                        test_socket_fd_pass_num_good);
    366        g_test_add_func("/socket/fd-pass/num/bad",
    367                        test_socket_fd_pass_num_bad);
    368        g_test_add_func("/socket/fd-pass/num/nocli",
    369                        test_socket_fd_pass_num_nocli);
    370#endif
    371    }
    372
    373#ifdef CONFIG_LINUX
    374    g_test_add_func("/util/socket/unix-abstract",
    375                    test_socket_unix_abstract);
    376#endif
    377
    378end:
    379    return g_test_run();
    380}