From: Cen Zhang <zzzccc427@gmail.com>
To: marcel@holtmann.org, luiz.dentz@gmail.com,
padovan@profusion.mobi, johan.hedberg@nokia.com
Cc: linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org,
baijiaju1990@gmail.com, jjzuming@gmail.com, zzzccc427@gmail.com
Subject: [PATCH] Bluetooth: MGMT: Serialize power-on with power-off completion
Date: Wed, 14 Oct 2026 00:28:14 +0800 [thread overview]
Message-ID: <pm-bluetooth-objects-candidate-0063-v7-35a6680c94a332fea155@gmail.com> (raw)
mgmt_set_powered_complete() must only consume the pending command for
its own request. However, __mgmt_power_off() removes and frees the
SET_POWERED command before the request's destroy callback runs, and
mgmt_pending_valid() identifies outstanding commands only by address.
When a powered controller is switched off and another management socket
requests power-on, the allocator can reuse the old command's address:
Power-off request worker Power-on management handler
------------------------ ---------------------------
__mgmt_power_off(): free cmd
hci_dev_close_sync(): unlock
set_powered_sync(): return
set_powered(): lock hdev
allocate and link replacement
mgmt_pending_valid(): unlink
replacement at old address
read replacement's cp->val = 1
wait for hdev->lock
submit fails: remove/free cmd
unlock hdev
acquire hdev->lock
read freed cmd->opcode
The old callback can respond through and free the new command instead of
completing its own request. If hci_cmd_sync_submit() fails to allocate
its work entry after the callback has unlinked the replacement,
set_powered() removes and frees it again while still holding hdev->lock.
The old callback then acquires that lock and reads the freed command.
Serialize power-on publication with the existing request mutex, which
hci_cmd_sync_work() holds across the request function and its destroy
callback. Hold it through submission and error cleanup so the
replacement cannot be published before the old callback finishes.
Acquire it before hdev->lock to preserve the worker's lock order.
Power-off retains its existing cancellation path.
KASAN report as below:
BUG: KASAN: slab-use-after-free in
mgmt_set_powered_complete+0x450/0x4d0
Read of size 2 at addr ffff88810921ab10 by task kworker/u17:0/500
Workqueue: hci0 hci_cmd_sync_work
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? mgmt_set_powered_complete+0x450/0x4d0
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? mgmt_set_powered_complete+0x450/0x4d0
kasan_report+0xe0/0x110
? mgmt_set_powered_complete+0x450/0x4d0
mgmt_set_powered_complete+0x450/0x4d0
? __pfx_mgmt_set_powered_complete+0x10/0x10
hci_cmd_sync_work+0x207/0x450
? __pfx_mgmt_set_powered_complete+0x10/0x10
process_one_work+0x908/0x19c0
? __pfx_process_one_work+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? lock_is_held_type+0x8f/0x100
? srso_alias_return_thunk+0x5/0xfbef5
worker_thread+0x65c/0xe40
? __pfx_worker_thread+0x10/0x10
kthread+0x34f/0x460
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_kthread+0x10/0x10
ret_from_fork+0x659/0x940
? __pfx_ret_from_fork+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __switch_to+0x74f/0xf80
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1a/0x30
</TASK>
Allocated by task 531:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x251/0x610
mgmt_pending_new+0x60/0x230
mgmt_pending_add+0x3b/0x180
set_powered+0x2a8/0x7e0
hci_sock_sendmsg+0x128b/0x22e0
__sys_sendto+0x425/0x470
__x64_sys_sendto+0xe5/0x1c0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 531:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
kfree+0x307/0x580
set_powered+0x336/0x7e0
hci_sock_sendmsg+0x128b/0x22e0
__sys_sendto+0x425/0x470
__x64_sys_sendto+0xe5/0x1c0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88810921ab00
which
belongs to the cache kmalloc-96 of size 96
The buggy address is located 16 bytes inside of
freed
96-byte region [ffff88810921ab00,
ffff88810921ab60)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0
pfn:0x10921a
flags: 0x200000000000000(node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000000 ffff888100042280 dead000000000100
dead000000000122
raw: 0000000000000000 0000000000200020 00000000f5000000
0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff88810921aa00: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc
ffff88810921aa80: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc
>ffff88810921ab00: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
^
ffff88810921ab80: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc
ffff88810921ac00: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc
==================================================================
Fixes: eec8d2bcc841 ("Bluetooth: Add support for set_powered management command")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9f65863e7457d..d523ae2268be8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1408,6 +1408,13 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
MGMT_STATUS_INVALID_PARAMS);
+ /*
+ * Wait for the previous power-off completion before publishing a
+ * new command that could reuse its freed pending-command address.
+ */
+ if (cp->val)
+ hci_req_sync_lock(hdev);
+
hci_dev_lock(hdev);
if (!cp->val) {
@@ -1451,6 +1458,8 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
failed:
hci_dev_unlock(hdev);
+ if (cp->val)
+ hci_req_sync_unlock(hdev);
return err;
}
next reply other threads:[~2026-10-13 16:28 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 16:28 Cen Zhang [this message]
2026-10-13 20:19 ` Bluetooth: MGMT: Serialize power-on with power-off completion bluez.test.bot
2026-10-14 19:11 ` [PATCH] " kernel test robot
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=pm-bluetooth-objects-candidate-0063-v7-35a6680c94a332fea155@gmail.com \
--to=zzzccc427@gmail.com \
--cc=baijiaju1990@gmail.com \
--cc=jjzuming@gmail.com \
--cc=johan.hedberg@nokia.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=marcel@holtmann.org \
--cc=padovan@profusion.mobi \
/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.