xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/setsockopt/setsockopt09.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2022 SUSE LLC
4  * Author: Marcos Paulo de Souza <[email protected]>
5  * LTP port: Martin Doucha <[email protected]>
6  */
7 
8 /*\
9  * [Description]
10  *
11  * Check for possible double free of rx_owner_map after switching packet
12  * interface versions aka CVE-2021-22600.
13  *
14  * Kernel crash fixed in:
15  *
16  *  commit ec6af094ea28f0f2dda1a6a33b14cd57e36a9755
17  *  Author: Willem de Bruijn <[email protected]>
18  *  Date:   Wed Dec 15 09:39:37 2021 -0500
19  *
20  *  net/packet: rx_owner_map depends on pg_vec
21  *
22  *  commit c800aaf8d869f2b9b47b10c5c312fe19f0a94042
23  *  Author: WANG Cong <[email protected]>
24  *  Date:   Mon Jul 24 10:07:32 2017 -0700
25  *
26  *  packet: fix use-after-free in prb_retire_rx_blk_timer_expired()
27  */
28 
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 
33 #include "tst_test.h"
34 #include "lapi/if_packet.h"
35 
36 static int sock = -1;
37 static unsigned int pagesize;
38 
setup(void)39 static void setup(void)
40 {
41 	pagesize = SAFE_SYSCONF(_SC_PAGESIZE);
42 	tst_setup_netns();
43 }
44 
run(void)45 static void run(void)
46 {
47 	unsigned int i, version = TPACKET_V3;
48 	struct tpacket_req3 req = {
49 		.tp_block_size = 4 * pagesize,
50 		.tp_frame_size = TPACKET_ALIGNMENT << 7,
51 		.tp_retire_blk_tov = 64,
52 		.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH
53 	};
54 
55 	for (i = 0; i < 5; i++) {
56 		req.tp_block_nr = 256;
57 		req.tp_frame_nr = req.tp_block_size * req.tp_block_nr;
58 		req.tp_frame_nr /= req.tp_frame_size;
59 
60 		sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, 0);
61 		TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &version,
62 			sizeof(version)));
63 
64 		if (TST_RET == -1 && TST_ERR == EINVAL)
65 			tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported");
66 
67 		if (TST_RET) {
68 			tst_brk(TBROK | TTERRNO,
69 				"setsockopt(PACKET_VERSION, TPACKET_V3)");
70 		}
71 
72 		/* Allocate owner map and then free it again */
73 		SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req,
74 			sizeof(req));
75 		req.tp_block_nr = 0;
76 		req.tp_frame_nr = 0;
77 		SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req,
78 			sizeof(req));
79 
80 		/* Switch packet version and trigger double free of owner map */
81 		SAFE_SETSOCKOPT_INT(sock, SOL_PACKET, PACKET_VERSION,
82 			TPACKET_V2);
83 		SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req,
84 			sizeof(req));
85 		SAFE_CLOSE(sock);
86 
87 		/* Wait for socket timer to expire just in case */
88 		usleep(req.tp_retire_blk_tov * 3000);
89 
90 		if (tst_taint_check()) {
91 			tst_res(TFAIL, "Kernel is vulnerable");
92 			return;
93 		}
94 	}
95 
96 	tst_res(TPASS, "Nothing bad happened, probably");
97 }
98 
cleanup(void)99 static void cleanup(void)
100 {
101 	if (sock >= 0)
102 		SAFE_CLOSE(sock);
103 }
104 
105 static struct tst_test test = {
106 	.test_all = run,
107 	.setup = setup,
108 	.cleanup = cleanup,
109 	.taint_check = TST_TAINT_W | TST_TAINT_D,
110 	.needs_kconfigs = (const char *[]) {
111 		"CONFIG_USER_NS=y",
112 		"CONFIG_NET_NS=y",
113 		NULL
114 	},
115 	.save_restore = (const struct tst_path_val[]) {
116 		{"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP},
117 		{}
118 	},
119 	.tags = (const struct tst_tag[]) {
120 		{"linux-git", "ec6af094ea28"},
121 		{"linux-git", "c800aaf8d869"},
122 		{"CVE", "2021-22600"},
123 		{}
124 	}
125 };
126