From d4091899c9bbfd6695449c6b09517ceb45bb379d Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Tue, 2 Feb 2016 10:52:14 +0100 Subject: [PATCH] tipc: hold subscriber->lock for tipc_nametbl_subscribe() Until now, while creating a subscription the subscriber lock protects only the subscribers subscription list and not the nametable. The call to tipc_nametbl_subscribe() is outside the lock. However, at subscription timeout and cancel both the subscribers subscription list and the nametable are protected by the subscriber lock. This asymmetric locking mechanism leads to the following problem: In a SMP system, the timer can be fire on another core before the create request is complete. When the timer thread calls tipc_nametbl_unsubscribe() before create thread calls tipc_nametbl_subscribe(), we get a nullptr exception. This can be simulated by creating subscription with timeout=0 and sometimes the timeout occurs before the create request is complete. The following is the oops: [57.569661] BUG: unable to handle kernel NULL pointer dereference at (null) [57.577498] IP: [] tipc_nametbl_unsubscribe+0x8a/0x120 [tipc] [57.584820] PGD 0 [57.586834] Oops: 0002 [#1] SMP [57.685506] CPU: 14 PID: 10077 Comm: kworker/u40:1 Tainted: P OENX 3.12.48-52.27.1. 9688.1.PTF-default #1 [57.703637] Workqueue: tipc_rcv tipc_recv_work [tipc] [57.708697] task: ffff88064c7f00c0 ti: ffff880629ef4000 task.ti: ffff880629ef4000 [57.716181] RIP: 0010:[] [] tipc_nametbl_unsubscribe+0x8a/ 0x120 [tipc] [...] [57.812327] Call Trace: [57.814806] [] tipc_subscrp_delete+0x37/0x90 [tipc] [57.821357] [] tipc_subscrp_timeout+0x3f/0x70 [tipc] [57.827982] [] call_timer_fn+0x31/0x100 [57.833490] [] run_timer_softirq+0x1f9/0x2b0 [57.839414] [] __do_softirq+0xe5/0x230 [57.844827] [] call_softirq+0x1c/0x30 [57.850150] [] do_softirq+0x55/0x90 [57.855285] [] irq_exit+0x95/0xa0 [57.860290] [] smp_apic_timer_interrupt+0x45/0x60 [57.866644] [] apic_timer_interrupt+0x6d/0x80 [57.872686] [] tipc_subscrb_rcv_cb+0x2a5/0x3f0 [tipc] [57.879425] [] tipc_receive_from_sock+0x9f/0x100 [tipc] [57.886324] [] tipc_recv_work+0x26/0x60 [tipc] [57.892463] [] process_one_work+0x172/0x420 [57.898309] [] worker_thread+0x11a/0x3c0 [57.903871] [] kthread+0xb4/0xc0 [57.908751] [] ret_from_fork+0x58/0x90 In this commit, we do the following at subscription creation: 1. set the subscription's subscriber pointer before performing tipc_nametbl_subscribe(), as this value is required further in the call chain ex: by tipc_subscrp_send_event(). 2. move tipc_nametbl_subscribe() under the scope of subscriber lock Acked-by: Ying Xue Reviewed-by: Jon Maloy Signed-off-by: Parthasarathy Bhuvaragan Signed-off-by: David S. Miller --- net/tipc/subscr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 24d2c8128bac..e4ebbc161e42 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -284,13 +284,13 @@ static void tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s, spin_lock_bh(&subscriber->lock); list_add(&sub->subscrp_list, &subscriber->subscrp_list); + sub->subscriber = subscriber; + tipc_nametbl_subscribe(sub); spin_unlock_bh(&subscriber->lock); - sub->subscriber = subscriber; timeout = htohl(sub->evt.s.timeout, swap); if (!mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout))) tipc_subscrb_get(subscriber); - tipc_nametbl_subscribe(sub); } /* Handle one termination request for the subscriber */ -- 2.30.2