• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define _GNU_SOURCE
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sched.h>
24 
25 #include "tst_test.h"
26 #include "tst_fuzzy_sync.h"
27 #include "lapi/if_packet.h"
28 #include "lapi/if_ether.h"
29 
30 static int sock = -1;
31 static struct tst_fzsync_pair fzsync_pair;
32 
setup(void)33 static void setup(void)
34 {
35 	int real_uid = getuid();
36 	int real_gid = getgid();
37 
38 	SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10);
39 
40 	SAFE_UNSHARE(CLONE_NEWUSER);
41 	SAFE_UNSHARE(CLONE_NEWNET);
42 	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
43 	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid);
44 	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid);
45 
46 	fzsync_pair.exec_loops = 100000;
47 	fzsync_pair.exec_time_p = 0.9;
48 	tst_fzsync_pair_init(&fzsync_pair);
49 }
50 
thread_run(void * arg)51 static void *thread_run(void *arg)
52 {
53 	int ret;
54 	struct tpacket_req3 req = {
55 		.tp_block_size = 4096,
56 		.tp_block_nr = 1,
57 		.tp_frame_size = 4096,
58 		.tp_frame_nr = 1,
59 		.tp_retire_blk_tov = 100
60 	};
61 
62 	while (tst_fzsync_run_b(&fzsync_pair)) {
63 		tst_fzsync_start_race_b(&fzsync_pair);
64 		ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req,
65 			sizeof(req));
66 		tst_fzsync_end_race_b(&fzsync_pair);
67 
68 		if (!ret)
69 			tst_fzsync_pair_add_bias(&fzsync_pair, -10);
70 	}
71 
72 	return arg;
73 }
74 
run(void)75 static void run(void)
76 {
77 	int val1 = TPACKET_V1, val3 = TPACKET_V3;
78 
79 	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
80 
81 	while (tst_fzsync_run_a(&fzsync_pair)) {
82 		sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
83 		TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &val3,
84 			sizeof(val3)));
85 
86 		if (TST_RET == -1 && TST_ERR == EINVAL)
87 			tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
88 
89 		if (TST_RET) {
90 			tst_brk(TBROK | TTERRNO,
91 				"setsockopt(PACKET_VERSION, TPACKET_V3");
92 		}
93 
94 		tst_fzsync_start_race_a(&fzsync_pair);
95 		setsockopt(sock, SOL_PACKET, PACKET_VERSION, &val1,
96 			sizeof(val1));
97 		tst_fzsync_end_race_a(&fzsync_pair);
98 		SAFE_CLOSE(sock);
99 	}
100 
101 	/* setsockopt(PACKET_RX_RING) created a 100ms timer. Wait for it. */
102 	usleep(300000);
103 
104 	if (tst_taint_check()) {
105 		tst_res(TFAIL, "Kernel is vulnerable");
106 		return;
107 	}
108 
109 	tst_res(TPASS, "Nothing bad happened, probably");
110 }
111 
cleanup(void)112 static void cleanup(void)
113 {
114 	tst_fzsync_pair_cleanup(&fzsync_pair);
115 
116 	if (sock >= 0)
117 		SAFE_CLOSE(sock);
118 }
119 
120 static struct tst_test test = {
121 	.test_all = run,
122 	.setup = setup,
123 	.cleanup = cleanup,
124 	.taint_check = TST_TAINT_W | TST_TAINT_D,
125 	.needs_kconfigs = (const char *[]) {
126 		"CONFIG_USER_NS=y",
127 		"CONFIG_NET_NS=y",
128 		NULL
129 	},
130 	.save_restore = (const char * const[]) {
131 		"?/proc/sys/user/max_user_namespaces",
132 		NULL,
133 	},
134 	.tags = (const struct tst_tag[]) {
135 		{"linux-git", "84ac7260236a"},
136 		{"CVE", "2016-8655"},
137 		{}
138 	}
139 };
140