-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
netfilter: nf_conntrack: make event callback registration per-netns
This patch fixes an oops that can be triggered following this recipe: 0) make sure nf_conntrack_netlink and nf_conntrack_ipv4 are loaded. 1) container is started. 2) connect to it via lxc-console. 3) generate some traffic with the container to create some conntrack entries in its table. 4) stop the container: you hit one oops because the conntrack table cleanup tries to report the destroy event to user-space but the per-netns nfnetlink socket has already gone (as the nfnetlink socket is per-netns but event callback registration is global). To fix this situation, we make the ctnl_notifier per-netns so the callback is registered/unregistered if the container is created/destroyed. Alex Bligh and Alexey Dobriyan originally proposed one small patch to check if the nfnetlink socket is gone in nfnetlink_has_listeners, but this is a very visited path for events, thus, it may reduce performance and it looks a bit hackish to check for the nfnetlink socket only to workaround this situation. As a result, I decided to follow the bigger path choice, which seems to look nicer to me. Cc: Alexey Dobriyan <[email protected]> Reported-by: Alex Bligh <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
- Loading branch information
Showing
4 changed files
with
82 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
* (C) 2001 by Jay Schulist <[email protected]> | ||
* (C) 2002-2006 by Harald Welte <[email protected]> | ||
* (C) 2003 by Patrick Mchardy <[email protected]> | ||
* (C) 2005-2008 by Pablo Neira Ayuso <[email protected]> | ||
* (C) 2005-2011 by Pablo Neira Ayuso <[email protected]> | ||
* | ||
* Initial connection tracking via netlink development funded and | ||
* generally made possible by Network Robots, Inc. (www.networkrobots.com) | ||
|
@@ -2163,6 +2163,54 @@ MODULE_ALIAS("ip_conntrack_netlink"); | |
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); | ||
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP); | ||
|
||
static int __net_init ctnetlink_net_init(struct net *net) | ||
{ | ||
#ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
int ret; | ||
|
||
ret = nf_conntrack_register_notifier(net, &ctnl_notifier); | ||
if (ret < 0) { | ||
pr_err("ctnetlink_init: cannot register notifier.\n"); | ||
goto err_out; | ||
} | ||
|
||
ret = nf_ct_expect_register_notifier(net, &ctnl_notifier_exp); | ||
if (ret < 0) { | ||
pr_err("ctnetlink_init: cannot expect register notifier.\n"); | ||
goto err_unreg_notifier; | ||
} | ||
#endif | ||
return 0; | ||
|
||
#ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
err_unreg_notifier: | ||
nf_conntrack_unregister_notifier(net, &ctnl_notifier); | ||
err_out: | ||
return ret; | ||
#endif | ||
} | ||
|
||
static void ctnetlink_net_exit(struct net *net) | ||
{ | ||
#ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
nf_ct_expect_unregister_notifier(net, &ctnl_notifier_exp); | ||
nf_conntrack_unregister_notifier(net, &ctnl_notifier); | ||
#endif | ||
} | ||
|
||
static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list) | ||
{ | ||
struct net *net; | ||
|
||
list_for_each_entry(net, net_exit_list, exit_list) | ||
ctnetlink_net_exit(net); | ||
} | ||
|
||
static struct pernet_operations ctnetlink_net_ops = { | ||
.init = ctnetlink_net_init, | ||
.exit_batch = ctnetlink_net_exit_batch, | ||
}; | ||
|
||
static int __init ctnetlink_init(void) | ||
{ | ||
int ret; | ||
|
@@ -2180,28 +2228,15 @@ static int __init ctnetlink_init(void) | |
goto err_unreg_subsys; | ||
} | ||
|
||
#ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
ret = nf_conntrack_register_notifier(&ctnl_notifier); | ||
if (ret < 0) { | ||
pr_err("ctnetlink_init: cannot register notifier.\n"); | ||
if (register_pernet_subsys(&ctnetlink_net_ops)) { | ||
pr_err("ctnetlink_init: cannot register pernet operations\n"); | ||
goto err_unreg_exp_subsys; | ||
} | ||
|
||
ret = nf_ct_expect_register_notifier(&ctnl_notifier_exp); | ||
if (ret < 0) { | ||
pr_err("ctnetlink_init: cannot expect register notifier.\n"); | ||
goto err_unreg_notifier; | ||
} | ||
#endif | ||
|
||
return 0; | ||
|
||
#ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
err_unreg_notifier: | ||
nf_conntrack_unregister_notifier(&ctnl_notifier); | ||
err_unreg_exp_subsys: | ||
nfnetlink_subsys_unregister(&ctnl_exp_subsys); | ||
#endif | ||
err_unreg_subsys: | ||
nfnetlink_subsys_unregister(&ctnl_subsys); | ||
err_out: | ||
|
@@ -2213,11 +2248,7 @@ static void __exit ctnetlink_exit(void) | |
pr_info("ctnetlink: unregistering from nfnetlink.\n"); | ||
|
||
nf_ct_remove_userspace_expectations(); | ||
#ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
nf_ct_expect_unregister_notifier(&ctnl_notifier_exp); | ||
nf_conntrack_unregister_notifier(&ctnl_notifier); | ||
#endif | ||
|
||
unregister_pernet_subsys(&ctnetlink_net_ops); | ||
nfnetlink_subsys_unregister(&ctnl_exp_subsys); | ||
nfnetlink_subsys_unregister(&ctnl_subsys); | ||
} | ||
|