From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.216.52 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793279565; b=jYGQZOQvgINJauHARr2ojvnJ8Jv9YUBofCZXkhAcU+rBMgLC1C6S3bJFAFxyZ+XgX0v3 iXaUofegN+ynjFXWpryWf5rKjtroPFZkR0ypbtqJbZwJG/T07o3hTdBQljofDHAbGyiuL 2i91ye6JUig86Mxrfe5hWyxy+dW5vLTAKbIffMi4hhfWNKIfXE0RhWPFqonZiVx+mTDGT vMeVvuD13TcfTzDUncNFqbBneAvCp9K7MGw6pDl1KpDMBiDxJvnl68j/vrOk9lkzMlFjM RqE65WUkDT/my8d5UHOMwm6pumYrgIhP2RSpYNmo8/Yn75bhTnYSMuI+Wy7eHOoXD8w== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793279565; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=4Sd/OQGtJkeXZk5BSc86/9EjmvIr9Fkqx8cwz8Jfs40=; b=CTt8glfrO1lx/DQX0pr09WSd5DdmvOUX+qPnW0PPFy3ZejwbTeBL3uD7tiYYNhCeN1N/ nXllnCl7C/uJIMznl2okgD/uovFDNXMhla/Yo/Vyn6U6QU1vrYf01ZBOBVFc0tgUy9MCp ptb70uWWpzeGHrxrjqCiO7PYhA50UeNBC0SVUoTnQaa2J2ahq3xnJmaBkeI7Hz7vI5nfc 6TLcXoTckLaY4aNg4vKm6ZIsDJGYG4ZGseD87ieAd+BKLALRQXMiFbpM9+Pclmg0ZFD4n UO4WpYqaOsQGah31E4C2V1zSwr0BAp6J1/A7y2yapEdFs5+ezh2mZTTJhO45TIedosg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=AXKec16p; arc=none smtp.remote-ip=209.85.216.52 Received: from mail-pj1-f52.google.com (mail-pj1-f52.google.com [209.85.216.52]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E7756606A33F for ; Thu, 29 Oct 2026 13:12:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org E7756606A33F 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, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=AXKec16p Received: by mail-pj1-f52.google.com with SMTP id 98e67ed59e1d1-3ac78f4c10bso1041892a91.1 for ; Thu, 29 Oct 2026 06:12:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793279564; x=1793884364; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=4Sd/OQGtJkeXZk5BSc86/9EjmvIr9Fkqx8cwz8Jfs40=; b=AXKec16pl+6z6yHbl1TZWuSc1Z56cwd4J1VCXJvMRDQYf2PtsveBYMY+a2TLpvdbh1 l3bRNRpfigDcVuo9qdhIlmciXBTC5JcgPF2MjS3I/kUIIKAnKajm/HpZvRCPxLESP7FE EbLxQnMovOlyLz8yubLcE6n0lpfZoPmVIY9lRGNhYu5TL7MvKzJrb+dQEY+kThE+21aH yHuXx74ulc1Z42jgQG08DSu1aDIZGL1MHjKi648th/AA2IrbQMub+Ft+F/O3a9u7T9j4 OLNdRhYLcLJOgG6rvOy8gcIeGYjwtZuWPFiqi/CRCMBzRYh3SmgXkcPk74TXjVts8tbF yOtQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793279564; x=1793884364; h=content-transfer-encoding:mime-version:references:in-reply-to :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=4Sd/OQGtJkeXZk5BSc86/9EjmvIr9Fkqx8cwz8Jfs40=; b=0xhAaG4Sp4iRMUktUsmJgp2pbCVOYY/bPfgmjQmwb/88jn4lJynx/OiWaAweDNLoSA 2gAWFDiIDYcCYt2xWy8ImrHBFV6Z97yDJJ/oLBY+aJYfY+6Gf07TmdfZIYvlDTthgFvo 6SB/8ynYiylxW1yZXPB8PAXr+XjJno4K83KU8ULZLR+Q/1jiPtsRCHEgVXMkYKEBEey3 mcdVTsUNqc46bijxP0o3lnL+obBy4eb8TwgrM1PMTO/FoGhkYzjY8PwJw08msM9PCGkD CltryTx83jGkbQ6HjqyG9/WwVS7C7Up0QBkXZ7KMZbUJbUx2mMcD+k/Vkaq9Ppmyd7TS 962w== X-Forwarded-Encrypted: i=1; AKwUvBxptIVOWJELgLO3Uci5Dntqcb20EvuHRCZlqXZfCjIx6ksy3xgBhaHTwLPz4ALh+b8/6TduzYjWWO0KBSs=@vger.kernel.org X-Gm-Message-State: AFq9FYJUqFx4m+CB3ElN76DMfRbz+jWIbT0BjNUyrMC5KphbPyYBt5e8 61cFWxgAO+Lw7TALKAW4JzsWve5RAYmU5JvXCCdzk1zrl6thZlqPx6r3 X-Gm-Gg: AYBFou39sWwHgAIFM2xtVGF5D+Ak5D9dg0blxPrir/17R3iQ5DemRFbbyY/8HlM4UtD jzZohQzfKnbVMyFmvGYNwof3V2u32O/GktYArSL5WHbjLi+pdFy6gcmE/rcdUorAVLrF9Ln6lEJ T6MCsMUECdf5DgCgjytg2lTJO9BxCYI78b3o+68QBAZwPB6kJZ3JDXkg0l3vPB/o+H4xLHzaWRQ VzKQ3Ye4G/N5b9BL2+T6LvvZUA6JHx5trF2a9R3hmvh10AB4vatDyB43oYLni7MPKu9qiTZV8lz EjkT+4Lz54mC4kPbJk++XY3oMGYPmhirOiZgzDaxcnDV+LC6MQLTCXZuhkMREsVtTeVT7E+JAfZ j05FyEvGFKzLV/xuQvRghO4DOPp+JDgewJxmHFXkvpyNKUCmkPfpuPw1deHRaupTlzxEHkMbS3K L/+eZfqAEOc/+fYIIqgBOd5JFYYfif8uxy0eVjv7xti+SeRYo5i+0gE5/FPEBvEM/Zfs2NwD6jj yfCL4xF7ioW4VFbHNU6S/+3a1jcYK9pA7c2bNAk8bAF+Tqf35AOGAd0UuvJRjfN6iAVl3EmnH5L YX+3Q7r3Gkp2e+JfwOwURiGrGoY9Pm04/1Vdo4Dd0aFRNA== X-Received: by 2002:a17:90a:e18e:b0:3aa:f875:3385 with SMTP id 98e67ed59e1d1-3ae580a01e1mr4232675a91.26.1793279564181; Thu, 29 Oct 2026 06:12:44 -0700 (PDT) Received: from localhost ([111.228.63.84]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3ae55d555d4sm4090445a91.1.2026.10.29.06.12.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2026 06:12:43 -0700 (PDT) From: Cen Zhang To: marcel@holtmann.org, luiz.dentz@gmail.com Cc: linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, jjzuming@gmail.com, zzzccc427@gmail.com Subject: [PATCH 2/4] Bluetooth: SMP: Protect link keys during LTK derivation Date: Thu, 29 Oct 2026 21:12:27 +0800 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit sc_generate_ltk() reads the type and value of the peer link key after hci_find_link_key() has returned. The finder ends its RCU read-side section before returning the borrowed entry, and the SMP receive path does not hold hdev->lock: l2cap_recv_acldata() releases it before the PDU is dispatched. The L2CAP connection and channel locks held by SMP do not serialize with management link-key removal. When BR/EDR Secure Connections pairing derives an LTK from the stored link key, MGMT_OP_LOAD_LINK_KEYS can free that key mid-derivation: HCI RX worker (SMP) Management / RCU reclamation sc_generate_ltk() key = hci_find_link_key() load_link_keys() hci_dev_lock(hdev) hci_link_keys_clear(hdev) list_del_rcu(), kfree_rcu() hci_dev_unlock(hdev) grace period ends, key is freed read key->type smp_h6() or smp_h7() reads key->val Hold an RCU read-side section from the lookup until the type and value have been consumed. smp_h6() and smp_h7() only run the synchronous AES-CMAC library code, which neither sleeps nor allocates. Release the section before sc_add_ltk(), which allocates with GFP_KERNEL. KASAN reported this on a test kernel whose scheduling hook paused the receive worker after the lookup; the hook frames appear in the trace. KASAN report as below: ================================================================== BUG: KASAN: slab-use-after-free in smp_distribute_keys+0x2983/0x2b70 Read of size 1 at addr ffff88810618e9a6 by task kworker/u17:0/500 CPU: 0 UID: 0 PID: 500 Comm: kworker/u17:0 Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #1 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: hci1 hci_rx_work Call Trace: dump_stack_lvl+0x93/0xd0 print_report+0xce/0x630 ? smp_distribute_keys+0x2983/0x2b70 ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x20d/0x410 ? smp_distribute_keys+0x2983/0x2b70 kasan_report+0xe0/0x110 ? smp_distribute_keys+0x2983/0x2b70 smp_distribute_keys+0x2983/0x2b70 ? __pfx_smp_distribute_keys+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_gate_maybe+0x47/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_probe_hit_cookie+0xe7/0x1c0 ? srso_alias_return_thunk+0x5/0xfbef5 ? pmbd_probe_hit_cookie+0xee/0x1c0 ? __pfx_pmbd_probe_hit_cookie+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __asan_memset+0x23/0x50 ? smp_recv_cb+0x12e2/0x8f30 ? srso_alias_return_thunk+0x5/0xfbef5 smp_recv_cb+0x12e2/0x8f30 ? __pfx_smp_recv_cb+0x10/0x10 ? __pfx___might_resched+0x10/0x10 ? __pfx_sched_balance_find_src_group+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_lock+0x182c/0x2590 ? l2cap_recv_frame+0x9ef/0x8830 ? __pfx___mutex_lock+0x10/0x10 ? __lock_acquire+0x466/0x2260 ? __pfx_l2cap_chan_hold_unless_zero+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? l2cap_recv_frame+0x13cc/0x8830 ? __pfx_smp_recv_cb+0x10/0x10 l2cap_recv_frame+0x13cc/0x8830 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_lock+0x182c/0x2590 ? __pfx_l2cap_recv_frame+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? find_held_lock+0x2b/0x80 ? l2cap_recv_acldata+0x1eb/0x10e0 ? __pfx___mutex_lock+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __mutex_unlock_slowpath+0x147/0x920 ? __pfx_l2cap_conn_hold_unless_zero+0x10/0x10 ? __pfx_hci_conn_enter_active_mode+0x10/0x10 ? l2cap_recv_acldata+0x13d/0x10e0 ? srso_alias_return_thunk+0x5/0xfbef5 l2cap_recv_acldata+0xe9f/0x10e0 ? srso_alias_return_thunk+0x5/0xfbef5 hci_rx_work+0x5a6/0xf00 ? srso_alias_return_thunk+0x5/0xfbef5 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 Allocated by task 500: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_cache_noprof+0x251/0x610 hci_add_link_key+0x474/0x840 hci_link_key_notify_evt+0x492/0xce0 hci_event_packet+0x894/0xc70 hci_rx_work+0x367/0xf00 process_one_work+0x908/0x19c0 worker_thread+0x65c/0xe40 kthread+0x34f/0x460 ret_from_fork+0x659/0x940 ret_from_fork_asm+0x1a/0x30 Freed by task 0: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 __rcu_free_sheaf_prepare+0x65/0x2a0 rcu_free_sheaf+0x1f/0xe0 rcu_core+0x661/0x1d10 handle_softirqs+0x201/0x930 __irq_exit_rcu+0x110/0x1e0 irq_exit_rcu+0xe/0x20 sysvec_apic_timer_interrupt+0x6c/0x80 asm_sysvec_apic_timer_interrupt+0x1a/0x20 The buggy address belongs to the object at ffff88810618e980 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 38 bytes inside of freed 64-byte region [ffff88810618e980, ffff88810618e9c0) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10618e flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff8881000428c0 dead000000000122 0000000000000000 raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88810618e880: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810618e900: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc >ffff88810618e980: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ ffff88810618ea00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffff88810618ea80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ================================================================== Fixes: b5ae344d4c0f ("Bluetooth: Add full SMP BR/EDR support") Assisted-by: LLM Signed-off-by: Cen Zhang --- net/bluetooth/smp.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 984b2d0b5e3e9..1d3f3ceb3ecc8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1186,9 +1186,13 @@ static void sc_generate_ltk(struct smp_chan *smp) struct hci_conn *hcon = smp->conn->hcon; struct hci_dev *hdev = hcon->hdev; struct link_key *key; + int err; + + rcu_read_lock(); key = hci_find_link_key(hdev, &hcon->dst); if (!key) { + rcu_read_unlock(); bt_dev_err(hdev, "no Link Key found to generate LTK"); return; } @@ -1200,16 +1204,19 @@ static void sc_generate_ltk(struct smp_chan *smp) /* SALT = 0x000000000000000000000000746D7032 */ const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 }; - if (smp_h7(key->val, salt, smp->tk)) - return; + err = smp_h7(key->val, salt, smp->tk); } else { /* From core spec. Spells out in ASCII as 'tmp2'. */ const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 }; - if (smp_h6(key->val, tmp2, smp->tk)) - return; + err = smp_h6(key->val, tmp2, smp->tk); } + rcu_read_unlock(); + + if (err) + return; + if (smp_h6(smp->tk, brle, smp->tk)) return;