--- /dev/null
+From bb067a99a0356196c0b89a95721985485ebce5a5 Mon Sep 17 00:00:00 2001
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Date: Sun, 28 Jun 2026 02:50:58 +0200
+Subject: Bluetooth: bnep: pin L2CAP connection during netdev registration
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+commit bb067a99a0356196c0b89a95721985485ebce5a5 upstream.
+
+bnep_add_connection() reads the L2CAP connection without holding the
+channel lock, then passes its HCI device to register_netdev(). Controller
+teardown can clear and release that connection concurrently, leaving the
+network device registration path to dereference a freed parent device.
+
+Take a reference to the L2CAP connection while holding the channel lock.
+Retain it until register_netdev() has taken the parent device reference.
+
+Fixes: 65f53e9802db ("Bluetooth: Access BNEP session addresses through L2CAP channel")
+Reported-by: syzbot+fed5dce4553262f3b35c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=fed5dce4553262f3b35c
+Cc: stable@vger.kernel.org
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/bnep/core.c | 27 +++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+--- a/net/bluetooth/bnep/core.c
++++ b/net/bluetooth/bnep/core.c
+@@ -562,14 +562,18 @@ static int bnep_session(void *arg)
+ return 0;
+ }
+
+-static struct device *bnep_get_device(struct bnep_session *session)
++static struct l2cap_conn *bnep_get_conn(struct bnep_session *session)
+ {
+- struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
++ struct l2cap_chan *chan = l2cap_pi(session->sock->sk)->chan;
++ struct l2cap_conn *conn;
+
+- if (!conn || !conn->hcon)
+- return NULL;
++ l2cap_chan_lock(chan);
++ conn = chan->conn;
++ if (conn)
++ l2cap_conn_get(conn);
++ l2cap_chan_unlock(chan);
+
+- return &conn->hcon->dev;
++ return conn;
+ }
+
+ static struct device_type bnep_type = {
+@@ -581,6 +585,7 @@ int bnep_add_connection(struct bnep_conn
+ u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
+ struct net_device *dev;
+ struct bnep_session *s, *ss;
++ struct l2cap_conn *conn = NULL;
+ u8 dst[ETH_ALEN], src[ETH_ALEN];
+ int err;
+
+@@ -640,10 +645,18 @@ int bnep_add_connection(struct bnep_conn
+ bnep_set_default_proto_filter(s);
+ #endif
+
+- SET_NETDEV_DEV(dev, bnep_get_device(s));
++ conn = bnep_get_conn(s);
++ if (!conn) {
++ err = -ENOTCONN;
++ goto failed;
++ }
++
++ SET_NETDEV_DEV(dev, &conn->hcon->dev);
+ SET_NETDEV_DEVTYPE(dev, &bnep_type);
+
+ err = register_netdev(dev);
++ l2cap_conn_put(conn);
++ conn = NULL;
+ if (err)
+ goto failed;
+
+@@ -665,6 +678,8 @@ int bnep_add_connection(struct bnep_conn
+ return 0;
+
+ failed:
++ if (conn)
++ l2cap_conn_put(conn);
+ up_write(&bnep_session_sem);
+ free_netdev(dev);
+ return err;
--- /dev/null
+From a257407e2bbbb099ed427719a50563f67fa366d8 Mon Sep 17 00:00:00 2001
+From: Sergey Senozhatsky <senozhatsky@chromium.org>
+Date: Tue, 9 Jun 2026 21:10:06 +0900
+Subject: Bluetooth: btmtksdio: fix infinite loop in btmtksdio_txrx_work()
+
+From: Sergey Senozhatsky <senozhatsky@chromium.org>
+
+commit a257407e2bbbb099ed427719a50563f67fa366d8 upstream.
+
+Every once in a while we see a hung btmtksdio_flush() task:
+
+ INFO: task kworker/u17:0:189 blocked for more than 122 seconds.
+ __cancel_work_timer+0x3f4/0x460
+ cancel_work_sync+0x1c/0x2c
+ btmtksdio_flush+0x2c/0x40
+ hci_dev_open_sync+0x10c4/0x2190
+ [..]
+
+It all boils down to incorrect time_is_before_jiffies() usage in
+btmtksdio_txrx_work(). The btmtksdio_txrx_work() loop is expected
+to be terminated if running for longer than 5*HZ. However the
+timeout check is twisted: time_is_before_jiffies(old_jiffies + 5*HZ)
+evaluates to true when old_jiffies + 5*HZ is in the past i.e. when a
+timeout has occurred. Using OR with time_is_before_jiffies(txrx_timeout)
+means that:
+- before the 5-second timeout: the condition is `int_status || false`,
+ so it loops as long as there are pending interrupts.
+- after the 5-second timeout: the condition becomes `int_status || true`,
+ which is always true.
+
+When the loop becomes infinite btmtksdio_txrx_work() loop never
+terminates and never releases the SDIO host.
+
+Fix loop termination condition to actually enforce a 5*HZ timeout.
+
+Fixes: 26270bc189ea4 ("Bluetooth: btmtksdio: move interrupt service to work")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Reviewed-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/bluetooth/btmtksdio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/bluetooth/btmtksdio.c
++++ b/drivers/bluetooth/btmtksdio.c
+@@ -605,7 +605,7 @@ static void btmtksdio_txrx_work(struct w
+ if (btmtksdio_rx_packet(bdev, rx_size) < 0)
+ bdev->hdev->stat.err_rx++;
+ }
+- } while (int_status || time_is_before_jiffies(txrx_timeout));
++ } while (int_status && time_is_after_jiffies(txrx_timeout));
+
+ /* Enable interrupt */
+ sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, 0);
--- /dev/null
+From 4bd0b274054f2679f28b70222b607bb0afc3ab9a Mon Sep 17 00:00:00 2001
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Date: Sun, 28 Jun 2026 02:23:05 +0200
+Subject: Bluetooth: fix UAF in bt_accept_dequeue()
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+commit 4bd0b274054f2679f28b70222b607bb0afc3ab9a upstream.
+
+bt_accept_get() takes a temporary reference before dropping the accept
+queue lock. bt_accept_dequeue() currently drops that reference before
+bt_accept_unlink(), leaving only the queue reference.
+
+bt_accept_unlink() drops the queue reference. The subsequent
+sock_hold() therefore accesses freed memory if it was the final
+reference, as observed by KASAN during listening L2CAP socket cleanup.
+
+Retain the temporary queue-walk reference through unlink and hand it to
+the caller on success. Drop it explicitly on the closed and
+not-yet-connected paths.
+
+Fixes: ab1513597c6c ("Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs l2cap_conn_del()")
+Reported-by: syzbot+674ff7e4d7fdfd572afc@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=674ff7e4d7fdfd572afc
+Cc: stable@vger.kernel.org
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/af_bluetooth.c | 17 +++--------------
+ net/bluetooth/l2cap_sock.c | 4 ++--
+ 2 files changed, 5 insertions(+), 16 deletions(-)
+
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -305,7 +305,7 @@ struct sock *bt_accept_dequeue(struct so
+
+ restart:
+ for (sk = bt_accept_get(parent, NULL); sk; sk = next) {
+- /* Prevent early freeing of sk due to unlink and sock_kill */
++ /* The reference from bt_accept_get() keeps sk alive. */
+ lock_sock(sk);
+
+ /* Check sk has not already been unlinked via
+@@ -321,13 +321,11 @@ restart:
+
+ next = bt_accept_get(parent, sk);
+
+- /* sk is safely in the parent list so reduce reference count */
+- sock_put(sk);
+-
+ /* FIXME: Is this check still needed */
+ if (sk->sk_state == BT_CLOSED) {
+ bt_accept_unlink(sk);
+ release_sock(sk);
++ sock_put(sk);
+ continue;
+ }
+
+@@ -337,16 +335,6 @@ restart:
+ if (newsock)
+ sock_graft(sk, newsock);
+
+- /* Hand the caller a reference taken while sk is
+- * still locked. bt_accept_unlink() just dropped
+- * the accept-queue reference; without this hold a
+- * concurrent teardown (e.g. l2cap_conn_del() ->
+- * l2cap_sock_kill()) could free sk between
+- * release_sock() and the caller using it. Every
+- * caller drops this with sock_put() when done.
+- */
+- sock_hold(sk);
+-
+ release_sock(sk);
+ if (next)
+ sock_put(next);
+@@ -354,6 +342,7 @@ restart:
+ }
+
+ release_sock(sk);
++ sock_put(sk);
+ }
+
+ return NULL;
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -1465,8 +1465,8 @@ static void l2cap_sock_cleanup_listen(st
+
+ /* Close not yet accepted channels.
+ *
+- * bt_accept_dequeue() now returns sk with an extra reference held
+- * (taken while sk was still locked) so a concurrent l2cap_conn_del()
++ * bt_accept_dequeue() returns sk with its temporary queue-walk
++ * reference held, so a concurrent l2cap_conn_del()
+ * -> l2cap_sock_kill() cannot free sk under us.
+ *
+ * cleanup_listen() runs under the parent sk lock, so unlike
--- /dev/null
+From 687617555cedfb74c9e3cb85d759b908dcb17856 Mon Sep 17 00:00:00 2001
+From: Muhammad Bilal <meatuni001@gmail.com>
+Date: Sun, 21 Jun 2026 00:56:35 +0500
+Subject: Bluetooth: L2CAP: validate option length before reading conf opt value
+
+From: Muhammad Bilal <meatuni001@gmail.com>
+
+commit 687617555cedfb74c9e3cb85d759b908dcb17856 upstream.
+
+l2cap_get_conf_opt() derives the option length from the
+attacker-controlled opt->len field and immediately dereferences
+opt->val (as u8, get_unaligned_le16() or get_unaligned_le32(), or a
+raw pointer for the default case) before any caller has confirmed
+that opt->len bytes are present in the buffer. The callers
+(l2cap_parse_conf_req(), l2cap_parse_conf_rsp() and
+l2cap_conf_rfc_get()) only detect a malformed option afterwards, once
+the running length has gone negative, by which point the
+out-of-bounds read has already executed.
+
+An existing post-hoc length check keeps the garbage value from being
+consumed, so this is not a data leak in the current control flow. It
+is still a validate-after-use ordering bug: up to 4 bytes are read
+past the end of the buffer before it is known to contain them, and it
+is fragile to future changes in the callers.
+
+Fix it at the source. Pass the end of the buffer into
+l2cap_get_conf_opt() and refuse to touch opt->val unless the full
+option (header + value) fits. Each caller computes an end pointer
+once before the loop and checks the return value directly instead of
+inferring the error from a negative length.
+
+Fixes: 7c9cbd0b5e38 ("Bluetooth: Verify that l2cap_get_conf_opt provides large enough buffer")
+Cc: stable@vger.kernel.org
+Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/l2cap_core.c | 36 ++++++++++++++++++++++++++++--------
+ 1 file changed, 28 insertions(+), 8 deletions(-)
+
+--- a/net/bluetooth/l2cap_core.c
++++ b/net/bluetooth/l2cap_core.c
+@@ -3188,13 +3188,24 @@ fail:
+ return NULL;
+ }
+
+-static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
+- unsigned long *val)
++static inline int l2cap_get_conf_opt(void **ptr, void *end, int *type,
++ int *olen, unsigned long *val)
+ {
+ struct l2cap_conf_opt *opt = *ptr;
+ int len;
+
++ /* opt->len is attacker-controlled. Validate that the full option
++ * (header + value) actually fits in the buffer before touching
++ * opt->val, otherwise the switch below reads past the end of the
++ * caller's buffer.
++ */
++ if (end - *ptr < L2CAP_CONF_OPT_SIZE)
++ return -EINVAL;
++
+ len = L2CAP_CONF_OPT_SIZE + opt->len;
++ if (end - *ptr < len)
++ return -EINVAL;
++
+ *ptr += len;
+
+ *type = opt->type;
+@@ -3600,6 +3611,7 @@ static int l2cap_parse_conf_req(struct l
+ void *ptr = rsp->data;
+ void *endptr = data + data_size;
+ void *req = chan->conf_req;
++ void *req_end = req + chan->conf_len;
+ int len = chan->conf_len;
+ int type, hint, olen;
+ unsigned long val;
+@@ -3613,9 +3625,11 @@ static int l2cap_parse_conf_req(struct l
+ BT_DBG("chan %p", chan);
+
+ while (len >= L2CAP_CONF_OPT_SIZE) {
+- len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
+- if (len < 0)
++ int ret = l2cap_get_conf_opt(&req, req_end, &type, &olen, &val);
++
++ if (ret < 0)
+ break;
++ len -= ret;
+
+ hint = type & L2CAP_CONF_HINT;
+ type &= L2CAP_CONF_MASK;
+@@ -3849,6 +3863,7 @@ static int l2cap_parse_conf_rsp(struct l
+ struct l2cap_conf_req *req = data;
+ void *ptr = req->data;
+ void *endptr = data + size;
++ void *rsp_end = rsp + len;
+ int type, olen;
+ unsigned long val;
+ struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+@@ -3857,9 +3872,11 @@ static int l2cap_parse_conf_rsp(struct l
+ BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
+
+ while (len >= L2CAP_CONF_OPT_SIZE) {
+- len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
+- if (len < 0)
++ int ret = l2cap_get_conf_opt(&rsp, rsp_end, &type, &olen, &val);
++
++ if (ret < 0)
+ break;
++ len -= ret;
+
+ switch (type) {
+ case L2CAP_CONF_MTU:
+@@ -4112,6 +4129,7 @@ static void l2cap_conf_rfc_get(struct l2
+ {
+ int type, olen;
+ unsigned long val;
++ void *rsp_end = rsp + len;
+ /* Use sane default values in case a misbehaving remote device
+ * did not send an RFC or extended window size option.
+ */
+@@ -4130,9 +4148,11 @@ static void l2cap_conf_rfc_get(struct l2
+ return;
+
+ while (len >= L2CAP_CONF_OPT_SIZE) {
+- len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
+- if (len < 0)
++ int ret = l2cap_get_conf_opt(&rsp, rsp_end, &type, &olen, &val);
++
++ if (ret < 0)
+ break;
++ len -= ret;
+
+ switch (type) {
+ case L2CAP_CONF_RFC:
netfilter-ctnetlink-use-nf_ct_exp_net-in-expectation-dump.patch
netfilter-ebtables-module-names-must-be-null-terminated.patch
netfilter-ebtables-terminate-table-name-before-find_table_lock.patch
+bluetooth-btmtksdio-fix-infinite-loop-in-btmtksdio_txrx_work.patch
+bluetooth-bnep-pin-l2cap-connection-during-netdev-registration.patch
+bluetooth-fix-uaf-in-bt_accept_dequeue.patch
+bluetooth-l2cap-validate-option-length-before-reading-conf-opt-value.patch