lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20240410035300.21160-1-duoming@zju.edu.cn>
Date: Wed, 10 Apr 2024 11:53:00 +0800
From: Duoming Zhou <duoming@....edu.cn>
To: linux-bluetooth@...r.kernel.org
Cc: linux-kernel@...r.kernel.org,
	luiz.dentz@...il.com,
	johan.hedberg@...il.com,
	marcel@...tmann.org,
	Duoming Zhou <duoming@....edu.cn>
Subject: [PATCH v2] Bluetooth: Fix use-after-free bug caused by hci_cmd_timeout

When the kernel send a command to the hci device, the hdev->cmd_timer
will be scheduled to judge whether is command is timeout.

Meanwhile, the user space program uses ioctl(..., HCI_INQUIRY) to inquiry
the status of the command, it will wait the reply of the command until
the command is timeout. If it is timeout, the req_skb will be deallocated,
but req_skb could be dereferenced in hci_cmd_timeout() as well.

As a result, the use-after-free bug will happen. One of the scenarios
that could trigger the bug is shown below:

     thread 1                       thread2
hci_sock_ioctl()             | hci_sock_sendmsg()
 hci_inquiry()               |  queue_work(...,&hdev->cmd_work)
  hci_req_sync()             |   hci_cmd_work()
   __hci_req_sync()          |    queue_delayed_work(...,&hdev->cmd_timer)
    kfree_skb(hdev->req_skb) |     hci_cmd_timeout()
                             |      hci_skb_opcode(hdev->req_skb)

The KASan report for such a POC is shown below:

 ==================================================================
 BUG: KASAN: slab-use-after-free in hci_cmd_timeout+0x3c/0x110
 Read of size 2 at addr ffff8880087a1c78 by task kworker/u21:0/131
 ...
 Workqueue: hci0 hci_cmd_timeout
 Call Trace:
  <TASK>
  dump_stack_lvl+0x84/0xc0
  print_address_description+0x78/0x440
  print_report+0x11b/0x220
  ? pfn_valid+0xe4/0x140
  ? __virt_addr_valid+0x7c/0x90
  ? hci_cmd_timeout+0x3c/0x110
  kasan_report+0xc7/0x100
  ? hci_cmd_timeout+0x3c/0x110
  hci_cmd_timeout+0x3c/0x110
  process_one_work+0x2df/0x610
  worker_thread+0x72f/0x870
  ? pr_cont_work+0x280/0x280
  kthread+0x18a/0x1b0
  ? kthread_blkcg+0x50/0x50
  ret_from_fork+0x34/0x50
  ? kthread_blkcg+0x50/0x50
  ret_from_fork_asm+0x11/0x20
  </TASK>

 Allocated by task 131 on cpu 1 at 45.611537s:
  kasan_save_track+0x32/0x90
  __kasan_slab_alloc+0x4b/0x60
  kmem_cache_alloc+0xcb/0x240
  skb_clone+0x117/0x170
  hci_cmd_work+0x19c/0x2a0
  process_one_work+0x2df/0x610
  worker_thread+0x72f/0x870
  kthread+0x18a/0x1b0
  ret_from_fork+0x34/0x50
  ret_from_fork_asm+0x11/0x20

 Freed by task 135 on cpu 2 at 47.671850s:
  kasan_save_track+0x32/0x90
  kasan_save_free_info+0x40/0x50
  poison_slab_object+0x118/0x180
  __kasan_slab_free+0x12/0x30
  kmem_cache_free+0x92/0x200
  __hci_req_sync+0x2e2/0x350
  hci_req_sync+0x73/0x90
  hci_inquiry+0x1c1/0x350
  sock_do_ioctl+0x50/0x1a0
  sock_ioctl+0x2ea/0x3b0
  __se_sys_ioctl+0x89/0xd0
  do_syscall_64+0xc4/0x1b0
  entry_SYSCALL_64_after_hwframe+0x62/0x6a
  ...

In order to mitigate the bug, add cancel_delayed_work_sync() in
__hci_req_sync() to cancel the cmd_timer before the req_skb is
deallocated when the command is timeout.

Fixes: 9afee94939e3 ("Bluetooth: Fix memory leak at end of hci requests")
Signed-off-by: Duoming Zhou <duoming@....edu.cn>
---
Changes in v2:
  - Call cancel_delayed_work_sync() only if the command is timeout.

 net/bluetooth/hci_request.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 00e02138003..0b002f01816 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -174,6 +174,7 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
 
 	default:
 		err = -ETIMEDOUT;
+		cancel_delayed_work_sync(&hdev->cmd_timer);
 		if (hci_status)
 			*hci_status = HCI_ERROR_UNSPECIFIED;
 		break;
-- 
2.17.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ