xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/setsockopt/setsockopt06.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 SUSE LLC <[email protected]>
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 <[email protected]>
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 
28 static int sock = -1;
29 static unsigned int pagesize;
30 static struct tst_fzsync_pair fzsync_pair;
31 
setup(void)32 static 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 
thread_run(void * arg)41 static 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 
run(void)65 static 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 
cleanup(void)102 static void cleanup(void)
103 {
104 	tst_fzsync_pair_cleanup(&fzsync_pair);
105 
106 	if (sock >= 0)
107 		SAFE_CLOSE(sock);
108 }
109 
110 static 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