oss-sec mailing list archives
CVE-2021-3640: Linux kernel: UAF in sco_send_frame function
From: Lin Horse <kylin.formalin () gmail com>
Date: Thu, 22 Jul 2021 14:28:05 +0800
Hello there, Just like the previous, tedious race condition vulnerability caused by the unexpected locking behavior (CVE-2021-3573), a similar one is found this time. =*=*=*=*=*=*=*=*= BUG DETAILS =*=*=*=*=*=*=*=*= We can find another place that uses bh_lock_sock() in the Linux Bluetooth stacks. static void sco_conn_del(struct hci_conn *hcon, int err) { ... if (sk) { sock_hold(sk); bh_lock_sock(sk); // {1} LOCK sco_sock_clear_timer(sk); sco_chan_del(sk, err); bh_unlock_sock(sk); // {2} UNLOCK sco_sock_kill(sk); sock_put(sk); } ... hcon->sco_data = NULL; kfree(conn); } Between these lock pairs, sco_chan_del() is called, which will delete the channel associated with this sk. At the end of this function, the conn will be released by kfree(). Similar to the CVE-2021-3573, there is another thread that can be controlled by the attacker. It will wait for the kfree() and thereafter, race to cause UAF. For example, the sco_sock_sendmsg() function. static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { ... lock_sock(sk); if (sk->sk_state == BT_CONNECTED) err = sco_send_frame(sk, msg, len); else err = -ENOTCONN; release_sock(sk); return err; } static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) { ... skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return err; if (memcpy_from_msg(skb_put(skb, len), msg, len)) { // {3} kfree_skb(skb); return -EFAULT; } hci_send_sco(conn->hcon, skb); ... } As you can see, the attacker can adopt userfaultfd technique to stop the thread at {3} point. Because the sco_send_frame() is protected by the lock_sock() and release_sock(), which will not block the sco_conn_del() to release the conn. One vulnerable race window is shown below: sco_sock_sendmsg thread | sco_conn_del thread | | lock_sock(sk); | | ... | bh_lock_sock(sk); | ... | bh_unlock_sock(sk); | ... | kfree(conn); // UAF | hci_send_sco(conn->hcon, skb); | | | =*=*=*=*=*=*=*=*= BUG EFFECTS =*=*=*=*=*=*=*=*= Similar to CVE-2021-3573, the attacker may stably cause the UAF and do further exploitation. As the sco_conn struct is pretty juicy (two previous data pointers inside) struct sco_conn { struct hci_conn *hcon; spinlock_t lock; struct sock *sk; unsigned int mtu; }; The attacker can easily spray these kmalloc-32 objects with the malicious payload, with CAP_NET_ADMIN privilege. The provided POC code can cause the crash report below: [ 62.856933] ================================================================== [ 62.857336] BUG: KASAN: use-after-free in sco_sock_sendmsg+0x1d6/0x2c0 [ 62.858202] Read of size 8 at addr ffff888002478540 by task poc.sco.new/120 [ 62.858663] [ 62.859014] CPU: 0 PID: 120 Comm: poc.sco.new Not tainted 5.13.0+ #1 [ 62.859405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 62.859884] Call Trace: [ 62.860168] dump_stack_lvl+0x73/0x9e [ 62.860525] print_address_description+0x82/0x3a0 [ 62.860879] __kasan_report+0x154/0x240 [ 62.861115] ? lock_sock_nested+0x100/0x140 [ 62.861446] ? sco_sock_sendmsg+0x1d6/0x2c0 [ 62.861811] kasan_report+0x45/0x60 [ 62.862133] sco_sock_sendmsg+0x1d6/0x2c0 [ 62.862461] ? sco_sock_getsockopt+0x410/0x410 [ 62.862748] ? inet_send_prepare+0x190/0x190 [ 62.863000] sock_write_iter+0x21b/0x230 [ 62.863232] vfs_write+0x53a/0x5c0 [ 62.863479] ksys_write+0x8b/0x100 [ 62.863723] ? __fpregs_load_activate+0xc2/0x150 [ 62.864017] do_syscall_64+0x43/0x90 [ 62.864287] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 62.864615] RIP: 0033:0x7f9b6c8d4abf [ 62.865073] Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 69 fd ff ff 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 2d 44 89 c7 48 89 44 24 08 e8 9c fd ff ff 48 [ 62.865843] RSP: 002b:00007ffd6b0133a0 EFLAGS: 00000293 ORIG_RAX: 0000000000000001 [ 62.866304] RAX: ffffffffffffffda RBX: 000055be494024e0 RCX: 00007f9b6c8d4abf [ 62.866660] RDX: 0000000000000010 RSI: 00007f9b6c90e000 RDI: 0000000000000005 [ 62.866992] RBP: 00007ffd6b013480 R08: 0000000000000000 R09: 00007f9b6c703700 [ 62.867293] R10: 00007f9b6c7039d0 R11: 0000000000000293 R12: 000055be49400d10 [ 62.867576] R13: 00007ffd6b013570 R14: 0000000000000000 R15: 0000000000000000 [ 62.868106] [ 62.868302] Allocated by task 120: [ 62.868586] ____kasan_kmalloc+0xb5/0xe0 [ 62.868999] kmem_cache_alloc_trace+0x12d/0x210 [ 62.869349] sco_sock_connect+0x1f7/0x4a0 [ 62.869647] __sys_connect+0x16f/0x1a0 [ 62.869944] __x64_sys_connect+0x38/0x40 [ 62.870243] do_syscall_64+0x43/0x90 [ 62.870556] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 62.870883] [ 62.871020] Freed by task 125: [ 62.871192] kasan_set_track+0x3d/0x70 [ 62.871432] kasan_set_free_info+0x1f/0x40 [ 62.871708] ____kasan_slab_free+0x111/0x150 [ 62.871956] kfree+0xf3/0x2d0 [ 62.872208] hci_conn_hash_flush+0xbf/0x120 [ 62.872529] hci_dev_do_close+0x51a/0x870 [ 62.872789] hci_unregister_dev+0x23a/0xb70 [ 62.873054] vhci_release+0x3f/0x70 [ 62.873334] __fput+0x197/0x360 [ 62.873598] task_work_run+0xc0/0xe0 [ 62.873919] exit_to_user_mode_prepare+0xf0/0x130 [ 62.874253] syscall_exit_to_user_mode+0x20/0x40 [ 62.874511] do_syscall_64+0x52/0x90 [ 62.874768] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 62.875160] [ 62.875352] The buggy address belongs to the object at ffff888002478540 [ 62.875352] which belongs to the cache kmalloc-32 of size 32 [ 62.875900] The buggy address is located 0 bytes inside of [ 62.875900] 32-byte region [ffff888002478540, ffff888002478560) [ 62.876472] The buggy address belongs to the page: [ 62.876885] page:00000000db13206d refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x2478 [ 62.877481] flags: 0x100000000000200(slab|node=0|zone=1) [ 62.878361] raw: 0100000000000200 ffffea0000078d00 0000000e0000000e ffff888001041500 [ 62.878901] raw: 0000000000000000 0000000080400040 00000001ffffffff 0000000000000000 [ 62.879313] page dumped because: kasan: bad access detected [ 62.879588] [ 62.879704] Memory state around the buggy address: [ 62.880003] ffff888002478400: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc [ 62.880286] ffff888002478480: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc [ 62.880532] >ffff888002478500: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc [ 62.880785] ^ [ 62.881199] ffff888002478580: 00 00 00 00 fc fc fc fc 00 00 00 fc fc fc fc fc [ 62.881457] ffff888002478600: 00 00 00 fc fc fc fc fc 00 00 00 fc fc fc fc fc [ 62.881716] ================================================================== [ 62.881991] Disabling lock debugging due to kernel taint [ 62.883072] BUG: unable to handle page fault for address: fffffbfff22fa79f [ 62.883427] #PF: supervisor read access in kernel mode [ 62.883774] #PF: error_code(0x0000) - not-present page [ 62.884165] PGD 36fd0067 P4D 36fd0067 PUD 36df4067 PMD 0 [ 62.884827] Oops: 0000 [#1] SMP KASAN NOPTI [ 62.885132] CPU: 0 PID: 120 Comm: poc.sco.new Tainted: G B 5.13.0+ #1 [ 62.885528] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 62.885901] RIP: 0010:__asan_store8+0x6c/0xb0 [ 62.886184] Code: be 00 00 00 00 00 fc ff df 0f be 14 32 85 d2 74 07 83 e0 07 39 d0 7d 29 c3 48 89 fe 48 c1 ee 03 48 ba 00 00 00 00 00 fc ff df <80> 3c 16 00 75 11 48 89 c6 48 c1 ee 03 0f be 14 16 85 d2 75 d2 eb [ 62.886853] RSP: 0018:ffff8880030ffbf8 EFLAGS: 00000006 [ 62.887244] RAX: ffffffff917d3d02 RBX: 0000000000040000 RCX: ffffffffba337d86 [ 62.887524] RDX: dffffc0000000000 RSI: 1ffffffff22fa79f RDI: ffffffff917d3cfb [ 62.887855] RBP: 0000000000000030 R08: dffffc0000000000 R09: 0000000000000007 [ 62.888162] R10: ffffed100035159c R11: 00000000000000fb R12: ffffffff917a1b4b [ 62.888476] R13: fffffffffffffff8 R14: ffff888001a8acdc R15: ffff888036432188 [ 62.888838] FS: 00007f9b6c704740(0000) GS:ffff888036400000(0000) knlGS:0000000000000000 [ 62.889331] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 62.889908] CR2: fffffbfff22fa79f CR3: 00000000011c0000 CR4: 00000000003006f0 [ 62.890341] Call Trace: [ 62.890617] queued_spin_lock_slowpath+0x286/0x410 [ 62.890915] _raw_spin_lock_irqsave+0x9f/0xb0 [ 62.891201] skb_queue_tail+0x1c/0x90 [ 62.891548] hci_send_sco+0xd6/0x110 [ 62.891871] sco_sock_sendmsg+0x1e1/0x2c0 [ 62.892170] ? sco_sock_getsockopt+0x410/0x410 [ 62.892511] ? inet_send_prepare+0x190/0x190 [ 62.892796] sock_write_iter+0x21b/0x230 [ 62.893156] vfs_write+0x53a/0x5c0 [ 62.893533] ksys_write+0x8b/0x100 [ 62.893870] ? __fpregs_load_activate+0xc2/0x150 [ 62.894258] do_syscall_64+0x43/0x90 [ 62.894523] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 62.894929] RIP: 0033:0x7f9b6c8d4abf [ 62.895178] Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 69 fd ff ff 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 2d 44 89 c7 48 89 44 24 08 e8 9c fd ff ff 48 [ 62.895930] RSP: 002b:00007ffd6b0133a0 EFLAGS: 00000293 ORIG_RAX: 0000000000000001 [ 62.896396] RAX: ffffffffffffffda RBX: 000055be494024e0 RCX: 00007f9b6c8d4abf [ 62.896749] RDX: 0000000000000010 RSI: 00007f9b6c90e000 RDI: 0000000000000005 [ 62.897081] RBP: 00007ffd6b013480 R08: 0000000000000000 R09: 00007f9b6c703700 [ 62.897430] R10: 00007f9b6c7039d0 R11: 0000000000000293 R12: 000055be49400d10 [ 62.897814] R13: 00007ffd6b013570 R14: 0000000000000000 R15: 0000000000000000 [ 62.898239] Modules linked in: [ 62.898623] CR2: fffffbfff22fa79f [ 62.899350] ---[ end trace e705e323d4c8b589 ]--- [ 62.899645] RIP: 0010:__asan_store8+0x6c/0xb0 [ 62.899918] Code: be 00 00 00 00 00 fc ff df 0f be 14 32 85 d2 74 07 83 e0 07 39 d0 7d 29 c3 48 89 fe 48 c1 ee 03 48 ba 00 00 00 00 00 fc ff df <80> 3c 16 00 75 11 48 89 c6 48 c1 ee 03 0f be 14 16 85 d2 75 d2 eb [ 62.900625] RSP: 0018:ffff8880030ffbf8 EFLAGS: 00000006 [ 62.900997] RAX: ffffffff917d3d02 RBX: 0000000000040000 RCX: ffffffffba337d86 [ 62.901276] RDX: dffffc0000000000 RSI: 1ffffffff22fa79f RDI: ffffffff917d3cfb [ 62.901700] RBP: 0000000000000030 R08: dffffc0000000000 R09: 0000000000000007 [ 62.902083] R10: ffffed100035159c R11: 00000000000000fb R12: ffffffff917a1b4b [ 62.902496] R13: fffffffffffffff8 R14: ffff888001a8acdc R15: ffff888036432188 [ 62.902820] FS: 00007f9b6c704740(0000) GS:ffff888036400000(0000) knlGS:0000000000000000 [ 62.903228] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 62.903566] CR2: fffffbfff22fa79f CR3: 00000000011c0000 CR4: 00000000003006f0 =*=*=*=*=*=*=*=*= BUG REPRODUCE =*=*=*=*=*=*=*=*= As above introduced, this race condition is highly controllable with userfaultfd techniques. The attacker has to fake an SCO connection and then calls sco_sock_sendmsg() with the expected controllable faulting page. After that, the attacker just needs to detach the controller to call sco_conn_del(). The calling trace is: hci_unregister_dev() -> hci_dev_do_close() -> hci_conn_hash_flush() -> hci_disconn_cfm() -> sco_disconn_cfm() -> sco_conn_del(). You can refer to the provided POC code for the details. =*=*=*=*=*=*=*=*= Timeline =*=*=*=*=*=*=*=*= 2021-07-08: Bug reported to security () kernel org and linux-distros () vs openwall org 2021-07-09: CVE-2021-3640 is assigned 2021-07-22: 14 days of the embargo is over One sad thing is that the bluez team is currently focused on fixing up the CVE-2021-3573, which I failed to properly patched, and the patch for this new is not yet fully discussed. I hope the patch will be settled down and merged to the mainline in the near future. =*=*=*=*=*=*=*=*= Credt =*=*=*=*=*=*=*=*= LinMa@BlockSec Team Best Regards
Attachment:
reproduce.tar
Description:
Current thread:
- CVE-2021-3640: Linux kernel: UAF in sco_send_frame function Lin Horse (Jul 22)