• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2023 SUSE LLC
4  * Author: Marcos Paulo de Souza <mpdesouza@suse.com>
5  * LTP port: Martin Doucha <mdoucha@suse.cz>
6  */
7 
8 /*\
9  * [Description]
10  *
11  * CVE-2023-1829
12  *
13  * Test for use-after-free after removing tcindex traffic filter with certain
14  * parameters.
15  *
16  * Tcindex filter was removed in kernel v6.3:
17  * 8c710f75256b ("net/sched: Retire tcindex classifier")
18  */
19 
20 #include <linux/netlink.h>
21 #include <linux/pkt_sched.h>
22 #include <linux/pkt_cls.h>
23 #include "tst_test.h"
24 #include "tst_netlink.h"
25 #include "tst_netdevice.h"
26 #include "lapi/sched.h"
27 #include "lapi/if_ether.h"
28 #include "lapi/rtnetlink.h"
29 
30 #define DEVNAME "ltp_dummy1"
31 
32 #ifndef TCA_TCINDEX_MAX
33 enum {
34        TCA_TCINDEX_UNSPEC,
35        TCA_TCINDEX_HASH,
36        TCA_TCINDEX_MASK,
37        TCA_TCINDEX_SHIFT,
38        TCA_TCINDEX_FALL_THROUGH,
39        TCA_TCINDEX_CLASSID,
40        TCA_TCINDEX_POLICE,
41        TCA_TCINDEX_ACT,
42        __TCA_TCINDEX_MAX
43 };
44 
45 #define TCA_TCINDEX_MAX     (__TCA_TCINDEX_MAX - 1)
46 #endif
47 
48 
49 static const uint32_t qd_handle = TC_H_MAKE(1 << 16, 0);
50 static const uint32_t clsid = TC_H_MAKE(1 << 16, 1);
51 static const uint32_t shift = 10;
52 static const uint16_t mask = 0xffff;
53 
54 /* rtnetlink payloads */
55 static const struct tc_htb_glob qd_opt = {
56 	.rate2quantum = 10,
57 	.version = 3,
58 	.defcls = 30
59 };
60 static struct tc_htb_opt cls_opt = {};
61 
62 /* htb qdisc and class options */
63 static const struct tst_netlink_attr_list qd_config[] = {
64 	{TCA_OPTIONS, NULL, 0, (const struct tst_netlink_attr_list[]){
65 		{TCA_HTB_INIT, &qd_opt, sizeof(qd_opt), NULL},
66 		{0, NULL, -1, NULL}
67 	}},
68 	{0, NULL, -1, NULL}
69 };
70 static const struct tst_netlink_attr_list cls_config[] = {
71 	{TCA_OPTIONS, NULL, 0, (const struct tst_netlink_attr_list[]){
72 		{TCA_HTB_PARMS, &cls_opt, sizeof(cls_opt), NULL},
73 		{0, NULL, -1, NULL}
74 	}},
75 	{0, NULL, -1, NULL}
76 };
77 
78 /* tcindex filter options */
79 static const struct tst_netlink_attr_list f_config[] = {
80 	{TCA_OPTIONS, NULL, 0, (const struct tst_netlink_attr_list[]){
81 		{TCA_TCINDEX_MASK, &mask, sizeof(mask), NULL},
82 		{TCA_TCINDEX_SHIFT, &shift, sizeof(shift), NULL},
83 		{TCA_TCINDEX_CLASSID, &clsid, sizeof(clsid), NULL},
84 		{0, NULL, -1, NULL}
85 	}},
86 	{0, NULL, -1, NULL}
87 };
88 
setup(void)89 static void setup(void)
90 {
91 	tst_setup_netns();
92 	NETDEV_ADD_DEVICE(DEVNAME, "dummy");
93 
94 	cls_opt.rate.rate = cls_opt.ceil.rate = 256000;
95 	cls_opt.buffer = 1000000 * 1600 / cls_opt.rate.rate;
96 	cls_opt.cbuffer = 1000000 * 1600 / cls_opt.ceil.rate;
97 }
98 
run(void)99 static void run(void)
100 {
101 	int ret;
102 
103 	NETDEV_ADD_QDISC(DEVNAME, AF_UNSPEC, TC_H_ROOT, qd_handle, "htb",
104 		qd_config);
105 	NETDEV_ADD_TRAFFIC_CLASS(DEVNAME, qd_handle, clsid, "htb", cls_config);
106 	ret = NETDEV_ADD_TRAFFIC_FILTER_RET(DEVNAME, qd_handle, 10, ETH_P_IP,
107 		1, "tcindex", f_config);
108 	TST_ERR = tst_netlink_errno;
109 
110 	if (!ret && TST_ERR == ENOENT) {
111 		tst_res(TPASS | TTERRNO,
112 			"tcindex module is blacklisted or unavailable");
113 		return;
114 	}
115 
116 	if (!ret)
117 		tst_brk(TBROK | TTERRNO, "Cannot add tcindex filter");
118 
119 	NETDEV_REMOVE_TRAFFIC_FILTER(DEVNAME, qd_handle, 10, ETH_P_IP,
120 		1, "tcindex");
121 	ret = NETDEV_ADD_TRAFFIC_FILTER_RET(DEVNAME, qd_handle, 10, ETH_P_IP,
122 		1, "tcindex", f_config);
123 	TST_ERR = tst_netlink_errno;
124 	NETDEV_REMOVE_QDISC(DEVNAME, AF_UNSPEC, TC_H_ROOT, qd_handle, "htb");
125 
126 	if (ret)
127 		tst_res(TPASS, "Removing tcindex filter works correctly");
128 	else if (TST_ERR == EEXIST)
129 		tst_res(TFAIL, "Kernel traffic filter list is corrupted");
130 	else
131 		tst_brk(TBROK | TTERRNO, "Unexpected rtnetlink error");
132 }
133 
cleanup(void)134 static void cleanup(void)
135 {
136 	NETDEV_REMOVE_DEVICE(DEVNAME);
137 }
138 
139 static struct tst_test test = {
140 	.test_all = run,
141 	.setup = setup,
142 	.cleanup = cleanup,
143 	.taint_check = TST_TAINT_W | TST_TAINT_D,
144 	.needs_kconfigs = (const char *[]) {
145 		"CONFIG_VETH",
146 		"CONFIG_USER_NS=y",
147 		"CONFIG_NET_NS=y",
148 		"CONFIG_NET_SCH_HTB",
149 		"CONFIG_NET_CLS_TCINDEX",
150 		NULL
151 	},
152 	.save_restore = (const struct tst_path_val[]) {
153 		{"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP},
154 		{}
155 	},
156 	.needs_drivers = (const char *const []) {
157 		"dummy",
158 		NULL
159 	},
160 	.tags = (const struct tst_tag[]) {
161 		{"linux-git", "8c710f75256b"},
162 		{"CVE", "2023-1829"},
163 		{}
164 	}
165 };
166