[PATCH 2/3] Bluetooth: Fix freeing l2cap_chan while it's locked

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Johan Hedberg <johan.hedberg@xxxxxxxxx>

There's a race condition where it's possible that user space closes the
socket right at the moment that the kernel is inside some L2CAP
signaling channel handler with the lock held for the l2cap_chan tied to
the socket. When the race occurs it can look as follows:

 WARNING: CPU: 1 PID: 2395 at kernel/locking/mutex.c:565 __mutex_lock_slowpath+0x1ff/0x26a()
 DEBUG_LOCKS_WARN_ON(l->magic != l)
 CPU: 1 PID: 2395 Comm: kworker/u5:1 Not tainted 3.12.0+ #224
 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
 Workqueue: hci0 hci_rx_work
  00000007 00000000 ed74dcd0 c1344099 ed74dcf8 ed74dce8 c1028b29 c1346891
  ed5e0b80 00000246 f61d7600 ed74dd00 c1028b88 00000009 ed74dcf8 c13fd4cc
  ed74dd14 ed74dd50 c1346891 c13fd4e4 00000235 c13fd4cc c13fd50a 5a5a5a5a
 Call Trace:
  [<c1344099>] dump_stack+0x48/0x60
  [<c1028b29>] warn_slowpath_common+0x57/0x6e
  [<c1346891>] ? __mutex_lock_slowpath+0x1ff/0x26a
  [<c1028b88>] warn_slowpath_fmt+0x26/0x2a
  [<c1346891>] __mutex_lock_slowpath+0x1ff/0x26a
  [<c134691f>] mutex_lock+0x23/0x2f
  [<c130e79a>] l2cap_get_chan_by_scid+0x32/0x40
  [<c13143cb>] l2cap_config_req+0x6d/0x78f
  [<c1009486>] ? save_stack_trace+0x1d/0x3b
  [<c10915c2>] ? set_track+0x48/0xa7
  [<c134312b>] ? free_debug_processing+0x134/0x16b
  [<c1006019>] ? native_sched_clock+0x37/0x3a
  [<c1315107>] l2cap_recv_frame+0x2f2/0x1a85
  [<c1315107>] ? l2cap_recv_frame+0x2f2/0x1a85
  [<c1317913>] l2cap_recv_acldata+0xe8/0x239
  [<c1317913>] ? l2cap_recv_acldata+0xe8/0x239
  [<c12fa470>] hci_rx_work+0x1b0/0x295
  [<c13465d9>] ? mutex_unlock+0x8/0xa
  [<c12fa470>] ? hci_rx_work+0x1b0/0x295
  [<c103592c>] ? pwq_activate_delayed_work+0x1c/0x27
  [<c1036d25>] process_one_work+0x128/0x1df
  [<c1347401>] ? _raw_spin_unlock_irq+0x8/0x12
  [<c1036d25>] ? process_one_work+0x128/0x1df
  [<c103713a>] worker_thread+0x127/0x1c4
  [<c1037013>] ? rescuer_thread+0x216/0x216
  [<c103aec6>] kthread+0x88/0x8d
  [<c1040000>] ? task_rq_lock+0x37/0x6e
  [<c1347e77>] ret_from_kernel_thread+0x1b/0x28
  [<c103ae3e>] ? __kthread_parkme+0x50/0x50
 ---[ end trace 81d41a8e15d9559e ]---
 =============================================================================
 BUG kmalloc-1024 (Tainted: G        W   ): Poison overwritten
 -----------------------------------------------------------------------------
 INFO: 0xed5e0b80-0xed5e0b85. First byte 0xff instead of 0x6b
 INFO: Allocated in l2cap_chan_create+0x1f/0xf9 age=9986 cpu=1 pid=2395
 	__slab_alloc.constprop.66+0x1c5/0x36e
 	kmem_cache_alloc+0x54/0xb4
 	l2cap_chan_create+0x1f/0xf9
 	l2cap_sock_alloc.constprop.5+0x73/0x9b
 	l2cap_sock_new_connection_cb+0x5d/0x95
 	l2cap_connect+0x112/0x3a0
 	l2cap_recv_frame+0x534/0x1a85
 	process_pending_rx+0x48/0x56
 	process_one_work+0x128/0x1df
 	worker_thread+0x127/0x1c4
 	kthread+0x88/0x8d
 	ret_from_kernel_thread+0x1b/0x28
 INFO: Freed in l2cap_chan_destroy+0x59/0x65 age=9986 cpu=0 pid=2363
 	__slab_free+0x3c/0x260
 	kfree+0xb3/0xbc
 	l2cap_chan_destroy+0x59/0x65
 	kref_put+0x2a/0x33
 	l2cap_chan_put+0x3f/0x4a
 	l2cap_sock_destruct+0x3d/0x77
 	__sk_free+0x20/0x116
 	sk_free+0x1c/0x1f
 	l2cap_sock_kill+0x6f/0x74
 	l2cap_sock_teardown_cb+0xc1/0x119
 	l2cap_chan_close+0x186/0x192
 	l2cap_sock_shutdown+0x1af/0x214
 	l2cap_sock_release+0x56/0xa2
 	sock_release+0x10/0x55
 	sock_close+0xb/0xf
 	__fput+0xd3/0x175

This patch fixes the race by acquiring the l2cap_chan lock in
l2cap_chan_destroy before removing the channel from the global list.

Signed-off-by: Johan Hedberg <johan.hedberg@xxxxxxxxx>
---
 net/bluetooth/l2cap_core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index e5c5c7427c41..3a9917be6c6e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -442,10 +442,14 @@ static void l2cap_chan_destroy(struct kref *kref)
 
 	BT_DBG("chan %p", chan);
 
+	l2cap_chan_lock(chan);
+
 	write_lock(&chan_list_lock);
 	list_del(&chan->global_l);
 	write_unlock(&chan_list_lock);
 
+	l2cap_chan_unlock(chan);
+
 	kfree(chan);
 }
 
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux