| From d804261f9f31ef6ebd26b5a77cabe92c0d00750f Mon Sep 17 00:00:00 2001 |
| From: Matias Karhumaa <matias.karhumaa@gmail.com> |
| Date: Wed, 26 Sep 2018 09:13:46 +0300 |
| Subject: Bluetooth: SMP: fix crash in unpairing |
| |
| [ Upstream commit cb28c306b93b71f2741ce1a5a66289db26715f4d ] |
| |
| In case unpair_device() was called through mgmt interface at the same time |
| when pairing was in progress, Bluetooth kernel module crash was seen. |
| |
| [ 600.351225] general protection fault: 0000 [#1] SMP PTI |
| [ 600.351235] CPU: 1 PID: 11096 Comm: btmgmt Tainted: G OE 4.19.0-rc1+ #1 |
| [ 600.351238] Hardware name: Dell Inc. Latitude E5440/08RCYC, BIOS A18 05/14/2017 |
| [ 600.351272] RIP: 0010:smp_chan_destroy.isra.10+0xce/0x2c0 [bluetooth] |
| [ 600.351276] Code: c0 0f 84 b4 01 00 00 80 78 28 04 0f 84 53 01 00 00 4d 85 ed 0f 85 ab 00 00 00 48 8b 08 48 8b 50 08 be 10 00 00 00 48 89 51 08 <48> 89 0a 48 b9 00 02 00 00 00 00 ad de 48 89 48 08 48 8b 83 00 01 |
| [ 600.351279] RSP: 0018:ffffa9be839b3b50 EFLAGS: 00010246 |
| [ 600.351282] RAX: ffff9c999ac565a0 RBX: ffff9c9996e98c00 RCX: ffff9c999aa28b60 |
| [ 600.351285] RDX: dead000000000200 RSI: 0000000000000010 RDI: ffff9c999e403500 |
| [ 600.351287] RBP: ffffa9be839b3b70 R08: 0000000000000000 R09: ffffffff92a25c00 |
| [ 600.351290] R10: ffffa9be839b3ae8 R11: 0000000000000001 R12: ffff9c995375b800 |
| [ 600.351292] R13: 0000000000000000 R14: ffff9c99619a5000 R15: ffff9c9962a01c00 |
| [ 600.351295] FS: 00007fb2be27c700(0000) GS:ffff9c999e880000(0000) knlGS:0000000000000000 |
| [ 600.351298] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 |
| [ 600.351300] CR2: 00007fb2bdadbad0 CR3: 000000041c328001 CR4: 00000000001606e0 |
| [ 600.351302] Call Trace: |
| [ 600.351325] smp_failure+0x4f/0x70 [bluetooth] |
| [ 600.351345] smp_cancel_pairing+0x74/0x80 [bluetooth] |
| [ 600.351370] unpair_device+0x1c1/0x330 [bluetooth] |
| [ 600.351399] hci_sock_sendmsg+0x960/0x9f0 [bluetooth] |
| [ 600.351409] ? apparmor_socket_sendmsg+0x1e/0x20 |
| [ 600.351417] sock_sendmsg+0x3e/0x50 |
| [ 600.351422] sock_write_iter+0x85/0xf0 |
| [ 600.351429] do_iter_readv_writev+0x12b/0x1b0 |
| [ 600.351434] do_iter_write+0x87/0x1a0 |
| [ 600.351439] vfs_writev+0x98/0x110 |
| [ 600.351443] ? ep_poll+0x16d/0x3d0 |
| [ 600.351447] ? ep_modify+0x73/0x170 |
| [ 600.351451] do_writev+0x61/0xf0 |
| [ 600.351455] ? do_writev+0x61/0xf0 |
| [ 600.351460] __x64_sys_writev+0x1c/0x20 |
| [ 600.351465] do_syscall_64+0x5a/0x110 |
| [ 600.351471] entry_SYSCALL_64_after_hwframe+0x44/0xa9 |
| [ 600.351474] RIP: 0033:0x7fb2bdb62fe0 |
| [ 600.351477] Code: 73 01 c3 48 8b 0d b8 6e 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d 69 c7 2c 00 00 75 10 b8 14 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 de 80 01 00 48 89 04 24 |
| [ 600.351479] RSP: 002b:00007ffe062cb8f8 EFLAGS: 00000246 ORIG_RAX: 0000000000000014 |
| [ 600.351484] RAX: ffffffffffffffda RBX: 000000000255b3d0 RCX: 00007fb2bdb62fe0 |
| [ 600.351487] RDX: 0000000000000001 RSI: 00007ffe062cb920 RDI: 0000000000000004 |
| [ 600.351490] RBP: 00007ffe062cb920 R08: 000000000255bd80 R09: 0000000000000000 |
| [ 600.351494] R10: 0000000000000353 R11: 0000000000000246 R12: 0000000000000001 |
| [ 600.351497] R13: 00007ffe062cbbe0 R14: 0000000000000000 R15: 0000000000000000 |
| [ 600.351501] Modules linked in: algif_hash algif_skcipher af_alg cmac ipt_MASQUERADE nf_conntrack_netlink nfnetlink xfrm_user xfrm_algo iptable_nat nf_nat_ipv4 xt_addrtype iptable_filter ip_tables xt_conntrack x_tables nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 libcrc32c br_netfilter bridge stp llc overlay arc4 nls_iso8859_1 dm_crypt intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp dell_laptop kvm_intel crct10dif_pclmul dell_smm_hwmon crc32_pclmul ghash_clmulni_intel pcbc aesni_intel aes_x86_64 crypto_simd cryptd glue_helper intel_cstate intel_rapl_perf uvcvideo videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_common videodev media hid_multitouch input_leds joydev serio_raw dell_wmi snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic dell_smbios dcdbas sparse_keymap |
| [ 600.351569] snd_hda_intel btusb snd_hda_codec btrtl btbcm btintel snd_hda_core bluetooth(OE) snd_hwdep snd_pcm iwlmvm ecdh_generic wmi_bmof dell_wmi_descriptor snd_seq_midi mac80211 snd_seq_midi_event lpc_ich iwlwifi snd_rawmidi snd_seq snd_seq_device snd_timer cfg80211 snd soundcore mei_me mei dell_rbtn dell_smo8800 mac_hid parport_pc ppdev lp parport autofs4 hid_generic usbhid hid i915 nouveau kvmgt vfio_mdev mdev vfio_iommu_type1 vfio kvm irqbypass i2c_algo_bit ttm drm_kms_helper syscopyarea sysfillrect sysimgblt mxm_wmi psmouse ahci sdhci_pci cqhci libahci fb_sys_fops sdhci drm e1000e video wmi |
| [ 600.351637] ---[ end trace e49e9f1df09c94fb ]--- |
| [ 600.351664] RIP: 0010:smp_chan_destroy.isra.10+0xce/0x2c0 [bluetooth] |
| [ 600.351666] Code: c0 0f 84 b4 01 00 00 80 78 28 04 0f 84 53 01 00 00 4d 85 ed 0f 85 ab 00 00 00 48 8b 08 48 8b 50 08 be 10 00 00 00 48 89 51 08 <48> 89 0a 48 b9 00 02 00 00 00 00 ad de 48 89 48 08 48 8b 83 00 01 |
| [ 600.351669] RSP: 0018:ffffa9be839b3b50 EFLAGS: 00010246 |
| [ 600.351672] RAX: ffff9c999ac565a0 RBX: ffff9c9996e98c00 RCX: ffff9c999aa28b60 |
| [ 600.351674] RDX: dead000000000200 RSI: 0000000000000010 RDI: ffff9c999e403500 |
| [ 600.351676] RBP: ffffa9be839b3b70 R08: 0000000000000000 R09: ffffffff92a25c00 |
| [ 600.351679] R10: ffffa9be839b3ae8 R11: 0000000000000001 R12: ffff9c995375b800 |
| [ 600.351681] R13: 0000000000000000 R14: ffff9c99619a5000 R15: ffff9c9962a01c00 |
| [ 600.351684] FS: 00007fb2be27c700(0000) GS:ffff9c999e880000(0000) knlGS:0000000000000000 |
| [ 600.351686] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 |
| [ 600.351689] CR2: 00007fb2bdadbad0 CR3: 000000041c328001 CR4: 00000000001606e0 |
| |
| Crash happened because list_del_rcu() was called twice for smp->ltk. This |
| was possible if unpair_device was called right after ltk was generated |
| but before keys were distributed. |
| |
| In this commit smp_cancel_pairing was refactored to cancel pairing if it |
| is in progress and otherwise just removes keys. Once keys are removed from |
| rcu list, pointers to smp context's keys are set to NULL to make sure |
| removed list items are not accessed later. |
| |
| This commit also adjusts the functionality of mgmt unpair_device() little |
| bit. Previously pairing was canceled only if pairing was in state that |
| keys were already generated. With this commit unpair_device() cancels |
| pairing already in earlier states. |
| |
| Bug was found by fuzzing kernel SMP implementation using Synopsys |
| Defensics. |
| |
| Reported-by: Pekka Oikarainen <pekka.oikarainen@synopsys.com> |
| Signed-off-by: Matias Karhumaa <matias.karhumaa@gmail.com> |
| Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/bluetooth/mgmt.c | 7 ++----- |
| net/bluetooth/smp.c | 29 +++++++++++++++++++++++++---- |
| net/bluetooth/smp.h | 3 ++- |
| 3 files changed, 29 insertions(+), 10 deletions(-) |
| |
| diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c |
| index 1fba2a03f8ae..ba24f613c0fc 100644 |
| --- a/net/bluetooth/mgmt.c |
| +++ b/net/bluetooth/mgmt.c |
| @@ -2298,9 +2298,8 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, |
| /* LE address type */ |
| addr_type = le_addr_type(cp->addr.type); |
| |
| - hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type); |
| - |
| - err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); |
| + /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */ |
| + err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type); |
| if (err < 0) { |
| err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, |
| MGMT_STATUS_NOT_PAIRED, &rp, |
| @@ -2314,8 +2313,6 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, |
| goto done; |
| } |
| |
| - /* Abort any ongoing SMP pairing */ |
| - smp_cancel_pairing(conn); |
| |
| /* Defer clearing up the connection parameters until closing to |
| * give a chance of keeping them if a repairing happens. |
| diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c |
| index ead4d1baeaa6..1abfbcd8090a 100644 |
| --- a/net/bluetooth/smp.c |
| +++ b/net/bluetooth/smp.c |
| @@ -2353,30 +2353,51 @@ unlock: |
| return ret; |
| } |
| |
| -void smp_cancel_pairing(struct hci_conn *hcon) |
| +int smp_cancel_and_remove_pairing(struct hci_dev *hdev, bdaddr_t *bdaddr, |
| + u8 addr_type) |
| { |
| - struct l2cap_conn *conn = hcon->l2cap_data; |
| + struct hci_conn *hcon; |
| + struct l2cap_conn *conn; |
| struct l2cap_chan *chan; |
| struct smp_chan *smp; |
| + int err; |
| + |
| + err = hci_remove_ltk(hdev, bdaddr, addr_type); |
| + hci_remove_irk(hdev, bdaddr, addr_type); |
| + |
| + hcon = hci_conn_hash_lookup_le(hdev, bdaddr, addr_type); |
| + if (!hcon) |
| + goto done; |
| |
| + conn = hcon->l2cap_data; |
| if (!conn) |
| - return; |
| + goto done; |
| |
| chan = conn->smp; |
| if (!chan) |
| - return; |
| + goto done; |
| |
| l2cap_chan_lock(chan); |
| |
| smp = chan->data; |
| if (smp) { |
| + /* Set keys to NULL to make sure smp_failure() does not try to |
| + * remove and free already invalidated rcu list entries. */ |
| + smp->ltk = NULL; |
| + smp->slave_ltk = NULL; |
| + smp->remote_irk = NULL; |
| + |
| if (test_bit(SMP_FLAG_COMPLETE, &smp->flags)) |
| smp_failure(conn, 0); |
| else |
| smp_failure(conn, SMP_UNSPECIFIED); |
| + err = 0; |
| } |
| |
| l2cap_chan_unlock(chan); |
| + |
| +done: |
| + return err; |
| } |
| |
| static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) |
| diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h |
| index ffcc70b6b199..993cbd7bcfe7 100644 |
| --- a/net/bluetooth/smp.h |
| +++ b/net/bluetooth/smp.h |
| @@ -180,7 +180,8 @@ enum smp_key_pref { |
| }; |
| |
| /* SMP Commands */ |
| -void smp_cancel_pairing(struct hci_conn *hcon); |
| +int smp_cancel_and_remove_pairing(struct hci_dev *hdev, bdaddr_t *bdaddr, |
| + u8 addr_type); |
| bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level, |
| enum smp_key_pref key_pref); |
| int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); |
| -- |
| 2.17.1 |
| |