xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/setsockopt/setsockopt07.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-2017-1000111
8  *
9  * Check for race condition between packet_set_ring() and tp_reserve.
10  * The race allows you to set tp_reserve bigger than ring buffer size.
11  * While this will cause truncation of all incoming packets to 0 bytes,
12  * sanity checks in tpacket_rcv() prevent any exploitable buffer overflows.
13  * Race fixed in:
14  *
15  *  commit c27927e372f0785f3303e8fad94b85945e2c97b7 (HEAD)
16  *  Author: Willem de Bruijn <[email protected]>
17  *  Date:   Thu Aug 10 12:41:58 2017 -0400
18  *
19  *  packet: fix tp_reserve race in packet_set_ring
20  */
21 
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 
26 #include "tst_test.h"
27 #include "tst_fuzzy_sync.h"
28 #include "lapi/if_packet.h"
29 #include "lapi/if_ether.h"
30 
31 static int sock = -1;
32 static unsigned int pagesize;
33 static struct tst_fzsync_pair fzsync_pair;
34 
setup(void)35 static void setup(void)
36 {
37 	pagesize = SAFE_SYSCONF(_SC_PAGESIZE);
38 	tst_setup_netns();
39 
40 	/*
41 	 * Reproducing the bug on unpatched system takes <15 loops. The test
42 	 * is slow and the bug is mostly harmless so don't waste too much
43 	 * time.
44 	 */
45 	fzsync_pair.exec_loops = 500;
46 	tst_fzsync_pair_init(&fzsync_pair);
47 }
48 
thread_run(void * arg)49 static void *thread_run(void *arg)
50 {
51 	unsigned int val = 1 << 30;
52 
53 	while (tst_fzsync_run_b(&fzsync_pair)) {
54 		tst_fzsync_start_race_b(&fzsync_pair);
55 		setsockopt(sock, SOL_PACKET, PACKET_RESERVE, &val, sizeof(val));
56 		tst_fzsync_end_race_b(&fzsync_pair);
57 	}
58 
59 	return arg;
60 }
61 
run(void)62 static void run(void)
63 {
64 	unsigned int val, version = TPACKET_V3;
65 	socklen_t vsize = sizeof(val);
66 	struct tpacket_req3 req = {
67 		.tp_block_size = pagesize,
68 		.tp_block_nr = 1,
69 		.tp_frame_size = pagesize,
70 		.tp_frame_nr = 1,
71 		.tp_retire_blk_tov = 100
72 	};
73 
74 	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
75 
76 	while (tst_fzsync_run_a(&fzsync_pair)) {
77 		sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
78 		TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &version,
79 			sizeof(version)));
80 
81 		if (TST_RET == -1 && TST_ERR == EINVAL)
82 			tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
83 
84 		if (TST_RET) {
85 			tst_brk(TBROK | TTERRNO,
86 				"setsockopt(PACKET_VERSION, TPACKET_V3");
87 		}
88 
89 		tst_fzsync_start_race_a(&fzsync_pair);
90 		TEST(setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req,
91 			sizeof(req)));
92 		tst_fzsync_end_race_a(&fzsync_pair);
93 
94 		SAFE_GETSOCKOPT(sock, SOL_PACKET, PACKET_RESERVE, &val, &vsize);
95 		SAFE_CLOSE(sock);
96 
97 		if (TST_RET == -1 && TST_ERR == EINVAL) {
98 			tst_fzsync_pair_add_bias(&fzsync_pair, 1);
99 			continue;
100 		}
101 
102 		if (TST_RET) {
103 			tst_brk(TBROK | TTERRNO,
104 				"Invalid setsockopt() return value");
105 		}
106 
107 		if (val > req.tp_block_size) {
108 			tst_res(TFAIL, "PACKET_RESERVE checks bypassed");
109 			return;
110 		}
111 	}
112 
113 	tst_res(TPASS, "Cannot reproduce bug");
114 }
115 
cleanup(void)116 static void cleanup(void)
117 {
118 	tst_fzsync_pair_cleanup(&fzsync_pair);
119 
120 	if (sock >= 0)
121 		SAFE_CLOSE(sock);
122 }
123 
124 static struct tst_test test = {
125 	.test_all = run,
126 	.setup = setup,
127 	.cleanup = cleanup,
128 	.max_runtime = 150,
129 	.needs_kconfigs = (const char *[]) {
130 		"CONFIG_USER_NS=y",
131 		"CONFIG_NET_NS=y",
132 		NULL
133 	},
134 	.save_restore = (const struct tst_path_val[]) {
135 		{"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP},
136 		{}
137 	},
138 	.tags = (const struct tst_tag[]) {
139 		{"linux-git", "c27927e372f0"},
140 		{"CVE", "2017-1000111"},
141 		{}
142 	}
143 };
144