hci: fix double free in hci_req_sync
Subsystems (2)
PATCH 1/1 hci: fix double free in hci_req_sync
The approach taken to address the 'CVE-2024-35978' introduced another double-free vulnerability. commit 45d355a926ab ("Bluetooth: Fix memory leak in hci_req_sync_complete()")
'hdev->req_skb' double free scenario:
cpu1 cpu2
==== ====
sock_ioctl
sock_do_ioctl
hci_sock_ioctl
hci_dev_cmd
hci_req_sync
__hci_req_sync hci_rx_work
kfree_skb(hdev->req_skb) hci_event_packet
(sleep) hci_req_sync_complete
\__ Longer times, kfree_skb(hdev->req_skb)
reproduce well hdev->req_skb = NULLThe longer cpu1 sleep in '__hci_req_sync', the more reproducible it is. We've tested it by inserting the 'msleep()' function, and it's frequently at 1000ms, and It has been consistently reproducible at 2000ms.
We confirmed the detection with various workloads that cause CPU1 to sleep. The call trace below is one of the KASAN has seen.
Bluetooth: hci0: unexpected cc 0x0c38 length: 249 > 2
==================================================================
BUG: KASAN: slab-use-after-free in skb_release_data+0x7d8/0x8a0 home/paran/linux/net/core/skbuff.c:1119 Write of size 1 at addr ffff00000947d3fe by task syz-executor.2/2010 CPU: 1 PID: 2010 Comm: syz-executor.2 Not tainted 6.10.0-rc4-00217-g35bb670d65fc-dirty #22 Hardware name: linux,dummy-virt (DT) Call trace: dump_backtrace+0x318/0x348 home/paran/linux/arch/arm64/kernel/stacktrace.c:317 show_stack+0x4c/0x80 home/paran/linux/arch/arm64/kernel/stacktrace.c:324 __dump_stack home/paran/linux/lib/dump_stack.c:88 [inline] dump_stack_lvl+0x214/0x328 home/paran/linux/lib/dump_stack.c:114 print_address_description home/paran/linux/mm/kasan/report.c:377 [inline] print_report+0x2ac/0x948 home/paran/linux/mm/kasan/report.c:488 kasan_report+0xc8/0x148 home/paran/linux/mm/kasan/report.c:601 __asan_report_store1_noabort+0x44/0x60 home/paran/linux/mm/kasan/report_generic.c:383 skb_release_data+0x7d8/0x8a0 home/paran/linux/net/core/skbuff.c:1119 skb_release_all+0x80/0xe0 home/paran/linux/net/core/skbuff.c:1173 __kfree_skb home/paran/linux/net/core/skbuff.c:1187 [inline] kfree_skb_reason+0x138/0x3a8 home/paran/linux/net/core/skbuff.c:1223 __hci_req_sync+0x404/0x948 [bluetooth] hci_req_sync+0xc0/0x138 [bluetooth] hci_dev_cmd+0x33c/0xc18 [bluetooth] hci_sock_ioctl+0x800/0xb68 [bluetooth] sock_do_ioctl+0xfc/0x2e0 home/paran/linux/net/socket.c:1222 sock_ioctl+0x62c/0xab0 home/paran/linux/net/socket.c:1341 vfs_ioctl+0x90/0x140 home/paran/linux/fs/ioctl.c:51 __do_sys_ioctl home/paran/linux/fs/ioctl.c:907 [inline] __se_sys_ioctl home/paran/linux/fs/ioctl.c:893 [inline] __arm64_sys_ioctl+0x218/0x268 home/paran/linux/fs/ioctl.c:893 __invoke_syscall home/paran/linux/arch/arm64/kernel/syscall.c:34 [inline] invoke_syscall+0xdc/0x460 home/paran/linux/arch/arm64/kernel/syscall.c:48 el0_svc_common.constprop.0+0x2d4/0x3e8 home/paran/linux/arch/arm64/kernel/syscall.c:133 do_el0_svc+0x60/0x98 home/paran/linux/arch/arm64/kernel/syscall.c:152 el0_svc+0xc4/0x240 home/paran/linux/arch/arm64/kernel/entry-common.c:712 el0t_64_sync_handler+0x120/0x130 home/paran/linux/arch/arm64/kernel/entry-common.c:730 el0t_64_sync+0x190/0x198 home/paran/linux/arch/arm64/kernel/entry.S:598 Allocated by task 577: kasan_save_stack+0x48/0x90 home/paran/linux/mm/kasan/common.c:47 kasan_save_track+0x38/0x60 home/paran/linux/mm/kasan/common.c:68 kasan_save_alloc_info+0x64/0xc0 home/paran/linux/mm/kasan/generic.c:565 unpoison_slab_object home/paran/linux/mm/kasan/common.c:312 [inline] __kasan_slab_alloc+0x100/0x110 home/paran/linux/mm/kasan/common.c:338 kasan_slab_alloc home/paran/linux/./include/linux/kasan.h:201 [inline] slab_post_alloc_hook home/paran/linux/mm/slub.c:3941 [inline] slab_alloc_node home/paran/linux/mm/slub.c:4001 [inline] kmem_cache_alloc_noprof+0x2e8/0x630 home/paran/linux/mm/slub.c:4008 skb_clone+0x1a4/0x4d0 home/paran/linux/net/core/skbuff.c:2052 hci_cmd_work+0x78c/0x868 [bluetooth] process_one_work home/paran/linux/kernel/workqueue.c:3231 [inline] process_scheduled_works+0x9fc/0x1d98 home/paran/linux/kernel/workqueue.c:3312 worker_thread+0x57c/0xf98 home/paran/linux/kernel/workqueue.c:3393 kthread+0x3c8/0x478 home/paran/linux/kernel/kthread.c:389 ret_from_fork+0x10/0x20 home/paran/linux/arch/arm64/kernel/entry.S:860 Freed by task 577: kasan_save_stack+0x48/0x90 home/paran/linux/mm/kasan/common.c:47 kasan_save_track+0x38/0x60 home/paran/linux/mm/kasan/common.c:68 kasan_save_free_info+0x64/0xf0 home/paran/linux/mm/kasan/generic.c:579 poison_slab_object+0x168/0x270 home/paran/linux/mm/kasan/common.c:240 __kasan_slab_free+0x34/0xa0 home/paran/linux/mm/kasan/common.c:256 kasan_slab_free home/paran/linux/./include/linux/kasan.h:184 [inline] slab_free_hook home/paran/linux/mm/slub.c:2196 [inline] slab_free home/paran/linux/mm/slub.c:4437 [inline] kmem_cache_free+0x20c/0x670 home/paran/linux/mm/slub.c:4512 kfree_skbmem+0x2b0/0x390 home/paran/linux/net/core/skbuff.c:1131 __kfree_skb home/paran/linux/net/core/skbuff.c:1188 [inline] kfree_skb_reason+0x14c/0x3a8 home/paran/linux/net/core/skbuff.c:1223 hci_req_sync_complete+0x114/0x308 [bluetooth] hci_event_packet+0xa10/0x12a0 [bluetooth] hci_rx_work+0x4d8/0xa80 [bluetooth] process_one_work home/paran/linux/kernel/workqueue.c:3231 [inline] process_scheduled_works+0x9fc/0x1d98 home/paran/linux/kernel/workqueue.c:3312 worker_thread+0x57c/0xf98 home/paran/linux/kernel/workqueue.c:3393 kthread+0x3c8/0x478 home/paran/linux/kernel/kthread.c:389 ret_from_fork+0x10/0x20 home/paran/linux/arch/arm64/kernel/entry.S:860 The buggy address belongs to the object at ffff00000947d380 which belongs to the cache skbuff_head_cache of size 232
The buggy address is located 126 bytes inside of
freed 232-byte region [ffff00000947d380, ffff00000947d468)
The buggy address belongs to the physical page: page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x4947c
head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 memcg:ffff0000222a73b1
flags: 0x3fffe0000000040(head|node=0|zone=0|lastcpupid=0x1ffff)page_type: 0xffffefff(slab)
raw: 03fffe0000000040 ffff0000133a41c0 fffffdffc0e3a090 fffffdffc1069290 raw: 0000000000000000 0000000000120012 00000001ffffefff ffff0000222a73b1
head: 03fffe0000000040 ffff0000133a41c0 fffffdffc0e3a090 fffffdffc1069290
head: 0000000000000000 0000000000120012 00000001ffffefff ffff0000222a73b1
head: 03fffe0000000001 fffffdffc0251f01 ffffffffffffffff 0000000000000000
head: 0000000000000002 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff00000947d280: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc
ffff00000947d300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff00000947d380: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff00000947d400: fb fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc
ffff00000947d480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================We considered using the "hci_req_sync_lock" mutex, but concluded it wasn't a good solution due to the increased sleep intervals causing this issue. Instead, we introduced a spinlock member on 'struct hci_dev'.
Since applying our patch, we have repeatedly run the same tests in the syzkaller without encountering any issues.
--- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 1 + net/bluetooth/hci_request.c | 6 ++---- net/bluetooth/hci_request.h | 9 +++++++++ net/bluetooth/hci_sync.c | 13 +++---------- 5 files changed, 16 insertions(+), 14 deletions(-)
include/net/bluetooth/hci_core.h +1 -0
@@ -519,6 +519,7 @@ struct hci_dev {struct sk_buff *recv_event;struct mutex req_lock; +spinlock_t req_skb_lock;wait_queue_head_t req_wait_q;__u32 req_status;__u32 req_result;
net/bluetooth/hci_core.c +1 -0
@@ -2572,6 +2572,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)mutex_init (&hdev->lock);mutex_init (&hdev->req_lock); +spin_lock_init (&hdev->req_skb_lock);ida_init (&hdev->unset_handle_ida);
net/bluetooth/hci_request.c +2 -4
@@ -106,8 +106,7 @@ void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, hdev->req_result = result; hdev->req_status =HCI_REQ_DONE ;if (skb) { -kfree_skb (hdev->req_skb); - hdev->req_skb =skb_get (skb); +hci_req_skb_release_and_set (hdev,skb_get (skb)); }wake_up_interruptible (&hdev->req_wait_q); }
@@ -181,8 +180,7 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,break ; } -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ; +hci_req_skb_release_and_set (hdev,NULL ); hdev->req_status = hdev->req_result =0 ;bt_dev_dbg (hdev,"end: err %d" , err);
net/bluetooth/hci_request.h +9 -0
@@ -28,6 +28,15 @@#define hci_req_sync_lock (hdev) mutex_lock(&hdev->req_lock)#define hci_req_sync_unlock (hdev) mutex_unlock(&hdev->req_lock) +#define hci_req_skb_release_and_set (hdev, val) \ +({ \ + if (hdev->req_skb) { \ + spin_lock(&hdev->req_skb_lock); \ + kfree_skb(hdev->req_skb); \ + hdev->req_skb = val; \ + spin_unlock(&hdev->req_skb_lock); \ + } \ +})struct hci_request {struct hci_dev *hdev;
net/bluetooth/hci_sync.c +3 -10
@@ -33,8 +33,7 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, hdev->req_status =HCI_REQ_DONE ;/* Free the request command so it is not used as response */ -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ; +hci_req_skb_release_and_set (hdev,NULL );if (skb) {struct sock *sk =hci_skb_sk (skb);
@@ -4935,10 +4934,7 @@ int hci_dev_open_sync(struct hci_dev *hdev) hdev->sent_cmd =NULL ; } -if (hdev->req_skb) { -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ; - } +hci_req_skb_release_and_set (hdev,NULL );clear_bit (HCI_RUNNING , &hdev->flags);hci_sock_dev_event (hdev,HCI_DEV_CLOSE );
@@ -5100,10 +5096,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) }/* Drop last request */ -if (hdev->req_skb) { -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ; - } +hci_req_skb_release_and_set (hdev,NULL );clear_bit (HCI_RUNNING , &hdev->flags);hci_sock_dev_event (hdev,HCI_DEV_CLOSE );
Signature · 1 line
2.45.2
Luiz Augusto von Dentz
maintainerHi,
Quoted 7 lines · Yunseong Kim
The approach taken to address the 'CVE-2024-35978' introduced another double-free vulnerability. commit
45d355a926ab("Bluetooth: Fix memory leak inhci_req_sync_complete()")'
hdev->req_skb' double free scenario:
Quoted 7 lines
cpu1 cpu2
==== ====
sock_ioctl
sock_do_ioctl
hci_sock_ioctl
hci_dev_cmd
hci_req_sync
hci_req_sync is no longer called from hci_dev_cmd:
And I'm in process of removing hci_request.c completely.
Quoted 211 lines
__hci_req_sync hci_rx_work kfree_skb(hdev->req_skb) hci_event_packet (sleep) hci_req_sync_complete \__ Longer times, kfree_skb(hdev->req_skb) reproduce well hdev->req_skb = NULLThe longer cpu1 sleep in '
__hci_req_sync', the more reproducible it is. We've tested it by inserting the 'msleep()' function, and it's frequently at 1000ms, and It has been consistently reproducible at 2000ms.We confirmed the detection with various workloads that cause CPU1 to sleep. The call trace below is one of the KASAN has seen.
Bluetooth: hci0: unexpected cc
0x0c38length: 249 > 2
==================================================================BUG: KASAN: slab-use-after-free in skb_release_data+0x7d8/0x8a0 home/paran/linux/net/core/skbuff.c:1119 Write of size 1 at addr ffff00000947d3fe by task syz-executor.2/2010 CPU: 1 PID: 2010 Comm: syz-executor.2 Not tainted 6.10.0-rc4-00217-g35bb670d65fc-dirty #22 Hardware name: linux,dummy-virt (DT) Call trace: dump_backtrace+0x318/0x348 home/paran/linux/arch/arm64/kernel/stacktrace.c:317 show_stack+0x4c/0x80 home/paran/linux/arch/arm64/kernel/stacktrace.c:324 __dump_stack home/paran/linux/lib/dump_stack.c:88 [inline] dump_stack_lvl+0x214/0x328 home/paran/linux/lib/dump_stack.c:114 print_address_description home/paran/linux/mm/kasan/report.c:377 [inline] print_report+0x2ac/0x948 home/paran/linux/mm/kasan/report.c:488 kasan_report+0xc8/0x148 home/paran/linux/mm/kasan/report.c:601 __asan_report_store1_noabort+0x44/0x60 home/paran/linux/mm/kasan/report_generic.c:383 skb_release_data+0x7d8/0x8a0 home/paran/linux/net/core/skbuff.c:1119 skb_release_all+0x80/0xe0 home/paran/linux/net/core/skbuff.c:1173 __kfree_skb home/paran/linux/net/core/skbuff.c:1187 [inline] kfree_skb_reason+0x138/0x3a8 home/paran/linux/net/core/skbuff.c:1223 __hci_req_sync+0x404/0x948 [bluetooth] hci_req_sync+0xc0/0x138 [bluetooth] hci_dev_cmd+0x33c/0xc18 [bluetooth] hci_sock_ioctl+0x800/0xb68 [bluetooth] sock_do_ioctl+0xfc/0x2e0 home/paran/linux/net/socket.c:1222 sock_ioctl+0x62c/0xab0 home/paran/linux/net/socket.c:1341 vfs_ioctl+0x90/0x140 home/paran/linux/fs/ioctl.c:51 __do_sys_ioctl home/paran/linux/fs/ioctl.c:907 [inline] __se_sys_ioctl home/paran/linux/fs/ioctl.c:893 [inline] __arm64_sys_ioctl+0x218/0x268 home/paran/linux/fs/ioctl.c:893 __invoke_syscall home/paran/linux/arch/arm64/kernel/syscall.c:34 [inline] invoke_syscall+0xdc/0x460 home/paran/linux/arch/arm64/kernel/syscall.c:48 el0_svc_common.constprop.0+0x2d4/0x3e8 home/paran/linux/arch/arm64/kernel/syscall.c:133 do_el0_svc+0x60/0x98 home/paran/linux/arch/arm64/kernel/syscall.c:152 el0_svc+0xc4/0x240 home/paran/linux/arch/arm64/kernel/entry-common.c:712 el0t_64_sync_handler+0x120/0x130 home/paran/linux/arch/arm64/kernel/entry-common.c:730 el0t_64_sync+0x190/0x198 home/paran/linux/arch/arm64/kernel/entry.S:598 Allocated by task 577: kasan_save_stack+0x48/0x90 home/paran/linux/mm/kasan/common.c:47 kasan_save_track+0x38/0x60 home/paran/linux/mm/kasan/common.c:68 kasan_save_alloc_info+0x64/0xc0 home/paran/linux/mm/kasan/generic.c:565 unpoison_slab_object home/paran/linux/mm/kasan/common.c:312 [inline] __kasan_slab_alloc+0x100/0x110 home/paran/linux/mm/kasan/common.c:338 kasan_slab_alloc home/paran/linux/./include/linux/kasan.h:201 [inline] slab_post_alloc_hook home/paran/linux/mm/slub.c:3941 [inline] slab_alloc_node home/paran/linux/mm/slub.c:4001 [inline] kmem_cache_alloc_noprof+0x2e8/0x630 home/paran/linux/mm/slub.c:4008 skb_clone+0x1a4/0x4d0 home/paran/linux/net/core/skbuff.c:2052 hci_cmd_work+0x78c/0x868 [bluetooth] process_one_work home/paran/linux/kernel/workqueue.c:3231 [inline] process_scheduled_works+0x9fc/0x1d98 home/paran/linux/kernel/workqueue.c:3312 worker_thread+0x57c/0xf98 home/paran/linux/kernel/workqueue.c:3393 kthread+0x3c8/0x478 home/paran/linux/kernel/kthread.c:389 ret_from_fork+0x10/0x20 home/paran/linux/arch/arm64/kernel/entry.S:860 Freed by task 577: kasan_save_stack+0x48/0x90 home/paran/linux/mm/kasan/common.c:47 kasan_save_track+0x38/0x60 home/paran/linux/mm/kasan/common.c:68 kasan_save_free_info+0x64/0xf0 home/paran/linux/mm/kasan/generic.c:579 poison_slab_object+0x168/0x270 home/paran/linux/mm/kasan/common.c:240 __kasan_slab_free+0x34/0xa0 home/paran/linux/mm/kasan/common.c:256 kasan_slab_free home/paran/linux/./include/linux/kasan.h:184 [inline] slab_free_hook home/paran/linux/mm/slub.c:2196 [inline] slab_free home/paran/linux/mm/slub.c:4437 [inline] kmem_cache_free+0x20c/0x670 home/paran/linux/mm/slub.c:4512 kfree_skbmem+0x2b0/0x390 home/paran/linux/net/core/skbuff.c:1131 __kfree_skb home/paran/linux/net/core/skbuff.c:1188 [inline] kfree_skb_reason+0x14c/0x3a8 home/paran/linux/net/core/skbuff.c:1223 hci_req_sync_complete+0x114/0x308 [bluetooth] hci_event_packet+0xa10/0x12a0 [bluetooth] hci_rx_work+0x4d8/0xa80 [bluetooth] process_one_work home/paran/linux/kernel/workqueue.c:3231 [inline] process_scheduled_works+0x9fc/0x1d98 home/paran/linux/kernel/workqueue.c:3312 worker_thread+0x57c/0xf98 home/paran/linux/kernel/workqueue.c:3393 kthread+0x3c8/0x478 home/paran/linux/kernel/kthread.c:389 ret_from_fork+0x10/0x20 home/paran/linux/arch/arm64/kernel/entry.S:860 The buggy address belongs to the object at ffff00000947d380 which belongs to the cache skbuff_head_cache of size 232The buggy address is located 126 bytes inside of
freed 232-byte region [ffff00000947d380,ffff00000947d468)The buggy address belongs to the physical page: page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x4947chead: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 memcg:ffff0000222a73b1
flags: 0x3fffe0000000040(head|node=0|zone=0|lastcpupid=0x1ffff)page_type: 0xffffefff(slab)raw: 03fffe0000000040 ffff0000133a41c0 fffffdffc0e3a090 fffffdffc1069290 raw: 0000000000000000 0000000000120012 00000001ffffefff ffff0000222a73b1head:
03fffe0000000040ffff0000133a41c0fffffdffc0e3a090fffffdffc1069290
head: 0000000000000000 000000000012001200000001ffffefffffff0000222a73b1
head:03fffe0000000001fffffdffc0251f01ffffffffffffffff 0000000000000000
head: 0000000000000002 000000000000000000000000ffffffff0000000000000000page dumped because: kasan: bad access detected Memory state around the buggy address: ffff00000947d280: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc ffff00000947d300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc >ffff00000947d380: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff00000947d400: fb fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc ffff00000947d480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ==================================================================We considered using the "
hci_req_sync_lock" mutex, but concluded it wasn't a good solution due to the increased sleep intervals causing this issue. Instead, we introduced a spinlock member on 'structhci_dev'.Since applying our patch, we have repeatedly run the same tests in the syzkaller without encountering any issues.
Fixes 45d355a926ab ("Bluetooth: Fix memory leak in hci_req_sync_complete()")Signed-off-by Levi Yun <[email protected]>Signed-off-by Yunseong Kim <[email protected]>--- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 1 + net/bluetooth/hci_request.c | 6 ++---- net/bluetooth/hci_request.h | 9 +++++++++ net/bluetooth/hci_sync.c | 13 +++---------- 5 files changed, 16 insertions(+), 14 deletions(-)include/net/bluetooth/hci_core.h +1
-0@@ -519,6 +519,7 @@ struct hci_dev {struct sk_buff *recv_event;struct mutex req_lock; +spinlock_t req_skb_lock;wait_queue_head_t req_wait_q;__u32 req_status;__u32 req_result;net/bluetooth/hci_core.c +1
-0@@ -2572,6 +2572,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)mutex_init (&hdev->lock);mutex_init (&hdev->req_lock); +spin_lock_init (&hdev->req_skb_lock);ida_init (&hdev->unset_handle_ida);net/bluetooth/hci_request.c +2
-4@@ -106,8 +106,7 @@ void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, hdev->req_result = result; hdev->req_status =HCI_REQ_DONE ;if (skb) { -kfree_skb (hdev->req_skb); - hdev->req_skb =skb_get (skb); +hci_req_skb_release_and_set (hdev,skb_get (skb)); }wake_up_interruptible (&hdev->req_wait_q); }@@ -181,8 +180,7 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,break ; } -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ; +hci_req_skb_release_and_set (hdev,NULL ); hdev->req_status = hdev->req_result =0 ;bt_dev_dbg (hdev,"end: err %d" , err);net/bluetooth/hci_request.h +9
-0@@ -28,6 +28,15 @@#define hci_req_sync_lock (hdev) mutex_lock(&hdev->req_lock)#define hci_req_sync_unlock (hdev) mutex_unlock(&hdev->req_lock) +#define hci_req_skb_release_and_set (hdev, val) \ +({ \ + if (hdev->req_skb) { \ + spin_lock(&hdev->req_skb_lock); \ + kfree_skb(hdev->req_skb); \ + hdev->req_skb = val; \ + spin_unlock(&hdev->req_skb_lock); \ + } \ +})struct hci_request {struct hci_dev *hdev;net/bluetooth/hci_sync.c +0
-0
net/bluetooth/hci_sync.c static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, · line 37
Quoted 5 lines
net/bluetooth/hci_sync.c +0
-2@@ -33,8 +33,7 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, hdev->req_status =HCI_REQ_DONE ;/* Free the request command so it is not used as response */ -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ;
This doesn't even apply upstream
Quoted 31 lines
net/bluetooth/hci_sync.c +3
-9+hci_req_skb_release_and_set (hdev,NULL );if (skb) {struct sock *sk =hci_skb_sk (skb);@@ -4935,10 +4934,7 @@ int hci_dev_open_sync(struct hci_dev *hdev) hdev->sent_cmd =NULL ; } -if (hdev->req_skb) { -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ; - } +hci_req_skb_release_and_set (hdev,NULL );clear_bit (HCI_RUNNING , &hdev->flags);hci_sock_dev_event (hdev,HCI_DEV_CLOSE );@@ -5100,10 +5096,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) }/* Drop last request */ -if (hdev->req_skb) { -kfree_skb (hdev->req_skb); - hdev->req_skb =NULL ; - } +hci_req_skb_release_and_set (hdev,NULL );clear_bit (HCI_RUNNING , &hdev->flags);hci_sock_dev_event (hdev,HCI_DEV_CLOSE ); --2.45.2
Signature · 1 line
Luiz Augusto von Dentz
Hi Luiz,
Quoted 18 lines · Luiz Augusto von Dentz
Hi,
Quoted 7 lines · Yunseong Kim
The approach taken to address the 'CVE-2024-35978' introduced another double-free vulnerability. commit
45d355a926ab("Bluetooth: Fix memory leak inhci_req_sync_complete()")'
hdev->req_skb' double free scenario:Quoted 7 lines
cpu1 cpu2
==== ====
sock_ioctl
sock_do_ioctl
hci_sock_ioctl
hci_dev_cmd
hci_req_sync
Quoted 12 lines
hci_req_syncis no longer called fromhci_dev_cmd:And I'm in process of removing
hci_request.ccompletely.Quoted 6 lines
__hci_req_sync hci_rx_work kfree_skb(hdev->req_skb) hci_event_packet (sleep) hci_req_sync_complete \__ Longer times, kfree_skb(hdev->req_skb) reproduce well hdev->req_skb = NULL
Thank you so much your hard work.
I saw the patch email at the link below.
Link:
https://lore.kernel.org/all/[email protected]/T/
Does the patch you mentioned apply to backports as well?
Warm regards,
Yunseong Kim
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=867274
---Test result---
Test Summary:
CheckPatch FAIL 1.82 seconds GitLint FAIL 0.49 seconds SubjectPrefix FAIL 0.31 seconds BuildKernel PASS 30.54 seconds CheckAllWarning PASS 45.30 seconds CheckSparse PASS 38.87 seconds CheckSmatch PASS 107.07 seconds BuildKernel32 PASS 29.74 seconds TestRunnerSetup PASS 530.55 seconds TestRunner_l2cap-tester PASS 24.05 seconds TestRunner_iso-tester PASS 37.17 seconds TestRunner_bnep-tester PASS 4.93 seconds TestRunner_mgmt-tester FAIL 110.24 seconds TestRunner_rfcomm-tester PASS 7.56 seconds TestRunner_sco-tester PASS 15.26 seconds TestRunner_ioctl-tester PASS 8.16 seconds TestRunner_mesh-tester PASS 6.21 seconds TestRunner_smp-tester PASS 7.00 seconds TestRunner_userchan-tester PASS 10.04 seconds IncrementalBuild PASS 28.81 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
hci: fix double free in hci_req_sync
WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?) #129:
6.10.0-rc4-00217-g35bb670d65fc-dirty #22 Hardware name: linux,dummy-virt (DT)
CHECK: Macro argument reuse 'hdev' - possible side-effects? #304: FILE: net/bluetooth/hci_request.h:31:
+#define hci_req_skb_release_and_set(hdev, val) \
+({ \
+ if (hdev->req_skb) { \
+ spin_lock(&hdev->req_skb_lock); \
+ kfree_skb(hdev->req_skb); \
+ hdev->req_skb = val; \
+ spin_unlock(&hdev->req_skb_lock); \
+ } \
+})
CHECK: Macro argument 'hdev' may be better as '(hdev)' to avoid precedence issues #304: FILE: net/bluetooth/hci_request.h:31:
+#define hci_req_skb_release_and_set(hdev, val) \
+({ \
+ if (hdev->req_skb) { \
+ spin_lock(&hdev->req_skb_lock); \
+ kfree_skb(hdev->req_skb); \
+ hdev->req_skb = val; \
+ spin_unlock(&hdev->req_skb_lock); \
+ } \
+})
total: 0 errors, 1 warnings, 2 checks, 78 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/src/13718597.patch has style problems, please review.
NOTE: Ignored message types: UNKNOWN_COMMIT_ID
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
hci: fix double free in hci_req_sync
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
31: B1 Line exceeds max length (103>80): "BUG: KASAN: slab-use-after-free in skb_release_data+0x7d8/0x8a0 home/paran/linux/net/core/skbuff.c:1119"
44: B1 Line exceeds max length (86>80): " __asan_report_store1_noabort+0x44/0x60 home/paran/linux/mm/kasan/report_generic.c:383"
61: B1 Line exceeds max length (88>80): " el0_svc_common.constprop.0+0x2d4/0x3e8 home/paran/linux/arch/arm64/kernel/syscall.c:133"
64: B1 Line exceeds max length (87>80): " el0t_64_sync_handler+0x120/0x130 home/paran/linux/arch/arm64/kernel/entry-common.c:730"
139: B2 Line has trailing whitespace: "Since applying our patch, we have repeatedly run the same tests in "
142: B1 Line exceeds max length (122>80): "Link: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=89a32741f4217856066c198a4a7267bcdd1edd67"
##############################
Test: SubjectPrefix - FAIL
Desc: Check subject contains "Bluetooth" prefix
Output:
"Bluetooth: " prefix is not specified in the subject
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 492, Passed: 489 (99.4%), Failed: 1, Not Run: 2
Failed Test Cases
LL Privacy - Add Device 4 (2 Devices to AL) Failed 0.163 seconds
---
Regards,
Linux Bluetooth
…
net/bluetooth/hci_request.c void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, · line 111
Quoted 10 lines
+++
b/net/bluetooth/hci_request.cnet/bluetooth/hci_request.c +1
-2@@ -106,8 +106,7 @@ void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, hdev->req_result = result; hdev->req_status =HCI_REQ_DONE ;if (skb) { -kfree_skb (hdev->req_skb); - hdev->req_skb =skb_get (skb); +hci_req_skb_release_and_set (hdev,skb_get (skb)); }wake_up_interruptible (&hdev->req_wait_q);
…
How do you think about to omit any curly brackets here?
…
Quoted 4 lines
net/bluetooth/hci_request.h +1
-0+++ b/net/bluetooth/hci_request.h@@ -28,6 +28,15 @@#define hci_req_sync_lock (hdev) mutex_lock(&hdev->req_lock)
net/bluetooth/hci_request.h line 39
Quoted 10 lines
net/bluetooth/hci_request.h +9
-0#define hci_req_sync_unlock (hdev) mutex_unlock(&hdev->req_lock) +#define hci_req_skb_release_and_set (hdev, val) \ +({ \ + if (hdev->req_skb) { \ + spin_lock(&hdev->req_skb_lock); \ + kfree_skb(hdev->req_skb); \ + hdev->req_skb = val; \ + spin_unlock(&hdev->req_skb_lock); \ + } \ +})
…
* Do you expect that any data synchronisation should be performed for the shown pointer check?
* Can it eventually matter to implement such a macro with a statement like “guard(spinlock)(&hdev->req_skb_lock);”?
https://elixir.bootlin.com/linux/v6.10-rc6/source/include/linux/spinlock.h#L561
Regards,
Markus