From: Johan Hedberg Date: Tue, 29 Jul 2014 11:18:48 +0000 (+0300) Subject: Bluetooth: Fix SMP context tracking leading to a kernel crash X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=616d55be4c754dc7e1e1b7df59fb6cc5aee19ddd;p=linux-beck.git Bluetooth: Fix SMP context tracking leading to a kernel crash The HCI_CONN_LE_SMP_PEND flag is supposed to indicate whether we have an SMP context or not. If the context creation fails, or some other error is indicated between setting the flag and creating the context the flag must be cleared first. This patch ensures that smp_chan_create() clears the flag in case of allocation failure as well as reorders code in smp_cmd_security_req() that could lead to returning an error between setting the flag and creating the context. Without the patch the following kind of kernel crash could be observed (this one because of unacceptable authentication requirements in a Security Request): [ +0.000855] kernel BUG at net/bluetooth/smp.c:606! [ +0.000000] invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC [ +0.000000] CPU: 0 PID: 58 Comm: kworker/u5:2 Tainted: G W 3.16.0-rc1+ #785 [ +0.008391] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ +0.000000] Workqueue: hci0 hci_rx_work [ +0.000000] task: f4dc8f90 ti: f4ef0000 task.ti: f4ef0000 [ +0.000000] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 [ +0.000000] EIP is at smp_chan_destroy+0x1e/0x145 [ +0.000709] EAX: f46db870 EBX: 00000000 ECX: 00000000 EDX: 00000005 [ +0.000000] ESI: f46db870 EDI: f46db870 EBP: f4ef1dc0 ESP: f4ef1db0 [ +0.000000] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 [ +0.000000] CR0: 8005003b CR2: b666b0b0 CR3: 00022000 CR4: 00000690 [ +0.000000] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [ +0.000000] DR6: fffe0ff0 DR7: 00000400 [ +0.000000] Stack: [ +0.000000] 00000005 f17b7840 f46db870 f4ef1dd4 f4ef1de4 c1343441 c134342e 00000000 [ +0.000000] c1343441 00000005 00000002 00000000 f17b7840 f4ef1e38 c134452a 00002aae [ +0.000000] 01ef1e00 00002aae f46bd980 f46db870 00000039 ffffffff 00000007 f4ef1e34 [ +0.000000] Call Trace: [ +0.000000] [] smp_failure+0x64/0x6c [ +0.000000] [] ? smp_failure+0x51/0x6c [ +0.000000] [] ? smp_failure+0x64/0x6c [ +0.000000] [] smp_sig_channel+0xad6/0xafc [ +0.000000] [] ? vprintk_emit+0x343/0x366 [ +0.000000] [] l2cap_recv_frame+0x1337/0x1ac4 [ +0.000000] [] ? l2cap_recv_frame+0x1337/0x1ac4 [ +0.000000] [] ? __dynamic_pr_debug+0x3e/0x40 [ +0.000000] [] ? debug_smp_processor_id+0x12/0x14 [ +0.000000] [] l2cap_recv_acldata+0xe8/0x239 [ +0.000000] [] ? l2cap_recv_acldata+0xe8/0x239 [ +0.000000] [] ? __const_udelay+0x1a/0x1c [ +0.000000] [] hci_rx_work+0x1a1/0x286 [ +0.000000] [] ? mutex_unlock+0x8/0xa [ +0.000000] [] ? hci_rx_work+0x1a1/0x286 [ +0.000000] [] process_one_work+0x128/0x1df [ +0.000000] [] ? process_one_work+0x128/0x1df [ +0.000000] [] worker_thread+0x222/0x2de [ +0.000000] [] ? process_scheduled_works+0x21/0x21 [ +0.000000] [] kthread+0x82/0x87 [ +0.000000] [] ? create_new_namespaces+0x90/0x105 [ +0.000000] [] ret_from_kernel_thread+0x21/0x30 [ +0.000000] [] ? __kthread_parkme+0x50/0x50 [ +0.000000] Code: 65 f4 89 f0 5b 5e 5f 5d 8d 67 f8 5f c3 57 8d 7c 24 08 83 e4 f8 ff 77 fc 55 89 e5 57 89 c7 56 53 52 8b 98 e0 00 00 00 85 db 75 02 <0f> 0b 8b b3 80 00 00 00 8b 00 c1 ee 03 83 e6 01 89 f2 e8 ef 09 [ +0.000000] EIP: [] smp_chan_destroy+0x1e/0x145 SS:ESP 0068:f4ef1db0 Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a7c344b4acbc..eaa8e7482bb4 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -579,13 +579,16 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) struct smp_chan *smp; smp = kzalloc(sizeof(*smp), GFP_ATOMIC); - if (!smp) + if (!smp) { + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); return NULL; + } smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(smp->tfm_aes)) { BT_ERR("Unable to create ECB crypto context"); kfree(smp); + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); return NULL; } @@ -923,14 +926,14 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; - if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && - (rp->auth_req & SMP_AUTH_BONDING)) - return SMP_PAIRING_NOTSUPP; - smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; + if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && + (rp->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp));