aboutsummaryrefslogtreecommitdiff
path: root/testcases/network/sockets/vsock01.c
blob: 7be71a83bb873d9e5d874e6215b0dc15fc304f9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2021 SUSE LLC <rpalethorpe@suse.com>
 */

/*\
 * [Description]
 *
 * Reproducer of CVE-2021-26708
 *
 * Based on POC https://github.com/jordan9001/vsock_poc.
 * Fuzzy Sync has been substituted for userfaultfd.
 *
 * Fixed by: c518adafa39f ("vsock: fix the race conditions in multi-transport support")
 *
 * Fixes: c0cfa2d8a788fcf4 ("vsock: add multi-transports support")
 *
 * Note that in many testing environments this will reproduce the race
 * silently. For the test to produce visible errors the loopback
 * transport should be registered, but not the g2h or h2g transports.
 *
 * One way to do this is to remove CONFIG_VIRTIO_VSOCKETS in the guest
 * or CONFIG_VHOST_VSOCK on the host. Or just unload the
 * modules. Alternatively run the test on a bare metal host which has
 * never started a VM.
 */

#include "config.h"
#include "tst_test.h"

#if HAVE_LINUX_VM_SOCKETS_H
#  include "tst_fuzzy_sync.h"
#  include "lapi/vm_sockets.h"

static struct tst_fzsync_pair pair;
static int vsock = -1;

static void *writer(LTP_ATTRIBUTE_UNUSED void *unused)
{
	const uint64_t b_buflen = 0x4141;

	while (tst_fzsync_run_b(&pair)) {
		tst_fzsync_start_race_b(&pair);
		SAFE_SETSOCKOPT(vsock, AF_VSOCK,
				SO_VM_SOCKETS_BUFFER_SIZE,
				&b_buflen, sizeof(b_buflen));
		tst_fzsync_end_race_b(&pair);
	}


	return NULL;
}

static void run(void)
{
	struct sockaddr_vm addr = { 0 };
	const struct timeval timeout = { 0, 1 };
	const uint64_t a_buflen = 0x4140;

	vsock = SAFE_SOCKET(AF_VSOCK, SOCK_STREAM, 0);
	SAFE_SETSOCKOPT(vsock, AF_VSOCK, SO_VM_SOCKETS_CONNECT_TIMEOUT,
			&timeout, sizeof(timeout));

	tst_res(TINFO, "Colliding transport change and setsockopt");
	tst_fzsync_pair_reset(&pair, writer);
	while (tst_fzsync_run_a(&pair)) {

		addr.svm_family = AF_VSOCK;
		addr.svm_port = 1234;
		addr.svm_cid = VMADDR_CID_LOCAL;

		if (!connect(vsock, (struct sockaddr *)&addr, sizeof(addr)))
			tst_brk(TCONF, "Connected to something on VSOCK loopback");

		if (errno == ENODEV)
			tst_brk(TCONF | TERRNO, "No loopback transport");

		SAFE_SETSOCKOPT(vsock, AF_VSOCK,
				SO_VM_SOCKETS_BUFFER_SIZE,
				&a_buflen, sizeof(a_buflen));

		addr.svm_family = AF_VSOCK;
		addr.svm_port = 5678;
		addr.svm_cid = VMADDR_CID_HOST + 3;

		tst_fzsync_start_race_a(&pair);
		TEST(connect(vsock, (struct sockaddr *)&addr, sizeof(addr)));
		tst_fzsync_end_race_a(&pair);

		if (!TST_RET) {
			tst_brk(TCONF,
				"g2h or h2g transport exists and we connected to something");
		}
	}

	SAFE_CLOSE(vsock);
	tst_res(TPASS, "Nothing bad happened, probably.");
}

static void cleanup(void)
{
	tst_fzsync_pair_cleanup(&pair);
}

static void setup(void)
{
	tst_fzsync_pair_init(&pair);
}

static struct tst_test test = {
	.test_all = run,
	.setup = setup,
	.cleanup = cleanup,
	.taint_check = TST_TAINT_W | TST_TAINT_D,
	.max_runtime = 60,
	.needs_kconfigs = (const char *[]) {
		"CONFIG_VSOCKETS_LOOPBACK",
		NULL
	},
	.tags = (const struct tst_tag[]) {
		{"linux-git", "c518adafa39f"},
		{"CVE", "CVE-2021-26708"},
		{}
	},
};

#else

TST_TEST_TCONF("No linux/vm_sockets.h");

#endif