From: Greg Kroah-Hartman Date: Tue, 18 Mar 2025 16:47:25 +0000 (+0100) Subject: 6.6-stable patches X-Git-Tag: v6.6.84~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ebf7521699d7f44fd994461ed86efb0d18befabe;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: bluetooth-l2cap-fix-corrupted-list-in-hci_chan_del.patch hid-apple-disable-fn-key-handling-on-the-omoton-kb066.patch nvme-fc-rely-on-state-transitions-to-handle-connectivity-loss.patch nvme-tcp-fix-a-c2htermreq-error-message.patch --- diff --git a/queue-6.6/bluetooth-l2cap-fix-corrupted-list-in-hci_chan_del.patch b/queue-6.6/bluetooth-l2cap-fix-corrupted-list-in-hci_chan_del.patch new file mode 100644 index 0000000000..1fa04422ce --- /dev/null +++ b/queue-6.6/bluetooth-l2cap-fix-corrupted-list-in-hci_chan_del.patch @@ -0,0 +1,660 @@ +From ab4eedb790cae44313759b50fe47da285e2519d5 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Thu, 6 Feb 2025 15:54:45 -0500 +Subject: Bluetooth: L2CAP: Fix corrupted list in hci_chan_del + +From: Luiz Augusto von Dentz + +commit ab4eedb790cae44313759b50fe47da285e2519d5 upstream. + +This fixes the following trace by reworking the locking of l2cap_conn +so instead of only locking when changing the chan_l list this promotes +chan_lock to a general lock of l2cap_conn so whenever it is being held +it would prevents the likes of l2cap_conn_del to run: + +list_del corruption, ffff888021297e00->prev is LIST_POISON2 (dead000000000122) +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:61! +Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN PTI +CPU: 1 UID: 0 PID: 5896 Comm: syz-executor213 Not tainted 6.14.0-rc1-next-20250204-syzkaller #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 12/27/2024 +RIP: 0010:__list_del_entry_valid_or_report+0x12c/0x190 lib/list_debug.c:59 +Code: 8c 4c 89 fe 48 89 da e8 32 8c 37 fc 90 0f 0b 48 89 df e8 27 9f 14 fd 48 c7 c7 a0 c0 60 8c 4c 89 fe 48 89 da e8 15 8c 37 fc 90 <0f> 0b 4c 89 e7 e8 0a 9f 14 fd 42 80 3c 2b 00 74 08 4c 89 e7 e8 cb +RSP: 0018:ffffc90003f6f998 EFLAGS: 00010246 +RAX: 000000000000004e RBX: dead000000000122 RCX: 01454d423f7fbf00 +RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000 +RBP: dffffc0000000000 R08: ffffffff819f077c R09: 1ffff920007eded0 +R10: dffffc0000000000 R11: fffff520007eded1 R12: dead000000000122 +R13: dffffc0000000000 R14: ffff8880352248d8 R15: ffff888021297e00 +FS: 00007f7ace6686c0(0000) GS:ffff8880b8700000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f7aceeeb1d0 CR3: 000000003527c000 CR4: 00000000003526f0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +Call Trace: + + __list_del_entry_valid include/linux/list.h:124 [inline] + __list_del_entry include/linux/list.h:215 [inline] + list_del_rcu include/linux/rculist.h:168 [inline] + hci_chan_del+0x70/0x1b0 net/bluetooth/hci_conn.c:2858 + l2cap_conn_free net/bluetooth/l2cap_core.c:1816 [inline] + kref_put include/linux/kref.h:65 [inline] + l2cap_conn_put+0x70/0xe0 net/bluetooth/l2cap_core.c:1830 + l2cap_sock_shutdown+0xa8a/0x1020 net/bluetooth/l2cap_sock.c:1377 + l2cap_sock_release+0x79/0x1d0 net/bluetooth/l2cap_sock.c:1416 + __sock_release net/socket.c:642 [inline] + sock_close+0xbc/0x240 net/socket.c:1393 + __fput+0x3e9/0x9f0 fs/file_table.c:448 + task_work_run+0x24f/0x310 kernel/task_work.c:227 + ptrace_notify+0x2d2/0x380 kernel/signal.c:2522 + ptrace_report_syscall include/linux/ptrace.h:415 [inline] + ptrace_report_syscall_exit include/linux/ptrace.h:477 [inline] + syscall_exit_work+0xc7/0x1d0 kernel/entry/common.c:173 + syscall_exit_to_user_mode_prepare kernel/entry/common.c:200 [inline] + __syscall_exit_to_user_mode_work kernel/entry/common.c:205 [inline] + syscall_exit_to_user_mode+0x24a/0x340 kernel/entry/common.c:218 + do_syscall_64+0x100/0x230 arch/x86/entry/common.c:89 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f7aceeaf449 +Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 41 19 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f7ace668218 EFLAGS: 00000246 ORIG_RAX: 000000000000002a +RAX: fffffffffffffffc RBX: 00007f7acef39328 RCX: 00007f7aceeaf449 +RDX: 000000000000000e RSI: 0000000020000100 RDI: 0000000000000004 +RBP: 00007f7acef39320 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000003 +R13: 0000000000000004 R14: 00007f7ace668670 R15: 000000000000000b + +Modules linked in: +---[ end trace 0000000000000000 ]--- +RIP: 0010:__list_del_entry_valid_or_report+0x12c/0x190 lib/list_debug.c:59 +Code: 8c 4c 89 fe 48 89 da e8 32 8c 37 fc 90 0f 0b 48 89 df e8 27 9f 14 fd 48 c7 c7 a0 c0 60 8c 4c 89 fe 48 89 da e8 15 8c 37 fc 90 <0f> 0b 4c 89 e7 e8 0a 9f 14 fd 42 80 3c 2b 00 74 08 4c 89 e7 e8 cb +RSP: 0018:ffffc90003f6f998 EFLAGS: 00010246 +RAX: 000000000000004e RBX: dead000000000122 RCX: 01454d423f7fbf00 +RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000 +RBP: dffffc0000000000 R08: ffffffff819f077c R09: 1ffff920007eded0 +R10: dffffc0000000000 R11: fffff520007eded1 R12: dead000000000122 +R13: dffffc0000000000 R14: ffff8880352248d8 R15: ffff888021297e00 +FS: 00007f7ace6686c0(0000) GS:ffff8880b8600000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f7acef05b08 CR3: 000000003527c000 CR4: 00000000003526f0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + +Reported-by: syzbot+10bd8fe6741eedd2be2e@syzkaller.appspotmail.com +Tested-by: syzbot+10bd8fe6741eedd2be2e@syzkaller.appspotmail.com +Fixes: b4f82f9ed43a ("Bluetooth: L2CAP: Fix slab-use-after-free Read in l2cap_send_cmd") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Dan Carpenter +Signed-off-by: Greg Kroah-Hartman +--- + include/net/bluetooth/l2cap.h | 3 + net/bluetooth/l2cap_core.c | 138 ++++++++++++++---------------------------- + net/bluetooth/l2cap_sock.c | 15 ++-- + 3 files changed, 58 insertions(+), 98 deletions(-) + +--- a/include/net/bluetooth/l2cap.h ++++ b/include/net/bluetooth/l2cap.h +@@ -662,7 +662,7 @@ struct l2cap_conn { + struct l2cap_chan *smp; + + struct list_head chan_l; +- struct mutex chan_lock; ++ struct mutex lock; + struct kref ref; + struct list_head users; + }; +@@ -968,6 +968,7 @@ void l2cap_logical_cfm(struct l2cap_chan + void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); + + struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn); ++struct l2cap_conn *l2cap_conn_hold_unless_zero(struct l2cap_conn *conn); + void l2cap_conn_put(struct l2cap_conn *conn); + + int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -119,7 +119,6 @@ static struct l2cap_chan *l2cap_get_chan + { + struct l2cap_chan *c; + +- mutex_lock(&conn->chan_lock); + c = __l2cap_get_chan_by_scid(conn, cid); + if (c) { + /* Only lock if chan reference is not 0 */ +@@ -127,7 +126,6 @@ static struct l2cap_chan *l2cap_get_chan + if (c) + l2cap_chan_lock(c); + } +- mutex_unlock(&conn->chan_lock); + + return c; + } +@@ -140,7 +138,6 @@ static struct l2cap_chan *l2cap_get_chan + { + struct l2cap_chan *c; + +- mutex_lock(&conn->chan_lock); + c = __l2cap_get_chan_by_dcid(conn, cid); + if (c) { + /* Only lock if chan reference is not 0 */ +@@ -148,7 +145,6 @@ static struct l2cap_chan *l2cap_get_chan + if (c) + l2cap_chan_lock(c); + } +- mutex_unlock(&conn->chan_lock); + + return c; + } +@@ -418,7 +414,7 @@ static void l2cap_chan_timeout(struct wo + if (!conn) + return; + +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + /* __set_chan_timer() calls l2cap_chan_hold(chan) while scheduling + * this work. No need to call l2cap_chan_hold(chan) here again. + */ +@@ -439,7 +435,7 @@ static void l2cap_chan_timeout(struct wo + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); + +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + } + + struct l2cap_chan *l2cap_chan_create(void) +@@ -642,9 +638,9 @@ void __l2cap_chan_add(struct l2cap_conn + + void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) + { +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + __l2cap_chan_add(conn, chan); +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + } + + void l2cap_chan_del(struct l2cap_chan *chan, int err) +@@ -732,9 +728,9 @@ void l2cap_chan_list(struct l2cap_conn * + if (!conn) + return; + +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + __l2cap_chan_list(conn, func, data); +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + } + + EXPORT_SYMBOL_GPL(l2cap_chan_list); +@@ -746,7 +742,7 @@ static void l2cap_conn_update_id_addr(st + struct hci_conn *hcon = conn->hcon; + struct l2cap_chan *chan; + +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + + list_for_each_entry(chan, &conn->chan_l, list) { + l2cap_chan_lock(chan); +@@ -755,7 +751,7 @@ static void l2cap_conn_update_id_addr(st + l2cap_chan_unlock(chan); + } + +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + } + + static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) +@@ -1508,8 +1504,6 @@ static void l2cap_conn_start(struct l2ca + + BT_DBG("conn %p", conn); + +- mutex_lock(&conn->chan_lock); +- + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + l2cap_chan_lock(chan); + +@@ -1578,8 +1572,6 @@ static void l2cap_conn_start(struct l2ca + + l2cap_chan_unlock(chan); + } +- +- mutex_unlock(&conn->chan_lock); + } + + static void l2cap_le_conn_ready(struct l2cap_conn *conn) +@@ -1625,7 +1617,7 @@ static void l2cap_conn_ready(struct l2ca + if (hcon->type == ACL_LINK) + l2cap_request_info(conn); + +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + + list_for_each_entry(chan, &conn->chan_l, list) { + +@@ -1643,7 +1635,7 @@ static void l2cap_conn_ready(struct l2ca + l2cap_chan_unlock(chan); + } + +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + + if (hcon->type == LE_LINK) + l2cap_le_conn_ready(conn); +@@ -1658,14 +1650,10 @@ static void l2cap_conn_unreliable(struct + + BT_DBG("conn %p", conn); + +- mutex_lock(&conn->chan_lock); +- + list_for_each_entry(chan, &conn->chan_l, list) { + if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) + l2cap_chan_set_err(chan, err); + } +- +- mutex_unlock(&conn->chan_lock); + } + + static void l2cap_info_timeout(struct work_struct *work) +@@ -1676,7 +1664,9 @@ static void l2cap_info_timeout(struct wo + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + conn->info_ident = 0; + ++ mutex_lock(&conn->lock); + l2cap_conn_start(conn); ++ mutex_unlock(&conn->lock); + } + + /* +@@ -1768,6 +1758,8 @@ static void l2cap_conn_del(struct hci_co + + BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); + ++ mutex_lock(&conn->lock); ++ + kfree_skb(conn->rx_skb); + + skb_queue_purge(&conn->pending_rx); +@@ -1786,8 +1778,6 @@ static void l2cap_conn_del(struct hci_co + /* Force the connection to be immediately dropped */ + hcon->disc_timeout = 0; + +- mutex_lock(&conn->chan_lock); +- + /* Kill channels */ + list_for_each_entry_safe(chan, l, &conn->chan_l, list) { + l2cap_chan_hold(chan); +@@ -1801,12 +1791,14 @@ static void l2cap_conn_del(struct hci_co + l2cap_chan_put(chan); + } + +- mutex_unlock(&conn->chan_lock); +- + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) + cancel_delayed_work_sync(&conn->info_timer); + ++ hci_chan_del(conn->hchan); ++ conn->hchan = NULL; ++ + hcon->l2cap_data = NULL; ++ mutex_unlock(&conn->lock); + l2cap_conn_put(conn); + } + +@@ -1814,7 +1806,6 @@ static void l2cap_conn_free(struct kref + { + struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref); + +- hci_chan_del(conn->hchan); + hci_conn_put(conn->hcon); + kfree(conn); + } +@@ -2925,8 +2916,6 @@ static void l2cap_raw_recv(struct l2cap_ + + BT_DBG("conn %p", conn); + +- mutex_lock(&conn->chan_lock); +- + list_for_each_entry(chan, &conn->chan_l, list) { + if (chan->chan_type != L2CAP_CHAN_RAW) + continue; +@@ -2941,8 +2930,6 @@ static void l2cap_raw_recv(struct l2cap_ + if (chan->ops->recv(chan, nskb)) + kfree_skb(nskb); + } +- +- mutex_unlock(&conn->chan_lock); + } + + /* ---- L2CAP signalling commands ---- */ +@@ -3963,7 +3950,6 @@ static void l2cap_connect(struct l2cap_c + goto response; + } + +- mutex_lock(&conn->chan_lock); + l2cap_chan_lock(pchan); + + /* Check if the ACL is secure enough (if not SDP) */ +@@ -4070,7 +4056,6 @@ response: + } + + l2cap_chan_unlock(pchan); +- mutex_unlock(&conn->chan_lock); + l2cap_chan_put(pchan); + } + +@@ -4109,27 +4094,19 @@ static int l2cap_connect_create_rsp(stru + BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", + dcid, scid, result, status); + +- mutex_lock(&conn->chan_lock); +- + if (scid) { + chan = __l2cap_get_chan_by_scid(conn, scid); +- if (!chan) { +- err = -EBADSLT; +- goto unlock; +- } ++ if (!chan) ++ return -EBADSLT; + } else { + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); +- if (!chan) { +- err = -EBADSLT; +- goto unlock; +- } ++ if (!chan) ++ return -EBADSLT; + } + + chan = l2cap_chan_hold_unless_zero(chan); +- if (!chan) { +- err = -EBADSLT; +- goto unlock; +- } ++ if (!chan) ++ return -EBADSLT; + + err = 0; + +@@ -4167,9 +4144,6 @@ static int l2cap_connect_create_rsp(stru + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); + +-unlock: +- mutex_unlock(&conn->chan_lock); +- + return err; + } + +@@ -4457,11 +4431,7 @@ static inline int l2cap_disconnect_req(s + + chan->ops->set_shutdown(chan); + +- l2cap_chan_unlock(chan); +- mutex_lock(&conn->chan_lock); +- l2cap_chan_lock(chan); + l2cap_chan_del(chan, ECONNRESET); +- mutex_unlock(&conn->chan_lock); + + chan->ops->close(chan); + +@@ -4498,11 +4468,7 @@ static inline int l2cap_disconnect_rsp(s + return 0; + } + +- l2cap_chan_unlock(chan); +- mutex_lock(&conn->chan_lock); +- l2cap_chan_lock(chan); + l2cap_chan_del(chan, 0); +- mutex_unlock(&conn->chan_lock); + + chan->ops->close(chan); + +@@ -4700,13 +4666,9 @@ static int l2cap_le_connect_rsp(struct l + BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x", + dcid, mtu, mps, credits, result); + +- mutex_lock(&conn->chan_lock); +- + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); +- if (!chan) { +- err = -EBADSLT; +- goto unlock; +- } ++ if (!chan) ++ return -EBADSLT; + + err = 0; + +@@ -4754,9 +4716,6 @@ static int l2cap_le_connect_rsp(struct l + + l2cap_chan_unlock(chan); + +-unlock: +- mutex_unlock(&conn->chan_lock); +- + return err; + } + +@@ -4868,7 +4827,6 @@ static int l2cap_le_connect_req(struct l + goto response; + } + +- mutex_lock(&conn->chan_lock); + l2cap_chan_lock(pchan); + + if (!smp_sufficient_security(conn->hcon, pchan->sec_level, +@@ -4934,7 +4892,6 @@ static int l2cap_le_connect_req(struct l + + response_unlock: + l2cap_chan_unlock(pchan); +- mutex_unlock(&conn->chan_lock); + l2cap_chan_put(pchan); + + if (result == L2CAP_CR_PEND) +@@ -5071,7 +5028,6 @@ static inline int l2cap_ecred_conn_req(s + goto response; + } + +- mutex_lock(&conn->chan_lock); + l2cap_chan_lock(pchan); + + if (!smp_sufficient_security(conn->hcon, pchan->sec_level, +@@ -5146,7 +5102,6 @@ static inline int l2cap_ecred_conn_req(s + + unlock: + l2cap_chan_unlock(pchan); +- mutex_unlock(&conn->chan_lock); + l2cap_chan_put(pchan); + + response: +@@ -5183,8 +5138,6 @@ static inline int l2cap_ecred_conn_rsp(s + BT_DBG("mtu %u mps %u credits %u result 0x%4.4x", mtu, mps, credits, + result); + +- mutex_lock(&conn->chan_lock); +- + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { +@@ -5270,8 +5223,6 @@ static inline int l2cap_ecred_conn_rsp(s + l2cap_chan_unlock(chan); + } + +- mutex_unlock(&conn->chan_lock); +- + return err; + } + +@@ -5384,8 +5335,6 @@ static inline int l2cap_le_command_rej(s + if (cmd_len < sizeof(*rej)) + return -EPROTO; + +- mutex_lock(&conn->chan_lock); +- + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); + if (!chan) + goto done; +@@ -5400,7 +5349,6 @@ static inline int l2cap_le_command_rej(s + l2cap_chan_put(chan); + + done: +- mutex_unlock(&conn->chan_lock); + return 0; + } + +@@ -6855,8 +6803,12 @@ static void process_pending_rx(struct wo + + BT_DBG(""); + ++ mutex_lock(&conn->lock); ++ + while ((skb = skb_dequeue(&conn->pending_rx))) + l2cap_recv_frame(conn, skb); ++ ++ mutex_unlock(&conn->lock); + } + + static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) +@@ -6895,7 +6847,7 @@ static struct l2cap_conn *l2cap_conn_add + conn->local_fixed_chan |= L2CAP_FC_SMP_BREDR; + + mutex_init(&conn->ident_lock); +- mutex_init(&conn->chan_lock); ++ mutex_init(&conn->lock); + + INIT_LIST_HEAD(&conn->chan_l); + INIT_LIST_HEAD(&conn->users); +@@ -7088,7 +7040,7 @@ int l2cap_chan_connect(struct l2cap_chan + } + } + +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + l2cap_chan_lock(chan); + + if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { +@@ -7129,7 +7081,7 @@ int l2cap_chan_connect(struct l2cap_chan + + chan_unlock: + l2cap_chan_unlock(chan); +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + done: + hci_dev_unlock(hdev); + hci_dev_put(hdev); +@@ -7345,7 +7297,7 @@ static void l2cap_security_cfm(struct hc + + BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt); + +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + + list_for_each_entry(chan, &conn->chan_l, list) { + l2cap_chan_lock(chan); +@@ -7419,7 +7371,7 @@ static void l2cap_security_cfm(struct hc + l2cap_chan_unlock(chan); + } + +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + } + + /* Append fragment into frame respecting the maximum len of rx_skb */ +@@ -7486,8 +7438,11 @@ static void l2cap_recv_reset(struct l2ca + conn->rx_len = 0; + } + +-static struct l2cap_conn *l2cap_conn_hold_unless_zero(struct l2cap_conn *c) ++struct l2cap_conn *l2cap_conn_hold_unless_zero(struct l2cap_conn *c) + { ++ if (!c) ++ return NULL; ++ + BT_DBG("conn %p orig refcnt %u", c, kref_read(&c->ref)); + + if (!kref_get_unless_zero(&c->ref)) +@@ -7513,11 +7468,15 @@ void l2cap_recv_acldata(struct hci_conn + + hci_dev_unlock(hcon->hdev); + +- if (!conn) +- goto drop; ++ if (!conn) { ++ kfree_skb(skb); ++ return; ++ } + + BT_DBG("conn %p len %u flags 0x%x", conn, skb->len, flags); + ++ mutex_lock(&conn->lock); ++ + switch (flags) { + case ACL_START: + case ACL_START_NO_FLUSH: +@@ -7542,7 +7501,7 @@ void l2cap_recv_acldata(struct hci_conn + if (len == skb->len) { + /* Complete frame received */ + l2cap_recv_frame(conn, skb); +- return; ++ goto unlock; + } + + BT_DBG("Start: total len %d, frag len %u", len, skb->len); +@@ -7604,10 +7563,11 @@ void l2cap_recv_acldata(struct hci_conn + break; + } + +- l2cap_conn_put(conn); +- + drop: + kfree_skb(skb); ++unlock: ++ mutex_unlock(&conn->lock); ++ l2cap_conn_put(conn); + } + + static struct hci_cb l2cap_cb = { +--- a/net/bluetooth/l2cap_sock.c ++++ b/net/bluetooth/l2cap_sock.c +@@ -1323,9 +1323,10 @@ static int l2cap_sock_shutdown(struct so + /* prevent sk structure from being freed whilst unlocked */ + sock_hold(sk); + +- chan = l2cap_pi(sk)->chan; + /* prevent chan structure from being freed whilst unlocked */ +- l2cap_chan_hold(chan); ++ chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan); ++ if (!chan) ++ goto shutdown_already; + + BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); + +@@ -1355,22 +1356,20 @@ static int l2cap_sock_shutdown(struct so + release_sock(sk); + + l2cap_chan_lock(chan); +- conn = chan->conn; +- if (conn) +- /* prevent conn structure from being freed */ +- l2cap_conn_get(conn); ++ /* prevent conn structure from being freed */ ++ conn = l2cap_conn_hold_unless_zero(chan->conn); + l2cap_chan_unlock(chan); + + if (conn) + /* mutex lock must be taken before l2cap_chan_lock() */ +- mutex_lock(&conn->chan_lock); ++ mutex_lock(&conn->lock); + + l2cap_chan_lock(chan); + l2cap_chan_close(chan, 0); + l2cap_chan_unlock(chan); + + if (conn) { +- mutex_unlock(&conn->chan_lock); ++ mutex_unlock(&conn->lock); + l2cap_conn_put(conn); + } + diff --git a/queue-6.6/hid-apple-disable-fn-key-handling-on-the-omoton-kb066.patch b/queue-6.6/hid-apple-disable-fn-key-handling-on-the-omoton-kb066.patch new file mode 100644 index 0000000000..a99f011694 --- /dev/null +++ b/queue-6.6/hid-apple-disable-fn-key-handling-on-the-omoton-kb066.patch @@ -0,0 +1,72 @@ +From 221cea1003d8a412e5ec64a58df7ab19b654f490 Mon Sep 17 00:00:00 2001 +From: Alex Henrie +Date: Sun, 23 Feb 2025 22:36:30 -0700 +Subject: HID: apple: disable Fn key handling on the Omoton KB066 + +From: Alex Henrie + +commit 221cea1003d8a412e5ec64a58df7ab19b654f490 upstream. + +Remove the fixup to make the Omoton KB066's F6 key F6 when not holding +Fn. That was really just a hack to allow typing F6 in fnmode>0, and it +didn't fix any of the other F keys that were likewise untypable in +fnmode>0. Instead, because the Omoton's Fn key is entirely internal to +the keyboard, completely disable Fn key translation when an Omoton is +detected, which will prevent the hid-apple driver from interfering with +the keyboard's built-in Fn key handling. All of the F keys, including +F6, are then typable when Fn is held. + +The Omoton KB066 and the Apple A1255 both have HID product code +05ac:022c. The self-reported name of every original A1255 when they left +the factory was "Apple Wireless Keyboard". By default, Mac OS changes +the name to "'s keyboard" when pairing with the keyboard, but +Mac OS allows the user to set the internal name of Apple keyboards to +anything they like. The Omoton KB066's name, on the other hand, is not +configurable: It is always "Bluetooth Keyboard". Because that name is so +generic that a user might conceivably use the same name for a real Apple +keyboard, detect Omoton keyboards based on both having that exact name +and having HID product code 022c. + +Fixes: 819083cb6eed ("HID: apple: fix up the F6 key on the Omoton KB066 keyboard") +Signed-off-by: Alex Henrie +Reviewed-by: Aditya Garg +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-apple.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/hid/hid-apple.c ++++ b/drivers/hid/hid-apple.c +@@ -363,6 +363,12 @@ static bool apple_is_non_apple_keyboard( + return false; + } + ++static bool apple_is_omoton_kb066(struct hid_device *hdev) ++{ ++ return hdev->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI && ++ strcmp(hdev->name, "Bluetooth Keyboard") == 0; ++} ++ + static inline void apple_setup_key_translation(struct input_dev *input, + const struct apple_key_translation *table) + { +@@ -531,9 +537,6 @@ static int hidinput_apple_event(struct h + } + } + +- if (usage->hid == 0xc0301) /* Omoton KB066 quirk */ +- code = KEY_F6; +- + if (usage->code != code) { + input_event_with_scancode(input, usage->type, code, usage->hid, value); + +@@ -713,7 +716,7 @@ static int apple_input_configured(struct + { + struct apple_sc *asc = hid_get_drvdata(hdev); + +- if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) { ++ if (((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) || apple_is_omoton_kb066(hdev)) { + hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n"); + asc->quirks &= ~APPLE_HAS_FN; + } diff --git a/queue-6.6/nvme-fc-rely-on-state-transitions-to-handle-connectivity-loss.patch b/queue-6.6/nvme-fc-rely-on-state-transitions-to-handle-connectivity-loss.patch new file mode 100644 index 0000000000..bdda127983 --- /dev/null +++ b/queue-6.6/nvme-fc-rely-on-state-transitions-to-handle-connectivity-loss.patch @@ -0,0 +1,138 @@ +From f13409bb3f9140dad7256febcb478f0c9600312c Mon Sep 17 00:00:00 2001 +From: Daniel Wagner +Date: Fri, 14 Feb 2025 09:02:04 +0100 +Subject: nvme-fc: rely on state transitions to handle connectivity loss + +From: Daniel Wagner + +commit f13409bb3f9140dad7256febcb478f0c9600312c upstream. + +It's not possible to call nvme_state_ctrl_state with holding a spin +lock, because nvme_state_ctrl_state calls cancel_delayed_work_sync +when fastfail is enabled. + +Instead syncing the ASSOC_FLAG and state transitions using a lock, it's +possible to only rely on the state machine transitions. That means +nvme_fc_ctrl_connectivity_loss should unconditionally call +nvme_reset_ctrl which avoids the read race on the ctrl state variable. +Actually, it's not necessary to test in which state the ctrl is, the +reset work will only scheduled when the state machine is in LIVE state. + +In nvme_fc_create_association, the LIVE state can only be entered if it +was previously CONNECTING. If this is not possible then the reset +handler got triggered. Thus just error out here. + +Fixes: ee59e3820ca9 ("nvme-fc: do not ignore connectivity loss during connecting") +Closes: https://lore.kernel.org/all/denqwui6sl5erqmz2gvrwueyxakl5txzbbiu3fgebryzrfxunm@iwxuthct377m/ +Reported-by: Shinichiro Kawasaki +Tested-by: Shin'ichiro Kawasaki +Reviewed-by: Sagi Grimberg +Signed-off-by: Daniel Wagner +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/host/fc.c | 67 ++++--------------------------------------------- + 1 file changed, 6 insertions(+), 61 deletions(-) + +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -782,61 +782,12 @@ restart: + static void + nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl) + { +- enum nvme_ctrl_state state; +- unsigned long flags; +- + dev_info(ctrl->ctrl.device, + "NVME-FC{%d}: controller connectivity lost. Awaiting " + "Reconnect", ctrl->cnum); + +- spin_lock_irqsave(&ctrl->lock, flags); + set_bit(ASSOC_FAILED, &ctrl->flags); +- state = nvme_ctrl_state(&ctrl->ctrl); +- spin_unlock_irqrestore(&ctrl->lock, flags); +- +- switch (state) { +- case NVME_CTRL_NEW: +- case NVME_CTRL_LIVE: +- /* +- * Schedule a controller reset. The reset will terminate the +- * association and schedule the reconnect timer. Reconnects +- * will be attempted until either the ctlr_loss_tmo +- * (max_retries * connect_delay) expires or the remoteport's +- * dev_loss_tmo expires. +- */ +- if (nvme_reset_ctrl(&ctrl->ctrl)) { +- dev_warn(ctrl->ctrl.device, +- "NVME-FC{%d}: Couldn't schedule reset.\n", +- ctrl->cnum); +- nvme_delete_ctrl(&ctrl->ctrl); +- } +- break; +- +- case NVME_CTRL_CONNECTING: +- /* +- * The association has already been terminated and the +- * controller is attempting reconnects. No need to do anything +- * futher. Reconnects will be attempted until either the +- * ctlr_loss_tmo (max_retries * connect_delay) expires or the +- * remoteport's dev_loss_tmo expires. +- */ +- break; +- +- case NVME_CTRL_RESETTING: +- /* +- * Controller is already in the process of terminating the +- * association. No need to do anything further. The reconnect +- * step will kick in naturally after the association is +- * terminated. +- */ +- break; +- +- case NVME_CTRL_DELETING: +- case NVME_CTRL_DELETING_NOIO: +- default: +- /* no action to take - let it delete */ +- break; +- } ++ nvme_reset_ctrl(&ctrl->ctrl); + } + + /** +@@ -3070,7 +3021,6 @@ nvme_fc_create_association(struct nvme_f + struct nvmefc_ls_rcv_op *disls = NULL; + unsigned long flags; + int ret; +- bool changed; + + ++ctrl->ctrl.nr_reconnects; + +@@ -3175,23 +3125,18 @@ nvme_fc_create_association(struct nvme_f + else + ret = nvme_fc_recreate_io_queues(ctrl); + } ++ if (!ret && test_bit(ASSOC_FAILED, &ctrl->flags)) ++ ret = -EIO; + if (ret) + goto out_term_aen_ops; + +- spin_lock_irqsave(&ctrl->lock, flags); +- if (!test_bit(ASSOC_FAILED, &ctrl->flags)) +- changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE); +- else ++ if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE)) { + ret = -EIO; +- spin_unlock_irqrestore(&ctrl->lock, flags); +- +- if (ret) + goto out_term_aen_ops; ++ } + + ctrl->ctrl.nr_reconnects = 0; +- +- if (changed) +- nvme_start_ctrl(&ctrl->ctrl); ++ nvme_start_ctrl(&ctrl->ctrl); + + return 0; /* Success */ + diff --git a/queue-6.6/nvme-tcp-fix-a-c2htermreq-error-message.patch b/queue-6.6/nvme-tcp-fix-a-c2htermreq-error-message.patch new file mode 100644 index 0000000000..36f46aa990 --- /dev/null +++ b/queue-6.6/nvme-tcp-fix-a-c2htermreq-error-message.patch @@ -0,0 +1,33 @@ +From afb41b08c44e5386f2f52fa859010ac4afd2b66f Mon Sep 17 00:00:00 2001 +From: Maurizio Lombardi +Date: Mon, 24 Feb 2025 15:40:58 +0100 +Subject: nvme-tcp: Fix a C2HTermReq error message + +From: Maurizio Lombardi + +commit afb41b08c44e5386f2f52fa859010ac4afd2b66f upstream. + +In H2CTermReq, a FES with value 0x05 means "R2T Limit Exceeded"; but +in C2HTermReq the same value has a different meaning (Data Transfer Limit +Exceeded). + +Fixes: 84e009042d0f ("nvme-tcp: add basic support for the C2HTermReq PDU") +Signed-off-by: Maurizio Lombardi +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/host/tcp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -719,7 +719,7 @@ static void nvme_tcp_handle_c2h_term(str + [NVME_TCP_FES_PDU_SEQ_ERR] = "PDU Sequence Error", + [NVME_TCP_FES_HDR_DIGEST_ERR] = "Header Digest Error", + [NVME_TCP_FES_DATA_OUT_OF_RANGE] = "Data Transfer Out Of Range", +- [NVME_TCP_FES_R2T_LIMIT_EXCEEDED] = "R2T Limit Exceeded", ++ [NVME_TCP_FES_DATA_LIMIT_EXCEEDED] = "Data Transfer Limit Exceeded", + [NVME_TCP_FES_UNSUPPORTED_PARAM] = "Unsupported Parameter", + }; + diff --git a/queue-6.6/series b/queue-6.6/series index 48063afb3d..089a7ae009 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -163,3 +163,7 @@ i2c-sis630-fix-an-error-handling-path-in-sis630_prob.patch stmmac-loongson-pass-correct-arg-to-pci-function.patch smb3-add-support-for-iakerb.patch smb-client-fix-match_session-bug-preventing-session-.patch +bluetooth-l2cap-fix-corrupted-list-in-hci_chan_del.patch +nvme-fc-rely-on-state-transitions-to-handle-connectivity-loss.patch +hid-apple-disable-fn-key-handling-on-the-omoton-kb066.patch +nvme-tcp-fix-a-c2htermreq-error-message.patch