]> git.karo-electronics.de Git - linux-beck.git/commitdiff
netfilter: nf_queue: fix nf_queue_nf_hook_drop()
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 20 Jul 2015 10:55:02 +0000 (12:55 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 23 Jul 2015 14:17:58 +0000 (16:17 +0200)
This function reacquires the rtnl_lock() which is already held by
nf_unregister_hook().

This can be triggered via: modprobe nf_conntrack_ipv4 && rmmod nf_conntrack_ipv4

[  720.628746] INFO: task rmmod:3578 blocked for more than 120 seconds.
[  720.628749]       Not tainted 4.2.0-rc2+ #113
[  720.628752] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[  720.628754] rmmod           D ffff8800ca46fd58     0  3578   3571 0x00000080
[...]
[  720.628783] Call Trace:
[  720.628790]  [<ffffffff8152ea0b>] schedule+0x6b/0x90
[  720.628795]  [<ffffffff8152ecb3>] schedule_preempt_disabled+0x13/0x20
[  720.628799]  [<ffffffff8152ff55>] mutex_lock_nested+0x1f5/0x380
[  720.628803]  [<ffffffff81462622>] ? rtnl_lock+0x12/0x20
[  720.628807]  [<ffffffff81462622>] ? rtnl_lock+0x12/0x20
[  720.628812]  [<ffffffff81462622>] rtnl_lock+0x12/0x20
[  720.628817]  [<ffffffff8148ab25>] nf_queue_nf_hook_drop+0x15/0x160
[  720.628825]  [<ffffffff81488d48>] nf_unregister_net_hook+0x168/0x190
[  720.628831]  [<ffffffff81488e24>] nf_unregister_hook+0x64/0x80
[  720.628837]  [<ffffffff81488e60>] nf_unregister_hooks+0x20/0x30
[...]

Moreover, nf_unregister_net_hook() should only destroy the queue for this
netns, not for every netns.

Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Fixes: 085db2c04557 ("netfilter: Per network namespace netfilter hooks.")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
net/netfilter/core.c
net/netfilter/nf_internals.h
net/netfilter/nf_queue.c

index 87d237d20870ffa9d83e9f90c303abf61e813c35..12504fbbeef7623ab6d32ea1d61b47bd777b544a 100644 (file)
@@ -154,7 +154,7 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
        static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
 #endif
        synchronize_net();
-       nf_queue_nf_hook_drop(elem);
+       nf_queue_nf_hook_drop(net, elem);
        kfree(elem);
 }
 EXPORT_SYMBOL(nf_unregister_net_hook);
index 399210693c2a8bfac527e85ea6285757c70c1571..065522564ac6a032ce1ece83be62438f7d8b0636 100644 (file)
@@ -19,7 +19,7 @@ unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb,
 /* nf_queue.c */
 int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem,
             struct nf_hook_state *state, unsigned int queuenum);
-void nf_queue_nf_hook_drop(struct nf_hook_ops *ops);
+void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops);
 int __init netfilter_queue_init(void);
 
 /* nf_log.c */
index 8a8b2abc35ffdeacb5a61e1a801c92f91998bc3d..96777f9a9350b3a684ae56b50c77400fde3ad305 100644 (file)
@@ -105,21 +105,15 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
 }
 EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
 
-void nf_queue_nf_hook_drop(struct nf_hook_ops *ops)
+void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops)
 {
        const struct nf_queue_handler *qh;
-       struct net *net;
 
-       rtnl_lock();
        rcu_read_lock();
        qh = rcu_dereference(queue_handler);
-       if (qh) {
-               for_each_net(net) {
-                       qh->nf_hook_drop(net, ops);
-               }
-       }
+       if (qh)
+               qh->nf_hook_drop(net, ops);
        rcu_read_unlock();
-       rtnl_unlock();
 }
 
 /*