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