aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancesco Ruggeri <fruggeri@aristanetworks.com>2015-05-17 17:30:31 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2015-05-20 07:46:48 -0400
commit3bfe049807c240344b407e3cfb74544927359817 (patch)
tree22abdea7b3d64fbf55a028afc0066ddc9ca40235
parent13c3ed6a92724d8c8cb148a14b0ae190ddfe7413 (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.c19
-rw-r--r--net/netfilter/nfnetlink_queue_core.c18
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
1074static int __init nfnetlink_log_init(void) 1074static 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
1098cleanup_logger:
1099 nf_log_unregister(&nfulnl_logger);
1100cleanup_subsys: 1099cleanup_subsys:
1101 nfnetlink_subsys_unregister(&nfulnl_subsys); 1100 nfnetlink_subsys_unregister(&nfulnl_subsys);
1102cleanup_netlink_notifier: 1101cleanup_netlink_notifier:
1103 netlink_unregister_notifier(&nfulnl_rtnl_notifier); 1102 netlink_unregister_notifier(&nfulnl_rtnl_notifier);
1103 unregister_pernet_subsys(&nfnl_log_net_ops);
1104out:
1104 return status; 1105 return status;
1105} 1106}
1106 1107
1107static void __exit nfnetlink_log_fini(void) 1108static 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
1115MODULE_DESCRIPTION("netfilter userspace logging"); 1116MODULE_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
1318static int __init nfnetlink_queue_init(void) 1318static 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
1338cleanup_subsys:
1339 nfnetlink_subsys_unregister(&nfqnl_subsys);
1340cleanup_netlink_notifier: 1339cleanup_netlink_notifier:
1341 netlink_unregister_notifier(&nfqnl_rtnl_notifier); 1340 netlink_unregister_notifier(&nfqnl_rtnl_notifier);
1341out:
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}