netfilter: invoke synchronize_rcu after set the _hook_ to NULL
Otherwise, another CPU may access the invalid pointer. For example: CPU0 CPU1 - rcu_read_lock(); - pfunc = _hook_; _hook_ = NULL; - mod unload - - pfunc(); // invalid, panic - rcu_read_unlock(); So we must call synchronize_rcu() to wait the rcu reader to finish. Also note, in nf_nat_snmp_basic_fini, synchronize_rcu() will be invoked by later nf_conntrack_helper_unregister, but I'm inclined to add a explicit synchronize_rcu after set the nf_nat_snmp_hook to NULL. Depend on such obscure assumptions is not a good idea. Last, in nfnetlink_cttimeout, we use kfree_rcu to free the time object, so in cttimeout_exit, invoking rcu_barrier() is not necessary at all, remove it too. Signed-off-by: Liping Zhang <zlpnobody@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Родитель
f83bf8da11
Коммит
3b7dabf029
|
@ -1304,6 +1304,7 @@ static int __init nf_nat_snmp_basic_init(void)
|
||||||
static void __exit nf_nat_snmp_basic_fini(void)
|
static void __exit nf_nat_snmp_basic_fini(void)
|
||||||
{
|
{
|
||||||
RCU_INIT_POINTER(nf_nat_snmp_hook, NULL);
|
RCU_INIT_POINTER(nf_nat_snmp_hook, NULL);
|
||||||
|
synchronize_rcu();
|
||||||
nf_conntrack_helper_unregister(&snmp_trap_helper);
|
nf_conntrack_helper_unregister(&snmp_trap_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,7 @@ void nf_conntrack_unregister_notifier(struct net *net,
|
||||||
BUG_ON(notify != new);
|
BUG_ON(notify != new);
|
||||||
RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL);
|
RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL);
|
||||||
mutex_unlock(&nf_ct_ecache_mutex);
|
mutex_unlock(&nf_ct_ecache_mutex);
|
||||||
|
/* synchronize_rcu() is called from ctnetlink_exit. */
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
|
EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
|
||||||
|
|
||||||
|
@ -326,6 +327,7 @@ void nf_ct_expect_unregister_notifier(struct net *net,
|
||||||
BUG_ON(notify != new);
|
BUG_ON(notify != new);
|
||||||
RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL);
|
RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL);
|
||||||
mutex_unlock(&nf_ct_ecache_mutex);
|
mutex_unlock(&nf_ct_ecache_mutex);
|
||||||
|
/* synchronize_rcu() is called from ctnetlink_exit. */
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
|
EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
|
||||||
|
|
||||||
|
|
|
@ -3442,6 +3442,7 @@ static void __exit ctnetlink_exit(void)
|
||||||
#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
|
#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
|
||||||
RCU_INIT_POINTER(nfnl_ct_hook, NULL);
|
RCU_INIT_POINTER(nfnl_ct_hook, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
synchronize_rcu();
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(ctnetlink_init);
|
module_init(ctnetlink_init);
|
||||||
|
|
|
@ -903,6 +903,8 @@ static void __exit nf_nat_cleanup(void)
|
||||||
#ifdef CONFIG_XFRM
|
#ifdef CONFIG_XFRM
|
||||||
RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL);
|
RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
synchronize_rcu();
|
||||||
|
|
||||||
for (i = 0; i < NFPROTO_NUMPROTO; i++)
|
for (i = 0; i < NFPROTO_NUMPROTO; i++)
|
||||||
kfree(nf_nat_l4protos[i]);
|
kfree(nf_nat_l4protos[i]);
|
||||||
|
|
||||||
|
|
|
@ -646,8 +646,8 @@ static void __exit cttimeout_exit(void)
|
||||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||||
RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL);
|
RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL);
|
||||||
RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL);
|
RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL);
|
||||||
|
synchronize_rcu();
|
||||||
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
|
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
|
||||||
rcu_barrier();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(cttimeout_init);
|
module_init(cttimeout_init);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче