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