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