1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2021 SUSE LLC <[email protected]>
4 */
5
6 /*\
7 * [Description]
8 *
9 * Reproducer of CVE-2021-26708
10 *
11 * Based on POC https://github.com/jordan9001/vsock_poc.
12 * Fuzzy Sync has been substituted for userfaultfd.
13 *
14 * Fixed by: c518adafa39f ("vsock: fix the race conditions in multi-transport support")
15 *
16 * Fixes: c0cfa2d8a788fcf4 ("vsock: add multi-transports support")
17 *
18 * Note that in many testing environments this will reproduce the race
19 * silently. For the test to produce visible errors the loopback
20 * transport should be registered, but not the g2h or h2g transports.
21 *
22 * One way to do this is to remove CONFIG_VIRTIO_VSOCKETS in the guest
23 * or CONFIG_VHOST_VSOCK on the host. Or just unload the
24 * modules. Alternatively run the test on a bare metal host which has
25 * never started a VM.
26 */
27
28 #include "config.h"
29 #include "tst_test.h"
30
31 #if HAVE_LINUX_VM_SOCKETS_H
32 # include "tst_fuzzy_sync.h"
33 # include "lapi/vm_sockets.h"
34
35 static struct tst_fzsync_pair pair;
36 static int vsock = -1;
37
writer(LTP_ATTRIBUTE_UNUSED void * unused)38 static void *writer(LTP_ATTRIBUTE_UNUSED void *unused)
39 {
40 const uint64_t b_buflen = 0x4141;
41
42 while (tst_fzsync_run_b(&pair)) {
43 tst_fzsync_start_race_b(&pair);
44 SAFE_SETSOCKOPT(vsock, AF_VSOCK,
45 SO_VM_SOCKETS_BUFFER_SIZE,
46 &b_buflen, sizeof(b_buflen));
47 tst_fzsync_end_race_b(&pair);
48 }
49
50
51 return NULL;
52 }
53
run(void)54 static void run(void)
55 {
56 struct sockaddr_vm addr = { 0 };
57 const struct timeval timeout = { 0, 1 };
58 const uint64_t a_buflen = 0x4140;
59
60 vsock = SAFE_SOCKET(AF_VSOCK, SOCK_STREAM, 0);
61 SAFE_SETSOCKOPT(vsock, AF_VSOCK, SO_VM_SOCKETS_CONNECT_TIMEOUT,
62 &timeout, sizeof(timeout));
63
64 tst_res(TINFO, "Colliding transport change and setsockopt");
65 tst_fzsync_pair_reset(&pair, writer);
66 while (tst_fzsync_run_a(&pair)) {
67
68 addr.svm_family = AF_VSOCK;
69 addr.svm_port = 1234;
70 addr.svm_cid = VMADDR_CID_LOCAL;
71
72 if (!connect(vsock, (struct sockaddr *)&addr, sizeof(addr)))
73 tst_brk(TCONF, "Connected to something on VSOCK loopback");
74
75 if (errno == ENODEV)
76 tst_brk(TCONF | TERRNO, "No loopback transport");
77
78 SAFE_SETSOCKOPT(vsock, AF_VSOCK,
79 SO_VM_SOCKETS_BUFFER_SIZE,
80 &a_buflen, sizeof(a_buflen));
81
82 addr.svm_family = AF_VSOCK;
83 addr.svm_port = 5678;
84 addr.svm_cid = VMADDR_CID_HOST + 3;
85
86 tst_fzsync_start_race_a(&pair);
87 TEST(connect(vsock, (struct sockaddr *)&addr, sizeof(addr)));
88 tst_fzsync_end_race_a(&pair);
89
90 if (!TST_RET) {
91 tst_brk(TCONF,
92 "g2h or h2g transport exists and we connected to something");
93 }
94 }
95
96 SAFE_CLOSE(vsock);
97 tst_res(TPASS, "Nothing bad happened, probably.");
98 }
99
cleanup(void)100 static void cleanup(void)
101 {
102 tst_fzsync_pair_cleanup(&pair);
103 }
104
setup(void)105 static void setup(void)
106 {
107 tst_fzsync_pair_init(&pair);
108 }
109
110 static struct tst_test test = {
111 .test_all = run,
112 .setup = setup,
113 .cleanup = cleanup,
114 .taint_check = TST_TAINT_W | TST_TAINT_D,
115 .max_runtime = 60,
116 .needs_kconfigs = (const char *[]) {
117 "CONFIG_VSOCKETS_LOOPBACK",
118 NULL
119 },
120 .tags = (const struct tst_tag[]) {
121 {"linux-git", "c518adafa39f"},
122 {"CVE", "CVE-2021-26708"},
123 {}
124 },
125 };
126
127 #else
128
129 TST_TEST_TCONF("No linux/vm_sockets.h");
130
131 #endif
132