Skip to content

Commit 233bb97

Browse files
committed
netfilter: nft_set_pipapo: do not free live element
jira LE-2169 cve CVE-2024-26924 Rebuild_History Non-Buildable kernel-4.18.0-553.27.1.el8_10 commit-author Florian Westphal <[email protected]> commit 3cfc9ec 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/3cfc9ec0.failed Pablo reports a crash with large batches of elements with a back-to-back add/remove pattern. Quoting Pablo: add_elem("00000000") timeout 100 ms ... add_elem("0000000X") timeout 100 ms del_elem("0000000X") <---------------- delete one that was just added ... add_elem("00005000") timeout 100 ms 1) nft_pipapo_remove() removes element 0000000X Then, KASAN shows a splat. Looking at the remove function there is a chance that we will drop a rule that maps to a non-deactivated element. Removal happens in two steps, first we do a lookup for key k and return the to-be-removed element and mark it as inactive in the next generation. Then, in a second step, the element gets removed from the set/map. The _remove function does not work correctly if we have more than one element that share the same key. This can happen if we insert an element into a set when the set already holds an element with same key, but the element mapping to the existing key has timed out or is not active in the next generation. In such case its possible that removal will unmap the wrong element. If this happens, we will leak the non-deactivated element, it becomes unreachable. The element that got deactivated (and will be freed later) will remain reachable in the set data structure, this can result in a crash when such an element is retrieved during lookup (stale pointer). Add a check that the fully matching key does in fact map to the element that we have marked as inactive in the deactivation step. If not, we need to continue searching. Add a bug/warn trap at the end of the function as well, the remove function must not ever be called with an invisible/unreachable/non-existent element. v2: avoid uneeded temporary variable (Stefano) Fixes: 3c4287f ("nf_tables: Add set type for arbitrary concatenation of ranges") Reported-by: Pablo Neira Ayuso <[email protected]> Reviewed-by: Stefano Brivio <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]> (cherry picked from commit 3cfc9ec) Signed-off-by: Jonathan Maple <[email protected]> # Conflicts: # net/netfilter/nft_set_pipapo.c
1 parent 456bd2a commit 233bb97

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
netfilter: nft_set_pipapo: do not free live element
2+
3+
jira LE-2169
4+
cve CVE-2024-26924
5+
Rebuild_History Non-Buildable kernel-4.18.0-553.27.1.el8_10
6+
commit-author Florian Westphal <[email protected]>
7+
commit 3cfc9ec039af60dbd8965ae085b2c2ccdcfbe1cc
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/3cfc9ec0.failed
11+
12+
Pablo reports a crash with large batches of elements with a
13+
back-to-back add/remove pattern. Quoting Pablo:
14+
15+
add_elem("00000000") timeout 100 ms
16+
...
17+
add_elem("0000000X") timeout 100 ms
18+
del_elem("0000000X") <---------------- delete one that was just added
19+
...
20+
add_elem("00005000") timeout 100 ms
21+
22+
1) nft_pipapo_remove() removes element 0000000X
23+
Then, KASAN shows a splat.
24+
25+
Looking at the remove function there is a chance that we will drop a
26+
rule that maps to a non-deactivated element.
27+
28+
Removal happens in two steps, first we do a lookup for key k and return the
29+
to-be-removed element and mark it as inactive in the next generation.
30+
Then, in a second step, the element gets removed from the set/map.
31+
32+
The _remove function does not work correctly if we have more than one
33+
element that share the same key.
34+
35+
This can happen if we insert an element into a set when the set already
36+
holds an element with same key, but the element mapping to the existing
37+
key has timed out or is not active in the next generation.
38+
39+
In such case its possible that removal will unmap the wrong element.
40+
If this happens, we will leak the non-deactivated element, it becomes
41+
unreachable.
42+
43+
The element that got deactivated (and will be freed later) will
44+
remain reachable in the set data structure, this can result in
45+
a crash when such an element is retrieved during lookup (stale
46+
pointer).
47+
48+
Add a check that the fully matching key does in fact map to the element
49+
that we have marked as inactive in the deactivation step.
50+
If not, we need to continue searching.
51+
52+
Add a bug/warn trap at the end of the function as well, the remove
53+
function must not ever be called with an invisible/unreachable/non-existent
54+
element.
55+
56+
v2: avoid uneeded temporary variable (Stefano)
57+
58+
Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
59+
Reported-by: Pablo Neira Ayuso <[email protected]>
60+
Reviewed-by: Stefano Brivio <[email protected]>
61+
Signed-off-by: Florian Westphal <[email protected]>
62+
Signed-off-by: Pablo Neira Ayuso <[email protected]>
63+
(cherry picked from commit 3cfc9ec039af60dbd8965ae085b2c2ccdcfbe1cc)
64+
Signed-off-by: Jonathan Maple <[email protected]>
65+
66+
# Conflicts:
67+
# net/netfilter/nft_set_pipapo.c
68+
diff --cc net/netfilter/nft_set_pipapo.c
69+
index 4b6a6667d72b,eeaf05ffba95..000000000000
70+
--- a/net/netfilter/nft_set_pipapo.c
71+
+++ b/net/netfilter/nft_set_pipapo.c
72+
@@@ -1880,14 -2089,14 +1882,20 @@@ static void nft_pipapo_remove(const str
73+
rules_fx = f->mt[start].n;
74+
start = f->mt[start].to;
75+
76+
++<<<<<<< HEAD
77+
+ match_start += NFT_PIPAPO_GROUPS_PADDED_SIZE(f->groups);
78+
+ match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f->groups);
79+
+ }
80+
-
81+
- if (i == m->field_count) {
82+
- priv->dirty = true;
83+
- pipapo_drop(m, rulemap);
84+
- return;
85+
++=======
86+
+ match_start += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
87+
+ match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
88+
++>>>>>>> 3cfc9ec039af (netfilter: nft_set_pipapo: do not free live element)
89+
+
90+
+ if (last && f->mt[rulemap[i].to].e == e) {
91+
+ priv->dirty = true;
92+
+ pipapo_drop(m, rulemap);
93+
+ return;
94+
+ }
95+
}
96+
97+
first_rule += rules_f0;
98+
* Unmerged path net/netfilter/nft_set_pipapo.c

0 commit comments

Comments
 (0)