Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter/IPVS fixes for net 1) netlink socket notifier might win race to release objects that are already pending to be released via commit release path, reported by syzbot. 2) No need to postpone flow rule release to commit release path, this triggered the syzbot report, complementary fix to previous patch. 3) Use explicit signed chars in IPVS to unbreak arm, from Jason A. Donenfeld. 4) Missing check for proc entry creation failure in IPVS, from Zhengchao Shao. 5) Incorrect error path handling when BPF NAT fails to register, from Chen Zhongjin. 6) Prevent huge memory allocation in ipset hash types, from Jozsef Kadlecsik. Except the incorrect BPF NAT error path which is broken in 6.1-rc, anything else has been broken for several releases. * git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: ipset: enforce documented limit to prevent allocating huge memory netfilter: nf_nat: Fix possible memory leak in nf_nat_init() ipvs: fix WARNING in ip_vs_app_net_cleanup() ipvs: fix WARNING in __ip_vs_cleanup_batch() ipvs: use explicitly signed chars netfilter: nf_tables: release flow rule object from commit path netfilter: nf_tables: netlink notifier might race to release objects ==================== Link: https://lore.kernel.org/r/20221102184659.2502-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
dac1dc7e4d
@ -42,31 +42,8 @@
|
||||
#define AHASH_MAX_SIZE (6 * AHASH_INIT_SIZE)
|
||||
/* Max muber of elements in the array block when tuned */
|
||||
#define AHASH_MAX_TUNED 64
|
||||
|
||||
#define AHASH_MAX(h) ((h)->bucketsize)
|
||||
|
||||
/* Max number of elements can be tuned */
|
||||
#ifdef IP_SET_HASH_WITH_MULTI
|
||||
static u8
|
||||
tune_bucketsize(u8 curr, u32 multi)
|
||||
{
|
||||
u32 n;
|
||||
|
||||
if (multi < curr)
|
||||
return curr;
|
||||
|
||||
n = curr + AHASH_INIT_SIZE;
|
||||
/* Currently, at listing one hash bucket must fit into a message.
|
||||
* Therefore we have a hard limit here.
|
||||
*/
|
||||
return n > curr && n <= AHASH_MAX_TUNED ? n : curr;
|
||||
}
|
||||
#define TUNE_BUCKETSIZE(h, multi) \
|
||||
((h)->bucketsize = tune_bucketsize((h)->bucketsize, multi))
|
||||
#else
|
||||
#define TUNE_BUCKETSIZE(h, multi)
|
||||
#endif
|
||||
|
||||
/* A hash bucket */
|
||||
struct hbucket {
|
||||
struct rcu_head rcu; /* for call_rcu */
|
||||
@ -936,7 +913,12 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
||||
goto set_full;
|
||||
/* Create a new slot */
|
||||
if (n->pos >= n->size) {
|
||||
TUNE_BUCKETSIZE(h, multi);
|
||||
#ifdef IP_SET_HASH_WITH_MULTI
|
||||
if (h->bucketsize >= AHASH_MAX_TUNED)
|
||||
goto set_full;
|
||||
else if (h->bucketsize < multi)
|
||||
h->bucketsize += AHASH_INIT_SIZE;
|
||||
#endif
|
||||
if (n->size >= AHASH_MAX(h)) {
|
||||
/* Trigger rehashing */
|
||||
mtype_data_next(&h->next, d);
|
||||
|
@ -599,13 +599,19 @@ static const struct seq_operations ip_vs_app_seq_ops = {
|
||||
int __net_init ip_vs_app_net_init(struct netns_ipvs *ipvs)
|
||||
{
|
||||
INIT_LIST_HEAD(&ipvs->app_list);
|
||||
proc_create_net("ip_vs_app", 0, ipvs->net->proc_net, &ip_vs_app_seq_ops,
|
||||
sizeof(struct seq_net_private));
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create_net("ip_vs_app", 0, ipvs->net->proc_net,
|
||||
&ip_vs_app_seq_ops,
|
||||
sizeof(struct seq_net_private)))
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __net_exit ip_vs_app_net_cleanup(struct netns_ipvs *ipvs)
|
||||
{
|
||||
unregister_ip_vs_app(ipvs, NULL /* all */);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("ip_vs_app", ipvs->net->proc_net);
|
||||
#endif
|
||||
}
|
||||
|
@ -1265,8 +1265,8 @@ static inline int todrop_entry(struct ip_vs_conn *cp)
|
||||
* The drop rate array needs tuning for real environments.
|
||||
* Called from timer bh only => no locking
|
||||
*/
|
||||
static const char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
static char todrop_counter[9] = {0};
|
||||
static const signed char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
static signed char todrop_counter[9] = {0};
|
||||
int i;
|
||||
|
||||
/* if the conn entry hasn't lasted for 60 seconds, don't drop it.
|
||||
@ -1447,20 +1447,36 @@ int __net_init ip_vs_conn_net_init(struct netns_ipvs *ipvs)
|
||||
{
|
||||
atomic_set(&ipvs->conn_count, 0);
|
||||
|
||||
proc_create_net("ip_vs_conn", 0, ipvs->net->proc_net,
|
||||
&ip_vs_conn_seq_ops, sizeof(struct ip_vs_iter_state));
|
||||
proc_create_net("ip_vs_conn_sync", 0, ipvs->net->proc_net,
|
||||
&ip_vs_conn_sync_seq_ops,
|
||||
sizeof(struct ip_vs_iter_state));
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create_net("ip_vs_conn", 0, ipvs->net->proc_net,
|
||||
&ip_vs_conn_seq_ops,
|
||||
sizeof(struct ip_vs_iter_state)))
|
||||
goto err_conn;
|
||||
|
||||
if (!proc_create_net("ip_vs_conn_sync", 0, ipvs->net->proc_net,
|
||||
&ip_vs_conn_sync_seq_ops,
|
||||
sizeof(struct ip_vs_iter_state)))
|
||||
goto err_conn_sync;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
err_conn_sync:
|
||||
remove_proc_entry("ip_vs_conn", ipvs->net->proc_net);
|
||||
err_conn:
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __net_exit ip_vs_conn_net_cleanup(struct netns_ipvs *ipvs)
|
||||
{
|
||||
/* flush all the connection entries first */
|
||||
ip_vs_conn_flush(ipvs);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("ip_vs_conn", ipvs->net->proc_net);
|
||||
remove_proc_entry("ip_vs_conn_sync", ipvs->net->proc_net);
|
||||
#endif
|
||||
}
|
||||
|
||||
int __init ip_vs_conn_init(void)
|
||||
|
@ -1152,7 +1152,16 @@ static int __init nf_nat_init(void)
|
||||
WARN_ON(nf_nat_hook != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_hook, &nat_hook);
|
||||
|
||||
return register_nf_nat_bpf();
|
||||
ret = register_nf_nat_bpf();
|
||||
if (ret < 0) {
|
||||
RCU_INIT_POINTER(nf_nat_hook, NULL);
|
||||
nf_ct_helper_expectfn_unregister(&follow_master_nat);
|
||||
synchronize_net();
|
||||
unregister_pernet_subsys(&nat_net_ops);
|
||||
kvfree(nf_nat_bysource);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit nf_nat_cleanup(void)
|
||||
|
@ -8465,9 +8465,6 @@ static void nft_commit_release(struct nft_trans *trans)
|
||||
nf_tables_chain_destroy(&trans->ctx);
|
||||
break;
|
||||
case NFT_MSG_DELRULE:
|
||||
if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
|
||||
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
|
||||
|
||||
nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
|
||||
break;
|
||||
case NFT_MSG_DELSET:
|
||||
@ -8973,6 +8970,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
||||
nft_rule_expr_deactivate(&trans->ctx,
|
||||
nft_trans_rule(trans),
|
||||
NFT_TRANS_COMMIT);
|
||||
|
||||
if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
|
||||
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
|
||||
break;
|
||||
case NFT_MSG_NEWSET:
|
||||
nft_clear(net, nft_trans_set(trans));
|
||||
@ -10030,6 +10030,8 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
|
||||
nft_net = nft_pernet(net);
|
||||
deleted = 0;
|
||||
mutex_lock(&nft_net->commit_mutex);
|
||||
if (!list_empty(&nf_tables_destroy_list))
|
||||
rcu_barrier();
|
||||
again:
|
||||
list_for_each_entry(table, &nft_net->tables, list) {
|
||||
if (nft_table_has_owner(table) &&
|
||||
|
Loading…
Reference in New Issue
Block a user