diff options
author | Francesco Ruggeri <fruggeri@aristanetworks.com> | 2015-05-17 17:30:31 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-05-20 07:46:48 -0400 |
commit | 3bfe049807c240344b407e3cfb74544927359817 (patch) | |
tree | 22abdea7b3d64fbf55a028afc0066ddc9ca40235 | |
parent | 13c3ed6a92724d8c8cb148a14b0ae190ddfe7413 (diff) |
netfilter: nfnetlink_{log,queue}: Register pernet in first place
nfnetlink_{log,queue}_init() register the netlink callback nf*_rcv_nl_event
before registering the pernet_subsys, but the callback relies on data
structures allocated by pernet init functions.
When nfnetlink_{log,queue} is loaded, if a netlink message is received after
the netlink callback is registered but before the pernet_subsys is registered,
the kernel will panic in the sequence
nfulnl_rcv_nl_event
nfnl_log_pernet
net_generic
BUG_ON(id == 0) where id is nfnl_log_net_id.
The panic can be easily reproduced in 4.0.3 by:
while true ;do modprobe nfnetlink_log ; rmmod nfnetlink_log ; done &
while true ;do ip netns add dummy ; ip netns del dummy ; done &
This patch moves register_pernet_subsys to earlier in nfnetlink_log_init.
Notice that the BUG_ON hit in 4.0.3 was recently removed in 2591ffd308
["netns: remove BUG_ONs from net_generic()"].
Signed-off-by: Francesco Ruggeri <fruggeri@arista.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 19 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue_core.c | 18 |
2 files changed, 19 insertions, 18 deletions
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 3ad91266c821..4ef1fae8445e 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -1073,7 +1073,13 @@ static struct pernet_operations nfnl_log_net_ops = { | |||
1073 | 1073 | ||
1074 | static int __init nfnetlink_log_init(void) | 1074 | static int __init nfnetlink_log_init(void) |
1075 | { | 1075 | { |
1076 | int status = -ENOMEM; | 1076 | int status; |
1077 | |||
1078 | status = register_pernet_subsys(&nfnl_log_net_ops); | ||
1079 | if (status < 0) { | ||
1080 | pr_err("failed to register pernet ops\n"); | ||
1081 | goto out; | ||
1082 | } | ||
1077 | 1083 | ||
1078 | netlink_register_notifier(&nfulnl_rtnl_notifier); | 1084 | netlink_register_notifier(&nfulnl_rtnl_notifier); |
1079 | status = nfnetlink_subsys_register(&nfulnl_subsys); | 1085 | status = nfnetlink_subsys_register(&nfulnl_subsys); |
@@ -1088,28 +1094,23 @@ static int __init nfnetlink_log_init(void) | |||
1088 | goto cleanup_subsys; | 1094 | goto cleanup_subsys; |
1089 | } | 1095 | } |
1090 | 1096 | ||
1091 | status = register_pernet_subsys(&nfnl_log_net_ops); | ||
1092 | if (status < 0) { | ||
1093 | pr_err("failed to register pernet ops\n"); | ||
1094 | goto cleanup_logger; | ||
1095 | } | ||
1096 | return status; | 1097 | return status; |
1097 | 1098 | ||
1098 | cleanup_logger: | ||
1099 | nf_log_unregister(&nfulnl_logger); | ||
1100 | cleanup_subsys: | 1099 | cleanup_subsys: |
1101 | nfnetlink_subsys_unregister(&nfulnl_subsys); | 1100 | nfnetlink_subsys_unregister(&nfulnl_subsys); |
1102 | cleanup_netlink_notifier: | 1101 | cleanup_netlink_notifier: |
1103 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); | 1102 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); |
1103 | unregister_pernet_subsys(&nfnl_log_net_ops); | ||
1104 | out: | ||
1104 | return status; | 1105 | return status; |
1105 | } | 1106 | } |
1106 | 1107 | ||
1107 | static void __exit nfnetlink_log_fini(void) | 1108 | static void __exit nfnetlink_log_fini(void) |
1108 | { | 1109 | { |
1109 | unregister_pernet_subsys(&nfnl_log_net_ops); | ||
1110 | nf_log_unregister(&nfulnl_logger); | 1110 | nf_log_unregister(&nfulnl_logger); |
1111 | nfnetlink_subsys_unregister(&nfulnl_subsys); | 1111 | nfnetlink_subsys_unregister(&nfulnl_subsys); |
1112 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); | 1112 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); |
1113 | unregister_pernet_subsys(&nfnl_log_net_ops); | ||
1113 | } | 1114 | } |
1114 | 1115 | ||
1115 | MODULE_DESCRIPTION("netfilter userspace logging"); | 1116 | MODULE_DESCRIPTION("netfilter userspace logging"); |
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 0b98c7420239..11c7682fa0ea 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c | |||
@@ -1317,7 +1317,13 @@ static struct pernet_operations nfnl_queue_net_ops = { | |||
1317 | 1317 | ||
1318 | static int __init nfnetlink_queue_init(void) | 1318 | static int __init nfnetlink_queue_init(void) |
1319 | { | 1319 | { |
1320 | int status = -ENOMEM; | 1320 | int status; |
1321 | |||
1322 | status = register_pernet_subsys(&nfnl_queue_net_ops); | ||
1323 | if (status < 0) { | ||
1324 | pr_err("nf_queue: failed to register pernet ops\n"); | ||
1325 | goto out; | ||
1326 | } | ||
1321 | 1327 | ||
1322 | netlink_register_notifier(&nfqnl_rtnl_notifier); | 1328 | netlink_register_notifier(&nfqnl_rtnl_notifier); |
1323 | status = nfnetlink_subsys_register(&nfqnl_subsys); | 1329 | status = nfnetlink_subsys_register(&nfqnl_subsys); |
@@ -1326,19 +1332,13 @@ static int __init nfnetlink_queue_init(void) | |||
1326 | goto cleanup_netlink_notifier; | 1332 | goto cleanup_netlink_notifier; |
1327 | } | 1333 | } |
1328 | 1334 | ||
1329 | status = register_pernet_subsys(&nfnl_queue_net_ops); | ||
1330 | if (status < 0) { | ||
1331 | pr_err("nf_queue: failed to register pernet ops\n"); | ||
1332 | goto cleanup_subsys; | ||
1333 | } | ||
1334 | register_netdevice_notifier(&nfqnl_dev_notifier); | 1335 | register_netdevice_notifier(&nfqnl_dev_notifier); |
1335 | nf_register_queue_handler(&nfqh); | 1336 | nf_register_queue_handler(&nfqh); |
1336 | return status; | 1337 | return status; |
1337 | 1338 | ||
1338 | cleanup_subsys: | ||
1339 | nfnetlink_subsys_unregister(&nfqnl_subsys); | ||
1340 | cleanup_netlink_notifier: | 1339 | cleanup_netlink_notifier: |
1341 | netlink_unregister_notifier(&nfqnl_rtnl_notifier); | 1340 | netlink_unregister_notifier(&nfqnl_rtnl_notifier); |
1341 | out: | ||
1342 | return status; | 1342 | return status; |
1343 | } | 1343 | } |
1344 | 1344 | ||
@@ -1346,9 +1346,9 @@ static void __exit nfnetlink_queue_fini(void) | |||
1346 | { | 1346 | { |
1347 | nf_unregister_queue_handler(); | 1347 | nf_unregister_queue_handler(); |
1348 | unregister_netdevice_notifier(&nfqnl_dev_notifier); | 1348 | unregister_netdevice_notifier(&nfqnl_dev_notifier); |
1349 | unregister_pernet_subsys(&nfnl_queue_net_ops); | ||
1350 | nfnetlink_subsys_unregister(&nfqnl_subsys); | 1349 | nfnetlink_subsys_unregister(&nfqnl_subsys); |
1351 | netlink_unregister_notifier(&nfqnl_rtnl_notifier); | 1350 | netlink_unregister_notifier(&nfqnl_rtnl_notifier); |
1351 | unregister_pernet_subsys(&nfnl_queue_net_ops); | ||
1352 | 1352 | ||
1353 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 1353 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
1354 | } | 1354 | } |