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)
