Skip to content

Commit b4324f1

Browse files
committed
netfilter: nft_set_pipapo: walk over current view on netlink dump
jira LE-2169 cve CVE-2024-27017 Rebuild_History Non-Buildable kernel-4.18.0-553.27.1.el8_10 commit-author Pablo Neira Ayuso <[email protected]> commit 29b359c Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-4.18.0-553.27.1.el8_10/29b359cf.failed The generation mask can be updated while netlink dump is in progress. The pipapo set backend walk iterator cannot rely on it to infer what view of the datastructure is to be used. Add notation to specify if user wants to read/update the set. Based on patch from Florian Westphal. Fixes: 2b84e21 ("netfilter: nft_set_pipapo: .walk does not deal with generations") Signed-off-by: Pablo Neira Ayuso <[email protected]> (cherry picked from commit 29b359c) Signed-off-by: Jonathan Maple <[email protected]> # Conflicts: # include/net/netfilter/nf_tables.h # net/netfilter/nf_tables_api.c # net/netfilter/nft_set_pipapo.c
1 parent a896979 commit b4324f1

File tree

1 file changed

+311
-0
lines changed

1 file changed

+311
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
netfilter: nft_set_pipapo: walk over current view on netlink dump
2+
3+
jira LE-2169
4+
cve CVE-2024-27017
5+
Rebuild_History Non-Buildable kernel-4.18.0-553.27.1.el8_10
6+
commit-author Pablo Neira Ayuso <[email protected]>
7+
commit 29b359cf6d95fd60730533f7f10464e95bd17c73
8+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
9+
Will be included in final tarball splat. Ref for failed cherry-pick at:
10+
ciq/ciq_backports/kernel-4.18.0-553.27.1.el8_10/29b359cf.failed
11+
12+
The generation mask can be updated while netlink dump is in progress.
13+
The pipapo set backend walk iterator cannot rely on it to infer what
14+
view of the datastructure is to be used. Add notation to specify if user
15+
wants to read/update the set.
16+
17+
Based on patch from Florian Westphal.
18+
19+
Fixes: 2b84e215f874 ("netfilter: nft_set_pipapo: .walk does not deal with generations")
20+
Signed-off-by: Pablo Neira Ayuso <[email protected]>
21+
(cherry picked from commit 29b359cf6d95fd60730533f7f10464e95bd17c73)
22+
Signed-off-by: Jonathan Maple <[email protected]>
23+
24+
# Conflicts:
25+
# include/net/netfilter/nf_tables.h
26+
# net/netfilter/nf_tables_api.c
27+
# net/netfilter/nft_set_pipapo.c
28+
diff --cc include/net/netfilter/nf_tables.h
29+
index dc1113771aec,3f1ed467f951..000000000000
30+
--- a/include/net/netfilter/nf_tables.h
31+
+++ b/include/net/netfilter/nf_tables.h
32+
@@@ -246,9 -295,31 +246,30 @@@ struct nft_set_elem
33+
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
34+
struct nft_data val;
35+
} key_end;
36+
- union {
37+
- u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
38+
- struct nft_data val;
39+
- } data;
40+
- struct nft_elem_priv *priv;
41+
+ void *priv;
42+
};
43+
44+
++<<<<<<< HEAD
45+
++=======
46+
+ static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
47+
+ {
48+
+ return (void *)priv;
49+
+ }
50+
+
51+
+
52+
+ /**
53+
+ * enum nft_iter_type - nftables set iterator type
54+
+ *
55+
+ * @NFT_ITER_READ: read-only iteration over set elements
56+
+ * @NFT_ITER_UPDATE: iteration under mutex to update set element state
57+
+ */
58+
+ enum nft_iter_type {
59+
+ NFT_ITER_UNSPEC,
60+
+ NFT_ITER_READ,
61+
+ NFT_ITER_UPDATE,
62+
+ };
63+
+
64+
++>>>>>>> 29b359cf6d95 (netfilter: nft_set_pipapo: walk over current view on netlink dump)
65+
struct nft_set;
66+
struct nft_set_iter {
67+
u8 genmask;
68+
diff --cc net/netfilter/nf_tables_api.c
69+
index a8d03cec29c3,a7a34db62ea9..000000000000
70+
--- a/net/netfilter/nf_tables_api.c
71+
+++ b/net/netfilter/nf_tables_api.c
72+
@@@ -490,6 -583,59 +490,62 @@@ static int nft_trans_set_add(const stru
73+
return 0;
74+
}
75+
76+
++<<<<<<< HEAD
77+
++=======
78+
+ static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
79+
+ struct nft_set *set)
80+
+ {
81+
+ return __nft_trans_set_add(ctx, msg_type, set, NULL);
82+
+ }
83+
+
84+
+ static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
85+
+ struct nft_set *set,
86+
+ const struct nft_set_iter *iter,
87+
+ struct nft_elem_priv *elem_priv)
88+
+ {
89+
+ nft_setelem_data_deactivate(ctx->net, set, elem_priv);
90+
+
91+
+ return 0;
92+
+ }
93+
+
94+
+ struct nft_set_elem_catchall {
95+
+ struct list_head list;
96+
+ struct rcu_head rcu;
97+
+ struct nft_elem_priv *elem;
98+
+ };
99+
+
100+
+ static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
101+
+ struct nft_set *set)
102+
+ {
103+
+ u8 genmask = nft_genmask_next(ctx->net);
104+
+ struct nft_set_elem_catchall *catchall;
105+
+ struct nft_set_ext *ext;
106+
+
107+
+ list_for_each_entry(catchall, &set->catchall_list, list) {
108+
+ ext = nft_set_elem_ext(set, catchall->elem);
109+
+ if (!nft_set_elem_active(ext, genmask))
110+
+ continue;
111+
+
112+
+ nft_setelem_data_deactivate(ctx->net, set, catchall->elem);
113+
+ break;
114+
+ }
115+
+ }
116+
+
117+
+ static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
118+
+ {
119+
+ struct nft_set_iter iter = {
120+
+ .genmask = nft_genmask_next(ctx->net),
121+
+ .type = NFT_ITER_UPDATE,
122+
+ .fn = nft_mapelem_deactivate,
123+
+ };
124+
+
125+
+ set->ops->walk(ctx, set, &iter);
126+
+ WARN_ON_ONCE(iter.err);
127+
+
128+
+ nft_map_catchall_deactivate(ctx, set);
129+
+ }
130+
+
131+
++>>>>>>> 29b359cf6d95 (netfilter: nft_set_pipapo: walk over current view on netlink dump)
132+
static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
133+
{
134+
int err;
135+
@@@ -4586,7 -5484,51 +4643,55 @@@ void nf_tables_unbind_set(const struct
136+
GFP_KERNEL);
137+
}
138+
}
139+
++<<<<<<< HEAD
140+
+EXPORT_SYMBOL_GPL(nf_tables_unbind_set);
141+
++=======
142+
+
143+
+ static void nft_setelem_data_activate(const struct net *net,
144+
+ const struct nft_set *set,
145+
+ struct nft_elem_priv *elem_priv);
146+
+
147+
+ static int nft_mapelem_activate(const struct nft_ctx *ctx,
148+
+ struct nft_set *set,
149+
+ const struct nft_set_iter *iter,
150+
+ struct nft_elem_priv *elem_priv)
151+
+ {
152+
+ nft_setelem_data_activate(ctx->net, set, elem_priv);
153+
+
154+
+ return 0;
155+
+ }
156+
+
157+
+ static void nft_map_catchall_activate(const struct nft_ctx *ctx,
158+
+ struct nft_set *set)
159+
+ {
160+
+ u8 genmask = nft_genmask_next(ctx->net);
161+
+ struct nft_set_elem_catchall *catchall;
162+
+ struct nft_set_ext *ext;
163+
+
164+
+ list_for_each_entry(catchall, &set->catchall_list, list) {
165+
+ ext = nft_set_elem_ext(set, catchall->elem);
166+
+ if (!nft_set_elem_active(ext, genmask))
167+
+ continue;
168+
+
169+
+ nft_setelem_data_activate(ctx->net, set, catchall->elem);
170+
+ break;
171+
+ }
172+
+ }
173+
+
174+
+ static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set)
175+
+ {
176+
+ struct nft_set_iter iter = {
177+
+ .genmask = nft_genmask_next(ctx->net),
178+
+ .type = NFT_ITER_UPDATE,
179+
+ .fn = nft_mapelem_activate,
180+
+ };
181+
+
182+
+ set->ops->walk(ctx, set, &iter);
183+
+ WARN_ON_ONCE(iter.err);
184+
+
185+
+ nft_map_catchall_activate(ctx, set);
186+
+ }
187+
++>>>>>>> 29b359cf6d95 (netfilter: nft_set_pipapo: walk over current view on netlink dump)
188+
189+
void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set)
190+
{
191+
@@@ -4925,7 -5893,9 +5030,8 @@@ static int nf_tables_dump_set(struct sk
192+
193+
args.cb = cb;
194+
args.skb = skb;
195+
- args.reset = dump_ctx->reset;
196+
args.iter.genmask = nft_genmask_cur(net);
197+
+ args.iter.type = NFT_ITER_READ;
198+
args.iter.skip = cb->args[0];
199+
args.iter.count = 0;
200+
args.iter.err = 0;
201+
@@@ -5978,13 -7335,72 +6084,76 @@@ static int nft_flush_set(const struct n
202+
return 0;
203+
}
204+
205+
-static int __nft_set_catchall_flush(const struct nft_ctx *ctx,
206+
- struct nft_set *set,
207+
- struct nft_elem_priv *elem_priv)
208+
+static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
209+
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
210+
+ const struct nlattr * const nla[],
211+
+ struct netlink_ext_ack *extack)
212+
{
213+
++<<<<<<< HEAD
214+
+ u8 genmask = nft_genmask_next(net);
215+
++=======
216+
+ struct nft_trans *trans;
217+
+
218+
+ trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
219+
+ sizeof(struct nft_trans_elem), GFP_KERNEL);
220+
+ if (!trans)
221+
+ return -ENOMEM;
222+
+
223+
+ nft_setelem_data_deactivate(ctx->net, set, elem_priv);
224+
+ nft_trans_elem_set(trans) = set;
225+
+ nft_trans_elem_priv(trans) = elem_priv;
226+
+ nft_trans_commit_list_add_tail(ctx->net, trans);
227+
+
228+
+ return 0;
229+
+ }
230+
+
231+
+ static int nft_set_catchall_flush(const struct nft_ctx *ctx,
232+
+ struct nft_set *set)
233+
+ {
234+
+ u8 genmask = nft_genmask_next(ctx->net);
235+
+ struct nft_set_elem_catchall *catchall;
236+
+ struct nft_set_ext *ext;
237+
+ int ret = 0;
238+
+
239+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
240+
+ ext = nft_set_elem_ext(set, catchall->elem);
241+
+ if (!nft_set_elem_active(ext, genmask))
242+
+ continue;
243+
+
244+
+ ret = __nft_set_catchall_flush(ctx, set, catchall->elem);
245+
+ if (ret < 0)
246+
+ break;
247+
+ nft_set_elem_change_active(ctx->net, set, ext);
248+
+ }
249+
+
250+
+ return ret;
251+
+ }
252+
+
253+
+ static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
254+
+ {
255+
+ struct nft_set_iter iter = {
256+
+ .genmask = genmask,
257+
+ .type = NFT_ITER_UPDATE,
258+
+ .fn = nft_setelem_flush,
259+
+ };
260+
+
261+
+ set->ops->walk(ctx, set, &iter);
262+
+ if (!iter.err)
263+
+ iter.err = nft_set_catchall_flush(ctx, set);
264+
+
265+
+ return iter.err;
266+
+ }
267+
+
268+
+ static int nf_tables_delsetelem(struct sk_buff *skb,
269+
+ const struct nfnl_info *info,
270+
+ const struct nlattr * const nla[])
271+
+ {
272+
+ struct netlink_ext_ack *extack = info->extack;
273+
+ u8 genmask = nft_genmask_next(info->net);
274+
+ u8 family = info->nfmsg->nfgen_family;
275+
+ struct net *net = info->net;
276+
++>>>>>>> 29b359cf6d95 (netfilter: nft_set_pipapo: walk over current view on netlink dump)
277+
const struct nlattr *attr;
278+
- struct nft_table *table;
279+
struct nft_set *set;
280+
struct nft_ctx ctx;
281+
int rem, err = 0;
282+
diff --cc net/netfilter/nft_set_pipapo.c
283+
index 4b6a6667d72b,11e44e4dfb1f..000000000000
284+
--- a/net/netfilter/nft_set_pipapo.c
285+
+++ b/net/netfilter/nft_set_pipapo.c
286+
@@@ -1908,13 -2115,14 +1908,21 @@@ static void nft_pipapo_walk(const struc
287+
struct nft_set_iter *iter)
288+
{
289+
struct nft_pipapo *priv = nft_set_priv(set);
290+
++<<<<<<< HEAD
291+
+ struct net *net = read_pnet(&set->net);
292+
+ struct nft_pipapo_match *m;
293+
+ struct nft_pipapo_field *f;
294+
+ int i, r;
295+
++=======
296+
+ const struct nft_pipapo_match *m;
297+
+ const struct nft_pipapo_field *f;
298+
+ unsigned int i, r;
299+
++>>>>>>> 29b359cf6d95 (netfilter: nft_set_pipapo: walk over current view on netlink dump)
300+
+
301+
+ WARN_ON_ONCE(iter->type == NFT_ITER_UNSPEC);
302+
303+
rcu_read_lock();
304+
- if (iter->genmask == nft_genmask_cur(net))
305+
+ if (iter->type == NFT_ITER_READ)
306+
m = rcu_dereference(priv->match);
307+
else
308+
m = priv->clone;
309+
* Unmerged path include/net/netfilter/nf_tables.h
310+
* Unmerged path net/netfilter/nf_tables_api.c
311+
* Unmerged path net/netfilter/nft_set_pipapo.c

0 commit comments

Comments
 (0)