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

netfilter: nf_tables: avoid global info storage

This works because all accesses are currently serialized by nfnl
nf_tables subsys mutex.

If we want to have per-netns locking, we need to make this scratch
area pernetns or allocate it on demand.

This does the latter, its ~28kbyte but we can fallback to vmalloc
so it should be fine.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
2a43ecf9 be2ab5b4

+12 -16
+12 -16
net/netfilter/nf_tables_api.c
··· 2454 2454 2455 2455 #define NFT_RULE_MAXEXPRS 128 2456 2456 2457 - static struct nft_expr_info *info; 2458 - 2459 2457 static int nf_tables_newrule(struct net *net, struct sock *nlsk, 2460 2458 struct sk_buff *skb, const struct nlmsghdr *nlh, 2461 2459 const struct nlattr * const nla[], ··· 2461 2463 { 2462 2464 const struct nfgenmsg *nfmsg = nlmsg_data(nlh); 2463 2465 u8 genmask = nft_genmask_next(net); 2466 + struct nft_expr_info *info = NULL; 2464 2467 int family = nfmsg->nfgen_family; 2465 2468 struct nft_table *table; 2466 2469 struct nft_chain *chain; ··· 2532 2533 n = 0; 2533 2534 size = 0; 2534 2535 if (nla[NFTA_RULE_EXPRESSIONS]) { 2536 + info = kvmalloc_array(NFT_RULE_MAXEXPRS, 2537 + sizeof(struct nft_expr_info), 2538 + GFP_KERNEL); 2539 + if (!info) 2540 + return -ENOMEM; 2541 + 2535 2542 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) { 2536 2543 err = -EINVAL; 2537 2544 if (nla_type(tmp) != NFTA_LIST_ELEM) ··· 2630 2625 list_add_rcu(&rule->list, &chain->rules); 2631 2626 } 2632 2627 } 2628 + kvfree(info); 2633 2629 chain->use++; 2634 2630 2635 2631 if (net->nft.validate_state == NFT_VALIDATE_DO) ··· 2644 2638 if (info[i].ops != NULL) 2645 2639 module_put(info[i].ops->type->owner); 2646 2640 } 2641 + kvfree(info); 2647 2642 return err; 2648 2643 } 2649 2644 ··· 7210 7203 7211 7204 nft_chain_filter_init(); 7212 7205 7213 - info = kmalloc_array(NFT_RULE_MAXEXPRS, sizeof(struct nft_expr_info), 7214 - GFP_KERNEL); 7215 - if (info == NULL) { 7216 - err = -ENOMEM; 7217 - goto err1; 7218 - } 7219 - 7220 7206 err = nf_tables_core_module_init(); 7221 7207 if (err < 0) 7222 - goto err2; 7208 + return err; 7223 7209 7224 7210 err = nfnetlink_subsys_register(&nf_tables_subsys); 7225 7211 if (err < 0) 7226 - goto err3; 7212 + goto err; 7227 7213 7228 7214 register_netdevice_notifier(&nf_tables_flowtable_notifier); 7229 7215 7230 7216 return register_pernet_subsys(&nf_tables_net_ops); 7231 - err3: 7217 + err: 7232 7218 nf_tables_core_module_exit(); 7233 - err2: 7234 - kfree(info); 7235 - err1: 7236 7219 return err; 7237 7220 } 7238 7221 ··· 7234 7237 unregister_pernet_subsys(&nf_tables_net_ops); 7235 7238 rcu_barrier(); 7236 7239 nf_tables_core_module_exit(); 7237 - kfree(info); 7238 7240 } 7239 7241 7240 7242 module_init(nf_tables_module_init);