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