summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRobert Shearman <rshearma@brocade.com>2017-01-24 11:26:48 -0500
committerDavid S. Miller <davem@davemloft.net>2017-01-24 16:21:36 -0500
commit85c814016ce3b371016c2c054a905fa2492f5a65 (patch)
treec9c7eb5576834cae05dba40e82ca84a7772b7a51 /net
parent88ff7334f25909802140e690c0e16433e485b0a0 (diff)
lwtunnel: Fix oops on state free after encap module unload
When attempting to free lwtunnel state after the module for the encap has been unloaded an oops occurs: BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: lwtstate_free+0x18/0x40 [..] task: ffff88003e372380 task.stack: ffffc900001fc000 RIP: 0010:lwtstate_free+0x18/0x40 RSP: 0018:ffff88003fd83e88 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff88002bbb3380 RCX: ffff88000c91a300 [..] Call Trace: <IRQ> free_fib_info_rcu+0x195/0x1a0 ? rt_fibinfo_free+0x50/0x50 rcu_process_callbacks+0x2d3/0x850 ? rcu_process_callbacks+0x296/0x850 __do_softirq+0xe4/0x4cb irq_exit+0xb0/0xc0 smp_apic_timer_interrupt+0x3d/0x50 apic_timer_interrupt+0x93/0xa0 [..] Code: e8 6e c6 fc ff 89 d8 5b 5d c3 bb de ff ff ff eb f4 66 90 66 66 66 66 90 55 48 89 e5 53 0f b7 07 48 89 fb 48 8b 04 c5 00 81 d5 81 <48> 8b 40 08 48 85 c0 74 13 ff d0 48 8d 7b 20 be 20 00 00 00 e8 The problem is after the module for the encap can be unloaded the corresponding ops is removed and is thus NULL here. Modules implementing lwtunnel ops should not be allowed to unload while there is state alive using those ops, so grab the module reference for the ops on creating lwtunnel state and of course release the reference when freeing the state. Fixes: 1104d9ba443a ("lwtunnel: Add destroy state operation") Signed-off-by: Robert Shearman <rshearma@brocade.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/lwtunnel.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index 47b1dd65947b..c23465005f2f 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -115,8 +115,11 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
115 ret = -EOPNOTSUPP; 115 ret = -EOPNOTSUPP;
116 rcu_read_lock(); 116 rcu_read_lock();
117 ops = rcu_dereference(lwtun_encaps[encap_type]); 117 ops = rcu_dereference(lwtun_encaps[encap_type]);
118 if (likely(ops && ops->build_state)) 118 if (likely(ops && ops->build_state && try_module_get(ops->owner))) {
119 ret = ops->build_state(dev, encap, family, cfg, lws); 119 ret = ops->build_state(dev, encap, family, cfg, lws);
120 if (ret)
121 module_put(ops->owner);
122 }
120 rcu_read_unlock(); 123 rcu_read_unlock();
121 124
122 return ret; 125 return ret;
@@ -194,6 +197,7 @@ void lwtstate_free(struct lwtunnel_state *lws)
194 } else { 197 } else {
195 kfree(lws); 198 kfree(lws);
196 } 199 }
200 module_put(ops->owner);
197} 201}
198EXPORT_SYMBOL(lwtstate_free); 202EXPORT_SYMBOL(lwtstate_free);
199 203