All of lore.kernel.org
 help / color / mirror / Atom feed
From: Cen Zhang <zzzccc427@gmail.com>
To: Marcel Holtmann <marcel@holtmann.org>,
	Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Cc: linux-bluetooth@vger.kernel.org, baijiaju1990@gmail.com,
	zzzccc427@gmail.com
Subject: [PATCH] Bluetooth: MGMT: dequeue queued mesh send before freeing canceled tx
Date: Fri,  3 Jul 2026 14:00:24 +0800	[thread overview]
Message-ID: <20260703060024.570535-1-zzzccc427@gmail.com> (raw)

mesh_next() queues mesh_send_sync() with a raw mgmt_mesh_tx pointer after
a previous mesh send completes. MGMT_OP_MESH_SEND_CANCEL can already be
queued on the same hci_cmd_sync_work list. If cancel runs before the queued
send, it can remove and free the same mgmt_mesh_tx while mesh_send_sync()
still carries that pointer as callback data.

The buggy scenario involves two paths, with each column showing the order
within that path:

  mesh completion path:              cancel command path:
  1. mesh_send_done_sync() returns   1. send_cancel is already queued
  2. mesh_next() selects next_tx     2. send_cancel finds next_tx
  3. mesh_next() queues              3. send_cancel frees next_tx
     mesh_send_sync(next_tx)
  4. mesh_send_sync() later
     dereferences next_tx

Validation reproduced this kernel report:
BUG: KASAN: slab-use-after-free in mesh_send_sync+0x5a/0x1c0 [bluetooth]
Read of size 1 at addr ffff88811a01d13b by task kworker/u17:0/562
Workqueue: hci0 hci_cmd_sync_work [bluetooth]

Call Trace:
 <TASK>
 dump_stack_lvl+0x66/0xa0
 print_report+0xce/0x5f0
 ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
 ? __virt_addr_valid+0x19f/0x330
 ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
 kasan_report+0xe0/0x110
 ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
 ? __pfx_mesh_send_sync+0x10/0x10 [bluetooth]
 mesh_send_sync+0x5a/0x1c0 [bluetooth]
 ? mesh_send_sync+0x9/0x1c0 [bluetooth]
 ? __pfx_mesh_send_sync+0x10/0x10 [bluetooth]
 hci_cmd_sync_work+0x187/0x210 [bluetooth]
 process_one_work+0x4fd/0xbc0
 worker_thread+0x2d8/0x570
 kthread+0x1ad/0x1f0
 ret_from_fork+0x3c9/0x540
 ret_from_fork_asm+0x1a/0x30

Allocated by task 602:
 kasan_save_stack+0x33/0x60
 kasan_save_track+0x17/0x60
 __kasan_kmalloc+0xaa/0xb0
 mgmt_mesh_add+0x41/0x1a0 [bluetooth]
 mesh_send+0x197/0x3a0 [bluetooth]
 hci_sock_sendmsg+0x96b/0xf80 [bluetooth]
 __sys_sendto+0x2bc/0x2d0
 __x64_sys_sendto+0x76/0x90
 do_syscall_64+0x115/0x6a0
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 562:
 kasan_save_stack+0x33/0x60
 kasan_save_track+0x17/0x60
 kasan_save_free_info+0x3b/0x60
 __kasan_slab_free+0x5f/0x80
 kfree+0x313/0x590
 send_cancel+0x1d8/0x210 [bluetooth]
 hci_cmd_sync_work+0x187/0x210 [bluetooth]
 process_one_work+0x4fd/0xbc0
 worker_thread+0x2d8/0x570
 kthread+0x1ad/0x1f0
 ret_from_fork+0x3c9/0x540
 ret_from_fork_asm+0x1a/0x30

Dequeue any queued mesh_send_sync() for the target tx from send_cancel().
When a queued send is found, the dequeue path invokes
mesh_send_start_complete(), which completes and frees the tx; send_cancel()
must not complete it again.

Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
 net/bluetooth/mgmt.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 733a4b70e10c..ac4922cb39b5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2416,17 +2416,28 @@ static int send_cancel(struct hci_dev *hdev, void *data)
 	struct mgmt_mesh_tx *mesh_tx;
 
 	if (!cancel->handle) {
-		do {
+		for (;;) {
 			mesh_tx = mgmt_mesh_next(hdev, cmd->sk);
 
-			if (mesh_tx)
-				mesh_send_complete(hdev, mesh_tx, false);
-		} while (mesh_tx);
+			if (!mesh_tx)
+				break;
+
+			/* Dequeue any queued send before freeing the tx. */
+			if (hci_cmd_sync_dequeue(hdev, mesh_send_sync, mesh_tx,
+						 mesh_send_start_complete))
+				continue;
+
+			mesh_send_complete(hdev, mesh_tx, false);
+		}
 	} else {
 		mesh_tx = mgmt_mesh_find(hdev, cancel->handle);
 
-		if (mesh_tx && mesh_tx->sk == cmd->sk)
-			mesh_send_complete(hdev, mesh_tx, false);
+		if (mesh_tx && mesh_tx->sk == cmd->sk) {
+			/* Dequeue any queued send before freeing the tx. */
+			if (!hci_cmd_sync_dequeue(hdev, mesh_send_sync, mesh_tx,
+						  mesh_send_start_complete))
+				mesh_send_complete(hdev, mesh_tx, false);
+		}
 	}
 
 	mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
-- 
2.43.0

             reply	other threads:[~2026-07-03  6:00 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-03  6:00 Cen Zhang [this message]
2026-07-03  6:41 ` Bluetooth: MGMT: dequeue queued mesh send before freeing canceled tx bluez.test.bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260703060024.570535-1-zzzccc427@gmail.com \
    --to=zzzccc427@gmail.com \
    --cc=baijiaju1990@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=marcel@holtmann.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.