1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
4 */
5
6/*
7 * CVE-2016-8655
8 *
9 * Check for race condition between packet_set_ring() and tp_version. On some
10 * kernels, this may lead to use-after-free. Kernel crash fixed in:
11 *
12 *  commit 84ac7260236a49c79eede91617700174c2c19b0c
13 *  Author: Philip Pettersson <philip.pettersson@gmail.com>
14 *  Date:   Wed Nov 30 14:55:36 2016 -0800
15 *
16 *  packet: fix race condition in packet_set_ring
17 */
18
19#include <unistd.h>
20#include <sys/types.h>
21#include <sys/socket.h>
22
23#include "tst_test.h"
24#include "tst_fuzzy_sync.h"
25#include "lapi/if_packet.h"
26#include "lapi/if_ether.h"
27
28static int sock = -1;
29static unsigned int pagesize;
30static struct tst_fzsync_pair fzsync_pair;
31
32static void setup(void)
33{
34	pagesize = SAFE_SYSCONF(_SC_PAGESIZE);
35	tst_setup_netns();
36
37	fzsync_pair.exec_loops = 100000;
38	tst_fzsync_pair_init(&fzsync_pair);
39}
40
41static void *thread_run(void *arg)
42{
43	int ret;
44	struct tpacket_req3 req = {
45		.tp_block_size = pagesize,
46		.tp_block_nr = 1,
47		.tp_frame_size = pagesize,
48		.tp_frame_nr = 1,
49		.tp_retire_blk_tov = 100
50	};
51
52	while (tst_fzsync_run_b(&fzsync_pair)) {
53		tst_fzsync_start_race_b(&fzsync_pair);
54		ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req,
55			sizeof(req));
56		tst_fzsync_end_race_b(&fzsync_pair);
57
58		if (!ret)
59			tst_fzsync_pair_add_bias(&fzsync_pair, -10);
60	}
61
62	return arg;
63}
64
65static void run(void)
66{
67	int val1 = TPACKET_V1, val3 = TPACKET_V3;
68
69	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
70
71	while (tst_fzsync_run_a(&fzsync_pair)) {
72		sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
73		TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &val3,
74			sizeof(val3)));
75
76		if (TST_RET == -1 && TST_ERR == EINVAL)
77			tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
78
79		if (TST_RET) {
80			tst_brk(TBROK | TTERRNO,
81				"setsockopt(PACKET_VERSION, TPACKET_V3");
82		}
83
84		tst_fzsync_start_race_a(&fzsync_pair);
85		setsockopt(sock, SOL_PACKET, PACKET_VERSION, &val1,
86			sizeof(val1));
87		tst_fzsync_end_race_a(&fzsync_pair);
88		SAFE_CLOSE(sock);
89	}
90
91	/* setsockopt(PACKET_RX_RING) created a 100ms timer. Wait for it. */
92	usleep(300000);
93
94	if (tst_taint_check()) {
95		tst_res(TFAIL, "Kernel is vulnerable");
96		return;
97	}
98
99	tst_res(TPASS, "Nothing bad happened, probably");
100}
101
102static void cleanup(void)
103{
104	tst_fzsync_pair_cleanup(&fzsync_pair);
105
106	if (sock >= 0)
107		SAFE_CLOSE(sock);
108}
109
110static struct tst_test test = {
111	.test_all = run,
112	.setup = setup,
113	.cleanup = cleanup,
114	.max_runtime = 270,
115	.taint_check = TST_TAINT_W | TST_TAINT_D,
116	.needs_kconfigs = (const char *[]) {
117		"CONFIG_USER_NS=y",
118		"CONFIG_NET_NS=y",
119		NULL
120	},
121	.save_restore = (const struct tst_path_val[]) {
122		{"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP},
123		{}
124	},
125	.tags = (const struct tst_tag[]) {
126		{"linux-git", "84ac7260236a"},
127		{"CVE", "2016-8655"},
128		{}
129	}
130};
131