Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nft_set_pipapo: release elements in clone from abort path

New elements that reside in the clone are not released in case that the
transaction is aborted.

[16302.231754] ------------[ cut here ]------------
[16302.231756] WARNING: CPU: 0 PID: 100509 at net/netfilter/nf_tables_api.c:1864 nf_tables_chain_destroy+0x26/0x127 [nf_tables]
[...]
[16302.231882] CPU: 0 PID: 100509 Comm: nft Tainted: G W 5.19.0-rc3+ #155
[...]
[16302.231887] RIP: 0010:nf_tables_chain_destroy+0x26/0x127 [nf_tables]
[16302.231899] Code: f3 fe ff ff 41 55 41 54 55 53 48 8b 6f 10 48 89 fb 48 c7 c7 82 96 d9 a0 8b 55 50 48 8b 75 58 e8 de f5 92 e0 83 7d 50 00 74 09 <0f> 0b 5b 5d 41 5c 41 5d c3 4c 8b 65 00 48 8b 7d 08 49 39 fc 74 05
[...]
[16302.231917] Call Trace:
[16302.231919] <TASK>
[16302.231921] __nf_tables_abort.cold+0x23/0x28 [nf_tables]
[16302.231934] nf_tables_abort+0x30/0x50 [nf_tables]
[16302.231946] nfnetlink_rcv_batch+0x41a/0x840 [nfnetlink]
[16302.231952] ? __nla_validate_parse+0x48/0x190
[16302.231959] nfnetlink_rcv+0x110/0x129 [nfnetlink]
[16302.231963] netlink_unicast+0x211/0x340
[16302.231969] netlink_sendmsg+0x21e/0x460

Add nft_set_pipapo_match_destroy() helper function to release the
elements in the lookup tables.

Stefano Brivio says: "We additionally look for elements pointers in the
cloned matching data if priv->dirty is set, because that means that
cloned data might point to additional elements we did not commit to the
working copy yet (such as the abort path case, but perhaps not limited
to it)."

Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+33 -15
+33 -15
net/netfilter/nft_set_pipapo.c
··· 2125 2125 } 2126 2126 2127 2127 /** 2128 + * nft_set_pipapo_match_destroy() - Destroy elements from key mapping array 2129 + * @set: nftables API set representation 2130 + * @m: matching data pointing to key mapping array 2131 + */ 2132 + static void nft_set_pipapo_match_destroy(const struct nft_set *set, 2133 + struct nft_pipapo_match *m) 2134 + { 2135 + struct nft_pipapo_field *f; 2136 + int i, r; 2137 + 2138 + for (i = 0, f = m->f; i < m->field_count - 1; i++, f++) 2139 + ; 2140 + 2141 + for (r = 0; r < f->rules; r++) { 2142 + struct nft_pipapo_elem *e; 2143 + 2144 + if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e) 2145 + continue; 2146 + 2147 + e = f->mt[r].e; 2148 + 2149 + nft_set_elem_destroy(set, e, true); 2150 + } 2151 + } 2152 + 2153 + /** 2128 2154 * nft_pipapo_destroy() - Free private data for set and all committed elements 2129 2155 * @set: nftables API set representation 2130 2156 */ ··· 2158 2132 { 2159 2133 struct nft_pipapo *priv = nft_set_priv(set); 2160 2134 struct nft_pipapo_match *m; 2161 - struct nft_pipapo_field *f; 2162 - int i, r, cpu; 2135 + int cpu; 2163 2136 2164 2137 m = rcu_dereference_protected(priv->match, true); 2165 2138 if (m) { 2166 2139 rcu_barrier(); 2167 2140 2168 - for (i = 0, f = m->f; i < m->field_count - 1; i++, f++) 2169 - ; 2170 - 2171 - for (r = 0; r < f->rules; r++) { 2172 - struct nft_pipapo_elem *e; 2173 - 2174 - if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e) 2175 - continue; 2176 - 2177 - e = f->mt[r].e; 2178 - 2179 - nft_set_elem_destroy(set, e, true); 2180 - } 2141 + nft_set_pipapo_match_destroy(set, m); 2181 2142 2182 2143 #ifdef NFT_PIPAPO_ALIGN 2183 2144 free_percpu(m->scratch_aligned); ··· 2178 2165 } 2179 2166 2180 2167 if (priv->clone) { 2168 + m = priv->clone; 2169 + 2170 + if (priv->dirty) 2171 + nft_set_pipapo_match_destroy(set, m); 2172 + 2181 2173 #ifdef NFT_PIPAPO_ALIGN 2182 2174 free_percpu(priv->clone->scratch_aligned); 2183 2175 #endif