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

Configure Feed

Select the types of activity you want to include in your feed.

Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

1) Missing proper sanitization for nft_set_desc_concat_parse().

2) Missing mutex in nf_tables pre_exit path.

3) Possible double hook unregistration from clean_net path.

4) Missing FLOWI_FLAG_ANYSRC flag in flowtable route lookup.
Fix incorrect source and destination address in case of NAT.
Patch from wenxu.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
netfilter: flowtable: fix nft_flow_route source address for nat case
netfilter: flowtable: fix missing FLOWI_FLAG_ANYSRC flag
netfilter: nf_tables: double hook unregistration in netns path
netfilter: nf_tables: hold mutex on netns pre_exit path
netfilter: nf_tables: sanitize nft_set_desc_concat_parse()
====================

Link: https://lore.kernel.org/r/20220531215839.84765-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+62 -19
+58 -17
net/netfilter/nf_tables_api.c
··· 222 222 } 223 223 224 224 static void nft_netdev_unregister_hooks(struct net *net, 225 - struct list_head *hook_list) 225 + struct list_head *hook_list, 226 + bool release_netdev) 226 227 { 227 - struct nft_hook *hook; 228 + struct nft_hook *hook, *next; 228 229 229 - list_for_each_entry(hook, hook_list, list) 230 + list_for_each_entry_safe(hook, next, hook_list, list) { 230 231 nf_unregister_net_hook(net, &hook->ops); 232 + if (release_netdev) { 233 + list_del(&hook->list); 234 + kfree_rcu(hook, rcu); 235 + } 236 + } 231 237 } 232 238 233 239 static int nf_tables_register_hook(struct net *net, ··· 259 253 return nf_register_net_hook(net, &basechain->ops); 260 254 } 261 255 262 - static void nf_tables_unregister_hook(struct net *net, 263 - const struct nft_table *table, 264 - struct nft_chain *chain) 256 + static void __nf_tables_unregister_hook(struct net *net, 257 + const struct nft_table *table, 258 + struct nft_chain *chain, 259 + bool release_netdev) 265 260 { 266 261 struct nft_base_chain *basechain; 267 262 const struct nf_hook_ops *ops; ··· 277 270 return basechain->type->ops_unregister(net, ops); 278 271 279 272 if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) 280 - nft_netdev_unregister_hooks(net, &basechain->hook_list); 273 + nft_netdev_unregister_hooks(net, &basechain->hook_list, 274 + release_netdev); 281 275 else 282 276 nf_unregister_net_hook(net, &basechain->ops); 277 + } 278 + 279 + static void nf_tables_unregister_hook(struct net *net, 280 + const struct nft_table *table, 281 + struct nft_chain *chain) 282 + { 283 + return __nf_tables_unregister_hook(net, table, chain, false); 283 284 } 284 285 285 286 static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans) ··· 4261 4246 u32 len; 4262 4247 int err; 4263 4248 4249 + if (desc->field_count >= ARRAY_SIZE(desc->field_len)) 4250 + return -E2BIG; 4251 + 4264 4252 err = nla_parse_nested_deprecated(tb, NFTA_SET_FIELD_MAX, attr, 4265 4253 nft_concat_policy, NULL); 4266 4254 if (err < 0) ··· 4273 4255 return -EINVAL; 4274 4256 4275 4257 len = ntohl(nla_get_be32(tb[NFTA_SET_FIELD_LEN])); 4276 - 4277 - if (len * BITS_PER_BYTE / 32 > NFT_REG32_COUNT) 4278 - return -E2BIG; 4258 + if (!len || len > U8_MAX) 4259 + return -EINVAL; 4279 4260 4280 4261 desc->field_len[desc->field_count++] = len; 4281 4262 ··· 4285 4268 const struct nlattr *nla) 4286 4269 { 4287 4270 struct nlattr *attr; 4288 - int rem, err; 4271 + u32 num_regs = 0; 4272 + int rem, err, i; 4289 4273 4290 4274 nla_for_each_nested(attr, nla, rem) { 4291 4275 if (nla_type(attr) != NFTA_LIST_ELEM) ··· 4296 4278 if (err < 0) 4297 4279 return err; 4298 4280 } 4281 + 4282 + for (i = 0; i < desc->field_count; i++) 4283 + num_regs += DIV_ROUND_UP(desc->field_len[i], sizeof(u32)); 4284 + 4285 + if (num_regs > NFT_REG32_COUNT) 4286 + return -E2BIG; 4299 4287 4300 4288 return 0; 4301 4289 } ··· 7322 7298 FLOW_BLOCK_UNBIND); 7323 7299 } 7324 7300 7301 + static void __nft_unregister_flowtable_net_hooks(struct net *net, 7302 + struct list_head *hook_list, 7303 + bool release_netdev) 7304 + { 7305 + struct nft_hook *hook, *next; 7306 + 7307 + list_for_each_entry_safe(hook, next, hook_list, list) { 7308 + nf_unregister_net_hook(net, &hook->ops); 7309 + if (release_netdev) { 7310 + list_del(&hook->list); 7311 + kfree_rcu(hook); 7312 + } 7313 + } 7314 + } 7315 + 7325 7316 static void nft_unregister_flowtable_net_hooks(struct net *net, 7326 7317 struct list_head *hook_list) 7327 7318 { 7328 - struct nft_hook *hook; 7329 - 7330 - list_for_each_entry(hook, hook_list, list) 7331 - nf_unregister_net_hook(net, &hook->ops); 7319 + __nft_unregister_flowtable_net_hooks(net, hook_list, false); 7332 7320 } 7333 7321 7334 7322 static int nft_register_flowtable_net_hooks(struct net *net, ··· 9782 9746 struct nft_chain *chain; 9783 9747 9784 9748 list_for_each_entry(chain, &table->chains, list) 9785 - nf_tables_unregister_hook(net, table, chain); 9749 + __nf_tables_unregister_hook(net, table, chain, true); 9786 9750 list_for_each_entry(flowtable, &table->flowtables, list) 9787 - nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list); 9751 + __nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list, 9752 + true); 9788 9753 } 9789 9754 9790 9755 static void __nft_release_hooks(struct net *net) ··· 9924 9887 9925 9888 static void __net_exit nf_tables_pre_exit_net(struct net *net) 9926 9889 { 9890 + struct nftables_pernet *nft_net = nft_pernet(net); 9891 + 9892 + mutex_lock(&nft_net->commit_mutex); 9927 9893 __nft_release_hooks(net); 9894 + mutex_unlock(&nft_net->commit_mutex); 9928 9895 } 9929 9896 9930 9897 static void __net_exit nf_tables_exit_net(struct net *net)
+4 -2
net/netfilter/nft_flow_offload.c
··· 232 232 switch (nft_pf(pkt)) { 233 233 case NFPROTO_IPV4: 234 234 fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; 235 - fl.u.ip4.saddr = ct->tuplehash[dir].tuple.dst.u3.ip; 235 + fl.u.ip4.saddr = ct->tuplehash[!dir].tuple.src.u3.ip; 236 236 fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex; 237 237 fl.u.ip4.flowi4_iif = this_dst->dev->ifindex; 238 238 fl.u.ip4.flowi4_tos = RT_TOS(ip_hdr(pkt->skb)->tos); 239 239 fl.u.ip4.flowi4_mark = pkt->skb->mark; 240 + fl.u.ip4.flowi4_flags = FLOWI_FLAG_ANYSRC; 240 241 break; 241 242 case NFPROTO_IPV6: 242 243 fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; 243 - fl.u.ip6.saddr = ct->tuplehash[dir].tuple.dst.u3.in6; 244 + fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.src.u3.in6; 244 245 fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex; 245 246 fl.u.ip6.flowi6_iif = this_dst->dev->ifindex; 246 247 fl.u.ip6.flowlabel = ip6_flowinfo(ipv6_hdr(pkt->skb)); 247 248 fl.u.ip6.flowi6_mark = pkt->skb->mark; 249 + fl.u.ip6.flowi6_flags = FLOWI_FLAG_ANYSRC; 248 250 break; 249 251 } 250 252