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