From: Sasha Levin Date: Tue, 9 Jun 2026 15:29:02 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=d4abd7b3bb28edad0b427d7e5b33e53cb244447f;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/6lowpan-fix-off-by-one-in-multicast-context-address-.patch b/queue-5.10/6lowpan-fix-off-by-one-in-multicast-context-address-.patch new file mode 100644 index 0000000000..0ee1e96e6f --- /dev/null +++ b/queue-5.10/6lowpan-fix-off-by-one-in-multicast-context-address-.patch @@ -0,0 +1,67 @@ +From 5c52e27970f6ba797ace203a91f9642f4f0f0fa7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:18:01 +0800 +Subject: 6lowpan: fix off-by-one in multicast context address compression + +From: Yizhou Zhao + +[ Upstream commit 2a58899d11009bffc7b4b32a571858f381121837 ] + +The second memcpy in lowpan_iphc_mcast_ctx_addr_compress() uses +&data[1] as destination and &ipaddr->s6_addr[11] as source, but +both should be offset by one: &data[2] and &ipaddr->s6_addr[12] +respectively. + +This off-by-one has two consequences: +1. data[1] is overwritten with s6_addr[11], corrupting the RIID + field in the compressed multicast address +2. data[5] is never written, so uninitialized kernel stack memory + is transmitted over the network via lowpan_push_hc_data(), + leaking kernel stack contents + +The correct inline data layout must match what the decompression +function lowpan_uncompress_multicast_ctx_daddr() expects: + data[0..1] = s6_addr[1..2] (flags/scope + RIID) + data[2..5] = s6_addr[12..15] (group ID) + +Also zero-initialize the data array as a defensive measure against +similar bugs in the future. + +Fixes: 5609c185f24d ("6lowpan: iphc: add support for stateful compression") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Acked-by: Alexander Aring +Link: https://patch.msgid.link/20260527081806.42747-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/6lowpan/iphc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c +index 52fad5dad9f715..d762c49e722fae 100644 +--- a/net/6lowpan/iphc.c ++++ b/net/6lowpan/iphc.c +@@ -1086,12 +1086,12 @@ static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, + const struct lowpan_iphc_ctx *ctx, + const struct in6_addr *ipaddr) + { +- u8 data[6]; ++ u8 data[6] = {}; + + /* flags/scope, reserved (RIID) */ + memcpy(data, &ipaddr->s6_addr[1], 2); + /* group ID */ +- memcpy(&data[1], &ipaddr->s6_addr[11], 4); ++ memcpy(&data[2], &ipaddr->s6_addr[12], 4); + lowpan_push_hc_data(hc_ptr, data, 6); + + return LOWPAN_IPHC_DAM_00; +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch b/queue-5.10/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch new file mode 100644 index 0000000000..da9e9b1c49 --- /dev/null +++ b/queue-5.10/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch @@ -0,0 +1,73 @@ +From 102c8c2e5f7c57eed03e98492211e84a3de1b761 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 17:45:06 +0800 +Subject: Bluetooth: MGMT: validate advertising TLV before type checks + +From: Zhang Cen + +[ Upstream commit de23fb62259aa01d294f77238ae3b835eb674413 ] + +tlv_data_is_valid() reads each advertising data field length from +data[i], then inspects data[i + 1] for managed EIR types before +checking that the current field still fits inside the supplied buffer. + +A malformed field whose length byte is the last byte of the buffer can +therefore make the parser read one byte past the advertising data. + +KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING +request reached that path: + + BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid() + Read of size 1 + Call trace: + tlv_data_is_valid() + add_advertising() + hci_mgmt_cmd() + hci_sock_sendmsg() + +Move the existing element-length check before any type-octet inspection +so each non-empty element is proven to contain its type byte before the +parser looks at data[i + 1]. + +Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check") +Reviewed-by: Paul Menzel +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index b768abbf2b121a..3647e51d31062b 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -7364,6 +7364,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (!cur_len) + continue; + ++ /* If the current field length would exceed the total data ++ * length, then it's invalid. ++ */ ++ if (i + cur_len >= len) ++ return false; ++ + if (data[i + 1] == EIR_FLAGS && + (!is_adv_data || flags_managed(adv_flags))) + return false; +@@ -7380,12 +7386,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (data[i + 1] == EIR_APPEARANCE && + appearance_managed(adv_flags)) + return false; +- +- /* If the current field length would exceed the total data +- * length, then it's invalid. +- */ +- if (i + cur_len >= len) +- return false; + } + + return true; +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch b/queue-5.10/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch new file mode 100644 index 0000000000..dec3762a60 --- /dev/null +++ b/queue-5.10/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch @@ -0,0 +1,126 @@ +From 27ec0e481e2d63cadc82f117507cad3f7986b673 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 15:56:41 +0800 +Subject: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() + +From: Zhang Cen + +[ Upstream commit 43c441edacf953b39517a44f5e5e10a93618b226 ] + +rfcomm_get_sock_by_channel() scans rfcomm_sk_list under the list lock, +but returns the selected listener after dropping that lock without +taking a reference. rfcomm_connect_ind() then locks the listener, +queues a child socket on it, and may notify it after unlocking it. + +The buggy scenario involves two paths, with each column showing the +order within that path: + +rfcomm_connect_ind(): listener close: + 1. Find parent in 1. close() enters + rfcomm_get_sock_by_channel() rfcomm_sock_release(). + 2. Drop rfcomm_sk_list.lock 2. rfcomm_sock_shutdown() + without pinning parent. closes the listener. + 3. Call lock_sock(parent) and 3. rfcomm_sock_kill() + bt_accept_enqueue(parent, unlinks and puts parent. + sk, true). + 4. Read parent flags and may 4. parent can be freed. + call sk_state_change(). + +If close wins the race, parent can be freed before +rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or the +deferred-setup callback. + +Take a reference on the listener before leaving rfcomm_sk_list.lock. +After lock_sock() succeeds, recheck that it is still in BT_LISTEN +before queueing a child, cache the deferred-setup bit while the parent +is locked, and drop the reference after the last parent use. + +KASAN reported a slab-use-after-free in lock_sock_nested() from +rfcomm_connect_ind(), with the freeing stack going through +rfcomm_sock_kill() and rfcomm_sock_release(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index 2dcb70f49a68a5..faab36d54c5c5a 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) + } + + /* Find socket with channel and source bdaddr. +- * Returns closest match. ++ * Returns closest match with an extra reference held. + */ + static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) + { +@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t * + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ +- if (!bacmp(&rfcomm_pi(sk)->src, src)) ++ if (!bacmp(&rfcomm_pi(sk)->src, src)) { ++ sock_hold(sk); + break; ++ } + + /* Closest match */ +- if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) ++ if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) { ++ if (sk1) ++ sock_put(sk1); ++ + sk1 = sk; ++ sock_hold(sk1); ++ } + } + } + ++ if (sk && sk1) ++ sock_put(sk1); ++ + read_unlock(&rfcomm_sk_list.lock); + + return sk ? sk : sk1; +@@ -933,6 +943,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + { + struct sock *sk, *parent; + bdaddr_t src, dst; ++ bool defer_setup = false; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); +@@ -946,6 +957,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + + bh_lock_sock(parent); + ++ if (parent->sk_state != BT_LISTEN) ++ goto done; ++ ++ defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -973,9 +989,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + done: + bh_unlock_sock(parent); + +- if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) ++ if (defer_setup) + parent->sk_state_change(parent); + ++ sock_put(parent); ++ + return result; + } + +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-policy-smq-check-allocation-under-invalidat.patch b/queue-5.10/dm-cache-policy-smq-check-allocation-under-invalidat.patch new file mode 100644 index 0000000000..8f06af83c3 --- /dev/null +++ b/queue-5.10/dm-cache-policy-smq-check-allocation-under-invalidat.patch @@ -0,0 +1,71 @@ +From 73cda6fd16d981a07a3795de8a11734f0ae8ae8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:57:45 +0800 +Subject: dm cache policy smq: check allocation under invalidate lock + +From: Guangshuo Li + +[ Upstream commit d3f0a606b9f278ece8a0df626ded9c4044071235 ] + +commit 2d1f7b65f5de ("dm cache policy smq: fix missing locks in +invalidating cache blocks") added mq->lock around the destructive part of +smq_invalidate_mapping(), but left the e->allocated check outside the +critical section. + +That leaves a check-then-act race. Two concurrent invalidators can both +observe e->allocated as true before either of them takes mq->lock. The +first invalidator that acquires the lock removes the entry from the +queues and hash table and then calls free_entry(), which clears +e->allocated and puts the entry back on the free list. The second +invalidator can then acquire mq->lock and continue with the stale result +of the unlocked check. + +This can corrupt the SMQ queues or hash table by deleting an entry that +is no longer on those structures. It can also hit the allocation check in +free_entry() when the same entry is freed again. + +Move the allocation check under mq->lock so the predicate and the +destructive operations are serialized by the same lock. + +Fixes: 2d1f7b65f5de ("dm cache policy smq: fix missing locks in invalidating cache blocks") +Signed-off-by: Guangshuo Li +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 95b0670c32acda..e5c4d7ff2c655b 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1585,18 +1585,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; +- +- if (!e->allocated) +- return -ENODATA; ++ int r = 0; + + spin_lock_irqsave(&mq->lock, flags); ++ if (!e->allocated) { ++ r = -ENODATA; ++ goto out; ++ } + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ ++out: + spin_unlock_irqrestore(&mq->lock, flags); + +- return 0; ++ return r; + } + + static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) +-- +2.53.0 + diff --git a/queue-5.10/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch b/queue-5.10/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch new file mode 100644 index 0000000000..dffb92da98 --- /dev/null +++ b/queue-5.10/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch @@ -0,0 +1,53 @@ +From d98a5e38fdac7819c91b15754475bf7af9e429f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 19:00:13 +0100 +Subject: drm/imx: Fix three kernel-doc warnings in dcss-scaler.c + +From: Yicong Hui + +[ Upstream commit ae0383e5a9a4b12d68c76c4769857def4665deff ] + +Fix the following W=1 kerneldoc warnings by adding the missing parameter +descriptions for @phase0_identity and @nn_interpolation in +dcss_scaler_filter_design() and @phase0_identity in +dcss_scaler_gaussian_filter() + +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:173 function parameter 'phase0_identity' not described in 'dcss_scaler_gaussian_filter' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'phase0_identity' not described in 'dcss_scaler_filter_design' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'nn_interpolation' not described in 'dcss_scaler_filter_design' + +Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") +Signed-off-by: Yicong Hui +Reviewed-by: Laurentiu Palcu +Link: https://patch.msgid.link/20260406180013.2442096-1-yiconghui@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/dcss/dcss-scaler.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +index cd21905de580ff..d156cc60c3f4aa 100644 +--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c ++++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +@@ -164,6 +164,7 @@ static int exp_approx_q(int x) + * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter. + * @fc_q: fixed-point cutoff frequency normalized to range [0, 1] + * @use_5_taps: indicates whether to use 5 taps or 7 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output filter coefficients + */ + static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, +@@ -249,7 +250,9 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, + * @src_length: length of input + * @dst_length: length of output + * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output coefficients ++ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter + */ + static void dcss_scaler_filter_design(int src_length, int dst_length, + bool use_5_taps, bool phase0_identity, +-- +2.53.0 + diff --git a/queue-5.10/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch b/queue-5.10/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch new file mode 100644 index 0000000000..7b20c9b5c6 --- /dev/null +++ b/queue-5.10/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch @@ -0,0 +1,56 @@ +From 00df3310ed12fc676c5e7e7348ee5d26ded0ed99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 07:29:55 +0000 +Subject: ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit() + +From: Eric Dumazet + +[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ] + +The aoe driver (or similar) generates a non-IPv6 packet +(e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() +on a 6LoWPAN interface (configured by the user or test case). + +Since the packet is not IPv6, the 6LoWPAN header_ops->create function +(lowpan_header_create or header_create) returns early without initializing +the lowpan_addr_info structure in the skb headroom. + +In the transmit function (lowpan_xmit), the driver calls lowpan_header +(or setup_header) which unconditionally copies and uses the lowpan_addr_info +from the headroom, which contains uninitialized data. + +Fix this by dropping non IPv6 packets. + +A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit(). + +Fixes: 4dc315e267fe ("ieee802154: 6lowpan: move transmit functionality") +Reported-by: syzbot+f13c19f75e1097abd116@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1fd763.278b5b03.2bcf39.0049.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260603072955.4032221-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ieee802154/6lowpan/tx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c +index 0c07662b44c0ca..4df76ff50699ed 100644 +--- a/net/ieee802154/6lowpan/tx.c ++++ b/net/ieee802154/6lowpan/tx.c +@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) + + pr_debug("package xmit\n"); + ++ if (skb->protocol != htons(ETH_P_IPV6)) { ++ kfree_skb(skb); ++ return NET_XMIT_DROP; ++ } ++ + WARN_ON_ONCE(skb->len > IPV6_MIN_MTU); + + /* We must take a copy of the skb before we modify/replace the ipv6 +-- +2.53.0 + diff --git a/queue-5.10/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch b/queue-5.10/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch new file mode 100644 index 0000000000..09e1b0b2f8 --- /dev/null +++ b/queue-5.10/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch @@ -0,0 +1,54 @@ +From 273fc27cc2ef3363b93d1bcf1a8517892e84b8d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:15:47 +0000 +Subject: ipv4: restrict IPOPT_SSRR and IPOPT_LSRR options + +From: Eric Dumazet + +[ Upstream commit d3915a1f5a4bc0ac911032903c3c6ab8df9fcc7c ] + +This patch restricts setting Loose Source and Record Route (LSRR) +and Strict Source and Record Route (SSRR) IP options to users +with CAP_NET_RAW capability. + +This prevents unprivileged applications from forcing packets to route +through attacker-controlled nodes to leak TCP ISN and possibly other +protocol information. + +While LSRR and SSRR are commonly filtered in many network environments, +they may still be supported and forwarded along some network paths. + +RFC 7126 (Recommendations on Filtering of IPv4 Packets Containing +IPv4 Options) recommend to drop these options in 4.3 and 4.4. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260602161547.2642155-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_options.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index da1b5038bdfd04..4afdaaab616239 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -543,6 +543,10 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp, + kfree(opt); + return -EINVAL; + } ++ if (opt->opt.srr && !ns_capable(net->user_ns, CAP_NET_RAW)) { ++ kfree(opt); ++ return -EPERM; ++ } + kfree(*optp); + *optp = opt; + return 0; +-- +2.53.0 + diff --git a/queue-5.10/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch b/queue-5.10/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch new file mode 100644 index 0000000000..0b8f86836e --- /dev/null +++ b/queue-5.10/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch @@ -0,0 +1,127 @@ +From d2f7195ce52377f76e3585b6a25ee857ed166ec0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 07:07:44 +0300 +Subject: ipvs: clear the svc scheduler ptr early on edit + +From: Julian Anastasov + +[ Upstream commit 193989cc6d80dd8e0460fb3992e69fa03bf0ff9b ] + +ip_vs_edit_service() while unbinding the old scheduler clears +the svc->scheduler ptr after the scheduler module initiates +RCU callbacks. This can cause packets to use the old +scheduler at the time when svc->sched_data is already freed +after RCU grace period. + +Fix it by clearing the ptr early in ip_vs_unbind_scheduler(), +before the done_service method schedules any RCU callbacks. + +Also, if the new scheduler fails to initialize when replacing +the old scheduler, try to restore the old scheduler while still +returning the error code. + +Link: https://sashiko.dev/#/patchset/20260519015506.634185-1-rosenp%40gmail.com +Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed") +Signed-off-by: Julian Anastasov +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/ip_vs.h | 3 +-- + net/netfilter/ipvs/ip_vs_ctl.c | 13 ++++++++----- + net/netfilter/ipvs/ip_vs_sched.c | 14 +++++++------- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +index c02c3bb0fe091d..7891c17ff8b688 100644 +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -1396,8 +1396,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched); ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc); + struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); + void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); + struct ip_vs_conn * +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index 4c9ef2ae4d6877..0805c9083eaa8f 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -1417,7 +1417,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, + if (ret_hooks >= 0) + ip_vs_unregister_hooks(ipvs, u->af); + if (svc != NULL) { +- ip_vs_unbind_scheduler(svc, sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_service_free(svc); + } + ip_vs_scheduler_put(sched); +@@ -1479,9 +1479,8 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + old_sched = rcu_dereference_protected(svc->scheduler, 1); + if (sched != old_sched) { + if (old_sched) { +- ip_vs_unbind_scheduler(svc, old_sched); +- RCU_INIT_POINTER(svc->scheduler, NULL); +- /* Wait all svc->sched_data users */ ++ ip_vs_unbind_scheduler(svc); ++ /* Wait all svc->scheduler/sched_data users */ + synchronize_rcu(); + } + /* Bind the new scheduler */ +@@ -1489,6 +1488,10 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + ret = ip_vs_bind_scheduler(svc, sched); + if (ret) { + ip_vs_scheduler_put(sched); ++ /* Try to restore the old_sched */ ++ if (old_sched && ++ !ip_vs_bind_scheduler(svc, old_sched)) ++ old_sched = NULL; + goto out; + } + } +@@ -1545,7 +1548,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup) + + /* Unbind scheduler */ + old_sched = rcu_dereference_protected(svc->scheduler, 1); +- ip_vs_unbind_scheduler(svc, old_sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_scheduler_put(old_sched); + + /* Unbind persistence engine, keep svc->pe */ +diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c +index d4903723be7e90..49b2e5d2b2c837 100644 +--- a/net/netfilter/ipvs/ip_vs_sched.c ++++ b/net/netfilter/ipvs/ip_vs_sched.c +@@ -57,19 +57,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, + /* + * Unbind a service with its scheduler + */ +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched) ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc) + { +- struct ip_vs_scheduler *cur_sched; ++ struct ip_vs_scheduler *sched; + +- cur_sched = rcu_dereference_protected(svc->scheduler, 1); +- /* This check proves that old 'sched' was installed */ +- if (!cur_sched) ++ sched = rcu_dereference_protected(svc->scheduler, 1); ++ if (!sched) + return; + ++ /* Reset the scheduler before initiating any RCU callbacks */ ++ rcu_assign_pointer(svc->scheduler, NULL); ++ smp_wmb(); /* paired with smp_rmb() in ip_vs_schedule() */ + if (sched->done_service) + sched->done_service(svc); +- /* svc->scheduler can be set to NULL only by caller */ + } + + +-- +2.53.0 + diff --git a/queue-5.10/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch b/queue-5.10/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch new file mode 100644 index 0000000000..ec88c2571e --- /dev/null +++ b/queue-5.10/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch @@ -0,0 +1,79 @@ +From 4ff1ffb07e11f4a802ac3c0045c9bd1bcb86b784 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:00:13 +0800 +Subject: net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr + +From: Yizhou Zhao + +[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ] + +In mrp_pdu_parse_vecattr(), vector attribute events are encoded three +per byte and valen tracks the number of events left to process. + +The parser decrements valen after processing the first and second events +from each event byte, but not after processing the third one. When valen +is exactly a multiple of three, the loop continues after the last valid +event and consumes the next byte as a new event byte, applying a +spurious event to the MRP applicant state. + +Additionally, when valen is zero the parser unconditionally consumes +attrlen bytes as FirstValue and advances the offset, even though per +IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of +zero and no FirstValue or Vector fields. This corrupts the offset for +subsequent PDU parsing. + +Also, when valen exceeds three the loop crosses byte boundaries but +the attribute value is not incremented between the last event of one +byte and the first event of the next. This causes the first event of +the next byte to use the same attribute value as the third event +rather than the next consecutive value. + +Decrement valen after processing the third event, skip FirstValue +consumption when valen is zero, and increment the attribute value at +the end of each loop iteration. + +Fixes: febf018d2234 ("net/802: Implement Multiple Registration Protocol (MRP)") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Link: https://patch.msgid.link/20260603060016.21522-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/mrp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/802/mrp.c b/net/802/mrp.c +index c10a432a5b4351..017839c141841f 100644 +--- a/net/802/mrp.c ++++ b/net/802/mrp.c +@@ -702,6 +702,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) & + MRP_VECATTR_HDR_LEN_MASK); + ++ /* If valen is 0, only a LeaveAllEvent is present; FirstValue and ++ * Vector fields are absent per IEEE 802.1ak. ++ */ ++ if (valen == 0) ++ return 0; ++ + /* The VectorAttribute structure in a PDU carries event information + * about one or more attributes having consecutive values. Only the + * value for the first attribute is contained in the structure. So +@@ -752,6 +758,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + vaevents %= __MRP_VECATTR_EVENT_MAX; + vaevent = vaevents; + mrp_pdu_parse_vecattr_event(app, skb, vaevent); ++ valen--; ++ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue, ++ mrp_cb(skb)->mh->attrlen); + } + return 0; + } +-- +2.53.0 + diff --git a/queue-5.10/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch b/queue-5.10/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch new file mode 100644 index 0000000000..0753c64774 --- /dev/null +++ b/queue-5.10/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch @@ -0,0 +1,58 @@ +From aff237d0d358858dd8237da25666f69252b961d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:31:58 +0800 +Subject: net: garp: fix unsigned integer underflow in garp_pdu_parse_attr + +From: Yizhou Zhao + +[ Upstream commit 16e408e607a94b646fb14a2a98422c6877ae4b3c ] + +The receive-side GARP attribute parser computes dlen with reversed +operands: + + dlen = sizeof(*ga) - ga->len; + +ga->len is the on-wire attribute length and includes the GARP attribute +header. For normal attributes with data, ga->len is larger than +sizeof(*ga), so the subtraction underflows in unsigned arithmetic. + +The resulting value is later passed to garp_attr_lookup(), whose length +argument is u8. After truncation, the parsed data length usually no +longer matches the length stored for locally registered attributes, so +received Join/Leave events are ignored. This breaks the GARP receive path +for common attributes, such as GVRP VLAN registration attributes. + +Compute the data length as the attribute length minus the header length. + +Fixes: eca9ebac651f ("net: Add GARP applicant-only participant") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260527083200.42861-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/garp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/802/garp.c b/net/802/garp.c +index f6012f8e59f005..2c456b362621e6 100644 +--- a/net/802/garp.c ++++ b/net/802/garp.c +@@ -452,7 +452,7 @@ static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); +- dlen = sizeof(*ga) - ga->len; ++ dlen = ga->len - sizeof(*ga); + + if (attrtype > app->app->maxattr) + return 0; +-- +2.53.0 + diff --git a/queue-5.10/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch b/queue-5.10/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch new file mode 100644 index 0000000000..2e0103d4f6 --- /dev/null +++ b/queue-5.10/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch @@ -0,0 +1,99 @@ +From 02df86af6597091e0fdb3885710f541e0099c2ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 21:03:00 +0000 +Subject: net: lan743x: permit VLAN-tagged packets up to configured MTU + +From: David Thompson + +[ Upstream commit 8173d22b211f615015f7b35f48ab11a6dd78dc99 ] + +VLAN-tagged interfaces on lan743x devices were previously unreachable via +SSH and failed to respond to large ping packets (e.g. "ping -s 1469" given +MTU=1500). In these scenarios, "ethtool -S" reports non-zero "RX Oversize +Frame Errors". According to Microchip AN2948, the MAC_RX FSE (VLAN field +size enforcement) bit determines whether frames with VLAN tags exceeding +the base MTU plus tag length are discarded. + +The driver must set the MAC_RX.FSE bit before setting MAC_RX.RXEN to allow +VLAN-tagged frames up to the interface MTU, preventing them from being +treated as oversized. As a result, both the base and VLAN-tagged interfaces +can use the same MTU without receive errors. + +Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") +Signed-off-by: David Thompson +Reviewed-by: Thangaraj Samynathan +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz # lan7430 on arm64 (RevPi +Link: https://patch.msgid.link/20260529210300.433135-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 32 +++++++++++++++++++ + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 26a230c60efb70..f280fda24f7f07 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -799,6 +799,36 @@ static void lan743x_mac_set_address(struct lan743x_adapter *adapter, + "MAC address set to %pM\n", addr); + } + ++static void lan743x_mac_rx_enable_fse(struct lan743x_adapter *adapter) ++{ ++ u32 mac_rx; ++ bool rxen; ++ ++ mac_rx = lan743x_csr_read(adapter, MAC_RX); ++ if (mac_rx & MAC_RX_FSE_) ++ return; ++ ++ rxen = mac_rx & MAC_RX_RXEN_; ++ if (rxen) { ++ mac_rx &= ~MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, ++ 1, 1000, 20000, 100); ++ } ++ ++ /* Per AN2948, hardware prevents modification of the FSE bit while the ++ * MAC receiver is enabled (RXEN bit set). Use separate register write ++ * to assert the FSE bit before enabling the RXEN bit in MAC_RX ++ */ ++ mac_rx |= MAC_RX_FSE_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ ++ if (rxen) { ++ mac_rx |= MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ } ++} ++ + static int lan743x_mac_init(struct lan743x_adapter *adapter) + { + bool mac_address_valid = true; +@@ -838,6 +868,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter) + lan743x_mac_set_address(adapter, adapter->mac_address); + ether_addr_copy(netdev->dev_addr, adapter->mac_address); + ++ lan743x_mac_rx_enable_fse(adapter); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 2a40cc827b1872..3062c54faffd18 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -118,6 +118,7 @@ + #define MAC_RX (0x104) + #define MAC_RX_MAX_SIZE_SHIFT_ (16) + #define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) ++#define MAC_RX_FSE_ BIT(2) + #define MAC_RX_RXD_ BIT(1) + #define MAC_RX_RXEN_ BIT(0) + +-- +2.53.0 + diff --git a/queue-5.10/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch b/queue-5.10/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch new file mode 100644 index 0000000000..0a4c3dc79a --- /dev/null +++ b/queue-5.10/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch @@ -0,0 +1,106 @@ +From 51a5d4a931a07c68dc762d416e17c2edf3a79678 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 12:08:12 -0400 +Subject: net/sched: act_api: use RCU with deferred freeing for action + lifecycle + +From: Jamal Hadi Salim + +[ Upstream commit 5057e1aca011e51ef51498c940ef96f3d3e8a305 ] + +When NEWTFILTER and DELFILTER are run concurrently it is possible to create a +race with an associated action. + +Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: + + 0: mutex_lock() <-- holds the idr lock + 0: rcu_read_lock() + 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) + 0: mutex_unlock() <-- releases the idr lock + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) <-- Action removed from IDR + 1: mutex_unlock() <-- mutex released allowing us to delete the action + 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory + +This patch fixes the race condition between NEWTFILTER and DELFILTER by +adding struct rcu_head to tc_action used in the deferral and introducing a +call_rcu() in the delete path to defer the final kfree(). + +Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +but also modernization/simplification to directly use kfree_rcu(). + +Let's illustrate the new restored code path: + + 0: rcu_read_lock() + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) + 1: mutex_unlock() + 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period + 0: p = idr_find(idr, index) + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 + 1: rcu_read_unlock() <-- release so freeing can run after grace period + +After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. +CPU0's subsequent idr_find() will return NULL, and even if it still held a +stale pointer, the immediate kfree() is now deferred until after the RCU grace +period, so no UAF can occur. + +Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +Suggested-by: Jakub Kicinski +Reported-by: Kyle Zeng +Tested-by: Victor Nogueira +Tested-by: syzbot@syzkaller.appspotmail.com +Signed-off-by: Jamal Hadi Salim +Tested-by: Kyle Zeng +Reviewed-by: Pedro Tammela +Reviewed-by: Eric Dumazet +Reviewed-by: Victor Nogueira +Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/act_api.h | 1 + + net/sched/act_api.c | 7 +------ + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/net/act_api.h b/include/net/act_api.h +index 2c88b8af3cdbe1..bbc4ab5e04f7d1 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -41,6 +41,7 @@ struct tc_action { + struct tc_cookie __rcu *act_cookie; + struct tcf_chain __rcu *goto_chain; + u32 tcfa_flags; ++ struct rcu_head tcfa_rcu; + u8 hw_stats; + u8 used_hw_stats; + bool used_hw_stats_valid; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index bf98bb602a9de7..c724eea8cf8c52 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -93,11 +93,6 @@ struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action, + } + EXPORT_SYMBOL(tcf_action_set_ctrlact); + +-/* XXX: For standalone actions, we don't need a RCU grace period either, because +- * actions are always connected to filters and filters are already destroyed in +- * RCU callbacks, so after a RCU grace period actions are already disconnected +- * from filters. Readers later can not find us. +- */ + static void free_tcf(struct tc_action *p) + { + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); +@@ -110,7 +105,7 @@ static void free_tcf(struct tc_action *p) + if (chain) + tcf_chain_put_by_act(chain); + +- kfree(p); ++ kfree_rcu(p, tcfa_rcu); + } + + static void tcf_action_cleanup(struct tc_action *p) +-- +2.53.0 + diff --git a/queue-5.10/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch b/queue-5.10/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch new file mode 100644 index 0000000000..a7c336e8bf --- /dev/null +++ b/queue-5.10/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch @@ -0,0 +1,58 @@ +From 4daa3b40e6ee13d5a7031393a6f2321403f90d27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 12:29:10 +0000 +Subject: netfilter: bridge: make ebt_snat ARP rewrite writable + +From: Yiming Qian + +[ Upstream commit 67ba971ae02514d85818fe0c32549ab4bfa3bf49 ] + +The ebtables SNAT target keeps the Ethernet source address rewrite +behind skb_ensure_writable(skb, 0). This is intentional: at the bridge +ebtables hooks the Ethernet header is addressed through +skb_mac_header()/eth_hdr(), while skb->data points at the Ethernet +payload. Asking skb_ensure_writable() for ETH_HLEN bytes would check +the payload, not the Ethernet header, and would reintroduce the small +packet regression fixed by commit 63137bc5882a. + +However, the optional ARP sender hardware address rewrite is different. +It writes through skb_store_bits() at an offset relative to skb->data: + + skb_store_bits(skb, sizeof(struct arphdr), info->mac, ETH_ALEN) + +skb_header_pointer() only safely reads the ARP header; it does not make +the later sender hardware address range writable. If that range is +still held in a nonlinear skb fragment backed by a splice-imported file +page, skb_store_bits() maps the frag page and copies the new MAC address +directly into it. + +Ensure the ARP SHA range is writable before reading the ARP header and +before calling skb_store_bits(). + +Fixes: 63137bc5882a ("netfilter: ebtables: Fixes dropping of small packets in bridge nat") +Reported-by: Yiming Qian +Signed-off-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_snat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c +index 7dfbcdfc30e5d2..c9e229af0366b8 100644 +--- a/net/bridge/netfilter/ebt_snat.c ++++ b/net/bridge/netfilter/ebt_snat.c +@@ -31,6 +31,9 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) + const struct arphdr *ap; + struct arphdr _ah; + ++ if (skb_ensure_writable(skb, sizeof(_ah) + ETH_ALEN)) ++ return EBT_DROP; ++ + ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch b/queue-5.10/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch new file mode 100644 index 0000000000..d2e12da4dc --- /dev/null +++ b/queue-5.10/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch @@ -0,0 +1,50 @@ +From 1983fb134edd72f163eef4ed21eb5de40c4989b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:20:19 +0200 +Subject: netfilter: conntrack_irc: fix possible out-of-bounds read + +From: Florian Westphal + +[ Upstream commit 66eba0ffce3b7e11449946b4cbbef8ea36112f56 ] + +When parsing fails after we've matched the command string we +should bail out instead of trying to match a different command. + +This helper should be deprecated, given prevalence of TLS I doubt it has +any relevance in 2026. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Closes: https://sashiko.dev/#/patchset/20260525182924.28456-1-fw%40strlen.de +Signed-off-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_irc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c +index 65b5b05fe38d37..24533bee001b7d 100644 +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -199,7 +199,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + pr_debug("unable to parse dcc command\n"); +- continue; ++ goto out; + } + + pr_debug("DCC bound ip/port: %pI4:%u\n", +@@ -213,7 +213,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); +- continue; ++ goto out; + } + + exp = nf_ct_expect_alloc(ct); +-- +2.53.0 + diff --git a/queue-5.10/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch b/queue-5.10/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch new file mode 100644 index 0000000000..ce447e0578 --- /dev/null +++ b/queue-5.10/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch @@ -0,0 +1,113 @@ +From d502f5da6d6c84cde12899190c66894608216b7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 23:58:31 +0200 +Subject: netfilter: synproxy: add mutex to guard hook reference counting + +From: Fernando Fernandez Mancera + +[ Upstream commit 2fcba19caaeb2a33017459d3430f057967bb91b6 ] + +As the synproxy infrastructure register netfilter hooks on-demand when a +user adds the first iptables target or nftables expression, if done +concurrently they can race each other. + +Introduce a mutex to serialize the refcount control blocks access from +both frontends. While a per namespace mutex might be more efficient, it +is not needed for target/expression like SYNPROXY. + +Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 0a97b1a0f53e45..4a742dda15da71 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -21,6 +21,8 @@ + #include + #include + ++static DEFINE_MUTEX(synproxy_mutex); ++ + unsigned int synproxy_net_id; + EXPORT_SYMBOL_GPL(synproxy_net_id); + +@@ -790,26 +792,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = { + + int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref4 == 0) { + err = nf_register_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref4++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init); + + void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref4--; + if (snet->hook_ref4 == 0) + nf_unregister_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini); + +@@ -1214,27 +1221,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = { + int + nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref6 == 0) { + err = nf_register_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref6++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init); + + void + nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref6--; + if (snet->hook_ref6 == 0) + nf_unregister_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini); + #endif /* CONFIG_IPV6 */ +-- +2.53.0 + diff --git a/queue-5.10/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch b/queue-5.10/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..1a64284ccb --- /dev/null +++ b/queue-5.10/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch @@ -0,0 +1,41 @@ +From 0b715677a39b2e66b3b4ecc00fa4af9672736a67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 12:47:17 +0200 +Subject: netfilter: xt_NFQUEUE: prefer raw_smp_processor_id + +From: Fernando Fernandez Mancera + +[ Upstream commit c6c5327dd18bec1e1bbf139b2cf5ae53608a9d30 ] + +With PREEMPT_RCU this triggers a splat because smp_processor_id() can be +preempted while inside a RCU critical section. If xt_NFQUEUE target is +invoked via nft_compat_eval() path, we are inside a RCU critical +section. + +Just use the raw version instead. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_NFQUEUE.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index 466da23e36ff47..b32d153e3a1862 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -91,7 +91,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) + + if (info->queues_total > 1) { + if (info->flags & NFQ_FLAG_CPU_FANOUT) { +- int cpu = smp_processor_id(); ++ int cpu = raw_smp_processor_id(); + + queue = info->queuenum + cpu % info->queues_total; + } else { +-- +2.53.0 + diff --git a/queue-5.10/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch b/queue-5.10/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch new file mode 100644 index 0000000000..8541467120 --- /dev/null +++ b/queue-5.10/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch @@ -0,0 +1,58 @@ +From 20a5fbb56e207ddf5452d119ab7754f5718017c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 16:03:20 +0200 +Subject: pcnet32: stop holding device spin lock during napi_complete_done + +From: Oscar Maes + +[ Upstream commit 73bf3cca7de6a73f53b6a52dc3b1c82ae5667a4d ] + +napi_complete_done may call gro_flush_normal (though not currently, as GRO +is unsupported at the moment), which may result in packet TX. This will +eventually result in calling pcnet32_start_xmit - resulting in a deadlock +while trying to re-acquire the already locked spin lock. + +It is safe to split the spinlock block into two, because the hardware +registers are still protected from concurrent access, and the two blocks +perform unrelated operations that don't need to happen atomically. + +Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()") +Reviewed-by: Andrew Lunn +Signed-off-by: Oscar Maes +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/pcnet32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c +index f78daba60b35c0..ce5b8e6aa976f9 100644 +--- a/drivers/net/ethernet/amd/pcnet32.c ++++ b/drivers/net/ethernet/amd/pcnet32.c +@@ -1399,8 +1399,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + pcnet32_restart(dev, CSR0_START); + netif_wake_queue(dev); + } ++ spin_unlock_irqrestore(&lp->lock, flags); + + if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a->read_csr(ioaddr, CSR3); + val &= 0x00ff; +@@ -1408,9 +1410,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + + /* Set interrupt enable. */ + lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN); ++ spin_unlock_irqrestore(&lp->lock, flags); + } + +- spin_unlock_irqrestore(&lp->lock, flags); + return work_done; + } + +-- +2.53.0 + diff --git a/queue-5.10/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch b/queue-5.10/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch new file mode 100644 index 0000000000..e7a0b75d08 --- /dev/null +++ b/queue-5.10/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch @@ -0,0 +1,87 @@ +From 6e21075789b42bb03af8b9beb767d6b85be83e54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:11:44 -0400 +Subject: sctp: purge outqueue on stale COOKIE-ECHO handling + +From: Xin Long + +[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ] + +sctp_stream_update() is only invoked when the association is moved into +COOKIE_WAIT during association setup/reconfiguration. In this path, the +outbound stream scheduler state (stream->out_curr) is expected to be +clean, since no user data should have been transmitted yet unless the +state machine has already partially progressed. + +However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a +Stale Cookie ERROR is received, the association is rolled back from +COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already +have been queued and even bundled with the COOKIE-ECHO chunk. + +During the rollback, sctp_stream_update() frees the old stream table +and installs a new one, but it does not invalidate stream->out_curr. +As a result, out_curr may still point to a freed sctp_stream_out +entry from the previous stream state. + +Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on +stream->out_curr->ext, which can lead to use-after-free once the old +stream state has been released via sctp_stream_free(). + +This results in crashes such as (reported by Yuqi): + + BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140 + Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312 + CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted + 7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full) + sctp_sched_fcfs_dequeue+0x13a/0x140 + sctp_outq_flush+0x1603/0x33e0 + sctp_do_sm+0x31c9/0x5d30 + sctp_assoc_bh_rcv+0x392/0x6f0 + sctp_inq_push+0x1db/0x270 + sctp_rcv+0x138d/0x3c10 + +Fix this by fully purging the association outqueue when handling the +Stale Cookie case. This ensures all pending transmit and retransmit +state is dropped, and any scheduler cached pointers are invalidated, +making it safe to rebuild stream state during COOKIE_WAIT restart. + +Updating only stream->out_curr would be insufficient, since queued +and retransmittable data would still reference the old stream state and +trigger later use-after-free in dequeue paths. + +Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Reported-by: Yuqi Xu +Reported-by: Ren Wei +Signed-off-by: Xin Long +Link: https://patch.msgid.link/94318159b9052907a6cbb7256aee8b5f8dfbfccb.1780510304.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index af75b940855681..7ac3ad83ddd5fe 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2523,11 +2523,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + +- /* If we've sent any data bundled with COOKIE-ECHO we will need to +- * resend +- */ +- sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, +- SCTP_TRANSPORT(asoc->peer.primary_path)); ++ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 009d4e8bc6..0916cf682e 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -127,3 +127,22 @@ hid-core-fix-size_t-specifier-in-hid_report_raw_even.patch usb-serial-mct_u232-fix-memory-corruption-with-small.patch compiler-clang.h-add-__diag-infrastructure-for-clang.patch disable-wattribute-alias-for-clang-23-and-newer.patch +tee-optee-prevent-use-after-free-when-the-client-exi.patch +netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch +ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch +netfilter-synproxy-add-mutex-to-guard-hook-reference.patch +netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch +netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch +dm-cache-policy-smq-check-allocation-under-invalidat.patch +net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch +6lowpan-fix-off-by-one-in-multicast-context-address-.patch +drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch +pcnet32-stop-holding-device-spin-lock-during-napi_co.patch +net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch +net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch +bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch +bluetooth-mgmt-validate-advertising-tlv-before-type-.patch +ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch +ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch +net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch +sctp-purge-outqueue-on-stale-cookie-echo-handling.patch diff --git a/queue-5.10/tee-optee-prevent-use-after-free-when-the-client-exi.patch b/queue-5.10/tee-optee-prevent-use-after-free-when-the-client-exi.patch new file mode 100644 index 0000000000..5dd6ec2c7c --- /dev/null +++ b/queue-5.10/tee-optee-prevent-use-after-free-when-the-client-exi.patch @@ -0,0 +1,287 @@ +From 936156aa94def542fd31e670379d7a6e5f35fee9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:24:06 -0800 +Subject: tee: optee: prevent use-after-free when the client exits before the + supplicant + +From: Amirreza Zarrabi + +[ Upstream commit 387a926ee166814611acecb960207fe2f3c4fd3e ] + +Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the +client wait as killable so it can be interrupted during shutdown or +after a supplicant crash. This changes the original lifetime expectations: +the client task can now terminate while the supplicant is still processing +its request. + +If the client exits first it removes the request from its queue and +kfree()s it, while the request ID remains in supp->idr. A subsequent +lookup on the supplicant path then dereferences freed memory, leading to +a use-after-free. + +Serialise access to the request with supp->mutex: + + * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while + looking up and touching the request. + * Let optee_supp_thrd_req() notice that the client has terminated and + signal optee_supp_send() accordingly. + +With these changes the request cannot be freed while the supplicant still +has a reference, eliminating the race. + +Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") +Signed-off-by: Amirreza Zarrabi +Tested-by: Ox Yeh +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/supp.c | 107 +++++++++++++++++++++++++++------------ + 1 file changed, 74 insertions(+), 33 deletions(-) + +diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c +index d0f397c9024201..2386bbd38ce78b 100644 +--- a/drivers/tee/optee/supp.c ++++ b/drivers/tee/optee/supp.c +@@ -10,7 +10,11 @@ + struct optee_supp_req { + struct list_head link; + ++ int id; ++ + bool in_queue; ++ bool processed; ++ + u32 func; + u32 ret; + size_t num_params; +@@ -19,6 +23,9 @@ struct optee_supp_req { + struct completion c; + }; + ++/* It is temporary request used for revoked pending request in supp->idr. */ ++#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) ++ + void optee_supp_init(struct optee_supp *supp) + { + memset(supp, 0, sizeof(*supp)); +@@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) + { + int id; + struct optee_supp_req *req; +- struct optee_supp_req *req_tmp; + + mutex_lock(&supp->mutex); + +- /* Abort all request retrieved by supplicant */ ++ /* Abort all request */ + idr_for_each_entry(&supp->idr, req, id) { + idr_remove(&supp->idr, id); +- req->ret = TEEC_ERROR_COMMUNICATION; +- complete(&req->c); +- } ++ /* Skip if request was already marked invalid */ ++ if (IS_ERR(req)) ++ continue; + +- /* Abort all queued requests */ +- list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { +- list_del(&req->link); +- req->in_queue = false; ++ /* For queued requests where supplicant has not seen it */ ++ if (req->in_queue) { ++ list_del(&req->link); ++ req->in_queue = false; ++ } ++ ++ req->processed = true; + req->ret = TEEC_ERROR_COMMUNICATION; + complete(&req->c); + } +@@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + + /* Insert the request in the request list */ + mutex_lock(&supp->mutex); ++ req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); ++ if (req->id < 0) { ++ mutex_unlock(&supp->mutex); ++ kfree(req); ++ return TEEC_ERROR_OUT_OF_MEMORY; ++ } ++ + list_add_tail(&req->link, &supp->reqs); + req->in_queue = true; ++ req->processed = false; + mutex_unlock(&supp->mutex); + + /* Tell an eventual waiter there's a new request */ +@@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + if (wait_for_completion_killable(&req->c)) { + mutex_lock(&supp->mutex); + if (req->in_queue) { ++ /* Supplicant has not seen this request yet. */ ++ idr_remove(&supp->idr, req->id); + list_del(&req->link); + req->in_queue = false; ++ ++ ret = TEEC_ERROR_COMMUNICATION; ++ } else if (req->processed) { ++ /* ++ * Supplicant has processed this request. Ignore the ++ * kill signal for now and submit the result. req is not ++ * in supp->reqs (removed by supp_pop_entry()) nor in ++ * supp->idr (removed by supp_pop_req()). ++ */ ++ ret = req->ret; ++ } else { ++ /* ++ * Supplicant is in the middle of processing this ++ * request. Replace req with INVALID_REQ_PTR so that ++ * the ID remains busy, causing optee_supp_send() to ++ * fail on the next call to supp_pop_req() with this ID. ++ */ ++ idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); ++ ret = TEEC_ERROR_COMMUNICATION; + } ++ + mutex_unlock(&supp->mutex); +- req->ret = TEEC_ERROR_COMMUNICATION; ++ } else { ++ ret = req->ret; + } + +- ret = req->ret; + kfree(req); + + return ret; + } + + static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, +- int num_params, int *id) ++ int num_params) + { + struct optee_supp_req *req; + +@@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, + return ERR_PTR(-EINVAL); + } + +- *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); +- if (*id < 0) +- return ERR_PTR(-ENOMEM); +- + list_del(&req->link); + req->in_queue = false; + +@@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + struct optee_supp_req *req = NULL; +- int id; + size_t num_meta; + int rc; + +@@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + + while (true) { + mutex_lock(&supp->mutex); +- req = supp_pop_entry(supp, *num_params - num_meta, &id); ++ req = supp_pop_entry(supp, *num_params - num_meta); ++ if (req) ++ break; /* Keep mutex held. */ + mutex_unlock(&supp->mutex); + +- if (req) { +- if (IS_ERR(req)) +- return PTR_ERR(req); +- break; +- } +- + /* + * If we didn't get a request we'll block in + * wait_for_completion() to avoid needless spinning. +@@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + return -ERESTARTSYS; + } + ++ /* supp->mutex held and req != NULL. */ ++ ++ if (IS_ERR(req)) { ++ mutex_unlock(&supp->mutex); ++ return PTR_ERR(req); ++ } ++ + if (num_meta) { + /* + * tee-supplicant support meta parameters -> requsts can be +@@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + */ + param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; +- param->u.value.a = id; ++ param->u.value.a = req->id; + param->u.value.b = 0; + param->u.value.c = 0; + } else { +- mutex_lock(&supp->mutex); +- supp->req_id = id; +- mutex_unlock(&supp->mutex); ++ supp->req_id = req->id; + } + + *func = req->func; +@@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + ++ mutex_unlock(&supp->mutex); + return 0; + } + +@@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, + if (!req) + return ERR_PTR(-ENOENT); + ++ /* optee_supp_thrd_req() already returned to optee. */ ++ if (IS_ERR(req)) ++ goto failed_req; ++ + if ((num_params - nm) != req->num_params) + return ERR_PTR(-EINVAL); + ++ *num_meta = nm; ++failed_req: + idr_remove(&supp->idr, id); + supp->req_id = -1; +- *num_meta = nm; + + return req; + } +@@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + + mutex_lock(&supp->mutex); + req = supp_pop_req(supp, num_params, param, &num_meta); +- mutex_unlock(&supp->mutex); +- + if (IS_ERR(req)) { +- /* Something is wrong, let supplicant restart. */ ++ mutex_unlock(&supp->mutex); ++ /* Something is wrong, let supplicant handel it. */ + return PTR_ERR(req); + } + +@@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + } + } + req->ret = ret; +- ++ req->processed = true; + /* Let the requesting thread continue */ + complete(&req->c); ++ mutex_unlock(&supp->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-5.15/6lowpan-fix-off-by-one-in-multicast-context-address-.patch b/queue-5.15/6lowpan-fix-off-by-one-in-multicast-context-address-.patch new file mode 100644 index 0000000000..f0ab0cefec --- /dev/null +++ b/queue-5.15/6lowpan-fix-off-by-one-in-multicast-context-address-.patch @@ -0,0 +1,67 @@ +From bff5b133340778a857c83761b3b1491a1e92fd5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:18:01 +0800 +Subject: 6lowpan: fix off-by-one in multicast context address compression + +From: Yizhou Zhao + +[ Upstream commit 2a58899d11009bffc7b4b32a571858f381121837 ] + +The second memcpy in lowpan_iphc_mcast_ctx_addr_compress() uses +&data[1] as destination and &ipaddr->s6_addr[11] as source, but +both should be offset by one: &data[2] and &ipaddr->s6_addr[12] +respectively. + +This off-by-one has two consequences: +1. data[1] is overwritten with s6_addr[11], corrupting the RIID + field in the compressed multicast address +2. data[5] is never written, so uninitialized kernel stack memory + is transmitted over the network via lowpan_push_hc_data(), + leaking kernel stack contents + +The correct inline data layout must match what the decompression +function lowpan_uncompress_multicast_ctx_daddr() expects: + data[0..1] = s6_addr[1..2] (flags/scope + RIID) + data[2..5] = s6_addr[12..15] (group ID) + +Also zero-initialize the data array as a defensive measure against +similar bugs in the future. + +Fixes: 5609c185f24d ("6lowpan: iphc: add support for stateful compression") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Acked-by: Alexander Aring +Link: https://patch.msgid.link/20260527081806.42747-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/6lowpan/iphc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c +index 52fad5dad9f715..d762c49e722fae 100644 +--- a/net/6lowpan/iphc.c ++++ b/net/6lowpan/iphc.c +@@ -1086,12 +1086,12 @@ static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, + const struct lowpan_iphc_ctx *ctx, + const struct in6_addr *ipaddr) + { +- u8 data[6]; ++ u8 data[6] = {}; + + /* flags/scope, reserved (RIID) */ + memcpy(data, &ipaddr->s6_addr[1], 2); + /* group ID */ +- memcpy(&data[1], &ipaddr->s6_addr[11], 4); ++ memcpy(&data[2], &ipaddr->s6_addr[12], 4); + lowpan_push_hc_data(hc_ptr, data, 6); + + return LOWPAN_IPHC_DAM_00; +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch b/queue-5.15/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch new file mode 100644 index 0000000000..24b2f7a431 --- /dev/null +++ b/queue-5.15/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch @@ -0,0 +1,71 @@ +From 5a25615f4b95f0196626c529cc94b9596cfd40ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:39:53 +0800 +Subject: Bluetooth: bnep: fix incorrect length parsing in bnep_rx_frame() + extension handling + +From: Dudu Lu + +[ Upstream commit 72b8deccff17a7644e0367e1aaf1a36cfb014324 ] + +In bnep_rx_frame(), the BNEP_FILTER_NET_TYPE_SET and +BNEP_FILTER_MULTI_ADDR_SET extension header parsing has two bugs: + +1) The 2-byte length field is read with *(u16 *)(skb->data + 1), which + performs a native-endian read. The BNEP protocol specifies this field + in big-endian (network byte order), and the same file correctly uses + get_unaligned_be16() for the identical fields in + bnep_ctrl_set_netfilter() and bnep_ctrl_set_mcfilter(). + +2) The length is multiplied by 2, but unlike BNEP_SETUP_CONN_REQ where + the length byte counts UUID pairs (requiring * 2 for two UUIDs per + entry), the filter extension length field already represents the total + data size in bytes. This is confirmed by bnep_ctrl_set_netfilter() + which reads the same field as a byte count and divides by 4 to get + the number of filter entries. + + The bogus * 2 means skb_pull advances twice as far as it should, + either dropping valid data from the next header or causing the pull + to fail entirely when the doubled length exceeds the remaining skb. + +Fix by splitting the pull into two steps: first use skb_pull_data() to +safely pull and validate the 3-byte fixed header (ctrl type + length), +then pull the variable-length data using the properly decoded length. + +Fixes: bf8b9a9cb77b ("Bluetooth: bnep: Add support to extended headers of control frames") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index f3b9c1dee1bb61..1798069ce79149 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -330,11 +330,18 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + goto badframe; + break; + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: +- /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */ +- if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2)) ++ case BNEP_FILTER_NET_TYPE_SET: { ++ u8 *hdr; ++ ++ /* Pull ctrl type (1 b) + len (2 b) */ ++ hdr = skb_pull_data(skb, 3); ++ if (!hdr) ++ goto badframe; ++ /* Pull data (len bytes); length is big-endian */ ++ if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) + goto badframe; + break; ++ } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-bnep-reject-short-frames-before-parsing.patch b/queue-5.15/bluetooth-bnep-reject-short-frames-before-parsing.patch new file mode 100644 index 0000000000..5226192588 --- /dev/null +++ b/queue-5.15/bluetooth-bnep-reject-short-frames-before-parsing.patch @@ -0,0 +1,170 @@ +From 4a6979aa5d542aa4339426c11bb2543f2d85a34b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 11:22:09 +0800 +Subject: Bluetooth: bnep: reject short frames before parsing + +From: Zhang Cen + +[ Upstream commit 6770d3a8acdf9151769180cc3710346c4cfbe6f0 ] + +A BNEP peer can send a short BNEP SDU. bnep_rx_frame() reads the +packet type byte immediately and, for control packets, reads the control +opcode and setup UUID-size byte before proving that those bytes are +present. bnep_rx_control() also dereferences the control opcode without +rejecting an empty control payload. + +Use skb_pull_data() for the fixed fields in bnep_rx_frame() so a NULL +return gates each dereference. Split the control handler so the frame +path can pass an opcode that has already been pulled, and keep the +byte-buffer wrapper for extension control payloads. + +For BNEP_SETUP_CONN_REQ, name the UUID-size byte before pulling the +setup payload. struct bnep_setup_conn_req carries destination and source +service UUIDs after that byte, each uuid_size bytes, so the parser now +documents that tuple explicitly instead of leaving the pull length as an +opaque multiplication. + +Validation reproduced this kernel report: +KASAN slab-out-of-bounds in bnep_rx_frame.isra.0+0x130c/0x1790 +The buggy address belongs to the object at ffff88800c0f7908 which belongs +to the cache kmalloc-8 of size 8 +The buggy address is located 0 bytes to the right of allocated 1-byte +region [ffff88800c0f7908, ffff88800c0f7909) +Read of size 1 +Call trace: + dump_stack_lvl+0xb3/0x140 (?:?) + print_address_description+0x57/0x3a0 (?:?) + bnep_rx_frame+0x130c/0x1790 (net/bluetooth/bnep/core.c:306) + print_report+0xb9/0x2b0 (?:?) + __virt_addr_valid+0x1ba/0x3a0 (?:?) + srso_alias_return_thunk+0x5/0xfbef5 (?:?) + kasan_addr_to_slab+0x21/0x60 (?:?) + kasan_report+0xe0/0x110 (?:?) + process_one_work+0xfce/0x17e0 (kernel/workqueue.c:3200) + worker_thread+0x65c/0xe40 (?:?) + __kthread_parkme+0x184/0x230 (?:?) + kthread+0x35e/0x470 (?:?) + _raw_spin_unlock_irq+0x28/0x50 (?:?) + ret_from_fork+0x586/0x870 (?:?) + __switch_to+0x74f/0xdc0 (?:?) + ret_from_fork_asm+0x1a/0x30 (?:?) + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 57 ++++++++++++++++++++++++--------------- + 1 file changed, 36 insertions(+), 21 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index 1798069ce79149..627ce3de29c8ee 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -206,14 +206,11 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) + return 0; + } + +-static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++static int bnep_rx_control_cmd(struct bnep_session *s, u8 cmd, void *data, ++ int len) + { +- u8 cmd = *(u8 *)data; + int err = 0; + +- data++; +- len--; +- + switch (cmd) { + case BNEP_CMD_NOT_UNDERSTOOD: + case BNEP_SETUP_CONN_RSP: +@@ -254,6 +251,14 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) + return err; + } + ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ if (len < 1) ++ return -EILSEQ; ++ ++ return bnep_rx_control_cmd(s, *(u8 *)data, data + 1, len - 1); ++} ++ + static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) + { + struct bnep_ext_hdr *h; +@@ -299,19 +304,26 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + { + struct net_device *dev = s->dev; + struct sk_buff *nskb; ++ u8 *data; + u8 type, ctrl_type; + + dev->stats.rx_bytes += skb->len; + +- type = *(u8 *) skb->data; +- skb_pull(skb, 1); +- ctrl_type = *(u8 *)skb->data; ++ data = skb_pull_data(skb, sizeof(type)); ++ if (!data) ++ goto badframe; ++ type = *data; + + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) + goto badframe; + + if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { +- if (bnep_rx_control(s, skb->data, skb->len) < 0) { ++ data = skb_pull_data(skb, sizeof(ctrl_type)); ++ if (!data) ++ goto badframe; ++ ctrl_type = *data; ++ ++ if (bnep_rx_control_cmd(s, ctrl_type, skb->data, skb->len) < 0) { + dev->stats.tx_errors++; + kfree_skb(skb); + return 0; +@@ -324,24 +336,27 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + + /* Verify and pull ctrl message since it's already processed */ + switch (ctrl_type) { +- case BNEP_SETUP_CONN_REQ: +- /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */ +- if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2)) ++ case BNEP_SETUP_CONN_REQ: { ++ u8 uuid_size; ++ ++ /* Pull uuid_size and the dst/src service UUIDs. */ ++ data = skb_pull_data(skb, sizeof(uuid_size)); ++ if (!data) ++ goto badframe; ++ uuid_size = *data; ++ if (!skb_pull(skb, uuid_size + uuid_size)) + goto badframe; + break; ++ } + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: { +- u8 *hdr; +- +- /* Pull ctrl type (1 b) + len (2 b) */ +- hdr = skb_pull_data(skb, 3); +- if (!hdr) ++ case BNEP_FILTER_NET_TYPE_SET: ++ /* Pull: len (2 b), data (len bytes) */ ++ data = skb_pull_data(skb, sizeof(u16)); ++ if (!data) + goto badframe; +- /* Pull data (len bytes); length is big-endian */ +- if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) ++ if (!skb_pull(skb, get_unaligned_be16(data))) + goto badframe; + break; +- } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch b/queue-5.15/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch new file mode 100644 index 0000000000..5aac30ac78 --- /dev/null +++ b/queue-5.15/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch @@ -0,0 +1,58 @@ +From 827605a6e1bfc878959df59247decd4b229877f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 08:54:26 +0530 +Subject: Bluetooth: fix memory leak in error path of hci_alloc_dev() + +From: Bharath Reddy + +[ Upstream commit 37b3009bf5976e8ab77c8b9a9bc3bbd7ff49e37f ] + +Early failures in Bluetooth HCI UART configuration leak SRCU percpu +memory. + +When device initialization fails before hci_register_dev() completes, +the HCI_UNREGISTER flag is never set. As a result, when the device +reference count reaches zero, bt_host_release() evaluates this flag as +false and falls back to a direct kfree(hdev). + +Because hci_release_dev() is bypassed, the SRCU struct initialized +early in hci_alloc_dev() is never cleaned up, resulting in a leak of +percpu memory. + +Fix the leak by explicitly calling cleanup_srcu_struct() in the +fallback (unregistered) branch of bt_host_release() before freeing +the device. + +Reported-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=535ecc844591e50588a5 +Tested-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Fixes: 1d6123102e9f ("Bluetooth: hci_core: Fix use-after-free in vhci_flush()") +Signed-off-by: Bharath Reddy +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sysfs.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c +index cc7d4a8ed8ce24..b1886e517a78bc 100644 +--- a/net/bluetooth/hci_sysfs.c ++++ b/net/bluetooth/hci_sysfs.c +@@ -81,10 +81,12 @@ static void bt_host_release(struct device *dev) + { + struct hci_dev *hdev = to_hci_dev(dev); + +- if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) ++ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + hci_release_dev(hdev); +- else ++ } else { ++ cleanup_srcu_struct(&hdev->srcu); + kfree(hdev); ++ } + module_put(THIS_MODULE); + } + +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch b/queue-5.15/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch new file mode 100644 index 0000000000..86fe9b383e --- /dev/null +++ b/queue-5.15/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch @@ -0,0 +1,73 @@ +From cfcda54752d4bae174baa4b89c2e45740a4a4d13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 17:45:06 +0800 +Subject: Bluetooth: MGMT: validate advertising TLV before type checks + +From: Zhang Cen + +[ Upstream commit de23fb62259aa01d294f77238ae3b835eb674413 ] + +tlv_data_is_valid() reads each advertising data field length from +data[i], then inspects data[i + 1] for managed EIR types before +checking that the current field still fits inside the supplied buffer. + +A malformed field whose length byte is the last byte of the buffer can +therefore make the parser read one byte past the advertising data. + +KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING +request reached that path: + + BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid() + Read of size 1 + Call trace: + tlv_data_is_valid() + add_advertising() + hci_mgmt_cmd() + hci_sock_sendmsg() + +Move the existing element-length check before any type-octet inspection +so each non-empty element is proven to contain its type byte before the +parser looks at data[i + 1]. + +Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check") +Reviewed-by: Paul Menzel +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 09232c424446bc..337c3cb8eec589 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -7635,6 +7635,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (!cur_len) + continue; + ++ /* If the current field length would exceed the total data ++ * length, then it's invalid. ++ */ ++ if (i + cur_len >= len) ++ return false; ++ + if (data[i + 1] == EIR_FLAGS && + (!is_adv_data || flags_managed(adv_flags))) + return false; +@@ -7651,12 +7657,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (data[i + 1] == EIR_APPEARANCE && + appearance_managed(adv_flags)) + return false; +- +- /* If the current field length would exceed the total data +- * length, then it's invalid. +- */ +- if (i + cur_len >= len) +- return false; + } + + return true; +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch b/queue-5.15/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch new file mode 100644 index 0000000000..2a309a03ac --- /dev/null +++ b/queue-5.15/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch @@ -0,0 +1,126 @@ +From 823f31595bde989177539441c4999a358f968365 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 15:56:41 +0800 +Subject: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() + +From: Zhang Cen + +[ Upstream commit 43c441edacf953b39517a44f5e5e10a93618b226 ] + +rfcomm_get_sock_by_channel() scans rfcomm_sk_list under the list lock, +but returns the selected listener after dropping that lock without +taking a reference. rfcomm_connect_ind() then locks the listener, +queues a child socket on it, and may notify it after unlocking it. + +The buggy scenario involves two paths, with each column showing the +order within that path: + +rfcomm_connect_ind(): listener close: + 1. Find parent in 1. close() enters + rfcomm_get_sock_by_channel() rfcomm_sock_release(). + 2. Drop rfcomm_sk_list.lock 2. rfcomm_sock_shutdown() + without pinning parent. closes the listener. + 3. Call lock_sock(parent) and 3. rfcomm_sock_kill() + bt_accept_enqueue(parent, unlinks and puts parent. + sk, true). + 4. Read parent flags and may 4. parent can be freed. + call sk_state_change(). + +If close wins the race, parent can be freed before +rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or the +deferred-setup callback. + +Take a reference on the listener before leaving rfcomm_sk_list.lock. +After lock_sock() succeeds, recheck that it is still in BT_LISTEN +before queueing a child, cache the deferred-setup bit while the parent +is locked, and drop the reference after the last parent use. + +KASAN reported a slab-use-after-free in lock_sock_nested() from +rfcomm_connect_ind(), with the freeing stack going through +rfcomm_sock_kill() and rfcomm_sock_release(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index d1f2c936a8a811..2f091f134a606c 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) + } + + /* Find socket with channel and source bdaddr. +- * Returns closest match. ++ * Returns closest match with an extra reference held. + */ + static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) + { +@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t * + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ +- if (!bacmp(&rfcomm_pi(sk)->src, src)) ++ if (!bacmp(&rfcomm_pi(sk)->src, src)) { ++ sock_hold(sk); + break; ++ } + + /* Closest match */ +- if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) ++ if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) { ++ if (sk1) ++ sock_put(sk1); ++ + sk1 = sk; ++ sock_hold(sk1); ++ } + } + } + ++ if (sk && sk1) ++ sock_put(sk1); ++ + read_unlock(&rfcomm_sk_list.lock); + + return sk ? sk : sk1; +@@ -941,6 +951,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + { + struct sock *sk, *parent; + bdaddr_t src, dst; ++ bool defer_setup = false; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); +@@ -954,6 +965,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + + lock_sock(parent); + ++ if (parent->sk_state != BT_LISTEN) ++ goto done; ++ ++ defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -981,9 +997,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + done: + release_sock(parent); + +- if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) ++ if (defer_setup) + parent->sk_state_change(parent); + ++ sock_put(parent); ++ + return result; + } + +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch b/queue-5.15/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch new file mode 100644 index 0000000000..dd804d2ffb --- /dev/null +++ b/queue-5.15/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch @@ -0,0 +1,167 @@ +From b9f42e89077b115bc15c205ead2af447593cb32a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:04:43 +0900 +Subject: Bluetooth: RFCOMM: validate skb length in MCC handlers + +From: SeungJu Cheon + +[ Upstream commit 23882b828c3c8c51d0c946446a396b10abb3b16b ] + +The RFCOMM MCC handlers cast skb->data to protocol-specific structs +without validating skb->len first. A malicious remote device can send +truncated MCC frames and trigger out-of-bounds reads in these handlers. + +Fix this by using skb_pull_data() to validate and access the required +data before dereferencing it. + +rfcomm_recv_rpn() requires special handling since ETSI TS 07.10 allows +1-byte RPN requests. Handle this by validating only the DLCI byte first, +and validating the full struct only when len > 1. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Suggested-by: Muhammad Bilal +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/core.c | 67 +++++++++++++++++++++++++++---------- + 1 file changed, 49 insertions(+), 18 deletions(-) + +diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c +index 4f54c7df3a94f8..374187def190da 100644 +--- a/net/bluetooth/rfcomm/core.c ++++ b/net/bluetooth/rfcomm/core.c +@@ -1427,10 +1427,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) + + static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_pn *pn; + struct rfcomm_dlc *d; +- u8 dlci = pn->dlci; ++ u8 dlci; ++ ++ pn = skb_pull_data(skb, sizeof(*pn)); ++ if (!pn) ++ return -EILSEQ; + ++ dlci = pn->dlci; + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) +@@ -1479,8 +1484,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + + static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) + { +- struct rfcomm_rpn *rpn = (void *) skb->data; +- u8 dlci = __get_dlci(rpn->dlci); ++ struct rfcomm_rpn *rpn; ++ u8 dlci; + + u8 bit_rate = 0; + u8 data_bits = 0; +@@ -1491,15 +1496,16 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + u8 xoff_char = 0; + u16 rpn_mask = RFCOMM_RPN_PM_ALL; + +- BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", +- dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, +- rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ if (len == 1) { ++ rpn = skb_pull_data(skb, 1); ++ if (!rpn) ++ return -EILSEQ; + +- if (!cr) +- return 0; ++ dlci = __get_dlci(rpn->dlci); ++ ++ if (!cr) ++ return 0; + +- if (len == 1) { +- /* This is a request, return default (according to ETSI TS 07.10) settings */ + bit_rate = RFCOMM_RPN_BR_9600; + data_bits = RFCOMM_RPN_DATA_8; + stop_bits = RFCOMM_RPN_STOP_1; +@@ -1510,6 +1516,19 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + goto rpn_out; + } + ++ rpn = skb_pull_data(skb, sizeof(*rpn)); ++ if (!rpn) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rpn->dlci); ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ + /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit, + * no parity, no flow control lines, normal XON/XOFF chars */ + +@@ -1585,9 +1604,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + + static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_rls *rls = (void *) skb->data; +- u8 dlci = __get_dlci(rls->dlci); ++ struct rfcomm_rls *rls; ++ u8 dlci; + ++ rls = skb_pull_data(skb, sizeof(*rls)); ++ if (!rls) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rls->dlci); + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) +@@ -1604,10 +1628,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_msc *msc; + struct rfcomm_dlc *d; +- u8 dlci = __get_dlci(msc->dlci); ++ u8 dlci; ++ ++ msc = skb_pull_data(skb, sizeof(*msc)); ++ if (!msc) ++ return -EILSEQ; + ++ dlci = __get_dlci(msc->dlci); + BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); + + d = rfcomm_dlc_get(s, dlci); +@@ -1640,17 +1669,19 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) + { +- struct rfcomm_mcc *mcc = (void *) skb->data; ++ struct rfcomm_mcc *mcc; + u8 type, cr, len; + ++ mcc = skb_pull_data(skb, sizeof(*mcc)); ++ if (!mcc) ++ return -EILSEQ; ++ + cr = __test_cr(mcc->type); + type = __get_mcc_type(mcc->type); + len = __get_mcc_len(mcc->len); + + BT_DBG("%p type 0x%x cr %d", s, type, cr); + +- skb_pull(skb, 2); +- + switch (type) { + case RFCOMM_PN: + rfcomm_recv_pn(s, cr, skb); +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-policy-smq-check-allocation-under-invalidat.patch b/queue-5.15/dm-cache-policy-smq-check-allocation-under-invalidat.patch new file mode 100644 index 0000000000..e08d71364b --- /dev/null +++ b/queue-5.15/dm-cache-policy-smq-check-allocation-under-invalidat.patch @@ -0,0 +1,71 @@ +From 2e14f447082e7619f48366f631a01ca68c121548 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:57:45 +0800 +Subject: dm cache policy smq: check allocation under invalidate lock + +From: Guangshuo Li + +[ Upstream commit d3f0a606b9f278ece8a0df626ded9c4044071235 ] + +commit 2d1f7b65f5de ("dm cache policy smq: fix missing locks in +invalidating cache blocks") added mq->lock around the destructive part of +smq_invalidate_mapping(), but left the e->allocated check outside the +critical section. + +That leaves a check-then-act race. Two concurrent invalidators can both +observe e->allocated as true before either of them takes mq->lock. The +first invalidator that acquires the lock removes the entry from the +queues and hash table and then calls free_entry(), which clears +e->allocated and puts the entry back on the free list. The second +invalidator can then acquire mq->lock and continue with the stale result +of the unlocked check. + +This can corrupt the SMQ queues or hash table by deleting an entry that +is no longer on those structures. It can also hit the allocation check in +free_entry() when the same entry is freed again. + +Move the allocation check under mq->lock so the predicate and the +destructive operations are serialized by the same lock. + +Fixes: 2d1f7b65f5de ("dm cache policy smq: fix missing locks in invalidating cache blocks") +Signed-off-by: Guangshuo Li +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 95b0670c32acda..e5c4d7ff2c655b 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1585,18 +1585,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; +- +- if (!e->allocated) +- return -ENODATA; ++ int r = 0; + + spin_lock_irqsave(&mq->lock, flags); ++ if (!e->allocated) { ++ r = -ENODATA; ++ goto out; ++ } + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ ++out: + spin_unlock_irqrestore(&mq->lock, flags); + +- return 0; ++ return r; + } + + static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) +-- +2.53.0 + diff --git a/queue-5.15/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch b/queue-5.15/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch new file mode 100644 index 0000000000..c66e3fd818 --- /dev/null +++ b/queue-5.15/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch @@ -0,0 +1,53 @@ +From 0c828af00c5388a4285ac63070e62e4d35fd9663 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 19:00:13 +0100 +Subject: drm/imx: Fix three kernel-doc warnings in dcss-scaler.c + +From: Yicong Hui + +[ Upstream commit ae0383e5a9a4b12d68c76c4769857def4665deff ] + +Fix the following W=1 kerneldoc warnings by adding the missing parameter +descriptions for @phase0_identity and @nn_interpolation in +dcss_scaler_filter_design() and @phase0_identity in +dcss_scaler_gaussian_filter() + +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:173 function parameter 'phase0_identity' not described in 'dcss_scaler_gaussian_filter' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'phase0_identity' not described in 'dcss_scaler_filter_design' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'nn_interpolation' not described in 'dcss_scaler_filter_design' + +Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") +Signed-off-by: Yicong Hui +Reviewed-by: Laurentiu Palcu +Link: https://patch.msgid.link/20260406180013.2442096-1-yiconghui@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/dcss/dcss-scaler.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +index 47852b9dd5eaa2..d2a89a99bd71cf 100644 +--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c ++++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +@@ -166,6 +166,7 @@ static int exp_approx_q(int x) + * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter. + * @fc_q: fixed-point cutoff frequency normalized to range [0, 1] + * @use_5_taps: indicates whether to use 5 taps or 7 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output filter coefficients + */ + static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, +@@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, + * @src_length: length of input + * @dst_length: length of output + * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output coefficients ++ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter + */ + static void dcss_scaler_filter_design(int src_length, int dst_length, + bool use_5_taps, bool phase0_identity, +-- +2.53.0 + diff --git a/queue-5.15/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch b/queue-5.15/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch new file mode 100644 index 0000000000..f95e8912ab --- /dev/null +++ b/queue-5.15/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch @@ -0,0 +1,56 @@ +From dd7e6eb119c3ea13d06d48b4c37667e1e343a7af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 07:29:55 +0000 +Subject: ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit() + +From: Eric Dumazet + +[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ] + +The aoe driver (or similar) generates a non-IPv6 packet +(e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() +on a 6LoWPAN interface (configured by the user or test case). + +Since the packet is not IPv6, the 6LoWPAN header_ops->create function +(lowpan_header_create or header_create) returns early without initializing +the lowpan_addr_info structure in the skb headroom. + +In the transmit function (lowpan_xmit), the driver calls lowpan_header +(or setup_header) which unconditionally copies and uses the lowpan_addr_info +from the headroom, which contains uninitialized data. + +Fix this by dropping non IPv6 packets. + +A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit(). + +Fixes: 4dc315e267fe ("ieee802154: 6lowpan: move transmit functionality") +Reported-by: syzbot+f13c19f75e1097abd116@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1fd763.278b5b03.2bcf39.0049.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260603072955.4032221-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ieee802154/6lowpan/tx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c +index 0c07662b44c0ca..4df76ff50699ed 100644 +--- a/net/ieee802154/6lowpan/tx.c ++++ b/net/ieee802154/6lowpan/tx.c +@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) + + pr_debug("package xmit\n"); + ++ if (skb->protocol != htons(ETH_P_IPV6)) { ++ kfree_skb(skb); ++ return NET_XMIT_DROP; ++ } ++ + WARN_ON_ONCE(skb->len > IPV6_MIN_MTU); + + /* We must take a copy of the skb before we modify/replace the ipv6 +-- +2.53.0 + diff --git a/queue-5.15/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch b/queue-5.15/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch new file mode 100644 index 0000000000..22db80ffd1 --- /dev/null +++ b/queue-5.15/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch @@ -0,0 +1,54 @@ +From 29696ef7caf95a71c3f3e7c372d0750e77a5ce51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:15:47 +0000 +Subject: ipv4: restrict IPOPT_SSRR and IPOPT_LSRR options + +From: Eric Dumazet + +[ Upstream commit d3915a1f5a4bc0ac911032903c3c6ab8df9fcc7c ] + +This patch restricts setting Loose Source and Record Route (LSRR) +and Strict Source and Record Route (SSRR) IP options to users +with CAP_NET_RAW capability. + +This prevents unprivileged applications from forcing packets to route +through attacker-controlled nodes to leak TCP ISN and possibly other +protocol information. + +While LSRR and SSRR are commonly filtered in many network environments, +they may still be supported and forwarded along some network paths. + +RFC 7126 (Recommendations on Filtering of IPv4 Packets Containing +IPv4 Options) recommend to drop these options in 4.3 and 4.4. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260602161547.2642155-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_options.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index da1b5038bdfd04..4afdaaab616239 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -543,6 +543,10 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp, + kfree(opt); + return -EINVAL; + } ++ if (opt->opt.srr && !ns_capable(net->user_ns, CAP_NET_RAW)) { ++ kfree(opt); ++ return -EPERM; ++ } + kfree(*optp); + *optp = opt; + return 0; +-- +2.53.0 + diff --git a/queue-5.15/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch b/queue-5.15/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch new file mode 100644 index 0000000000..57ee14e2fb --- /dev/null +++ b/queue-5.15/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch @@ -0,0 +1,107 @@ +From b9869d1ed6d30a63dc017f9a20f9b54491a7754e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 13:18:11 +0300 +Subject: ipv6: mcast: Fix use-after-free when processing MLD queries + +From: Ido Schimmel + +[ Upstream commit 791c91dc7a9dfb2457d5e29b8216a6484b9c4b40 ] + +When processing an MLD query, a pointer to the multicast group address +is retrieved when initially parsing the packet. This pointer is later +dereferenced without being reloaded despite the fact that the skb header +might have been reallocated following the pskb_may_pull() calls, leading +to a use-after-free [1]. + +Fix by copying the multicast group address when the packet is initially +parsed. + +[1] +BUG: KASAN: slab-use-after-free in __mld_query_work (net/ipv6/mcast.c:1512) +Read of size 8 at addr ffff8881154b8e90 by task kworker/4:1/118 + +Workqueue: mld mld_query_work +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +print_address_description.constprop.0 (mm/kasan/report.c:378) +print_report (mm/kasan/report.c:482) +kasan_report (mm/kasan/report.c:595) +__mld_query_work (net/ipv6/mcast.c:1512) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + + +[...] + +Freed by task 118: +kasan_save_stack (mm/kasan/common.c:57) +kasan_save_track (mm/kasan/common.c:78) +kasan_save_free_info (mm/kasan/generic.c:584) +__kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285) +kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566) +pskb_expand_head (net/core/skbuff.c:2335) +__pskb_pull_tail (net/core/skbuff.c:2878 (discriminator 4)) +__mld_query_work (net/ipv6/mcast.c:1495 (discriminator 1)) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + +Fixes: 97300b5fdfe2 ("[MCAST] IPv6: Check packet size when process Multicast") +Reported-by: Leo Lin +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260603101811.612594-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index 77a9f17c816b5d..18a3516abb586e 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1392,9 +1392,9 @@ void igmp6_event_query(struct sk_buff *skb) + static void __mld_query_work(struct sk_buff *skb) + { + struct mld2_query *mlh2 = NULL; +- const struct in6_addr *group; + unsigned long max_delay; + struct inet6_dev *idev; ++ struct in6_addr group; + struct ifmcaddr6 *ma; + struct mld_msg *mld; + int group_type; +@@ -1426,8 +1426,8 @@ static void __mld_query_work(struct sk_buff *skb) + goto kfree_skb; + + mld = (struct mld_msg *)icmp6_hdr(skb); +- group = &mld->mld_mca; +- group_type = ipv6_addr_type(group); ++ group = mld->mld_mca; ++ group_type = ipv6_addr_type(&group); + + if (group_type != IPV6_ADDR_ANY && + !(group_type&IPV6_ADDR_MULTICAST)) +@@ -1477,7 +1477,7 @@ static void __mld_query_work(struct sk_buff *skb) + } + } else { + for_each_mc_mclock(idev, ma) { +- if (!ipv6_addr_equal(group, &ma->mca_addr)) ++ if (!ipv6_addr_equal(&group, &ma->mca_addr)) + continue; + if (ma->mca_flags & MAF_TIMER_RUNNING) { + /* gsquery <- gsquery && mark */ +-- +2.53.0 + diff --git a/queue-5.15/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch b/queue-5.15/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch new file mode 100644 index 0000000000..e4c9177a7e --- /dev/null +++ b/queue-5.15/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch @@ -0,0 +1,127 @@ +From 3c989e329a03c95f1dd4708583193a8e9be00dbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 07:07:44 +0300 +Subject: ipvs: clear the svc scheduler ptr early on edit + +From: Julian Anastasov + +[ Upstream commit 193989cc6d80dd8e0460fb3992e69fa03bf0ff9b ] + +ip_vs_edit_service() while unbinding the old scheduler clears +the svc->scheduler ptr after the scheduler module initiates +RCU callbacks. This can cause packets to use the old +scheduler at the time when svc->sched_data is already freed +after RCU grace period. + +Fix it by clearing the ptr early in ip_vs_unbind_scheduler(), +before the done_service method schedules any RCU callbacks. + +Also, if the new scheduler fails to initialize when replacing +the old scheduler, try to restore the old scheduler while still +returning the error code. + +Link: https://sashiko.dev/#/patchset/20260519015506.634185-1-rosenp%40gmail.com +Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed") +Signed-off-by: Julian Anastasov +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/ip_vs.h | 3 +-- + net/netfilter/ipvs/ip_vs_ctl.c | 13 ++++++++----- + net/netfilter/ipvs/ip_vs_sched.c | 14 +++++++------- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +index 59f8412de45ac4..41e20b7e8e88db 100644 +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -1396,8 +1396,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched); ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc); + struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); + void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); + struct ip_vs_conn * +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index 4c9ef2ae4d6877..0805c9083eaa8f 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -1417,7 +1417,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, + if (ret_hooks >= 0) + ip_vs_unregister_hooks(ipvs, u->af); + if (svc != NULL) { +- ip_vs_unbind_scheduler(svc, sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_service_free(svc); + } + ip_vs_scheduler_put(sched); +@@ -1479,9 +1479,8 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + old_sched = rcu_dereference_protected(svc->scheduler, 1); + if (sched != old_sched) { + if (old_sched) { +- ip_vs_unbind_scheduler(svc, old_sched); +- RCU_INIT_POINTER(svc->scheduler, NULL); +- /* Wait all svc->sched_data users */ ++ ip_vs_unbind_scheduler(svc); ++ /* Wait all svc->scheduler/sched_data users */ + synchronize_rcu(); + } + /* Bind the new scheduler */ +@@ -1489,6 +1488,10 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + ret = ip_vs_bind_scheduler(svc, sched); + if (ret) { + ip_vs_scheduler_put(sched); ++ /* Try to restore the old_sched */ ++ if (old_sched && ++ !ip_vs_bind_scheduler(svc, old_sched)) ++ old_sched = NULL; + goto out; + } + } +@@ -1545,7 +1548,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup) + + /* Unbind scheduler */ + old_sched = rcu_dereference_protected(svc->scheduler, 1); +- ip_vs_unbind_scheduler(svc, old_sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_scheduler_put(old_sched); + + /* Unbind persistence engine, keep svc->pe */ +diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c +index d4903723be7e90..49b2e5d2b2c837 100644 +--- a/net/netfilter/ipvs/ip_vs_sched.c ++++ b/net/netfilter/ipvs/ip_vs_sched.c +@@ -57,19 +57,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, + /* + * Unbind a service with its scheduler + */ +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched) ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc) + { +- struct ip_vs_scheduler *cur_sched; ++ struct ip_vs_scheduler *sched; + +- cur_sched = rcu_dereference_protected(svc->scheduler, 1); +- /* This check proves that old 'sched' was installed */ +- if (!cur_sched) ++ sched = rcu_dereference_protected(svc->scheduler, 1); ++ if (!sched) + return; + ++ /* Reset the scheduler before initiating any RCU callbacks */ ++ rcu_assign_pointer(svc->scheduler, NULL); ++ smp_wmb(); /* paired with smp_rmb() in ip_vs_schedule() */ + if (sched->done_service) + sched->done_service(svc); +- /* svc->scheduler can be set to NULL only by caller */ + } + + +-- +2.53.0 + diff --git a/queue-5.15/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch b/queue-5.15/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch new file mode 100644 index 0000000000..9cea4bf64c --- /dev/null +++ b/queue-5.15/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch @@ -0,0 +1,79 @@ +From 06ded69c972add69866c41b515b86439c680c5d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:00:13 +0800 +Subject: net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr + +From: Yizhou Zhao + +[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ] + +In mrp_pdu_parse_vecattr(), vector attribute events are encoded three +per byte and valen tracks the number of events left to process. + +The parser decrements valen after processing the first and second events +from each event byte, but not after processing the third one. When valen +is exactly a multiple of three, the loop continues after the last valid +event and consumes the next byte as a new event byte, applying a +spurious event to the MRP applicant state. + +Additionally, when valen is zero the parser unconditionally consumes +attrlen bytes as FirstValue and advances the offset, even though per +IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of +zero and no FirstValue or Vector fields. This corrupts the offset for +subsequent PDU parsing. + +Also, when valen exceeds three the loop crosses byte boundaries but +the attribute value is not incremented between the last event of one +byte and the first event of the next. This causes the first event of +the next byte to use the same attribute value as the third event +rather than the next consecutive value. + +Decrement valen after processing the third event, skip FirstValue +consumption when valen is zero, and increment the attribute value at +the end of each loop iteration. + +Fixes: febf018d2234 ("net/802: Implement Multiple Registration Protocol (MRP)") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Link: https://patch.msgid.link/20260603060016.21522-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/mrp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/802/mrp.c b/net/802/mrp.c +index c10a432a5b4351..017839c141841f 100644 +--- a/net/802/mrp.c ++++ b/net/802/mrp.c +@@ -702,6 +702,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) & + MRP_VECATTR_HDR_LEN_MASK); + ++ /* If valen is 0, only a LeaveAllEvent is present; FirstValue and ++ * Vector fields are absent per IEEE 802.1ak. ++ */ ++ if (valen == 0) ++ return 0; ++ + /* The VectorAttribute structure in a PDU carries event information + * about one or more attributes having consecutive values. Only the + * value for the first attribute is contained in the structure. So +@@ -752,6 +758,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + vaevents %= __MRP_VECATTR_EVENT_MAX; + vaevent = vaevents; + mrp_pdu_parse_vecattr_event(app, skb, vaevent); ++ valen--; ++ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue, ++ mrp_cb(skb)->mh->attrlen); + } + return 0; + } +-- +2.53.0 + diff --git a/queue-5.15/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch b/queue-5.15/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch new file mode 100644 index 0000000000..aa1b97a94c --- /dev/null +++ b/queue-5.15/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch @@ -0,0 +1,58 @@ +From 5c7a3d4fef94a9abfb3734d9e32d80a5003cc4bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:31:58 +0800 +Subject: net: garp: fix unsigned integer underflow in garp_pdu_parse_attr + +From: Yizhou Zhao + +[ Upstream commit 16e408e607a94b646fb14a2a98422c6877ae4b3c ] + +The receive-side GARP attribute parser computes dlen with reversed +operands: + + dlen = sizeof(*ga) - ga->len; + +ga->len is the on-wire attribute length and includes the GARP attribute +header. For normal attributes with data, ga->len is larger than +sizeof(*ga), so the subtraction underflows in unsigned arithmetic. + +The resulting value is later passed to garp_attr_lookup(), whose length +argument is u8. After truncation, the parsed data length usually no +longer matches the length stored for locally registered attributes, so +received Join/Leave events are ignored. This breaks the GARP receive path +for common attributes, such as GVRP VLAN registration attributes. + +Compute the data length as the attribute length minus the header length. + +Fixes: eca9ebac651f ("net: Add GARP applicant-only participant") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260527083200.42861-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/garp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/802/garp.c b/net/802/garp.c +index f6012f8e59f005..2c456b362621e6 100644 +--- a/net/802/garp.c ++++ b/net/802/garp.c +@@ -452,7 +452,7 @@ static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); +- dlen = sizeof(*ga) - ga->len; ++ dlen = ga->len - sizeof(*ga); + + if (attrtype > app->app->maxattr) + return 0; +-- +2.53.0 + diff --git a/queue-5.15/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch b/queue-5.15/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch new file mode 100644 index 0000000000..7875e4dbbd --- /dev/null +++ b/queue-5.15/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch @@ -0,0 +1,99 @@ +From 5dfabbaf1f62630af1161648744ceab79a790141 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 21:03:00 +0000 +Subject: net: lan743x: permit VLAN-tagged packets up to configured MTU + +From: David Thompson + +[ Upstream commit 8173d22b211f615015f7b35f48ab11a6dd78dc99 ] + +VLAN-tagged interfaces on lan743x devices were previously unreachable via +SSH and failed to respond to large ping packets (e.g. "ping -s 1469" given +MTU=1500). In these scenarios, "ethtool -S" reports non-zero "RX Oversize +Frame Errors". According to Microchip AN2948, the MAC_RX FSE (VLAN field +size enforcement) bit determines whether frames with VLAN tags exceeding +the base MTU plus tag length are discarded. + +The driver must set the MAC_RX.FSE bit before setting MAC_RX.RXEN to allow +VLAN-tagged frames up to the interface MTU, preventing them from being +treated as oversized. As a result, both the base and VLAN-tagged interfaces +can use the same MTU without receive errors. + +Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") +Signed-off-by: David Thompson +Reviewed-by: Thangaraj Samynathan +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz # lan7430 on arm64 (RevPi +Link: https://patch.msgid.link/20260529210300.433135-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 32 +++++++++++++++++++ + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 49d40685136d46..8db83741aaa570 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -792,6 +792,36 @@ static void lan743x_mac_set_address(struct lan743x_adapter *adapter, + "MAC address set to %pM\n", addr); + } + ++static void lan743x_mac_rx_enable_fse(struct lan743x_adapter *adapter) ++{ ++ u32 mac_rx; ++ bool rxen; ++ ++ mac_rx = lan743x_csr_read(adapter, MAC_RX); ++ if (mac_rx & MAC_RX_FSE_) ++ return; ++ ++ rxen = mac_rx & MAC_RX_RXEN_; ++ if (rxen) { ++ mac_rx &= ~MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, ++ 1, 1000, 20000, 100); ++ } ++ ++ /* Per AN2948, hardware prevents modification of the FSE bit while the ++ * MAC receiver is enabled (RXEN bit set). Use separate register write ++ * to assert the FSE bit before enabling the RXEN bit in MAC_RX ++ */ ++ mac_rx |= MAC_RX_FSE_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ ++ if (rxen) { ++ mac_rx |= MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ } ++} ++ + static int lan743x_mac_init(struct lan743x_adapter *adapter) + { + bool mac_address_valid = true; +@@ -831,6 +861,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter) + lan743x_mac_set_address(adapter, adapter->mac_address); + eth_hw_addr_set(netdev, adapter->mac_address); + ++ lan743x_mac_rx_enable_fse(adapter); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index a1226ab0fb4217..40351d38299aac 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -118,6 +118,7 @@ + #define MAC_RX (0x104) + #define MAC_RX_MAX_SIZE_SHIFT_ (16) + #define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) ++#define MAC_RX_FSE_ BIT(2) + #define MAC_RX_RXD_ BIT(1) + #define MAC_RX_RXEN_ BIT(0) + +-- +2.53.0 + diff --git a/queue-5.15/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch b/queue-5.15/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch new file mode 100644 index 0000000000..289575c5c0 --- /dev/null +++ b/queue-5.15/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch @@ -0,0 +1,106 @@ +From cfb7a199cf50630100b0a7517d861e724429c06e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 12:08:12 -0400 +Subject: net/sched: act_api: use RCU with deferred freeing for action + lifecycle + +From: Jamal Hadi Salim + +[ Upstream commit 5057e1aca011e51ef51498c940ef96f3d3e8a305 ] + +When NEWTFILTER and DELFILTER are run concurrently it is possible to create a +race with an associated action. + +Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: + + 0: mutex_lock() <-- holds the idr lock + 0: rcu_read_lock() + 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) + 0: mutex_unlock() <-- releases the idr lock + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) <-- Action removed from IDR + 1: mutex_unlock() <-- mutex released allowing us to delete the action + 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory + +This patch fixes the race condition between NEWTFILTER and DELFILTER by +adding struct rcu_head to tc_action used in the deferral and introducing a +call_rcu() in the delete path to defer the final kfree(). + +Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +but also modernization/simplification to directly use kfree_rcu(). + +Let's illustrate the new restored code path: + + 0: rcu_read_lock() + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) + 1: mutex_unlock() + 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period + 0: p = idr_find(idr, index) + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 + 1: rcu_read_unlock() <-- release so freeing can run after grace period + +After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. +CPU0's subsequent idr_find() will return NULL, and even if it still held a +stale pointer, the immediate kfree() is now deferred until after the RCU grace +period, so no UAF can occur. + +Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +Suggested-by: Jakub Kicinski +Reported-by: Kyle Zeng +Tested-by: Victor Nogueira +Tested-by: syzbot@syzkaller.appspotmail.com +Signed-off-by: Jamal Hadi Salim +Tested-by: Kyle Zeng +Reviewed-by: Pedro Tammela +Reviewed-by: Eric Dumazet +Reviewed-by: Victor Nogueira +Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/act_api.h | 1 + + net/sched/act_api.c | 7 +------ + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/net/act_api.h b/include/net/act_api.h +index ab67d62ff31784..29d5dc201b5cc5 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -41,6 +41,7 @@ struct tc_action { + struct tc_cookie __rcu *act_cookie; + struct tcf_chain __rcu *goto_chain; + u32 tcfa_flags; ++ struct rcu_head tcfa_rcu; + u8 hw_stats; + u8 used_hw_stats; + bool used_hw_stats_valid; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index 0b4deb33bdf7ad..20944a2e162e7f 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -109,11 +109,6 @@ struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action, + } + EXPORT_SYMBOL(tcf_action_set_ctrlact); + +-/* XXX: For standalone actions, we don't need a RCU grace period either, because +- * actions are always connected to filters and filters are already destroyed in +- * RCU callbacks, so after a RCU grace period actions are already disconnected +- * from filters. Readers later can not find us. +- */ + static void free_tcf(struct tc_action *p) + { + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); +@@ -126,7 +121,7 @@ static void free_tcf(struct tc_action *p) + if (chain) + tcf_chain_put_by_act(chain); + +- kfree(p); ++ kfree_rcu(p, tcfa_rcu); + } + + static void tcf_action_cleanup(struct tc_action *p) +-- +2.53.0 + diff --git a/queue-5.15/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch b/queue-5.15/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch new file mode 100644 index 0000000000..139e7f1acc --- /dev/null +++ b/queue-5.15/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch @@ -0,0 +1,58 @@ +From 5a65db59beda62bcac8ad1f3f3f905bcbd4e6c1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 12:29:10 +0000 +Subject: netfilter: bridge: make ebt_snat ARP rewrite writable + +From: Yiming Qian + +[ Upstream commit 67ba971ae02514d85818fe0c32549ab4bfa3bf49 ] + +The ebtables SNAT target keeps the Ethernet source address rewrite +behind skb_ensure_writable(skb, 0). This is intentional: at the bridge +ebtables hooks the Ethernet header is addressed through +skb_mac_header()/eth_hdr(), while skb->data points at the Ethernet +payload. Asking skb_ensure_writable() for ETH_HLEN bytes would check +the payload, not the Ethernet header, and would reintroduce the small +packet regression fixed by commit 63137bc5882a. + +However, the optional ARP sender hardware address rewrite is different. +It writes through skb_store_bits() at an offset relative to skb->data: + + skb_store_bits(skb, sizeof(struct arphdr), info->mac, ETH_ALEN) + +skb_header_pointer() only safely reads the ARP header; it does not make +the later sender hardware address range writable. If that range is +still held in a nonlinear skb fragment backed by a splice-imported file +page, skb_store_bits() maps the frag page and copies the new MAC address +directly into it. + +Ensure the ARP SHA range is writable before reading the ARP header and +before calling skb_store_bits(). + +Fixes: 63137bc5882a ("netfilter: ebtables: Fixes dropping of small packets in bridge nat") +Reported-by: Yiming Qian +Signed-off-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_snat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c +index 7dfbcdfc30e5d2..c9e229af0366b8 100644 +--- a/net/bridge/netfilter/ebt_snat.c ++++ b/net/bridge/netfilter/ebt_snat.c +@@ -31,6 +31,9 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) + const struct arphdr *ap; + struct arphdr _ah; + ++ if (skb_ensure_writable(skb, sizeof(_ah) + ETH_ALEN)) ++ return EBT_DROP; ++ + ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch b/queue-5.15/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch new file mode 100644 index 0000000000..4e6b513a83 --- /dev/null +++ b/queue-5.15/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch @@ -0,0 +1,50 @@ +From d0a361e8d7b9c43fb4d1e4242c3b30007a52cd9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:20:19 +0200 +Subject: netfilter: conntrack_irc: fix possible out-of-bounds read + +From: Florian Westphal + +[ Upstream commit 66eba0ffce3b7e11449946b4cbbef8ea36112f56 ] + +When parsing fails after we've matched the command string we +should bail out instead of trying to match a different command. + +This helper should be deprecated, given prevalence of TLS I doubt it has +any relevance in 2026. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Closes: https://sashiko.dev/#/patchset/20260525182924.28456-1-fw%40strlen.de +Signed-off-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_irc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c +index 159e1e4441a433..7a0c645a11c390 100644 +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -202,7 +202,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + pr_debug("unable to parse dcc command\n"); +- continue; ++ goto out; + } + + pr_debug("DCC bound ip/port: %pI4:%u\n", +@@ -216,7 +216,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); +- continue; ++ goto out; + } + + exp = nf_ct_expect_alloc(ct); +-- +2.53.0 + diff --git a/queue-5.15/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch b/queue-5.15/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch new file mode 100644 index 0000000000..7702d4c85e --- /dev/null +++ b/queue-5.15/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch @@ -0,0 +1,113 @@ +From fc549900783654782236c2d05a99c966c30c31f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 23:58:31 +0200 +Subject: netfilter: synproxy: add mutex to guard hook reference counting + +From: Fernando Fernandez Mancera + +[ Upstream commit 2fcba19caaeb2a33017459d3430f057967bb91b6 ] + +As the synproxy infrastructure register netfilter hooks on-demand when a +user adds the first iptables target or nftables expression, if done +concurrently they can race each other. + +Introduce a mutex to serialize the refcount control blocks access from +both frontends. While a per namespace mutex might be more efficient, it +is not needed for target/expression like SYNPROXY. + +Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index cdb2c3e23af7ee..91d3e3eea1be0b 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -21,6 +21,8 @@ + #include + #include + ++static DEFINE_MUTEX(synproxy_mutex); ++ + unsigned int synproxy_net_id; + EXPORT_SYMBOL_GPL(synproxy_net_id); + +@@ -790,26 +792,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = { + + int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref4 == 0) { + err = nf_register_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref4++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init); + + void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref4--; + if (snet->hook_ref4 == 0) + nf_unregister_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini); + +@@ -1214,27 +1221,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = { + int + nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref6 == 0) { + err = nf_register_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref6++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init); + + void + nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref6--; + if (snet->hook_ref6 == 0) + nf_unregister_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini); + #endif /* CONFIG_IPV6 */ +-- +2.53.0 + diff --git a/queue-5.15/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch b/queue-5.15/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..e8ace3c2ae --- /dev/null +++ b/queue-5.15/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch @@ -0,0 +1,41 @@ +From 7ce66bd586341862d360969ad74af0b1b71ac2e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 12:47:17 +0200 +Subject: netfilter: xt_NFQUEUE: prefer raw_smp_processor_id + +From: Fernando Fernandez Mancera + +[ Upstream commit c6c5327dd18bec1e1bbf139b2cf5ae53608a9d30 ] + +With PREEMPT_RCU this triggers a splat because smp_processor_id() can be +preempted while inside a RCU critical section. If xt_NFQUEUE target is +invoked via nft_compat_eval() path, we are inside a RCU critical +section. + +Just use the raw version instead. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_NFQUEUE.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index 466da23e36ff47..b32d153e3a1862 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -91,7 +91,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) + + if (info->queues_total > 1) { + if (info->flags & NFQ_FLAG_CPU_FANOUT) { +- int cpu = smp_processor_id(); ++ int cpu = raw_smp_processor_id(); + + queue = info->queuenum + cpu % info->queues_total; + } else { +-- +2.53.0 + diff --git a/queue-5.15/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch b/queue-5.15/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch new file mode 100644 index 0000000000..f37834b2e9 --- /dev/null +++ b/queue-5.15/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch @@ -0,0 +1,58 @@ +From 61dc5c7f56fe563e757944560e510bc00e3d13e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 16:03:20 +0200 +Subject: pcnet32: stop holding device spin lock during napi_complete_done + +From: Oscar Maes + +[ Upstream commit 73bf3cca7de6a73f53b6a52dc3b1c82ae5667a4d ] + +napi_complete_done may call gro_flush_normal (though not currently, as GRO +is unsupported at the moment), which may result in packet TX. This will +eventually result in calling pcnet32_start_xmit - resulting in a deadlock +while trying to re-acquire the already locked spin lock. + +It is safe to split the spinlock block into two, because the hardware +registers are still protected from concurrent access, and the two blocks +perform unrelated operations that don't need to happen atomically. + +Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()") +Reviewed-by: Andrew Lunn +Signed-off-by: Oscar Maes +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/pcnet32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c +index 70d76fdb9f569d..58a59b2d70cf2b 100644 +--- a/drivers/net/ethernet/amd/pcnet32.c ++++ b/drivers/net/ethernet/amd/pcnet32.c +@@ -1399,8 +1399,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + pcnet32_restart(dev, CSR0_START); + netif_wake_queue(dev); + } ++ spin_unlock_irqrestore(&lp->lock, flags); + + if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a->read_csr(ioaddr, CSR3); + val &= 0x00ff; +@@ -1408,9 +1410,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + + /* Set interrupt enable. */ + lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN); ++ spin_unlock_irqrestore(&lp->lock, flags); + } + +- spin_unlock_irqrestore(&lp->lock, flags); + return work_done; + } + +-- +2.53.0 + diff --git a/queue-5.15/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch b/queue-5.15/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch new file mode 100644 index 0000000000..2ac5fe13e5 --- /dev/null +++ b/queue-5.15/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch @@ -0,0 +1,87 @@ +From 149b109f714a30308d37d39c3184ac87704eecea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:11:44 -0400 +Subject: sctp: purge outqueue on stale COOKIE-ECHO handling + +From: Xin Long + +[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ] + +sctp_stream_update() is only invoked when the association is moved into +COOKIE_WAIT during association setup/reconfiguration. In this path, the +outbound stream scheduler state (stream->out_curr) is expected to be +clean, since no user data should have been transmitted yet unless the +state machine has already partially progressed. + +However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a +Stale Cookie ERROR is received, the association is rolled back from +COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already +have been queued and even bundled with the COOKIE-ECHO chunk. + +During the rollback, sctp_stream_update() frees the old stream table +and installs a new one, but it does not invalidate stream->out_curr. +As a result, out_curr may still point to a freed sctp_stream_out +entry from the previous stream state. + +Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on +stream->out_curr->ext, which can lead to use-after-free once the old +stream state has been released via sctp_stream_free(). + +This results in crashes such as (reported by Yuqi): + + BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140 + Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312 + CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted + 7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full) + sctp_sched_fcfs_dequeue+0x13a/0x140 + sctp_outq_flush+0x1603/0x33e0 + sctp_do_sm+0x31c9/0x5d30 + sctp_assoc_bh_rcv+0x392/0x6f0 + sctp_inq_push+0x1db/0x270 + sctp_rcv+0x138d/0x3c10 + +Fix this by fully purging the association outqueue when handling the +Stale Cookie case. This ensures all pending transmit and retransmit +state is dropped, and any scheduler cached pointers are invalidated, +making it safe to rebuild stream state during COOKIE_WAIT restart. + +Updating only stream->out_curr would be insufficient, since queued +and retransmittable data would still reference the old stream state and +trigger later use-after-free in dequeue paths. + +Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Reported-by: Yuqi Xu +Reported-by: Ren Wei +Signed-off-by: Xin Long +Link: https://patch.msgid.link/94318159b9052907a6cbb7256aee8b5f8dfbfccb.1780510304.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 2f9f24b1885208..3ca6b7b81124ff 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2583,11 +2583,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + +- /* If we've sent any data bundled with COOKIE-ECHO we will need to +- * resend +- */ +- sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, +- SCTP_TRANSPORT(asoc->peer.primary_path)); ++ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index 01ae3f292b..7ac33f63f3 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -144,3 +144,27 @@ bpf-free-reuseport-cbpf-prog-after-rcu-grace-period.patch usb-serial-mct_u232-fix-memory-corruption-with-small.patch compiler-clang.h-add-__diag-infrastructure-for-clang.patch disable-wattribute-alias-for-clang-23-and-newer.patch +tee-optee-prevent-use-after-free-when-the-client-exi.patch +netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch +ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch +netfilter-synproxy-add-mutex-to-guard-hook-reference.patch +netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch +netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch +dm-cache-policy-smq-check-allocation-under-invalidat.patch +net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch +6lowpan-fix-off-by-one-in-multicast-context-address-.patch +drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch +pcnet32-stop-holding-device-spin-lock-during-napi_co.patch +net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch +net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch +bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch +bluetooth-mgmt-validate-advertising-tlv-before-type-.patch +bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch +bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch +bluetooth-bnep-reject-short-frames-before-parsing.patch +bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch +ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch +ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch +ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch +net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch +sctp-purge-outqueue-on-stale-cookie-echo-handling.patch diff --git a/queue-5.15/tee-optee-prevent-use-after-free-when-the-client-exi.patch b/queue-5.15/tee-optee-prevent-use-after-free-when-the-client-exi.patch new file mode 100644 index 0000000000..9537929c89 --- /dev/null +++ b/queue-5.15/tee-optee-prevent-use-after-free-when-the-client-exi.patch @@ -0,0 +1,287 @@ +From 3fbd7242b71fd460f8688becdd59db0e7a62fb07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:24:06 -0800 +Subject: tee: optee: prevent use-after-free when the client exits before the + supplicant + +From: Amirreza Zarrabi + +[ Upstream commit 387a926ee166814611acecb960207fe2f3c4fd3e ] + +Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the +client wait as killable so it can be interrupted during shutdown or +after a supplicant crash. This changes the original lifetime expectations: +the client task can now terminate while the supplicant is still processing +its request. + +If the client exits first it removes the request from its queue and +kfree()s it, while the request ID remains in supp->idr. A subsequent +lookup on the supplicant path then dereferences freed memory, leading to +a use-after-free. + +Serialise access to the request with supp->mutex: + + * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while + looking up and touching the request. + * Let optee_supp_thrd_req() notice that the client has terminated and + signal optee_supp_send() accordingly. + +With these changes the request cannot be freed while the supplicant still +has a reference, eliminating the race. + +Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") +Signed-off-by: Amirreza Zarrabi +Tested-by: Ox Yeh +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/supp.c | 107 +++++++++++++++++++++++++++------------ + 1 file changed, 74 insertions(+), 33 deletions(-) + +diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c +index d0f397c9024201..2386bbd38ce78b 100644 +--- a/drivers/tee/optee/supp.c ++++ b/drivers/tee/optee/supp.c +@@ -10,7 +10,11 @@ + struct optee_supp_req { + struct list_head link; + ++ int id; ++ + bool in_queue; ++ bool processed; ++ + u32 func; + u32 ret; + size_t num_params; +@@ -19,6 +23,9 @@ struct optee_supp_req { + struct completion c; + }; + ++/* It is temporary request used for revoked pending request in supp->idr. */ ++#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) ++ + void optee_supp_init(struct optee_supp *supp) + { + memset(supp, 0, sizeof(*supp)); +@@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) + { + int id; + struct optee_supp_req *req; +- struct optee_supp_req *req_tmp; + + mutex_lock(&supp->mutex); + +- /* Abort all request retrieved by supplicant */ ++ /* Abort all request */ + idr_for_each_entry(&supp->idr, req, id) { + idr_remove(&supp->idr, id); +- req->ret = TEEC_ERROR_COMMUNICATION; +- complete(&req->c); +- } ++ /* Skip if request was already marked invalid */ ++ if (IS_ERR(req)) ++ continue; + +- /* Abort all queued requests */ +- list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { +- list_del(&req->link); +- req->in_queue = false; ++ /* For queued requests where supplicant has not seen it */ ++ if (req->in_queue) { ++ list_del(&req->link); ++ req->in_queue = false; ++ } ++ ++ req->processed = true; + req->ret = TEEC_ERROR_COMMUNICATION; + complete(&req->c); + } +@@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + + /* Insert the request in the request list */ + mutex_lock(&supp->mutex); ++ req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); ++ if (req->id < 0) { ++ mutex_unlock(&supp->mutex); ++ kfree(req); ++ return TEEC_ERROR_OUT_OF_MEMORY; ++ } ++ + list_add_tail(&req->link, &supp->reqs); + req->in_queue = true; ++ req->processed = false; + mutex_unlock(&supp->mutex); + + /* Tell an eventual waiter there's a new request */ +@@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + if (wait_for_completion_killable(&req->c)) { + mutex_lock(&supp->mutex); + if (req->in_queue) { ++ /* Supplicant has not seen this request yet. */ ++ idr_remove(&supp->idr, req->id); + list_del(&req->link); + req->in_queue = false; ++ ++ ret = TEEC_ERROR_COMMUNICATION; ++ } else if (req->processed) { ++ /* ++ * Supplicant has processed this request. Ignore the ++ * kill signal for now and submit the result. req is not ++ * in supp->reqs (removed by supp_pop_entry()) nor in ++ * supp->idr (removed by supp_pop_req()). ++ */ ++ ret = req->ret; ++ } else { ++ /* ++ * Supplicant is in the middle of processing this ++ * request. Replace req with INVALID_REQ_PTR so that ++ * the ID remains busy, causing optee_supp_send() to ++ * fail on the next call to supp_pop_req() with this ID. ++ */ ++ idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); ++ ret = TEEC_ERROR_COMMUNICATION; + } ++ + mutex_unlock(&supp->mutex); +- req->ret = TEEC_ERROR_COMMUNICATION; ++ } else { ++ ret = req->ret; + } + +- ret = req->ret; + kfree(req); + + return ret; + } + + static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, +- int num_params, int *id) ++ int num_params) + { + struct optee_supp_req *req; + +@@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, + return ERR_PTR(-EINVAL); + } + +- *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); +- if (*id < 0) +- return ERR_PTR(-ENOMEM); +- + list_del(&req->link); + req->in_queue = false; + +@@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + struct optee_supp_req *req = NULL; +- int id; + size_t num_meta; + int rc; + +@@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + + while (true) { + mutex_lock(&supp->mutex); +- req = supp_pop_entry(supp, *num_params - num_meta, &id); ++ req = supp_pop_entry(supp, *num_params - num_meta); ++ if (req) ++ break; /* Keep mutex held. */ + mutex_unlock(&supp->mutex); + +- if (req) { +- if (IS_ERR(req)) +- return PTR_ERR(req); +- break; +- } +- + /* + * If we didn't get a request we'll block in + * wait_for_completion() to avoid needless spinning. +@@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + return -ERESTARTSYS; + } + ++ /* supp->mutex held and req != NULL. */ ++ ++ if (IS_ERR(req)) { ++ mutex_unlock(&supp->mutex); ++ return PTR_ERR(req); ++ } ++ + if (num_meta) { + /* + * tee-supplicant support meta parameters -> requsts can be +@@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + */ + param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; +- param->u.value.a = id; ++ param->u.value.a = req->id; + param->u.value.b = 0; + param->u.value.c = 0; + } else { +- mutex_lock(&supp->mutex); +- supp->req_id = id; +- mutex_unlock(&supp->mutex); ++ supp->req_id = req->id; + } + + *func = req->func; +@@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + ++ mutex_unlock(&supp->mutex); + return 0; + } + +@@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, + if (!req) + return ERR_PTR(-ENOENT); + ++ /* optee_supp_thrd_req() already returned to optee. */ ++ if (IS_ERR(req)) ++ goto failed_req; ++ + if ((num_params - nm) != req->num_params) + return ERR_PTR(-EINVAL); + ++ *num_meta = nm; ++failed_req: + idr_remove(&supp->idr, id); + supp->req_id = -1; +- *num_meta = nm; + + return req; + } +@@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + + mutex_lock(&supp->mutex); + req = supp_pop_req(supp, num_params, param, &num_meta); +- mutex_unlock(&supp->mutex); +- + if (IS_ERR(req)) { +- /* Something is wrong, let supplicant restart. */ ++ mutex_unlock(&supp->mutex); ++ /* Something is wrong, let supplicant handel it. */ + return PTR_ERR(req); + } + +@@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + } + } + req->ret = ret; +- ++ req->processed = true; + /* Let the requesting thread continue */ + complete(&req->c); ++ mutex_unlock(&supp->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/6lowpan-fix-off-by-one-in-multicast-context-address-.patch b/queue-6.1/6lowpan-fix-off-by-one-in-multicast-context-address-.patch new file mode 100644 index 0000000000..272688f014 --- /dev/null +++ b/queue-6.1/6lowpan-fix-off-by-one-in-multicast-context-address-.patch @@ -0,0 +1,67 @@ +From 8a4b969af3cec9a03083f52d2a6a12c9d56e4b3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:18:01 +0800 +Subject: 6lowpan: fix off-by-one in multicast context address compression + +From: Yizhou Zhao + +[ Upstream commit 2a58899d11009bffc7b4b32a571858f381121837 ] + +The second memcpy in lowpan_iphc_mcast_ctx_addr_compress() uses +&data[1] as destination and &ipaddr->s6_addr[11] as source, but +both should be offset by one: &data[2] and &ipaddr->s6_addr[12] +respectively. + +This off-by-one has two consequences: +1. data[1] is overwritten with s6_addr[11], corrupting the RIID + field in the compressed multicast address +2. data[5] is never written, so uninitialized kernel stack memory + is transmitted over the network via lowpan_push_hc_data(), + leaking kernel stack contents + +The correct inline data layout must match what the decompression +function lowpan_uncompress_multicast_ctx_daddr() expects: + data[0..1] = s6_addr[1..2] (flags/scope + RIID) + data[2..5] = s6_addr[12..15] (group ID) + +Also zero-initialize the data array as a defensive measure against +similar bugs in the future. + +Fixes: 5609c185f24d ("6lowpan: iphc: add support for stateful compression") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Acked-by: Alexander Aring +Link: https://patch.msgid.link/20260527081806.42747-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/6lowpan/iphc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c +index 52fad5dad9f715..d762c49e722fae 100644 +--- a/net/6lowpan/iphc.c ++++ b/net/6lowpan/iphc.c +@@ -1086,12 +1086,12 @@ static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, + const struct lowpan_iphc_ctx *ctx, + const struct in6_addr *ipaddr) + { +- u8 data[6]; ++ u8 data[6] = {}; + + /* flags/scope, reserved (RIID) */ + memcpy(data, &ipaddr->s6_addr[1], 2); + /* group ID */ +- memcpy(&data[1], &ipaddr->s6_addr[11], 4); ++ memcpy(&data[2], &ipaddr->s6_addr[12], 4); + lowpan_push_hc_data(hc_ptr, data, 6); + + return LOWPAN_IPHC_DAM_00; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch b/queue-6.1/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch new file mode 100644 index 0000000000..fd7731f075 --- /dev/null +++ b/queue-6.1/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch @@ -0,0 +1,71 @@ +From 7c4397588a208c6d9440401b3b9a97c27cc695ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:39:53 +0800 +Subject: Bluetooth: bnep: fix incorrect length parsing in bnep_rx_frame() + extension handling + +From: Dudu Lu + +[ Upstream commit 72b8deccff17a7644e0367e1aaf1a36cfb014324 ] + +In bnep_rx_frame(), the BNEP_FILTER_NET_TYPE_SET and +BNEP_FILTER_MULTI_ADDR_SET extension header parsing has two bugs: + +1) The 2-byte length field is read with *(u16 *)(skb->data + 1), which + performs a native-endian read. The BNEP protocol specifies this field + in big-endian (network byte order), and the same file correctly uses + get_unaligned_be16() for the identical fields in + bnep_ctrl_set_netfilter() and bnep_ctrl_set_mcfilter(). + +2) The length is multiplied by 2, but unlike BNEP_SETUP_CONN_REQ where + the length byte counts UUID pairs (requiring * 2 for two UUIDs per + entry), the filter extension length field already represents the total + data size in bytes. This is confirmed by bnep_ctrl_set_netfilter() + which reads the same field as a byte count and divides by 4 to get + the number of filter entries. + + The bogus * 2 means skb_pull advances twice as far as it should, + either dropping valid data from the next header or causing the pull + to fail entirely when the doubled length exceeds the remaining skb. + +Fix by splitting the pull into two steps: first use skb_pull_data() to +safely pull and validate the 3-byte fixed header (ctrl type + length), +then pull the variable-length data using the properly decoded length. + +Fixes: bf8b9a9cb77b ("Bluetooth: bnep: Add support to extended headers of control frames") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index e125afe573fcf2..9d804b08de88e0 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -330,11 +330,18 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + goto badframe; + break; + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: +- /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */ +- if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2)) ++ case BNEP_FILTER_NET_TYPE_SET: { ++ u8 *hdr; ++ ++ /* Pull ctrl type (1 b) + len (2 b) */ ++ hdr = skb_pull_data(skb, 3); ++ if (!hdr) ++ goto badframe; ++ /* Pull data (len bytes); length is big-endian */ ++ if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) + goto badframe; + break; ++ } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-bnep-reject-short-frames-before-parsing.patch b/queue-6.1/bluetooth-bnep-reject-short-frames-before-parsing.patch new file mode 100644 index 0000000000..2d29a6144b --- /dev/null +++ b/queue-6.1/bluetooth-bnep-reject-short-frames-before-parsing.patch @@ -0,0 +1,170 @@ +From 70401fc75bec46315758eed90c9c47837af2b376 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 11:22:09 +0800 +Subject: Bluetooth: bnep: reject short frames before parsing + +From: Zhang Cen + +[ Upstream commit 6770d3a8acdf9151769180cc3710346c4cfbe6f0 ] + +A BNEP peer can send a short BNEP SDU. bnep_rx_frame() reads the +packet type byte immediately and, for control packets, reads the control +opcode and setup UUID-size byte before proving that those bytes are +present. bnep_rx_control() also dereferences the control opcode without +rejecting an empty control payload. + +Use skb_pull_data() for the fixed fields in bnep_rx_frame() so a NULL +return gates each dereference. Split the control handler so the frame +path can pass an opcode that has already been pulled, and keep the +byte-buffer wrapper for extension control payloads. + +For BNEP_SETUP_CONN_REQ, name the UUID-size byte before pulling the +setup payload. struct bnep_setup_conn_req carries destination and source +service UUIDs after that byte, each uuid_size bytes, so the parser now +documents that tuple explicitly instead of leaving the pull length as an +opaque multiplication. + +Validation reproduced this kernel report: +KASAN slab-out-of-bounds in bnep_rx_frame.isra.0+0x130c/0x1790 +The buggy address belongs to the object at ffff88800c0f7908 which belongs +to the cache kmalloc-8 of size 8 +The buggy address is located 0 bytes to the right of allocated 1-byte +region [ffff88800c0f7908, ffff88800c0f7909) +Read of size 1 +Call trace: + dump_stack_lvl+0xb3/0x140 (?:?) + print_address_description+0x57/0x3a0 (?:?) + bnep_rx_frame+0x130c/0x1790 (net/bluetooth/bnep/core.c:306) + print_report+0xb9/0x2b0 (?:?) + __virt_addr_valid+0x1ba/0x3a0 (?:?) + srso_alias_return_thunk+0x5/0xfbef5 (?:?) + kasan_addr_to_slab+0x21/0x60 (?:?) + kasan_report+0xe0/0x110 (?:?) + process_one_work+0xfce/0x17e0 (kernel/workqueue.c:3200) + worker_thread+0x65c/0xe40 (?:?) + __kthread_parkme+0x184/0x230 (?:?) + kthread+0x35e/0x470 (?:?) + _raw_spin_unlock_irq+0x28/0x50 (?:?) + ret_from_fork+0x586/0x870 (?:?) + __switch_to+0x74f/0xdc0 (?:?) + ret_from_fork_asm+0x1a/0x30 (?:?) + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 57 ++++++++++++++++++++++++--------------- + 1 file changed, 36 insertions(+), 21 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index 9d804b08de88e0..45d0f84652fc60 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -206,14 +206,11 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) + return 0; + } + +-static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++static int bnep_rx_control_cmd(struct bnep_session *s, u8 cmd, void *data, ++ int len) + { +- u8 cmd = *(u8 *)data; + int err = 0; + +- data++; +- len--; +- + switch (cmd) { + case BNEP_CMD_NOT_UNDERSTOOD: + case BNEP_SETUP_CONN_RSP: +@@ -254,6 +251,14 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) + return err; + } + ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ if (len < 1) ++ return -EILSEQ; ++ ++ return bnep_rx_control_cmd(s, *(u8 *)data, data + 1, len - 1); ++} ++ + static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) + { + struct bnep_ext_hdr *h; +@@ -299,19 +304,26 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + { + struct net_device *dev = s->dev; + struct sk_buff *nskb; ++ u8 *data; + u8 type, ctrl_type; + + dev->stats.rx_bytes += skb->len; + +- type = *(u8 *) skb->data; +- skb_pull(skb, 1); +- ctrl_type = *(u8 *)skb->data; ++ data = skb_pull_data(skb, sizeof(type)); ++ if (!data) ++ goto badframe; ++ type = *data; + + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) + goto badframe; + + if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { +- if (bnep_rx_control(s, skb->data, skb->len) < 0) { ++ data = skb_pull_data(skb, sizeof(ctrl_type)); ++ if (!data) ++ goto badframe; ++ ctrl_type = *data; ++ ++ if (bnep_rx_control_cmd(s, ctrl_type, skb->data, skb->len) < 0) { + dev->stats.tx_errors++; + kfree_skb(skb); + return 0; +@@ -324,24 +336,27 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + + /* Verify and pull ctrl message since it's already processed */ + switch (ctrl_type) { +- case BNEP_SETUP_CONN_REQ: +- /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */ +- if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2)) ++ case BNEP_SETUP_CONN_REQ: { ++ u8 uuid_size; ++ ++ /* Pull uuid_size and the dst/src service UUIDs. */ ++ data = skb_pull_data(skb, sizeof(uuid_size)); ++ if (!data) ++ goto badframe; ++ uuid_size = *data; ++ if (!skb_pull(skb, uuid_size + uuid_size)) + goto badframe; + break; ++ } + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: { +- u8 *hdr; +- +- /* Pull ctrl type (1 b) + len (2 b) */ +- hdr = skb_pull_data(skb, 3); +- if (!hdr) ++ case BNEP_FILTER_NET_TYPE_SET: ++ /* Pull: len (2 b), data (len bytes) */ ++ data = skb_pull_data(skb, sizeof(u16)); ++ if (!data) + goto badframe; +- /* Pull data (len bytes); length is big-endian */ +- if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) ++ if (!skb_pull(skb, get_unaligned_be16(data))) + goto badframe; + break; +- } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch b/queue-6.1/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch new file mode 100644 index 0000000000..c5344df6e1 --- /dev/null +++ b/queue-6.1/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch @@ -0,0 +1,58 @@ +From f0b025f60ade21d989143d75ac3a0a75df167365 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 08:54:26 +0530 +Subject: Bluetooth: fix memory leak in error path of hci_alloc_dev() + +From: Bharath Reddy + +[ Upstream commit 37b3009bf5976e8ab77c8b9a9bc3bbd7ff49e37f ] + +Early failures in Bluetooth HCI UART configuration leak SRCU percpu +memory. + +When device initialization fails before hci_register_dev() completes, +the HCI_UNREGISTER flag is never set. As a result, when the device +reference count reaches zero, bt_host_release() evaluates this flag as +false and falls back to a direct kfree(hdev). + +Because hci_release_dev() is bypassed, the SRCU struct initialized +early in hci_alloc_dev() is never cleaned up, resulting in a leak of +percpu memory. + +Fix the leak by explicitly calling cleanup_srcu_struct() in the +fallback (unregistered) branch of bt_host_release() before freeing +the device. + +Reported-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=535ecc844591e50588a5 +Tested-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Fixes: 1d6123102e9f ("Bluetooth: hci_core: Fix use-after-free in vhci_flush()") +Signed-off-by: Bharath Reddy +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sysfs.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c +index cc7d4a8ed8ce24..b1886e517a78bc 100644 +--- a/net/bluetooth/hci_sysfs.c ++++ b/net/bluetooth/hci_sysfs.c +@@ -81,10 +81,12 @@ static void bt_host_release(struct device *dev) + { + struct hci_dev *hdev = to_hci_dev(dev); + +- if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) ++ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + hci_release_dev(hdev); +- else ++ } else { ++ cleanup_srcu_struct(&hdev->srcu); + kfree(hdev); ++ } + module_put(THIS_MODULE); + } + +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-mgmt-fix-backward-compatibility-with-users.patch b/queue-6.1/bluetooth-mgmt-fix-backward-compatibility-with-users.patch new file mode 100644 index 0000000000..792fd57a79 --- /dev/null +++ b/queue-6.1/bluetooth-mgmt-fix-backward-compatibility-with-users.patch @@ -0,0 +1,43 @@ +From aa1c286988ac33439a2b6190c7f476df01d22f40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:48:34 -0400 +Subject: Bluetooth: MGMT: Fix backward compatibility with userspace + +From: Luiz Augusto von Dentz + +[ Upstream commit 149324fc762c2a7acef9c26790566f81f475e51f ] + +bluetoothd has a bug with makes it send extra bytes as part of +MGMT_OP_ADD_EXT_ADV_DATA which are now being checked to be the +exact the expected length, relax this so only when the expected +length is greater than the data length to cause an error since +that would result in accessing invalid memory, otherwise just +ignore the extra bytes. + +Link: https://lore.kernel.org/linux-bluetooth/20260602204749.210857-1-luiz.dentz@gmail.com/T/#u +Fixes: d3f7d17960ed ("Bluetooth: MGMT: validate Add Extended Advertising Data length") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index cc058c77d2e252..cd494f5ebb4dba 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -9079,8 +9079,9 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data, + + BT_DBG("%s", hdev->name); + +- expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len); +- if (expected_len != data_len) ++ expected_len = struct_size(cp, data, cp->adv_data_len + ++ cp->scan_rsp_len); ++ if (expected_len > data_len) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_INVALID_PARAMS); + +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch b/queue-6.1/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch new file mode 100644 index 0000000000..a11a1b1c5c --- /dev/null +++ b/queue-6.1/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch @@ -0,0 +1,73 @@ +From 6d190e55eb8884130a2eda3da4ee17ebcdadc38e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 17:45:06 +0800 +Subject: Bluetooth: MGMT: validate advertising TLV before type checks + +From: Zhang Cen + +[ Upstream commit de23fb62259aa01d294f77238ae3b835eb674413 ] + +tlv_data_is_valid() reads each advertising data field length from +data[i], then inspects data[i + 1] for managed EIR types before +checking that the current field still fits inside the supplied buffer. + +A malformed field whose length byte is the last byte of the buffer can +therefore make the parser read one byte past the advertising data. + +KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING +request reached that path: + + BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid() + Read of size 1 + Call trace: + tlv_data_is_valid() + add_advertising() + hci_mgmt_cmd() + hci_sock_sendmsg() + +Move the existing element-length check before any type-octet inspection +so each non-empty element is proven to contain its type byte before the +parser looks at data[i + 1]. + +Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check") +Reviewed-by: Paul Menzel +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index dd7d12418e0738..cc058c77d2e252 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -8602,6 +8602,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (!cur_len) + continue; + ++ /* If the current field length would exceed the total data ++ * length, then it's invalid. ++ */ ++ if (i + cur_len >= len) ++ return false; ++ + if (data[i + 1] == EIR_FLAGS && + (!is_adv_data || flags_managed(adv_flags))) + return false; +@@ -8618,12 +8624,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (data[i + 1] == EIR_APPEARANCE && + appearance_managed(adv_flags)) + return false; +- +- /* If the current field length would exceed the total data +- * length, then it's invalid. +- */ +- if (i + cur_len >= len) +- return false; + } + + return true; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch b/queue-6.1/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch new file mode 100644 index 0000000000..3f5aba0013 --- /dev/null +++ b/queue-6.1/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch @@ -0,0 +1,126 @@ +From bd1c3678dda8f848d01c109d930b87d2f1bddf3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 15:56:41 +0800 +Subject: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() + +From: Zhang Cen + +[ Upstream commit 43c441edacf953b39517a44f5e5e10a93618b226 ] + +rfcomm_get_sock_by_channel() scans rfcomm_sk_list under the list lock, +but returns the selected listener after dropping that lock without +taking a reference. rfcomm_connect_ind() then locks the listener, +queues a child socket on it, and may notify it after unlocking it. + +The buggy scenario involves two paths, with each column showing the +order within that path: + +rfcomm_connect_ind(): listener close: + 1. Find parent in 1. close() enters + rfcomm_get_sock_by_channel() rfcomm_sock_release(). + 2. Drop rfcomm_sk_list.lock 2. rfcomm_sock_shutdown() + without pinning parent. closes the listener. + 3. Call lock_sock(parent) and 3. rfcomm_sock_kill() + bt_accept_enqueue(parent, unlinks and puts parent. + sk, true). + 4. Read parent flags and may 4. parent can be freed. + call sk_state_change(). + +If close wins the race, parent can be freed before +rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or the +deferred-setup callback. + +Take a reference on the listener before leaving rfcomm_sk_list.lock. +After lock_sock() succeeds, recheck that it is still in BT_LISTEN +before queueing a child, cache the deferred-setup bit while the parent +is locked, and drop the reference after the last parent use. + +KASAN reported a slab-use-after-free in lock_sock_nested() from +rfcomm_connect_ind(), with the freeing stack going through +rfcomm_sock_kill() and rfcomm_sock_release(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index bc2b22c2b3aec7..d72cdcd2e2bb11 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) + } + + /* Find socket with channel and source bdaddr. +- * Returns closest match. ++ * Returns closest match with an extra reference held. + */ + static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) + { +@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t * + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ +- if (!bacmp(&rfcomm_pi(sk)->src, src)) ++ if (!bacmp(&rfcomm_pi(sk)->src, src)) { ++ sock_hold(sk); + break; ++ } + + /* Closest match */ +- if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) ++ if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) { ++ if (sk1) ++ sock_put(sk1); ++ + sk1 = sk; ++ sock_hold(sk1); ++ } + } + } + ++ if (sk && sk1) ++ sock_put(sk1); ++ + read_unlock(&rfcomm_sk_list.lock); + + return sk ? sk : sk1; +@@ -941,6 +951,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + { + struct sock *sk, *parent; + bdaddr_t src, dst; ++ bool defer_setup = false; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); +@@ -954,6 +965,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + + lock_sock(parent); + ++ if (parent->sk_state != BT_LISTEN) ++ goto done; ++ ++ defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -981,9 +997,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + done: + release_sock(parent); + +- if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) ++ if (defer_setup) + parent->sk_state_change(parent); + ++ sock_put(parent); ++ + return result; + } + +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch b/queue-6.1/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch new file mode 100644 index 0000000000..94046298ee --- /dev/null +++ b/queue-6.1/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch @@ -0,0 +1,167 @@ +From 4f6ba19c8386a6022120a6ca3e95bce04cee0f03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:04:43 +0900 +Subject: Bluetooth: RFCOMM: validate skb length in MCC handlers + +From: SeungJu Cheon + +[ Upstream commit 23882b828c3c8c51d0c946446a396b10abb3b16b ] + +The RFCOMM MCC handlers cast skb->data to protocol-specific structs +without validating skb->len first. A malicious remote device can send +truncated MCC frames and trigger out-of-bounds reads in these handlers. + +Fix this by using skb_pull_data() to validate and access the required +data before dereferencing it. + +rfcomm_recv_rpn() requires special handling since ETSI TS 07.10 allows +1-byte RPN requests. Handle this by validating only the DLCI byte first, +and validating the full struct only when len > 1. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Suggested-by: Muhammad Bilal +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/core.c | 67 +++++++++++++++++++++++++++---------- + 1 file changed, 49 insertions(+), 18 deletions(-) + +diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c +index 4f54c7df3a94f8..374187def190da 100644 +--- a/net/bluetooth/rfcomm/core.c ++++ b/net/bluetooth/rfcomm/core.c +@@ -1427,10 +1427,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) + + static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_pn *pn; + struct rfcomm_dlc *d; +- u8 dlci = pn->dlci; ++ u8 dlci; ++ ++ pn = skb_pull_data(skb, sizeof(*pn)); ++ if (!pn) ++ return -EILSEQ; + ++ dlci = pn->dlci; + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) +@@ -1479,8 +1484,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + + static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) + { +- struct rfcomm_rpn *rpn = (void *) skb->data; +- u8 dlci = __get_dlci(rpn->dlci); ++ struct rfcomm_rpn *rpn; ++ u8 dlci; + + u8 bit_rate = 0; + u8 data_bits = 0; +@@ -1491,15 +1496,16 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + u8 xoff_char = 0; + u16 rpn_mask = RFCOMM_RPN_PM_ALL; + +- BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", +- dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, +- rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ if (len == 1) { ++ rpn = skb_pull_data(skb, 1); ++ if (!rpn) ++ return -EILSEQ; + +- if (!cr) +- return 0; ++ dlci = __get_dlci(rpn->dlci); ++ ++ if (!cr) ++ return 0; + +- if (len == 1) { +- /* This is a request, return default (according to ETSI TS 07.10) settings */ + bit_rate = RFCOMM_RPN_BR_9600; + data_bits = RFCOMM_RPN_DATA_8; + stop_bits = RFCOMM_RPN_STOP_1; +@@ -1510,6 +1516,19 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + goto rpn_out; + } + ++ rpn = skb_pull_data(skb, sizeof(*rpn)); ++ if (!rpn) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rpn->dlci); ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ + /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit, + * no parity, no flow control lines, normal XON/XOFF chars */ + +@@ -1585,9 +1604,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + + static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_rls *rls = (void *) skb->data; +- u8 dlci = __get_dlci(rls->dlci); ++ struct rfcomm_rls *rls; ++ u8 dlci; + ++ rls = skb_pull_data(skb, sizeof(*rls)); ++ if (!rls) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rls->dlci); + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) +@@ -1604,10 +1628,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_msc *msc; + struct rfcomm_dlc *d; +- u8 dlci = __get_dlci(msc->dlci); ++ u8 dlci; ++ ++ msc = skb_pull_data(skb, sizeof(*msc)); ++ if (!msc) ++ return -EILSEQ; + ++ dlci = __get_dlci(msc->dlci); + BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); + + d = rfcomm_dlc_get(s, dlci); +@@ -1640,17 +1669,19 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) + { +- struct rfcomm_mcc *mcc = (void *) skb->data; ++ struct rfcomm_mcc *mcc; + u8 type, cr, len; + ++ mcc = skb_pull_data(skb, sizeof(*mcc)); ++ if (!mcc) ++ return -EILSEQ; ++ + cr = __test_cr(mcc->type); + type = __get_mcc_type(mcc->type); + len = __get_mcc_len(mcc->len); + + BT_DBG("%p type 0x%x cr %d", s, type, cr); + +- skb_pull(skb, 2); +- + switch (type) { + case RFCOMM_PN: + rfcomm_recv_pn(s, cr, skb); +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-policy-smq-check-allocation-under-invalidat.patch b/queue-6.1/dm-cache-policy-smq-check-allocation-under-invalidat.patch new file mode 100644 index 0000000000..98a96a9620 --- /dev/null +++ b/queue-6.1/dm-cache-policy-smq-check-allocation-under-invalidat.patch @@ -0,0 +1,71 @@ +From 7a9bdea4f68036b07711fe38500ffa0558e0a401 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:57:45 +0800 +Subject: dm cache policy smq: check allocation under invalidate lock + +From: Guangshuo Li + +[ Upstream commit d3f0a606b9f278ece8a0df626ded9c4044071235 ] + +commit 2d1f7b65f5de ("dm cache policy smq: fix missing locks in +invalidating cache blocks") added mq->lock around the destructive part of +smq_invalidate_mapping(), but left the e->allocated check outside the +critical section. + +That leaves a check-then-act race. Two concurrent invalidators can both +observe e->allocated as true before either of them takes mq->lock. The +first invalidator that acquires the lock removes the entry from the +queues and hash table and then calls free_entry(), which clears +e->allocated and puts the entry back on the free list. The second +invalidator can then acquire mq->lock and continue with the stale result +of the unlocked check. + +This can corrupt the SMQ queues or hash table by deleting an entry that +is no longer on those structures. It can also hit the allocation check in +free_entry() when the same entry is freed again. + +Move the allocation check under mq->lock so the predicate and the +destructive operations are serialized by the same lock. + +Fixes: 2d1f7b65f5de ("dm cache policy smq: fix missing locks in invalidating cache blocks") +Signed-off-by: Guangshuo Li +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index d4c2bc5c0ef457..38fe5c31699bc1 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1588,18 +1588,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; +- +- if (!e->allocated) +- return -ENODATA; ++ int r = 0; + + spin_lock_irqsave(&mq->lock, flags); ++ if (!e->allocated) { ++ r = -ENODATA; ++ goto out; ++ } + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ ++out: + spin_unlock_irqrestore(&mq->lock, flags); + +- return 0; ++ return r; + } + + static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) +-- +2.53.0 + diff --git a/queue-6.1/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch b/queue-6.1/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch new file mode 100644 index 0000000000..4c1c5e8a19 --- /dev/null +++ b/queue-6.1/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch @@ -0,0 +1,53 @@ +From 7ee2facfa61ce6a095f53a1d200e810c6076b509 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 19:00:13 +0100 +Subject: drm/imx: Fix three kernel-doc warnings in dcss-scaler.c + +From: Yicong Hui + +[ Upstream commit ae0383e5a9a4b12d68c76c4769857def4665deff ] + +Fix the following W=1 kerneldoc warnings by adding the missing parameter +descriptions for @phase0_identity and @nn_interpolation in +dcss_scaler_filter_design() and @phase0_identity in +dcss_scaler_gaussian_filter() + +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:173 function parameter 'phase0_identity' not described in 'dcss_scaler_gaussian_filter' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'phase0_identity' not described in 'dcss_scaler_filter_design' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'nn_interpolation' not described in 'dcss_scaler_filter_design' + +Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") +Signed-off-by: Yicong Hui +Reviewed-by: Laurentiu Palcu +Link: https://patch.msgid.link/20260406180013.2442096-1-yiconghui@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/dcss/dcss-scaler.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +index 47852b9dd5eaa2..d2a89a99bd71cf 100644 +--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c ++++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +@@ -166,6 +166,7 @@ static int exp_approx_q(int x) + * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter. + * @fc_q: fixed-point cutoff frequency normalized to range [0, 1] + * @use_5_taps: indicates whether to use 5 taps or 7 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output filter coefficients + */ + static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, +@@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, + * @src_length: length of input + * @dst_length: length of output + * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output coefficients ++ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter + */ + static void dcss_scaler_filter_design(int src_length, int dst_length, + bool use_5_taps, bool phase0_identity, +-- +2.53.0 + diff --git a/queue-6.1/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch b/queue-6.1/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch new file mode 100644 index 0000000000..0d5cc44586 --- /dev/null +++ b/queue-6.1/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch @@ -0,0 +1,56 @@ +From 52f2d7471dd69649f4b73ce420fa7190b1950837 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 07:29:55 +0000 +Subject: ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit() + +From: Eric Dumazet + +[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ] + +The aoe driver (or similar) generates a non-IPv6 packet +(e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() +on a 6LoWPAN interface (configured by the user or test case). + +Since the packet is not IPv6, the 6LoWPAN header_ops->create function +(lowpan_header_create or header_create) returns early without initializing +the lowpan_addr_info structure in the skb headroom. + +In the transmit function (lowpan_xmit), the driver calls lowpan_header +(or setup_header) which unconditionally copies and uses the lowpan_addr_info +from the headroom, which contains uninitialized data. + +Fix this by dropping non IPv6 packets. + +A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit(). + +Fixes: 4dc315e267fe ("ieee802154: 6lowpan: move transmit functionality") +Reported-by: syzbot+f13c19f75e1097abd116@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1fd763.278b5b03.2bcf39.0049.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260603072955.4032221-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ieee802154/6lowpan/tx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c +index 0c07662b44c0ca..4df76ff50699ed 100644 +--- a/net/ieee802154/6lowpan/tx.c ++++ b/net/ieee802154/6lowpan/tx.c +@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) + + pr_debug("package xmit\n"); + ++ if (skb->protocol != htons(ETH_P_IPV6)) { ++ kfree_skb(skb); ++ return NET_XMIT_DROP; ++ } ++ + WARN_ON_ONCE(skb->len > IPV6_MIN_MTU); + + /* We must take a copy of the skb before we modify/replace the ipv6 +-- +2.53.0 + diff --git a/queue-6.1/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch b/queue-6.1/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch new file mode 100644 index 0000000000..3494947130 --- /dev/null +++ b/queue-6.1/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch @@ -0,0 +1,54 @@ +From b4dae8aac370b138fbf528c9d9ce9b0232bb7570 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:15:47 +0000 +Subject: ipv4: restrict IPOPT_SSRR and IPOPT_LSRR options + +From: Eric Dumazet + +[ Upstream commit d3915a1f5a4bc0ac911032903c3c6ab8df9fcc7c ] + +This patch restricts setting Loose Source and Record Route (LSRR) +and Strict Source and Record Route (SSRR) IP options to users +with CAP_NET_RAW capability. + +This prevents unprivileged applications from forcing packets to route +through attacker-controlled nodes to leak TCP ISN and possibly other +protocol information. + +While LSRR and SSRR are commonly filtered in many network environments, +they may still be supported and forwarded along some network paths. + +RFC 7126 (Recommendations on Filtering of IPv4 Packets Containing +IPv4 Options) recommend to drop these options in 4.3 and 4.4. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260602161547.2642155-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_options.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index d898e1523a453e..7a60bbf4bee3aa 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -530,6 +530,10 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp, + kfree(opt); + return -EINVAL; + } ++ if (opt->opt.srr && !ns_capable(net->user_ns, CAP_NET_RAW)) { ++ kfree(opt); ++ return -EPERM; ++ } + kfree(*optp); + *optp = opt; + return 0; +-- +2.53.0 + diff --git a/queue-6.1/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch b/queue-6.1/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch new file mode 100644 index 0000000000..5a809fde02 --- /dev/null +++ b/queue-6.1/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch @@ -0,0 +1,107 @@ +From 069404dfdfb6001db5fc68846b408ca92c65ec83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 13:18:11 +0300 +Subject: ipv6: mcast: Fix use-after-free when processing MLD queries + +From: Ido Schimmel + +[ Upstream commit 791c91dc7a9dfb2457d5e29b8216a6484b9c4b40 ] + +When processing an MLD query, a pointer to the multicast group address +is retrieved when initially parsing the packet. This pointer is later +dereferenced without being reloaded despite the fact that the skb header +might have been reallocated following the pskb_may_pull() calls, leading +to a use-after-free [1]. + +Fix by copying the multicast group address when the packet is initially +parsed. + +[1] +BUG: KASAN: slab-use-after-free in __mld_query_work (net/ipv6/mcast.c:1512) +Read of size 8 at addr ffff8881154b8e90 by task kworker/4:1/118 + +Workqueue: mld mld_query_work +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +print_address_description.constprop.0 (mm/kasan/report.c:378) +print_report (mm/kasan/report.c:482) +kasan_report (mm/kasan/report.c:595) +__mld_query_work (net/ipv6/mcast.c:1512) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + + +[...] + +Freed by task 118: +kasan_save_stack (mm/kasan/common.c:57) +kasan_save_track (mm/kasan/common.c:78) +kasan_save_free_info (mm/kasan/generic.c:584) +__kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285) +kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566) +pskb_expand_head (net/core/skbuff.c:2335) +__pskb_pull_tail (net/core/skbuff.c:2878 (discriminator 4)) +__mld_query_work (net/ipv6/mcast.c:1495 (discriminator 1)) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + +Fixes: 97300b5fdfe2 ("[MCAST] IPv6: Check packet size when process Multicast") +Reported-by: Leo Lin +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260603101811.612594-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index e7f569875e7186..f6af19b873a41d 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1392,9 +1392,9 @@ void igmp6_event_query(struct sk_buff *skb) + static void __mld_query_work(struct sk_buff *skb) + { + struct mld2_query *mlh2 = NULL; +- const struct in6_addr *group; + unsigned long max_delay; + struct inet6_dev *idev; ++ struct in6_addr group; + struct ifmcaddr6 *ma; + struct mld_msg *mld; + int group_type; +@@ -1426,8 +1426,8 @@ static void __mld_query_work(struct sk_buff *skb) + goto kfree_skb; + + mld = (struct mld_msg *)icmp6_hdr(skb); +- group = &mld->mld_mca; +- group_type = ipv6_addr_type(group); ++ group = mld->mld_mca; ++ group_type = ipv6_addr_type(&group); + + if (group_type != IPV6_ADDR_ANY && + !(group_type&IPV6_ADDR_MULTICAST)) +@@ -1477,7 +1477,7 @@ static void __mld_query_work(struct sk_buff *skb) + } + } else { + for_each_mc_mclock(idev, ma) { +- if (!ipv6_addr_equal(group, &ma->mca_addr)) ++ if (!ipv6_addr_equal(&group, &ma->mca_addr)) + continue; + if (ma->mca_flags & MAF_TIMER_RUNNING) { + /* gsquery <- gsquery && mark */ +-- +2.53.0 + diff --git a/queue-6.1/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch b/queue-6.1/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch new file mode 100644 index 0000000000..2eb16416fa --- /dev/null +++ b/queue-6.1/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch @@ -0,0 +1,127 @@ +From 47752dc8d230f26d6eb3c74c0a6b76d53b3c9348 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 07:07:44 +0300 +Subject: ipvs: clear the svc scheduler ptr early on edit + +From: Julian Anastasov + +[ Upstream commit 193989cc6d80dd8e0460fb3992e69fa03bf0ff9b ] + +ip_vs_edit_service() while unbinding the old scheduler clears +the svc->scheduler ptr after the scheduler module initiates +RCU callbacks. This can cause packets to use the old +scheduler at the time when svc->sched_data is already freed +after RCU grace period. + +Fix it by clearing the ptr early in ip_vs_unbind_scheduler(), +before the done_service method schedules any RCU callbacks. + +Also, if the new scheduler fails to initialize when replacing +the old scheduler, try to restore the old scheduler while still +returning the error code. + +Link: https://sashiko.dev/#/patchset/20260519015506.634185-1-rosenp%40gmail.com +Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed") +Signed-off-by: Julian Anastasov +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/ip_vs.h | 3 +-- + net/netfilter/ipvs/ip_vs_ctl.c | 13 ++++++++----- + net/netfilter/ipvs/ip_vs_sched.c | 14 +++++++------- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +index abc46f05762e6b..0b175ecd9562bd 100644 +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -1407,8 +1407,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched); ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc); + struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); + void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); + struct ip_vs_conn * +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index 6cc50f05c46c15..15a083dd459737 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -1415,7 +1415,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, + if (ret_hooks >= 0) + ip_vs_unregister_hooks(ipvs, u->af); + if (svc != NULL) { +- ip_vs_unbind_scheduler(svc, sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_service_free(svc); + } + ip_vs_scheduler_put(sched); +@@ -1477,9 +1477,8 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + old_sched = rcu_dereference_protected(svc->scheduler, 1); + if (sched != old_sched) { + if (old_sched) { +- ip_vs_unbind_scheduler(svc, old_sched); +- RCU_INIT_POINTER(svc->scheduler, NULL); +- /* Wait all svc->sched_data users */ ++ ip_vs_unbind_scheduler(svc); ++ /* Wait all svc->scheduler/sched_data users */ + synchronize_rcu(); + } + /* Bind the new scheduler */ +@@ -1487,6 +1486,10 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + ret = ip_vs_bind_scheduler(svc, sched); + if (ret) { + ip_vs_scheduler_put(sched); ++ /* Try to restore the old_sched */ ++ if (old_sched && ++ !ip_vs_bind_scheduler(svc, old_sched)) ++ old_sched = NULL; + goto out; + } + } +@@ -1543,7 +1546,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup) + + /* Unbind scheduler */ + old_sched = rcu_dereference_protected(svc->scheduler, 1); +- ip_vs_unbind_scheduler(svc, old_sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_scheduler_put(old_sched); + + /* Unbind persistence engine, keep svc->pe */ +diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c +index d4903723be7e90..49b2e5d2b2c837 100644 +--- a/net/netfilter/ipvs/ip_vs_sched.c ++++ b/net/netfilter/ipvs/ip_vs_sched.c +@@ -57,19 +57,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, + /* + * Unbind a service with its scheduler + */ +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched) ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc) + { +- struct ip_vs_scheduler *cur_sched; ++ struct ip_vs_scheduler *sched; + +- cur_sched = rcu_dereference_protected(svc->scheduler, 1); +- /* This check proves that old 'sched' was installed */ +- if (!cur_sched) ++ sched = rcu_dereference_protected(svc->scheduler, 1); ++ if (!sched) + return; + ++ /* Reset the scheduler before initiating any RCU callbacks */ ++ rcu_assign_pointer(svc->scheduler, NULL); ++ smp_wmb(); /* paired with smp_rmb() in ip_vs_schedule() */ + if (sched->done_service) + sched->done_service(svc); +- /* svc->scheduler can be set to NULL only by caller */ + } + + +-- +2.53.0 + diff --git a/queue-6.1/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch b/queue-6.1/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch new file mode 100644 index 0000000000..8567edf1ee --- /dev/null +++ b/queue-6.1/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch @@ -0,0 +1,79 @@ +From 8d42bd4c2339914c5d72af008537d8e761307c60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:00:13 +0800 +Subject: net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr + +From: Yizhou Zhao + +[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ] + +In mrp_pdu_parse_vecattr(), vector attribute events are encoded three +per byte and valen tracks the number of events left to process. + +The parser decrements valen after processing the first and second events +from each event byte, but not after processing the third one. When valen +is exactly a multiple of three, the loop continues after the last valid +event and consumes the next byte as a new event byte, applying a +spurious event to the MRP applicant state. + +Additionally, when valen is zero the parser unconditionally consumes +attrlen bytes as FirstValue and advances the offset, even though per +IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of +zero and no FirstValue or Vector fields. This corrupts the offset for +subsequent PDU parsing. + +Also, when valen exceeds three the loop crosses byte boundaries but +the attribute value is not incremented between the last event of one +byte and the first event of the next. This causes the first event of +the next byte to use the same attribute value as the third event +rather than the next consecutive value. + +Decrement valen after processing the third event, skip FirstValue +consumption when valen is zero, and increment the attribute value at +the end of each loop iteration. + +Fixes: febf018d2234 ("net/802: Implement Multiple Registration Protocol (MRP)") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Link: https://patch.msgid.link/20260603060016.21522-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/mrp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/802/mrp.c b/net/802/mrp.c +index 6c927d4b35f06e..dea0fd28cbed88 100644 +--- a/net/802/mrp.c ++++ b/net/802/mrp.c +@@ -702,6 +702,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) & + MRP_VECATTR_HDR_LEN_MASK); + ++ /* If valen is 0, only a LeaveAllEvent is present; FirstValue and ++ * Vector fields are absent per IEEE 802.1ak. ++ */ ++ if (valen == 0) ++ return 0; ++ + /* The VectorAttribute structure in a PDU carries event information + * about one or more attributes having consecutive values. Only the + * value for the first attribute is contained in the structure. So +@@ -752,6 +758,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + vaevents %= __MRP_VECATTR_EVENT_MAX; + vaevent = vaevents; + mrp_pdu_parse_vecattr_event(app, skb, vaevent); ++ valen--; ++ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue, ++ mrp_cb(skb)->mh->attrlen); + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/net-annotate-sk-sk_write_space-for-udp-sockmap.patch b/queue-6.1/net-annotate-sk-sk_write_space-for-udp-sockmap.patch new file mode 100644 index 0000000000..8d6ba477be --- /dev/null +++ b/queue-6.1/net-annotate-sk-sk_write_space-for-udp-sockmap.patch @@ -0,0 +1,60 @@ +From 96e4e4d4a0a9d81b49be0034bcad03d7e64d97da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:39:23 +0000 +Subject: net: Annotate sk->sk_write_space() for UDP SOCKMAP. + +From: Kuniyuki Iwashima + +[ Upstream commit b748765019fe9e9234660327090fc1a9665cdbdd ] + +UDP TX skb->destructor() is sock_wfree(), and UDP holds lock_sock() +only for UDP_CORK / MSG_MORE sendmsg(). + +Otherwise, sk->sk_write_space() may be read locklessly while SOCKMAP +rewrites sk->sk_write_space(). + +Let's use WRITE_ONCE() and READ_ONCE() for sk->sk_write_space(). + +Note that the write side is annotated by commit 2ef2b20cf4e0 +("net: annotate data-races around sk->sk_{data_ready,write_space}"). + +Fixes: 7b98cd42b049 ("bpf: sockmap: Add UDP support") +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Jakub Sitnicki +Link: https://patch.msgid.link/20260529193941.3897256-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 6c178b47426669..62411c8870e855 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2433,8 +2433,12 @@ void sock_wfree(struct sk_buff *skb) + bool free; + + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { ++ void (*sk_write_space)(struct sock *sk); ++ ++ sk_write_space = READ_ONCE(sk->sk_write_space); ++ + if (sock_flag(sk, SOCK_RCU_FREE) && +- sk->sk_write_space == sock_def_write_space) { ++ sk_write_space == sock_def_write_space) { + rcu_read_lock(); + free = refcount_sub_and_test(len, &sk->sk_wmem_alloc); + sock_def_write_space_wfree(sk); +@@ -2449,7 +2453,7 @@ void sock_wfree(struct sk_buff *skb) + * after sk_write_space() call + */ + WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc)); +- sk->sk_write_space(sk); ++ sk_write_space(sk); + len = 1; + } + /* +-- +2.53.0 + diff --git a/queue-6.1/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch b/queue-6.1/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch new file mode 100644 index 0000000000..e091894a3f --- /dev/null +++ b/queue-6.1/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch @@ -0,0 +1,62 @@ +From 1e5682714e8ed1da386872b3f5443f0fc6a1e352 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 06:18:57 +0000 +Subject: net: fec: fix pinctrl default state restore order on resume + +From: Tapio Reijonen + +[ Upstream commit b455410146bf723c7ebcb49ecd5becc0d6611482 ] + +In fec_resume(), fec_enet_clk_enable() is called before +pinctrl_pm_select_default_state() in the non-WoL path, inverting the +ordering used in fec_suspend() which correctly switches to the sleep +pinctrl state before disabling clocks. + +For PHYs with the PHY_RST_AFTER_CLK_EN flag (e.g. TI DP83848 or +SMSC LAN87xx), fec_enet_clk_enable() triggers a hardware reset pulse +via the phy-reset GPIO. With the GPIO pin still in sleep pinctrl state +at that point, the GPIO write has no physical effect and the PHY never +receives the required reset after clock enable, leading to unreliable +link establishment after system resume. + +Fix by restoring the default pinctrl state before enabling clocks, +making resume the proper mirror of suspend. The call is made +unconditionally: fec_suspend() only switches to the sleep pinctrl state +on the non-WoL path and leaves the pins in the default state when WoL +is enabled, so on a WoL resume the device is already in the default +state and pinctrl_pm_select_default_state() is a no-op. + +Fixes: de40ed31b3c5 ("net: fec: add Wake-on-LAN support") +Signed-off-by: Tapio Reijonen +Reviewed-by: Wei Fang +Link: https://patch.msgid.link/20260529-b4-fec-resume-pinctrl-order-v3-1-6eda0f592fca@vaisala.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/fec_main.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index e9c4945d0c2713..d1510af6aff1b5 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -4322,6 +4322,7 @@ static int __maybe_unused fec_resume(struct device *dev) + if (fep->rpm_active) + pm_runtime_force_resume(dev); + ++ pinctrl_pm_select_default_state(&fep->pdev->dev); + ret = fec_enet_clk_enable(ndev, true); + if (ret) { + rtnl_unlock(); +@@ -4338,8 +4339,6 @@ static int __maybe_unused fec_resume(struct device *dev) + val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; +- } else { +- pinctrl_pm_select_default_state(&fep->pdev->dev); + } + fec_restart(ndev); + netif_tx_lock_bh(ndev); +-- +2.53.0 + diff --git a/queue-6.1/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch b/queue-6.1/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch new file mode 100644 index 0000000000..dc10d80fdb --- /dev/null +++ b/queue-6.1/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch @@ -0,0 +1,58 @@ +From 6e40d171b9819dfe5707ea7a2796a4daf92d62f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:31:58 +0800 +Subject: net: garp: fix unsigned integer underflow in garp_pdu_parse_attr + +From: Yizhou Zhao + +[ Upstream commit 16e408e607a94b646fb14a2a98422c6877ae4b3c ] + +The receive-side GARP attribute parser computes dlen with reversed +operands: + + dlen = sizeof(*ga) - ga->len; + +ga->len is the on-wire attribute length and includes the GARP attribute +header. For normal attributes with data, ga->len is larger than +sizeof(*ga), so the subtraction underflows in unsigned arithmetic. + +The resulting value is later passed to garp_attr_lookup(), whose length +argument is u8. After truncation, the parsed data length usually no +longer matches the length stored for locally registered attributes, so +received Join/Leave events are ignored. This breaks the GARP receive path +for common attributes, such as GVRP VLAN registration attributes. + +Compute the data length as the attribute length minus the header length. + +Fixes: eca9ebac651f ("net: Add GARP applicant-only participant") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260527083200.42861-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/garp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/802/garp.c b/net/802/garp.c +index fc9eb02a912f81..f8037227e6dd66 100644 +--- a/net/802/garp.c ++++ b/net/802/garp.c +@@ -452,7 +452,7 @@ static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); +- dlen = sizeof(*ga) - ga->len; ++ dlen = ga->len - sizeof(*ga); + + if (attrtype > app->app->maxattr) + return 0; +-- +2.53.0 + diff --git a/queue-6.1/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch b/queue-6.1/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch new file mode 100644 index 0000000000..651a32e635 --- /dev/null +++ b/queue-6.1/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch @@ -0,0 +1,99 @@ +From 7df39d54a71914f8a75f58e323e56e6244f1ddab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 21:03:00 +0000 +Subject: net: lan743x: permit VLAN-tagged packets up to configured MTU + +From: David Thompson + +[ Upstream commit 8173d22b211f615015f7b35f48ab11a6dd78dc99 ] + +VLAN-tagged interfaces on lan743x devices were previously unreachable via +SSH and failed to respond to large ping packets (e.g. "ping -s 1469" given +MTU=1500). In these scenarios, "ethtool -S" reports non-zero "RX Oversize +Frame Errors". According to Microchip AN2948, the MAC_RX FSE (VLAN field +size enforcement) bit determines whether frames with VLAN tags exceeding +the base MTU plus tag length are discarded. + +The driver must set the MAC_RX.FSE bit before setting MAC_RX.RXEN to allow +VLAN-tagged frames up to the interface MTU, preventing them from being +treated as oversized. As a result, both the base and VLAN-tagged interfaces +can use the same MTU without receive errors. + +Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") +Signed-off-by: David Thompson +Reviewed-by: Thangaraj Samynathan +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz # lan7430 on arm64 (RevPi +Link: https://patch.msgid.link/20260529210300.433135-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 32 +++++++++++++++++++ + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 5dacc786db4559..c51d316ccdfb86 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1271,6 +1271,36 @@ static void lan743x_mac_set_address(struct lan743x_adapter *adapter, + "MAC address set to %pM\n", addr); + } + ++static void lan743x_mac_rx_enable_fse(struct lan743x_adapter *adapter) ++{ ++ u32 mac_rx; ++ bool rxen; ++ ++ mac_rx = lan743x_csr_read(adapter, MAC_RX); ++ if (mac_rx & MAC_RX_FSE_) ++ return; ++ ++ rxen = mac_rx & MAC_RX_RXEN_; ++ if (rxen) { ++ mac_rx &= ~MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, ++ 1, 1000, 20000, 100); ++ } ++ ++ /* Per AN2948, hardware prevents modification of the FSE bit while the ++ * MAC receiver is enabled (RXEN bit set). Use separate register write ++ * to assert the FSE bit before enabling the RXEN bit in MAC_RX ++ */ ++ mac_rx |= MAC_RX_FSE_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ ++ if (rxen) { ++ mac_rx |= MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ } ++} ++ + static int lan743x_mac_init(struct lan743x_adapter *adapter) + { + bool mac_address_valid = true; +@@ -1310,6 +1340,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter) + lan743x_mac_set_address(adapter, adapter->mac_address); + eth_hw_addr_set(netdev, adapter->mac_address); + ++ lan743x_mac_rx_enable_fse(adapter); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index c0d209f36188a1..9f20c727a7e137 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -180,6 +180,7 @@ + #define MAC_RX (0x104) + #define MAC_RX_MAX_SIZE_SHIFT_ (16) + #define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) ++#define MAC_RX_FSE_ BIT(2) + #define MAC_RX_RXD_ BIT(1) + #define MAC_RX_RXEN_ BIT(0) + +-- +2.53.0 + diff --git a/queue-6.1/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch b/queue-6.1/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch new file mode 100644 index 0000000000..215ef60877 --- /dev/null +++ b/queue-6.1/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch @@ -0,0 +1,106 @@ +From 82e15b7f2b587e340d1f585eec4be0c2bedb03a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 12:08:12 -0400 +Subject: net/sched: act_api: use RCU with deferred freeing for action + lifecycle + +From: Jamal Hadi Salim + +[ Upstream commit 5057e1aca011e51ef51498c940ef96f3d3e8a305 ] + +When NEWTFILTER and DELFILTER are run concurrently it is possible to create a +race with an associated action. + +Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: + + 0: mutex_lock() <-- holds the idr lock + 0: rcu_read_lock() + 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) + 0: mutex_unlock() <-- releases the idr lock + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) <-- Action removed from IDR + 1: mutex_unlock() <-- mutex released allowing us to delete the action + 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory + +This patch fixes the race condition between NEWTFILTER and DELFILTER by +adding struct rcu_head to tc_action used in the deferral and introducing a +call_rcu() in the delete path to defer the final kfree(). + +Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +but also modernization/simplification to directly use kfree_rcu(). + +Let's illustrate the new restored code path: + + 0: rcu_read_lock() + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) + 1: mutex_unlock() + 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period + 0: p = idr_find(idr, index) + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 + 1: rcu_read_unlock() <-- release so freeing can run after grace period + +After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. +CPU0's subsequent idr_find() will return NULL, and even if it still held a +stale pointer, the immediate kfree() is now deferred until after the RCU grace +period, so no UAF can occur. + +Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +Suggested-by: Jakub Kicinski +Reported-by: Kyle Zeng +Tested-by: Victor Nogueira +Tested-by: syzbot@syzkaller.appspotmail.com +Signed-off-by: Jamal Hadi Salim +Tested-by: Kyle Zeng +Reviewed-by: Pedro Tammela +Reviewed-by: Eric Dumazet +Reviewed-by: Victor Nogueira +Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/act_api.h | 1 + + net/sched/act_api.c | 7 +------ + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/net/act_api.h b/include/net/act_api.h +index 31e8d8f8bcd7eb..55e3b5ec1d92d8 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -42,6 +42,7 @@ struct tc_action { + struct tc_cookie __rcu *act_cookie; + struct tcf_chain __rcu *goto_chain; + u32 tcfa_flags; ++ struct rcu_head tcfa_rcu; + u8 hw_stats; + u8 used_hw_stats; + bool used_hw_stats_valid; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index b75e22756c4b09..47f0d4c3dc487f 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -111,11 +111,6 @@ struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action, + } + EXPORT_SYMBOL(tcf_action_set_ctrlact); + +-/* XXX: For standalone actions, we don't need a RCU grace period either, because +- * actions are always connected to filters and filters are already destroyed in +- * RCU callbacks, so after a RCU grace period actions are already disconnected +- * from filters. Readers later can not find us. +- */ + static void free_tcf(struct tc_action *p) + { + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); +@@ -128,7 +123,7 @@ static void free_tcf(struct tc_action *p) + if (chain) + tcf_chain_put_by_act(chain); + +- kfree(p); ++ kfree_rcu(p, tcfa_rcu); + } + + static void offload_action_hw_count_set(struct tc_action *act, +-- +2.53.0 + diff --git a/queue-6.1/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch b/queue-6.1/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch new file mode 100644 index 0000000000..d9360c349d --- /dev/null +++ b/queue-6.1/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch @@ -0,0 +1,58 @@ +From 6f049ce4657e6963d0b7c56e3d0dc94a81048981 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 12:29:10 +0000 +Subject: netfilter: bridge: make ebt_snat ARP rewrite writable + +From: Yiming Qian + +[ Upstream commit 67ba971ae02514d85818fe0c32549ab4bfa3bf49 ] + +The ebtables SNAT target keeps the Ethernet source address rewrite +behind skb_ensure_writable(skb, 0). This is intentional: at the bridge +ebtables hooks the Ethernet header is addressed through +skb_mac_header()/eth_hdr(), while skb->data points at the Ethernet +payload. Asking skb_ensure_writable() for ETH_HLEN bytes would check +the payload, not the Ethernet header, and would reintroduce the small +packet regression fixed by commit 63137bc5882a. + +However, the optional ARP sender hardware address rewrite is different. +It writes through skb_store_bits() at an offset relative to skb->data: + + skb_store_bits(skb, sizeof(struct arphdr), info->mac, ETH_ALEN) + +skb_header_pointer() only safely reads the ARP header; it does not make +the later sender hardware address range writable. If that range is +still held in a nonlinear skb fragment backed by a splice-imported file +page, skb_store_bits() maps the frag page and copies the new MAC address +directly into it. + +Ensure the ARP SHA range is writable before reading the ARP header and +before calling skb_store_bits(). + +Fixes: 63137bc5882a ("netfilter: ebtables: Fixes dropping of small packets in bridge nat") +Reported-by: Yiming Qian +Signed-off-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_snat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c +index 7dfbcdfc30e5d2..c9e229af0366b8 100644 +--- a/net/bridge/netfilter/ebt_snat.c ++++ b/net/bridge/netfilter/ebt_snat.c +@@ -31,6 +31,9 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) + const struct arphdr *ap; + struct arphdr _ah; + ++ if (skb_ensure_writable(skb, sizeof(_ah) + ETH_ALEN)) ++ return EBT_DROP; ++ + ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch b/queue-6.1/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch new file mode 100644 index 0000000000..5d997e87f0 --- /dev/null +++ b/queue-6.1/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch @@ -0,0 +1,50 @@ +From 549a8637c5f59dcc9e05d3a02424b4db609f4366 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:20:19 +0200 +Subject: netfilter: conntrack_irc: fix possible out-of-bounds read + +From: Florian Westphal + +[ Upstream commit 66eba0ffce3b7e11449946b4cbbef8ea36112f56 ] + +When parsing fails after we've matched the command string we +should bail out instead of trying to match a different command. + +This helper should be deprecated, given prevalence of TLS I doubt it has +any relevance in 2026. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Closes: https://sashiko.dev/#/patchset/20260525182924.28456-1-fw%40strlen.de +Signed-off-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_irc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c +index 5703846bea3b69..0f50ea92ced9df 100644 +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -208,7 +208,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + pr_debug("unable to parse dcc command\n"); +- continue; ++ goto out; + } + + pr_debug("DCC bound ip/port: %pI4:%u\n", +@@ -222,7 +222,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); +- continue; ++ goto out; + } + + exp = nf_ct_expect_alloc(ct); +-- +2.53.0 + diff --git a/queue-6.1/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch b/queue-6.1/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch new file mode 100644 index 0000000000..9e0b0eedfd --- /dev/null +++ b/queue-6.1/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch @@ -0,0 +1,113 @@ +From d5810721e683d187a1cb80440aefae3c859ed075 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 23:58:31 +0200 +Subject: netfilter: synproxy: add mutex to guard hook reference counting + +From: Fernando Fernandez Mancera + +[ Upstream commit 2fcba19caaeb2a33017459d3430f057967bb91b6 ] + +As the synproxy infrastructure register netfilter hooks on-demand when a +user adds the first iptables target or nftables expression, if done +concurrently they can race each other. + +Introduce a mutex to serialize the refcount control blocks access from +both frontends. While a per namespace mutex might be more efficient, it +is not needed for target/expression like SYNPROXY. + +Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index f5a52075691faa..500a90311ed505 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -21,6 +21,8 @@ + #include + #include + ++static DEFINE_MUTEX(synproxy_mutex); ++ + unsigned int synproxy_net_id; + EXPORT_SYMBOL_GPL(synproxy_net_id); + +@@ -768,26 +770,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = { + + int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref4 == 0) { + err = nf_register_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref4++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init); + + void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref4--; + if (snet->hook_ref4 == 0) + nf_unregister_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini); + +@@ -1192,27 +1199,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = { + int + nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref6 == 0) { + err = nf_register_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref6++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init); + + void + nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref6--; + if (snet->hook_ref6 == 0) + nf_unregister_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini); + #endif /* CONFIG_IPV6 */ +-- +2.53.0 + diff --git a/queue-6.1/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch b/queue-6.1/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..d79f1eca62 --- /dev/null +++ b/queue-6.1/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch @@ -0,0 +1,41 @@ +From 13fa5a1978240b227253246af2e2a816ef9b2314 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 12:47:17 +0200 +Subject: netfilter: xt_NFQUEUE: prefer raw_smp_processor_id + +From: Fernando Fernandez Mancera + +[ Upstream commit c6c5327dd18bec1e1bbf139b2cf5ae53608a9d30 ] + +With PREEMPT_RCU this triggers a splat because smp_processor_id() can be +preempted while inside a RCU critical section. If xt_NFQUEUE target is +invoked via nft_compat_eval() path, we are inside a RCU critical +section. + +Just use the raw version instead. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_NFQUEUE.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index 466da23e36ff47..b32d153e3a1862 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -91,7 +91,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) + + if (info->queues_total > 1) { + if (info->flags & NFQ_FLAG_CPU_FANOUT) { +- int cpu = smp_processor_id(); ++ int cpu = raw_smp_processor_id(); + + queue = info->queuenum + cpu % info->queues_total; + } else { +-- +2.53.0 + diff --git a/queue-6.1/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch b/queue-6.1/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch new file mode 100644 index 0000000000..c011517856 --- /dev/null +++ b/queue-6.1/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch @@ -0,0 +1,119 @@ +From 008a9b234b914d27cac828a11788de0d1b71504f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 10:28:53 +0530 +Subject: octeontx2-af: npc: Fix CPT channel mask in npc_install_flow + +From: Nithin Dabilpuram + +[ Upstream commit 1d31eb27e570daa04f5373345f9ac98c95863be9 ] + +Use the CPT-aware NIX channel mask in the npc_install_flow path so that +when the host PF installs steering rules in kernel for a VF used from +userspace (e.g. DPDK), MCAM entries see the same channel mask semantics as +other RX paths. + +Fixes: 56bcef528bd8 ("octeontx2-af: Use npc_install_flow API for promisc and broadcast entries") +Cc: Naveen Mamindlapalli +Signed-off-by: Nithin Dabilpuram +Signed-off-by: Ratheesh Kannoth +Link: https://patch.msgid.link/20260602045853.1558530-1-rkannoth@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + + .../ethernet/marvell/octeontx2/af/rvu_npc.c | 32 +++++++++---------- + .../marvell/octeontx2/af/rvu_npc_fs.c | 2 +- + 3 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index fc0f3398a556bb..86ef67745ebdf7 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -895,6 +895,7 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int lf, + int slot); + int rvu_cpt_ctx_flush(struct rvu *rvu, u16 pcifunc); + int rvu_cpt_init(struct rvu *rvu); ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu); + + #define NDC_AF_BANK_MASK GENMASK_ULL(7, 0) + #define NDC_AF_BANK_LINE_MASK GENMASK_ULL(31, 16) +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index 9b8a6046e6dff0..65ad7476e60983 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -609,6 +609,19 @@ static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + NPC_AF_MCAMEX_BANKX_ACTION(index, bank)); + } + ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu) ++{ ++ /* For cn10k the upper two bits of the channel number are ++ * cpt channel number. with masking out these bits in the ++ * mcam entry, same entry used for NIX will allow packets ++ * received from cpt for parsing. ++ */ ++ if (!is_rvu_otx2(rvu)) ++ return NIX_CHAN_CPT_X2P_MASK; ++ else ++ return 0xFFFu; ++} ++ + void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + int nixlf, u64 chan, u8 *mac_addr) + { +@@ -652,7 +665,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + eth_broadcast_addr((u8 *)&req.mask.dmac); + req.features = BIT_ULL(NPC_DMAC); + req.channel = chan; +- req.chan_mask = 0xFFFU; ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.intf = pfvf->nix_rx_intf; + req.op = action.op; + req.hdr.pcifunc = 0; /* AF is requester */ +@@ -722,11 +735,7 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc, + * mcam entry, same entry used for NIX will allow packets + * received from cpt for parsing. + */ +- if (!is_rvu_otx2(rvu)) { +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- } else { +- req.chan_mask = 0xFFFU; +- } ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + + if (chan_cnt > 1) { + if (!is_power_of_2(chan_cnt)) { +@@ -915,16 +924,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf, + ether_addr_copy(req.mask.dmac, mac_addr); + req.features = BIT_ULL(NPC_DMAC); + +- /* For cn10k the upper two bits of the channel number are +- * cpt channel number. with masking out these bits in the +- * mcam entry, same entry used for NIX will allow packets +- * received from cpt for parsing. +- */ +- if (!is_rvu_otx2(rvu)) +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- else +- req.chan_mask = 0xFFFU; +- ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.channel = chan; + req.intf = pfvf->nix_rx_intf; + req.entry = index; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +index 80d6aa3f14c11f..b79b28192a5764 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +@@ -1320,7 +1320,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, + + /* ignore chan_mask in case pf func is not AF, revisit later */ + if (!is_pffunc_af(req->hdr.pcifunc)) +- req->chan_mask = 0xFFF; ++ req->chan_mask = rvu_get_cpt_chan_mask(rvu); + + err = npc_check_unsupported_flows(rvu, req->features, req->intf); + if (err) +-- +2.53.0 + diff --git a/queue-6.1/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch b/queue-6.1/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch new file mode 100644 index 0000000000..e4b83cb4a0 --- /dev/null +++ b/queue-6.1/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch @@ -0,0 +1,58 @@ +From 16ef2f9bf8b59d0e5f2d29e7d3374374dad2677f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 16:03:20 +0200 +Subject: pcnet32: stop holding device spin lock during napi_complete_done + +From: Oscar Maes + +[ Upstream commit 73bf3cca7de6a73f53b6a52dc3b1c82ae5667a4d ] + +napi_complete_done may call gro_flush_normal (though not currently, as GRO +is unsupported at the moment), which may result in packet TX. This will +eventually result in calling pcnet32_start_xmit - resulting in a deadlock +while trying to re-acquire the already locked spin lock. + +It is safe to split the spinlock block into two, because the hardware +registers are still protected from concurrent access, and the two blocks +perform unrelated operations that don't need to happen atomically. + +Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()") +Reviewed-by: Andrew Lunn +Signed-off-by: Oscar Maes +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/pcnet32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c +index 72db9f9e7beeae..81cb83caf62a15 100644 +--- a/drivers/net/ethernet/amd/pcnet32.c ++++ b/drivers/net/ethernet/amd/pcnet32.c +@@ -1403,8 +1403,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + pcnet32_restart(dev, CSR0_START); + netif_wake_queue(dev); + } ++ spin_unlock_irqrestore(&lp->lock, flags); + + if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a->read_csr(ioaddr, CSR3); + val &= 0x00ff; +@@ -1412,9 +1414,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + + /* Set interrupt enable. */ + lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN); ++ spin_unlock_irqrestore(&lp->lock, flags); + } + +- spin_unlock_irqrestore(&lp->lock, flags); + return work_done; + } + +-- +2.53.0 + diff --git a/queue-6.1/ptp-vclock-switch-from-rcu-to-srcu.patch b/queue-6.1/ptp-vclock-switch-from-rcu-to-srcu.patch new file mode 100644 index 0000000000..b1b3874b32 --- /dev/null +++ b/queue-6.1/ptp-vclock-switch-from-rcu-to-srcu.patch @@ -0,0 +1,85 @@ +From 7b283be128c82c8d41ab77f641af44db44e15d43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:11:47 +0200 +Subject: ptp: vclock: Switch from RCU to SRCU + +From: Kurt Kanzenbach + +[ Upstream commit 672bd0519e27c357c43b7f8c0d653fce3817d06e ] + +The usage of PTP vClocks leads immediately to the following issues with +ptp4l with LOCKDEP and DEBUG_ATOMIC_SLEEP enabled: "BUG: sleeping function +called from invalid context". + +ptp_convert_timestamp() acquires a mutex_t within a RCU read section. This +is illegal, because acquiring a mutex_t can result in voluntary scheduling +request which is not allowed within a RCU read section. + +Replace the RCU usage with SRCU where sleeping is allowed. + +Reported-by: Florian Zeitz +Closes: https://lore.kernel.org/all/00a8cce8-410e-4038-98af-49be6d93d7bd@schettke.com/ +Fixes: 67d93ffc0f3c ("ptp: vclock: use mutex to fix "sleep on atomic" bug") +Signed-off-by: Kurt Kanzenbach +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260529-vclock_rcu-v2-1-02a5531fab92@linutronix.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_vclock.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c +index dcf752c9e04506..eb57338a32414a 100644 +--- a/drivers/ptp/ptp_vclock.c ++++ b/drivers/ptp/ptp_vclock.c +@@ -19,6 +19,8 @@ static DEFINE_SPINLOCK(vclock_hash_lock); + + static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8); + ++DEFINE_STATIC_SRCU(vclock_srcu); ++ + static void ptp_vclock_hash_add(struct ptp_vclock *vclock) + { + spin_lock(&vclock_hash_lock); +@@ -37,7 +39,7 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock) + + spin_unlock(&vclock_hash_lock); + +- synchronize_rcu(); ++ synchronize_srcu(&vclock_srcu); + } + + static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +@@ -269,14 +271,16 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + { + unsigned int hash = vclock_index % HASH_SIZE(vclock_hash); + struct ptp_vclock *vclock; +- u64 ns; + u64 vclock_ns = 0; ++ int srcu_idx; ++ u64 ns; + + ns = ktime_to_ns(*hwtstamp); + +- rcu_read_lock(); ++ srcu_idx = srcu_read_lock(&vclock_srcu); + +- hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) { ++ hlist_for_each_entry_srcu(vclock, &vclock_hash[hash], vclock_hash_node, ++ srcu_read_lock_held(&vclock_srcu)) { + if (vclock->clock->index != vclock_index) + continue; + +@@ -287,7 +291,7 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + break; + } + +- rcu_read_unlock(); ++ srcu_read_unlock(&vclock_srcu, srcu_idx); + + return ns_to_ktime(vclock_ns); + } +-- +2.53.0 + diff --git a/queue-6.1/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch b/queue-6.1/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch new file mode 100644 index 0000000000..34dff6205b --- /dev/null +++ b/queue-6.1/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch @@ -0,0 +1,87 @@ +From 0b159fc6cf012d4af0609f7fecac6c45ab09b7a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:11:44 -0400 +Subject: sctp: purge outqueue on stale COOKIE-ECHO handling + +From: Xin Long + +[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ] + +sctp_stream_update() is only invoked when the association is moved into +COOKIE_WAIT during association setup/reconfiguration. In this path, the +outbound stream scheduler state (stream->out_curr) is expected to be +clean, since no user data should have been transmitted yet unless the +state machine has already partially progressed. + +However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a +Stale Cookie ERROR is received, the association is rolled back from +COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already +have been queued and even bundled with the COOKIE-ECHO chunk. + +During the rollback, sctp_stream_update() frees the old stream table +and installs a new one, but it does not invalidate stream->out_curr. +As a result, out_curr may still point to a freed sctp_stream_out +entry from the previous stream state. + +Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on +stream->out_curr->ext, which can lead to use-after-free once the old +stream state has been released via sctp_stream_free(). + +This results in crashes such as (reported by Yuqi): + + BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140 + Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312 + CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted + 7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full) + sctp_sched_fcfs_dequeue+0x13a/0x140 + sctp_outq_flush+0x1603/0x33e0 + sctp_do_sm+0x31c9/0x5d30 + sctp_assoc_bh_rcv+0x392/0x6f0 + sctp_inq_push+0x1db/0x270 + sctp_rcv+0x138d/0x3c10 + +Fix this by fully purging the association outqueue when handling the +Stale Cookie case. This ensures all pending transmit and retransmit +state is dropped, and any scheduler cached pointers are invalidated, +making it safe to rebuild stream state during COOKIE_WAIT restart. + +Updating only stream->out_curr would be insufficient, since queued +and retransmittable data would still reference the old stream state and +trigger later use-after-free in dequeue paths. + +Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Reported-by: Yuqi Xu +Reported-by: Ren Wei +Signed-off-by: Xin Long +Link: https://patch.msgid.link/94318159b9052907a6cbb7256aee8b5f8dfbfccb.1780510304.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 1685f73602d5e3..f5dc7822d220f2 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2599,11 +2599,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + +- /* If we've sent any data bundled with COOKIE-ECHO we will need to +- * resend +- */ +- sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, +- SCTP_TRANSPORT(asoc->peer.primary_path)); ++ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index b52eb86872..705032ff5d 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -191,3 +191,34 @@ bpf-free-reuseport-cbpf-prog-after-rcu-grace-period.patch usb-serial-mct_u232-fix-memory-corruption-with-small.patch dmaengine-idxd-fix-not-releasing-workqueue-on-.relea.patch disable-wattribute-alias-for-clang-23-and-newer.patch +tee-optee-prevent-use-after-free-when-the-client-exi.patch +netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch +ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch +netfilter-synproxy-add-mutex-to-guard-hook-reference.patch +netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch +netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch +dm-cache-policy-smq-check-allocation-under-invalidat.patch +net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch +6lowpan-fix-off-by-one-in-multicast-context-address-.patch +drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch +pcnet32-stop-holding-device-spin-lock-during-napi_co.patch +net-annotate-sk-sk_write_space-for-udp-sockmap.patch +net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch +net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch +net-fec-fix-pinctrl-default-state-restore-order-on-r.patch +bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch +bluetooth-mgmt-validate-advertising-tlv-before-type-.patch +bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch +bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch +bluetooth-bnep-reject-short-frames-before-parsing.patch +bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch +bluetooth-mgmt-fix-backward-compatibility-with-users.patch +ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch +ptp-vclock-switch-from-rcu-to-srcu.patch +octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch +vxlan-vnifilter-send-notification-on-vni-add.patch +vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch +ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch +ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch +net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch +sctp-purge-outqueue-on-stale-cookie-echo-handling.patch diff --git a/queue-6.1/tee-optee-prevent-use-after-free-when-the-client-exi.patch b/queue-6.1/tee-optee-prevent-use-after-free-when-the-client-exi.patch new file mode 100644 index 0000000000..0d063a36f1 --- /dev/null +++ b/queue-6.1/tee-optee-prevent-use-after-free-when-the-client-exi.patch @@ -0,0 +1,287 @@ +From a7533b9bc4c9575e33c510069be43f4ba018d49c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:24:06 -0800 +Subject: tee: optee: prevent use-after-free when the client exits before the + supplicant + +From: Amirreza Zarrabi + +[ Upstream commit 387a926ee166814611acecb960207fe2f3c4fd3e ] + +Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the +client wait as killable so it can be interrupted during shutdown or +after a supplicant crash. This changes the original lifetime expectations: +the client task can now terminate while the supplicant is still processing +its request. + +If the client exits first it removes the request from its queue and +kfree()s it, while the request ID remains in supp->idr. A subsequent +lookup on the supplicant path then dereferences freed memory, leading to +a use-after-free. + +Serialise access to the request with supp->mutex: + + * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while + looking up and touching the request. + * Let optee_supp_thrd_req() notice that the client has terminated and + signal optee_supp_send() accordingly. + +With these changes the request cannot be freed while the supplicant still +has a reference, eliminating the race. + +Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") +Signed-off-by: Amirreza Zarrabi +Tested-by: Ox Yeh +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/supp.c | 107 +++++++++++++++++++++++++++------------ + 1 file changed, 74 insertions(+), 33 deletions(-) + +diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c +index d0f397c9024201..2386bbd38ce78b 100644 +--- a/drivers/tee/optee/supp.c ++++ b/drivers/tee/optee/supp.c +@@ -10,7 +10,11 @@ + struct optee_supp_req { + struct list_head link; + ++ int id; ++ + bool in_queue; ++ bool processed; ++ + u32 func; + u32 ret; + size_t num_params; +@@ -19,6 +23,9 @@ struct optee_supp_req { + struct completion c; + }; + ++/* It is temporary request used for revoked pending request in supp->idr. */ ++#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) ++ + void optee_supp_init(struct optee_supp *supp) + { + memset(supp, 0, sizeof(*supp)); +@@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) + { + int id; + struct optee_supp_req *req; +- struct optee_supp_req *req_tmp; + + mutex_lock(&supp->mutex); + +- /* Abort all request retrieved by supplicant */ ++ /* Abort all request */ + idr_for_each_entry(&supp->idr, req, id) { + idr_remove(&supp->idr, id); +- req->ret = TEEC_ERROR_COMMUNICATION; +- complete(&req->c); +- } ++ /* Skip if request was already marked invalid */ ++ if (IS_ERR(req)) ++ continue; + +- /* Abort all queued requests */ +- list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { +- list_del(&req->link); +- req->in_queue = false; ++ /* For queued requests where supplicant has not seen it */ ++ if (req->in_queue) { ++ list_del(&req->link); ++ req->in_queue = false; ++ } ++ ++ req->processed = true; + req->ret = TEEC_ERROR_COMMUNICATION; + complete(&req->c); + } +@@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + + /* Insert the request in the request list */ + mutex_lock(&supp->mutex); ++ req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); ++ if (req->id < 0) { ++ mutex_unlock(&supp->mutex); ++ kfree(req); ++ return TEEC_ERROR_OUT_OF_MEMORY; ++ } ++ + list_add_tail(&req->link, &supp->reqs); + req->in_queue = true; ++ req->processed = false; + mutex_unlock(&supp->mutex); + + /* Tell an eventual waiter there's a new request */ +@@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + if (wait_for_completion_killable(&req->c)) { + mutex_lock(&supp->mutex); + if (req->in_queue) { ++ /* Supplicant has not seen this request yet. */ ++ idr_remove(&supp->idr, req->id); + list_del(&req->link); + req->in_queue = false; ++ ++ ret = TEEC_ERROR_COMMUNICATION; ++ } else if (req->processed) { ++ /* ++ * Supplicant has processed this request. Ignore the ++ * kill signal for now and submit the result. req is not ++ * in supp->reqs (removed by supp_pop_entry()) nor in ++ * supp->idr (removed by supp_pop_req()). ++ */ ++ ret = req->ret; ++ } else { ++ /* ++ * Supplicant is in the middle of processing this ++ * request. Replace req with INVALID_REQ_PTR so that ++ * the ID remains busy, causing optee_supp_send() to ++ * fail on the next call to supp_pop_req() with this ID. ++ */ ++ idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); ++ ret = TEEC_ERROR_COMMUNICATION; + } ++ + mutex_unlock(&supp->mutex); +- req->ret = TEEC_ERROR_COMMUNICATION; ++ } else { ++ ret = req->ret; + } + +- ret = req->ret; + kfree(req); + + return ret; + } + + static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, +- int num_params, int *id) ++ int num_params) + { + struct optee_supp_req *req; + +@@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, + return ERR_PTR(-EINVAL); + } + +- *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); +- if (*id < 0) +- return ERR_PTR(-ENOMEM); +- + list_del(&req->link); + req->in_queue = false; + +@@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + struct optee_supp_req *req = NULL; +- int id; + size_t num_meta; + int rc; + +@@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + + while (true) { + mutex_lock(&supp->mutex); +- req = supp_pop_entry(supp, *num_params - num_meta, &id); ++ req = supp_pop_entry(supp, *num_params - num_meta); ++ if (req) ++ break; /* Keep mutex held. */ + mutex_unlock(&supp->mutex); + +- if (req) { +- if (IS_ERR(req)) +- return PTR_ERR(req); +- break; +- } +- + /* + * If we didn't get a request we'll block in + * wait_for_completion() to avoid needless spinning. +@@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + return -ERESTARTSYS; + } + ++ /* supp->mutex held and req != NULL. */ ++ ++ if (IS_ERR(req)) { ++ mutex_unlock(&supp->mutex); ++ return PTR_ERR(req); ++ } ++ + if (num_meta) { + /* + * tee-supplicant support meta parameters -> requsts can be +@@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + */ + param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; +- param->u.value.a = id; ++ param->u.value.a = req->id; + param->u.value.b = 0; + param->u.value.c = 0; + } else { +- mutex_lock(&supp->mutex); +- supp->req_id = id; +- mutex_unlock(&supp->mutex); ++ supp->req_id = req->id; + } + + *func = req->func; +@@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + ++ mutex_unlock(&supp->mutex); + return 0; + } + +@@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, + if (!req) + return ERR_PTR(-ENOENT); + ++ /* optee_supp_thrd_req() already returned to optee. */ ++ if (IS_ERR(req)) ++ goto failed_req; ++ + if ((num_params - nm) != req->num_params) + return ERR_PTR(-EINVAL); + ++ *num_meta = nm; ++failed_req: + idr_remove(&supp->idr, id); + supp->req_id = -1; +- *num_meta = nm; + + return req; + } +@@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + + mutex_lock(&supp->mutex); + req = supp_pop_req(supp, num_params, param, &num_meta); +- mutex_unlock(&supp->mutex); +- + if (IS_ERR(req)) { +- /* Something is wrong, let supplicant restart. */ ++ mutex_unlock(&supp->mutex); ++ /* Something is wrong, let supplicant handel it. */ + return PTR_ERR(req); + } + +@@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + } + } + req->ret = ret; +- ++ req->processed = true; + /* Let the requesting thread continue */ + complete(&req->c); ++ mutex_unlock(&supp->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch b/queue-6.1/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch new file mode 100644 index 0000000000..e594ecb3be --- /dev/null +++ b/queue-6.1/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch @@ -0,0 +1,55 @@ +From 0a6687f0501158dd054feafaf4dd4d8a6da012f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:37 -0700 +Subject: vxlan: vnifilter: fix spurious notification on VNI update + +From: Andy Roulin + +[ Upstream commit 84683b5b60c7274e2c8f7f413d39d78d3db5540f ] + +When a VNI is re-added with the same attributes (e.g. same group or no +group), vxlan_vni_update() sends a spurious RTM_NEWTUNNEL notification +even though nothing changed. + +The bug is that 'if (changed)' tests whether the pointer is non-NULL, +not the bool value it points to. Since every caller passes a valid +pointer, the condition is always true and the notification fires +unconditionally. + +Fix by dereferencing the pointer: 'if (*changed)'. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 + # bridge vni add vni 1000 dev vxlan100 # spurious notification + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-3-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index ca866740a955d0..abf96d60eb30d5 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -671,7 +671,7 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan, + if (ret) + return ret; + +- if (changed) ++ if (*changed) + vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/vxlan-vnifilter-send-notification-on-vni-add.patch b/queue-6.1/vxlan-vnifilter-send-notification-on-vni-add.patch new file mode 100644 index 0000000000..8c1b434ea9 --- /dev/null +++ b/queue-6.1/vxlan-vnifilter-send-notification-on-vni-add.patch @@ -0,0 +1,69 @@ +From bd89c4769ddff8e567d5b52a1fb30dee09ee7886 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:36 -0700 +Subject: vxlan: vnifilter: send notification on VNI add + +From: Andy Roulin + +[ Upstream commit aa6ca1c5c338907817374b59f7551fd855a88754 ] + +When a new VNI is added to a vxlan device with vnifilter enabled, +no RTM_NEWTUNNEL notification is sent to userspace. This means +'bridge monitor vni' never shows VNI add events, even though +VNI delete events are reported correctly. + +The bug is in vxlan_vni_add(), where the notification is guarded by +'if (changed)'. The 'changed' flag is set by vxlan_vni_update_group() +only when the multicast group or remote IP is modified, but for a +new VNI added without a group (e.g. in L3 VxLAN interface scenarios), +the function returns early without setting changed=true. Since this +is a new VNI, the notification should be sent unconditionally. + +The notification is not guarded by the return value of +vxlan_vni_update_group() because, at this point, the VNI has already +been inserted into the hash table and list with no rollback on error. +The VNI will be visible in 'bridge vni show' regardless, so userspace +should be informed. This is consistent with vxlan_vni_del() which also +notifies unconditionally. + +The 'if (changed)' guard remains correct in vxlan_vni_update(), which +handles the case where a VNI already exists and is being re-added -- +there, we only want to notify if the group/remote actually changed. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 # no notification + # bridge vni delete vni 1000 dev vxlan100 # notification received + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Reported-by: Chirag Shah +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-2-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index c6d4fae958ca80..ca866740a955d0 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -769,8 +769,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, + err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed, + extack); + +- if (changed) +- vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); ++ vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return err; + } +-- +2.53.0 + diff --git a/queue-6.12/6lowpan-fix-off-by-one-in-multicast-context-address-.patch b/queue-6.12/6lowpan-fix-off-by-one-in-multicast-context-address-.patch new file mode 100644 index 0000000000..b0c625e336 --- /dev/null +++ b/queue-6.12/6lowpan-fix-off-by-one-in-multicast-context-address-.patch @@ -0,0 +1,67 @@ +From 1c4e9569df149491ee33428b3b1105826887a71a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:18:01 +0800 +Subject: 6lowpan: fix off-by-one in multicast context address compression + +From: Yizhou Zhao + +[ Upstream commit 2a58899d11009bffc7b4b32a571858f381121837 ] + +The second memcpy in lowpan_iphc_mcast_ctx_addr_compress() uses +&data[1] as destination and &ipaddr->s6_addr[11] as source, but +both should be offset by one: &data[2] and &ipaddr->s6_addr[12] +respectively. + +This off-by-one has two consequences: +1. data[1] is overwritten with s6_addr[11], corrupting the RIID + field in the compressed multicast address +2. data[5] is never written, so uninitialized kernel stack memory + is transmitted over the network via lowpan_push_hc_data(), + leaking kernel stack contents + +The correct inline data layout must match what the decompression +function lowpan_uncompress_multicast_ctx_daddr() expects: + data[0..1] = s6_addr[1..2] (flags/scope + RIID) + data[2..5] = s6_addr[12..15] (group ID) + +Also zero-initialize the data array as a defensive measure against +similar bugs in the future. + +Fixes: 5609c185f24d ("6lowpan: iphc: add support for stateful compression") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Acked-by: Alexander Aring +Link: https://patch.msgid.link/20260527081806.42747-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/6lowpan/iphc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c +index e116d308a8df6d..37eaff3f7b6940 100644 +--- a/net/6lowpan/iphc.c ++++ b/net/6lowpan/iphc.c +@@ -1086,12 +1086,12 @@ static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, + const struct lowpan_iphc_ctx *ctx, + const struct in6_addr *ipaddr) + { +- u8 data[6]; ++ u8 data[6] = {}; + + /* flags/scope, reserved (RIID) */ + memcpy(data, &ipaddr->s6_addr[1], 2); + /* group ID */ +- memcpy(&data[1], &ipaddr->s6_addr[11], 4); ++ memcpy(&data[2], &ipaddr->s6_addr[12], 4); + lowpan_push_hc_data(hc_ptr, data, 6); + + return LOWPAN_IPHC_DAM_00; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch b/queue-6.12/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch new file mode 100644 index 0000000000..38969713f4 --- /dev/null +++ b/queue-6.12/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch @@ -0,0 +1,71 @@ +From 15bcba5ce3ba4bb008cb056fbbc271df62669764 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:39:53 +0800 +Subject: Bluetooth: bnep: fix incorrect length parsing in bnep_rx_frame() + extension handling + +From: Dudu Lu + +[ Upstream commit 72b8deccff17a7644e0367e1aaf1a36cfb014324 ] + +In bnep_rx_frame(), the BNEP_FILTER_NET_TYPE_SET and +BNEP_FILTER_MULTI_ADDR_SET extension header parsing has two bugs: + +1) The 2-byte length field is read with *(u16 *)(skb->data + 1), which + performs a native-endian read. The BNEP protocol specifies this field + in big-endian (network byte order), and the same file correctly uses + get_unaligned_be16() for the identical fields in + bnep_ctrl_set_netfilter() and bnep_ctrl_set_mcfilter(). + +2) The length is multiplied by 2, but unlike BNEP_SETUP_CONN_REQ where + the length byte counts UUID pairs (requiring * 2 for two UUIDs per + entry), the filter extension length field already represents the total + data size in bytes. This is confirmed by bnep_ctrl_set_netfilter() + which reads the same field as a byte count and divides by 4 to get + the number of filter entries. + + The bogus * 2 means skb_pull advances twice as far as it should, + either dropping valid data from the next header or causing the pull + to fail entirely when the doubled length exceeds the remaining skb. + +Fix by splitting the pull into two steps: first use skb_pull_data() to +safely pull and validate the 3-byte fixed header (ctrl type + length), +then pull the variable-length data using the properly decoded length. + +Fixes: bf8b9a9cb77b ("Bluetooth: bnep: Add support to extended headers of control frames") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index b3cef7a4db5412..0de5df690bd0b2 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -330,11 +330,18 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + goto badframe; + break; + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: +- /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */ +- if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2)) ++ case BNEP_FILTER_NET_TYPE_SET: { ++ u8 *hdr; ++ ++ /* Pull ctrl type (1 b) + len (2 b) */ ++ hdr = skb_pull_data(skb, 3); ++ if (!hdr) ++ goto badframe; ++ /* Pull data (len bytes); length is big-endian */ ++ if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) + goto badframe; + break; ++ } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-bnep-reject-short-frames-before-parsing.patch b/queue-6.12/bluetooth-bnep-reject-short-frames-before-parsing.patch new file mode 100644 index 0000000000..aa44bc735b --- /dev/null +++ b/queue-6.12/bluetooth-bnep-reject-short-frames-before-parsing.patch @@ -0,0 +1,170 @@ +From 961c818b74013a279fe4f5335d89ce589e52f32e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 11:22:09 +0800 +Subject: Bluetooth: bnep: reject short frames before parsing + +From: Zhang Cen + +[ Upstream commit 6770d3a8acdf9151769180cc3710346c4cfbe6f0 ] + +A BNEP peer can send a short BNEP SDU. bnep_rx_frame() reads the +packet type byte immediately and, for control packets, reads the control +opcode and setup UUID-size byte before proving that those bytes are +present. bnep_rx_control() also dereferences the control opcode without +rejecting an empty control payload. + +Use skb_pull_data() for the fixed fields in bnep_rx_frame() so a NULL +return gates each dereference. Split the control handler so the frame +path can pass an opcode that has already been pulled, and keep the +byte-buffer wrapper for extension control payloads. + +For BNEP_SETUP_CONN_REQ, name the UUID-size byte before pulling the +setup payload. struct bnep_setup_conn_req carries destination and source +service UUIDs after that byte, each uuid_size bytes, so the parser now +documents that tuple explicitly instead of leaving the pull length as an +opaque multiplication. + +Validation reproduced this kernel report: +KASAN slab-out-of-bounds in bnep_rx_frame.isra.0+0x130c/0x1790 +The buggy address belongs to the object at ffff88800c0f7908 which belongs +to the cache kmalloc-8 of size 8 +The buggy address is located 0 bytes to the right of allocated 1-byte +region [ffff88800c0f7908, ffff88800c0f7909) +Read of size 1 +Call trace: + dump_stack_lvl+0xb3/0x140 (?:?) + print_address_description+0x57/0x3a0 (?:?) + bnep_rx_frame+0x130c/0x1790 (net/bluetooth/bnep/core.c:306) + print_report+0xb9/0x2b0 (?:?) + __virt_addr_valid+0x1ba/0x3a0 (?:?) + srso_alias_return_thunk+0x5/0xfbef5 (?:?) + kasan_addr_to_slab+0x21/0x60 (?:?) + kasan_report+0xe0/0x110 (?:?) + process_one_work+0xfce/0x17e0 (kernel/workqueue.c:3200) + worker_thread+0x65c/0xe40 (?:?) + __kthread_parkme+0x184/0x230 (?:?) + kthread+0x35e/0x470 (?:?) + _raw_spin_unlock_irq+0x28/0x50 (?:?) + ret_from_fork+0x586/0x870 (?:?) + __switch_to+0x74f/0xdc0 (?:?) + ret_from_fork_asm+0x1a/0x30 (?:?) + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 57 ++++++++++++++++++++++++--------------- + 1 file changed, 36 insertions(+), 21 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index 0de5df690bd0b2..5c5f53ff30e8e5 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -206,14 +206,11 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) + return 0; + } + +-static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++static int bnep_rx_control_cmd(struct bnep_session *s, u8 cmd, void *data, ++ int len) + { +- u8 cmd = *(u8 *)data; + int err = 0; + +- data++; +- len--; +- + switch (cmd) { + case BNEP_CMD_NOT_UNDERSTOOD: + case BNEP_SETUP_CONN_RSP: +@@ -254,6 +251,14 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) + return err; + } + ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ if (len < 1) ++ return -EILSEQ; ++ ++ return bnep_rx_control_cmd(s, *(u8 *)data, data + 1, len - 1); ++} ++ + static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) + { + struct bnep_ext_hdr *h; +@@ -299,19 +304,26 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + { + struct net_device *dev = s->dev; + struct sk_buff *nskb; ++ u8 *data; + u8 type, ctrl_type; + + dev->stats.rx_bytes += skb->len; + +- type = *(u8 *) skb->data; +- skb_pull(skb, 1); +- ctrl_type = *(u8 *)skb->data; ++ data = skb_pull_data(skb, sizeof(type)); ++ if (!data) ++ goto badframe; ++ type = *data; + + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) + goto badframe; + + if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { +- if (bnep_rx_control(s, skb->data, skb->len) < 0) { ++ data = skb_pull_data(skb, sizeof(ctrl_type)); ++ if (!data) ++ goto badframe; ++ ctrl_type = *data; ++ ++ if (bnep_rx_control_cmd(s, ctrl_type, skb->data, skb->len) < 0) { + dev->stats.tx_errors++; + kfree_skb(skb); + return 0; +@@ -324,24 +336,27 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + + /* Verify and pull ctrl message since it's already processed */ + switch (ctrl_type) { +- case BNEP_SETUP_CONN_REQ: +- /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */ +- if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2)) ++ case BNEP_SETUP_CONN_REQ: { ++ u8 uuid_size; ++ ++ /* Pull uuid_size and the dst/src service UUIDs. */ ++ data = skb_pull_data(skb, sizeof(uuid_size)); ++ if (!data) ++ goto badframe; ++ uuid_size = *data; ++ if (!skb_pull(skb, uuid_size + uuid_size)) + goto badframe; + break; ++ } + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: { +- u8 *hdr; +- +- /* Pull ctrl type (1 b) + len (2 b) */ +- hdr = skb_pull_data(skb, 3); +- if (!hdr) ++ case BNEP_FILTER_NET_TYPE_SET: ++ /* Pull: len (2 b), data (len bytes) */ ++ data = skb_pull_data(skb, sizeof(u16)); ++ if (!data) + goto badframe; +- /* Pull data (len bytes); length is big-endian */ +- if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) ++ if (!skb_pull(skb, get_unaligned_be16(data))) + goto badframe; + break; +- } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch b/queue-6.12/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch new file mode 100644 index 0000000000..d678121c7f --- /dev/null +++ b/queue-6.12/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch @@ -0,0 +1,58 @@ +From 34e0ccb47e3cdcf4b39ba32abfc0d8d5e5869d4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 08:54:26 +0530 +Subject: Bluetooth: fix memory leak in error path of hci_alloc_dev() + +From: Bharath Reddy + +[ Upstream commit 37b3009bf5976e8ab77c8b9a9bc3bbd7ff49e37f ] + +Early failures in Bluetooth HCI UART configuration leak SRCU percpu +memory. + +When device initialization fails before hci_register_dev() completes, +the HCI_UNREGISTER flag is never set. As a result, when the device +reference count reaches zero, bt_host_release() evaluates this flag as +false and falls back to a direct kfree(hdev). + +Because hci_release_dev() is bypassed, the SRCU struct initialized +early in hci_alloc_dev() is never cleaned up, resulting in a leak of +percpu memory. + +Fix the leak by explicitly calling cleanup_srcu_struct() in the +fallback (unregistered) branch of bt_host_release() before freeing +the device. + +Reported-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=535ecc844591e50588a5 +Tested-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Fixes: 1d6123102e9f ("Bluetooth: hci_core: Fix use-after-free in vhci_flush()") +Signed-off-by: Bharath Reddy +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sysfs.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c +index 4b54dbbf0729a3..60350c6723cb76 100644 +--- a/net/bluetooth/hci_sysfs.c ++++ b/net/bluetooth/hci_sysfs.c +@@ -83,10 +83,12 @@ static void bt_host_release(struct device *dev) + { + struct hci_dev *hdev = to_hci_dev(dev); + +- if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) ++ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + hci_release_dev(hdev); +- else ++ } else { ++ cleanup_srcu_struct(&hdev->srcu); + kfree(hdev); ++ } + module_put(THIS_MODULE); + } + +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch b/queue-6.12/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch new file mode 100644 index 0000000000..ad3011494c --- /dev/null +++ b/queue-6.12/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch @@ -0,0 +1,157 @@ +From 4999de8721dfb9b1e89baa6c551bd6a7570c8633 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 20:19:07 +0900 +Subject: Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls + +From: SeungJu Cheon + +[ Upstream commit 9ca7053d6215d89c33f28893bfd1625a32919d3f ] + +iso_connect_bis(), iso_connect_cis(), iso_listen_bis(), and +iso_conn_big_sync() call hci_get_route() using iso_pi(sk)->dst, +iso_pi(sk)->src, and iso_pi(sk)->src_type without holding lock_sock(). + +These fields may be modified concurrently by connect() or setsockopt() +on the same socket, resulting in data-races reported by KCSAN. + +Fix this by snapshotting the required fields under lock_sock() before +calling hci_get_route(). + +BUG: KCSAN: data-race in memcmp+0x45/0xb0 + +race at unknown origin, with read to 0xffff8880122135cf of 1 bytes +by task 333 on cpu 1: + memcmp+0x45/0xb0 + hci_get_route+0x27e/0x490 + iso_connect_cis+0x4c/0xa10 + iso_sock_connect+0x60e/0xb30 + __sys_connect_file+0xbd/0xe0 + __sys_connect+0xe0/0x110 + __x64_sys_connect+0x40/0x50 + x64_sys_call+0xcad/0x1c60 + do_syscall_64+0x133/0x590 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: 241f51931c35 ("Bluetooth: ISO: Avoid circular locking dependency") +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 60 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 44 insertions(+), 16 deletions(-) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index f9aa59c7ac0080..c0530442a94b9d 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -336,12 +336,20 @@ static int iso_connect_bis(struct sock *sk) + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type, bc_sid; + int err; + +- BT_DBG("%pMR (SID 0x%2.2x)", &iso_pi(sk)->src, iso_pi(sk)->bc_sid); ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ bc_sid = iso_pi(sk)->bc_sid; ++ release_sock(sk); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ BT_DBG("%pMR (SID 0x%2.2x)", &src, bc_sid); ++ ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -431,12 +439,19 @@ static int iso_connect_cis(struct sock *sk) + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type; + int err; + +- BT_DBG("%pMR -> %pMR", &iso_pi(sk)->src, &iso_pi(sk)->dst); ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ release_sock(sk); ++ ++ BT_DBG("%pMR -> %pMR", &src, &dst); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -1123,18 +1138,25 @@ static int iso_sock_connect(struct socket *sock, struct sockaddr *addr, + + static int iso_listen_bis(struct sock *sk) + { +- struct hci_dev *hdev; +- int err = 0; + struct iso_conn *conn; + struct hci_conn *hcon; ++ struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type, bc_sid; ++ int err = 0; ++ ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ bc_sid = iso_pi(sk)->bc_sid; ++ release_sock(sk); + +- BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src, +- &iso_pi(sk)->dst, iso_pi(sk)->bc_sid); ++ BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &src, &dst, bc_sid); + + write_lock(&iso_sk_list.lock); + +- if (__iso_get_sock_listen_by_sid(&iso_pi(sk)->src, &iso_pi(sk)->dst, +- iso_pi(sk)->bc_sid)) ++ if (__iso_get_sock_listen_by_sid(&src, &dst, bc_sid)) + err = -EADDRINUSE; + + write_unlock(&iso_sk_list.lock); +@@ -1142,8 +1164,7 @@ static int iso_listen_bis(struct sock *sk) + if (err) + return err; + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -1422,9 +1443,16 @@ static void iso_conn_big_sync(struct sock *sk) + { + int err; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type; ++ ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ release_sock(sk); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + + if (!hdev) + return; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch b/queue-6.12/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch new file mode 100644 index 0000000000..7254181938 --- /dev/null +++ b/queue-6.12/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch @@ -0,0 +1,36 @@ +From 37a890e21fa6e9bce10ce02177f7a4360d8555e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 14:45:42 -0400 +Subject: Bluetooth: ISO: Fix not releasing hdev reference on iso_conn_big_sync + +From: Luiz Augusto von Dentz + +[ Upstream commit 5cbf290b79351971f20c7a533247e8d58a3f970c ] + +hci_get_route() returns a reference-counted hci_dev pointer via +hci_dev_hold(). The function exits normally or with an error without ever +releasing it. + +Fixes: 07a9342b94a9 ("Bluetooth: ISO: Send BIG Create Sync via hci_sync") +Reported-by: Sashiko +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index f262c32da4f29b..935e230484b78c 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -1445,6 +1445,7 @@ static void iso_conn_big_sync(struct sock *sk) + + release_sock(sk); + hci_dev_unlock(hdev); ++ hci_dev_put(hdev); + } + + static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-iso-fix-not-using-bc_sid-as-advertisement-.patch b/queue-6.12/bluetooth-iso-fix-not-using-bc_sid-as-advertisement-.patch new file mode 100644 index 0000000000..40abe58120 --- /dev/null +++ b/queue-6.12/bluetooth-iso-fix-not-using-bc_sid-as-advertisement-.patch @@ -0,0 +1,333 @@ +From 29432e730d9bed25fd426c6d7c32fe4c635e41f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Jun 2025 14:32:49 -0400 +Subject: Bluetooth: ISO: Fix not using bc_sid as advertisement SID + +From: Luiz Augusto von Dentz + +[ Upstream commit 5842c01a9ed1d515c8ba2d6d3733eac78ace89c1 ] + +Currently bc_sid is being ignore when acting as Broadcast Source role, +so this fix it by passing the bc_sid and then use it when programming +the PA: + +< HCI Command: LE Set Exte.. (0x08|0x0036) plen 25 + Handle: 0x01 + Properties: 0x0000 + Min advertising interval: 140.000 msec (0x00e0) + Max advertising interval: 140.000 msec (0x00e0) + Channel map: 37, 38, 39 (0x07) + Own address type: Random (0x01) + Peer address type: Public (0x00) + Peer address: 00:00:00:00:00:00 (OUI 00-00-00) + Filter policy: Allow Scan Request from Any, Allow Connect Request from Any (0x00) + TX power: Host has no preference (0x7f) + Primary PHY: LE 1M (0x01) + Secondary max skip: 0x00 + Secondary PHY: LE 2M (0x02) + SID: 0x01 + Scan request notifications: Disabled (0x00) + +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: 9ca7053d6215 ("Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls") +Signed-off-by: Sasha Levin +--- + include/net/bluetooth/hci_core.h | 9 ++++++--- + include/net/bluetooth/hci_sync.h | 4 ++-- + net/bluetooth/hci_conn.c | 31 ++++++++++++++++++++++++------- + net/bluetooth/hci_core.c | 16 +++++++++++++++- + net/bluetooth/hci_sync.c | 20 +++++++++++++++++--- + net/bluetooth/iso.c | 12 ++++++++---- + 6 files changed, 72 insertions(+), 20 deletions(-) + +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index ba5d176069a692..a0c84a83f25eb1 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -244,6 +244,7 @@ struct adv_info { + __u8 mesh; + __u8 instance; + __u8 handle; ++ __u8 sid; + __u32 flags; + __u16 timeout; + __u16 remaining_time; +@@ -1576,13 +1577,14 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, + u16 timeout); + struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos); +-struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, ++struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, + struct bt_iso_qos *qos, + __u8 base_len, __u8 *base); + struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos); + struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, +- __u8 dst_type, struct bt_iso_qos *qos, ++ __u8 dst_type, __u8 sid, ++ struct bt_iso_qos *qos, + __u8 data_len, __u8 *data); + struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, __u8 sid, struct bt_iso_qos *qos); +@@ -1846,6 +1848,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + + void hci_adv_instances_clear(struct hci_dev *hdev); + struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance); ++struct adv_info *hci_find_adv_sid(struct hci_dev *hdev, u8 sid); + struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance); + struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, + u32 flags, u16 adv_data_len, u8 *adv_data, +@@ -1853,7 +1856,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, + u16 timeout, u16 duration, s8 tx_power, + u32 min_interval, u32 max_interval, + u8 mesh_handle); +-struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, ++struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, u8 sid, + u32 flags, u8 data_len, u8 *data, + u32 min_interval, u32 max_interval); + int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance, +diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h +index 17e5112f7840e0..4d3132a50ef058 100644 +--- a/include/net/bluetooth/hci_sync.h ++++ b/include/net/bluetooth/hci_sync.h +@@ -115,8 +115,8 @@ int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance); + int hci_enable_advertising_sync(struct hci_dev *hdev); + int hci_enable_advertising(struct hci_dev *hdev); + +-int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, +- u8 *data, u32 flags, u16 min_interval, ++int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 sid, ++ u8 data_len, u8 *data, u32 flags, u16 min_interval, + u16 max_interval, u16 sync_interval); + + int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance); +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index f89af453cb3b18..d34c66b92fbc1b 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -1494,8 +1494,8 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos) + + /* This function requires the caller holds hdev->lock */ + static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, +- struct bt_iso_qos *qos, __u8 base_len, +- __u8 *base) ++ __u8 sid, struct bt_iso_qos *qos, ++ __u8 base_len, __u8 *base) + { + struct hci_conn *conn; + int err; +@@ -1536,6 +1536,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, + return conn; + + conn->state = BT_CONNECT; ++ conn->sid = sid; + + hci_conn_hold(conn); + return conn; +@@ -2063,7 +2064,8 @@ static int create_big_sync(struct hci_dev *hdev, void *data) + if (qos->bcast.bis) + sync_interval = interval * 4; + +- err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->le_per_adv_data_len, ++ err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->sid, ++ conn->le_per_adv_data_len, + conn->le_per_adv_data, flags, interval, + interval, sync_interval); + if (err) +@@ -2148,7 +2150,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) + hci_conn_put(conn); + } + +-struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, ++struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, + struct bt_iso_qos *qos, + __u8 base_len, __u8 *base) + { +@@ -2170,7 +2172,7 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, + base, base_len); + + /* We need hci_conn object using the BDADDR_ANY as dst */ +- conn = hci_add_bis(hdev, dst, qos, base_len, eir); ++ conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir); + if (IS_ERR(conn)) + return conn; + +@@ -2221,20 +2223,35 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data) + } + + struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, +- __u8 dst_type, struct bt_iso_qos *qos, ++ __u8 dst_type, __u8 sid, ++ struct bt_iso_qos *qos, + __u8 base_len, __u8 *base) + { + struct hci_conn *conn; + int err; + struct iso_list_data data; + +- conn = hci_bind_bis(hdev, dst, qos, base_len, base); ++ conn = hci_bind_bis(hdev, dst, sid, qos, base_len, base); + if (IS_ERR(conn)) + return conn; + + if (conn->state == BT_CONNECTED) + return conn; + ++ /* Check if SID needs to be allocated then search for the first ++ * available. ++ */ ++ if (conn->sid == HCI_SID_INVALID) { ++ u8 sid; ++ ++ for (sid = 0; sid <= 0x0f; sid++) { ++ if (!hci_find_adv_sid(hdev, sid)) { ++ conn->sid = sid; ++ break; ++ } ++ } ++ } ++ + data.big = qos->bcast.big; + data.bis = qos->bcast.bis; + +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index 677f51edb27752..e96ccdd7ef15e7 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -1602,6 +1602,19 @@ struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance) + return NULL; + } + ++/* This function requires the caller holds hdev->lock */ ++struct adv_info *hci_find_adv_sid(struct hci_dev *hdev, u8 sid) ++{ ++ struct adv_info *adv; ++ ++ list_for_each_entry(adv, &hdev->adv_instances, list) { ++ if (adv->sid == sid) ++ return adv; ++ } ++ ++ return NULL; ++} ++ + /* This function requires the caller holds hdev->lock */ + struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) + { +@@ -1754,7 +1767,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, + } + + /* This function requires the caller holds hdev->lock */ +-struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, ++struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, u8 sid, + u32 flags, u8 data_len, u8 *data, + u32 min_interval, u32 max_interval) + { +@@ -1766,6 +1779,7 @@ struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, + if (IS_ERR(adv)) + return adv; + ++ adv->sid = sid; + adv->periodic = true; + adv->per_adv_data_len = data_len; + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 535fd7de9b1aec..fc9977c8c42705 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -1393,10 +1393,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) + hci_cpu_to_le24(adv->min_interval, cp.min_interval); + hci_cpu_to_le24(adv->max_interval, cp.max_interval); + cp.tx_power = adv->tx_power; ++ cp.sid = adv->sid; + } else { + hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval); + hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval); + cp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE; ++ cp.sid = 0x00; + } + + secondary_adv = (flags & MGMT_ADV_FLAG_SEC_MASK); +@@ -1730,8 +1732,8 @@ static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv) + return hci_update_adv_data_sync(hdev, adv->instance); + } + +-int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, +- u8 *data, u32 flags, u16 min_interval, ++int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 sid, ++ u8 data_len, u8 *data, u32 flags, u16 min_interval, + u16 max_interval, u16 sync_interval) + { + struct adv_info *adv = NULL; +@@ -1743,6 +1745,18 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, + if (instance) { + adv = hci_find_adv_instance(hdev, instance); + if (adv) { ++ if (sid != HCI_SID_INVALID && adv->sid != sid) { ++ /* If the SID don't match attempt to find by ++ * SID. ++ */ ++ adv = hci_find_adv_sid(hdev, sid); ++ if (!adv) { ++ bt_dev_err(hdev, ++ "Unable to find adv_info"); ++ return -EINVAL; ++ } ++ } ++ + /* Turn it into periodic advertising */ + adv->periodic = true; + adv->per_adv_data_len = data_len; +@@ -1751,7 +1765,7 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, + adv->flags = flags; + } else if (!adv) { + /* Create an instance if that could not be found */ +- adv = hci_add_per_instance(hdev, instance, flags, ++ adv = hci_add_per_instance(hdev, instance, sid, flags, + data_len, data, + sync_interval, + sync_interval); +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 935e230484b78c..f9aa59c7ac0080 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -338,7 +338,7 @@ static int iso_connect_bis(struct sock *sk) + struct hci_dev *hdev; + int err; + +- BT_DBG("%pMR", &iso_pi(sk)->src); ++ BT_DBG("%pMR (SID 0x%2.2x)", &iso_pi(sk)->src, iso_pi(sk)->bc_sid); + + hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, + iso_pi(sk)->src_type); +@@ -367,7 +367,7 @@ static int iso_connect_bis(struct sock *sk) + + /* Just bind if DEFER_SETUP has been set */ + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { +- hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, ++ hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid, + &iso_pi(sk)->qos, iso_pi(sk)->base_len, + iso_pi(sk)->base); + if (IS_ERR(hcon)) { +@@ -377,12 +377,16 @@ static int iso_connect_bis(struct sock *sk) + } else { + hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, + le_addr_type(iso_pi(sk)->dst_type), +- &iso_pi(sk)->qos, iso_pi(sk)->base_len, +- iso_pi(sk)->base); ++ iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, ++ iso_pi(sk)->base_len, iso_pi(sk)->base); + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); + goto unlock; + } ++ ++ /* Update SID if it was not set */ ++ if (iso_pi(sk)->bc_sid == HCI_SID_INVALID) ++ iso_pi(sk)->bc_sid = hcon->sid; + } + + conn = iso_conn_add(hcon); +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-mgmt-fix-backward-compatibility-with-users.patch b/queue-6.12/bluetooth-mgmt-fix-backward-compatibility-with-users.patch new file mode 100644 index 0000000000..11bc7c2e6c --- /dev/null +++ b/queue-6.12/bluetooth-mgmt-fix-backward-compatibility-with-users.patch @@ -0,0 +1,43 @@ +From 53b15a0dd39ec6642482ef7f26bce791fa3d0f33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:48:34 -0400 +Subject: Bluetooth: MGMT: Fix backward compatibility with userspace + +From: Luiz Augusto von Dentz + +[ Upstream commit 149324fc762c2a7acef9c26790566f81f475e51f ] + +bluetoothd has a bug with makes it send extra bytes as part of +MGMT_OP_ADD_EXT_ADV_DATA which are now being checked to be the +exact the expected length, relax this so only when the expected +length is greater than the data length to cause an error since +that would result in accessing invalid memory, otherwise just +ignore the extra bytes. + +Link: https://lore.kernel.org/linux-bluetooth/20260602204749.210857-1-luiz.dentz@gmail.com/T/#u +Fixes: d3f7d17960ed ("Bluetooth: MGMT: validate Add Extended Advertising Data length") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 040a5595f45fee..f494eda5cc81c1 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -9197,8 +9197,9 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data, + + BT_DBG("%s", hdev->name); + +- expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len); +- if (expected_len != data_len) ++ expected_len = struct_size(cp, data, cp->adv_data_len + ++ cp->scan_rsp_len); ++ if (expected_len > data_len) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_INVALID_PARAMS); + +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch b/queue-6.12/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch new file mode 100644 index 0000000000..e99357b1c9 --- /dev/null +++ b/queue-6.12/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch @@ -0,0 +1,73 @@ +From 3f65dd5340f9dc0c938815e011e8dc6e72f501dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 17:45:06 +0800 +Subject: Bluetooth: MGMT: validate advertising TLV before type checks + +From: Zhang Cen + +[ Upstream commit de23fb62259aa01d294f77238ae3b835eb674413 ] + +tlv_data_is_valid() reads each advertising data field length from +data[i], then inspects data[i + 1] for managed EIR types before +checking that the current field still fits inside the supplied buffer. + +A malformed field whose length byte is the last byte of the buffer can +therefore make the parser read one byte past the advertising data. + +KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING +request reached that path: + + BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid() + Read of size 1 + Call trace: + tlv_data_is_valid() + add_advertising() + hci_mgmt_cmd() + hci_sock_sendmsg() + +Move the existing element-length check before any type-octet inspection +so each non-empty element is proven to contain its type byte before the +parser looks at data[i + 1]. + +Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check") +Reviewed-by: Paul Menzel +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index a2bdf25a77aece..040a5595f45fee 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -8721,6 +8721,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (!cur_len) + continue; + ++ /* If the current field length would exceed the total data ++ * length, then it's invalid. ++ */ ++ if (i + cur_len >= len) ++ return false; ++ + if (data[i + 1] == EIR_FLAGS && + (!is_adv_data || flags_managed(adv_flags))) + return false; +@@ -8737,12 +8743,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (data[i + 1] == EIR_APPEARANCE && + appearance_managed(adv_flags)) + return false; +- +- /* If the current field length would exceed the total data +- * length, then it's invalid. +- */ +- if (i + cur_len >= len) +- return false; + } + + return true; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch b/queue-6.12/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch new file mode 100644 index 0000000000..0e312bd364 --- /dev/null +++ b/queue-6.12/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch @@ -0,0 +1,126 @@ +From 6a42518f30b2840b611340986a5feec20c3be95a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 15:56:41 +0800 +Subject: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() + +From: Zhang Cen + +[ Upstream commit 43c441edacf953b39517a44f5e5e10a93618b226 ] + +rfcomm_get_sock_by_channel() scans rfcomm_sk_list under the list lock, +but returns the selected listener after dropping that lock without +taking a reference. rfcomm_connect_ind() then locks the listener, +queues a child socket on it, and may notify it after unlocking it. + +The buggy scenario involves two paths, with each column showing the +order within that path: + +rfcomm_connect_ind(): listener close: + 1. Find parent in 1. close() enters + rfcomm_get_sock_by_channel() rfcomm_sock_release(). + 2. Drop rfcomm_sk_list.lock 2. rfcomm_sock_shutdown() + without pinning parent. closes the listener. + 3. Call lock_sock(parent) and 3. rfcomm_sock_kill() + bt_accept_enqueue(parent, unlinks and puts parent. + sk, true). + 4. Read parent flags and may 4. parent can be freed. + call sk_state_change(). + +If close wins the race, parent can be freed before +rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or the +deferred-setup callback. + +Take a reference on the listener before leaving rfcomm_sk_list.lock. +After lock_sock() succeeds, recheck that it is still in BT_LISTEN +before queueing a child, cache the deferred-setup bit while the parent +is locked, and drop the reference after the last parent use. + +KASAN reported a slab-use-after-free in lock_sock_nested() from +rfcomm_connect_ind(), with the freeing stack going through +rfcomm_sock_kill() and rfcomm_sock_release(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index 3052436e9c6de5..2286efef62f5b6 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) + } + + /* Find socket with channel and source bdaddr. +- * Returns closest match. ++ * Returns closest match with an extra reference held. + */ + static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) + { +@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t * + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ +- if (!bacmp(&rfcomm_pi(sk)->src, src)) ++ if (!bacmp(&rfcomm_pi(sk)->src, src)) { ++ sock_hold(sk); + break; ++ } + + /* Closest match */ +- if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) ++ if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) { ++ if (sk1) ++ sock_put(sk1); ++ + sk1 = sk; ++ sock_hold(sk1); ++ } + } + } + ++ if (sk && sk1) ++ sock_put(sk1); ++ + read_unlock(&rfcomm_sk_list.lock); + + return sk ? sk : sk1; +@@ -940,6 +950,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + { + struct sock *sk, *parent; + bdaddr_t src, dst; ++ bool defer_setup = false; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); +@@ -953,6 +964,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + + lock_sock(parent); + ++ if (parent->sk_state != BT_LISTEN) ++ goto done; ++ ++ defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -980,9 +996,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + done: + release_sock(parent); + +- if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) ++ if (defer_setup) + parent->sk_state_change(parent); + ++ sock_put(parent); ++ + return result; + } + +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch b/queue-6.12/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch new file mode 100644 index 0000000000..6197caa9bb --- /dev/null +++ b/queue-6.12/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch @@ -0,0 +1,167 @@ +From 5235f2c59d3d29f8d7013cbe22ed55e4a3b89b1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:04:43 +0900 +Subject: Bluetooth: RFCOMM: validate skb length in MCC handlers + +From: SeungJu Cheon + +[ Upstream commit 23882b828c3c8c51d0c946446a396b10abb3b16b ] + +The RFCOMM MCC handlers cast skb->data to protocol-specific structs +without validating skb->len first. A malicious remote device can send +truncated MCC frames and trigger out-of-bounds reads in these handlers. + +Fix this by using skb_pull_data() to validate and access the required +data before dereferencing it. + +rfcomm_recv_rpn() requires special handling since ETSI TS 07.10 allows +1-byte RPN requests. Handle this by validating only the DLCI byte first, +and validating the full struct only when len > 1. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Suggested-by: Muhammad Bilal +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/core.c | 67 +++++++++++++++++++++++++++---------- + 1 file changed, 49 insertions(+), 18 deletions(-) + +diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c +index ad5177e3a69b77..293bf67cf10d3e 100644 +--- a/net/bluetooth/rfcomm/core.c ++++ b/net/bluetooth/rfcomm/core.c +@@ -1431,10 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) + + static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_pn *pn; + struct rfcomm_dlc *d; +- u8 dlci = pn->dlci; ++ u8 dlci; ++ ++ pn = skb_pull_data(skb, sizeof(*pn)); ++ if (!pn) ++ return -EILSEQ; + ++ dlci = pn->dlci; + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) +@@ -1483,8 +1488,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + + static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) + { +- struct rfcomm_rpn *rpn = (void *) skb->data; +- u8 dlci = __get_dlci(rpn->dlci); ++ struct rfcomm_rpn *rpn; ++ u8 dlci; + + u8 bit_rate = 0; + u8 data_bits = 0; +@@ -1495,15 +1500,16 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + u8 xoff_char = 0; + u16 rpn_mask = RFCOMM_RPN_PM_ALL; + +- BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", +- dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, +- rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ if (len == 1) { ++ rpn = skb_pull_data(skb, 1); ++ if (!rpn) ++ return -EILSEQ; + +- if (!cr) +- return 0; ++ dlci = __get_dlci(rpn->dlci); ++ ++ if (!cr) ++ return 0; + +- if (len == 1) { +- /* This is a request, return default (according to ETSI TS 07.10) settings */ + bit_rate = RFCOMM_RPN_BR_9600; + data_bits = RFCOMM_RPN_DATA_8; + stop_bits = RFCOMM_RPN_STOP_1; +@@ -1514,6 +1520,19 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + goto rpn_out; + } + ++ rpn = skb_pull_data(skb, sizeof(*rpn)); ++ if (!rpn) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rpn->dlci); ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ + /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit, + * no parity, no flow control lines, normal XON/XOFF chars */ + +@@ -1589,9 +1608,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + + static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_rls *rls = (void *) skb->data; +- u8 dlci = __get_dlci(rls->dlci); ++ struct rfcomm_rls *rls; ++ u8 dlci; + ++ rls = skb_pull_data(skb, sizeof(*rls)); ++ if (!rls) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rls->dlci); + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) +@@ -1608,10 +1632,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_msc *msc; + struct rfcomm_dlc *d; +- u8 dlci = __get_dlci(msc->dlci); ++ u8 dlci; ++ ++ msc = skb_pull_data(skb, sizeof(*msc)); ++ if (!msc) ++ return -EILSEQ; + ++ dlci = __get_dlci(msc->dlci); + BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); + + d = rfcomm_dlc_get(s, dlci); +@@ -1644,17 +1673,19 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) + { +- struct rfcomm_mcc *mcc = (void *) skb->data; ++ struct rfcomm_mcc *mcc; + u8 type, cr, len; + ++ mcc = skb_pull_data(skb, sizeof(*mcc)); ++ if (!mcc) ++ return -EILSEQ; ++ + cr = __test_cr(mcc->type); + type = __get_mcc_type(mcc->type); + len = __get_mcc_len(mcc->len); + + BT_DBG("%p type 0x%x cr %d", s, type, cr); + +- skb_pull(skb, 2); +- + switch (type) { + case RFCOMM_PN: + rfcomm_recv_pn(s, cr, skb); +-- +2.53.0 + diff --git a/queue-6.12/devlink-release-nested-relation-on-devlink-free.patch b/queue-6.12/devlink-release-nested-relation-on-devlink-free.patch new file mode 100644 index 0000000000..f42ac8a6be --- /dev/null +++ b/queue-6.12/devlink-release-nested-relation-on-devlink-free.patch @@ -0,0 +1,49 @@ +From eb6ef0dddb7fa0b97f5e591f8a57d1b8a188890d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 22:14:10 +0300 +Subject: devlink: Release nested relation on devlink free + +From: Mark Bloch + +[ Upstream commit 3522b21fd7e1863d0734537737bd59f1b90d0190 ] + +devlink relation state is normally released from devl_unregister(), which +calls devlink_rel_put(). This misses devlink instances that get a nested +relation before registration and then fail probe before devl_register() is +reached. + +That flow can happen for SFs. The child devlink gets linked to its +parent before registration, then a later probe error calls devlink_free() +directly. Since the instance was never registered, devl_unregister() is not +called and devlink->rel is leaked. + +Release any pending relation from devlink_free() as well. The registered +path is unchanged because devl_unregister() already clears devlink->rel +before devlink_free() runs. + +Fixes: c137743bce02 ("devlink: introduce object and nested devlink relationship infra") +Signed-off-by: Mark Bloch +Reviewed-by: Jiri Pirko +Link: https://patch.msgid.link/20260528191411.3270532-1-mbloch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/devlink/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/devlink/core.c b/net/devlink/core.c +index 7203c39532fcc3..5f62fe5d2aa883 100644 +--- a/net/devlink/core.c ++++ b/net/devlink/core.c +@@ -469,6 +469,8 @@ void devlink_free(struct devlink *devlink) + { + ASSERT_DEVLINK_NOT_REGISTERED(devlink); + ++ devlink_rel_put(devlink); ++ + WARN_ON(!list_empty(&devlink->trap_policer_list)); + WARN_ON(!list_empty(&devlink->trap_group_list)); + WARN_ON(!list_empty(&devlink->trap_list)); +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-policy-smq-check-allocation-under-invalidat.patch b/queue-6.12/dm-cache-policy-smq-check-allocation-under-invalidat.patch new file mode 100644 index 0000000000..9e62ded068 --- /dev/null +++ b/queue-6.12/dm-cache-policy-smq-check-allocation-under-invalidat.patch @@ -0,0 +1,71 @@ +From 7cc42b60e028e84ed2da9ca60c9b876b647d4476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:57:45 +0800 +Subject: dm cache policy smq: check allocation under invalidate lock + +From: Guangshuo Li + +[ Upstream commit d3f0a606b9f278ece8a0df626ded9c4044071235 ] + +commit 2d1f7b65f5de ("dm cache policy smq: fix missing locks in +invalidating cache blocks") added mq->lock around the destructive part of +smq_invalidate_mapping(), but left the e->allocated check outside the +critical section. + +That leaves a check-then-act race. Two concurrent invalidators can both +observe e->allocated as true before either of them takes mq->lock. The +first invalidator that acquires the lock removes the entry from the +queues and hash table and then calls free_entry(), which clears +e->allocated and puts the entry back on the free list. The second +invalidator can then acquire mq->lock and continue with the stale result +of the unlocked check. + +This can corrupt the SMQ queues or hash table by deleting an entry that +is no longer on those structures. It can also hit the allocation check in +free_entry() when the same entry is freed again. + +Move the allocation check under mq->lock so the predicate and the +destructive operations are serialized by the same lock. + +Fixes: 2d1f7b65f5de ("dm cache policy smq: fix missing locks in invalidating cache blocks") +Signed-off-by: Guangshuo Li +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index d81a87142cacfa..5f48bcbdaf4351 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1590,18 +1590,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; +- +- if (!e->allocated) +- return -ENODATA; ++ int r = 0; + + spin_lock_irqsave(&mq->lock, flags); ++ if (!e->allocated) { ++ r = -ENODATA; ++ goto out; ++ } + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ ++out: + spin_unlock_irqrestore(&mq->lock, flags); + +- return 0; ++ return r; + } + + static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) +-- +2.53.0 + diff --git a/queue-6.12/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch b/queue-6.12/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch new file mode 100644 index 0000000000..73913fd156 --- /dev/null +++ b/queue-6.12/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch @@ -0,0 +1,53 @@ +From 28b8bb7cffae74a80146153caa47370e1334423d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 19:00:13 +0100 +Subject: drm/imx: Fix three kernel-doc warnings in dcss-scaler.c + +From: Yicong Hui + +[ Upstream commit ae0383e5a9a4b12d68c76c4769857def4665deff ] + +Fix the following W=1 kerneldoc warnings by adding the missing parameter +descriptions for @phase0_identity and @nn_interpolation in +dcss_scaler_filter_design() and @phase0_identity in +dcss_scaler_gaussian_filter() + +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:173 function parameter 'phase0_identity' not described in 'dcss_scaler_gaussian_filter' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'phase0_identity' not described in 'dcss_scaler_filter_design' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'nn_interpolation' not described in 'dcss_scaler_filter_design' + +Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") +Signed-off-by: Yicong Hui +Reviewed-by: Laurentiu Palcu +Link: https://patch.msgid.link/20260406180013.2442096-1-yiconghui@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/dcss/dcss-scaler.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +index 825728c356ffbe..eb81a4a57905a7 100644 +--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c ++++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +@@ -166,6 +166,7 @@ static int exp_approx_q(int x) + * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter. + * @fc_q: fixed-point cutoff frequency normalized to range [0, 1] + * @use_5_taps: indicates whether to use 5 taps or 7 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output filter coefficients + */ + static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, +@@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, + * @src_length: length of input + * @dst_length: length of output + * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output coefficients ++ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter + */ + static void dcss_scaler_filter_design(int src_length, int dst_length, + bool use_5_taps, bool phase0_identity, +-- +2.53.0 + diff --git a/queue-6.12/erofs-add-sysfs-node-to-drop-internal-caches.patch b/queue-6.12/erofs-add-sysfs-node-to-drop-internal-caches.patch new file mode 100644 index 0000000000..9628f5eda2 --- /dev/null +++ b/queue-6.12/erofs-add-sysfs-node-to-drop-internal-caches.patch @@ -0,0 +1,119 @@ +From e88f0809bbeb7a75baa767eb7708ff8510998a1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Nov 2024 21:11:48 -0700 +Subject: erofs: add sysfs node to drop internal caches + +From: Chunhai Guo + +[ Upstream commit db80b98305f73ca83891e4228ead5f0324118b00 ] + +Add a sysfs node to drop compression-related caches, currently used to +drop in-memory pclusters and cached compressed folios. + +Signed-off-by: Chunhai Guo +Reviewed-by: Gao Xiang +Link: https://lore.kernel.org/r/20241113041148.749129-1-guochunhai@vivo.com +Signed-off-by: Gao Xiang +Stable-dep-of: 1aee05e814d2 ("erofs: fix use-after-free on sbi->sync_decompress") +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-fs-erofs | 11 +++++++++++ + fs/erofs/internal.h | 2 ++ + fs/erofs/sysfs.c | 17 +++++++++++++++++ + fs/erofs/zdata.c | 1 - + 4 files changed, 30 insertions(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-fs-erofs b/Documentation/ABI/testing/sysfs-fs-erofs +index 284224d1b56fe1..b134146d735bc5 100644 +--- a/Documentation/ABI/testing/sysfs-fs-erofs ++++ b/Documentation/ABI/testing/sysfs-fs-erofs +@@ -16,3 +16,14 @@ Description: Control strategy of sync decompression: + readahead on atomic contexts only. + - 1 (force on): enable for readpage and readahead. + - 2 (force off): disable for all situations. ++ ++What: /sys/fs/erofs//drop_caches ++Date: November 2024 ++Contact: "Guo Chunhai" ++Description: Writing to this will drop compression-related caches, ++ currently used to drop in-memory pclusters and cached ++ compressed folios: ++ ++ - 1 : invalidate cached compressed folios ++ - 2 : drop in-memory pclusters ++ - 3 : drop in-memory pclusters and cached compressed folios +diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h +index 1c003412677ef6..24e01d9135c60d 100644 +--- a/fs/erofs/internal.h ++++ b/fs/erofs/internal.h +@@ -443,6 +443,8 @@ static inline void erofs_pagepool_add(struct page **pagepool, struct page *page) + void erofs_release_pages(struct page **pagepool); + + #ifdef CONFIG_EROFS_FS_ZIP ++#define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping) ++ + extern atomic_long_t erofs_global_shrink_cnt; + void erofs_shrinker_register(struct super_block *sb); + void erofs_shrinker_unregister(struct super_block *sb); +diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c +index 63cffd0fd26195..19d586273b7091 100644 +--- a/fs/erofs/sysfs.c ++++ b/fs/erofs/sysfs.c +@@ -10,6 +10,7 @@ + + enum { + attr_feature, ++ attr_drop_caches, + attr_pointer_ui, + attr_pointer_bool, + }; +@@ -57,11 +58,13 @@ static struct erofs_attr erofs_attr_##_name = { \ + + #ifdef CONFIG_EROFS_FS_ZIP + EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts); ++EROFS_ATTR_FUNC(drop_caches, 0200); + #endif + + static struct attribute *erofs_attrs[] = { + #ifdef CONFIG_EROFS_FS_ZIP + ATTR_LIST(sync_decompress), ++ ATTR_LIST(drop_caches), + #endif + NULL, + }; +@@ -163,6 +166,20 @@ static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr, + return -EINVAL; + *(bool *)ptr = !!t; + return len; ++#ifdef CONFIG_EROFS_FS_ZIP ++ case attr_drop_caches: ++ ret = kstrtoul(skip_spaces(buf), 0, &t); ++ if (ret) ++ return ret; ++ if (t < 1 || t > 3) ++ return -EINVAL; ++ ++ if (t & 2) ++ z_erofs_shrink_scan(sbi, ~0UL); ++ if (t & 1) ++ invalidate_mapping_pages(MNGD_MAPPING(sbi), 0, -1); ++ return len; ++#endif + } + return 0; + } +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index a81b6e6aee59ad..8192eb9b23bc7b 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -109,7 +109,6 @@ static inline unsigned int z_erofs_pclusterpages(struct z_erofs_pcluster *pcl) + return PAGE_ALIGN(pcl->pclustersize) >> PAGE_SHIFT; + } + +-#define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping) + static bool erofs_folio_is_managed(struct erofs_sb_info *sbi, struct folio *fo) + { + return fo->mapping == MNGD_MAPPING(sbi); +-- +2.53.0 + diff --git a/queue-6.12/erofs-fix-use-after-free-on-sbi-sync_decompress.patch b/queue-6.12/erofs-fix-use-after-free-on-sbi-sync_decompress.patch new file mode 100644 index 0000000000..c5f501e01c --- /dev/null +++ b/queue-6.12/erofs-fix-use-after-free-on-sbi-sync_decompress.patch @@ -0,0 +1,66 @@ +From c5ea0d1c9c4865af55344a839ed4f6e9e0c3f594 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:27:16 +0800 +Subject: erofs: fix use-after-free on sbi->sync_decompress + +From: Gao Xiang + +[ Upstream commit 1aee05e814d292064bf5fa15733741040cdc48ba ] + +z_erofs_decompress_kickoff() can race with filesystem unmount, causing +a use-after-free on sbi->sync_decompress. + +When I/O completes, z_erofs_endio() calls z_erofs_decompress_kickoff() +to queue z_erofs_decompressqueue_work() asynchronously. Then, after all +folios are unlocked, unmount workflow can proceed and sbi will be freed +before accessing to sbi->sync_decompress. + +Thread (unmount) I/O completion kworker + queue_work + z_erofs_decompressqueue_work + (all folios are unlocked) +cleanup_mnt + .. + erofs_kill_sb + erofs_sb_free + kfree(sbi) + access sbi->sync_decompress // UAF!! + +Fixes: 40452ffca3c1 ("erofs: add sysfs node to control sync decompression strategy") +Reported-by: syzbot+52bae5c495dbe261a0bc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=52bae5c495dbe261a0bc +Reviewed-by: Chao Yu +Reviewed-by: Jianan Huang +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index da421fe310df11..d625e3be9ec6ce 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1424,6 +1424,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + if (atomic_add_return(bios, &io->pending_bios)) + return; + if (z_erofs_in_atomic()) { ++ /* See `sync_decompress` in sysfs-fs-erofs for more details */ ++ if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) ++ sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + #ifdef CONFIG_EROFS_FS_PCPU_KTHREAD + struct kthread_worker *worker; + +@@ -1440,9 +1443,6 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + #else + queue_work(z_erofs_workqueue, &io->u.work); + #endif +- /* See `sync_decompress` in sysfs-fs-erofs for more details */ +- if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) +- sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + return; + } + gfp_flag = memalloc_noio_save(); +-- +2.53.0 + diff --git a/queue-6.12/erofs-tidy-up-synchronous-decompression.patch b/queue-6.12/erofs-tidy-up-synchronous-decompression.patch new file mode 100644 index 0000000000..4e60b60a1d --- /dev/null +++ b/queue-6.12/erofs-tidy-up-synchronous-decompression.patch @@ -0,0 +1,193 @@ +From f5be4014fefa035037f8e1aed49d051695c9efd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 11:43:30 +0800 +Subject: erofs: tidy up synchronous decompression + +From: Gao Xiang + +[ Upstream commit cc831ab33644088c1eef78936de24701014d520a ] + + - Get rid of `sbi->opt.max_sync_decompress_pages` since it's fixed as + 3 all the time; + + - Add Z_EROFS_MAX_SYNC_DECOMPRESS_BYTES in bytes instead of in pages, + since for non-4K pages, 3-page limitation makes no sense; + + - Move `sync_decompress` to sbi to avoid unexpected remount impact; + + - Fold z_erofs_is_sync_decompress() into its caller; + + - Better description of sysfs entry `sync_decompress`. + +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Stable-dep-of: 1aee05e814d2 ("erofs: fix use-after-free on sbi->sync_decompress") +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-fs-erofs | 14 ++++++---- + fs/erofs/internal.h | 5 +--- + fs/erofs/super.c | 3 +- + fs/erofs/sysfs.c | 2 +- + fs/erofs/zdata.c | 35 +++++++++--------------- + 5 files changed, 25 insertions(+), 34 deletions(-) + +diff --git a/Documentation/ABI/testing/sysfs-fs-erofs b/Documentation/ABI/testing/sysfs-fs-erofs +index b134146d735bc5..d76de22b6ef31c 100644 +--- a/Documentation/ABI/testing/sysfs-fs-erofs ++++ b/Documentation/ABI/testing/sysfs-fs-erofs +@@ -10,12 +10,16 @@ Description: Shows all enabled kernel features. + What: /sys/fs/erofs//sync_decompress + Date: November 2021 + Contact: "Huang Jianan" +-Description: Control strategy of sync decompression: ++Description: Control strategy of synchronous decompression. Synchronous ++ decompression tries to decompress in the reader thread for ++ synchronous reads and small asynchronous reads (<= 12 KiB): + +- - 0 (default, auto): enable for readpage, and enable for +- readahead on atomic contexts only. +- - 1 (force on): enable for readpage and readahead. +- - 2 (force off): disable for all situations. ++ - 0 (auto, default): apply to synchronous reads only, but will ++ switch to 1 (force on) if any decompression ++ request is detected in atomic contexts; ++ - 1 (force on): apply to synchronous reads and small ++ asynchronous reads; ++ - 2 (force off): disable synchronous decompression completely. + + What: /sys/fs/erofs//drop_caches + Date: November 2024 +diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h +index 24e01d9135c60d..89dfb3736daa41 100644 +--- a/fs/erofs/internal.h ++++ b/fs/erofs/internal.h +@@ -66,10 +66,6 @@ enum { + struct erofs_mount_opts { + /* current strategy of how to use managed cache */ + unsigned char cache_strategy; +- /* strategy of sync decompression (0 - auto, 1 - force on, 2 - force off) */ +- unsigned int sync_decompress; +- /* threshold for decompression synchronously */ +- unsigned int max_sync_decompress_pages; + unsigned int mount_opt; + }; + +@@ -123,6 +119,7 @@ struct erofs_sb_info { + /* managed XArray arranged in physical block number */ + struct xarray managed_pslots; + ++ unsigned int sync_decompress; /* strategy for sync decompression */ + unsigned int shrinker_run_no; + u16 available_compr_algs; + +diff --git a/fs/erofs/super.c b/fs/erofs/super.c +index bc968cf812bac4..1640ebc26ac9c4 100644 +--- a/fs/erofs/super.c ++++ b/fs/erofs/super.c +@@ -370,8 +370,7 @@ static void erofs_default_options(struct erofs_sb_info *sbi) + { + #ifdef CONFIG_EROFS_FS_ZIP + sbi->opt.cache_strategy = EROFS_ZIP_CACHE_READAROUND; +- sbi->opt.max_sync_decompress_pages = 3; +- sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_AUTO; ++ sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_AUTO; + #endif + #ifdef CONFIG_EROFS_FS_XATTR + set_opt(&sbi->opt, XATTR_USER); +diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c +index 19d586273b7091..3fbce0864a66f0 100644 +--- a/fs/erofs/sysfs.c ++++ b/fs/erofs/sysfs.c +@@ -57,7 +57,7 @@ static struct erofs_attr erofs_attr_##_name = { \ + #define ATTR_LIST(name) (&erofs_attr_##name.attr) + + #ifdef CONFIG_EROFS_FS_ZIP +-EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts); ++EROFS_ATTR_RW_UI(sync_decompress, erofs_sb_info); + EROFS_ATTR_FUNC(drop_caches, 0200); + #endif + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index 8192eb9b23bc7b..da421fe310df11 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -9,6 +9,7 @@ + #include + #include + ++#define Z_EROFS_MAX_SYNC_DECOMPRESS_BYTES 12288 + #define Z_EROFS_PCLUSTER_MAX_PAGES (Z_EROFS_PCLUSTER_MAX_SIZE / PAGE_SIZE) + #define Z_EROFS_INLINE_BVECS 2 + +@@ -1077,21 +1078,6 @@ static int z_erofs_scan_folio(struct z_erofs_frontend *f, + return err; + } + +-static bool z_erofs_is_sync_decompress(struct erofs_sb_info *sbi, +- unsigned int readahead_pages) +-{ +- /* auto: enable for read_folio, disable for readahead */ +- if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) && +- !readahead_pages) +- return true; +- +- if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_FORCE_ON) && +- (readahead_pages <= sbi->opt.max_sync_decompress_pages)) +- return true; +- +- return false; +-} +- + static bool z_erofs_page_is_invalidated(struct page *page) + { + return !page_folio(page)->mapping && !z_erofs_is_shortlived_page(page); +@@ -1454,9 +1440,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + #else + queue_work(z_erofs_workqueue, &io->u.work); + #endif +- /* enable sync decompression for readahead */ +- if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) +- sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; ++ /* See `sync_decompress` in sysfs-fs-erofs for more details */ ++ if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) ++ sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + return; + } + gfp_flag = memalloc_noio_save(); +@@ -1777,16 +1763,21 @@ static void z_erofs_submit_queue(struct z_erofs_frontend *f, + z_erofs_decompress_kickoff(q[JQ_SUBMIT], nr_bios); + } + +-static int z_erofs_runqueue(struct z_erofs_frontend *f, unsigned int rapages) ++static int z_erofs_runqueue(struct z_erofs_frontend *f, unsigned int rabytes) + { + struct z_erofs_decompressqueue io[NR_JOBQUEUES]; + struct erofs_sb_info *sbi = EROFS_I_SB(f->inode); +- bool force_fg = z_erofs_is_sync_decompress(sbi, rapages); ++ int syncmode = sbi->sync_decompress; ++ bool force_fg; + int err; + ++ force_fg = (syncmode == EROFS_SYNC_DECOMPRESS_AUTO && !rabytes) || ++ (syncmode == EROFS_SYNC_DECOMPRESS_FORCE_ON && ++ (rabytes <= Z_EROFS_MAX_SYNC_DECOMPRESS_BYTES)); ++ + if (f->head == Z_EROFS_PCLUSTER_TAIL) + return 0; +- z_erofs_submit_queue(f, io, &force_fg, !!rapages); ++ z_erofs_submit_queue(f, io, &force_fg, !!rabytes); + + /* handle bypass queue (no i/o pclusters) immediately */ + err = z_erofs_decompress_queue(&io[JQ_BYPASS], &f->pagepool); +@@ -1907,7 +1898,7 @@ static void z_erofs_readahead(struct readahead_control *rac) + z_erofs_pcluster_readmore(&f, rac, false); + z_erofs_pcluster_end(&f); + +- (void)z_erofs_runqueue(&f, nrpages); ++ (void)z_erofs_runqueue(&f, nrpages << PAGE_SHIFT); + erofs_put_metabuf(&f.map.buf); + erofs_release_pages(&f.pagepool); + } +-- +2.53.0 + diff --git a/queue-6.12/hsr-remove-warn_once-in-hsr_addr_is_self.patch b/queue-6.12/hsr-remove-warn_once-in-hsr_addr_is_self.patch new file mode 100644 index 0000000000..2d29efacd1 --- /dev/null +++ b/queue-6.12/hsr-remove-warn_once-in-hsr_addr_is_self.patch @@ -0,0 +1,109 @@ +From 5982f1924f07ceb926e9be9b13b7b77780d3d5f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 30 May 2026 06:42:58 +0000 +Subject: hsr: Remove WARN_ONCE() in hsr_addr_is_self(). + +From: Kuniyuki Iwashima + +[ Upstream commit afd0f17ca46258cec3a5cc48b8df9327fe772490 ] + +syzbot reported the warning [0] in hsr_addr_is_self(), +whose assumption is simply wrong. + +hsr->self_node is cleared in hsr_del_self_node(), which +is called from hsr_dellink(). + +Since dev->rtnl_link_ops->dellink() is called before +unregister_netdevice_many(), there is a window when +user can find the device but without hsr->self_node. + +Let's remove WARN_ONCE() in hsr_addr_is_self(). + +[0]: +HSR: No self node +WARNING: net/hsr/hsr_framereg.c:39 at hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39, CPU#0: syz.4.16848/17220 +Modules linked in: +CPU: 0 UID: 0 PID: 17220 Comm: syz.4.16848 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} +Tainted: [L]=SOFTLOCKUP +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 +RIP: 0010:hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39 +Code: 33 2f 41 0f b7 dd 89 ee 09 de 31 ff e8 c8 b4 c6 f6 09 dd 74 54 e8 0f b0 c6 f6 31 ed eb 53 e8 06 b0 c6 f6 48 8d 3d 2f 50 9c 04 <67> 48 0f b9 3a 31 ed eb 42 e8 c1 13 1f 00 89 c5 31 ff 89 c6 e8 96 +RSP: 0018:ffffc900041c70e0 EFLAGS: 00010283 +RAX: ffffffff8afdc6ca RBX: ffffffff8afdc4e6 RCX: 0000000000080000 +RDX: ffffc90010493000 RSI: 0000000000000948 RDI: ffffffff8f9a1700 +RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000 +R10: ffffc900041c71e8 R11: fffff52000838e3f R12: dffffc0000000000 +R13: ffff888041f9e3c0 R14: ffff888086ee3802 R15: 0000000000000000 +FS: 00007f6fe985d6c0(0000) GS:ffff888126176000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f80bd437dac CR3: 0000000025096000 CR4: 00000000003526f0 +DR0: ffffffffffffffff DR1: 00000000000001f8 DR2: 0000000000000002 +DR3: ffffffffefffff15 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +Call Trace: + + check_local_dest net/hsr/hsr_forward.c:592 [inline] + fill_frame_info net/hsr/hsr_forward.c:728 [inline] + hsr_forward_skb+0xa11/0x2a80 net/hsr/hsr_forward.c:739 + hsr_dev_xmit+0x253/0x370 net/hsr/hsr_device.c:236 + __netdev_start_xmit include/linux/netdevice.h:5368 [inline] + netdev_start_xmit include/linux/netdevice.h:5377 [inline] + xmit_one net/core/dev.c:3888 [inline] + dev_hard_start_xmit+0x2df/0x860 net/core/dev.c:3904 + __dev_queue_xmit+0x1428/0x3900 net/core/dev.c:4870 + neigh_output include/net/neighbour.h:556 [inline] + ip_finish_output2+0xcec/0x10b0 net/ipv4/ip_output.c:237 + ip_send_skb net/ipv4/ip_output.c:1510 [inline] + ip_push_pending_frames+0x8b/0x110 net/ipv4/ip_output.c:1530 + raw_sendmsg+0x1547/0x1a50 net/ipv4/raw.c:659 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x7da/0x9c0 net/socket.c:2698 + ___sys_sendmsg+0x2a5/0x360 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0x1c3/0x2a0 net/socket.c:2787 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f6feb62ce59 +Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 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 e8 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f6fe985d028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +RAX: ffffffffffffffda RBX: 00007f6feb8a6090 RCX: 00007f6feb62ce59 +RDX: 0000000000000000 RSI: 0000200000000000 RDI: 0000000000000004 +RBP: 00007f6feb6c2d6f R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 +R13: 00007f6feb8a6128 R14: 00007f6feb8a6090 R15: 00007ffcf01cc488 + + +Fixes: f266a683a480 ("net/hsr: Better frame dispatch") +Reported-by: syzbot+652670cf249077eb498b@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1a861e.b111c304.35cd64.0016.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260530064300.340793-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_framereg.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c +index 47faa8b4aaa901..2ba586cb829ff3 100644 +--- a/net/hsr/hsr_framereg.c ++++ b/net/hsr/hsr_framereg.c +@@ -52,10 +52,8 @@ bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr) + + rcu_read_lock(); + sn = rcu_dereference(hsr->self_node); +- if (!sn) { +- WARN_ONCE(1, "HSR: No self node\n"); ++ if (!sn) + goto out; +- } + + if (ether_addr_equal(addr, sn->macaddress_A) || + ether_addr_equal(addr, sn->macaddress_B)) +-- +2.53.0 + diff --git a/queue-6.12/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch b/queue-6.12/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch new file mode 100644 index 0000000000..e5814c446c --- /dev/null +++ b/queue-6.12/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch @@ -0,0 +1,56 @@ +From 25d7b310a797c7ad6b8e236adde87343b7d76159 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 07:29:55 +0000 +Subject: ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit() + +From: Eric Dumazet + +[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ] + +The aoe driver (or similar) generates a non-IPv6 packet +(e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() +on a 6LoWPAN interface (configured by the user or test case). + +Since the packet is not IPv6, the 6LoWPAN header_ops->create function +(lowpan_header_create or header_create) returns early without initializing +the lowpan_addr_info structure in the skb headroom. + +In the transmit function (lowpan_xmit), the driver calls lowpan_header +(or setup_header) which unconditionally copies and uses the lowpan_addr_info +from the headroom, which contains uninitialized data. + +Fix this by dropping non IPv6 packets. + +A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit(). + +Fixes: 4dc315e267fe ("ieee802154: 6lowpan: move transmit functionality") +Reported-by: syzbot+f13c19f75e1097abd116@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1fd763.278b5b03.2bcf39.0049.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260603072955.4032221-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ieee802154/6lowpan/tx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c +index 0c07662b44c0ca..4df76ff50699ed 100644 +--- a/net/ieee802154/6lowpan/tx.c ++++ b/net/ieee802154/6lowpan/tx.c +@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) + + pr_debug("package xmit\n"); + ++ if (skb->protocol != htons(ETH_P_IPV6)) { ++ kfree_skb(skb); ++ return NET_XMIT_DROP; ++ } ++ + WARN_ON_ONCE(skb->len > IPV6_MIN_MTU); + + /* We must take a copy of the skb before we modify/replace the ipv6 +-- +2.53.0 + diff --git a/queue-6.12/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch b/queue-6.12/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch new file mode 100644 index 0000000000..751efbb521 --- /dev/null +++ b/queue-6.12/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch @@ -0,0 +1,54 @@ +From 0c251db973e2f7e35577c6b084e41217f10a3a45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:15:47 +0000 +Subject: ipv4: restrict IPOPT_SSRR and IPOPT_LSRR options + +From: Eric Dumazet + +[ Upstream commit d3915a1f5a4bc0ac911032903c3c6ab8df9fcc7c ] + +This patch restricts setting Loose Source and Record Route (LSRR) +and Strict Source and Record Route (SSRR) IP options to users +with CAP_NET_RAW capability. + +This prevents unprivileged applications from forcing packets to route +through attacker-controlled nodes to leak TCP ISN and possibly other +protocol information. + +While LSRR and SSRR are commonly filtered in many network environments, +they may still be supported and forwarded along some network paths. + +RFC 7126 (Recommendations on Filtering of IPv4 Packets Containing +IPv4 Options) recommend to drop these options in 4.3 and 4.4. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260602161547.2642155-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_options.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index 3d154bc7e1f2e5..6527c3e88de36c 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -530,6 +530,10 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp, + kfree(opt); + return -EINVAL; + } ++ if (opt->opt.srr && !ns_capable(net->user_ns, CAP_NET_RAW)) { ++ kfree(opt); ++ return -EPERM; ++ } + kfree(*optp); + *optp = opt; + return 0; +-- +2.53.0 + diff --git a/queue-6.12/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch b/queue-6.12/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch new file mode 100644 index 0000000000..e3796f91d9 --- /dev/null +++ b/queue-6.12/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch @@ -0,0 +1,107 @@ +From f9ac9192b424b7eab8e2819013c2d9a82cb473d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 13:18:11 +0300 +Subject: ipv6: mcast: Fix use-after-free when processing MLD queries + +From: Ido Schimmel + +[ Upstream commit 791c91dc7a9dfb2457d5e29b8216a6484b9c4b40 ] + +When processing an MLD query, a pointer to the multicast group address +is retrieved when initially parsing the packet. This pointer is later +dereferenced without being reloaded despite the fact that the skb header +might have been reallocated following the pskb_may_pull() calls, leading +to a use-after-free [1]. + +Fix by copying the multicast group address when the packet is initially +parsed. + +[1] +BUG: KASAN: slab-use-after-free in __mld_query_work (net/ipv6/mcast.c:1512) +Read of size 8 at addr ffff8881154b8e90 by task kworker/4:1/118 + +Workqueue: mld mld_query_work +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +print_address_description.constprop.0 (mm/kasan/report.c:378) +print_report (mm/kasan/report.c:482) +kasan_report (mm/kasan/report.c:595) +__mld_query_work (net/ipv6/mcast.c:1512) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + + +[...] + +Freed by task 118: +kasan_save_stack (mm/kasan/common.c:57) +kasan_save_track (mm/kasan/common.c:78) +kasan_save_free_info (mm/kasan/generic.c:584) +__kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285) +kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566) +pskb_expand_head (net/core/skbuff.c:2335) +__pskb_pull_tail (net/core/skbuff.c:2878 (discriminator 4)) +__mld_query_work (net/ipv6/mcast.c:1495 (discriminator 1)) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + +Fixes: 97300b5fdfe2 ("[MCAST] IPv6: Check packet size when process Multicast") +Reported-by: Leo Lin +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260603101811.612594-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index e2a11a2f3b255d..b769e856a068d2 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1393,9 +1393,9 @@ void igmp6_event_query(struct sk_buff *skb) + static void __mld_query_work(struct sk_buff *skb) + { + struct mld2_query *mlh2 = NULL; +- const struct in6_addr *group; + unsigned long max_delay; + struct inet6_dev *idev; ++ struct in6_addr group; + struct ifmcaddr6 *ma; + struct mld_msg *mld; + int group_type; +@@ -1427,8 +1427,8 @@ static void __mld_query_work(struct sk_buff *skb) + goto kfree_skb; + + mld = (struct mld_msg *)icmp6_hdr(skb); +- group = &mld->mld_mca; +- group_type = ipv6_addr_type(group); ++ group = mld->mld_mca; ++ group_type = ipv6_addr_type(&group); + + if (group_type != IPV6_ADDR_ANY && + !(group_type&IPV6_ADDR_MULTICAST)) +@@ -1478,7 +1478,7 @@ static void __mld_query_work(struct sk_buff *skb) + } + } else { + for_each_mc_mclock(idev, ma) { +- if (!ipv6_addr_equal(group, &ma->mca_addr)) ++ if (!ipv6_addr_equal(&group, &ma->mca_addr)) + continue; + if (ma->mca_flags & MAF_TIMER_RUNNING) { + /* gsquery <- gsquery && mark */ +-- +2.53.0 + diff --git a/queue-6.12/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch b/queue-6.12/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch new file mode 100644 index 0000000000..2d87231e62 --- /dev/null +++ b/queue-6.12/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch @@ -0,0 +1,127 @@ +From a8b1f2e2024fc33ea8dab38f20ed5b7832dd6cf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 07:07:44 +0300 +Subject: ipvs: clear the svc scheduler ptr early on edit + +From: Julian Anastasov + +[ Upstream commit 193989cc6d80dd8e0460fb3992e69fa03bf0ff9b ] + +ip_vs_edit_service() while unbinding the old scheduler clears +the svc->scheduler ptr after the scheduler module initiates +RCU callbacks. This can cause packets to use the old +scheduler at the time when svc->sched_data is already freed +after RCU grace period. + +Fix it by clearing the ptr early in ip_vs_unbind_scheduler(), +before the done_service method schedules any RCU callbacks. + +Also, if the new scheduler fails to initialize when replacing +the old scheduler, try to restore the old scheduler while still +returning the error code. + +Link: https://sashiko.dev/#/patchset/20260519015506.634185-1-rosenp%40gmail.com +Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed") +Signed-off-by: Julian Anastasov +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/ip_vs.h | 3 +-- + net/netfilter/ipvs/ip_vs_ctl.c | 13 ++++++++----- + net/netfilter/ipvs/ip_vs_sched.c | 14 +++++++------- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +index ff406ef4fd4aab..d70268cf1af82e 100644 +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -1506,8 +1506,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched); ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc); + struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); + void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); + struct ip_vs_conn * +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index efa845ce616d9c..fb638758594d51 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -1496,7 +1496,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, + if (ret_hooks >= 0) + ip_vs_unregister_hooks(ipvs, u->af); + if (svc != NULL) { +- ip_vs_unbind_scheduler(svc, sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_service_free(svc); + } + ip_vs_scheduler_put(sched); +@@ -1558,9 +1558,8 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + old_sched = rcu_dereference_protected(svc->scheduler, 1); + if (sched != old_sched) { + if (old_sched) { +- ip_vs_unbind_scheduler(svc, old_sched); +- RCU_INIT_POINTER(svc->scheduler, NULL); +- /* Wait all svc->sched_data users */ ++ ip_vs_unbind_scheduler(svc); ++ /* Wait all svc->scheduler/sched_data users */ + synchronize_rcu(); + } + /* Bind the new scheduler */ +@@ -1568,6 +1567,10 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + ret = ip_vs_bind_scheduler(svc, sched); + if (ret) { + ip_vs_scheduler_put(sched); ++ /* Try to restore the old_sched */ ++ if (old_sched && ++ !ip_vs_bind_scheduler(svc, old_sched)) ++ old_sched = NULL; + goto out; + } + } +@@ -1624,7 +1627,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup) + + /* Unbind scheduler */ + old_sched = rcu_dereference_protected(svc->scheduler, 1); +- ip_vs_unbind_scheduler(svc, old_sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_scheduler_put(old_sched); + + /* Unbind persistence engine, keep svc->pe */ +diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c +index d4903723be7e90..49b2e5d2b2c837 100644 +--- a/net/netfilter/ipvs/ip_vs_sched.c ++++ b/net/netfilter/ipvs/ip_vs_sched.c +@@ -57,19 +57,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, + /* + * Unbind a service with its scheduler + */ +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched) ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc) + { +- struct ip_vs_scheduler *cur_sched; ++ struct ip_vs_scheduler *sched; + +- cur_sched = rcu_dereference_protected(svc->scheduler, 1); +- /* This check proves that old 'sched' was installed */ +- if (!cur_sched) ++ sched = rcu_dereference_protected(svc->scheduler, 1); ++ if (!sched) + return; + ++ /* Reset the scheduler before initiating any RCU callbacks */ ++ rcu_assign_pointer(svc->scheduler, NULL); ++ smp_wmb(); /* paired with smp_rmb() in ip_vs_schedule() */ + if (sched->done_service) + sched->done_service(svc); +- /* svc->scheduler can be set to NULL only by caller */ + } + + +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch b/queue-6.12/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch new file mode 100644 index 0000000000..ac63918636 --- /dev/null +++ b/queue-6.12/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch @@ -0,0 +1,75 @@ +From ecece5221c7a01e559789a22fa378f9626230eb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 00:00:00 +0000 +Subject: ksmbd: fix NULL-deref of opinfo->conn in oplock/lease break notifiers + +From: Gil Portnoy + +[ Upstream commit b003086d76968298f22e7cf62239833b5a3a06b1 ] + +smb2_oplock_break_noti() and smb2_lease_break_noti() read opinfo->conn +into a local with neither READ_ONCE() nor a NULL check. Both run from +oplock_break() after opinfo_get_list() has dropped ci->m_lock, so a +concurrent SMB2 LOGOFF (session_fd_check()) can set op->conn = NULL +under ci->m_lock within that window. ksmbd_conn_r_count_inc(conn) then +writes through NULL at offset 0xc4 -- a remotely triggerable oops. + +Guard both reads the way compare_guid_key() already does: read +opinfo->conn with READ_ONCE() and return early if it is NULL, before +allocating the work struct so nothing leaks. A NULL conn means the +client is gone and the break is moot, so return 0; oplock_break() treats +that as success and runs the normal teardown. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Assisted-by: Henry (Claude):claude-opus-4 +Signed-off-by: Gil Portnoy +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/oplock.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index a84c01bceb8ba2..6454c7a4baa450 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -714,11 +714,16 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) + */ + static int smb2_oplock_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct oplock_break_info *br_info; + int ret = 0; +- struct ksmbd_work *work = ksmbd_alloc_work_struct(); ++ struct ksmbd_work *work; ++ ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; + ++ work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; + +@@ -818,11 +823,15 @@ static void __smb2_lease_break_noti(struct work_struct *wk) + */ + static int smb2_lease_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct ksmbd_work *work; + struct lease_break_info *br_info; + struct lease *lease = opinfo->o_lease; + ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; ++ + work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.12/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch b/queue-6.12/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch new file mode 100644 index 0000000000..5831392c9f --- /dev/null +++ b/queue-6.12/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch @@ -0,0 +1,176 @@ +From b9866e7da1744a2e8c0aeb89a2429248b5f818ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:36:29 +0000 +Subject: l2tp: pppol2tp: hold reference to session in pppol2tp_ioctl() + +From: Lee Jones + +[ Upstream commit a213a8950414c684999dcf03edeea6c46ede172e ] + +pppol2tp_ioctl() read sock->sk->sk_user_data directly without any +locks or reference counting. If a controllable sleep was induced during +copy_from_user() (e.g. via a userfaultfd page fault sleep), a concurrent +socket close could trigger pppol2tp_session_close() asynchronously. This +frees the l2tp_session structure via the l2tp_session_del_work workqueue. +Upon resuming, the ioctl thread dereferences the stale session pointer, +resulting in a Use-After-Free (UAF). + +Fix this by securely fetching the session reference using the RCU-safe, +refcounted helper pppol2tp_sock_to_session(sk) on entry. This locks the +session's refcount across the sleep. We structured the function to exit +via standard err breaks, guaranteeing that l2tp_session_put() is cleanly +called on all return paths to drop the reference. + +To preserve existing behavior we validate the session and its magic +signature only for the specific L2TP commands that require it. This +ensures that generic/unknown ioctls called on an unconnected socket +still return -ENOIOCTLCMD and correctly fall back to generic handlers +(e.g. in sock_do_ioctl()). + +Signed-off-by: Lee Jones +Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") +Link: https://patch.msgid.link/20260527133630.2120612-1-lee@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/l2tp/l2tp_ppp.c | 82 +++++++++++++++++++++++++++------------------ + 1 file changed, 50 insertions(+), 32 deletions(-) + +diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c +index 16c514f628eaca..bf78edee1ef8a7 100644 +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -1043,64 +1043,76 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, + { + struct pppol2tp_ioc_stats stats; + struct l2tp_session *session; ++ int err = 0; ++ ++ session = pppol2tp_sock_to_session(sock->sk); + ++ /* Validate session presence and magic integrity ONLY for commands ++ * that belong to L2TP and require a valid session. ++ */ + switch (cmd) { + case PPPIOCGMRU: + case PPPIOCGFLAGS: +- session = sock->sk->sk_user_data; ++ case PPPIOCSMRU: ++ case PPPIOCSFLAGS: ++ case PPPIOCGL2TPSTATS: + if (!session) + return -ENOTCONN; + +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) ++ if (session->magic != L2TP_SESSION_MAGIC) { ++ l2tp_session_put(session); + return -EBADF; ++ } ++ break; ++ default: ++ break; ++ } + ++ switch (cmd) { ++ case PPPIOCGMRU: ++ case PPPIOCGFLAGS: + /* Not defined for tunnels */ +- if (!session->session_id && !session->peer_session_id) +- return -ENOSYS; ++ if (!session->session_id && !session->peer_session_id) { ++ err = -ENOSYS; ++ break; ++ } + +- if (put_user(0, (int __user *)arg)) +- return -EFAULT; ++ if (put_user(0, (int __user *)arg)) { ++ err = -EFAULT; ++ break; ++ } + break; + + case PPPIOCSMRU: + case PPPIOCSFLAGS: +- session = sock->sk->sk_user_data; +- if (!session) +- return -ENOTCONN; +- +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) +- return -EBADF; +- + /* Not defined for tunnels */ +- if (!session->session_id && !session->peer_session_id) +- return -ENOSYS; ++ if (!session->session_id && !session->peer_session_id) { ++ err = -ENOSYS; ++ break; ++ } + +- if (!access_ok((int __user *)arg, sizeof(int))) +- return -EFAULT; ++ if (!access_ok((int __user *)arg, sizeof(int))) { ++ err = -EFAULT; ++ break; ++ } + break; + + case PPPIOCGL2TPSTATS: +- session = sock->sk->sk_user_data; +- if (!session) +- return -ENOTCONN; +- +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) +- return -EBADF; +- + /* Session 0 represents the parent tunnel */ + if (!session->session_id && !session->peer_session_id) { + u32 session_id; +- int err; + + if (copy_from_user(&stats, (void __user *)arg, +- sizeof(stats))) +- return -EFAULT; ++ sizeof(stats))) { ++ err = -EFAULT; ++ break; ++ } + + session_id = stats.session_id; + err = pppol2tp_tunnel_copy_stats(&stats, + session->tunnel); + if (err < 0) +- return err; ++ break; + + stats.session_id = session_id; + } else { +@@ -1110,15 +1122,21 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, + stats.tunnel_id = session->tunnel->tunnel_id; + stats.using_ipsec = l2tp_tunnel_uses_xfrm(session->tunnel); + +- if (copy_to_user((void __user *)arg, &stats, sizeof(stats))) +- return -EFAULT; ++ if (copy_to_user((void __user *)arg, &stats, sizeof(stats))) { ++ err = -EFAULT; ++ break; ++ } + break; + + default: +- return -ENOIOCTLCMD; ++ err = -ENOIOCTLCMD; ++ break; + } + +- return 0; ++ if (session) ++ l2tp_session_put(session); ++ ++ return err; + } + + /***************************************************************************** +-- +2.53.0 + diff --git a/queue-6.12/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch b/queue-6.12/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch new file mode 100644 index 0000000000..cfe340a0d7 --- /dev/null +++ b/queue-6.12/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch @@ -0,0 +1,79 @@ +From 0302e6f01dbc3950a6c84e5ea700535c49ea4d6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:00:13 +0800 +Subject: net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr + +From: Yizhou Zhao + +[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ] + +In mrp_pdu_parse_vecattr(), vector attribute events are encoded three +per byte and valen tracks the number of events left to process. + +The parser decrements valen after processing the first and second events +from each event byte, but not after processing the third one. When valen +is exactly a multiple of three, the loop continues after the last valid +event and consumes the next byte as a new event byte, applying a +spurious event to the MRP applicant state. + +Additionally, when valen is zero the parser unconditionally consumes +attrlen bytes as FirstValue and advances the offset, even though per +IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of +zero and no FirstValue or Vector fields. This corrupts the offset for +subsequent PDU parsing. + +Also, when valen exceeds three the loop crosses byte boundaries but +the attribute value is not incremented between the last event of one +byte and the first event of the next. This causes the first event of +the next byte to use the same attribute value as the third event +rather than the next consecutive value. + +Decrement valen after processing the third event, skip FirstValue +consumption when valen is zero, and increment the attribute value at +the end of each loop iteration. + +Fixes: febf018d2234 ("net/802: Implement Multiple Registration Protocol (MRP)") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Link: https://patch.msgid.link/20260603060016.21522-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/mrp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/802/mrp.c b/net/802/mrp.c +index e0c96d0da8d599..8d08ace05fb8e8 100644 +--- a/net/802/mrp.c ++++ b/net/802/mrp.c +@@ -703,6 +703,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) & + MRP_VECATTR_HDR_LEN_MASK); + ++ /* If valen is 0, only a LeaveAllEvent is present; FirstValue and ++ * Vector fields are absent per IEEE 802.1ak. ++ */ ++ if (valen == 0) ++ return 0; ++ + /* The VectorAttribute structure in a PDU carries event information + * about one or more attributes having consecutive values. Only the + * value for the first attribute is contained in the structure. So +@@ -753,6 +759,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + vaevents %= __MRP_VECATTR_EVENT_MAX; + vaevent = vaevents; + mrp_pdu_parse_vecattr_event(app, skb, vaevent); ++ valen--; ++ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue, ++ mrp_cb(skb)->mh->attrlen); + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/net-annotate-sk-sk_write_space-for-udp-sockmap.patch b/queue-6.12/net-annotate-sk-sk_write_space-for-udp-sockmap.patch new file mode 100644 index 0000000000..b42b19659a --- /dev/null +++ b/queue-6.12/net-annotate-sk-sk_write_space-for-udp-sockmap.patch @@ -0,0 +1,60 @@ +From a846df0ff882ce383c5d90ef82d8419b4b7c24fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:39:23 +0000 +Subject: net: Annotate sk->sk_write_space() for UDP SOCKMAP. + +From: Kuniyuki Iwashima + +[ Upstream commit b748765019fe9e9234660327090fc1a9665cdbdd ] + +UDP TX skb->destructor() is sock_wfree(), and UDP holds lock_sock() +only for UDP_CORK / MSG_MORE sendmsg(). + +Otherwise, sk->sk_write_space() may be read locklessly while SOCKMAP +rewrites sk->sk_write_space(). + +Let's use WRITE_ONCE() and READ_ONCE() for sk->sk_write_space(). + +Note that the write side is annotated by commit 2ef2b20cf4e0 +("net: annotate data-races around sk->sk_{data_ready,write_space}"). + +Fixes: 7b98cd42b049 ("bpf: sockmap: Add UDP support") +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Jakub Sitnicki +Link: https://patch.msgid.link/20260529193941.3897256-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 58f3f0d979540f..7b6ed7c85a58cc 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2591,8 +2591,12 @@ void sock_wfree(struct sk_buff *skb) + bool free; + + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { ++ void (*sk_write_space)(struct sock *sk); ++ ++ sk_write_space = READ_ONCE(sk->sk_write_space); ++ + if (sock_flag(sk, SOCK_RCU_FREE) && +- sk->sk_write_space == sock_def_write_space) { ++ sk_write_space == sock_def_write_space) { + rcu_read_lock(); + free = refcount_sub_and_test(len, &sk->sk_wmem_alloc); + sock_def_write_space_wfree(sk); +@@ -2607,7 +2611,7 @@ void sock_wfree(struct sk_buff *skb) + * after sk_write_space() call + */ + WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc)); +- sk->sk_write_space(sk); ++ sk_write_space(sk); + len = 1; + } + /* +-- +2.53.0 + diff --git a/queue-6.12/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch b/queue-6.12/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch new file mode 100644 index 0000000000..aba3a7235d --- /dev/null +++ b/queue-6.12/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch @@ -0,0 +1,48 @@ +From 693009237798e050591bf129020f5a040d75f8bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:21:05 +0200 +Subject: net: ethernet: mtk_eth_soc: Fix use-after-free in metadata dst + teardown + +From: Lorenzo Bianconi + +[ Upstream commit 80df409e1a483676826a6c66e693dba6ac507751 ] + +mtk_free_dev() calls metadata_dst_free() which frees the metadata_dst +with kfree() immediately, bypassing the RCU grace period. +In the RX path, skb_dst_set_noref() sets a non-refcounted pointer from +the skb to the metadata_dst. This function requires RCU read-side +protection and the dst must remain valid until all RCU readers complete. +Since metadata_dst_free() calls kfree() directly, a use-after-free can +occur if any skb still holds a noref pointer to the dst when the driver +tears it down. +Replace metadata_dst_free() with dst_release() which properly goes +through the refcount path: when the refcount drops to zero, it schedules +the actual free via call_rcu_hurry(), ensuring all RCU readers have +completed before the memory is freed. + +Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260602-airoha-mtk-metadata-uaf-fix-v1-2-3aaa99d83351@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 7406b706fb7530..ebf5432cb328d7 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4287,7 +4287,7 @@ static int mtk_free_dev(struct mtk_eth *eth) + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { + if (!eth->dsa_meta[i]) + break; +- metadata_dst_free(eth->dsa_meta[i]); ++ dst_release(ð->dsa_meta[i]->dst); + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch b/queue-6.12/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch new file mode 100644 index 0000000000..96c9fcb6f5 --- /dev/null +++ b/queue-6.12/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch @@ -0,0 +1,62 @@ +From 0574f4a70049763b884d46d77d931d637200c4a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 06:18:57 +0000 +Subject: net: fec: fix pinctrl default state restore order on resume + +From: Tapio Reijonen + +[ Upstream commit b455410146bf723c7ebcb49ecd5becc0d6611482 ] + +In fec_resume(), fec_enet_clk_enable() is called before +pinctrl_pm_select_default_state() in the non-WoL path, inverting the +ordering used in fec_suspend() which correctly switches to the sleep +pinctrl state before disabling clocks. + +For PHYs with the PHY_RST_AFTER_CLK_EN flag (e.g. TI DP83848 or +SMSC LAN87xx), fec_enet_clk_enable() triggers a hardware reset pulse +via the phy-reset GPIO. With the GPIO pin still in sleep pinctrl state +at that point, the GPIO write has no physical effect and the PHY never +receives the required reset after clock enable, leading to unreliable +link establishment after system resume. + +Fix by restoring the default pinctrl state before enabling clocks, +making resume the proper mirror of suspend. The call is made +unconditionally: fec_suspend() only switches to the sleep pinctrl state +on the non-WoL path and leaves the pins in the default state when WoL +is enabled, so on a WoL resume the device is already in the default +state and pinctrl_pm_select_default_state() is a no-op. + +Fixes: de40ed31b3c5 ("net: fec: add Wake-on-LAN support") +Signed-off-by: Tapio Reijonen +Reviewed-by: Wei Fang +Link: https://patch.msgid.link/20260529-b4-fec-resume-pinctrl-order-v3-1-6eda0f592fca@vaisala.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/fec_main.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 9018a7d3864fd5..d8189c433847c4 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -4731,6 +4731,7 @@ static int fec_resume(struct device *dev) + if (fep->rpm_active) + pm_runtime_force_resume(dev); + ++ pinctrl_pm_select_default_state(&fep->pdev->dev); + ret = fec_enet_clk_enable(ndev, true); + if (ret) { + rtnl_unlock(); +@@ -4747,8 +4748,6 @@ static int fec_resume(struct device *dev) + val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; +- } else { +- pinctrl_pm_select_default_state(&fep->pdev->dev); + } + fec_restart(ndev); + netif_tx_lock_bh(ndev); +-- +2.53.0 + diff --git a/queue-6.12/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch b/queue-6.12/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch new file mode 100644 index 0000000000..2521ef90bf --- /dev/null +++ b/queue-6.12/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch @@ -0,0 +1,58 @@ +From 5a3e73af17de8592f11d1c29318e44c6ffb9ce24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:31:58 +0800 +Subject: net: garp: fix unsigned integer underflow in garp_pdu_parse_attr + +From: Yizhou Zhao + +[ Upstream commit 16e408e607a94b646fb14a2a98422c6877ae4b3c ] + +The receive-side GARP attribute parser computes dlen with reversed +operands: + + dlen = sizeof(*ga) - ga->len; + +ga->len is the on-wire attribute length and includes the GARP attribute +header. For normal attributes with data, ga->len is larger than +sizeof(*ga), so the subtraction underflows in unsigned arithmetic. + +The resulting value is later passed to garp_attr_lookup(), whose length +argument is u8. After truncation, the parsed data length usually no +longer matches the length stored for locally registered attributes, so +received Join/Leave events are ignored. This breaks the GARP receive path +for common attributes, such as GVRP VLAN registration attributes. + +Compute the data length as the attribute length minus the header length. + +Fixes: eca9ebac651f ("net: Add GARP applicant-only participant") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260527083200.42861-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/garp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/802/garp.c b/net/802/garp.c +index 27f0ab146026b4..d2dcdef85d39af 100644 +--- a/net/802/garp.c ++++ b/net/802/garp.c +@@ -453,7 +453,7 @@ static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); +- dlen = sizeof(*ga) - ga->len; ++ dlen = ga->len - sizeof(*ga); + + if (attrtype > app->app->maxattr) + return 0; +-- +2.53.0 + diff --git a/queue-6.12/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch b/queue-6.12/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch new file mode 100644 index 0000000000..dfddc33951 --- /dev/null +++ b/queue-6.12/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch @@ -0,0 +1,99 @@ +From 8c12d30aafec63c019661b8e91f899c5d6336801 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 21:03:00 +0000 +Subject: net: lan743x: permit VLAN-tagged packets up to configured MTU + +From: David Thompson + +[ Upstream commit 8173d22b211f615015f7b35f48ab11a6dd78dc99 ] + +VLAN-tagged interfaces on lan743x devices were previously unreachable via +SSH and failed to respond to large ping packets (e.g. "ping -s 1469" given +MTU=1500). In these scenarios, "ethtool -S" reports non-zero "RX Oversize +Frame Errors". According to Microchip AN2948, the MAC_RX FSE (VLAN field +size enforcement) bit determines whether frames with VLAN tags exceeding +the base MTU plus tag length are discarded. + +The driver must set the MAC_RX.FSE bit before setting MAC_RX.RXEN to allow +VLAN-tagged frames up to the interface MTU, preventing them from being +treated as oversized. As a result, both the base and VLAN-tagged interfaces +can use the same MTU without receive errors. + +Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") +Signed-off-by: David Thompson +Reviewed-by: Thangaraj Samynathan +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz # lan7430 on arm64 (RevPi +Link: https://patch.msgid.link/20260529210300.433135-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 32 +++++++++++++++++++ + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index b897d071fc4524..dff5767671b127 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1212,6 +1212,36 @@ static void lan743x_mac_set_address(struct lan743x_adapter *adapter, + "MAC address set to %pM\n", addr); + } + ++static void lan743x_mac_rx_enable_fse(struct lan743x_adapter *adapter) ++{ ++ u32 mac_rx; ++ bool rxen; ++ ++ mac_rx = lan743x_csr_read(adapter, MAC_RX); ++ if (mac_rx & MAC_RX_FSE_) ++ return; ++ ++ rxen = mac_rx & MAC_RX_RXEN_; ++ if (rxen) { ++ mac_rx &= ~MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, ++ 1, 1000, 20000, 100); ++ } ++ ++ /* Per AN2948, hardware prevents modification of the FSE bit while the ++ * MAC receiver is enabled (RXEN bit set). Use separate register write ++ * to assert the FSE bit before enabling the RXEN bit in MAC_RX ++ */ ++ mac_rx |= MAC_RX_FSE_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ ++ if (rxen) { ++ mac_rx |= MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ } ++} ++ + static int lan743x_mac_init(struct lan743x_adapter *adapter) + { + bool mac_address_valid = true; +@@ -1251,6 +1281,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter) + lan743x_mac_set_address(adapter, adapter->mac_address); + eth_hw_addr_set(netdev, adapter->mac_address); + ++ lan743x_mac_rx_enable_fse(adapter); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 2f0cab0c85e1d0..b8bb31c0400d16 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -181,6 +181,7 @@ + #define MAC_RX (0x104) + #define MAC_RX_MAX_SIZE_SHIFT_ (16) + #define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) ++#define MAC_RX_FSE_ BIT(2) + #define MAC_RX_RXD_ BIT(1) + #define MAC_RX_RXEN_ BIT(0) + +-- +2.53.0 + diff --git a/queue-6.12/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch b/queue-6.12/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch new file mode 100644 index 0000000000..55f436afb9 --- /dev/null +++ b/queue-6.12/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch @@ -0,0 +1,106 @@ +From 67cad93c67f9c335501764aec553b638e11ddfca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 12:08:12 -0400 +Subject: net/sched: act_api: use RCU with deferred freeing for action + lifecycle + +From: Jamal Hadi Salim + +[ Upstream commit 5057e1aca011e51ef51498c940ef96f3d3e8a305 ] + +When NEWTFILTER and DELFILTER are run concurrently it is possible to create a +race with an associated action. + +Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: + + 0: mutex_lock() <-- holds the idr lock + 0: rcu_read_lock() + 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) + 0: mutex_unlock() <-- releases the idr lock + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) <-- Action removed from IDR + 1: mutex_unlock() <-- mutex released allowing us to delete the action + 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory + +This patch fixes the race condition between NEWTFILTER and DELFILTER by +adding struct rcu_head to tc_action used in the deferral and introducing a +call_rcu() in the delete path to defer the final kfree(). + +Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +but also modernization/simplification to directly use kfree_rcu(). + +Let's illustrate the new restored code path: + + 0: rcu_read_lock() + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) + 1: mutex_unlock() + 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period + 0: p = idr_find(idr, index) + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 + 1: rcu_read_unlock() <-- release so freeing can run after grace period + +After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. +CPU0's subsequent idr_find() will return NULL, and even if it still held a +stale pointer, the immediate kfree() is now deferred until after the RCU grace +period, so no UAF can occur. + +Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +Suggested-by: Jakub Kicinski +Reported-by: Kyle Zeng +Tested-by: Victor Nogueira +Tested-by: syzbot@syzkaller.appspotmail.com +Signed-off-by: Jamal Hadi Salim +Tested-by: Kyle Zeng +Reviewed-by: Pedro Tammela +Reviewed-by: Eric Dumazet +Reviewed-by: Victor Nogueira +Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/act_api.h | 1 + + net/sched/act_api.c | 7 +------ + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/net/act_api.h b/include/net/act_api.h +index d8103b2270d98f..539ea6693a2470 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -42,6 +42,7 @@ struct tc_action { + struct tc_cookie __rcu *user_cookie; + struct tcf_chain __rcu *goto_chain; + u32 tcfa_flags; ++ struct rcu_head tcfa_rcu; + u8 hw_stats; + u8 used_hw_stats; + bool used_hw_stats_valid; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index eecad65fec92ca..7d903f0607439d 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -112,11 +112,6 @@ struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action, + } + EXPORT_SYMBOL(tcf_action_set_ctrlact); + +-/* XXX: For standalone actions, we don't need a RCU grace period either, because +- * actions are always connected to filters and filters are already destroyed in +- * RCU callbacks, so after a RCU grace period actions are already disconnected +- * from filters. Readers later can not find us. +- */ + static void free_tcf(struct tc_action *p) + { + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); +@@ -129,7 +124,7 @@ static void free_tcf(struct tc_action *p) + if (chain) + tcf_chain_put_by_act(chain); + +- kfree(p); ++ kfree_rcu(p, tcfa_rcu); + } + + static void offload_action_hw_count_set(struct tc_action *act, +-- +2.53.0 + diff --git a/queue-6.12/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch b/queue-6.12/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch new file mode 100644 index 0000000000..c577783315 --- /dev/null +++ b/queue-6.12/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch @@ -0,0 +1,228 @@ +From e2c97bfcb530099cb50b14133ab389b143429038 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 08:32:21 -0400 +Subject: net/sched: fix pedit partial COW leading to page cache corruption +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rajat Gupta + +[ Upstream commit 899ee91156e57784090c5565e4f31bd7dbffbc5a ] + +tcf_pedit_act() computes the COW range for skb_ensure_writable() +once before the key loop using tcfp_off_max_hint, but the hint does +not account for the runtime header offset added by typed keys. This +can leave part of the write region un-COW'd. + +Fix by moving skb_ensure_writable() inside the per-key loop where +the actual write offset is known, and add overflow checking on the +offset arithmetic. For negative offsets (e.g. Ethernet header edits +at ingress), use skb_cow() to COW the headroom instead. Guard +offset_valid() against INT_MIN, where negation is undefined. + +Fixes: 8b796475fd78 ("net/sched: act_pedit: really ensure the skb is writable") +Reported-by: Yiming Qian +Reported-by: Keenan Dong +Reported-by: Han Guidong <2045gemini@gmail.com> +Reported-by: Zhang Cen +Reviewed-by: Han Guidong <2045gemini@gmail.com> +Tested-by: Han Guidong <2045gemini@gmail.com> +Reviewed-by: Davide Caratti +Tested-by: Davide Caratti +Reviewed-by: Toke Høiland-Jørgensen +Tested-by: Toke Høiland-Jørgensen +Reviewed-by: Victor Nogueira +Tested-by: Victor Nogueira +Acked-by: Jamal Hadi Salim +Signed-off-by: Rajat Gupta +Link: https://patch.msgid.link/20260531123221.48732-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tc_act/tc_pedit.h | 1 - + net/sched/act_pedit.c | 77 +++++++++++++++++++---------------- + 2 files changed, 41 insertions(+), 37 deletions(-) + +diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h +index f58ee15cd858cf..cb7b82f2cbc7fd 100644 +--- a/include/net/tc_act/tc_pedit.h ++++ b/include/net/tc_act/tc_pedit.h +@@ -15,7 +15,6 @@ struct tcf_pedit_parms { + struct tc_pedit_key *tcfp_keys; + struct tcf_pedit_key_ex *tcfp_keys_ex; + int action; +- u32 tcfp_off_max_hint; + unsigned char tcfp_nkeys; + unsigned char tcfp_flags; + struct rcu_head rcu; +diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c +index 4b65901397a888..c0a5f5d78dacd9 100644 +--- a/net/sched/act_pedit.c ++++ b/net/sched/act_pedit.c +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -242,7 +244,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + goto out_free_ex; + } + +- nparms->tcfp_off_max_hint = 0; + nparms->tcfp_flags = parm->flags; + nparms->tcfp_nkeys = parm->nkeys; + +@@ -268,14 +269,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + BITS_PER_TYPE(int) - 1, + nparms->tcfp_keys[i].shift); + +- /* The AT option can read a single byte, we can bound the actual +- * value with uchar max. +- */ +- cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift; +- +- /* Each key touches 4 bytes starting from the computed offset */ +- nparms->tcfp_off_max_hint = +- max(nparms->tcfp_off_max_hint, cur + 4); + } + + p = to_pedit(*a); +@@ -318,15 +311,12 @@ static void tcf_pedit_cleanup(struct tc_action *a) + call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu); + } + +-static bool offset_valid(struct sk_buff *skb, int offset) ++static bool offset_valid(struct sk_buff *skb, int offset, int len) + { +- if (offset > 0 && offset > skb->len) +- return false; +- +- if (offset < 0 && -offset > skb_headroom(skb)) ++ if (offset < -(int)skb_headroom(skb)) + return false; + +- return true; ++ return offset <= (int)skb->len - len; + } + + static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type) +@@ -393,18 +383,10 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + struct tcf_pedit_key_ex *tkey_ex; + struct tcf_pedit_parms *parms; + struct tc_pedit_key *tkey; +- u32 max_offset; + int i; + + parms = rcu_dereference_bh(p->parms); + +- max_offset = (skb_transport_header_was_set(skb) ? +- skb_transport_offset(skb) : +- skb_network_offset(skb)) + +- parms->tcfp_off_max_hint; +- if (skb_ensure_writable(skb, min(skb->len, max_offset))) +- goto done; +- + tcf_lastuse_update(&p->tcf_tm); + tcf_action_update_bstats(&p->common, skb); + +@@ -412,10 +394,11 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + tkey_ex = parms->tcfp_keys_ex; + + for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { ++ int write_offset, write_len; + int offset = tkey->off; + int hoffset = 0; +- u32 *ptr, hdata; +- u32 val; ++ u32 cur_val, val; ++ u32 *ptr; + int rc; + + if (tkey_ex) { +@@ -433,13 +416,15 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + + if (tkey->offmask) { + u8 *d, _d; ++ int at_offset; + +- if (!offset_valid(skb, hoffset + tkey->at)) { ++ if (check_add_overflow(hoffset, (int)tkey->at, &at_offset) || ++ !offset_valid(skb, at_offset, sizeof(_d))) { + pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n", + hoffset + tkey->at); + goto bad; + } +- d = skb_header_pointer(skb, hoffset + tkey->at, ++ d = skb_header_pointer(skb, at_offset, + sizeof(_d), &_d); + if (!d) + goto bad; +@@ -451,31 +436,51 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + } + } + +- if (!offset_valid(skb, hoffset + offset)) { +- pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset); ++ if (check_add_overflow(hoffset, offset, &write_offset)) { ++ pr_info_ratelimited("tc action pedit offset overflow\n"); + goto bad; + } + +- ptr = skb_header_pointer(skb, hoffset + offset, +- sizeof(hdata), &hdata); +- if (!ptr) ++ if (!offset_valid(skb, write_offset, sizeof(*ptr))) { ++ pr_info_ratelimited("tc action pedit offset %d out of bounds\n", ++ write_offset); + goto bad; ++ } ++ ++ if (write_offset < 0) { ++ if (skb_cow(skb, -write_offset)) ++ goto bad; ++ if (write_offset + (int)sizeof(*ptr) > 0) { ++ if (skb_ensure_writable(skb, ++ min_t(int, skb->len, ++ write_offset + (int)sizeof(*ptr)))) ++ goto bad; ++ } ++ } else { ++ if (check_add_overflow(write_offset, (int)sizeof(*ptr), ++ &write_len)) ++ goto bad; ++ if (skb_ensure_writable(skb, min_t(int, skb->len, ++ write_len))) ++ goto bad; ++ } ++ ++ ptr = (u32 *)(skb->data + write_offset); ++ cur_val = get_unaligned(ptr); + /* just do it, baby */ + switch (cmd) { + case TCA_PEDIT_KEY_EX_CMD_SET: + val = tkey->val; + break; + case TCA_PEDIT_KEY_EX_CMD_ADD: +- val = (*ptr + tkey->val) & ~tkey->mask; ++ val = (cur_val + tkey->val) & ~tkey->mask; + break; + default: + pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd); + goto bad; + } + +- *ptr = ((*ptr & tkey->mask) ^ val); +- if (ptr == &hdata) +- skb_store_bits(skb, hoffset + offset, ptr, 4); ++ put_unaligned((cur_val & tkey->mask) ^ val, ptr); + } + + goto done; +-- +2.53.0 + diff --git a/queue-6.12/net_sched-act_pedit-use-rcu-in-tcf_pedit_dump.patch b/queue-6.12/net_sched-act_pedit-use-rcu-in-tcf_pedit_dump.patch new file mode 100644 index 0000000000..ca654a6b31 --- /dev/null +++ b/queue-6.12/net_sched-act_pedit-use-rcu-in-tcf_pedit_dump.patch @@ -0,0 +1,109 @@ +From 9f374bf663ac3cc81b8168bef435e6d5d61c5f15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Jul 2025 09:02:01 +0000 +Subject: net_sched: act_pedit: use RCU in tcf_pedit_dump() + +From: Eric Dumazet + +[ Upstream commit 9d096746572616a50cac4906f528a1959c0ee1c2 ] + +Also storing tcf_action into struct tcf_pedit_params +makes sure there is no discrepancy in tcf_pedit_act(). + +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20250709090204.797558-10-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 899ee91156e5 ("net/sched: fix pedit partial COW leading to page cache corruption") +Signed-off-by: Sasha Levin +--- + include/net/tc_act/tc_pedit.h | 1 + + net/sched/act_pedit.c | 20 ++++++++++---------- + 2 files changed, 11 insertions(+), 10 deletions(-) + +diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h +index 83fe3993178180..f58ee15cd858cf 100644 +--- a/include/net/tc_act/tc_pedit.h ++++ b/include/net/tc_act/tc_pedit.h +@@ -14,6 +14,7 @@ struct tcf_pedit_key_ex { + struct tcf_pedit_parms { + struct tc_pedit_key *tcfp_keys; + struct tcf_pedit_key_ex *tcfp_keys_ex; ++ int action; + u32 tcfp_off_max_hint; + unsigned char tcfp_nkeys; + unsigned char tcfp_flags; +diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c +index fc0a35a7b62ac7..4b65901397a888 100644 +--- a/net/sched/act_pedit.c ++++ b/net/sched/act_pedit.c +@@ -279,7 +279,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + } + + p = to_pedit(*a); +- ++ nparms->action = parm->action; + spin_lock_bh(&p->tcf_lock); + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); + oparms = rcu_replace_pointer(p->parms, nparms, 1); +@@ -483,7 +483,7 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + bad: + tcf_action_inc_overlimit_qstats(&p->common); + done: +- return p->tcf_action; ++ return parms->action; + } + + static void tcf_pedit_stats_update(struct tc_action *a, u64 bytes, u64 packets, +@@ -500,19 +500,19 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, + int bind, int ref) + { + unsigned char *b = skb_tail_pointer(skb); +- struct tcf_pedit *p = to_pedit(a); +- struct tcf_pedit_parms *parms; ++ const struct tcf_pedit *p = to_pedit(a); ++ const struct tcf_pedit_parms *parms; + struct tc_pedit *opt; + struct tcf_t t; + int s; + +- spin_lock_bh(&p->tcf_lock); +- parms = rcu_dereference_protected(p->parms, 1); ++ rcu_read_lock(); ++ parms = rcu_dereference(p->parms); + s = struct_size(opt, keys, parms->tcfp_nkeys); + + opt = kzalloc(s, GFP_ATOMIC); + if (unlikely(!opt)) { +- spin_unlock_bh(&p->tcf_lock); ++ rcu_read_unlock(); + return -ENOBUFS; + } + opt->nkeys = parms->tcfp_nkeys; +@@ -521,7 +521,7 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, + flex_array_size(opt, keys, parms->tcfp_nkeys)); + opt->index = p->tcf_index; + opt->flags = parms->tcfp_flags; +- opt->action = p->tcf_action; ++ opt->action = parms->action; + opt->refcnt = refcount_read(&p->tcf_refcnt) - ref; + opt->bindcnt = atomic_read(&p->tcf_bindcnt) - bind; + +@@ -540,13 +540,13 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, + tcf_tm_dump(&t, &p->tcf_tm); + if (nla_put_64bit(skb, TCA_PEDIT_TM, sizeof(t), &t, TCA_PEDIT_PAD)) + goto nla_put_failure; +- spin_unlock_bh(&p->tcf_lock); ++ rcu_read_unlock(); + + kfree(opt); + return skb->len; + + nla_put_failure: +- spin_unlock_bh(&p->tcf_lock); ++ rcu_read_unlock(); + nlmsg_trim(skb, b); + kfree(opt); + return -1; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch b/queue-6.12/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch new file mode 100644 index 0000000000..36583a9130 --- /dev/null +++ b/queue-6.12/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch @@ -0,0 +1,58 @@ +From 85d1d41c32d374b0878e8935ec4f231c6cc34992 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 12:29:10 +0000 +Subject: netfilter: bridge: make ebt_snat ARP rewrite writable + +From: Yiming Qian + +[ Upstream commit 67ba971ae02514d85818fe0c32549ab4bfa3bf49 ] + +The ebtables SNAT target keeps the Ethernet source address rewrite +behind skb_ensure_writable(skb, 0). This is intentional: at the bridge +ebtables hooks the Ethernet header is addressed through +skb_mac_header()/eth_hdr(), while skb->data points at the Ethernet +payload. Asking skb_ensure_writable() for ETH_HLEN bytes would check +the payload, not the Ethernet header, and would reintroduce the small +packet regression fixed by commit 63137bc5882a. + +However, the optional ARP sender hardware address rewrite is different. +It writes through skb_store_bits() at an offset relative to skb->data: + + skb_store_bits(skb, sizeof(struct arphdr), info->mac, ETH_ALEN) + +skb_header_pointer() only safely reads the ARP header; it does not make +the later sender hardware address range writable. If that range is +still held in a nonlinear skb fragment backed by a splice-imported file +page, skb_store_bits() maps the frag page and copies the new MAC address +directly into it. + +Ensure the ARP SHA range is writable before reading the ARP header and +before calling skb_store_bits(). + +Fixes: 63137bc5882a ("netfilter: ebtables: Fixes dropping of small packets in bridge nat") +Reported-by: Yiming Qian +Signed-off-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_snat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c +index 7dfbcdfc30e5d2..c9e229af0366b8 100644 +--- a/net/bridge/netfilter/ebt_snat.c ++++ b/net/bridge/netfilter/ebt_snat.c +@@ -31,6 +31,9 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) + const struct arphdr *ap; + struct arphdr _ah; + ++ if (skb_ensure_writable(skb, sizeof(_ah) + ETH_ALEN)) ++ return EBT_DROP; ++ + ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch b/queue-6.12/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch new file mode 100644 index 0000000000..8f5c33be67 --- /dev/null +++ b/queue-6.12/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch @@ -0,0 +1,50 @@ +From 28146e0ae0a82103c54c5971625108ba6cd31420 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:20:19 +0200 +Subject: netfilter: conntrack_irc: fix possible out-of-bounds read + +From: Florian Westphal + +[ Upstream commit 66eba0ffce3b7e11449946b4cbbef8ea36112f56 ] + +When parsing fails after we've matched the command string we +should bail out instead of trying to match a different command. + +This helper should be deprecated, given prevalence of TLS I doubt it has +any relevance in 2026. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Closes: https://sashiko.dev/#/patchset/20260525182924.28456-1-fw%40strlen.de +Signed-off-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_irc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c +index 5703846bea3b69..0f50ea92ced9df 100644 +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -208,7 +208,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + pr_debug("unable to parse dcc command\n"); +- continue; ++ goto out; + } + + pr_debug("DCC bound ip/port: %pI4:%u\n", +@@ -222,7 +222,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); +- continue; ++ goto out; + } + + exp = nf_ct_expect_alloc(ct); +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch b/queue-6.12/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch new file mode 100644 index 0000000000..bedf2dff38 --- /dev/null +++ b/queue-6.12/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch @@ -0,0 +1,96 @@ +From a590999c564903a3f5fbf7e41ecdad46049ade19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:09:19 +0800 +Subject: netfilter: nft_ct: bail out on template ct in get eval + +From: Jiayuan Chen + +[ Upstream commit 3027ecbdb5fdf9200251c21d4818e4c447ef78e1 ] + +I noticed this issue while looking at a historic syzbot report [1]. + +A rule like the one below is enough to trigger the bug: + + table ip t { + chain pre { + type filter hook prerouting priority raw; + ct zone set 1 + ct original saddr 1.2.3.4 accept + } + } + +The first expression attaches a per-cpu template ct via +nft_ct_set_zone_eval() (nf_ct_tmpl_alloc -> kzalloc, tuple is all +zero, nf_ct_l3num(ct) == 0). The next expression then calls +nft_ct_get_eval() on the same skb, treats the template as a real ct +and hits the 16-byte memcpy path. With dreg at NFT_REG32_15 this +overflows past struct nft_regs on the kernel stack; with smaller +dreg values it silently clobbers adjacent registers. + +Reject template ct at the eval entry and in nft_ct_get_fast_eval(), +mirroring the check nft_ct_set_eval() already has. Additionally, +bound the address copy in NFT_CT_SRC / NFT_CT_DST by priv->len +instead of by nf_ct_l3num(ct): nf_ct_get_tuple() zeroes the tuple +before pkt_to_tuple() fills in only the protocol-relevant leading +bytes, so the trailing bytes of tuple->{src,dst}.u3.all are +well-defined zero. priv->len is validated at rule load, so the +copy size is now bounded by the destination register rather than +by an untrusted field on the conntrack. + +[1]: https://syzkaller.appspot.com/bug?id=389cf09cb72926114fce90dc85a2c3231dcb647c + +Fixes: 45d9bcda21f4 ("netfilter: nf_tables: validate len in nft_validate_data_load()") +Suggested-by: Florian Westphal +Signed-off-by: Jiayuan Chen +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_ct.c | 8 +++----- + net/netfilter/nft_ct_fast.c | 2 +- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c +index 5310c3dca8327b..65fbbf4a219e9e 100644 +--- a/net/netfilter/nft_ct.c ++++ b/net/netfilter/nft_ct.c +@@ -78,7 +78,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + break; + } + +- if (ct == NULL) ++ if (!ct || nf_ct_is_template(ct)) + goto err; + + switch (priv->key) { +@@ -180,12 +180,10 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + tuple = &ct->tuplehash[priv->dir].tuple; + switch (priv->key) { + case NFT_CT_SRC: +- memcpy(dest, tuple->src.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->src.u3.all, priv->len); + return; + case NFT_CT_DST: +- memcpy(dest, tuple->dst.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->dst.u3.all, priv->len); + return; + case NFT_CT_PROTO_SRC: + nft_reg_store16(dest, (__force u16)tuple->src.u.all); +diff --git a/net/netfilter/nft_ct_fast.c b/net/netfilter/nft_ct_fast.c +index e684c8a9184877..ecf7b3a404be26 100644 +--- a/net/netfilter/nft_ct_fast.c ++++ b/net/netfilter/nft_ct_fast.c +@@ -30,7 +30,7 @@ void nft_ct_get_fast_eval(const struct nft_expr *expr, + break; + } + +- if (!ct) { ++ if (!ct || nf_ct_is_template(ct)) { + regs->verdict.code = NFT_BREAK; + return; + } +-- +2.53.0 + diff --git a/queue-6.12/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch b/queue-6.12/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch new file mode 100644 index 0000000000..d0360a03de --- /dev/null +++ b/queue-6.12/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch @@ -0,0 +1,113 @@ +From f438a624fd9fe9109adf28f5a293ca0c51abb9f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 23:58:31 +0200 +Subject: netfilter: synproxy: add mutex to guard hook reference counting + +From: Fernando Fernandez Mancera + +[ Upstream commit 2fcba19caaeb2a33017459d3430f057967bb91b6 ] + +As the synproxy infrastructure register netfilter hooks on-demand when a +user adds the first iptables target or nftables expression, if done +concurrently they can race each other. + +Introduce a mutex to serialize the refcount control blocks access from +both frontends. While a per namespace mutex might be more efficient, it +is not needed for target/expression like SYNPROXY. + +Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 6a851ac4dd048f..a277b2bd3275dc 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -21,6 +21,8 @@ + #include + #include + ++static DEFINE_MUTEX(synproxy_mutex); ++ + unsigned int synproxy_net_id; + EXPORT_SYMBOL_GPL(synproxy_net_id); + +@@ -768,26 +770,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = { + + int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref4 == 0) { + err = nf_register_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref4++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init); + + void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref4--; + if (snet->hook_ref4 == 0) + nf_unregister_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini); + +@@ -1192,27 +1199,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = { + int + nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref6 == 0) { + err = nf_register_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref6++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init); + + void + nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref6--; + if (snet->hook_ref6 == 0) + nf_unregister_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini); + #endif /* CONFIG_IPV6 */ +-- +2.53.0 + diff --git a/queue-6.12/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch b/queue-6.12/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..bdf0529ea0 --- /dev/null +++ b/queue-6.12/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch @@ -0,0 +1,41 @@ +From 849c3cd18db9650f3371433888fef1ebaa6c70eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 12:47:17 +0200 +Subject: netfilter: xt_NFQUEUE: prefer raw_smp_processor_id + +From: Fernando Fernandez Mancera + +[ Upstream commit c6c5327dd18bec1e1bbf139b2cf5ae53608a9d30 ] + +With PREEMPT_RCU this triggers a splat because smp_processor_id() can be +preempted while inside a RCU critical section. If xt_NFQUEUE target is +invoked via nft_compat_eval() path, we are inside a RCU critical +section. + +Just use the raw version instead. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_NFQUEUE.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index 466da23e36ff47..b32d153e3a1862 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -91,7 +91,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) + + if (info->queues_total > 1) { + if (info->flags & NFQ_FLAG_CPU_FANOUT) { +- int cpu = smp_processor_id(); ++ int cpu = raw_smp_processor_id(); + + queue = info->queuenum + cpu % info->queues_total; + } else { +-- +2.53.0 + diff --git a/queue-6.12/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch b/queue-6.12/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch new file mode 100644 index 0000000000..72b414dea4 --- /dev/null +++ b/queue-6.12/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch @@ -0,0 +1,44 @@ +From 37a8a8832baeff47353749b7cbe17fba5f6e2cce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 17:07:05 +0530 +Subject: octeontx2-af: Fix initialization of mcam's entry2target_pffunc field + +From: Suman Ghosh + +[ Upstream commit 9a85ec3dc28b6df246801c19e4d9bae6297a25b0 ] + +NPC mcam entry stores a mapping between mcam entry and target pcifunc. +During initialization of this field, API kmalloc_array has been used which +caused some junk values to array. Whereas, the array is expected to be +initialized by 0. This patch fixes the same by using kcalloc instead of +kmalloc_array. + +Fixes: 55307fcb9258 ("octeontx2-af: Add mbox messages to install and delete MCAM rules") +Signed-off-by: Suman Ghosh +Signed-off-by: Subbaraya Sundeep +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/1780054625-17090-1-git-send-email-sbhatta@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index e3038a912a5805..3e03f85bf362cb 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -1944,8 +1944,8 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr) + goto free_entry_cntr_map; + + /* Alloc memory for saving target device of mcam rule */ +- mcam->entry2target_pffunc = kmalloc_array(mcam->total_entries, +- sizeof(u16), GFP_KERNEL); ++ mcam->entry2target_pffunc = kcalloc(mcam->total_entries, ++ sizeof(u16), GFP_KERNEL); + if (!mcam->entry2target_pffunc) + goto free_cntr_refcnt; + +-- +2.53.0 + diff --git a/queue-6.12/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch b/queue-6.12/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch new file mode 100644 index 0000000000..95a4186116 --- /dev/null +++ b/queue-6.12/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch @@ -0,0 +1,119 @@ +From 582b42f16b56d31715b4137891d3f04d32233ea8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 10:28:53 +0530 +Subject: octeontx2-af: npc: Fix CPT channel mask in npc_install_flow + +From: Nithin Dabilpuram + +[ Upstream commit 1d31eb27e570daa04f5373345f9ac98c95863be9 ] + +Use the CPT-aware NIX channel mask in the npc_install_flow path so that +when the host PF installs steering rules in kernel for a VF used from +userspace (e.g. DPDK), MCAM entries see the same channel mask semantics as +other RX paths. + +Fixes: 56bcef528bd8 ("octeontx2-af: Use npc_install_flow API for promisc and broadcast entries") +Cc: Naveen Mamindlapalli +Signed-off-by: Nithin Dabilpuram +Signed-off-by: Ratheesh Kannoth +Link: https://patch.msgid.link/20260602045853.1558530-1-rkannoth@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + + .../ethernet/marvell/octeontx2/af/rvu_npc.c | 32 +++++++++---------- + .../marvell/octeontx2/af/rvu_npc_fs.c | 2 +- + 3 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index f94bf04788e986..77a03e29a77116 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -1020,6 +1020,7 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int lf, + int slot); + int rvu_cpt_ctx_flush(struct rvu *rvu, u16 pcifunc); + int rvu_cpt_init(struct rvu *rvu); ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu); + + #define NDC_AF_BANK_MASK GENMASK_ULL(7, 0) + #define NDC_AF_BANK_LINE_MASK GENMASK_ULL(31, 16) +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index 3e03f85bf362cb..0163fbb758d3d3 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -597,6 +597,19 @@ void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + NPC_AF_MCAMEX_BANKX_ACTION(index, bank), cfg); + } + ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu) ++{ ++ /* For cn10k the upper two bits of the channel number are ++ * cpt channel number. with masking out these bits in the ++ * mcam entry, same entry used for NIX will allow packets ++ * received from cpt for parsing. ++ */ ++ if (!is_rvu_otx2(rvu)) ++ return NIX_CHAN_CPT_X2P_MASK; ++ else ++ return 0xFFFu; ++} ++ + void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + int nixlf, u64 chan, u8 *mac_addr) + { +@@ -640,7 +653,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + eth_broadcast_addr((u8 *)&req.mask.dmac); + req.features = BIT_ULL(NPC_DMAC); + req.channel = chan; +- req.chan_mask = 0xFFFU; ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.intf = pfvf->nix_rx_intf; + req.op = action.op; + req.hdr.pcifunc = 0; /* AF is requester */ +@@ -710,11 +723,7 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc, + * mcam entry, same entry used for NIX will allow packets + * received from cpt for parsing. + */ +- if (!is_rvu_otx2(rvu)) { +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- } else { +- req.chan_mask = 0xFFFU; +- } ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + + if (chan_cnt > 1) { + if (!is_power_of_2(chan_cnt)) { +@@ -903,16 +912,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf, + ether_addr_copy(req.mask.dmac, mac_addr); + req.features = BIT_ULL(NPC_DMAC); + +- /* For cn10k the upper two bits of the channel number are +- * cpt channel number. with masking out these bits in the +- * mcam entry, same entry used for NIX will allow packets +- * received from cpt for parsing. +- */ +- if (!is_rvu_otx2(rvu)) +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- else +- req.chan_mask = 0xFFFU; +- ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.channel = chan; + req.intf = pfvf->nix_rx_intf; + req.entry = index; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +index 0c484120be7993..73850213b1f30a 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +@@ -1484,7 +1484,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, + + /* ignore chan_mask in case pf func is not AF, revisit later */ + if (!is_pffunc_af(req->hdr.pcifunc)) +- req->chan_mask = 0xFFF; ++ req->chan_mask = rvu_get_cpt_chan_mask(rvu); + + err = npc_check_unsupported_flows(rvu, req->features, req->intf); + if (err) +-- +2.53.0 + diff --git a/queue-6.12/octeontx2-pf-fix-ndc-sync-operation-errors.patch b/queue-6.12/octeontx2-pf-fix-ndc-sync-operation-errors.patch new file mode 100644 index 0000000000..9c40c4cb4a --- /dev/null +++ b/queue-6.12/octeontx2-pf-fix-ndc-sync-operation-errors.patch @@ -0,0 +1,40 @@ +From d9be109ef1df9d2231e0ce7868be817b95f8e00b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 17:07:57 +0530 +Subject: octeontx2-pf: Fix NDC sync operation errors + +From: Geetha sowjanya + +[ Upstream commit a910fb8f7b9e4c566db363e6c2ec378dc7153995 ] + +On system reboot "rvu_nicpf 0002:03:00.0: NDC sync operation failed" +error messages are shown, even if the operations is successful. +This is due to wrong if error check in ndc_syc() function. + +Fixes: 42c45ac1419c ("octeontx2-af: Sync NIX and NPA contexts from NDC to LLC/DRAM") +Signed-off-by: Geetha sowjanya +Signed-off-by: Subbaraya Sundeep +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/1780054677-17249-1-git-send-email-sbhatta@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index 2de9c44ef57c77..ce01fab28624f2 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3263,7 +3263,7 @@ static void otx2_ndc_sync(struct otx2_nic *pf) + req->nix_lf_rx_sync = 1; + req->npa_lf_sync = 1; + +- if (!otx2_sync_mbox_msg(mbox)) ++ if (otx2_sync_mbox_msg(mbox)) + dev_err(pf->dev, "NDC sync operation failed\n"); + + mutex_unlock(&mbox->lock); +-- +2.53.0 + diff --git a/queue-6.12/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch b/queue-6.12/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch new file mode 100644 index 0000000000..2bc2ab392e --- /dev/null +++ b/queue-6.12/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch @@ -0,0 +1,58 @@ +From 69b73d02df434ebe99b3e6599b31999a74a7fa7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 16:03:20 +0200 +Subject: pcnet32: stop holding device spin lock during napi_complete_done + +From: Oscar Maes + +[ Upstream commit 73bf3cca7de6a73f53b6a52dc3b1c82ae5667a4d ] + +napi_complete_done may call gro_flush_normal (though not currently, as GRO +is unsupported at the moment), which may result in packet TX. This will +eventually result in calling pcnet32_start_xmit - resulting in a deadlock +while trying to re-acquire the already locked spin lock. + +It is safe to split the spinlock block into two, because the hardware +registers are still protected from concurrent access, and the two blocks +perform unrelated operations that don't need to happen atomically. + +Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()") +Reviewed-by: Andrew Lunn +Signed-off-by: Oscar Maes +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/pcnet32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c +index 72db9f9e7beeae..81cb83caf62a15 100644 +--- a/drivers/net/ethernet/amd/pcnet32.c ++++ b/drivers/net/ethernet/amd/pcnet32.c +@@ -1403,8 +1403,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + pcnet32_restart(dev, CSR0_START); + netif_wake_queue(dev); + } ++ spin_unlock_irqrestore(&lp->lock, flags); + + if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a->read_csr(ioaddr, CSR3); + val &= 0x00ff; +@@ -1412,9 +1414,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + + /* Set interrupt enable. */ + lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN); ++ spin_unlock_irqrestore(&lp->lock, flags); + } + +- spin_unlock_irqrestore(&lp->lock, flags); + return work_done; + } + +-- +2.53.0 + diff --git a/queue-6.12/ptp-vclock-switch-from-rcu-to-srcu.patch b/queue-6.12/ptp-vclock-switch-from-rcu-to-srcu.patch new file mode 100644 index 0000000000..a53f861ad9 --- /dev/null +++ b/queue-6.12/ptp-vclock-switch-from-rcu-to-srcu.patch @@ -0,0 +1,85 @@ +From d39c3554013aefdb958c15e6cc6f384780e536cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:11:47 +0200 +Subject: ptp: vclock: Switch from RCU to SRCU + +From: Kurt Kanzenbach + +[ Upstream commit 672bd0519e27c357c43b7f8c0d653fce3817d06e ] + +The usage of PTP vClocks leads immediately to the following issues with +ptp4l with LOCKDEP and DEBUG_ATOMIC_SLEEP enabled: "BUG: sleeping function +called from invalid context". + +ptp_convert_timestamp() acquires a mutex_t within a RCU read section. This +is illegal, because acquiring a mutex_t can result in voluntary scheduling +request which is not allowed within a RCU read section. + +Replace the RCU usage with SRCU where sleeping is allowed. + +Reported-by: Florian Zeitz +Closes: https://lore.kernel.org/all/00a8cce8-410e-4038-98af-49be6d93d7bd@schettke.com/ +Fixes: 67d93ffc0f3c ("ptp: vclock: use mutex to fix "sleep on atomic" bug") +Signed-off-by: Kurt Kanzenbach +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260529-vclock_rcu-v2-1-02a5531fab92@linutronix.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_vclock.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c +index 8ed4b85989242f..5e2730c73bc286 100644 +--- a/drivers/ptp/ptp_vclock.c ++++ b/drivers/ptp/ptp_vclock.c +@@ -19,6 +19,8 @@ static DEFINE_SPINLOCK(vclock_hash_lock); + + static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8); + ++DEFINE_STATIC_SRCU(vclock_srcu); ++ + static void ptp_vclock_hash_add(struct ptp_vclock *vclock) + { + spin_lock(&vclock_hash_lock); +@@ -37,7 +39,7 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock) + + spin_unlock(&vclock_hash_lock); + +- synchronize_rcu(); ++ synchronize_srcu(&vclock_srcu); + } + + static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +@@ -276,14 +278,16 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + { + unsigned int hash = vclock_index % HASH_SIZE(vclock_hash); + struct ptp_vclock *vclock; +- u64 ns; + u64 vclock_ns = 0; ++ int srcu_idx; ++ u64 ns; + + ns = ktime_to_ns(*hwtstamp); + +- rcu_read_lock(); ++ srcu_idx = srcu_read_lock(&vclock_srcu); + +- hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) { ++ hlist_for_each_entry_srcu(vclock, &vclock_hash[hash], vclock_hash_node, ++ srcu_read_lock_held(&vclock_srcu)) { + if (vclock->clock->index != vclock_index) + continue; + +@@ -294,7 +298,7 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + break; + } + +- rcu_read_unlock(); ++ srcu_read_unlock(&vclock_srcu, srcu_idx); + + return ns_to_ktime(vclock_ns); + } +-- +2.53.0 + diff --git a/queue-6.12/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch b/queue-6.12/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch new file mode 100644 index 0000000000..f001832d28 --- /dev/null +++ b/queue-6.12/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch @@ -0,0 +1,87 @@ +From 72d983ff1c88faa4171275db30dd712b9c491e5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:11:44 -0400 +Subject: sctp: purge outqueue on stale COOKIE-ECHO handling + +From: Xin Long + +[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ] + +sctp_stream_update() is only invoked when the association is moved into +COOKIE_WAIT during association setup/reconfiguration. In this path, the +outbound stream scheduler state (stream->out_curr) is expected to be +clean, since no user data should have been transmitted yet unless the +state machine has already partially progressed. + +However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a +Stale Cookie ERROR is received, the association is rolled back from +COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already +have been queued and even bundled with the COOKIE-ECHO chunk. + +During the rollback, sctp_stream_update() frees the old stream table +and installs a new one, but it does not invalidate stream->out_curr. +As a result, out_curr may still point to a freed sctp_stream_out +entry from the previous stream state. + +Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on +stream->out_curr->ext, which can lead to use-after-free once the old +stream state has been released via sctp_stream_free(). + +This results in crashes such as (reported by Yuqi): + + BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140 + Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312 + CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted + 7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full) + sctp_sched_fcfs_dequeue+0x13a/0x140 + sctp_outq_flush+0x1603/0x33e0 + sctp_do_sm+0x31c9/0x5d30 + sctp_assoc_bh_rcv+0x392/0x6f0 + sctp_inq_push+0x1db/0x270 + sctp_rcv+0x138d/0x3c10 + +Fix this by fully purging the association outqueue when handling the +Stale Cookie case. This ensures all pending transmit and retransmit +state is dropped, and any scheduler cached pointers are invalidated, +making it safe to rebuild stream state during COOKIE_WAIT restart. + +Updating only stream->out_curr would be insufficient, since queued +and retransmittable data would still reference the old stream state and +trigger later use-after-free in dequeue paths. + +Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Reported-by: Yuqi Xu +Reported-by: Ren Wei +Signed-off-by: Xin Long +Link: https://patch.msgid.link/94318159b9052907a6cbb7256aee8b5f8dfbfccb.1780510304.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 376d4ce5ebb3cb..613c5c3fa8462e 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2598,11 +2598,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + +- /* If we've sent any data bundled with COOKIE-ECHO we will need to +- * resend +- */ +- sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, +- SCTP_TRANSPORT(asoc->peer.primary_path)); ++ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index 10876eb595..cc27fc4b65 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -6,3 +6,52 @@ arm-fix-hash_name-fault.patch arm-fix-branch-predictor-hardening.patch net-phy-micrel-fix-lan8814-qsgmii-soft-reset.patch wifi-remove-zero-length-arrays.patch +tee-optee-prevent-use-after-free-when-the-client-exi.patch +soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch +erofs-add-sysfs-node-to-drop-internal-caches.patch +erofs-tidy-up-synchronous-decompression.patch +erofs-fix-use-after-free-on-sbi-sync_decompress.patch +ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch +netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch +ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch +netfilter-synproxy-add-mutex-to-guard-hook-reference.patch +netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch +netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch +netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch +dm-cache-policy-smq-check-allocation-under-invalidat.patch +net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch +6lowpan-fix-off-by-one-in-multicast-context-address-.patch +l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch +devlink-release-nested-relation-on-devlink-free.patch +drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch +wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch +pcnet32-stop-holding-device-spin-lock-during-napi_co.patch +net-annotate-sk-sk_write_space-for-udp-sockmap.patch +hsr-remove-warn_once-in-hsr_addr_is_self.patch +net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch +net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch +net-fec-fix-pinctrl-default-state-restore-order-on-r.patch +bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch +bluetooth-mgmt-validate-advertising-tlv-before-type-.patch +bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch +bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch +bluetooth-bnep-reject-short-frames-before-parsing.patch +bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch +bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch +bluetooth-iso-fix-not-using-bc_sid-as-advertisement-.patch +bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch +bluetooth-mgmt-fix-backward-compatibility-with-users.patch +octeontx2-pf-fix-ndc-sync-operation-errors.patch +octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch +ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch +ptp-vclock-switch-from-rcu-to-srcu.patch +net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch +net_sched-act_pedit-use-rcu-in-tcf_pedit_dump.patch +net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch +octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch +vxlan-vnifilter-send-notification-on-vni-add.patch +vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch +ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch +ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch +net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch +sctp-purge-outqueue-on-stale-cookie-echo-handling.patch diff --git a/queue-6.12/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch b/queue-6.12/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch new file mode 100644 index 0000000000..bf17e4fab7 --- /dev/null +++ b/queue-6.12/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch @@ -0,0 +1,44 @@ +From b447174623e201ed0c1c00b326a060b483f73b5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 May 2026 19:22:18 +0530 +Subject: soc: qcom: ice: Return -ENODEV if the ICE platform device is not + found + +From: Manivannan Sadhasivam + +[ Upstream commit 5a4dc805a80e6fe303d6a4748cd451ea15987ffd ] + +By the time the consumer driver calls devm_of_qcom_ice_get(), all the +platform devices for ICE nodes would've been created by +of_platform_default_populate(). + +So for the absence of any platform device, -ENODEV should not returned, not +-EPROBE_DEFER. + +Fixes: 2afbf43a4aec ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver") +Tested-by: Sumit Garg # OP-TEE as TZ +Acked-by: Sumit Garg +Signed-off-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-2-2a595382185b@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ice.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index 9d89bfc50e8b86..66b64509347a64 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -301,7 +301,7 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_err(dev, "Cannot find device node %s\n", node->name); +- return ERR_PTR(-EPROBE_DEFER); ++ return ERR_PTR(-ENODEV); + } + + ice = platform_get_drvdata(pdev); +-- +2.53.0 + diff --git a/queue-6.12/tee-optee-prevent-use-after-free-when-the-client-exi.patch b/queue-6.12/tee-optee-prevent-use-after-free-when-the-client-exi.patch new file mode 100644 index 0000000000..a65b3dbd51 --- /dev/null +++ b/queue-6.12/tee-optee-prevent-use-after-free-when-the-client-exi.patch @@ -0,0 +1,287 @@ +From 524240f19e8109ccb8154a72935966ff4c7a2b58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:24:06 -0800 +Subject: tee: optee: prevent use-after-free when the client exits before the + supplicant + +From: Amirreza Zarrabi + +[ Upstream commit 387a926ee166814611acecb960207fe2f3c4fd3e ] + +Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the +client wait as killable so it can be interrupted during shutdown or +after a supplicant crash. This changes the original lifetime expectations: +the client task can now terminate while the supplicant is still processing +its request. + +If the client exits first it removes the request from its queue and +kfree()s it, while the request ID remains in supp->idr. A subsequent +lookup on the supplicant path then dereferences freed memory, leading to +a use-after-free. + +Serialise access to the request with supp->mutex: + + * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while + looking up and touching the request. + * Let optee_supp_thrd_req() notice that the client has terminated and + signal optee_supp_send() accordingly. + +With these changes the request cannot be freed while the supplicant still +has a reference, eliminating the race. + +Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") +Signed-off-by: Amirreza Zarrabi +Tested-by: Ox Yeh +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/supp.c | 107 +++++++++++++++++++++++++++------------ + 1 file changed, 74 insertions(+), 33 deletions(-) + +diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c +index d0f397c9024201..2386bbd38ce78b 100644 +--- a/drivers/tee/optee/supp.c ++++ b/drivers/tee/optee/supp.c +@@ -10,7 +10,11 @@ + struct optee_supp_req { + struct list_head link; + ++ int id; ++ + bool in_queue; ++ bool processed; ++ + u32 func; + u32 ret; + size_t num_params; +@@ -19,6 +23,9 @@ struct optee_supp_req { + struct completion c; + }; + ++/* It is temporary request used for revoked pending request in supp->idr. */ ++#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) ++ + void optee_supp_init(struct optee_supp *supp) + { + memset(supp, 0, sizeof(*supp)); +@@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) + { + int id; + struct optee_supp_req *req; +- struct optee_supp_req *req_tmp; + + mutex_lock(&supp->mutex); + +- /* Abort all request retrieved by supplicant */ ++ /* Abort all request */ + idr_for_each_entry(&supp->idr, req, id) { + idr_remove(&supp->idr, id); +- req->ret = TEEC_ERROR_COMMUNICATION; +- complete(&req->c); +- } ++ /* Skip if request was already marked invalid */ ++ if (IS_ERR(req)) ++ continue; + +- /* Abort all queued requests */ +- list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { +- list_del(&req->link); +- req->in_queue = false; ++ /* For queued requests where supplicant has not seen it */ ++ if (req->in_queue) { ++ list_del(&req->link); ++ req->in_queue = false; ++ } ++ ++ req->processed = true; + req->ret = TEEC_ERROR_COMMUNICATION; + complete(&req->c); + } +@@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + + /* Insert the request in the request list */ + mutex_lock(&supp->mutex); ++ req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); ++ if (req->id < 0) { ++ mutex_unlock(&supp->mutex); ++ kfree(req); ++ return TEEC_ERROR_OUT_OF_MEMORY; ++ } ++ + list_add_tail(&req->link, &supp->reqs); + req->in_queue = true; ++ req->processed = false; + mutex_unlock(&supp->mutex); + + /* Tell an eventual waiter there's a new request */ +@@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + if (wait_for_completion_killable(&req->c)) { + mutex_lock(&supp->mutex); + if (req->in_queue) { ++ /* Supplicant has not seen this request yet. */ ++ idr_remove(&supp->idr, req->id); + list_del(&req->link); + req->in_queue = false; ++ ++ ret = TEEC_ERROR_COMMUNICATION; ++ } else if (req->processed) { ++ /* ++ * Supplicant has processed this request. Ignore the ++ * kill signal for now and submit the result. req is not ++ * in supp->reqs (removed by supp_pop_entry()) nor in ++ * supp->idr (removed by supp_pop_req()). ++ */ ++ ret = req->ret; ++ } else { ++ /* ++ * Supplicant is in the middle of processing this ++ * request. Replace req with INVALID_REQ_PTR so that ++ * the ID remains busy, causing optee_supp_send() to ++ * fail on the next call to supp_pop_req() with this ID. ++ */ ++ idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); ++ ret = TEEC_ERROR_COMMUNICATION; + } ++ + mutex_unlock(&supp->mutex); +- req->ret = TEEC_ERROR_COMMUNICATION; ++ } else { ++ ret = req->ret; + } + +- ret = req->ret; + kfree(req); + + return ret; + } + + static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, +- int num_params, int *id) ++ int num_params) + { + struct optee_supp_req *req; + +@@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, + return ERR_PTR(-EINVAL); + } + +- *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); +- if (*id < 0) +- return ERR_PTR(-ENOMEM); +- + list_del(&req->link); + req->in_queue = false; + +@@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + struct optee_supp_req *req = NULL; +- int id; + size_t num_meta; + int rc; + +@@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + + while (true) { + mutex_lock(&supp->mutex); +- req = supp_pop_entry(supp, *num_params - num_meta, &id); ++ req = supp_pop_entry(supp, *num_params - num_meta); ++ if (req) ++ break; /* Keep mutex held. */ + mutex_unlock(&supp->mutex); + +- if (req) { +- if (IS_ERR(req)) +- return PTR_ERR(req); +- break; +- } +- + /* + * If we didn't get a request we'll block in + * wait_for_completion() to avoid needless spinning. +@@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + return -ERESTARTSYS; + } + ++ /* supp->mutex held and req != NULL. */ ++ ++ if (IS_ERR(req)) { ++ mutex_unlock(&supp->mutex); ++ return PTR_ERR(req); ++ } ++ + if (num_meta) { + /* + * tee-supplicant support meta parameters -> requsts can be +@@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + */ + param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; +- param->u.value.a = id; ++ param->u.value.a = req->id; + param->u.value.b = 0; + param->u.value.c = 0; + } else { +- mutex_lock(&supp->mutex); +- supp->req_id = id; +- mutex_unlock(&supp->mutex); ++ supp->req_id = req->id; + } + + *func = req->func; +@@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + ++ mutex_unlock(&supp->mutex); + return 0; + } + +@@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, + if (!req) + return ERR_PTR(-ENOENT); + ++ /* optee_supp_thrd_req() already returned to optee. */ ++ if (IS_ERR(req)) ++ goto failed_req; ++ + if ((num_params - nm) != req->num_params) + return ERR_PTR(-EINVAL); + ++ *num_meta = nm; ++failed_req: + idr_remove(&supp->idr, id); + supp->req_id = -1; +- *num_meta = nm; + + return req; + } +@@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + + mutex_lock(&supp->mutex); + req = supp_pop_req(supp, num_params, param, &num_meta); +- mutex_unlock(&supp->mutex); +- + if (IS_ERR(req)) { +- /* Something is wrong, let supplicant restart. */ ++ mutex_unlock(&supp->mutex); ++ /* Something is wrong, let supplicant handel it. */ + return PTR_ERR(req); + } + +@@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + } + } + req->ret = ret; +- ++ req->processed = true; + /* Let the requesting thread continue */ + complete(&req->c); ++ mutex_unlock(&supp->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch b/queue-6.12/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch new file mode 100644 index 0000000000..a1985a1e25 --- /dev/null +++ b/queue-6.12/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch @@ -0,0 +1,55 @@ +From eb4ce7d7a563f721bbc55c3b39b93949546e6a49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:37 -0700 +Subject: vxlan: vnifilter: fix spurious notification on VNI update + +From: Andy Roulin + +[ Upstream commit 84683b5b60c7274e2c8f7f413d39d78d3db5540f ] + +When a VNI is re-added with the same attributes (e.g. same group or no +group), vxlan_vni_update() sends a spurious RTM_NEWTUNNEL notification +even though nothing changed. + +The bug is that 'if (changed)' tests whether the pointer is non-NULL, +not the bool value it points to. Since every caller passes a valid +pointer, the condition is always true and the notification fires +unconditionally. + +Fix by dereferencing the pointer: 'if (*changed)'. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 + # bridge vni add vni 1000 dev vxlan100 # spurious notification + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-3-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 1ab78a8bb9e011..272fa31ef07454 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -671,7 +671,7 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan, + if (ret) + return ret; + +- if (changed) ++ if (*changed) + vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/vxlan-vnifilter-send-notification-on-vni-add.patch b/queue-6.12/vxlan-vnifilter-send-notification-on-vni-add.patch new file mode 100644 index 0000000000..60b29c5287 --- /dev/null +++ b/queue-6.12/vxlan-vnifilter-send-notification-on-vni-add.patch @@ -0,0 +1,69 @@ +From 9996fd4ada87cd72370682cf6999c1beb23274f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:36 -0700 +Subject: vxlan: vnifilter: send notification on VNI add + +From: Andy Roulin + +[ Upstream commit aa6ca1c5c338907817374b59f7551fd855a88754 ] + +When a new VNI is added to a vxlan device with vnifilter enabled, +no RTM_NEWTUNNEL notification is sent to userspace. This means +'bridge monitor vni' never shows VNI add events, even though +VNI delete events are reported correctly. + +The bug is in vxlan_vni_add(), where the notification is guarded by +'if (changed)'. The 'changed' flag is set by vxlan_vni_update_group() +only when the multicast group or remote IP is modified, but for a +new VNI added without a group (e.g. in L3 VxLAN interface scenarios), +the function returns early without setting changed=true. Since this +is a new VNI, the notification should be sent unconditionally. + +The notification is not guarded by the return value of +vxlan_vni_update_group() because, at this point, the VNI has already +been inserted into the hash table and list with no rollback on error. +The VNI will be visible in 'bridge vni show' regardless, so userspace +should be informed. This is consistent with vxlan_vni_del() which also +notifies unconditionally. + +The 'if (changed)' guard remains correct in vxlan_vni_update(), which +handles the case where a VNI already exists and is being re-added -- +there, we only want to notify if the group/remote actually changed. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 # no notification + # bridge vni delete vni 1000 dev vxlan100 # notification received + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Reported-by: Chirag Shah +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-2-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 06d19e90eadb59..1ab78a8bb9e011 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -769,8 +769,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, + err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed, + extack); + +- if (changed) +- vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); ++ vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return err; + } +-- +2.53.0 + diff --git a/queue-6.12/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch b/queue-6.12/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch new file mode 100644 index 0000000000..31acf42e2f --- /dev/null +++ b/queue-6.12/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch @@ -0,0 +1,61 @@ +From 6382fe010e4ca3ae5aa318f30c74ada1f0e8c584 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 06:47:21 +0530 +Subject: wifi: mac80211: limit injected antenna index in + ieee80211_parse_tx_radiotap + +From: Deepanshu Kartikey + +[ Upstream commit 6c0cf89f36ac0c0fd8687a4ccdce2efb23a9c663 ] + +When parsing the radiotap header of an injected frame, +ieee80211_parse_tx_radiotap() uses the IEEE80211_RADIOTAP_ANTENNA value +directly as a shift count: + + info->control.antennas |= BIT(*iterator.this_arg); + +*iterator.this_arg is an 8-bit value taken straight from the frame +supplied by userspace, so BIT() can be asked to shift by up to 255. That +is undefined behaviour on the unsigned long and is reported by UBSAN: + + UBSAN: shift-out-of-bounds in net/mac80211/tx.c:2174:30 + shift exponent 235 is too large for 64-bit type 'unsigned long' + Call Trace: + ieee80211_parse_tx_radiotap+0xadb/0x1950 net/mac80211/tx.c:2174 + ieee80211_monitor_start_xmit+0xb1f/0x1250 net/mac80211/tx.c:2451 + ... + packet_sendmsg+0x3eb6/0x50f0 net/packet/af_packet.c:3109 + +info->control.antennas is a 2-bit bitmap (u8 antennas:2), so only antenna +indices 0 and 1 can ever be represented. Ignore any larger value instead +of shifting out of bounds. + +Reported-by: syzbot+8e0622f6d9446420271f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8e0622f6d9446420271f +Fixes: ef246a1480cc ("wifi: mac80211: support antenna control in injection") +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20260531011721.102941-1-kartikey406@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/tx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 0458cbba232e21..b82c7884a92db3 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -2169,7 +2169,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, + + case IEEE80211_RADIOTAP_ANTENNA: + /* this can appear multiple times, keep a bitmap */ +- info->control.antennas |= BIT(*iterator.this_arg); ++ /* control.antennas is only a 2-bit bitmap */ ++ if (*iterator.this_arg < 2) ++ info->control.antennas |= BIT(*iterator.this_arg); + break; + + case IEEE80211_RADIOTAP_DATA_RETRIES: +-- +2.53.0 + diff --git a/queue-6.18/6lowpan-fix-off-by-one-in-multicast-context-address-.patch b/queue-6.18/6lowpan-fix-off-by-one-in-multicast-context-address-.patch new file mode 100644 index 0000000000..a2ef324595 --- /dev/null +++ b/queue-6.18/6lowpan-fix-off-by-one-in-multicast-context-address-.patch @@ -0,0 +1,67 @@ +From 6be8b447edb1cf5f18babfe5ae6fe69f20e44524 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:18:01 +0800 +Subject: 6lowpan: fix off-by-one in multicast context address compression + +From: Yizhou Zhao + +[ Upstream commit 2a58899d11009bffc7b4b32a571858f381121837 ] + +The second memcpy in lowpan_iphc_mcast_ctx_addr_compress() uses +&data[1] as destination and &ipaddr->s6_addr[11] as source, but +both should be offset by one: &data[2] and &ipaddr->s6_addr[12] +respectively. + +This off-by-one has two consequences: +1. data[1] is overwritten with s6_addr[11], corrupting the RIID + field in the compressed multicast address +2. data[5] is never written, so uninitialized kernel stack memory + is transmitted over the network via lowpan_push_hc_data(), + leaking kernel stack contents + +The correct inline data layout must match what the decompression +function lowpan_uncompress_multicast_ctx_daddr() expects: + data[0..1] = s6_addr[1..2] (flags/scope + RIID) + data[2..5] = s6_addr[12..15] (group ID) + +Also zero-initialize the data array as a defensive measure against +similar bugs in the future. + +Fixes: 5609c185f24d ("6lowpan: iphc: add support for stateful compression") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Acked-by: Alexander Aring +Link: https://patch.msgid.link/20260527081806.42747-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/6lowpan/iphc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c +index e116d308a8df6d..37eaff3f7b6940 100644 +--- a/net/6lowpan/iphc.c ++++ b/net/6lowpan/iphc.c +@@ -1086,12 +1086,12 @@ static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, + const struct lowpan_iphc_ctx *ctx, + const struct in6_addr *ipaddr) + { +- u8 data[6]; ++ u8 data[6] = {}; + + /* flags/scope, reserved (RIID) */ + memcpy(data, &ipaddr->s6_addr[1], 2); + /* group ID */ +- memcpy(&data[1], &ipaddr->s6_addr[11], 4); ++ memcpy(&data[2], &ipaddr->s6_addr[12], 4); + lowpan_push_hc_data(hc_ptr, data, 6); + + return LOWPAN_IPHC_DAM_00; +-- +2.53.0 + diff --git a/queue-6.18/af_unix-fix-inq_len-update-problem-in-partial-read.patch b/queue-6.18/af_unix-fix-inq_len-update-problem-in-partial-read.patch new file mode 100644 index 0000000000..3bd5aec387 --- /dev/null +++ b/queue-6.18/af_unix-fix-inq_len-update-problem-in-partial-read.patch @@ -0,0 +1,60 @@ +From 289519c54e407fb9c75630b620820d759f7bac9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 19:36:39 +0800 +Subject: af_unix: Fix inq_len update problem in partial read + +From: Jianyu Li + +[ Upstream commit c1f07a7f2d47aeb9878301e7bb36bc1c2bc2be8e ] + +Currently inq_len is updated only when the whole skb is consumed. +If only part of the data is read, following SIOCINQ query would +get value greater than what actually left. + +This change update inq_len timely in unix_stream_read_generic(), +and adjust unix_stream_read_skb() accordingly to prevent +repetitive update. + +Fixes: f4e1fb04c123 ("af_unix: Use cached value for SOCK_STREAM in unix_inq_len().") +Signed-off-by: Jianyu Li +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260601113640.231897-2-jianyu.li@mediatek.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index faf04d1b6c013c..b339f83caf036e 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2891,7 +2891,7 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor) + return -EAGAIN; + } + +- WRITE_ONCE(u->inq_len, u->inq_len - skb->len); ++ WRITE_ONCE(u->inq_len, u->inq_len - unix_skb_len(skb)); + + #if IS_ENABLED(CONFIG_AF_UNIX_OOB) + if (skb == u->oob_skb) { +@@ -3065,11 +3065,12 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, + unix_detach_fds(&scm, skb); + } + +- if (unix_skb_len(skb)) +- break; +- + spin_lock(&sk->sk_receive_queue.lock); +- WRITE_ONCE(u->inq_len, u->inq_len - skb->len); ++ WRITE_ONCE(u->inq_len, u->inq_len - chunk); ++ if (unix_skb_len(skb)) { ++ spin_unlock(&sk->sk_receive_queue.lock); ++ break; ++ } + __skb_unlink(skb, &sk->sk_receive_queue); + spin_unlock(&sk->sk_receive_queue.lock); + +-- +2.53.0 + diff --git a/queue-6.18/arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch b/queue-6.18/arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch new file mode 100644 index 0000000000..f2ef95b0cc --- /dev/null +++ b/queue-6.18/arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch @@ -0,0 +1,56 @@ +From ba748aca4bd9f4a5ab450a8cd4057518ce9ef09c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:53:29 +0200 +Subject: ARM: dts: microchip: sam9x7: fix GMAC clock configuration + +From: Mihai Sain + +[ Upstream commit 765aaba18413a66f6c8fe8416336ca9b3dd98a79 ] + +The GMAC node incorrectly listed four clocks, including a separate tx_clk +and a TSU GCK clock sourced from ID 67. According to the SAM9X7 clocking +scheme, the GMAC uses only three clocks: HCLK, PCLK, and the TSU GCK +derived from the GMAC peripheral clock (ID 24). + +Remove the unused tx_clk, update the clock-names accordingly, and correct +the assigned clock to use GCK 24 instead of GCK 67. This aligns the device +tree with the actual hardware clock topology and prevents misconfiguration +of the GMAC clock tree. + +[root@SAM9X75 ~]$ cat /sys/kernel/debug/clk/clk_summary | grep gmac + +gmac_gclk 1 1 1 266666666 0 0 50000 Y f802c000.ethernet tsu_clk + f802c000.ethernet tsu_clk +gmac_clk 2 2 0 266666666 0 0 50000 Y f802c000.ethernet hclk + f802c000.ethernet pclk + +Fixes: 41af45af8bc3 ("ARM: dts: at91: sam9x7: add device tree for SoC") +Signed-off-by: Mihai Sain +Link: https://lore.kernel.org/r/20260309075329.1528-5-mihai.sain@microchip.com +[claudiu.beznea: massaged the patch description] +Signed-off-by: Claudiu Beznea +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/microchip/sam9x7.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/microchip/sam9x7.dtsi b/arch/arm/boot/dts/microchip/sam9x7.dtsi +index d242d7a934d0fa..c680a5033b6b4e 100644 +--- a/arch/arm/boot/dts/microchip/sam9x7.dtsi ++++ b/arch/arm/boot/dts/microchip/sam9x7.dtsi +@@ -990,9 +990,9 @@ gmac: ethernet@f802c000 { + <62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */ + <63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */ + <64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */ +- clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>, <&pmc PMC_TYPE_GCK 67>; +- clock-names = "hclk", "pclk", "tx_clk", "tsu_clk"; +- assigned-clocks = <&pmc PMC_TYPE_GCK 67>; ++ clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>; ++ clock-names = "hclk", "pclk", "tsu_clk"; ++ assigned-clocks = <&pmc PMC_TYPE_GCK 24>; + assigned-clock-rates = <266666666>; + status = "disabled"; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch b/queue-6.18/arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch new file mode 100644 index 0000000000..e77f709386 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch @@ -0,0 +1,53 @@ +From bb6f4ebba7d67e9365cc1c19421838b8535a4ae5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 21:53:37 -0300 +Subject: arm64: dts: qcom: x1-dell-thena: remove i2c20 (battery SMBus) and + reserve its pins + +From: Val Packett + +[ Upstream commit 4b15b03166cc5d28e9912287b1f9b6607c8710ec ] + +i2c20 is used by the battmgr service on the ADSP to communicate with the +SBS interface of the battery. Initializing it from Linux would break the +battmgr functionality when booted in EL2. Mark those pins as reserved. + +Fixes: e7733b42111c ("arm64: dts: qcom: Add support for Dell Inspiron 7441 / Latitude 7455") +Reviewed-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312005731.12488-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +index 847b678f040c00..5b5a10a31a253a 100644 +--- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +@@ -982,12 +982,6 @@ &i2c8 { + status = "okay"; + }; + +-&i2c20 { +- clock-frequency = <400000>; +- +- status = "okay"; +-}; +- + &lpass_tlmm { + spkr_01_sd_n_active: spkr-01-sd-n-active-state { + pins = "gpio12"; +@@ -1306,6 +1300,7 @@ right_tweeter: speaker@0,1 { + &tlmm { + gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */ + <76 4>, /* SPI19 (TZ Protected) */ ++ <80 2>, /* I2C20 (Battery SMBus) */ + <238 1>; /* UFS Reset */ + + cam_rgb_default: cam-rgb-default-state { +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch b/queue-6.18/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch new file mode 100644 index 0000000000..8fa80cde25 --- /dev/null +++ b/queue-6.18/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch @@ -0,0 +1,71 @@ +From 679966cc98c19bd833847bd527dd55aef6f2a20c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:39:53 +0800 +Subject: Bluetooth: bnep: fix incorrect length parsing in bnep_rx_frame() + extension handling + +From: Dudu Lu + +[ Upstream commit 72b8deccff17a7644e0367e1aaf1a36cfb014324 ] + +In bnep_rx_frame(), the BNEP_FILTER_NET_TYPE_SET and +BNEP_FILTER_MULTI_ADDR_SET extension header parsing has two bugs: + +1) The 2-byte length field is read with *(u16 *)(skb->data + 1), which + performs a native-endian read. The BNEP protocol specifies this field + in big-endian (network byte order), and the same file correctly uses + get_unaligned_be16() for the identical fields in + bnep_ctrl_set_netfilter() and bnep_ctrl_set_mcfilter(). + +2) The length is multiplied by 2, but unlike BNEP_SETUP_CONN_REQ where + the length byte counts UUID pairs (requiring * 2 for two UUIDs per + entry), the filter extension length field already represents the total + data size in bytes. This is confirmed by bnep_ctrl_set_netfilter() + which reads the same field as a byte count and divides by 4 to get + the number of filter entries. + + The bogus * 2 means skb_pull advances twice as far as it should, + either dropping valid data from the next header or causing the pull + to fail entirely when the doubled length exceeds the remaining skb. + +Fix by splitting the pull into two steps: first use skb_pull_data() to +safely pull and validate the 3-byte fixed header (ctrl type + length), +then pull the variable-length data using the properly decoded length. + +Fixes: bf8b9a9cb77b ("Bluetooth: bnep: Add support to extended headers of control frames") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index b3cef7a4db5412..0de5df690bd0b2 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -330,11 +330,18 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + goto badframe; + break; + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: +- /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */ +- if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2)) ++ case BNEP_FILTER_NET_TYPE_SET: { ++ u8 *hdr; ++ ++ /* Pull ctrl type (1 b) + len (2 b) */ ++ hdr = skb_pull_data(skb, 3); ++ if (!hdr) ++ goto badframe; ++ /* Pull data (len bytes); length is big-endian */ ++ if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) + goto badframe; + break; ++ } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-bnep-reject-short-frames-before-parsing.patch b/queue-6.18/bluetooth-bnep-reject-short-frames-before-parsing.patch new file mode 100644 index 0000000000..a964aec484 --- /dev/null +++ b/queue-6.18/bluetooth-bnep-reject-short-frames-before-parsing.patch @@ -0,0 +1,170 @@ +From ef7e5bc527e344f789ad03691086bf793d6eab80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 11:22:09 +0800 +Subject: Bluetooth: bnep: reject short frames before parsing + +From: Zhang Cen + +[ Upstream commit 6770d3a8acdf9151769180cc3710346c4cfbe6f0 ] + +A BNEP peer can send a short BNEP SDU. bnep_rx_frame() reads the +packet type byte immediately and, for control packets, reads the control +opcode and setup UUID-size byte before proving that those bytes are +present. bnep_rx_control() also dereferences the control opcode without +rejecting an empty control payload. + +Use skb_pull_data() for the fixed fields in bnep_rx_frame() so a NULL +return gates each dereference. Split the control handler so the frame +path can pass an opcode that has already been pulled, and keep the +byte-buffer wrapper for extension control payloads. + +For BNEP_SETUP_CONN_REQ, name the UUID-size byte before pulling the +setup payload. struct bnep_setup_conn_req carries destination and source +service UUIDs after that byte, each uuid_size bytes, so the parser now +documents that tuple explicitly instead of leaving the pull length as an +opaque multiplication. + +Validation reproduced this kernel report: +KASAN slab-out-of-bounds in bnep_rx_frame.isra.0+0x130c/0x1790 +The buggy address belongs to the object at ffff88800c0f7908 which belongs +to the cache kmalloc-8 of size 8 +The buggy address is located 0 bytes to the right of allocated 1-byte +region [ffff88800c0f7908, ffff88800c0f7909) +Read of size 1 +Call trace: + dump_stack_lvl+0xb3/0x140 (?:?) + print_address_description+0x57/0x3a0 (?:?) + bnep_rx_frame+0x130c/0x1790 (net/bluetooth/bnep/core.c:306) + print_report+0xb9/0x2b0 (?:?) + __virt_addr_valid+0x1ba/0x3a0 (?:?) + srso_alias_return_thunk+0x5/0xfbef5 (?:?) + kasan_addr_to_slab+0x21/0x60 (?:?) + kasan_report+0xe0/0x110 (?:?) + process_one_work+0xfce/0x17e0 (kernel/workqueue.c:3200) + worker_thread+0x65c/0xe40 (?:?) + __kthread_parkme+0x184/0x230 (?:?) + kthread+0x35e/0x470 (?:?) + _raw_spin_unlock_irq+0x28/0x50 (?:?) + ret_from_fork+0x586/0x870 (?:?) + __switch_to+0x74f/0xdc0 (?:?) + ret_from_fork_asm+0x1a/0x30 (?:?) + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 57 ++++++++++++++++++++++++--------------- + 1 file changed, 36 insertions(+), 21 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index 0de5df690bd0b2..5c5f53ff30e8e5 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -206,14 +206,11 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) + return 0; + } + +-static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++static int bnep_rx_control_cmd(struct bnep_session *s, u8 cmd, void *data, ++ int len) + { +- u8 cmd = *(u8 *)data; + int err = 0; + +- data++; +- len--; +- + switch (cmd) { + case BNEP_CMD_NOT_UNDERSTOOD: + case BNEP_SETUP_CONN_RSP: +@@ -254,6 +251,14 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) + return err; + } + ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ if (len < 1) ++ return -EILSEQ; ++ ++ return bnep_rx_control_cmd(s, *(u8 *)data, data + 1, len - 1); ++} ++ + static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) + { + struct bnep_ext_hdr *h; +@@ -299,19 +304,26 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + { + struct net_device *dev = s->dev; + struct sk_buff *nskb; ++ u8 *data; + u8 type, ctrl_type; + + dev->stats.rx_bytes += skb->len; + +- type = *(u8 *) skb->data; +- skb_pull(skb, 1); +- ctrl_type = *(u8 *)skb->data; ++ data = skb_pull_data(skb, sizeof(type)); ++ if (!data) ++ goto badframe; ++ type = *data; + + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) + goto badframe; + + if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { +- if (bnep_rx_control(s, skb->data, skb->len) < 0) { ++ data = skb_pull_data(skb, sizeof(ctrl_type)); ++ if (!data) ++ goto badframe; ++ ctrl_type = *data; ++ ++ if (bnep_rx_control_cmd(s, ctrl_type, skb->data, skb->len) < 0) { + dev->stats.tx_errors++; + kfree_skb(skb); + return 0; +@@ -324,24 +336,27 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + + /* Verify and pull ctrl message since it's already processed */ + switch (ctrl_type) { +- case BNEP_SETUP_CONN_REQ: +- /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */ +- if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2)) ++ case BNEP_SETUP_CONN_REQ: { ++ u8 uuid_size; ++ ++ /* Pull uuid_size and the dst/src service UUIDs. */ ++ data = skb_pull_data(skb, sizeof(uuid_size)); ++ if (!data) ++ goto badframe; ++ uuid_size = *data; ++ if (!skb_pull(skb, uuid_size + uuid_size)) + goto badframe; + break; ++ } + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: { +- u8 *hdr; +- +- /* Pull ctrl type (1 b) + len (2 b) */ +- hdr = skb_pull_data(skb, 3); +- if (!hdr) ++ case BNEP_FILTER_NET_TYPE_SET: ++ /* Pull: len (2 b), data (len bytes) */ ++ data = skb_pull_data(skb, sizeof(u16)); ++ if (!data) + goto badframe; +- /* Pull data (len bytes); length is big-endian */ +- if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) ++ if (!skb_pull(skb, get_unaligned_be16(data))) + goto badframe; + break; +- } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch b/queue-6.18/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch new file mode 100644 index 0000000000..4da1c5167f --- /dev/null +++ b/queue-6.18/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch @@ -0,0 +1,58 @@ +From a0c4e2eec04bb3ca408aa2aff7d619ce4a19607f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 08:54:26 +0530 +Subject: Bluetooth: fix memory leak in error path of hci_alloc_dev() + +From: Bharath Reddy + +[ Upstream commit 37b3009bf5976e8ab77c8b9a9bc3bbd7ff49e37f ] + +Early failures in Bluetooth HCI UART configuration leak SRCU percpu +memory. + +When device initialization fails before hci_register_dev() completes, +the HCI_UNREGISTER flag is never set. As a result, when the device +reference count reaches zero, bt_host_release() evaluates this flag as +false and falls back to a direct kfree(hdev). + +Because hci_release_dev() is bypassed, the SRCU struct initialized +early in hci_alloc_dev() is never cleaned up, resulting in a leak of +percpu memory. + +Fix the leak by explicitly calling cleanup_srcu_struct() in the +fallback (unregistered) branch of bt_host_release() before freeing +the device. + +Reported-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=535ecc844591e50588a5 +Tested-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Fixes: 1d6123102e9f ("Bluetooth: hci_core: Fix use-after-free in vhci_flush()") +Signed-off-by: Bharath Reddy +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sysfs.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c +index 041ce9adc378ae..8957ce7c21b76c 100644 +--- a/net/bluetooth/hci_sysfs.c ++++ b/net/bluetooth/hci_sysfs.c +@@ -83,10 +83,12 @@ static void bt_host_release(struct device *dev) + { + struct hci_dev *hdev = to_hci_dev(dev); + +- if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) ++ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + hci_release_dev(hdev); +- else ++ } else { ++ cleanup_srcu_struct(&hdev->srcu); + kfree(hdev); ++ } + module_put(THIS_MODULE); + } + +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch b/queue-6.18/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch new file mode 100644 index 0000000000..38f7cc693f --- /dev/null +++ b/queue-6.18/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch @@ -0,0 +1,157 @@ +From f633d9bbb4434b66d7516b1dc4123908de67839b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 20:19:07 +0900 +Subject: Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls + +From: SeungJu Cheon + +[ Upstream commit 9ca7053d6215d89c33f28893bfd1625a32919d3f ] + +iso_connect_bis(), iso_connect_cis(), iso_listen_bis(), and +iso_conn_big_sync() call hci_get_route() using iso_pi(sk)->dst, +iso_pi(sk)->src, and iso_pi(sk)->src_type without holding lock_sock(). + +These fields may be modified concurrently by connect() or setsockopt() +on the same socket, resulting in data-races reported by KCSAN. + +Fix this by snapshotting the required fields under lock_sock() before +calling hci_get_route(). + +BUG: KCSAN: data-race in memcmp+0x45/0xb0 + +race at unknown origin, with read to 0xffff8880122135cf of 1 bytes +by task 333 on cpu 1: + memcmp+0x45/0xb0 + hci_get_route+0x27e/0x490 + iso_connect_cis+0x4c/0xa10 + iso_sock_connect+0x60e/0xb30 + __sys_connect_file+0xbd/0xe0 + __sys_connect+0xe0/0x110 + __x64_sys_connect+0x40/0x50 + x64_sys_call+0xcad/0x1c60 + do_syscall_64+0x133/0x590 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: 241f51931c35 ("Bluetooth: ISO: Avoid circular locking dependency") +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 60 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 44 insertions(+), 16 deletions(-) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 355487613c82a0..c1e3015a6630d5 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -336,12 +336,20 @@ static int iso_connect_bis(struct sock *sk) + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type, bc_sid; + int err; + +- BT_DBG("%pMR (SID 0x%2.2x)", &iso_pi(sk)->src, iso_pi(sk)->bc_sid); ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ bc_sid = iso_pi(sk)->bc_sid; ++ release_sock(sk); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ BT_DBG("%pMR (SID 0x%2.2x)", &src, bc_sid); ++ ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -433,12 +441,19 @@ static int iso_connect_cis(struct sock *sk) + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type; + int err; + +- BT_DBG("%pMR -> %pMR", &iso_pi(sk)->src, &iso_pi(sk)->dst); ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ release_sock(sk); ++ ++ BT_DBG("%pMR -> %pMR", &src, &dst); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -1138,18 +1153,25 @@ static int iso_sock_connect(struct socket *sock, struct sockaddr *addr, + + static int iso_listen_bis(struct sock *sk) + { +- struct hci_dev *hdev; +- int err = 0; + struct iso_conn *conn; + struct hci_conn *hcon; ++ struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type, bc_sid; ++ int err = 0; ++ ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ bc_sid = iso_pi(sk)->bc_sid; ++ release_sock(sk); + +- BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src, +- &iso_pi(sk)->dst, iso_pi(sk)->bc_sid); ++ BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &src, &dst, bc_sid); + + write_lock(&iso_sk_list.lock); + +- if (__iso_get_sock_listen_by_sid(&iso_pi(sk)->src, &iso_pi(sk)->dst, +- iso_pi(sk)->bc_sid)) ++ if (__iso_get_sock_listen_by_sid(&src, &dst, bc_sid)) + err = -EADDRINUSE; + + write_unlock(&iso_sk_list.lock); +@@ -1157,8 +1179,7 @@ static int iso_listen_bis(struct sock *sk) + if (err) + return err; + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -1494,9 +1515,16 @@ static void iso_conn_big_sync(struct sock *sk) + { + int err; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type; ++ ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ release_sock(sk); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + + if (!hdev) + return; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch b/queue-6.18/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch new file mode 100644 index 0000000000..9fa0b3552b --- /dev/null +++ b/queue-6.18/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch @@ -0,0 +1,36 @@ +From 3b8b08499b44e9ded90f5623bc11214eede0b337 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 14:45:42 -0400 +Subject: Bluetooth: ISO: Fix not releasing hdev reference on iso_conn_big_sync + +From: Luiz Augusto von Dentz + +[ Upstream commit 5cbf290b79351971f20c7a533247e8d58a3f970c ] + +hci_get_route() returns a reference-counted hci_dev pointer via +hci_dev_hold(). The function exits normally or with an error without ever +releasing it. + +Fixes: 07a9342b94a9 ("Bluetooth: ISO: Send BIG Create Sync via hci_sync") +Reported-by: Sashiko +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 9b421e4a2466f7..355487613c82a0 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -1521,6 +1521,7 @@ static void iso_conn_big_sync(struct sock *sk) + + release_sock(sk); + hci_dev_unlock(hdev); ++ hci_dev_put(hdev); + } + + static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-mgmt-fix-backward-compatibility-with-users.patch b/queue-6.18/bluetooth-mgmt-fix-backward-compatibility-with-users.patch new file mode 100644 index 0000000000..8ad8d538e5 --- /dev/null +++ b/queue-6.18/bluetooth-mgmt-fix-backward-compatibility-with-users.patch @@ -0,0 +1,43 @@ +From 5c267a5c381b0de5a4f5e6b4df829e9d61d2571f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:48:34 -0400 +Subject: Bluetooth: MGMT: Fix backward compatibility with userspace + +From: Luiz Augusto von Dentz + +[ Upstream commit 149324fc762c2a7acef9c26790566f81f475e51f ] + +bluetoothd has a bug with makes it send extra bytes as part of +MGMT_OP_ADD_EXT_ADV_DATA which are now being checked to be the +exact the expected length, relax this so only when the expected +length is greater than the data length to cause an error since +that would result in accessing invalid memory, otherwise just +ignore the extra bytes. + +Link: https://lore.kernel.org/linux-bluetooth/20260602204749.210857-1-luiz.dentz@gmail.com/T/#u +Fixes: d3f7d17960ed ("Bluetooth: MGMT: validate Add Extended Advertising Data length") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 9bb82d1fdc3cad..c87ec0138c430b 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -9098,8 +9098,9 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data, + + BT_DBG("%s", hdev->name); + +- expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len); +- if (expected_len != data_len) ++ expected_len = struct_size(cp, data, cp->adv_data_len + ++ cp->scan_rsp_len); ++ if (expected_len > data_len) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_INVALID_PARAMS); + +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch b/queue-6.18/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch new file mode 100644 index 0000000000..0a3659242c --- /dev/null +++ b/queue-6.18/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch @@ -0,0 +1,73 @@ +From 02eb89cb047559a5667489fb7d7b5b741d27d40b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 17:45:06 +0800 +Subject: Bluetooth: MGMT: validate advertising TLV before type checks + +From: Zhang Cen + +[ Upstream commit de23fb62259aa01d294f77238ae3b835eb674413 ] + +tlv_data_is_valid() reads each advertising data field length from +data[i], then inspects data[i + 1] for managed EIR types before +checking that the current field still fits inside the supplied buffer. + +A malformed field whose length byte is the last byte of the buffer can +therefore make the parser read one byte past the advertising data. + +KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING +request reached that path: + + BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid() + Read of size 1 + Call trace: + tlv_data_is_valid() + add_advertising() + hci_mgmt_cmd() + hci_sock_sendmsg() + +Move the existing element-length check before any type-octet inspection +so each non-empty element is proven to contain its type byte before the +parser looks at data[i + 1]. + +Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check") +Reviewed-by: Paul Menzel +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 91d1c0d132f9e1..9bb82d1fdc3cad 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -8622,6 +8622,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (!cur_len) + continue; + ++ /* If the current field length would exceed the total data ++ * length, then it's invalid. ++ */ ++ if (i + cur_len >= len) ++ return false; ++ + if (data[i + 1] == EIR_FLAGS && + (!is_adv_data || flags_managed(adv_flags))) + return false; +@@ -8638,12 +8644,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (data[i + 1] == EIR_APPEARANCE && + appearance_managed(adv_flags)) + return false; +- +- /* If the current field length would exceed the total data +- * length, then it's invalid. +- */ +- if (i + cur_len >= len) +- return false; + } + + return true; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch b/queue-6.18/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch new file mode 100644 index 0000000000..f43662de36 --- /dev/null +++ b/queue-6.18/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch @@ -0,0 +1,126 @@ +From 6baf3c8af14a9be825a91d4720c42ec01f85f432 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 15:56:41 +0800 +Subject: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() + +From: Zhang Cen + +[ Upstream commit 43c441edacf953b39517a44f5e5e10a93618b226 ] + +rfcomm_get_sock_by_channel() scans rfcomm_sk_list under the list lock, +but returns the selected listener after dropping that lock without +taking a reference. rfcomm_connect_ind() then locks the listener, +queues a child socket on it, and may notify it after unlocking it. + +The buggy scenario involves two paths, with each column showing the +order within that path: + +rfcomm_connect_ind(): listener close: + 1. Find parent in 1. close() enters + rfcomm_get_sock_by_channel() rfcomm_sock_release(). + 2. Drop rfcomm_sk_list.lock 2. rfcomm_sock_shutdown() + without pinning parent. closes the listener. + 3. Call lock_sock(parent) and 3. rfcomm_sock_kill() + bt_accept_enqueue(parent, unlinks and puts parent. + sk, true). + 4. Read parent flags and may 4. parent can be freed. + call sk_state_change(). + +If close wins the race, parent can be freed before +rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or the +deferred-setup callback. + +Take a reference on the listener before leaving rfcomm_sk_list.lock. +After lock_sock() succeeds, recheck that it is still in BT_LISTEN +before queueing a child, cache the deferred-setup bit while the parent +is locked, and drop the reference after the last parent use. + +KASAN reported a slab-use-after-free in lock_sock_nested() from +rfcomm_connect_ind(), with the freeing stack going through +rfcomm_sock_kill() and rfcomm_sock_release(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index 3052436e9c6de5..2286efef62f5b6 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) + } + + /* Find socket with channel and source bdaddr. +- * Returns closest match. ++ * Returns closest match with an extra reference held. + */ + static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) + { +@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t * + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ +- if (!bacmp(&rfcomm_pi(sk)->src, src)) ++ if (!bacmp(&rfcomm_pi(sk)->src, src)) { ++ sock_hold(sk); + break; ++ } + + /* Closest match */ +- if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) ++ if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) { ++ if (sk1) ++ sock_put(sk1); ++ + sk1 = sk; ++ sock_hold(sk1); ++ } + } + } + ++ if (sk && sk1) ++ sock_put(sk1); ++ + read_unlock(&rfcomm_sk_list.lock); + + return sk ? sk : sk1; +@@ -940,6 +950,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + { + struct sock *sk, *parent; + bdaddr_t src, dst; ++ bool defer_setup = false; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); +@@ -953,6 +964,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + + lock_sock(parent); + ++ if (parent->sk_state != BT_LISTEN) ++ goto done; ++ ++ defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -980,9 +996,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + done: + release_sock(parent); + +- if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) ++ if (defer_setup) + parent->sk_state_change(parent); + ++ sock_put(parent); ++ + return result; + } + +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch b/queue-6.18/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch new file mode 100644 index 0000000000..473d92d65d --- /dev/null +++ b/queue-6.18/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch @@ -0,0 +1,167 @@ +From ba692464bb091ebb574316ec4b9be5503d96c037 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:04:43 +0900 +Subject: Bluetooth: RFCOMM: validate skb length in MCC handlers + +From: SeungJu Cheon + +[ Upstream commit 23882b828c3c8c51d0c946446a396b10abb3b16b ] + +The RFCOMM MCC handlers cast skb->data to protocol-specific structs +without validating skb->len first. A malicious remote device can send +truncated MCC frames and trigger out-of-bounds reads in these handlers. + +Fix this by using skb_pull_data() to validate and access the required +data before dereferencing it. + +rfcomm_recv_rpn() requires special handling since ETSI TS 07.10 allows +1-byte RPN requests. Handle this by validating only the DLCI byte first, +and validating the full struct only when len > 1. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Suggested-by: Muhammad Bilal +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/core.c | 67 +++++++++++++++++++++++++++---------- + 1 file changed, 49 insertions(+), 18 deletions(-) + +diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c +index 96250807b32b44..dfade1933fa730 100644 +--- a/net/bluetooth/rfcomm/core.c ++++ b/net/bluetooth/rfcomm/core.c +@@ -1431,10 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) + + static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_pn *pn; + struct rfcomm_dlc *d; +- u8 dlci = pn->dlci; ++ u8 dlci; ++ ++ pn = skb_pull_data(skb, sizeof(*pn)); ++ if (!pn) ++ return -EILSEQ; + ++ dlci = pn->dlci; + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) +@@ -1483,8 +1488,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + + static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) + { +- struct rfcomm_rpn *rpn = (void *) skb->data; +- u8 dlci = __get_dlci(rpn->dlci); ++ struct rfcomm_rpn *rpn; ++ u8 dlci; + + u8 bit_rate = 0; + u8 data_bits = 0; +@@ -1495,15 +1500,16 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + u8 xoff_char = 0; + u16 rpn_mask = RFCOMM_RPN_PM_ALL; + +- BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", +- dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, +- rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ if (len == 1) { ++ rpn = skb_pull_data(skb, 1); ++ if (!rpn) ++ return -EILSEQ; + +- if (!cr) +- return 0; ++ dlci = __get_dlci(rpn->dlci); ++ ++ if (!cr) ++ return 0; + +- if (len == 1) { +- /* This is a request, return default (according to ETSI TS 07.10) settings */ + bit_rate = RFCOMM_RPN_BR_9600; + data_bits = RFCOMM_RPN_DATA_8; + stop_bits = RFCOMM_RPN_STOP_1; +@@ -1514,6 +1520,19 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + goto rpn_out; + } + ++ rpn = skb_pull_data(skb, sizeof(*rpn)); ++ if (!rpn) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rpn->dlci); ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ + /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit, + * no parity, no flow control lines, normal XON/XOFF chars */ + +@@ -1589,9 +1608,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + + static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_rls *rls = (void *) skb->data; +- u8 dlci = __get_dlci(rls->dlci); ++ struct rfcomm_rls *rls; ++ u8 dlci; + ++ rls = skb_pull_data(skb, sizeof(*rls)); ++ if (!rls) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rls->dlci); + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) +@@ -1608,10 +1632,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_msc *msc; + struct rfcomm_dlc *d; +- u8 dlci = __get_dlci(msc->dlci); ++ u8 dlci; ++ ++ msc = skb_pull_data(skb, sizeof(*msc)); ++ if (!msc) ++ return -EILSEQ; + ++ dlci = __get_dlci(msc->dlci); + BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); + + d = rfcomm_dlc_get(s, dlci); +@@ -1644,17 +1673,19 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) + { +- struct rfcomm_mcc *mcc = (void *) skb->data; ++ struct rfcomm_mcc *mcc; + u8 type, cr, len; + ++ mcc = skb_pull_data(skb, sizeof(*mcc)); ++ if (!mcc) ++ return -EILSEQ; ++ + cr = __test_cr(mcc->type); + type = __get_mcc_type(mcc->type); + len = __get_mcc_len(mcc->len); + + BT_DBG("%p type 0x%x cr %d", s, type, cr); + +- skb_pull(skb, 2); +- + switch (type) { + case RFCOMM_PN: + rfcomm_recv_pn(s, cr, skb); +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch b/queue-6.18/bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch new file mode 100644 index 0000000000..e0259ec11a --- /dev/null +++ b/queue-6.18/bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch @@ -0,0 +1,96 @@ +From f1f36984a93c743e274e14081bc73b82756c2b99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 20:19:08 +0900 +Subject: Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect + +From: SeungJu Cheon + +[ Upstream commit 4847c5bca22227100ae69e96af86618b6fd2671f ] + +sco_sock_connect() copies the destination address into sco_pi(sk)->dst +under lock_sock(), then releases the lock and calls sco_connect(), +which reads dst, src, setting, and codec without holding lock_sock() in +hci_get_route() and hci_connect_sco(). + +These fields may be modified concurrently by connect(), bind(), or +setsockopt() on the same socket, resulting in data-races reported by +KCSAN. + +Fix this by snapshotting dst, src, setting, and codec under lock_sock() +at the start of sco_connect() before passing them to hci_get_route() +and hci_connect_sco(). + +BUG: KCSAN: data-race in memcmp+0x45/0xb0 + +race at unknown origin, with read to 0xffff88800e6b0dd0 of 1 bytes +by task 315 on cpu 0: + memcmp+0x45/0xb0 + hci_connect_acl+0x1b7/0x6b0 + hci_connect_sco+0x4d/0xb30 + sco_sock_connect+0x27b/0xd60 + __sys_connect_file+0xbd/0xe0 + __sys_connect+0xe0/0x110 + __x64_sys_connect+0x40/0x50 + x64_sys_call+0xcad/0x1c60 + do_syscall_64+0x133/0x590 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm") +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/sco.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index a536c2edd14f24..a19ae1b39bc02f 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -312,11 +312,21 @@ static int sco_connect(struct sock *sk) + struct sco_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ struct bt_codec codec; ++ __u16 setting; + int err, type; + +- BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst); ++ lock_sock(sk); ++ bacpy(&src, &sco_pi(sk)->src); ++ bacpy(&dst, &sco_pi(sk)->dst); ++ setting = sco_pi(sk)->setting; ++ codec = sco_pi(sk)->codec; ++ release_sock(sk); ++ ++ BT_DBG("%pMR -> %pMR", &src, &dst); + +- hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR); ++ hdev = hci_get_route(&dst, &src, BDADDR_BREDR); + if (!hdev) + return -EHOSTUNREACH; + +@@ -327,7 +337,7 @@ static int sco_connect(struct sock *sk) + else + type = SCO_LINK; + +- switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) { ++ switch (setting & SCO_AIRMODE_MASK) { + case SCO_AIRMODE_TRANSP: + if (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev)) { + err = -EOPNOTSUPP; +@@ -336,8 +346,8 @@ static int sco_connect(struct sock *sk) + break; + } + +- hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst, +- sco_pi(sk)->setting, &sco_pi(sk)->codec, ++ hcon = hci_connect_sco(hdev, type, &dst, ++ setting, &codec, + READ_ONCE(sk->sk_sndtimeo)); + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); +-- +2.53.0 + diff --git a/queue-6.18/devlink-release-nested-relation-on-devlink-free.patch b/queue-6.18/devlink-release-nested-relation-on-devlink-free.patch new file mode 100644 index 0000000000..bc58449043 --- /dev/null +++ b/queue-6.18/devlink-release-nested-relation-on-devlink-free.patch @@ -0,0 +1,49 @@ +From f691b230f1b949237fe5b72ed56660e22bcb6b22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 22:14:10 +0300 +Subject: devlink: Release nested relation on devlink free + +From: Mark Bloch + +[ Upstream commit 3522b21fd7e1863d0734537737bd59f1b90d0190 ] + +devlink relation state is normally released from devl_unregister(), which +calls devlink_rel_put(). This misses devlink instances that get a nested +relation before registration and then fail probe before devl_register() is +reached. + +That flow can happen for SFs. The child devlink gets linked to its +parent before registration, then a later probe error calls devlink_free() +directly. Since the instance was never registered, devl_unregister() is not +called and devlink->rel is leaked. + +Release any pending relation from devlink_free() as well. The registered +path is unchanged because devl_unregister() already clears devlink->rel +before devlink_free() runs. + +Fixes: c137743bce02 ("devlink: introduce object and nested devlink relationship infra") +Signed-off-by: Mark Bloch +Reviewed-by: Jiri Pirko +Link: https://patch.msgid.link/20260528191411.3270532-1-mbloch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/devlink/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/devlink/core.c b/net/devlink/core.c +index 58093f49c0905e..d8f875b229897e 100644 +--- a/net/devlink/core.c ++++ b/net/devlink/core.c +@@ -469,6 +469,8 @@ void devlink_free(struct devlink *devlink) + { + ASSERT_DEVLINK_NOT_REGISTERED(devlink); + ++ devlink_rel_put(devlink); ++ + WARN_ON(!list_empty(&devlink->trap_policer_list)); + WARN_ON(!list_empty(&devlink->trap_group_list)); + WARN_ON(!list_empty(&devlink->trap_list)); +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-policy-smq-check-allocation-under-invalidat.patch b/queue-6.18/dm-cache-policy-smq-check-allocation-under-invalidat.patch new file mode 100644 index 0000000000..1ee8f3f4f7 --- /dev/null +++ b/queue-6.18/dm-cache-policy-smq-check-allocation-under-invalidat.patch @@ -0,0 +1,71 @@ +From 5e1ccdc5946bfc7bc022f05c375409ef75d172d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:57:45 +0800 +Subject: dm cache policy smq: check allocation under invalidate lock + +From: Guangshuo Li + +[ Upstream commit d3f0a606b9f278ece8a0df626ded9c4044071235 ] + +commit 2d1f7b65f5de ("dm cache policy smq: fix missing locks in +invalidating cache blocks") added mq->lock around the destructive part of +smq_invalidate_mapping(), but left the e->allocated check outside the +critical section. + +That leaves a check-then-act race. Two concurrent invalidators can both +observe e->allocated as true before either of them takes mq->lock. The +first invalidator that acquires the lock removes the entry from the +queues and hash table and then calls free_entry(), which clears +e->allocated and puts the entry back on the free list. The second +invalidator can then acquire mq->lock and continue with the stale result +of the unlocked check. + +This can corrupt the SMQ queues or hash table by deleting an entry that +is no longer on those structures. It can also hit the allocation check in +free_entry() when the same entry is freed again. + +Move the allocation check under mq->lock so the predicate and the +destructive operations are serialized by the same lock. + +Fixes: 2d1f7b65f5de ("dm cache policy smq: fix missing locks in invalidating cache blocks") +Signed-off-by: Guangshuo Li +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 76a35cce85028e..7f661e8cbcc2be 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1590,18 +1590,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; +- +- if (!e->allocated) +- return -ENODATA; ++ int r = 0; + + spin_lock_irqsave(&mq->lock, flags); ++ if (!e->allocated) { ++ r = -ENODATA; ++ goto out; ++ } + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ ++out: + spin_unlock_irqrestore(&mq->lock, flags); + +- return 0; ++ return r; + } + + static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) +-- +2.53.0 + diff --git a/queue-6.18/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch b/queue-6.18/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch new file mode 100644 index 0000000000..c0798f9b8f --- /dev/null +++ b/queue-6.18/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch @@ -0,0 +1,53 @@ +From eec73918e4335f223a891decdb8b0956e0b649d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 19:00:13 +0100 +Subject: drm/imx: Fix three kernel-doc warnings in dcss-scaler.c + +From: Yicong Hui + +[ Upstream commit ae0383e5a9a4b12d68c76c4769857def4665deff ] + +Fix the following W=1 kerneldoc warnings by adding the missing parameter +descriptions for @phase0_identity and @nn_interpolation in +dcss_scaler_filter_design() and @phase0_identity in +dcss_scaler_gaussian_filter() + +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:173 function parameter 'phase0_identity' not described in 'dcss_scaler_gaussian_filter' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'phase0_identity' not described in 'dcss_scaler_filter_design' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'nn_interpolation' not described in 'dcss_scaler_filter_design' + +Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") +Signed-off-by: Yicong Hui +Reviewed-by: Laurentiu Palcu +Link: https://patch.msgid.link/20260406180013.2442096-1-yiconghui@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/dcss/dcss-scaler.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +index 32c3f46b21daea..5c7f8d952ec1a1 100644 +--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c ++++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +@@ -166,6 +166,7 @@ static int exp_approx_q(int x) + * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter. + * @fc_q: fixed-point cutoff frequency normalized to range [0, 1] + * @use_5_taps: indicates whether to use 5 taps or 7 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output filter coefficients + */ + static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, +@@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, + * @src_length: length of input + * @dst_length: length of output + * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output coefficients ++ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter + */ + static void dcss_scaler_filter_design(int src_length, int dst_length, + bool use_5_taps, bool phase0_identity, +-- +2.53.0 + diff --git a/queue-6.18/erofs-fix-use-after-free-on-sbi-sync_decompress.patch b/queue-6.18/erofs-fix-use-after-free-on-sbi-sync_decompress.patch new file mode 100644 index 0000000000..2756e771a7 --- /dev/null +++ b/queue-6.18/erofs-fix-use-after-free-on-sbi-sync_decompress.patch @@ -0,0 +1,66 @@ +From fd4dfabe3a247973a71218f972ea62d5e09a43e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:27:16 +0800 +Subject: erofs: fix use-after-free on sbi->sync_decompress + +From: Gao Xiang + +[ Upstream commit 1aee05e814d292064bf5fa15733741040cdc48ba ] + +z_erofs_decompress_kickoff() can race with filesystem unmount, causing +a use-after-free on sbi->sync_decompress. + +When I/O completes, z_erofs_endio() calls z_erofs_decompress_kickoff() +to queue z_erofs_decompressqueue_work() asynchronously. Then, after all +folios are unlocked, unmount workflow can proceed and sbi will be freed +before accessing to sbi->sync_decompress. + +Thread (unmount) I/O completion kworker + queue_work + z_erofs_decompressqueue_work + (all folios are unlocked) +cleanup_mnt + .. + erofs_kill_sb + erofs_sb_free + kfree(sbi) + access sbi->sync_decompress // UAF!! + +Fixes: 40452ffca3c1 ("erofs: add sysfs node to control sync decompression strategy") +Reported-by: syzbot+52bae5c495dbe261a0bc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=52bae5c495dbe261a0bc +Reviewed-by: Chao Yu +Reviewed-by: Jianan Huang +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index e98d9cb4fe99a4..a02ce7c06f9e1e 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1443,6 +1443,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + if (atomic_add_return(bios, &io->pending_bios)) + return; + if (z_erofs_in_atomic()) { ++ /* See `sync_decompress` in sysfs-fs-erofs for more details */ ++ if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) ++ sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + #ifdef CONFIG_EROFS_FS_PCPU_KTHREAD + struct kthread_worker *worker; + +@@ -1459,9 +1462,6 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + #else + queue_work(z_erofs_workqueue, &io->u.work); + #endif +- /* See `sync_decompress` in sysfs-fs-erofs for more details */ +- if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) +- sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + return; + } + gfp_flag = memalloc_noio_save(); +-- +2.53.0 + diff --git a/queue-6.18/erofs-tidy-up-synchronous-decompression.patch b/queue-6.18/erofs-tidy-up-synchronous-decompression.patch new file mode 100644 index 0000000000..5add32b660 --- /dev/null +++ b/queue-6.18/erofs-tidy-up-synchronous-decompression.patch @@ -0,0 +1,193 @@ +From fed83c9497a73f9eb5e4b3b61defb2fb1ded7df5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 11:43:30 +0800 +Subject: erofs: tidy up synchronous decompression + +From: Gao Xiang + +[ Upstream commit cc831ab33644088c1eef78936de24701014d520a ] + + - Get rid of `sbi->opt.max_sync_decompress_pages` since it's fixed as + 3 all the time; + + - Add Z_EROFS_MAX_SYNC_DECOMPRESS_BYTES in bytes instead of in pages, + since for non-4K pages, 3-page limitation makes no sense; + + - Move `sync_decompress` to sbi to avoid unexpected remount impact; + + - Fold z_erofs_is_sync_decompress() into its caller; + + - Better description of sysfs entry `sync_decompress`. + +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Stable-dep-of: 1aee05e814d2 ("erofs: fix use-after-free on sbi->sync_decompress") +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-fs-erofs | 14 ++++++---- + fs/erofs/internal.h | 5 +--- + fs/erofs/super.c | 3 +- + fs/erofs/sysfs.c | 2 +- + fs/erofs/zdata.c | 35 +++++++++--------------- + 5 files changed, 25 insertions(+), 34 deletions(-) + +diff --git a/Documentation/ABI/testing/sysfs-fs-erofs b/Documentation/ABI/testing/sysfs-fs-erofs +index 76d9808ed58143..b9243c7f28d718 100644 +--- a/Documentation/ABI/testing/sysfs-fs-erofs ++++ b/Documentation/ABI/testing/sysfs-fs-erofs +@@ -10,12 +10,16 @@ Description: Shows all enabled kernel features. + What: /sys/fs/erofs//sync_decompress + Date: November 2021 + Contact: "Huang Jianan" +-Description: Control strategy of sync decompression: ++Description: Control strategy of synchronous decompression. Synchronous ++ decompression tries to decompress in the reader thread for ++ synchronous reads and small asynchronous reads (<= 12 KiB): + +- - 0 (default, auto): enable for readpage, and enable for +- readahead on atomic contexts only. +- - 1 (force on): enable for readpage and readahead. +- - 2 (force off): disable for all situations. ++ - 0 (auto, default): apply to synchronous reads only, but will ++ switch to 1 (force on) if any decompression ++ request is detected in atomic contexts; ++ - 1 (force on): apply to synchronous reads and small ++ asynchronous reads; ++ - 2 (force off): disable synchronous decompression completely. + + What: /sys/fs/erofs//drop_caches + Date: November 2024 +diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h +index f7f622836198da..87edbb4366d16c 100644 +--- a/fs/erofs/internal.h ++++ b/fs/erofs/internal.h +@@ -59,10 +59,6 @@ enum { + struct erofs_mount_opts { + /* current strategy of how to use managed cache */ + unsigned char cache_strategy; +- /* strategy of sync decompression (0 - auto, 1 - force on, 2 - force off) */ +- unsigned int sync_decompress; +- /* threshold for decompression synchronously */ +- unsigned int max_sync_decompress_pages; + unsigned int mount_opt; + }; + +@@ -116,6 +112,7 @@ struct erofs_sb_info { + /* managed XArray arranged in physical block number */ + struct xarray managed_pslots; + ++ unsigned int sync_decompress; /* strategy for sync decompression */ + unsigned int shrinker_run_no; + u16 available_compr_algs; + +diff --git a/fs/erofs/super.c b/fs/erofs/super.c +index f5f5d19459eccd..e6725e9847bedd 100644 +--- a/fs/erofs/super.c ++++ b/fs/erofs/super.c +@@ -379,8 +379,7 @@ static void erofs_default_options(struct erofs_sb_info *sbi) + { + #ifdef CONFIG_EROFS_FS_ZIP + sbi->opt.cache_strategy = EROFS_ZIP_CACHE_READAROUND; +- sbi->opt.max_sync_decompress_pages = 3; +- sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_AUTO; ++ sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_AUTO; + #endif + #ifdef CONFIG_EROFS_FS_XATTR + set_opt(&sbi->opt, XATTR_USER); +diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c +index 1e0658a1d95b9a..86b22b9f0c1910 100644 +--- a/fs/erofs/sysfs.c ++++ b/fs/erofs/sysfs.c +@@ -59,7 +59,7 @@ static struct erofs_attr erofs_attr_##_name = { \ + #define ATTR_LIST(name) (&erofs_attr_##name.attr) + + #ifdef CONFIG_EROFS_FS_ZIP +-EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts); ++EROFS_ATTR_RW_UI(sync_decompress, erofs_sb_info); + EROFS_ATTR_FUNC(drop_caches, 0200); + #endif + #ifdef CONFIG_EROFS_FS_ZIP_ACCEL +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index 33932d56d3a46e..e98d9cb4fe99a4 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -9,6 +9,7 @@ + #include + #include + ++#define Z_EROFS_MAX_SYNC_DECOMPRESS_BYTES 12288 + #define Z_EROFS_PCLUSTER_MAX_PAGES (Z_EROFS_PCLUSTER_MAX_SIZE / PAGE_SIZE) + #define Z_EROFS_INLINE_BVECS 2 + +@@ -1097,21 +1098,6 @@ static int z_erofs_scan_folio(struct z_erofs_frontend *f, + return err; + } + +-static bool z_erofs_is_sync_decompress(struct erofs_sb_info *sbi, +- unsigned int readahead_pages) +-{ +- /* auto: enable for read_folio, disable for readahead */ +- if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) && +- !readahead_pages) +- return true; +- +- if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_FORCE_ON) && +- (readahead_pages <= sbi->opt.max_sync_decompress_pages)) +- return true; +- +- return false; +-} +- + static bool z_erofs_page_is_invalidated(struct page *page) + { + return !page_folio(page)->mapping && !z_erofs_is_shortlived_page(page); +@@ -1473,9 +1459,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + #else + queue_work(z_erofs_workqueue, &io->u.work); + #endif +- /* enable sync decompression for readahead */ +- if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) +- sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; ++ /* See `sync_decompress` in sysfs-fs-erofs for more details */ ++ if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) ++ sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + return; + } + gfp_flag = memalloc_noio_save(); +@@ -1795,16 +1781,21 @@ static void z_erofs_submit_queue(struct z_erofs_frontend *f, + z_erofs_decompress_kickoff(q[JQ_SUBMIT], nr_bios); + } + +-static int z_erofs_runqueue(struct z_erofs_frontend *f, unsigned int rapages) ++static int z_erofs_runqueue(struct z_erofs_frontend *f, unsigned int rabytes) + { + struct z_erofs_decompressqueue io[NR_JOBQUEUES]; + struct erofs_sb_info *sbi = EROFS_I_SB(f->inode); +- bool force_fg = z_erofs_is_sync_decompress(sbi, rapages); ++ int syncmode = sbi->sync_decompress; ++ bool force_fg; + int err; + ++ force_fg = (syncmode == EROFS_SYNC_DECOMPRESS_AUTO && !rabytes) || ++ (syncmode == EROFS_SYNC_DECOMPRESS_FORCE_ON && ++ (rabytes <= Z_EROFS_MAX_SYNC_DECOMPRESS_BYTES)); ++ + if (f->head == Z_EROFS_PCLUSTER_TAIL) + return 0; +- z_erofs_submit_queue(f, io, &force_fg, !!rapages); ++ z_erofs_submit_queue(f, io, &force_fg, !!rabytes); + + /* handle bypass queue (no i/o pclusters) immediately */ + err = z_erofs_decompress_queue(&io[JQ_BYPASS], &f->pagepool); +@@ -1925,7 +1916,7 @@ static void z_erofs_readahead(struct readahead_control *rac) + z_erofs_pcluster_readmore(&f, rac, false); + z_erofs_pcluster_end(&f); + +- (void)z_erofs_runqueue(&f, nrpages); ++ (void)z_erofs_runqueue(&f, nrpages << PAGE_SHIFT); + erofs_put_metabuf(&f.map.buf); + erofs_release_pages(&f.pagepool); + } +-- +2.53.0 + diff --git a/queue-6.18/hsr-remove-warn_once-in-hsr_addr_is_self.patch b/queue-6.18/hsr-remove-warn_once-in-hsr_addr_is_self.patch new file mode 100644 index 0000000000..6e31a299d9 --- /dev/null +++ b/queue-6.18/hsr-remove-warn_once-in-hsr_addr_is_self.patch @@ -0,0 +1,109 @@ +From b80a12a83986dc841b7f4e2429aecfc20d25afe4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 30 May 2026 06:42:58 +0000 +Subject: hsr: Remove WARN_ONCE() in hsr_addr_is_self(). + +From: Kuniyuki Iwashima + +[ Upstream commit afd0f17ca46258cec3a5cc48b8df9327fe772490 ] + +syzbot reported the warning [0] in hsr_addr_is_self(), +whose assumption is simply wrong. + +hsr->self_node is cleared in hsr_del_self_node(), which +is called from hsr_dellink(). + +Since dev->rtnl_link_ops->dellink() is called before +unregister_netdevice_many(), there is a window when +user can find the device but without hsr->self_node. + +Let's remove WARN_ONCE() in hsr_addr_is_self(). + +[0]: +HSR: No self node +WARNING: net/hsr/hsr_framereg.c:39 at hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39, CPU#0: syz.4.16848/17220 +Modules linked in: +CPU: 0 UID: 0 PID: 17220 Comm: syz.4.16848 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} +Tainted: [L]=SOFTLOCKUP +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 +RIP: 0010:hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39 +Code: 33 2f 41 0f b7 dd 89 ee 09 de 31 ff e8 c8 b4 c6 f6 09 dd 74 54 e8 0f b0 c6 f6 31 ed eb 53 e8 06 b0 c6 f6 48 8d 3d 2f 50 9c 04 <67> 48 0f b9 3a 31 ed eb 42 e8 c1 13 1f 00 89 c5 31 ff 89 c6 e8 96 +RSP: 0018:ffffc900041c70e0 EFLAGS: 00010283 +RAX: ffffffff8afdc6ca RBX: ffffffff8afdc4e6 RCX: 0000000000080000 +RDX: ffffc90010493000 RSI: 0000000000000948 RDI: ffffffff8f9a1700 +RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000 +R10: ffffc900041c71e8 R11: fffff52000838e3f R12: dffffc0000000000 +R13: ffff888041f9e3c0 R14: ffff888086ee3802 R15: 0000000000000000 +FS: 00007f6fe985d6c0(0000) GS:ffff888126176000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f80bd437dac CR3: 0000000025096000 CR4: 00000000003526f0 +DR0: ffffffffffffffff DR1: 00000000000001f8 DR2: 0000000000000002 +DR3: ffffffffefffff15 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +Call Trace: + + check_local_dest net/hsr/hsr_forward.c:592 [inline] + fill_frame_info net/hsr/hsr_forward.c:728 [inline] + hsr_forward_skb+0xa11/0x2a80 net/hsr/hsr_forward.c:739 + hsr_dev_xmit+0x253/0x370 net/hsr/hsr_device.c:236 + __netdev_start_xmit include/linux/netdevice.h:5368 [inline] + netdev_start_xmit include/linux/netdevice.h:5377 [inline] + xmit_one net/core/dev.c:3888 [inline] + dev_hard_start_xmit+0x2df/0x860 net/core/dev.c:3904 + __dev_queue_xmit+0x1428/0x3900 net/core/dev.c:4870 + neigh_output include/net/neighbour.h:556 [inline] + ip_finish_output2+0xcec/0x10b0 net/ipv4/ip_output.c:237 + ip_send_skb net/ipv4/ip_output.c:1510 [inline] + ip_push_pending_frames+0x8b/0x110 net/ipv4/ip_output.c:1530 + raw_sendmsg+0x1547/0x1a50 net/ipv4/raw.c:659 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x7da/0x9c0 net/socket.c:2698 + ___sys_sendmsg+0x2a5/0x360 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0x1c3/0x2a0 net/socket.c:2787 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f6feb62ce59 +Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 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 e8 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f6fe985d028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +RAX: ffffffffffffffda RBX: 00007f6feb8a6090 RCX: 00007f6feb62ce59 +RDX: 0000000000000000 RSI: 0000200000000000 RDI: 0000000000000004 +RBP: 00007f6feb6c2d6f R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 +R13: 00007f6feb8a6128 R14: 00007f6feb8a6090 R15: 00007ffcf01cc488 + + +Fixes: f266a683a480 ("net/hsr: Better frame dispatch") +Reported-by: syzbot+652670cf249077eb498b@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1a861e.b111c304.35cd64.0016.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260530064300.340793-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_framereg.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c +index 3a2a2fa7a0a396..bd2fbbc4420b29 100644 +--- a/net/hsr/hsr_framereg.c ++++ b/net/hsr/hsr_framereg.c +@@ -52,10 +52,8 @@ bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr) + + rcu_read_lock(); + sn = rcu_dereference(hsr->self_node); +- if (!sn) { +- WARN_ONCE(1, "HSR: No self node\n"); ++ if (!sn) + goto out; +- } + + if (ether_addr_equal(addr, sn->macaddress_A) || + ether_addr_equal(addr, sn->macaddress_B)) +-- +2.53.0 + diff --git a/queue-6.18/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch b/queue-6.18/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch new file mode 100644 index 0000000000..d74677cae1 --- /dev/null +++ b/queue-6.18/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch @@ -0,0 +1,56 @@ +From 4169245357913fbe03ee6115885a9ddfbf58e02c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 07:29:55 +0000 +Subject: ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit() + +From: Eric Dumazet + +[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ] + +The aoe driver (or similar) generates a non-IPv6 packet +(e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() +on a 6LoWPAN interface (configured by the user or test case). + +Since the packet is not IPv6, the 6LoWPAN header_ops->create function +(lowpan_header_create or header_create) returns early without initializing +the lowpan_addr_info structure in the skb headroom. + +In the transmit function (lowpan_xmit), the driver calls lowpan_header +(or setup_header) which unconditionally copies and uses the lowpan_addr_info +from the headroom, which contains uninitialized data. + +Fix this by dropping non IPv6 packets. + +A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit(). + +Fixes: 4dc315e267fe ("ieee802154: 6lowpan: move transmit functionality") +Reported-by: syzbot+f13c19f75e1097abd116@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1fd763.278b5b03.2bcf39.0049.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260603072955.4032221-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ieee802154/6lowpan/tx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c +index 0c07662b44c0ca..4df76ff50699ed 100644 +--- a/net/ieee802154/6lowpan/tx.c ++++ b/net/ieee802154/6lowpan/tx.c +@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) + + pr_debug("package xmit\n"); + ++ if (skb->protocol != htons(ETH_P_IPV6)) { ++ kfree_skb(skb); ++ return NET_XMIT_DROP; ++ } ++ + WARN_ON_ONCE(skb->len > IPV6_MIN_MTU); + + /* We must take a copy of the skb before we modify/replace the ipv6 +-- +2.53.0 + diff --git a/queue-6.18/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch b/queue-6.18/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch new file mode 100644 index 0000000000..6bf3954fc3 --- /dev/null +++ b/queue-6.18/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch @@ -0,0 +1,54 @@ +From eb5e7143752fc3268890e252c814783c5f1f6b28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:15:47 +0000 +Subject: ipv4: restrict IPOPT_SSRR and IPOPT_LSRR options + +From: Eric Dumazet + +[ Upstream commit d3915a1f5a4bc0ac911032903c3c6ab8df9fcc7c ] + +This patch restricts setting Loose Source and Record Route (LSRR) +and Strict Source and Record Route (SSRR) IP options to users +with CAP_NET_RAW capability. + +This prevents unprivileged applications from forcing packets to route +through attacker-controlled nodes to leak TCP ISN and possibly other +protocol information. + +While LSRR and SSRR are commonly filtered in many network environments, +they may still be supported and forwarded along some network paths. + +RFC 7126 (Recommendations on Filtering of IPv4 Packets Containing +IPv4 Options) recommend to drop these options in 4.3 and 4.4. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260602161547.2642155-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_options.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index be8815ce3ac242..09d745112c1526 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -530,6 +530,10 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp, + kfree(opt); + return -EINVAL; + } ++ if (opt->opt.srr && !ns_capable(net->user_ns, CAP_NET_RAW)) { ++ kfree(opt); ++ return -EPERM; ++ } + kfree(*optp); + *optp = opt; + return 0; +-- +2.53.0 + diff --git a/queue-6.18/ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch b/queue-6.18/ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch new file mode 100644 index 0000000000..dde3c60946 --- /dev/null +++ b/queue-6.18/ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch @@ -0,0 +1,124 @@ +From 3f1cabfb96610f6b061e5abbcf6d300097ac742e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:22:18 +0800 +Subject: ipv6: anycast: insert aca into global hash under idev->lock + +From: Jiayuan Chen + +[ Upstream commit f723ccaff2fb72b71ae8a9fd283f0dee4d9ae7a3 ] + +syzbot reported a splat [1]: a slab-use-after-free in +ipv6_chk_acast_addr(), which walks the global inet6_acaddr_lst[] hash +under RCU and dereferences a struct ifacaddr6 that has already been +freed while still linked in the hash, so a later reader walks into a +dangling node. + +In __ipv6_dev_ac_inc() the aca is allocated with refcount 1, then +aca_get() bumps it to 2 to keep it alive across the unlocked region. +It is published to idev->ac_list under idev->lock, but +ipv6_add_acaddr_hash() runs after write_unlock_bh(). A concurrent +teardown (ipv6_ac_destroy_dev() from addrconf_ifdown(), under RTNL) +can slip into that window: + + CPU0 __ipv6_dev_ac_inc CPU1 ipv6_ac_destroy_dev (RTNL) + ------------------------------ ------------------------------------ + aca_alloc() refcnt 1 + aca_get() refcnt 2 + write_lock_bh(idev->lock) + add aca to ac_list + write_unlock_bh(idev->lock) + write_lock_bh(idev->lock) + pull aca off ac_list + write_unlock_bh(idev->lock) + ipv6_del_acaddr_hash(aca) + hlist_del_init_rcu() is a no-op, + aca is not in the hash yet + aca_put() refcnt 2->1 + ipv6_add_acaddr_hash(aca) + aca now inserted into the hash + aca_put() refcnt 1->0 + call_rcu(aca_free_rcu) -> kfree(aca) + +The hash removal becomes a no-op because the insertion has not +happened yet, so once CPU0 inserts and drops the last reference, the +aca is freed while still linked in inet6_acaddr_lst[], and readers +dereference freed memory after the slab slot is reused. + +This window opened once RTNL stopped serializing the join path against +device teardown. Move ipv6_add_acaddr_hash() inside the idev->lock +section so the ac_list and hash insertions are atomic with respect to +teardown: a racing remover now either misses the aca entirely or finds +it in both lists. + +acaddr_hash_lock is now nested under idev->lock, which is acquired in +softirq context, so switch all acaddr_hash_lock sites to spin_lock_bh() +to avoid the irq lock inversion reported in [2]. + +[1] https://syzkaller.appspot.com/bug?extid=a01df04303c131efbf3a +[2] https://lore.kernel.org/netdev/6a194ef7.ba3b1513.1890b4.0000.GAE@google.com/ + +Reported-by: syzbot+819eb928d120d2bdad0e@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a191f87.ce022c6e.138e56.0003.GAE@google.com/T/ +Reviewed-by: Kuniyuki Iwashima +Fixes: eb1ac9ff6c4a ("ipv6: anycast: Don't hold RTNL for IPV6_JOIN_ANYCAST.") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260529152219.235475-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/anycast.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c +index 52599584422bf4..819c4ff10997e0 100644 +--- a/net/ipv6/anycast.c ++++ b/net/ipv6/anycast.c +@@ -243,16 +243,16 @@ static void ipv6_add_acaddr_hash(struct net *net, struct ifacaddr6 *aca) + { + unsigned int hash = inet6_acaddr_hash(net, &aca->aca_addr); + +- spin_lock(&acaddr_hash_lock); ++ spin_lock_bh(&acaddr_hash_lock); + hlist_add_head_rcu(&aca->aca_addr_lst, &inet6_acaddr_lst[hash]); +- spin_unlock(&acaddr_hash_lock); ++ spin_unlock_bh(&acaddr_hash_lock); + } + + static void ipv6_del_acaddr_hash(struct ifacaddr6 *aca) + { +- spin_lock(&acaddr_hash_lock); ++ spin_lock_bh(&acaddr_hash_lock); + hlist_del_init_rcu(&aca->aca_addr_lst); +- spin_unlock(&acaddr_hash_lock); ++ spin_unlock_bh(&acaddr_hash_lock); + } + + static void aca_get(struct ifacaddr6 *aca) +@@ -371,10 +371,10 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) + aca->aca_next = idev->ac_list; + rcu_assign_pointer(idev->ac_list, aca); + +- write_unlock_bh(&idev->lock); +- + ipv6_add_acaddr_hash(net, aca); + ++ write_unlock_bh(&idev->lock); ++ + ip6_ins_rt(net, f6i); + + addrconf_join_solict(idev->dev, &aca->aca_addr); +@@ -649,8 +649,8 @@ void ipv6_anycast_cleanup(void) + { + int i; + +- spin_lock(&acaddr_hash_lock); ++ spin_lock_bh(&acaddr_hash_lock); + for (i = 0; i < IN6_ADDR_HSIZE; i++) + WARN_ON(!hlist_empty(&inet6_acaddr_lst[i])); +- spin_unlock(&acaddr_hash_lock); ++ spin_unlock_bh(&acaddr_hash_lock); + } +-- +2.53.0 + diff --git a/queue-6.18/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch b/queue-6.18/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch new file mode 100644 index 0000000000..f39b33b114 --- /dev/null +++ b/queue-6.18/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch @@ -0,0 +1,107 @@ +From 5a688c86061ed594756a1c02aa894a2400dbad73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 13:18:11 +0300 +Subject: ipv6: mcast: Fix use-after-free when processing MLD queries + +From: Ido Schimmel + +[ Upstream commit 791c91dc7a9dfb2457d5e29b8216a6484b9c4b40 ] + +When processing an MLD query, a pointer to the multicast group address +is retrieved when initially parsing the packet. This pointer is later +dereferenced without being reloaded despite the fact that the skb header +might have been reallocated following the pskb_may_pull() calls, leading +to a use-after-free [1]. + +Fix by copying the multicast group address when the packet is initially +parsed. + +[1] +BUG: KASAN: slab-use-after-free in __mld_query_work (net/ipv6/mcast.c:1512) +Read of size 8 at addr ffff8881154b8e90 by task kworker/4:1/118 + +Workqueue: mld mld_query_work +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +print_address_description.constprop.0 (mm/kasan/report.c:378) +print_report (mm/kasan/report.c:482) +kasan_report (mm/kasan/report.c:595) +__mld_query_work (net/ipv6/mcast.c:1512) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + + +[...] + +Freed by task 118: +kasan_save_stack (mm/kasan/common.c:57) +kasan_save_track (mm/kasan/common.c:78) +kasan_save_free_info (mm/kasan/generic.c:584) +__kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285) +kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566) +pskb_expand_head (net/core/skbuff.c:2335) +__pskb_pull_tail (net/core/skbuff.c:2878 (discriminator 4)) +__mld_query_work (net/ipv6/mcast.c:1495 (discriminator 1)) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + +Fixes: 97300b5fdfe2 ("[MCAST] IPv6: Check packet size when process Multicast") +Reported-by: Leo Lin +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260603101811.612594-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index 016b572e7d6f02..f4b3cb48387096 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1424,9 +1424,9 @@ void igmp6_event_query(struct sk_buff *skb) + static void __mld_query_work(struct sk_buff *skb) + { + struct mld2_query *mlh2 = NULL; +- const struct in6_addr *group; + unsigned long max_delay; + struct inet6_dev *idev; ++ struct in6_addr group; + struct ifmcaddr6 *ma; + struct mld_msg *mld; + int group_type; +@@ -1458,8 +1458,8 @@ static void __mld_query_work(struct sk_buff *skb) + goto kfree_skb; + + mld = (struct mld_msg *)icmp6_hdr(skb); +- group = &mld->mld_mca; +- group_type = ipv6_addr_type(group); ++ group = mld->mld_mca; ++ group_type = ipv6_addr_type(&group); + + if (group_type != IPV6_ADDR_ANY && + !(group_type&IPV6_ADDR_MULTICAST)) +@@ -1509,7 +1509,7 @@ static void __mld_query_work(struct sk_buff *skb) + } + } else { + for_each_mc_mclock(idev, ma) { +- if (!ipv6_addr_equal(group, &ma->mca_addr)) ++ if (!ipv6_addr_equal(&group, &ma->mca_addr)) + continue; + if (ma->mca_flags & MAF_TIMER_RUNNING) { + /* gsquery <- gsquery && mark */ +-- +2.53.0 + diff --git a/queue-6.18/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch b/queue-6.18/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch new file mode 100644 index 0000000000..34904086d2 --- /dev/null +++ b/queue-6.18/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch @@ -0,0 +1,127 @@ +From 1a4a0cfecbb4a611d48a7618da527ae721ef2bb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 07:07:44 +0300 +Subject: ipvs: clear the svc scheduler ptr early on edit + +From: Julian Anastasov + +[ Upstream commit 193989cc6d80dd8e0460fb3992e69fa03bf0ff9b ] + +ip_vs_edit_service() while unbinding the old scheduler clears +the svc->scheduler ptr after the scheduler module initiates +RCU callbacks. This can cause packets to use the old +scheduler at the time when svc->sched_data is already freed +after RCU grace period. + +Fix it by clearing the ptr early in ip_vs_unbind_scheduler(), +before the done_service method schedules any RCU callbacks. + +Also, if the new scheduler fails to initialize when replacing +the old scheduler, try to restore the old scheduler while still +returning the error code. + +Link: https://sashiko.dev/#/patchset/20260519015506.634185-1-rosenp%40gmail.com +Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed") +Signed-off-by: Julian Anastasov +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/ip_vs.h | 3 +-- + net/netfilter/ipvs/ip_vs_ctl.c | 13 ++++++++----- + net/netfilter/ipvs/ip_vs_sched.c | 14 +++++++------- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +index 29a36709e7f35c..2163f32ef6abc1 100644 +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -1519,8 +1519,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched); ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc); + struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); + void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); + struct ip_vs_conn * +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index e442ba6033d5f8..a3b509908b8c0e 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -1497,7 +1497,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, + if (ret_hooks >= 0) + ip_vs_unregister_hooks(ipvs, u->af); + if (svc != NULL) { +- ip_vs_unbind_scheduler(svc, sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_service_free(svc); + } + ip_vs_scheduler_put(sched); +@@ -1559,9 +1559,8 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + old_sched = rcu_dereference_protected(svc->scheduler, 1); + if (sched != old_sched) { + if (old_sched) { +- ip_vs_unbind_scheduler(svc, old_sched); +- RCU_INIT_POINTER(svc->scheduler, NULL); +- /* Wait all svc->sched_data users */ ++ ip_vs_unbind_scheduler(svc); ++ /* Wait all svc->scheduler/sched_data users */ + synchronize_rcu(); + } + /* Bind the new scheduler */ +@@ -1569,6 +1568,10 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + ret = ip_vs_bind_scheduler(svc, sched); + if (ret) { + ip_vs_scheduler_put(sched); ++ /* Try to restore the old_sched */ ++ if (old_sched && ++ !ip_vs_bind_scheduler(svc, old_sched)) ++ old_sched = NULL; + goto out; + } + } +@@ -1625,7 +1628,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup) + + /* Unbind scheduler */ + old_sched = rcu_dereference_protected(svc->scheduler, 1); +- ip_vs_unbind_scheduler(svc, old_sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_scheduler_put(old_sched); + + /* Unbind persistence engine, keep svc->pe */ +diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c +index d4903723be7e90..49b2e5d2b2c837 100644 +--- a/net/netfilter/ipvs/ip_vs_sched.c ++++ b/net/netfilter/ipvs/ip_vs_sched.c +@@ -57,19 +57,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, + /* + * Unbind a service with its scheduler + */ +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched) ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc) + { +- struct ip_vs_scheduler *cur_sched; ++ struct ip_vs_scheduler *sched; + +- cur_sched = rcu_dereference_protected(svc->scheduler, 1); +- /* This check proves that old 'sched' was installed */ +- if (!cur_sched) ++ sched = rcu_dereference_protected(svc->scheduler, 1); ++ if (!sched) + return; + ++ /* Reset the scheduler before initiating any RCU callbacks */ ++ rcu_assign_pointer(svc->scheduler, NULL); ++ smp_wmb(); /* paired with smp_rmb() in ip_vs_schedule() */ + if (sched->done_service) + sched->done_service(svc); +- /* svc->scheduler can be set to NULL only by caller */ + } + + +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch b/queue-6.18/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch new file mode 100644 index 0000000000..13b86bf8b0 --- /dev/null +++ b/queue-6.18/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch @@ -0,0 +1,75 @@ +From cca951b3bfc41f7b7032138e0b2f069f30d21bb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 00:00:00 +0000 +Subject: ksmbd: fix NULL-deref of opinfo->conn in oplock/lease break notifiers + +From: Gil Portnoy + +[ Upstream commit b003086d76968298f22e7cf62239833b5a3a06b1 ] + +smb2_oplock_break_noti() and smb2_lease_break_noti() read opinfo->conn +into a local with neither READ_ONCE() nor a NULL check. Both run from +oplock_break() after opinfo_get_list() has dropped ci->m_lock, so a +concurrent SMB2 LOGOFF (session_fd_check()) can set op->conn = NULL +under ci->m_lock within that window. ksmbd_conn_r_count_inc(conn) then +writes through NULL at offset 0xc4 -- a remotely triggerable oops. + +Guard both reads the way compare_guid_key() already does: read +opinfo->conn with READ_ONCE() and return early if it is NULL, before +allocating the work struct so nothing leaks. A NULL conn means the +client is gone and the break is moot, so return 0; oplock_break() treats +that as success and runs the normal teardown. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Assisted-by: Henry (Claude):claude-opus-4 +Signed-off-by: Gil Portnoy +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/oplock.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index a84c01bceb8ba2..6454c7a4baa450 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -714,11 +714,16 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) + */ + static int smb2_oplock_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct oplock_break_info *br_info; + int ret = 0; +- struct ksmbd_work *work = ksmbd_alloc_work_struct(); ++ struct ksmbd_work *work; ++ ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; + ++ work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; + +@@ -818,11 +823,15 @@ static void __smb2_lease_break_noti(struct work_struct *wk) + */ + static int smb2_lease_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct ksmbd_work *work; + struct lease_break_info *br_info; + struct lease *lease = opinfo->o_lease; + ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; ++ + work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.18/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch b/queue-6.18/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch new file mode 100644 index 0000000000..3e642c32dc --- /dev/null +++ b/queue-6.18/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch @@ -0,0 +1,176 @@ +From bfb18f410d820b124deadb9917b1ceb858fd2310 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:36:29 +0000 +Subject: l2tp: pppol2tp: hold reference to session in pppol2tp_ioctl() + +From: Lee Jones + +[ Upstream commit a213a8950414c684999dcf03edeea6c46ede172e ] + +pppol2tp_ioctl() read sock->sk->sk_user_data directly without any +locks or reference counting. If a controllable sleep was induced during +copy_from_user() (e.g. via a userfaultfd page fault sleep), a concurrent +socket close could trigger pppol2tp_session_close() asynchronously. This +frees the l2tp_session structure via the l2tp_session_del_work workqueue. +Upon resuming, the ioctl thread dereferences the stale session pointer, +resulting in a Use-After-Free (UAF). + +Fix this by securely fetching the session reference using the RCU-safe, +refcounted helper pppol2tp_sock_to_session(sk) on entry. This locks the +session's refcount across the sleep. We structured the function to exit +via standard err breaks, guaranteeing that l2tp_session_put() is cleanly +called on all return paths to drop the reference. + +To preserve existing behavior we validate the session and its magic +signature only for the specific L2TP commands that require it. This +ensures that generic/unknown ioctls called on an unconnected socket +still return -ENOIOCTLCMD and correctly fall back to generic handlers +(e.g. in sock_do_ioctl()). + +Signed-off-by: Lee Jones +Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") +Link: https://patch.msgid.link/20260527133630.2120612-1-lee@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/l2tp/l2tp_ppp.c | 82 +++++++++++++++++++++++++++------------------ + 1 file changed, 50 insertions(+), 32 deletions(-) + +diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c +index 5e12e7ce17d8a7..f388bf9abf378d 100644 +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -1044,64 +1044,76 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, + { + struct pppol2tp_ioc_stats stats; + struct l2tp_session *session; ++ int err = 0; ++ ++ session = pppol2tp_sock_to_session(sock->sk); + ++ /* Validate session presence and magic integrity ONLY for commands ++ * that belong to L2TP and require a valid session. ++ */ + switch (cmd) { + case PPPIOCGMRU: + case PPPIOCGFLAGS: +- session = sock->sk->sk_user_data; ++ case PPPIOCSMRU: ++ case PPPIOCSFLAGS: ++ case PPPIOCGL2TPSTATS: + if (!session) + return -ENOTCONN; + +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) ++ if (session->magic != L2TP_SESSION_MAGIC) { ++ l2tp_session_put(session); + return -EBADF; ++ } ++ break; ++ default: ++ break; ++ } + ++ switch (cmd) { ++ case PPPIOCGMRU: ++ case PPPIOCGFLAGS: + /* Not defined for tunnels */ +- if (!session->session_id && !session->peer_session_id) +- return -ENOSYS; ++ if (!session->session_id && !session->peer_session_id) { ++ err = -ENOSYS; ++ break; ++ } + +- if (put_user(0, (int __user *)arg)) +- return -EFAULT; ++ if (put_user(0, (int __user *)arg)) { ++ err = -EFAULT; ++ break; ++ } + break; + + case PPPIOCSMRU: + case PPPIOCSFLAGS: +- session = sock->sk->sk_user_data; +- if (!session) +- return -ENOTCONN; +- +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) +- return -EBADF; +- + /* Not defined for tunnels */ +- if (!session->session_id && !session->peer_session_id) +- return -ENOSYS; ++ if (!session->session_id && !session->peer_session_id) { ++ err = -ENOSYS; ++ break; ++ } + +- if (!access_ok((int __user *)arg, sizeof(int))) +- return -EFAULT; ++ if (!access_ok((int __user *)arg, sizeof(int))) { ++ err = -EFAULT; ++ break; ++ } + break; + + case PPPIOCGL2TPSTATS: +- session = sock->sk->sk_user_data; +- if (!session) +- return -ENOTCONN; +- +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) +- return -EBADF; +- + /* Session 0 represents the parent tunnel */ + if (!session->session_id && !session->peer_session_id) { + u32 session_id; +- int err; + + if (copy_from_user(&stats, (void __user *)arg, +- sizeof(stats))) +- return -EFAULT; ++ sizeof(stats))) { ++ err = -EFAULT; ++ break; ++ } + + session_id = stats.session_id; + err = pppol2tp_tunnel_copy_stats(&stats, + session->tunnel); + if (err < 0) +- return err; ++ break; + + stats.session_id = session_id; + } else { +@@ -1111,15 +1123,21 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, + stats.tunnel_id = session->tunnel->tunnel_id; + stats.using_ipsec = l2tp_tunnel_uses_xfrm(session->tunnel); + +- if (copy_to_user((void __user *)arg, &stats, sizeof(stats))) +- return -EFAULT; ++ if (copy_to_user((void __user *)arg, &stats, sizeof(stats))) { ++ err = -EFAULT; ++ break; ++ } + break; + + default: +- return -ENOIOCTLCMD; ++ err = -ENOIOCTLCMD; ++ break; + } + +- return 0; ++ if (session) ++ l2tp_session_put(session); ++ ++ return err; + } + + /***************************************************************************** +-- +2.53.0 + diff --git a/queue-6.18/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch b/queue-6.18/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch new file mode 100644 index 0000000000..cc3262cced --- /dev/null +++ b/queue-6.18/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch @@ -0,0 +1,79 @@ +From 04782fd29e06d461bc89c20bbfb32b0effe51c6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:00:13 +0800 +Subject: net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr + +From: Yizhou Zhao + +[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ] + +In mrp_pdu_parse_vecattr(), vector attribute events are encoded three +per byte and valen tracks the number of events left to process. + +The parser decrements valen after processing the first and second events +from each event byte, but not after processing the third one. When valen +is exactly a multiple of three, the loop continues after the last valid +event and consumes the next byte as a new event byte, applying a +spurious event to the MRP applicant state. + +Additionally, when valen is zero the parser unconditionally consumes +attrlen bytes as FirstValue and advances the offset, even though per +IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of +zero and no FirstValue or Vector fields. This corrupts the offset for +subsequent PDU parsing. + +Also, when valen exceeds three the loop crosses byte boundaries but +the attribute value is not incremented between the last event of one +byte and the first event of the next. This causes the first event of +the next byte to use the same attribute value as the third event +rather than the next consecutive value. + +Decrement valen after processing the third event, skip FirstValue +consumption when valen is zero, and increment the attribute value at +the end of each loop iteration. + +Fixes: febf018d2234 ("net/802: Implement Multiple Registration Protocol (MRP)") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Link: https://patch.msgid.link/20260603060016.21522-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/mrp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/802/mrp.c b/net/802/mrp.c +index 23a88305f900cf..cb3535523bdffa 100644 +--- a/net/802/mrp.c ++++ b/net/802/mrp.c +@@ -703,6 +703,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) & + MRP_VECATTR_HDR_LEN_MASK); + ++ /* If valen is 0, only a LeaveAllEvent is present; FirstValue and ++ * Vector fields are absent per IEEE 802.1ak. ++ */ ++ if (valen == 0) ++ return 0; ++ + /* The VectorAttribute structure in a PDU carries event information + * about one or more attributes having consecutive values. Only the + * value for the first attribute is contained in the structure. So +@@ -753,6 +759,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + vaevents %= __MRP_VECATTR_EVENT_MAX; + vaevent = vaevents; + mrp_pdu_parse_vecattr_event(app, skb, vaevent); ++ valen--; ++ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue, ++ mrp_cb(skb)->mh->attrlen); + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch b/queue-6.18/net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch new file mode 100644 index 0000000000..7a6d4d027b --- /dev/null +++ b/queue-6.18/net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch @@ -0,0 +1,47 @@ +From 05402233e60d0b3b4ab86de6a3aa7f3390401bcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:21:04 +0200 +Subject: net: airoha: Fix use-after-free in metadata dst teardown + +From: Lorenzo Bianconi + +[ Upstream commit b38cae85d1c45ff189d7ecb6ac36f41cdc3d84d0 ] + +airoha_metadata_dst_free() runs metadata_dst_free() which frees the +metadata_dst with kfree() immediately, bypassing the RCU grace period. +In the RX path, skb_dst_set_noref() sets a non-refcounted pointer from +the skb to the metadata_dst. This function requires RCU read-side +protection and the dst must remain valid until all RCU readers complete. +Since metadata_dst_free() calls kfree() directly, an use-after-free can +occur if any skb still holds a noref pointer to the dst when the driver +tears it down. +Replace metadata_dst_free() with dst_release() which properly goes +through the refcount path: when the refcount drops to zero, it schedules +the actual free via call_rcu_hurry(), ensuring all RCU readers have +completed before the memory is freed. + +Fixes: af3cf757d5c9 ("net: airoha: Move DSA tag in DMA descriptor") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260602-airoha-mtk-metadata-uaf-fix-v1-1-3aaa99d83351@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 9781a6fc9bf9a8..f30bace944d694 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2933,7 +2933,7 @@ static void airoha_metadata_dst_free(struct airoha_gdm_port *port) + if (!port->dsa_meta[i]) + continue; + +- metadata_dst_free(port->dsa_meta[i]); ++ dst_release(&port->dsa_meta[i]->dst); + } + } + +-- +2.53.0 + diff --git a/queue-6.18/net-annotate-sk-sk_write_space-for-udp-sockmap.patch b/queue-6.18/net-annotate-sk-sk_write_space-for-udp-sockmap.patch new file mode 100644 index 0000000000..0ccbb7b65e --- /dev/null +++ b/queue-6.18/net-annotate-sk-sk_write_space-for-udp-sockmap.patch @@ -0,0 +1,60 @@ +From a50c1d80bb40231998fee25a1a05df0d573a2fe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:39:23 +0000 +Subject: net: Annotate sk->sk_write_space() for UDP SOCKMAP. + +From: Kuniyuki Iwashima + +[ Upstream commit b748765019fe9e9234660327090fc1a9665cdbdd ] + +UDP TX skb->destructor() is sock_wfree(), and UDP holds lock_sock() +only for UDP_CORK / MSG_MORE sendmsg(). + +Otherwise, sk->sk_write_space() may be read locklessly while SOCKMAP +rewrites sk->sk_write_space(). + +Let's use WRITE_ONCE() and READ_ONCE() for sk->sk_write_space(). + +Note that the write side is annotated by commit 2ef2b20cf4e0 +("net: annotate data-races around sk->sk_{data_ready,write_space}"). + +Fixes: 7b98cd42b049 ("bpf: sockmap: Add UDP support") +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Jakub Sitnicki +Link: https://patch.msgid.link/20260529193941.3897256-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 5a38837a583843..82470f59fa5c50 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2654,8 +2654,12 @@ void sock_wfree(struct sk_buff *skb) + bool free; + + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { ++ void (*sk_write_space)(struct sock *sk); ++ ++ sk_write_space = READ_ONCE(sk->sk_write_space); ++ + if (sock_flag(sk, SOCK_RCU_FREE) && +- sk->sk_write_space == sock_def_write_space) { ++ sk_write_space == sock_def_write_space) { + rcu_read_lock(); + free = refcount_sub_and_test(len, &sk->sk_wmem_alloc); + sock_def_write_space_wfree(sk); +@@ -2670,7 +2674,7 @@ void sock_wfree(struct sk_buff *skb) + * after sk_write_space() call + */ + WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc)); +- sk->sk_write_space(sk); ++ sk_write_space(sk); + len = 1; + } + /* +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch b/queue-6.18/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch new file mode 100644 index 0000000000..ef39eb730e --- /dev/null +++ b/queue-6.18/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch @@ -0,0 +1,48 @@ +From f00fb5d5cb4fa0b36fec2b6080e902004cbb64f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:21:05 +0200 +Subject: net: ethernet: mtk_eth_soc: Fix use-after-free in metadata dst + teardown + +From: Lorenzo Bianconi + +[ Upstream commit 80df409e1a483676826a6c66e693dba6ac507751 ] + +mtk_free_dev() calls metadata_dst_free() which frees the metadata_dst +with kfree() immediately, bypassing the RCU grace period. +In the RX path, skb_dst_set_noref() sets a non-refcounted pointer from +the skb to the metadata_dst. This function requires RCU read-side +protection and the dst must remain valid until all RCU readers complete. +Since metadata_dst_free() calls kfree() directly, a use-after-free can +occur if any skb still holds a noref pointer to the dst when the driver +tears it down. +Replace metadata_dst_free() with dst_release() which properly goes +through the refcount path: when the refcount drops to zero, it schedules +the actual free via call_rcu_hurry(), ensuring all RCU readers have +completed before the memory is freed. + +Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260602-airoha-mtk-metadata-uaf-fix-v1-2-3aaa99d83351@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 0f676bd72832bb..065f969ee44ef6 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4470,7 +4470,7 @@ static int mtk_free_dev(struct mtk_eth *eth) + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { + if (!eth->dsa_meta[i]) + break; +- metadata_dst_free(eth->dsa_meta[i]); ++ dst_release(ð->dsa_meta[i]->dst); + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch b/queue-6.18/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch new file mode 100644 index 0000000000..9b1b68ddb5 --- /dev/null +++ b/queue-6.18/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch @@ -0,0 +1,62 @@ +From e139f2b3a6ce64cd406813cab1c8fd0c0851be51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 06:18:57 +0000 +Subject: net: fec: fix pinctrl default state restore order on resume + +From: Tapio Reijonen + +[ Upstream commit b455410146bf723c7ebcb49ecd5becc0d6611482 ] + +In fec_resume(), fec_enet_clk_enable() is called before +pinctrl_pm_select_default_state() in the non-WoL path, inverting the +ordering used in fec_suspend() which correctly switches to the sleep +pinctrl state before disabling clocks. + +For PHYs with the PHY_RST_AFTER_CLK_EN flag (e.g. TI DP83848 or +SMSC LAN87xx), fec_enet_clk_enable() triggers a hardware reset pulse +via the phy-reset GPIO. With the GPIO pin still in sleep pinctrl state +at that point, the GPIO write has no physical effect and the PHY never +receives the required reset after clock enable, leading to unreliable +link establishment after system resume. + +Fix by restoring the default pinctrl state before enabling clocks, +making resume the proper mirror of suspend. The call is made +unconditionally: fec_suspend() only switches to the sleep pinctrl state +on the non-WoL path and leaves the pins in the default state when WoL +is enabled, so on a WoL resume the device is already in the default +state and pinctrl_pm_select_default_state() is a no-op. + +Fixes: de40ed31b3c5 ("net: fec: add Wake-on-LAN support") +Signed-off-by: Tapio Reijonen +Reviewed-by: Wei Fang +Link: https://patch.msgid.link/20260529-b4-fec-resume-pinctrl-order-v3-1-6eda0f592fca@vaisala.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/fec_main.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index f30e8fabfaded8..a2cf8cbe2539ef 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -4772,6 +4772,7 @@ static int fec_resume(struct device *dev) + if (fep->rpm_active) + pm_runtime_force_resume(dev); + ++ pinctrl_pm_select_default_state(&fep->pdev->dev); + ret = fec_enet_clk_enable(ndev, true); + if (ret) { + rtnl_unlock(); +@@ -4788,8 +4789,6 @@ static int fec_resume(struct device *dev) + val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; +- } else { +- pinctrl_pm_select_default_state(&fep->pdev->dev); + } + fec_restart(ndev); + netif_tx_lock_bh(ndev); +-- +2.53.0 + diff --git a/queue-6.18/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch b/queue-6.18/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch new file mode 100644 index 0000000000..19e7b7e67f --- /dev/null +++ b/queue-6.18/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch @@ -0,0 +1,58 @@ +From 18d8333bf1e13db2e375bb54be7208460f68ccbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:31:58 +0800 +Subject: net: garp: fix unsigned integer underflow in garp_pdu_parse_attr + +From: Yizhou Zhao + +[ Upstream commit 16e408e607a94b646fb14a2a98422c6877ae4b3c ] + +The receive-side GARP attribute parser computes dlen with reversed +operands: + + dlen = sizeof(*ga) - ga->len; + +ga->len is the on-wire attribute length and includes the GARP attribute +header. For normal attributes with data, ga->len is larger than +sizeof(*ga), so the subtraction underflows in unsigned arithmetic. + +The resulting value is later passed to garp_attr_lookup(), whose length +argument is u8. After truncation, the parsed data length usually no +longer matches the length stored for locally registered attributes, so +received Join/Leave events are ignored. This breaks the GARP receive path +for common attributes, such as GVRP VLAN registration attributes. + +Compute the data length as the attribute length minus the header length. + +Fixes: eca9ebac651f ("net: Add GARP applicant-only participant") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260527083200.42861-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/garp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/802/garp.c b/net/802/garp.c +index 2d1ffc4d946266..c45abaff515364 100644 +--- a/net/802/garp.c ++++ b/net/802/garp.c +@@ -453,7 +453,7 @@ static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); +- dlen = sizeof(*ga) - ga->len; ++ dlen = ga->len - sizeof(*ga); + + if (attrtype > app->app->maxattr) + return 0; +-- +2.53.0 + diff --git a/queue-6.18/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch b/queue-6.18/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch new file mode 100644 index 0000000000..c130b49820 --- /dev/null +++ b/queue-6.18/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch @@ -0,0 +1,99 @@ +From b158e8e39ead4149b4d1357a5cfc494d2b28a7fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 21:03:00 +0000 +Subject: net: lan743x: permit VLAN-tagged packets up to configured MTU + +From: David Thompson + +[ Upstream commit 8173d22b211f615015f7b35f48ab11a6dd78dc99 ] + +VLAN-tagged interfaces on lan743x devices were previously unreachable via +SSH and failed to respond to large ping packets (e.g. "ping -s 1469" given +MTU=1500). In these scenarios, "ethtool -S" reports non-zero "RX Oversize +Frame Errors". According to Microchip AN2948, the MAC_RX FSE (VLAN field +size enforcement) bit determines whether frames with VLAN tags exceeding +the base MTU plus tag length are discarded. + +The driver must set the MAC_RX.FSE bit before setting MAC_RX.RXEN to allow +VLAN-tagged frames up to the interface MTU, preventing them from being +treated as oversized. As a result, both the base and VLAN-tagged interfaces +can use the same MTU without receive errors. + +Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") +Signed-off-by: David Thompson +Reviewed-by: Thangaraj Samynathan +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz # lan7430 on arm64 (RevPi +Link: https://patch.msgid.link/20260529210300.433135-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 32 +++++++++++++++++++ + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 09d255e78f6cd1..ab2f3c92b3fa33 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1212,6 +1212,36 @@ static void lan743x_mac_set_address(struct lan743x_adapter *adapter, + "MAC address set to %pM\n", addr); + } + ++static void lan743x_mac_rx_enable_fse(struct lan743x_adapter *adapter) ++{ ++ u32 mac_rx; ++ bool rxen; ++ ++ mac_rx = lan743x_csr_read(adapter, MAC_RX); ++ if (mac_rx & MAC_RX_FSE_) ++ return; ++ ++ rxen = mac_rx & MAC_RX_RXEN_; ++ if (rxen) { ++ mac_rx &= ~MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, ++ 1, 1000, 20000, 100); ++ } ++ ++ /* Per AN2948, hardware prevents modification of the FSE bit while the ++ * MAC receiver is enabled (RXEN bit set). Use separate register write ++ * to assert the FSE bit before enabling the RXEN bit in MAC_RX ++ */ ++ mac_rx |= MAC_RX_FSE_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ ++ if (rxen) { ++ mac_rx |= MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ } ++} ++ + static int lan743x_mac_init(struct lan743x_adapter *adapter) + { + bool mac_address_valid = true; +@@ -1251,6 +1281,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter) + lan743x_mac_set_address(adapter, adapter->mac_address); + eth_hw_addr_set(netdev, adapter->mac_address); + ++ lan743x_mac_rx_enable_fse(adapter); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 02a28b7091630d..b977256b742061 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -181,6 +181,7 @@ + #define MAC_RX (0x104) + #define MAC_RX_MAX_SIZE_SHIFT_ (16) + #define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) ++#define MAC_RX_FSE_ BIT(2) + #define MAC_RX_RXD_ BIT(1) + #define MAC_RX_RXEN_ BIT(0) + +-- +2.53.0 + diff --git a/queue-6.18/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch b/queue-6.18/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch new file mode 100644 index 0000000000..e272eed656 --- /dev/null +++ b/queue-6.18/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch @@ -0,0 +1,106 @@ +From 5bc17a642f8c7723502699146b34b48af8801c32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 12:08:12 -0400 +Subject: net/sched: act_api: use RCU with deferred freeing for action + lifecycle + +From: Jamal Hadi Salim + +[ Upstream commit 5057e1aca011e51ef51498c940ef96f3d3e8a305 ] + +When NEWTFILTER and DELFILTER are run concurrently it is possible to create a +race with an associated action. + +Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: + + 0: mutex_lock() <-- holds the idr lock + 0: rcu_read_lock() + 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) + 0: mutex_unlock() <-- releases the idr lock + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) <-- Action removed from IDR + 1: mutex_unlock() <-- mutex released allowing us to delete the action + 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory + +This patch fixes the race condition between NEWTFILTER and DELFILTER by +adding struct rcu_head to tc_action used in the deferral and introducing a +call_rcu() in the delete path to defer the final kfree(). + +Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +but also modernization/simplification to directly use kfree_rcu(). + +Let's illustrate the new restored code path: + + 0: rcu_read_lock() + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) + 1: mutex_unlock() + 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period + 0: p = idr_find(idr, index) + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 + 1: rcu_read_unlock() <-- release so freeing can run after grace period + +After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. +CPU0's subsequent idr_find() will return NULL, and even if it still held a +stale pointer, the immediate kfree() is now deferred until after the RCU grace +period, so no UAF can occur. + +Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +Suggested-by: Jakub Kicinski +Reported-by: Kyle Zeng +Tested-by: Victor Nogueira +Tested-by: syzbot@syzkaller.appspotmail.com +Signed-off-by: Jamal Hadi Salim +Tested-by: Kyle Zeng +Reviewed-by: Pedro Tammela +Reviewed-by: Eric Dumazet +Reviewed-by: Victor Nogueira +Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/act_api.h | 1 + + net/sched/act_api.c | 7 +------ + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/net/act_api.h b/include/net/act_api.h +index 2ba40eb45aad2f..a6d6f09dd0cd6a 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -45,6 +45,7 @@ struct tc_action { + struct tc_cookie __rcu *user_cookie; + struct tcf_chain __rcu *goto_chain; + u32 tcfa_flags; ++ struct rcu_head tcfa_rcu; + u8 hw_stats; + u8 used_hw_stats; + bool used_hw_stats_valid; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index e1ab0faeb8113e..6afeeb6b590a2a 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -112,11 +112,6 @@ struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action, + } + EXPORT_SYMBOL(tcf_action_set_ctrlact); + +-/* XXX: For standalone actions, we don't need a RCU grace period either, because +- * actions are always connected to filters and filters are already destroyed in +- * RCU callbacks, so after a RCU grace period actions are already disconnected +- * from filters. Readers later can not find us. +- */ + static void free_tcf(struct tc_action *p) + { + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); +@@ -129,7 +124,7 @@ static void free_tcf(struct tc_action *p) + if (chain) + tcf_chain_put_by_act(chain); + +- kfree(p); ++ kfree_rcu(p, tcfa_rcu); + } + + static void offload_action_hw_count_set(struct tc_action *act, +-- +2.53.0 + diff --git a/queue-6.18/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch b/queue-6.18/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch new file mode 100644 index 0000000000..7ef98259d9 --- /dev/null +++ b/queue-6.18/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch @@ -0,0 +1,228 @@ +From fac4018807ace9df79d4a7a057953c6c5385c7e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 08:32:21 -0400 +Subject: net/sched: fix pedit partial COW leading to page cache corruption +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rajat Gupta + +[ Upstream commit 899ee91156e57784090c5565e4f31bd7dbffbc5a ] + +tcf_pedit_act() computes the COW range for skb_ensure_writable() +once before the key loop using tcfp_off_max_hint, but the hint does +not account for the runtime header offset added by typed keys. This +can leave part of the write region un-COW'd. + +Fix by moving skb_ensure_writable() inside the per-key loop where +the actual write offset is known, and add overflow checking on the +offset arithmetic. For negative offsets (e.g. Ethernet header edits +at ingress), use skb_cow() to COW the headroom instead. Guard +offset_valid() against INT_MIN, where negation is undefined. + +Fixes: 8b796475fd78 ("net/sched: act_pedit: really ensure the skb is writable") +Reported-by: Yiming Qian +Reported-by: Keenan Dong +Reported-by: Han Guidong <2045gemini@gmail.com> +Reported-by: Zhang Cen +Reviewed-by: Han Guidong <2045gemini@gmail.com> +Tested-by: Han Guidong <2045gemini@gmail.com> +Reviewed-by: Davide Caratti +Tested-by: Davide Caratti +Reviewed-by: Toke Høiland-Jørgensen +Tested-by: Toke Høiland-Jørgensen +Reviewed-by: Victor Nogueira +Tested-by: Victor Nogueira +Acked-by: Jamal Hadi Salim +Signed-off-by: Rajat Gupta +Link: https://patch.msgid.link/20260531123221.48732-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tc_act/tc_pedit.h | 1 - + net/sched/act_pedit.c | 77 +++++++++++++++++++---------------- + 2 files changed, 41 insertions(+), 37 deletions(-) + +diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h +index f58ee15cd858cf..cb7b82f2cbc7fd 100644 +--- a/include/net/tc_act/tc_pedit.h ++++ b/include/net/tc_act/tc_pedit.h +@@ -15,7 +15,6 @@ struct tcf_pedit_parms { + struct tc_pedit_key *tcfp_keys; + struct tcf_pedit_key_ex *tcfp_keys_ex; + int action; +- u32 tcfp_off_max_hint; + unsigned char tcfp_nkeys; + unsigned char tcfp_flags; + struct rcu_head rcu; +diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c +index 4b65901397a888..c0a5f5d78dacd9 100644 +--- a/net/sched/act_pedit.c ++++ b/net/sched/act_pedit.c +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -242,7 +244,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + goto out_free_ex; + } + +- nparms->tcfp_off_max_hint = 0; + nparms->tcfp_flags = parm->flags; + nparms->tcfp_nkeys = parm->nkeys; + +@@ -268,14 +269,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + BITS_PER_TYPE(int) - 1, + nparms->tcfp_keys[i].shift); + +- /* The AT option can read a single byte, we can bound the actual +- * value with uchar max. +- */ +- cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift; +- +- /* Each key touches 4 bytes starting from the computed offset */ +- nparms->tcfp_off_max_hint = +- max(nparms->tcfp_off_max_hint, cur + 4); + } + + p = to_pedit(*a); +@@ -318,15 +311,12 @@ static void tcf_pedit_cleanup(struct tc_action *a) + call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu); + } + +-static bool offset_valid(struct sk_buff *skb, int offset) ++static bool offset_valid(struct sk_buff *skb, int offset, int len) + { +- if (offset > 0 && offset > skb->len) +- return false; +- +- if (offset < 0 && -offset > skb_headroom(skb)) ++ if (offset < -(int)skb_headroom(skb)) + return false; + +- return true; ++ return offset <= (int)skb->len - len; + } + + static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type) +@@ -393,18 +383,10 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + struct tcf_pedit_key_ex *tkey_ex; + struct tcf_pedit_parms *parms; + struct tc_pedit_key *tkey; +- u32 max_offset; + int i; + + parms = rcu_dereference_bh(p->parms); + +- max_offset = (skb_transport_header_was_set(skb) ? +- skb_transport_offset(skb) : +- skb_network_offset(skb)) + +- parms->tcfp_off_max_hint; +- if (skb_ensure_writable(skb, min(skb->len, max_offset))) +- goto done; +- + tcf_lastuse_update(&p->tcf_tm); + tcf_action_update_bstats(&p->common, skb); + +@@ -412,10 +394,11 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + tkey_ex = parms->tcfp_keys_ex; + + for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { ++ int write_offset, write_len; + int offset = tkey->off; + int hoffset = 0; +- u32 *ptr, hdata; +- u32 val; ++ u32 cur_val, val; ++ u32 *ptr; + int rc; + + if (tkey_ex) { +@@ -433,13 +416,15 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + + if (tkey->offmask) { + u8 *d, _d; ++ int at_offset; + +- if (!offset_valid(skb, hoffset + tkey->at)) { ++ if (check_add_overflow(hoffset, (int)tkey->at, &at_offset) || ++ !offset_valid(skb, at_offset, sizeof(_d))) { + pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n", + hoffset + tkey->at); + goto bad; + } +- d = skb_header_pointer(skb, hoffset + tkey->at, ++ d = skb_header_pointer(skb, at_offset, + sizeof(_d), &_d); + if (!d) + goto bad; +@@ -451,31 +436,51 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + } + } + +- if (!offset_valid(skb, hoffset + offset)) { +- pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset); ++ if (check_add_overflow(hoffset, offset, &write_offset)) { ++ pr_info_ratelimited("tc action pedit offset overflow\n"); + goto bad; + } + +- ptr = skb_header_pointer(skb, hoffset + offset, +- sizeof(hdata), &hdata); +- if (!ptr) ++ if (!offset_valid(skb, write_offset, sizeof(*ptr))) { ++ pr_info_ratelimited("tc action pedit offset %d out of bounds\n", ++ write_offset); + goto bad; ++ } ++ ++ if (write_offset < 0) { ++ if (skb_cow(skb, -write_offset)) ++ goto bad; ++ if (write_offset + (int)sizeof(*ptr) > 0) { ++ if (skb_ensure_writable(skb, ++ min_t(int, skb->len, ++ write_offset + (int)sizeof(*ptr)))) ++ goto bad; ++ } ++ } else { ++ if (check_add_overflow(write_offset, (int)sizeof(*ptr), ++ &write_len)) ++ goto bad; ++ if (skb_ensure_writable(skb, min_t(int, skb->len, ++ write_len))) ++ goto bad; ++ } ++ ++ ptr = (u32 *)(skb->data + write_offset); ++ cur_val = get_unaligned(ptr); + /* just do it, baby */ + switch (cmd) { + case TCA_PEDIT_KEY_EX_CMD_SET: + val = tkey->val; + break; + case TCA_PEDIT_KEY_EX_CMD_ADD: +- val = (*ptr + tkey->val) & ~tkey->mask; ++ val = (cur_val + tkey->val) & ~tkey->mask; + break; + default: + pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd); + goto bad; + } + +- *ptr = ((*ptr & tkey->mask) ^ val); +- if (ptr == &hdata) +- skb_store_bits(skb, hoffset + offset, ptr, 4); ++ put_unaligned((cur_val & tkey->mask) ^ val, ptr); + } + + goto done; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch b/queue-6.18/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch new file mode 100644 index 0000000000..53e5fd13b7 --- /dev/null +++ b/queue-6.18/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch @@ -0,0 +1,58 @@ +From b1a2b3bcaccbb935f7fd7e51be84ea706a610a4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 12:29:10 +0000 +Subject: netfilter: bridge: make ebt_snat ARP rewrite writable + +From: Yiming Qian + +[ Upstream commit 67ba971ae02514d85818fe0c32549ab4bfa3bf49 ] + +The ebtables SNAT target keeps the Ethernet source address rewrite +behind skb_ensure_writable(skb, 0). This is intentional: at the bridge +ebtables hooks the Ethernet header is addressed through +skb_mac_header()/eth_hdr(), while skb->data points at the Ethernet +payload. Asking skb_ensure_writable() for ETH_HLEN bytes would check +the payload, not the Ethernet header, and would reintroduce the small +packet regression fixed by commit 63137bc5882a. + +However, the optional ARP sender hardware address rewrite is different. +It writes through skb_store_bits() at an offset relative to skb->data: + + skb_store_bits(skb, sizeof(struct arphdr), info->mac, ETH_ALEN) + +skb_header_pointer() only safely reads the ARP header; it does not make +the later sender hardware address range writable. If that range is +still held in a nonlinear skb fragment backed by a splice-imported file +page, skb_store_bits() maps the frag page and copies the new MAC address +directly into it. + +Ensure the ARP SHA range is writable before reading the ARP header and +before calling skb_store_bits(). + +Fixes: 63137bc5882a ("netfilter: ebtables: Fixes dropping of small packets in bridge nat") +Reported-by: Yiming Qian +Signed-off-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_snat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c +index 7dfbcdfc30e5d2..c9e229af0366b8 100644 +--- a/net/bridge/netfilter/ebt_snat.c ++++ b/net/bridge/netfilter/ebt_snat.c +@@ -31,6 +31,9 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) + const struct arphdr *ap; + struct arphdr _ah; + ++ if (skb_ensure_writable(skb, sizeof(_ah) + ETH_ALEN)) ++ return EBT_DROP; ++ + ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch b/queue-6.18/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch new file mode 100644 index 0000000000..75c9e511d3 --- /dev/null +++ b/queue-6.18/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch @@ -0,0 +1,50 @@ +From 786bfe9682326739d8421044871768a405a813fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:20:19 +0200 +Subject: netfilter: conntrack_irc: fix possible out-of-bounds read + +From: Florian Westphal + +[ Upstream commit 66eba0ffce3b7e11449946b4cbbef8ea36112f56 ] + +When parsing fails after we've matched the command string we +should bail out instead of trying to match a different command. + +This helper should be deprecated, given prevalence of TLS I doubt it has +any relevance in 2026. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Closes: https://sashiko.dev/#/patchset/20260525182924.28456-1-fw%40strlen.de +Signed-off-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_irc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c +index 5703846bea3b69..0f50ea92ced9df 100644 +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -208,7 +208,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + pr_debug("unable to parse dcc command\n"); +- continue; ++ goto out; + } + + pr_debug("DCC bound ip/port: %pI4:%u\n", +@@ -222,7 +222,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); +- continue; ++ goto out; + } + + exp = nf_ct_expect_alloc(ct); +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch b/queue-6.18/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch new file mode 100644 index 0000000000..819dbcce4b --- /dev/null +++ b/queue-6.18/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch @@ -0,0 +1,96 @@ +From a1b7aaa8c64e714a26658b65f16cde95eef8282c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:09:19 +0800 +Subject: netfilter: nft_ct: bail out on template ct in get eval + +From: Jiayuan Chen + +[ Upstream commit 3027ecbdb5fdf9200251c21d4818e4c447ef78e1 ] + +I noticed this issue while looking at a historic syzbot report [1]. + +A rule like the one below is enough to trigger the bug: + + table ip t { + chain pre { + type filter hook prerouting priority raw; + ct zone set 1 + ct original saddr 1.2.3.4 accept + } + } + +The first expression attaches a per-cpu template ct via +nft_ct_set_zone_eval() (nf_ct_tmpl_alloc -> kzalloc, tuple is all +zero, nf_ct_l3num(ct) == 0). The next expression then calls +nft_ct_get_eval() on the same skb, treats the template as a real ct +and hits the 16-byte memcpy path. With dreg at NFT_REG32_15 this +overflows past struct nft_regs on the kernel stack; with smaller +dreg values it silently clobbers adjacent registers. + +Reject template ct at the eval entry and in nft_ct_get_fast_eval(), +mirroring the check nft_ct_set_eval() already has. Additionally, +bound the address copy in NFT_CT_SRC / NFT_CT_DST by priv->len +instead of by nf_ct_l3num(ct): nf_ct_get_tuple() zeroes the tuple +before pkt_to_tuple() fills in only the protocol-relevant leading +bytes, so the trailing bytes of tuple->{src,dst}.u3.all are +well-defined zero. priv->len is validated at rule load, so the +copy size is now bounded by the destination register rather than +by an untrusted field on the conntrack. + +[1]: https://syzkaller.appspot.com/bug?id=389cf09cb72926114fce90dc85a2c3231dcb647c + +Fixes: 45d9bcda21f4 ("netfilter: nf_tables: validate len in nft_validate_data_load()") +Suggested-by: Florian Westphal +Signed-off-by: Jiayuan Chen +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_ct.c | 8 +++----- + net/netfilter/nft_ct_fast.c | 2 +- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c +index 8dbf31e7ddcbee..c776eb38f1dbd0 100644 +--- a/net/netfilter/nft_ct.c ++++ b/net/netfilter/nft_ct.c +@@ -78,7 +78,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + break; + } + +- if (ct == NULL) ++ if (!ct || nf_ct_is_template(ct)) + goto err; + + switch (priv->key) { +@@ -180,12 +180,10 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + tuple = &ct->tuplehash[priv->dir].tuple; + switch (priv->key) { + case NFT_CT_SRC: +- memcpy(dest, tuple->src.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->src.u3.all, priv->len); + return; + case NFT_CT_DST: +- memcpy(dest, tuple->dst.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->dst.u3.all, priv->len); + return; + case NFT_CT_PROTO_SRC: + nft_reg_store16(dest, (__force u16)tuple->src.u.all); +diff --git a/net/netfilter/nft_ct_fast.c b/net/netfilter/nft_ct_fast.c +index e684c8a9184877..ecf7b3a404be26 100644 +--- a/net/netfilter/nft_ct_fast.c ++++ b/net/netfilter/nft_ct_fast.c +@@ -30,7 +30,7 @@ void nft_ct_get_fast_eval(const struct nft_expr *expr, + break; + } + +- if (!ct) { ++ if (!ct || nf_ct_is_template(ct)) { + regs->verdict.code = NFT_BREAK; + return; + } +-- +2.53.0 + diff --git a/queue-6.18/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch b/queue-6.18/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch new file mode 100644 index 0000000000..b16738cc75 --- /dev/null +++ b/queue-6.18/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch @@ -0,0 +1,113 @@ +From 79673a3d724836387c6f300e69f297f396d392b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 23:58:31 +0200 +Subject: netfilter: synproxy: add mutex to guard hook reference counting + +From: Fernando Fernandez Mancera + +[ Upstream commit 2fcba19caaeb2a33017459d3430f057967bb91b6 ] + +As the synproxy infrastructure register netfilter hooks on-demand when a +user adds the first iptables target or nftables expression, if done +concurrently they can race each other. + +Introduce a mutex to serialize the refcount control blocks access from +both frontends. While a per namespace mutex might be more efficient, it +is not needed for target/expression like SYNPROXY. + +Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 6a851ac4dd048f..a277b2bd3275dc 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -21,6 +21,8 @@ + #include + #include + ++static DEFINE_MUTEX(synproxy_mutex); ++ + unsigned int synproxy_net_id; + EXPORT_SYMBOL_GPL(synproxy_net_id); + +@@ -768,26 +770,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = { + + int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref4 == 0) { + err = nf_register_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref4++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init); + + void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref4--; + if (snet->hook_ref4 == 0) + nf_unregister_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini); + +@@ -1192,27 +1199,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = { + int + nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref6 == 0) { + err = nf_register_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref6++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init); + + void + nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref6--; + if (snet->hook_ref6 == 0) + nf_unregister_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini); + #endif /* CONFIG_IPV6 */ +-- +2.53.0 + diff --git a/queue-6.18/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch b/queue-6.18/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..e15b239417 --- /dev/null +++ b/queue-6.18/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch @@ -0,0 +1,41 @@ +From 0b1c475da74b3ff4272ed64fe557696342fe74c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 12:47:17 +0200 +Subject: netfilter: xt_NFQUEUE: prefer raw_smp_processor_id + +From: Fernando Fernandez Mancera + +[ Upstream commit c6c5327dd18bec1e1bbf139b2cf5ae53608a9d30 ] + +With PREEMPT_RCU this triggers a splat because smp_processor_id() can be +preempted while inside a RCU critical section. If xt_NFQUEUE target is +invoked via nft_compat_eval() path, we are inside a RCU critical +section. + +Just use the raw version instead. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_NFQUEUE.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index 466da23e36ff47..b32d153e3a1862 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -91,7 +91,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) + + if (info->queues_total > 1) { + if (info->flags & NFQ_FLAG_CPU_FANOUT) { +- int cpu = smp_processor_id(); ++ int cpu = raw_smp_processor_id(); + + queue = info->queuenum + cpu % info->queues_total; + } else { +-- +2.53.0 + diff --git a/queue-6.18/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch b/queue-6.18/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch new file mode 100644 index 0000000000..e3997ce9d4 --- /dev/null +++ b/queue-6.18/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch @@ -0,0 +1,44 @@ +From 33e514b0762e666745ffa3a500304af7799a183c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 17:07:05 +0530 +Subject: octeontx2-af: Fix initialization of mcam's entry2target_pffunc field + +From: Suman Ghosh + +[ Upstream commit 9a85ec3dc28b6df246801c19e4d9bae6297a25b0 ] + +NPC mcam entry stores a mapping between mcam entry and target pcifunc. +During initialization of this field, API kmalloc_array has been used which +caused some junk values to array. Whereas, the array is expected to be +initialized by 0. This patch fixes the same by using kcalloc instead of +kmalloc_array. + +Fixes: 55307fcb9258 ("octeontx2-af: Add mbox messages to install and delete MCAM rules") +Signed-off-by: Suman Ghosh +Signed-off-by: Subbaraya Sundeep +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/1780054625-17090-1-git-send-email-sbhatta@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index e28675fe189071..a0d2ed56186d8d 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -1932,8 +1932,8 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr) + goto free_entry_cntr_map; + + /* Alloc memory for saving target device of mcam rule */ +- mcam->entry2target_pffunc = kmalloc_array(mcam->total_entries, +- sizeof(u16), GFP_KERNEL); ++ mcam->entry2target_pffunc = kcalloc(mcam->total_entries, ++ sizeof(u16), GFP_KERNEL); + if (!mcam->entry2target_pffunc) + goto free_cntr_refcnt; + +-- +2.53.0 + diff --git a/queue-6.18/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch b/queue-6.18/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch new file mode 100644 index 0000000000..00b95e0eb5 --- /dev/null +++ b/queue-6.18/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch @@ -0,0 +1,119 @@ +From d4eaf888f8e21c70415d933cd5020ece26cbbc3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 10:28:53 +0530 +Subject: octeontx2-af: npc: Fix CPT channel mask in npc_install_flow + +From: Nithin Dabilpuram + +[ Upstream commit 1d31eb27e570daa04f5373345f9ac98c95863be9 ] + +Use the CPT-aware NIX channel mask in the npc_install_flow path so that +when the host PF installs steering rules in kernel for a VF used from +userspace (e.g. DPDK), MCAM entries see the same channel mask semantics as +other RX paths. + +Fixes: 56bcef528bd8 ("octeontx2-af: Use npc_install_flow API for promisc and broadcast entries") +Cc: Naveen Mamindlapalli +Signed-off-by: Nithin Dabilpuram +Signed-off-by: Ratheesh Kannoth +Link: https://patch.msgid.link/20260602045853.1558530-1-rkannoth@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + + .../ethernet/marvell/octeontx2/af/rvu_npc.c | 32 +++++++++---------- + .../marvell/octeontx2/af/rvu_npc_fs.c | 2 +- + 3 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index b5828334192324..914ba2b691ec80 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -1124,6 +1124,7 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int lf, + int slot); + int rvu_cpt_ctx_flush(struct rvu *rvu, u16 pcifunc); + int rvu_cpt_init(struct rvu *rvu); ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu); + + #define NDC_AF_BANK_MASK GENMASK_ULL(7, 0) + #define NDC_AF_BANK_LINE_MASK GENMASK_ULL(31, 16) +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index a0d2ed56186d8d..65aa6aeab8e782 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -599,6 +599,19 @@ void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + NPC_AF_MCAMEX_BANKX_ACTION(index, bank), cfg); + } + ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu) ++{ ++ /* For cn10k the upper two bits of the channel number are ++ * cpt channel number. with masking out these bits in the ++ * mcam entry, same entry used for NIX will allow packets ++ * received from cpt for parsing. ++ */ ++ if (!is_rvu_otx2(rvu)) ++ return NIX_CHAN_CPT_X2P_MASK; ++ else ++ return 0xFFFu; ++} ++ + void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + int nixlf, u64 chan, u8 *mac_addr) + { +@@ -642,7 +655,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + eth_broadcast_addr((u8 *)&req.mask.dmac); + req.features = BIT_ULL(NPC_DMAC); + req.channel = chan; +- req.chan_mask = 0xFFFU; ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.intf = pfvf->nix_rx_intf; + req.op = action.op; + req.hdr.pcifunc = 0; /* AF is requester */ +@@ -712,11 +725,7 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc, + * mcam entry, same entry used for NIX will allow packets + * received from cpt for parsing. + */ +- if (!is_rvu_otx2(rvu)) { +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- } else { +- req.chan_mask = 0xFFFU; +- } ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + + if (chan_cnt > 1) { + if (!is_power_of_2(chan_cnt)) { +@@ -887,16 +896,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf, + ether_addr_copy(req.mask.dmac, mac_addr); + req.features = BIT_ULL(NPC_DMAC); + +- /* For cn10k the upper two bits of the channel number are +- * cpt channel number. with masking out these bits in the +- * mcam entry, same entry used for NIX will allow packets +- * received from cpt for parsing. +- */ +- if (!is_rvu_otx2(rvu)) +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- else +- req.chan_mask = 0xFFFU; +- ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.channel = chan; + req.intf = pfvf->nix_rx_intf; + req.entry = index; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +index b56395ac5a7439..e0262fcedd8984 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +@@ -1470,7 +1470,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, + + /* ignore chan_mask in case pf func is not AF, revisit later */ + if (!is_pffunc_af(req->hdr.pcifunc)) +- req->chan_mask = 0xFFF; ++ req->chan_mask = rvu_get_cpt_chan_mask(rvu); + + err = npc_check_unsupported_flows(rvu, req->features, req->intf); + if (err) +-- +2.53.0 + diff --git a/queue-6.18/octeontx2-pf-fix-ndc-sync-operation-errors.patch b/queue-6.18/octeontx2-pf-fix-ndc-sync-operation-errors.patch new file mode 100644 index 0000000000..c96b5fc1f1 --- /dev/null +++ b/queue-6.18/octeontx2-pf-fix-ndc-sync-operation-errors.patch @@ -0,0 +1,40 @@ +From 358de501dee14efe74efbfa661e02ac670f93ab1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 17:07:57 +0530 +Subject: octeontx2-pf: Fix NDC sync operation errors + +From: Geetha sowjanya + +[ Upstream commit a910fb8f7b9e4c566db363e6c2ec378dc7153995 ] + +On system reboot "rvu_nicpf 0002:03:00.0: NDC sync operation failed" +error messages are shown, even if the operations is successful. +This is due to wrong if error check in ndc_syc() function. + +Fixes: 42c45ac1419c ("octeontx2-af: Sync NIX and NPA contexts from NDC to LLC/DRAM") +Signed-off-by: Geetha sowjanya +Signed-off-by: Subbaraya Sundeep +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/1780054677-17249-1-git-send-email-sbhatta@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index bbf25769f4994a..fa23d42d1318b4 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3481,7 +3481,7 @@ static void otx2_ndc_sync(struct otx2_nic *pf) + req->nix_lf_rx_sync = 1; + req->npa_lf_sync = 1; + +- if (!otx2_sync_mbox_msg(mbox)) ++ if (otx2_sync_mbox_msg(mbox)) + dev_err(pf->dev, "NDC sync operation failed\n"); + + mutex_unlock(&mbox->lock); +-- +2.53.0 + diff --git a/queue-6.18/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch b/queue-6.18/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch new file mode 100644 index 0000000000..6b4d375e43 --- /dev/null +++ b/queue-6.18/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch @@ -0,0 +1,58 @@ +From 48727ee140080c6d4e8568375410b3cad8dbd5af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 16:03:20 +0200 +Subject: pcnet32: stop holding device spin lock during napi_complete_done + +From: Oscar Maes + +[ Upstream commit 73bf3cca7de6a73f53b6a52dc3b1c82ae5667a4d ] + +napi_complete_done may call gro_flush_normal (though not currently, as GRO +is unsupported at the moment), which may result in packet TX. This will +eventually result in calling pcnet32_start_xmit - resulting in a deadlock +while trying to re-acquire the already locked spin lock. + +It is safe to split the spinlock block into two, because the hardware +registers are still protected from concurrent access, and the two blocks +perform unrelated operations that don't need to happen atomically. + +Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()") +Reviewed-by: Andrew Lunn +Signed-off-by: Oscar Maes +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/pcnet32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c +index 9eaefa0f5e80c5..b465bb77432194 100644 +--- a/drivers/net/ethernet/amd/pcnet32.c ++++ b/drivers/net/ethernet/amd/pcnet32.c +@@ -1407,8 +1407,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + pcnet32_restart(dev, CSR0_START); + netif_wake_queue(dev); + } ++ spin_unlock_irqrestore(&lp->lock, flags); + + if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a->read_csr(ioaddr, CSR3); + val &= 0x00ff; +@@ -1416,9 +1418,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + + /* Set interrupt enable. */ + lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN); ++ spin_unlock_irqrestore(&lp->lock, flags); + } + +- spin_unlock_irqrestore(&lp->lock, flags); + return work_done; + } + +-- +2.53.0 + diff --git a/queue-6.18/ptp-vclock-switch-from-rcu-to-srcu.patch b/queue-6.18/ptp-vclock-switch-from-rcu-to-srcu.patch new file mode 100644 index 0000000000..89d88df6ec --- /dev/null +++ b/queue-6.18/ptp-vclock-switch-from-rcu-to-srcu.patch @@ -0,0 +1,85 @@ +From 6f33ef20cd374d326208db9f1263a2dbce5df8e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:11:47 +0200 +Subject: ptp: vclock: Switch from RCU to SRCU + +From: Kurt Kanzenbach + +[ Upstream commit 672bd0519e27c357c43b7f8c0d653fce3817d06e ] + +The usage of PTP vClocks leads immediately to the following issues with +ptp4l with LOCKDEP and DEBUG_ATOMIC_SLEEP enabled: "BUG: sleeping function +called from invalid context". + +ptp_convert_timestamp() acquires a mutex_t within a RCU read section. This +is illegal, because acquiring a mutex_t can result in voluntary scheduling +request which is not allowed within a RCU read section. + +Replace the RCU usage with SRCU where sleeping is allowed. + +Reported-by: Florian Zeitz +Closes: https://lore.kernel.org/all/00a8cce8-410e-4038-98af-49be6d93d7bd@schettke.com/ +Fixes: 67d93ffc0f3c ("ptp: vclock: use mutex to fix "sleep on atomic" bug") +Signed-off-by: Kurt Kanzenbach +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260529-vclock_rcu-v2-1-02a5531fab92@linutronix.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_vclock.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c +index 64c95045651787..295a64bdd846f2 100644 +--- a/drivers/ptp/ptp_vclock.c ++++ b/drivers/ptp/ptp_vclock.c +@@ -19,6 +19,8 @@ static DEFINE_SPINLOCK(vclock_hash_lock); + + static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8); + ++DEFINE_STATIC_SRCU(vclock_srcu); ++ + static void ptp_vclock_hash_add(struct ptp_vclock *vclock) + { + spin_lock(&vclock_hash_lock); +@@ -37,7 +39,7 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock) + + spin_unlock(&vclock_hash_lock); + +- synchronize_rcu(); ++ synchronize_srcu(&vclock_srcu); + } + + static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +@@ -276,14 +278,16 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + { + unsigned int hash = vclock_index % HASH_SIZE(vclock_hash); + struct ptp_vclock *vclock; +- u64 ns; + u64 vclock_ns = 0; ++ int srcu_idx; ++ u64 ns; + + ns = ktime_to_ns(*hwtstamp); + +- rcu_read_lock(); ++ srcu_idx = srcu_read_lock(&vclock_srcu); + +- hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) { ++ hlist_for_each_entry_srcu(vclock, &vclock_hash[hash], vclock_hash_node, ++ srcu_read_lock_held(&vclock_srcu)) { + if (vclock->clock->index != vclock_index) + continue; + +@@ -294,7 +298,7 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + break; + } + +- rcu_read_unlock(); ++ srcu_read_unlock(&vclock_srcu, srcu_idx); + + return ns_to_ktime(vclock_ns); + } +-- +2.53.0 + diff --git a/queue-6.18/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch b/queue-6.18/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch new file mode 100644 index 0000000000..d780f95227 --- /dev/null +++ b/queue-6.18/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch @@ -0,0 +1,87 @@ +From bac7c58ed1d278e2f5fbc13ee5e5fe6c80a7f801 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:11:44 -0400 +Subject: sctp: purge outqueue on stale COOKIE-ECHO handling + +From: Xin Long + +[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ] + +sctp_stream_update() is only invoked when the association is moved into +COOKIE_WAIT during association setup/reconfiguration. In this path, the +outbound stream scheduler state (stream->out_curr) is expected to be +clean, since no user data should have been transmitted yet unless the +state machine has already partially progressed. + +However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a +Stale Cookie ERROR is received, the association is rolled back from +COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already +have been queued and even bundled with the COOKIE-ECHO chunk. + +During the rollback, sctp_stream_update() frees the old stream table +and installs a new one, but it does not invalidate stream->out_curr. +As a result, out_curr may still point to a freed sctp_stream_out +entry from the previous stream state. + +Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on +stream->out_curr->ext, which can lead to use-after-free once the old +stream state has been released via sctp_stream_free(). + +This results in crashes such as (reported by Yuqi): + + BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140 + Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312 + CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted + 7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full) + sctp_sched_fcfs_dequeue+0x13a/0x140 + sctp_outq_flush+0x1603/0x33e0 + sctp_do_sm+0x31c9/0x5d30 + sctp_assoc_bh_rcv+0x392/0x6f0 + sctp_inq_push+0x1db/0x270 + sctp_rcv+0x138d/0x3c10 + +Fix this by fully purging the association outqueue when handling the +Stale Cookie case. This ensures all pending transmit and retransmit +state is dropped, and any scheduler cached pointers are invalidated, +making it safe to rebuild stream state during COOKIE_WAIT restart. + +Updating only stream->out_curr would be insufficient, since queued +and retransmittable data would still reference the old stream state and +trigger later use-after-free in dequeue paths. + +Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Reported-by: Yuqi Xu +Reported-by: Ren Wei +Signed-off-by: Xin Long +Link: https://patch.msgid.link/94318159b9052907a6cbb7256aee8b5f8dfbfccb.1780510304.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 8e89a870780c49..9b23c11cbb9ea4 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2598,11 +2598,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + +- /* If we've sent any data bundled with COOKIE-ECHO we will need to +- * resend +- */ +- sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, +- SCTP_TRANSPORT(asoc->peer.primary_path)); ++ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. +-- +2.53.0 + diff --git a/queue-6.18/sctp-validate-cached-peer-init-chunk-length-in-cooki.patch b/queue-6.18/sctp-validate-cached-peer-init-chunk-length-in-cooki.patch new file mode 100644 index 0000000000..251b8fc7ed --- /dev/null +++ b/queue-6.18/sctp-validate-cached-peer-init-chunk-length-in-cooki.patch @@ -0,0 +1,61 @@ +From faeef7ac112e041e07ae1c629a5117c03299af33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 21:06:06 -0400 +Subject: sctp: validate cached peer INIT chunk length in COOKIE_ECHO + processing + +From: Xin Long + +[ Upstream commit 0861615c28de668669d748ef4eb913ea9262d13b ] + +When a listening SCTP server processes a COOKIE_ECHO chunk, the cached +peer INIT chunk embedded after the cookie is parsed and its parameters +are later walked by sctp_process_init() using sctp_walk_params(). + +However, the chunk header length of this cached INIT chunk was not +validated against the remaining buffer in the COOKIE_ECHO payload. If +the length field is inflated, the parameter walk can run beyond the +actual received data, leading to out-of-bounds reads and potential +memory corruption during later parameter handling (e.g. STATE_COOKIE +processing and kmemdup() copies). + +Add a bounds check in sctp_unpack_cookie() to ensure the cached INIT +chunk length does not exceed the available data in the COOKIE_ECHO +buffer before it is used. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Brian Geffon +Signed-off-by: Xin Long +Link: https://patch.msgid.link/eb60825fa22d6f9e663c7d4dbb69f397b5d34d42.1780362366.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_make_chunk.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index 2c0017d058d409..9014b095f52ddb 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -1730,6 +1730,7 @@ struct sctp_association *sctp_unpack_cookie( + struct sctp_signed_cookie *cookie; + struct sk_buff *skb = chunk->skb; + struct sctp_cookie *bear_cookie; ++ struct sctp_chunkhdr *ch; + enum sctp_scope scope; + unsigned int len; + ktime_t kt; +@@ -1759,6 +1760,10 @@ struct sctp_association *sctp_unpack_cookie( + cookie = chunk->subh.cookie_hdr; + bear_cookie = &cookie->c; + ++ ch = (struct sctp_chunkhdr *)(bear_cookie + 1); ++ if (ntohs(ch->length) > len - fixed_size) ++ goto malformed; ++ + /* Verify the cookie's MAC, if cookie authentication is enabled. */ + if (sctp_sk(ep->base.sk)->cookie_auth_enable) { + u8 mac[SHA256_DIGEST_SIZE]; +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index 3a3e22f743..03e135d424 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -3,3 +3,62 @@ arm-group-is_permission_fault-with-is_translation_fa.patch arm-allow-__do_kernel_fault-to-report-execution-of-m.patch arm-fix-hash_name-fault.patch arm-fix-branch-predictor-hardening.patch +tee-optee-prevent-use-after-free-when-the-client-exi.patch +soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch +arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch +arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch +soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch +tee-fix-tee_ioctl_object_invoke_arg-padding.patch +tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch +erofs-tidy-up-synchronous-decompression.patch +erofs-fix-use-after-free-on-sbi-sync_decompress.patch +wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch +ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch +netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch +ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch +netfilter-synproxy-add-mutex-to-guard-hook-reference.patch +netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch +netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch +netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch +dm-cache-policy-smq-check-allocation-under-invalidat.patch +net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch +6lowpan-fix-off-by-one-in-multicast-context-address-.patch +l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch +devlink-release-nested-relation-on-devlink-free.patch +drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch +wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch +pcnet32-stop-holding-device-spin-lock-during-napi_co.patch +net-annotate-sk-sk_write_space-for-udp-sockmap.patch +hsr-remove-warn_once-in-hsr_addr_is_self.patch +net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch +net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch +net-fec-fix-pinctrl-default-state-restore-order-on-r.patch +ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch +wifi-fix-leak-if-split-6-ghz-scanning-fails.patch +bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch +bluetooth-mgmt-validate-advertising-tlv-before-type-.patch +bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch +bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch +bluetooth-bnep-reject-short-frames-before-parsing.patch +bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch +bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch +bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch +bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch +bluetooth-mgmt-fix-backward-compatibility-with-users.patch +xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch +octeontx2-pf-fix-ndc-sync-operation-errors.patch +octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch +af_unix-fix-inq_len-update-problem-in-partial-read.patch +ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch +ptp-vclock-switch-from-rcu-to-srcu.patch +net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch +net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch +net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch +sctp-validate-cached-peer-init-chunk-length-in-cooki.patch +octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch +vxlan-vnifilter-send-notification-on-vni-add.patch +vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch +ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch +ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch +net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch +sctp-purge-outqueue-on-stale-cookie-echo-handling.patch diff --git a/queue-6.18/soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch b/queue-6.18/soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch new file mode 100644 index 0000000000..0fdeb962bf --- /dev/null +++ b/queue-6.18/soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch @@ -0,0 +1,87 @@ +From fc7202ea6aa440a60f11f1721cc8df9e4c0a8f4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:29:19 +0530 +Subject: soc: qcom: ice: Allow explicit votes on 'iface' clock for ICE + +From: Harshal Dev + +[ Upstream commit 0d5dc5818191b55e4364d04b1b898a14a2ccac38 ] + +Since Qualcomm inline-crypto engine (ICE) is now a dedicated driver +de-coupled from the QCOM UFS driver, it explicitly votes for its required +clocks during probe. For scenarios where the 'clk_ignore_unused' flag is +not passed on the kernel command line, to avoid potential unclocked ICE +hardware register access during probe the ICE driver should additionally +vote on the 'iface' clock. +Also update the suspend and resume callbacks to handle un-voting and voting +on the 'iface' clock. + +Fixes: 2afbf43a4aec6 ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver") +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Kuldeep Singh +Reviewed-by: Konrad Dybcio +Signed-off-by: Harshal Dev +Link: https://lore.kernel.org/r/20260416-qcom_ice_power_and_clk_vote-v5-2-5ccf5d7e2846@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ice.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index c467b55b41744e..05055e097ff8fb 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -95,6 +95,7 @@ struct qcom_ice { + void __iomem *base; + + struct clk *core_clk; ++ struct clk *iface_clk; + bool use_hwkm; + bool hwkm_init_complete; + }; +@@ -278,8 +279,13 @@ int qcom_ice_resume(struct qcom_ice *ice) + + err = clk_prepare_enable(ice->core_clk); + if (err) { +- dev_err(dev, "failed to enable core clock (%d)\n", +- err); ++ dev_err(dev, "Failed to enable core clock: %d\n", err); ++ return err; ++ } ++ ++ err = clk_prepare_enable(ice->iface_clk); ++ if (err) { ++ dev_err(dev, "Failed to enable iface clock: %d\n", err); + return err; + } + qcom_ice_hwkm_init(ice); +@@ -289,6 +295,7 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume); + + int qcom_ice_suspend(struct qcom_ice *ice) + { ++ clk_disable_unprepare(ice->iface_clk); + clk_disable_unprepare(ice->core_clk); + ice->hwkm_init_complete = false; + +@@ -544,11 +551,17 @@ static struct qcom_ice *qcom_ice_create(struct device *dev, + engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk"); + if (!engine->core_clk) + engine->core_clk = devm_clk_get_optional_enabled(dev, "ice"); ++ if (!engine->core_clk) ++ engine->core_clk = devm_clk_get_optional_enabled(dev, "core"); + if (!engine->core_clk) + engine->core_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(engine->core_clk)) + return ERR_CAST(engine->core_clk); + ++ engine->iface_clk = devm_clk_get_optional_enabled(dev, "iface"); ++ if (IS_ERR(engine->iface_clk)) ++ return ERR_CAST(engine->iface_clk); ++ + if (!qcom_ice_check_supported(engine)) + return ERR_PTR(-EOPNOTSUPP); + +-- +2.53.0 + diff --git a/queue-6.18/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch b/queue-6.18/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch new file mode 100644 index 0000000000..806f71dd44 --- /dev/null +++ b/queue-6.18/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch @@ -0,0 +1,44 @@ +From 16c1f6d52fabb42a66fd20ba426e0ff3ae230527 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 May 2026 19:22:18 +0530 +Subject: soc: qcom: ice: Return -ENODEV if the ICE platform device is not + found + +From: Manivannan Sadhasivam + +[ Upstream commit 5a4dc805a80e6fe303d6a4748cd451ea15987ffd ] + +By the time the consumer driver calls devm_of_qcom_ice_get(), all the +platform devices for ICE nodes would've been created by +of_platform_default_populate(). + +So for the absence of any platform device, -ENODEV should not returned, not +-EPROBE_DEFER. + +Fixes: 2afbf43a4aec ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver") +Tested-by: Sumit Garg # OP-TEE as TZ +Acked-by: Sumit Garg +Signed-off-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-2-2a595382185b@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ice.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index 05055e097ff8fb..ba53aea828ba76 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -622,7 +622,7 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev) + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_err(dev, "Cannot find device node %s\n", node->name); +- return ERR_PTR(-EPROBE_DEFER); ++ return ERR_PTR(-ENODEV); + } + + ice = platform_get_drvdata(pdev); +-- +2.53.0 + diff --git a/queue-6.18/tee-fix-tee_ioctl_object_invoke_arg-padding.patch b/queue-6.18/tee-fix-tee_ioctl_object_invoke_arg-padding.patch new file mode 100644 index 0000000000..f4cd84ee00 --- /dev/null +++ b/queue-6.18/tee-fix-tee_ioctl_object_invoke_arg-padding.patch @@ -0,0 +1,44 @@ +From 5d030a4a8344f340e5d04a5d0b30e2b857eb6474 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 11:17:23 +0100 +Subject: tee: fix tee_ioctl_object_invoke_arg padding + +From: Arnd Bergmann + +[ Upstream commit c15d7a2a11ea055bcecc0b538ae8ba79475637f9 ] + +The tee_ioctl_object_invoke_arg structure has padding on some +architectures but not on x86-32 and a few others: + +include/linux/tee.h:474:32: error: padding struct to align 'params' [-Werror=padded] + +I expect that all current users of this are on architectures that do +have implicit padding here (arm64, arm, x86, riscv), so make the padding +explicit in order to avoid surprises if this later gets used elsewhere. + +Fixes: d5b8b0fa1775 ("tee: add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF") +Signed-off-by: Arnd Bergmann +Reviewed-by: Jens Wiklander +Tested-by: Harshal Dev +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + include/uapi/linux/tee.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h +index cab5cadca8ef99..5203977ed35d1d 100644 +--- a/include/uapi/linux/tee.h ++++ b/include/uapi/linux/tee.h +@@ -470,6 +470,7 @@ struct tee_ioctl_object_invoke_arg { + __u32 op; + __u32 ret; + __u32 num_params; ++ __u32 :32; + /* num_params tells the actual number of element in params */ + struct tee_ioctl_param params[]; + }; +-- +2.53.0 + diff --git a/queue-6.18/tee-optee-prevent-use-after-free-when-the-client-exi.patch b/queue-6.18/tee-optee-prevent-use-after-free-when-the-client-exi.patch new file mode 100644 index 0000000000..8f3e3b463d --- /dev/null +++ b/queue-6.18/tee-optee-prevent-use-after-free-when-the-client-exi.patch @@ -0,0 +1,287 @@ +From 947a5698797496b8de1a3c791f32d7ed81a53897 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:24:06 -0800 +Subject: tee: optee: prevent use-after-free when the client exits before the + supplicant + +From: Amirreza Zarrabi + +[ Upstream commit 387a926ee166814611acecb960207fe2f3c4fd3e ] + +Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the +client wait as killable so it can be interrupted during shutdown or +after a supplicant crash. This changes the original lifetime expectations: +the client task can now terminate while the supplicant is still processing +its request. + +If the client exits first it removes the request from its queue and +kfree()s it, while the request ID remains in supp->idr. A subsequent +lookup on the supplicant path then dereferences freed memory, leading to +a use-after-free. + +Serialise access to the request with supp->mutex: + + * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while + looking up and touching the request. + * Let optee_supp_thrd_req() notice that the client has terminated and + signal optee_supp_send() accordingly. + +With these changes the request cannot be freed while the supplicant still +has a reference, eliminating the race. + +Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") +Signed-off-by: Amirreza Zarrabi +Tested-by: Ox Yeh +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/supp.c | 107 +++++++++++++++++++++++++++------------ + 1 file changed, 74 insertions(+), 33 deletions(-) + +diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c +index d0f397c9024201..2386bbd38ce78b 100644 +--- a/drivers/tee/optee/supp.c ++++ b/drivers/tee/optee/supp.c +@@ -10,7 +10,11 @@ + struct optee_supp_req { + struct list_head link; + ++ int id; ++ + bool in_queue; ++ bool processed; ++ + u32 func; + u32 ret; + size_t num_params; +@@ -19,6 +23,9 @@ struct optee_supp_req { + struct completion c; + }; + ++/* It is temporary request used for revoked pending request in supp->idr. */ ++#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) ++ + void optee_supp_init(struct optee_supp *supp) + { + memset(supp, 0, sizeof(*supp)); +@@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) + { + int id; + struct optee_supp_req *req; +- struct optee_supp_req *req_tmp; + + mutex_lock(&supp->mutex); + +- /* Abort all request retrieved by supplicant */ ++ /* Abort all request */ + idr_for_each_entry(&supp->idr, req, id) { + idr_remove(&supp->idr, id); +- req->ret = TEEC_ERROR_COMMUNICATION; +- complete(&req->c); +- } ++ /* Skip if request was already marked invalid */ ++ if (IS_ERR(req)) ++ continue; + +- /* Abort all queued requests */ +- list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { +- list_del(&req->link); +- req->in_queue = false; ++ /* For queued requests where supplicant has not seen it */ ++ if (req->in_queue) { ++ list_del(&req->link); ++ req->in_queue = false; ++ } ++ ++ req->processed = true; + req->ret = TEEC_ERROR_COMMUNICATION; + complete(&req->c); + } +@@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + + /* Insert the request in the request list */ + mutex_lock(&supp->mutex); ++ req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); ++ if (req->id < 0) { ++ mutex_unlock(&supp->mutex); ++ kfree(req); ++ return TEEC_ERROR_OUT_OF_MEMORY; ++ } ++ + list_add_tail(&req->link, &supp->reqs); + req->in_queue = true; ++ req->processed = false; + mutex_unlock(&supp->mutex); + + /* Tell an eventual waiter there's a new request */ +@@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + if (wait_for_completion_killable(&req->c)) { + mutex_lock(&supp->mutex); + if (req->in_queue) { ++ /* Supplicant has not seen this request yet. */ ++ idr_remove(&supp->idr, req->id); + list_del(&req->link); + req->in_queue = false; ++ ++ ret = TEEC_ERROR_COMMUNICATION; ++ } else if (req->processed) { ++ /* ++ * Supplicant has processed this request. Ignore the ++ * kill signal for now and submit the result. req is not ++ * in supp->reqs (removed by supp_pop_entry()) nor in ++ * supp->idr (removed by supp_pop_req()). ++ */ ++ ret = req->ret; ++ } else { ++ /* ++ * Supplicant is in the middle of processing this ++ * request. Replace req with INVALID_REQ_PTR so that ++ * the ID remains busy, causing optee_supp_send() to ++ * fail on the next call to supp_pop_req() with this ID. ++ */ ++ idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); ++ ret = TEEC_ERROR_COMMUNICATION; + } ++ + mutex_unlock(&supp->mutex); +- req->ret = TEEC_ERROR_COMMUNICATION; ++ } else { ++ ret = req->ret; + } + +- ret = req->ret; + kfree(req); + + return ret; + } + + static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, +- int num_params, int *id) ++ int num_params) + { + struct optee_supp_req *req; + +@@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, + return ERR_PTR(-EINVAL); + } + +- *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); +- if (*id < 0) +- return ERR_PTR(-ENOMEM); +- + list_del(&req->link); + req->in_queue = false; + +@@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + struct optee_supp_req *req = NULL; +- int id; + size_t num_meta; + int rc; + +@@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + + while (true) { + mutex_lock(&supp->mutex); +- req = supp_pop_entry(supp, *num_params - num_meta, &id); ++ req = supp_pop_entry(supp, *num_params - num_meta); ++ if (req) ++ break; /* Keep mutex held. */ + mutex_unlock(&supp->mutex); + +- if (req) { +- if (IS_ERR(req)) +- return PTR_ERR(req); +- break; +- } +- + /* + * If we didn't get a request we'll block in + * wait_for_completion() to avoid needless spinning. +@@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + return -ERESTARTSYS; + } + ++ /* supp->mutex held and req != NULL. */ ++ ++ if (IS_ERR(req)) { ++ mutex_unlock(&supp->mutex); ++ return PTR_ERR(req); ++ } ++ + if (num_meta) { + /* + * tee-supplicant support meta parameters -> requsts can be +@@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + */ + param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; +- param->u.value.a = id; ++ param->u.value.a = req->id; + param->u.value.b = 0; + param->u.value.c = 0; + } else { +- mutex_lock(&supp->mutex); +- supp->req_id = id; +- mutex_unlock(&supp->mutex); ++ supp->req_id = req->id; + } + + *func = req->func; +@@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + ++ mutex_unlock(&supp->mutex); + return 0; + } + +@@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, + if (!req) + return ERR_PTR(-ENOENT); + ++ /* optee_supp_thrd_req() already returned to optee. */ ++ if (IS_ERR(req)) ++ goto failed_req; ++ + if ((num_params - nm) != req->num_params) + return ERR_PTR(-EINVAL); + ++ *num_meta = nm; ++failed_req: + idr_remove(&supp->idr, id); + supp->req_id = -1; +- *num_meta = nm; + + return req; + } +@@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + + mutex_lock(&supp->mutex); + req = supp_pop_req(supp, num_params, param, &num_meta); +- mutex_unlock(&supp->mutex); +- + if (IS_ERR(req)) { +- /* Something is wrong, let supplicant restart. */ ++ mutex_unlock(&supp->mutex); ++ /* Something is wrong, let supplicant handel it. */ + return PTR_ERR(req); + } + +@@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + } + } + req->ret = ret; +- ++ req->processed = true; + /* Let the requesting thread continue */ + complete(&req->c); ++ mutex_unlock(&supp->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch b/queue-6.18/tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch new file mode 100644 index 0000000000..d2f68d6f79 --- /dev/null +++ b/queue-6.18/tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch @@ -0,0 +1,47 @@ +From c56c0c17c2ae653224443f1ee988eba441ac8b83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 09:05:28 +0700 +Subject: tee: qcomtee: add missing va_end in early return + qcomtee_object_user_init() + +From: Robertus Diawan Chris + +[ Upstream commit 471c18323dfdfe7844e193b896a9267ae23a1026 ] + +qcomtee_object_user_init() is a variadic function and when the function +return because there's no dispatch callback in QCOMTEE_OBJECT_TYPE_CB +case, there's no va_end to cleanup "ap" object initialized by va_start +and that can cause undefined behavior. So make sure to use va_end before +returning the error code when there's no dispatch callback. + +This is reported by Coverity Scan as "Missing varargs init or cleanup". + +Fixes: d6e290837e50 ("tee: add Qualcomm TEE driver") +Signed-off-by: Robertus Diawan Chris +Reviewed-by: Amirreza Zarrabi +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/qcomtee/core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c +index ecd04403591cf9..10717434275b1b 100644 +--- a/drivers/tee/qcomtee/core.c ++++ b/drivers/tee/qcomtee/core.c +@@ -306,8 +306,10 @@ int qcomtee_object_user_init(struct qcomtee_object *object, + break; + case QCOMTEE_OBJECT_TYPE_CB: + object->ops = ops; +- if (!object->ops->dispatch) +- return -EINVAL; ++ if (!object->ops->dispatch) { ++ ret = -EINVAL; ++ break; ++ } + + /* If failed, "no-name". */ + object->name = kvasprintf_const(GFP_KERNEL, fmt, ap); +-- +2.53.0 + diff --git a/queue-6.18/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch b/queue-6.18/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch new file mode 100644 index 0000000000..e52ba46d80 --- /dev/null +++ b/queue-6.18/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch @@ -0,0 +1,55 @@ +From 8b81d60d52fa8488c61da8f97ec7de19d85c3e65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:37 -0700 +Subject: vxlan: vnifilter: fix spurious notification on VNI update + +From: Andy Roulin + +[ Upstream commit 84683b5b60c7274e2c8f7f413d39d78d3db5540f ] + +When a VNI is re-added with the same attributes (e.g. same group or no +group), vxlan_vni_update() sends a spurious RTM_NEWTUNNEL notification +even though nothing changed. + +The bug is that 'if (changed)' tests whether the pointer is non-NULL, +not the bool value it points to. Since every caller passes a valid +pointer, the condition is always true and the notification fires +unconditionally. + +Fix by dereferencing the pointer: 'if (*changed)'. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 + # bridge vni add vni 1000 dev vxlan100 # spurious notification + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-3-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 43c70c395b58e5..215e82876662de 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -661,7 +661,7 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan, + if (ret) + return ret; + +- if (changed) ++ if (*changed) + vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/vxlan-vnifilter-send-notification-on-vni-add.patch b/queue-6.18/vxlan-vnifilter-send-notification-on-vni-add.patch new file mode 100644 index 0000000000..ca178d9730 --- /dev/null +++ b/queue-6.18/vxlan-vnifilter-send-notification-on-vni-add.patch @@ -0,0 +1,69 @@ +From b2d790101ee7097912598ceaaaff98c64fe391b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:36 -0700 +Subject: vxlan: vnifilter: send notification on VNI add + +From: Andy Roulin + +[ Upstream commit aa6ca1c5c338907817374b59f7551fd855a88754 ] + +When a new VNI is added to a vxlan device with vnifilter enabled, +no RTM_NEWTUNNEL notification is sent to userspace. This means +'bridge monitor vni' never shows VNI add events, even though +VNI delete events are reported correctly. + +The bug is in vxlan_vni_add(), where the notification is guarded by +'if (changed)'. The 'changed' flag is set by vxlan_vni_update_group() +only when the multicast group or remote IP is modified, but for a +new VNI added without a group (e.g. in L3 VxLAN interface scenarios), +the function returns early without setting changed=true. Since this +is a new VNI, the notification should be sent unconditionally. + +The notification is not guarded by the return value of +vxlan_vni_update_group() because, at this point, the VNI has already +been inserted into the hash table and list with no rollback on error. +The VNI will be visible in 'bridge vni show' regardless, so userspace +should be informed. This is consistent with vxlan_vni_del() which also +notifies unconditionally. + +The 'if (changed)' guard remains correct in vxlan_vni_update(), which +handles the case where a VNI already exists and is being re-added -- +there, we only want to notify if the group/remote actually changed. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 # no notification + # bridge vni delete vni 1000 dev vxlan100 # notification received + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Reported-by: Chirag Shah +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-2-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index adc89e651e27c8..43c70c395b58e5 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -759,8 +759,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, + err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed, + extack); + +- if (changed) +- vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); ++ vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return err; + } +-- +2.53.0 + diff --git a/queue-6.18/wifi-fix-leak-if-split-6-ghz-scanning-fails.patch b/queue-6.18/wifi-fix-leak-if-split-6-ghz-scanning-fails.patch new file mode 100644 index 0000000000..a8f2d9df2f --- /dev/null +++ b/queue-6.18/wifi-fix-leak-if-split-6-ghz-scanning-fails.patch @@ -0,0 +1,79 @@ +From e5e32608acb284f934201381a8a5dcc97316b087 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:41:56 +0300 +Subject: wifi: fix leak if split 6 GHz scanning fails + +From: Fedor Pchelkin + +[ Upstream commit e8694f7cc29287e843648d1075177b9a2000d957 ] + +rdev->int_scan_req is leaked if cfg80211_scan() fails. Note that it's +supposed to be released at ___cfg80211_scan_done() but this doesn't happen +as rdev->scan_req is NULL at that point, too, leading to the early return +from the freeing function. + +unreferenced object 0xffff8881161d0800 (size 512): + comm "wpa_supplicant", pid 379, jiffies 4294749765 + hex dump (first 32 bytes): + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 00 00 00 00 00 00 00 00 f0 81 13 16 81 88 ff ff ................ + backtrace (crc c867fdb6): + kmemleak_alloc+0x89/0x90 + __kmalloc_noprof+0x2fd/0x410 + cfg80211_scan+0x133/0x730 + nl80211_trigger_scan+0xc69/0x1cc0 + genl_family_rcv_msg_doit+0x204/0x2f0 + genl_rcv_msg+0x431/0x6b0 + netlink_rcv_skb+0x143/0x3f0 + genl_rcv+0x27/0x40 + netlink_unicast+0x4f6/0x820 + netlink_sendmsg+0x797/0xce0 + __sock_sendmsg+0xc4/0x160 + ____sys_sendmsg+0x5e4/0x890 + ___sys_sendmsg+0xf8/0x180 + __sys_sendmsg+0x136/0x1e0 + __x64_sys_sendmsg+0x76/0xc0 + x64_sys_call+0x13f0/0x17d0 + +Found by Linux Verification Center (linuxtesting.org). + +Fixes: c8cb5b854b40 ("nl80211/cfg80211: support 6 GHz scanning") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260601094157.92703-1-pchelkin@ispras.ru +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/scan.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 4a1cdfc3221ca4..199c63de01457a 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -1071,6 +1071,7 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev) + struct cfg80211_scan_request_int *request; + struct cfg80211_scan_request_int *rdev_req = rdev->scan_req; + u32 n_channels = 0, idx, i; ++ int err; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ)) { + rdev_req->req.first_part = true; +@@ -1101,8 +1102,14 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev) + + rdev_req->req.scan_6ghz = false; + rdev_req->req.first_part = true; ++ err = rdev_scan(rdev, request); ++ if (err) { ++ kfree(request); ++ return err; ++ } ++ + rdev->int_scan_req = request; +- return rdev_scan(rdev, request); ++ return 0; + } + + void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, +-- +2.53.0 + diff --git a/queue-6.18/wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch b/queue-6.18/wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch new file mode 100644 index 0000000000..31accf2407 --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch @@ -0,0 +1,45 @@ +From 1aee8ce3f32a35ba2cfaa3002964756929e5a3aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 08:57:05 +0300 +Subject: wifi: iwlwifi: mvm: don't support the reset handshake for old + firmwares + +From: Emmanuel Grumbach + +[ Upstream commit 0eaa1f245ac03ed0c6394159360532726f666811 ] + +-77.ucode doesn't contain the fixes for this flow it seems. +Don't use the firmware reset handshake even if the firmware claims +support for it. + +Fixes: 906d4eb84408 ("iwlwifi: support firmware reset handshake") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220600 +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260529085453.9307b81d9b02.I21bba9e649f4cd0e35d3ea6cd97a03258be5832f@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +index 5ebd046371f50d..8e6913c7712f09 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +@@ -1416,6 +1416,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE); + ++ /* Those firmware versions claim to support the fw_reset_handshake ++ * but they are buggy. ++ */ ++ if (IWL_UCODE_MAJOR(mvm->fw->ucode_ver) <= 77) ++ trans->conf.fw_reset_handshake = false; ++ + trans->conf.queue_alloc_cmd_ver = + iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(DATA_PATH_GROUP, +-- +2.53.0 + diff --git a/queue-6.18/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch b/queue-6.18/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch new file mode 100644 index 0000000000..fadb3fe30c --- /dev/null +++ b/queue-6.18/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch @@ -0,0 +1,61 @@ +From 13b91167008bcdbf88a5bf11f440ac2e5e80f157 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 06:47:21 +0530 +Subject: wifi: mac80211: limit injected antenna index in + ieee80211_parse_tx_radiotap + +From: Deepanshu Kartikey + +[ Upstream commit 6c0cf89f36ac0c0fd8687a4ccdce2efb23a9c663 ] + +When parsing the radiotap header of an injected frame, +ieee80211_parse_tx_radiotap() uses the IEEE80211_RADIOTAP_ANTENNA value +directly as a shift count: + + info->control.antennas |= BIT(*iterator.this_arg); + +*iterator.this_arg is an 8-bit value taken straight from the frame +supplied by userspace, so BIT() can be asked to shift by up to 255. That +is undefined behaviour on the unsigned long and is reported by UBSAN: + + UBSAN: shift-out-of-bounds in net/mac80211/tx.c:2174:30 + shift exponent 235 is too large for 64-bit type 'unsigned long' + Call Trace: + ieee80211_parse_tx_radiotap+0xadb/0x1950 net/mac80211/tx.c:2174 + ieee80211_monitor_start_xmit+0xb1f/0x1250 net/mac80211/tx.c:2451 + ... + packet_sendmsg+0x3eb6/0x50f0 net/packet/af_packet.c:3109 + +info->control.antennas is a 2-bit bitmap (u8 antennas:2), so only antenna +indices 0 and 1 can ever be represented. Ignore any larger value instead +of shifting out of bounds. + +Reported-by: syzbot+8e0622f6d9446420271f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8e0622f6d9446420271f +Fixes: ef246a1480cc ("wifi: mac80211: support antenna control in injection") +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20260531011721.102941-1-kartikey406@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/tx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 2f830001b0cd6d..98f0a275b60c3a 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -2169,7 +2169,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, + + case IEEE80211_RADIOTAP_ANTENNA: + /* this can appear multiple times, keep a bitmap */ +- info->control.antennas |= BIT(*iterator.this_arg); ++ /* control.antennas is only a 2-bit bitmap */ ++ if (*iterator.this_arg < 2) ++ info->control.antennas |= BIT(*iterator.this_arg); + break; + + case IEEE80211_RADIOTAP_DATA_RETRIES: +-- +2.53.0 + diff --git a/queue-6.18/xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch b/queue-6.18/xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch new file mode 100644 index 0000000000..e014e1ebd0 --- /dev/null +++ b/queue-6.18/xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch @@ -0,0 +1,73 @@ +From 1a07021e7974e804927ab6d0c8b8b36ccf1c60f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 30 May 2026 12:26:30 +0800 +Subject: xsk: cache csum_start/csum_offset to fix TOCTOU in xsk_skb_metadata() + +From: Jason Xing + +[ Upstream commit 22ba97ea9cc1f63a0d0244fae38057ed452b6ac7 ] + +The TX metadata area resides in the UMEM buffer which is memory-mapped +and concurrently writable by userspace. In xsk_skb_metadata(), +csum_start and csum_offset are read from shared memory for bounds +validation, then read again for skb assignment. A malicious userspace +application can race to overwrite these values between the two reads, +bypassing the bounds check and causing out-of-bounds memory access +during checksum computation in the transmit path. + +Fix this by reading csum_start and csum_offset into local variables +once, then using the local copies for both validation and assignment. + +Note that other metadata fields (flags, launch_time) and the cached +csum fields may be mutually inconsistent due to concurrent userspace +writes, but this is benign: the only security-critical invariant is +that each field's validated value is the same one used, which local +caching guarantees. + +Closes: https://lore.kernel.org/all/20260503200927.73EA1C2BCB4@smtp.kernel.org/ +Reviewed-by: Maciej Fijalkowski +Signed-off-by: Jason Xing +Acked-by: Stanislav Fomichev +Fixes: 48eb03dd2630 ("xsk: Add TX timestamp and TX checksum offload support") +Link: https://patch.msgid.link/20260530042630.80626-1-kerneljasonxing@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/xdp/xsk.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c +index 259ad9a3abcc42..9e0a486d54fb33 100644 +--- a/net/xdp/xsk.c ++++ b/net/xdp/xsk.c +@@ -685,6 +685,7 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer, + u32 hr) + { + struct xsk_tx_metadata *meta = NULL; ++ u16 csum_start, csum_offset; + + if (unlikely(pool->tx_metadata_len == 0)) + return -EINVAL; +@@ -694,13 +695,15 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer, + return -EINVAL; + + if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) { +- if (unlikely(meta->request.csum_start + +- meta->request.csum_offset + ++ csum_start = READ_ONCE(meta->request.csum_start); ++ csum_offset = READ_ONCE(meta->request.csum_offset); ++ ++ if (unlikely(csum_start + csum_offset + + sizeof(__sum16) > desc->len)) + return -EINVAL; + +- skb->csum_start = hr + meta->request.csum_start; +- skb->csum_offset = meta->request.csum_offset; ++ skb->csum_start = hr + csum_start; ++ skb->csum_offset = csum_offset; + skb->ip_summed = CHECKSUM_PARTIAL; + + if (unlikely(pool->tx_sw_csum)) { +-- +2.53.0 + diff --git a/queue-6.6/6lowpan-fix-off-by-one-in-multicast-context-address-.patch b/queue-6.6/6lowpan-fix-off-by-one-in-multicast-context-address-.patch new file mode 100644 index 0000000000..fdeda97d6b --- /dev/null +++ b/queue-6.6/6lowpan-fix-off-by-one-in-multicast-context-address-.patch @@ -0,0 +1,67 @@ +From 5682355411236e1cef8ba3886b10cef19c075d8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:18:01 +0800 +Subject: 6lowpan: fix off-by-one in multicast context address compression + +From: Yizhou Zhao + +[ Upstream commit 2a58899d11009bffc7b4b32a571858f381121837 ] + +The second memcpy in lowpan_iphc_mcast_ctx_addr_compress() uses +&data[1] as destination and &ipaddr->s6_addr[11] as source, but +both should be offset by one: &data[2] and &ipaddr->s6_addr[12] +respectively. + +This off-by-one has two consequences: +1. data[1] is overwritten with s6_addr[11], corrupting the RIID + field in the compressed multicast address +2. data[5] is never written, so uninitialized kernel stack memory + is transmitted over the network via lowpan_push_hc_data(), + leaking kernel stack contents + +The correct inline data layout must match what the decompression +function lowpan_uncompress_multicast_ctx_daddr() expects: + data[0..1] = s6_addr[1..2] (flags/scope + RIID) + data[2..5] = s6_addr[12..15] (group ID) + +Also zero-initialize the data array as a defensive measure against +similar bugs in the future. + +Fixes: 5609c185f24d ("6lowpan: iphc: add support for stateful compression") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Acked-by: Alexander Aring +Link: https://patch.msgid.link/20260527081806.42747-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/6lowpan/iphc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c +index e116d308a8df6d..37eaff3f7b6940 100644 +--- a/net/6lowpan/iphc.c ++++ b/net/6lowpan/iphc.c +@@ -1086,12 +1086,12 @@ static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, + const struct lowpan_iphc_ctx *ctx, + const struct in6_addr *ipaddr) + { +- u8 data[6]; ++ u8 data[6] = {}; + + /* flags/scope, reserved (RIID) */ + memcpy(data, &ipaddr->s6_addr[1], 2); + /* group ID */ +- memcpy(&data[1], &ipaddr->s6_addr[11], 4); ++ memcpy(&data[2], &ipaddr->s6_addr[12], 4); + lowpan_push_hc_data(hc_ptr, data, 6); + + return LOWPAN_IPHC_DAM_00; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch b/queue-6.6/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch new file mode 100644 index 0000000000..97ac696d6d --- /dev/null +++ b/queue-6.6/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch @@ -0,0 +1,71 @@ +From 6050dac57415a917605ae0d3141de360b0c286e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:39:53 +0800 +Subject: Bluetooth: bnep: fix incorrect length parsing in bnep_rx_frame() + extension handling + +From: Dudu Lu + +[ Upstream commit 72b8deccff17a7644e0367e1aaf1a36cfb014324 ] + +In bnep_rx_frame(), the BNEP_FILTER_NET_TYPE_SET and +BNEP_FILTER_MULTI_ADDR_SET extension header parsing has two bugs: + +1) The 2-byte length field is read with *(u16 *)(skb->data + 1), which + performs a native-endian read. The BNEP protocol specifies this field + in big-endian (network byte order), and the same file correctly uses + get_unaligned_be16() for the identical fields in + bnep_ctrl_set_netfilter() and bnep_ctrl_set_mcfilter(). + +2) The length is multiplied by 2, but unlike BNEP_SETUP_CONN_REQ where + the length byte counts UUID pairs (requiring * 2 for two UUIDs per + entry), the filter extension length field already represents the total + data size in bytes. This is confirmed by bnep_ctrl_set_netfilter() + which reads the same field as a byte count and divides by 4 to get + the number of filter entries. + + The bogus * 2 means skb_pull advances twice as far as it should, + either dropping valid data from the next header or causing the pull + to fail entirely when the doubled length exceeds the remaining skb. + +Fix by splitting the pull into two steps: first use skb_pull_data() to +safely pull and validate the 3-byte fixed header (ctrl type + length), +then pull the variable-length data using the properly decoded length. + +Fixes: bf8b9a9cb77b ("Bluetooth: bnep: Add support to extended headers of control frames") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index e125afe573fcf2..9d804b08de88e0 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -330,11 +330,18 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + goto badframe; + break; + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: +- /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */ +- if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2)) ++ case BNEP_FILTER_NET_TYPE_SET: { ++ u8 *hdr; ++ ++ /* Pull ctrl type (1 b) + len (2 b) */ ++ hdr = skb_pull_data(skb, 3); ++ if (!hdr) ++ goto badframe; ++ /* Pull data (len bytes); length is big-endian */ ++ if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) + goto badframe; + break; ++ } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-bnep-reject-short-frames-before-parsing.patch b/queue-6.6/bluetooth-bnep-reject-short-frames-before-parsing.patch new file mode 100644 index 0000000000..1731314080 --- /dev/null +++ b/queue-6.6/bluetooth-bnep-reject-short-frames-before-parsing.patch @@ -0,0 +1,170 @@ +From 8435ec5230ab97655b7182aaee9256f5414eb9aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 11:22:09 +0800 +Subject: Bluetooth: bnep: reject short frames before parsing + +From: Zhang Cen + +[ Upstream commit 6770d3a8acdf9151769180cc3710346c4cfbe6f0 ] + +A BNEP peer can send a short BNEP SDU. bnep_rx_frame() reads the +packet type byte immediately and, for control packets, reads the control +opcode and setup UUID-size byte before proving that those bytes are +present. bnep_rx_control() also dereferences the control opcode without +rejecting an empty control payload. + +Use skb_pull_data() for the fixed fields in bnep_rx_frame() so a NULL +return gates each dereference. Split the control handler so the frame +path can pass an opcode that has already been pulled, and keep the +byte-buffer wrapper for extension control payloads. + +For BNEP_SETUP_CONN_REQ, name the UUID-size byte before pulling the +setup payload. struct bnep_setup_conn_req carries destination and source +service UUIDs after that byte, each uuid_size bytes, so the parser now +documents that tuple explicitly instead of leaving the pull length as an +opaque multiplication. + +Validation reproduced this kernel report: +KASAN slab-out-of-bounds in bnep_rx_frame.isra.0+0x130c/0x1790 +The buggy address belongs to the object at ffff88800c0f7908 which belongs +to the cache kmalloc-8 of size 8 +The buggy address is located 0 bytes to the right of allocated 1-byte +region [ffff88800c0f7908, ffff88800c0f7909) +Read of size 1 +Call trace: + dump_stack_lvl+0xb3/0x140 (?:?) + print_address_description+0x57/0x3a0 (?:?) + bnep_rx_frame+0x130c/0x1790 (net/bluetooth/bnep/core.c:306) + print_report+0xb9/0x2b0 (?:?) + __virt_addr_valid+0x1ba/0x3a0 (?:?) + srso_alias_return_thunk+0x5/0xfbef5 (?:?) + kasan_addr_to_slab+0x21/0x60 (?:?) + kasan_report+0xe0/0x110 (?:?) + process_one_work+0xfce/0x17e0 (kernel/workqueue.c:3200) + worker_thread+0x65c/0xe40 (?:?) + __kthread_parkme+0x184/0x230 (?:?) + kthread+0x35e/0x470 (?:?) + _raw_spin_unlock_irq+0x28/0x50 (?:?) + ret_from_fork+0x586/0x870 (?:?) + __switch_to+0x74f/0xdc0 (?:?) + ret_from_fork_asm+0x1a/0x30 (?:?) + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 57 ++++++++++++++++++++++++--------------- + 1 file changed, 36 insertions(+), 21 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index 9d804b08de88e0..45d0f84652fc60 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -206,14 +206,11 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) + return 0; + } + +-static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++static int bnep_rx_control_cmd(struct bnep_session *s, u8 cmd, void *data, ++ int len) + { +- u8 cmd = *(u8 *)data; + int err = 0; + +- data++; +- len--; +- + switch (cmd) { + case BNEP_CMD_NOT_UNDERSTOOD: + case BNEP_SETUP_CONN_RSP: +@@ -254,6 +251,14 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) + return err; + } + ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ if (len < 1) ++ return -EILSEQ; ++ ++ return bnep_rx_control_cmd(s, *(u8 *)data, data + 1, len - 1); ++} ++ + static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) + { + struct bnep_ext_hdr *h; +@@ -299,19 +304,26 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + { + struct net_device *dev = s->dev; + struct sk_buff *nskb; ++ u8 *data; + u8 type, ctrl_type; + + dev->stats.rx_bytes += skb->len; + +- type = *(u8 *) skb->data; +- skb_pull(skb, 1); +- ctrl_type = *(u8 *)skb->data; ++ data = skb_pull_data(skb, sizeof(type)); ++ if (!data) ++ goto badframe; ++ type = *data; + + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) + goto badframe; + + if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { +- if (bnep_rx_control(s, skb->data, skb->len) < 0) { ++ data = skb_pull_data(skb, sizeof(ctrl_type)); ++ if (!data) ++ goto badframe; ++ ctrl_type = *data; ++ ++ if (bnep_rx_control_cmd(s, ctrl_type, skb->data, skb->len) < 0) { + dev->stats.tx_errors++; + kfree_skb(skb); + return 0; +@@ -324,24 +336,27 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + + /* Verify and pull ctrl message since it's already processed */ + switch (ctrl_type) { +- case BNEP_SETUP_CONN_REQ: +- /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */ +- if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2)) ++ case BNEP_SETUP_CONN_REQ: { ++ u8 uuid_size; ++ ++ /* Pull uuid_size and the dst/src service UUIDs. */ ++ data = skb_pull_data(skb, sizeof(uuid_size)); ++ if (!data) ++ goto badframe; ++ uuid_size = *data; ++ if (!skb_pull(skb, uuid_size + uuid_size)) + goto badframe; + break; ++ } + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: { +- u8 *hdr; +- +- /* Pull ctrl type (1 b) + len (2 b) */ +- hdr = skb_pull_data(skb, 3); +- if (!hdr) ++ case BNEP_FILTER_NET_TYPE_SET: ++ /* Pull: len (2 b), data (len bytes) */ ++ data = skb_pull_data(skb, sizeof(u16)); ++ if (!data) + goto badframe; +- /* Pull data (len bytes); length is big-endian */ +- if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) ++ if (!skb_pull(skb, get_unaligned_be16(data))) + goto badframe; + break; +- } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch b/queue-6.6/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch new file mode 100644 index 0000000000..08781dbd18 --- /dev/null +++ b/queue-6.6/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch @@ -0,0 +1,58 @@ +From 92509b57f8fcaaaebebba4ee24070e73ed0dfcf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 08:54:26 +0530 +Subject: Bluetooth: fix memory leak in error path of hci_alloc_dev() + +From: Bharath Reddy + +[ Upstream commit 37b3009bf5976e8ab77c8b9a9bc3bbd7ff49e37f ] + +Early failures in Bluetooth HCI UART configuration leak SRCU percpu +memory. + +When device initialization fails before hci_register_dev() completes, +the HCI_UNREGISTER flag is never set. As a result, when the device +reference count reaches zero, bt_host_release() evaluates this flag as +false and falls back to a direct kfree(hdev). + +Because hci_release_dev() is bypassed, the SRCU struct initialized +early in hci_alloc_dev() is never cleaned up, resulting in a leak of +percpu memory. + +Fix the leak by explicitly calling cleanup_srcu_struct() in the +fallback (unregistered) branch of bt_host_release() before freeing +the device. + +Reported-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=535ecc844591e50588a5 +Tested-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Fixes: 1d6123102e9f ("Bluetooth: hci_core: Fix use-after-free in vhci_flush()") +Signed-off-by: Bharath Reddy +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sysfs.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c +index 4b54dbbf0729a3..60350c6723cb76 100644 +--- a/net/bluetooth/hci_sysfs.c ++++ b/net/bluetooth/hci_sysfs.c +@@ -83,10 +83,12 @@ static void bt_host_release(struct device *dev) + { + struct hci_dev *hdev = to_hci_dev(dev); + +- if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) ++ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + hci_release_dev(hdev); +- else ++ } else { ++ cleanup_srcu_struct(&hdev->srcu); + kfree(hdev); ++ } + module_put(THIS_MODULE); + } + +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-mgmt-fix-backward-compatibility-with-users.patch b/queue-6.6/bluetooth-mgmt-fix-backward-compatibility-with-users.patch new file mode 100644 index 0000000000..1d1d9506a7 --- /dev/null +++ b/queue-6.6/bluetooth-mgmt-fix-backward-compatibility-with-users.patch @@ -0,0 +1,43 @@ +From bcb33b4138da75b06e790ecde0c60bedfab75d79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:48:34 -0400 +Subject: Bluetooth: MGMT: Fix backward compatibility with userspace + +From: Luiz Augusto von Dentz + +[ Upstream commit 149324fc762c2a7acef9c26790566f81f475e51f ] + +bluetoothd has a bug with makes it send extra bytes as part of +MGMT_OP_ADD_EXT_ADV_DATA which are now being checked to be the +exact the expected length, relax this so only when the expected +length is greater than the data length to cause an error since +that would result in accessing invalid memory, otherwise just +ignore the extra bytes. + +Link: https://lore.kernel.org/linux-bluetooth/20260602204749.210857-1-luiz.dentz@gmail.com/T/#u +Fixes: d3f7d17960ed ("Bluetooth: MGMT: validate Add Extended Advertising Data length") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 7b86e287b12d64..88f44cb36e241e 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -9144,8 +9144,9 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data, + + BT_DBG("%s", hdev->name); + +- expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len); +- if (expected_len != data_len) ++ expected_len = struct_size(cp, data, cp->adv_data_len + ++ cp->scan_rsp_len); ++ if (expected_len > data_len) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_INVALID_PARAMS); + +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch b/queue-6.6/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch new file mode 100644 index 0000000000..1886b866b7 --- /dev/null +++ b/queue-6.6/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch @@ -0,0 +1,73 @@ +From 0b303417a25df3b775bd2dbbae0cac87de5620ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 17:45:06 +0800 +Subject: Bluetooth: MGMT: validate advertising TLV before type checks + +From: Zhang Cen + +[ Upstream commit de23fb62259aa01d294f77238ae3b835eb674413 ] + +tlv_data_is_valid() reads each advertising data field length from +data[i], then inspects data[i + 1] for managed EIR types before +checking that the current field still fits inside the supplied buffer. + +A malformed field whose length byte is the last byte of the buffer can +therefore make the parser read one byte past the advertising data. + +KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING +request reached that path: + + BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid() + Read of size 1 + Call trace: + tlv_data_is_valid() + add_advertising() + hci_mgmt_cmd() + hci_sock_sendmsg() + +Move the existing element-length check before any type-octet inspection +so each non-empty element is proven to contain its type byte before the +parser looks at data[i + 1]. + +Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check") +Reviewed-by: Paul Menzel +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 4271fba3245ce1..7b86e287b12d64 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -8667,6 +8667,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (!cur_len) + continue; + ++ /* If the current field length would exceed the total data ++ * length, then it's invalid. ++ */ ++ if (i + cur_len >= len) ++ return false; ++ + if (data[i + 1] == EIR_FLAGS && + (!is_adv_data || flags_managed(adv_flags))) + return false; +@@ -8683,12 +8689,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (data[i + 1] == EIR_APPEARANCE && + appearance_managed(adv_flags)) + return false; +- +- /* If the current field length would exceed the total data +- * length, then it's invalid. +- */ +- if (i + cur_len >= len) +- return false; + } + + return true; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch b/queue-6.6/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch new file mode 100644 index 0000000000..8b52d0d9db --- /dev/null +++ b/queue-6.6/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch @@ -0,0 +1,126 @@ +From 8b7dc9c0c18f5cb26721dda836f9ca4707889105 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 15:56:41 +0800 +Subject: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() + +From: Zhang Cen + +[ Upstream commit 43c441edacf953b39517a44f5e5e10a93618b226 ] + +rfcomm_get_sock_by_channel() scans rfcomm_sk_list under the list lock, +but returns the selected listener after dropping that lock without +taking a reference. rfcomm_connect_ind() then locks the listener, +queues a child socket on it, and may notify it after unlocking it. + +The buggy scenario involves two paths, with each column showing the +order within that path: + +rfcomm_connect_ind(): listener close: + 1. Find parent in 1. close() enters + rfcomm_get_sock_by_channel() rfcomm_sock_release(). + 2. Drop rfcomm_sk_list.lock 2. rfcomm_sock_shutdown() + without pinning parent. closes the listener. + 3. Call lock_sock(parent) and 3. rfcomm_sock_kill() + bt_accept_enqueue(parent, unlinks and puts parent. + sk, true). + 4. Read parent flags and may 4. parent can be freed. + call sk_state_change(). + +If close wins the race, parent can be freed before +rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or the +deferred-setup callback. + +Take a reference on the listener before leaving rfcomm_sk_list.lock. +After lock_sock() succeeds, recheck that it is still in BT_LISTEN +before queueing a child, cache the deferred-setup bit while the parent +is locked, and drop the reference after the last parent use. + +KASAN reported a slab-use-after-free in lock_sock_nested() from +rfcomm_connect_ind(), with the freeing stack going through +rfcomm_sock_kill() and rfcomm_sock_release(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index bc2b22c2b3aec7..d72cdcd2e2bb11 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) + } + + /* Find socket with channel and source bdaddr. +- * Returns closest match. ++ * Returns closest match with an extra reference held. + */ + static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) + { +@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t * + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ +- if (!bacmp(&rfcomm_pi(sk)->src, src)) ++ if (!bacmp(&rfcomm_pi(sk)->src, src)) { ++ sock_hold(sk); + break; ++ } + + /* Closest match */ +- if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) ++ if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) { ++ if (sk1) ++ sock_put(sk1); ++ + sk1 = sk; ++ sock_hold(sk1); ++ } + } + } + ++ if (sk && sk1) ++ sock_put(sk1); ++ + read_unlock(&rfcomm_sk_list.lock); + + return sk ? sk : sk1; +@@ -941,6 +951,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + { + struct sock *sk, *parent; + bdaddr_t src, dst; ++ bool defer_setup = false; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); +@@ -954,6 +965,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + + lock_sock(parent); + ++ if (parent->sk_state != BT_LISTEN) ++ goto done; ++ ++ defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -981,9 +997,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + done: + release_sock(parent); + +- if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) ++ if (defer_setup) + parent->sk_state_change(parent); + ++ sock_put(parent); ++ + return result; + } + +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch b/queue-6.6/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch new file mode 100644 index 0000000000..336a6c1131 --- /dev/null +++ b/queue-6.6/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch @@ -0,0 +1,167 @@ +From aff357d33d7279eb136d3c7628ffb99c31b8d981 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:04:43 +0900 +Subject: Bluetooth: RFCOMM: validate skb length in MCC handlers + +From: SeungJu Cheon + +[ Upstream commit 23882b828c3c8c51d0c946446a396b10abb3b16b ] + +The RFCOMM MCC handlers cast skb->data to protocol-specific structs +without validating skb->len first. A malicious remote device can send +truncated MCC frames and trigger out-of-bounds reads in these handlers. + +Fix this by using skb_pull_data() to validate and access the required +data before dereferencing it. + +rfcomm_recv_rpn() requires special handling since ETSI TS 07.10 allows +1-byte RPN requests. Handle this by validating only the DLCI byte first, +and validating the full struct only when len > 1. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Suggested-by: Muhammad Bilal +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/core.c | 67 +++++++++++++++++++++++++++---------- + 1 file changed, 49 insertions(+), 18 deletions(-) + +diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c +index 1d34d849703329..07971e918e5b60 100644 +--- a/net/bluetooth/rfcomm/core.c ++++ b/net/bluetooth/rfcomm/core.c +@@ -1431,10 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) + + static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_pn *pn; + struct rfcomm_dlc *d; +- u8 dlci = pn->dlci; ++ u8 dlci; ++ ++ pn = skb_pull_data(skb, sizeof(*pn)); ++ if (!pn) ++ return -EILSEQ; + ++ dlci = pn->dlci; + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) +@@ -1483,8 +1488,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + + static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) + { +- struct rfcomm_rpn *rpn = (void *) skb->data; +- u8 dlci = __get_dlci(rpn->dlci); ++ struct rfcomm_rpn *rpn; ++ u8 dlci; + + u8 bit_rate = 0; + u8 data_bits = 0; +@@ -1495,15 +1500,16 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + u8 xoff_char = 0; + u16 rpn_mask = RFCOMM_RPN_PM_ALL; + +- BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", +- dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, +- rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ if (len == 1) { ++ rpn = skb_pull_data(skb, 1); ++ if (!rpn) ++ return -EILSEQ; + +- if (!cr) +- return 0; ++ dlci = __get_dlci(rpn->dlci); ++ ++ if (!cr) ++ return 0; + +- if (len == 1) { +- /* This is a request, return default (according to ETSI TS 07.10) settings */ + bit_rate = RFCOMM_RPN_BR_9600; + data_bits = RFCOMM_RPN_DATA_8; + stop_bits = RFCOMM_RPN_STOP_1; +@@ -1514,6 +1520,19 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + goto rpn_out; + } + ++ rpn = skb_pull_data(skb, sizeof(*rpn)); ++ if (!rpn) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rpn->dlci); ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ + /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit, + * no parity, no flow control lines, normal XON/XOFF chars */ + +@@ -1589,9 +1608,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + + static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_rls *rls = (void *) skb->data; +- u8 dlci = __get_dlci(rls->dlci); ++ struct rfcomm_rls *rls; ++ u8 dlci; + ++ rls = skb_pull_data(skb, sizeof(*rls)); ++ if (!rls) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rls->dlci); + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) +@@ -1608,10 +1632,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_msc *msc; + struct rfcomm_dlc *d; +- u8 dlci = __get_dlci(msc->dlci); ++ u8 dlci; ++ ++ msc = skb_pull_data(skb, sizeof(*msc)); ++ if (!msc) ++ return -EILSEQ; + ++ dlci = __get_dlci(msc->dlci); + BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); + + d = rfcomm_dlc_get(s, dlci); +@@ -1644,17 +1673,19 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) + { +- struct rfcomm_mcc *mcc = (void *) skb->data; ++ struct rfcomm_mcc *mcc; + u8 type, cr, len; + ++ mcc = skb_pull_data(skb, sizeof(*mcc)); ++ if (!mcc) ++ return -EILSEQ; ++ + cr = __test_cr(mcc->type); + type = __get_mcc_type(mcc->type); + len = __get_mcc_len(mcc->len); + + BT_DBG("%p type 0x%x cr %d", s, type, cr); + +- skb_pull(skb, 2); +- + switch (type) { + case RFCOMM_PN: + rfcomm_recv_pn(s, cr, skb); +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-policy-smq-check-allocation-under-invalidat.patch b/queue-6.6/dm-cache-policy-smq-check-allocation-under-invalidat.patch new file mode 100644 index 0000000000..280eb49086 --- /dev/null +++ b/queue-6.6/dm-cache-policy-smq-check-allocation-under-invalidat.patch @@ -0,0 +1,71 @@ +From 4ba915ebc5828776fce9888dea3588cc1b22bd85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:57:45 +0800 +Subject: dm cache policy smq: check allocation under invalidate lock + +From: Guangshuo Li + +[ Upstream commit d3f0a606b9f278ece8a0df626ded9c4044071235 ] + +commit 2d1f7b65f5de ("dm cache policy smq: fix missing locks in +invalidating cache blocks") added mq->lock around the destructive part of +smq_invalidate_mapping(), but left the e->allocated check outside the +critical section. + +That leaves a check-then-act race. Two concurrent invalidators can both +observe e->allocated as true before either of them takes mq->lock. The +first invalidator that acquires the lock removes the entry from the +queues and hash table and then calls free_entry(), which clears +e->allocated and puts the entry back on the free list. The second +invalidator can then acquire mq->lock and continue with the stale result +of the unlocked check. + +This can corrupt the SMQ queues or hash table by deleting an entry that +is no longer on those structures. It can also hit the allocation check in +free_entry() when the same entry is freed again. + +Move the allocation check under mq->lock so the predicate and the +destructive operations are serialized by the same lock. + +Fixes: 2d1f7b65f5de ("dm cache policy smq: fix missing locks in invalidating cache blocks") +Signed-off-by: Guangshuo Li +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 1566e040f7aac7..c4bc5016840c25 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1590,18 +1590,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; +- +- if (!e->allocated) +- return -ENODATA; ++ int r = 0; + + spin_lock_irqsave(&mq->lock, flags); ++ if (!e->allocated) { ++ r = -ENODATA; ++ goto out; ++ } + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ ++out: + spin_unlock_irqrestore(&mq->lock, flags); + +- return 0; ++ return r; + } + + static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) +-- +2.53.0 + diff --git a/queue-6.6/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch b/queue-6.6/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch new file mode 100644 index 0000000000..6bb75dbada --- /dev/null +++ b/queue-6.6/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch @@ -0,0 +1,53 @@ +From b7ab0a61684e6f56b73759d9fb7fa3188c6659eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 19:00:13 +0100 +Subject: drm/imx: Fix three kernel-doc warnings in dcss-scaler.c + +From: Yicong Hui + +[ Upstream commit ae0383e5a9a4b12d68c76c4769857def4665deff ] + +Fix the following W=1 kerneldoc warnings by adding the missing parameter +descriptions for @phase0_identity and @nn_interpolation in +dcss_scaler_filter_design() and @phase0_identity in +dcss_scaler_gaussian_filter() + +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:173 function parameter 'phase0_identity' not described in 'dcss_scaler_gaussian_filter' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'phase0_identity' not described in 'dcss_scaler_filter_design' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'nn_interpolation' not described in 'dcss_scaler_filter_design' + +Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") +Signed-off-by: Yicong Hui +Reviewed-by: Laurentiu Palcu +Link: https://patch.msgid.link/20260406180013.2442096-1-yiconghui@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/dcss/dcss-scaler.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +index 47852b9dd5eaa2..d2a89a99bd71cf 100644 +--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c ++++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +@@ -166,6 +166,7 @@ static int exp_approx_q(int x) + * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter. + * @fc_q: fixed-point cutoff frequency normalized to range [0, 1] + * @use_5_taps: indicates whether to use 5 taps or 7 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output filter coefficients + */ + static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, +@@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, + * @src_length: length of input + * @dst_length: length of output + * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output coefficients ++ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter + */ + static void dcss_scaler_filter_design(int src_length, int dst_length, + bool use_5_taps, bool phase0_identity, +-- +2.53.0 + diff --git a/queue-6.6/hsr-remove-warn_once-in-hsr_addr_is_self.patch b/queue-6.6/hsr-remove-warn_once-in-hsr_addr_is_self.patch new file mode 100644 index 0000000000..ddd8cb7ea5 --- /dev/null +++ b/queue-6.6/hsr-remove-warn_once-in-hsr_addr_is_self.patch @@ -0,0 +1,109 @@ +From 0a275e2ff3230e09fd153d2472c9b2fbc4e86176 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 30 May 2026 06:42:58 +0000 +Subject: hsr: Remove WARN_ONCE() in hsr_addr_is_self(). + +From: Kuniyuki Iwashima + +[ Upstream commit afd0f17ca46258cec3a5cc48b8df9327fe772490 ] + +syzbot reported the warning [0] in hsr_addr_is_self(), +whose assumption is simply wrong. + +hsr->self_node is cleared in hsr_del_self_node(), which +is called from hsr_dellink(). + +Since dev->rtnl_link_ops->dellink() is called before +unregister_netdevice_many(), there is a window when +user can find the device but without hsr->self_node. + +Let's remove WARN_ONCE() in hsr_addr_is_self(). + +[0]: +HSR: No self node +WARNING: net/hsr/hsr_framereg.c:39 at hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39, CPU#0: syz.4.16848/17220 +Modules linked in: +CPU: 0 UID: 0 PID: 17220 Comm: syz.4.16848 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} +Tainted: [L]=SOFTLOCKUP +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 +RIP: 0010:hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39 +Code: 33 2f 41 0f b7 dd 89 ee 09 de 31 ff e8 c8 b4 c6 f6 09 dd 74 54 e8 0f b0 c6 f6 31 ed eb 53 e8 06 b0 c6 f6 48 8d 3d 2f 50 9c 04 <67> 48 0f b9 3a 31 ed eb 42 e8 c1 13 1f 00 89 c5 31 ff 89 c6 e8 96 +RSP: 0018:ffffc900041c70e0 EFLAGS: 00010283 +RAX: ffffffff8afdc6ca RBX: ffffffff8afdc4e6 RCX: 0000000000080000 +RDX: ffffc90010493000 RSI: 0000000000000948 RDI: ffffffff8f9a1700 +RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000 +R10: ffffc900041c71e8 R11: fffff52000838e3f R12: dffffc0000000000 +R13: ffff888041f9e3c0 R14: ffff888086ee3802 R15: 0000000000000000 +FS: 00007f6fe985d6c0(0000) GS:ffff888126176000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f80bd437dac CR3: 0000000025096000 CR4: 00000000003526f0 +DR0: ffffffffffffffff DR1: 00000000000001f8 DR2: 0000000000000002 +DR3: ffffffffefffff15 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +Call Trace: + + check_local_dest net/hsr/hsr_forward.c:592 [inline] + fill_frame_info net/hsr/hsr_forward.c:728 [inline] + hsr_forward_skb+0xa11/0x2a80 net/hsr/hsr_forward.c:739 + hsr_dev_xmit+0x253/0x370 net/hsr/hsr_device.c:236 + __netdev_start_xmit include/linux/netdevice.h:5368 [inline] + netdev_start_xmit include/linux/netdevice.h:5377 [inline] + xmit_one net/core/dev.c:3888 [inline] + dev_hard_start_xmit+0x2df/0x860 net/core/dev.c:3904 + __dev_queue_xmit+0x1428/0x3900 net/core/dev.c:4870 + neigh_output include/net/neighbour.h:556 [inline] + ip_finish_output2+0xcec/0x10b0 net/ipv4/ip_output.c:237 + ip_send_skb net/ipv4/ip_output.c:1510 [inline] + ip_push_pending_frames+0x8b/0x110 net/ipv4/ip_output.c:1530 + raw_sendmsg+0x1547/0x1a50 net/ipv4/raw.c:659 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x7da/0x9c0 net/socket.c:2698 + ___sys_sendmsg+0x2a5/0x360 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0x1c3/0x2a0 net/socket.c:2787 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f6feb62ce59 +Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 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 e8 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f6fe985d028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +RAX: ffffffffffffffda RBX: 00007f6feb8a6090 RCX: 00007f6feb62ce59 +RDX: 0000000000000000 RSI: 0000200000000000 RDI: 0000000000000004 +RBP: 00007f6feb6c2d6f R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 +R13: 00007f6feb8a6128 R14: 00007f6feb8a6090 R15: 00007ffcf01cc488 + + +Fixes: f266a683a480 ("net/hsr: Better frame dispatch") +Reported-by: syzbot+652670cf249077eb498b@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1a861e.b111c304.35cd64.0016.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260530064300.340793-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_framereg.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c +index 26329db09210bb..ad07a3b1ac20f0 100644 +--- a/net/hsr/hsr_framereg.c ++++ b/net/hsr/hsr_framereg.c +@@ -43,10 +43,8 @@ bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr) + + rcu_read_lock(); + sn = rcu_dereference(hsr->self_node); +- if (!sn) { +- WARN_ONCE(1, "HSR: No self node\n"); ++ if (!sn) + goto out; +- } + + if (ether_addr_equal(addr, sn->macaddress_A) || + ether_addr_equal(addr, sn->macaddress_B)) +-- +2.53.0 + diff --git a/queue-6.6/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch b/queue-6.6/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch new file mode 100644 index 0000000000..dede77acf8 --- /dev/null +++ b/queue-6.6/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch @@ -0,0 +1,56 @@ +From 71d21c0421e4b8573e51c9ded4bb961c4bfbb796 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 07:29:55 +0000 +Subject: ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit() + +From: Eric Dumazet + +[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ] + +The aoe driver (or similar) generates a non-IPv6 packet +(e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() +on a 6LoWPAN interface (configured by the user or test case). + +Since the packet is not IPv6, the 6LoWPAN header_ops->create function +(lowpan_header_create or header_create) returns early without initializing +the lowpan_addr_info structure in the skb headroom. + +In the transmit function (lowpan_xmit), the driver calls lowpan_header +(or setup_header) which unconditionally copies and uses the lowpan_addr_info +from the headroom, which contains uninitialized data. + +Fix this by dropping non IPv6 packets. + +A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit(). + +Fixes: 4dc315e267fe ("ieee802154: 6lowpan: move transmit functionality") +Reported-by: syzbot+f13c19f75e1097abd116@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1fd763.278b5b03.2bcf39.0049.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260603072955.4032221-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ieee802154/6lowpan/tx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c +index 0c07662b44c0ca..4df76ff50699ed 100644 +--- a/net/ieee802154/6lowpan/tx.c ++++ b/net/ieee802154/6lowpan/tx.c +@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) + + pr_debug("package xmit\n"); + ++ if (skb->protocol != htons(ETH_P_IPV6)) { ++ kfree_skb(skb); ++ return NET_XMIT_DROP; ++ } ++ + WARN_ON_ONCE(skb->len > IPV6_MIN_MTU); + + /* We must take a copy of the skb before we modify/replace the ipv6 +-- +2.53.0 + diff --git a/queue-6.6/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch b/queue-6.6/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch new file mode 100644 index 0000000000..ee3c8fc8df --- /dev/null +++ b/queue-6.6/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch @@ -0,0 +1,54 @@ +From 24e29da5ff91b6083fb6a95f7b35d467314dd3f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:15:47 +0000 +Subject: ipv4: restrict IPOPT_SSRR and IPOPT_LSRR options + +From: Eric Dumazet + +[ Upstream commit d3915a1f5a4bc0ac911032903c3c6ab8df9fcc7c ] + +This patch restricts setting Loose Source and Record Route (LSRR) +and Strict Source and Record Route (SSRR) IP options to users +with CAP_NET_RAW capability. + +This prevents unprivileged applications from forcing packets to route +through attacker-controlled nodes to leak TCP ISN and possibly other +protocol information. + +While LSRR and SSRR are commonly filtered in many network environments, +they may still be supported and forwarded along some network paths. + +RFC 7126 (Recommendations on Filtering of IPv4 Packets Containing +IPv4 Options) recommend to drop these options in 4.3 and 4.4. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260602161547.2642155-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_options.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index d898e1523a453e..7a60bbf4bee3aa 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -530,6 +530,10 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp, + kfree(opt); + return -EINVAL; + } ++ if (opt->opt.srr && !ns_capable(net->user_ns, CAP_NET_RAW)) { ++ kfree(opt); ++ return -EPERM; ++ } + kfree(*optp); + *optp = opt; + return 0; +-- +2.53.0 + diff --git a/queue-6.6/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch b/queue-6.6/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch new file mode 100644 index 0000000000..a4d74437de --- /dev/null +++ b/queue-6.6/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch @@ -0,0 +1,107 @@ +From 1bb28a2c0b24a60a2a573a9a1664c70a7b819c84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 13:18:11 +0300 +Subject: ipv6: mcast: Fix use-after-free when processing MLD queries + +From: Ido Schimmel + +[ Upstream commit 791c91dc7a9dfb2457d5e29b8216a6484b9c4b40 ] + +When processing an MLD query, a pointer to the multicast group address +is retrieved when initially parsing the packet. This pointer is later +dereferenced without being reloaded despite the fact that the skb header +might have been reallocated following the pskb_may_pull() calls, leading +to a use-after-free [1]. + +Fix by copying the multicast group address when the packet is initially +parsed. + +[1] +BUG: KASAN: slab-use-after-free in __mld_query_work (net/ipv6/mcast.c:1512) +Read of size 8 at addr ffff8881154b8e90 by task kworker/4:1/118 + +Workqueue: mld mld_query_work +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +print_address_description.constprop.0 (mm/kasan/report.c:378) +print_report (mm/kasan/report.c:482) +kasan_report (mm/kasan/report.c:595) +__mld_query_work (net/ipv6/mcast.c:1512) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + + +[...] + +Freed by task 118: +kasan_save_stack (mm/kasan/common.c:57) +kasan_save_track (mm/kasan/common.c:78) +kasan_save_free_info (mm/kasan/generic.c:584) +__kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285) +kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566) +pskb_expand_head (net/core/skbuff.c:2335) +__pskb_pull_tail (net/core/skbuff.c:2878 (discriminator 4)) +__mld_query_work (net/ipv6/mcast.c:1495 (discriminator 1)) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + +Fixes: 97300b5fdfe2 ("[MCAST] IPv6: Check packet size when process Multicast") +Reported-by: Leo Lin +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260603101811.612594-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index 160b452f75e7d2..c52865e20a4114 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1392,9 +1392,9 @@ void igmp6_event_query(struct sk_buff *skb) + static void __mld_query_work(struct sk_buff *skb) + { + struct mld2_query *mlh2 = NULL; +- const struct in6_addr *group; + unsigned long max_delay; + struct inet6_dev *idev; ++ struct in6_addr group; + struct ifmcaddr6 *ma; + struct mld_msg *mld; + int group_type; +@@ -1426,8 +1426,8 @@ static void __mld_query_work(struct sk_buff *skb) + goto kfree_skb; + + mld = (struct mld_msg *)icmp6_hdr(skb); +- group = &mld->mld_mca; +- group_type = ipv6_addr_type(group); ++ group = mld->mld_mca; ++ group_type = ipv6_addr_type(&group); + + if (group_type != IPV6_ADDR_ANY && + !(group_type&IPV6_ADDR_MULTICAST)) +@@ -1477,7 +1477,7 @@ static void __mld_query_work(struct sk_buff *skb) + } + } else { + for_each_mc_mclock(idev, ma) { +- if (!ipv6_addr_equal(group, &ma->mca_addr)) ++ if (!ipv6_addr_equal(&group, &ma->mca_addr)) + continue; + if (ma->mca_flags & MAF_TIMER_RUNNING) { + /* gsquery <- gsquery && mark */ +-- +2.53.0 + diff --git a/queue-6.6/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch b/queue-6.6/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch new file mode 100644 index 0000000000..e2eef38ad0 --- /dev/null +++ b/queue-6.6/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch @@ -0,0 +1,127 @@ +From ee96bb7f20fe494e769042f1fbac083926bbac7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 07:07:44 +0300 +Subject: ipvs: clear the svc scheduler ptr early on edit + +From: Julian Anastasov + +[ Upstream commit 193989cc6d80dd8e0460fb3992e69fa03bf0ff9b ] + +ip_vs_edit_service() while unbinding the old scheduler clears +the svc->scheduler ptr after the scheduler module initiates +RCU callbacks. This can cause packets to use the old +scheduler at the time when svc->sched_data is already freed +after RCU grace period. + +Fix it by clearing the ptr early in ip_vs_unbind_scheduler(), +before the done_service method schedules any RCU callbacks. + +Also, if the new scheduler fails to initialize when replacing +the old scheduler, try to restore the old scheduler while still +returning the error code. + +Link: https://sashiko.dev/#/patchset/20260519015506.634185-1-rosenp%40gmail.com +Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed") +Signed-off-by: Julian Anastasov +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/ip_vs.h | 3 +-- + net/netfilter/ipvs/ip_vs_ctl.c | 13 ++++++++----- + net/netfilter/ipvs/ip_vs_sched.c | 14 +++++++------- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +index ff406ef4fd4aab..d70268cf1af82e 100644 +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -1506,8 +1506,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched); ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc); + struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); + void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); + struct ip_vs_conn * +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index 25f586fab2bcc9..27b7552b1e2481 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -1496,7 +1496,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, + if (ret_hooks >= 0) + ip_vs_unregister_hooks(ipvs, u->af); + if (svc != NULL) { +- ip_vs_unbind_scheduler(svc, sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_service_free(svc); + } + ip_vs_scheduler_put(sched); +@@ -1558,9 +1558,8 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + old_sched = rcu_dereference_protected(svc->scheduler, 1); + if (sched != old_sched) { + if (old_sched) { +- ip_vs_unbind_scheduler(svc, old_sched); +- RCU_INIT_POINTER(svc->scheduler, NULL); +- /* Wait all svc->sched_data users */ ++ ip_vs_unbind_scheduler(svc); ++ /* Wait all svc->scheduler/sched_data users */ + synchronize_rcu(); + } + /* Bind the new scheduler */ +@@ -1568,6 +1567,10 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + ret = ip_vs_bind_scheduler(svc, sched); + if (ret) { + ip_vs_scheduler_put(sched); ++ /* Try to restore the old_sched */ ++ if (old_sched && ++ !ip_vs_bind_scheduler(svc, old_sched)) ++ old_sched = NULL; + goto out; + } + } +@@ -1624,7 +1627,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup) + + /* Unbind scheduler */ + old_sched = rcu_dereference_protected(svc->scheduler, 1); +- ip_vs_unbind_scheduler(svc, old_sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_scheduler_put(old_sched); + + /* Unbind persistence engine, keep svc->pe */ +diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c +index d4903723be7e90..49b2e5d2b2c837 100644 +--- a/net/netfilter/ipvs/ip_vs_sched.c ++++ b/net/netfilter/ipvs/ip_vs_sched.c +@@ -57,19 +57,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, + /* + * Unbind a service with its scheduler + */ +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched) ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc) + { +- struct ip_vs_scheduler *cur_sched; ++ struct ip_vs_scheduler *sched; + +- cur_sched = rcu_dereference_protected(svc->scheduler, 1); +- /* This check proves that old 'sched' was installed */ +- if (!cur_sched) ++ sched = rcu_dereference_protected(svc->scheduler, 1); ++ if (!sched) + return; + ++ /* Reset the scheduler before initiating any RCU callbacks */ ++ rcu_assign_pointer(svc->scheduler, NULL); ++ smp_wmb(); /* paired with smp_rmb() in ip_vs_schedule() */ + if (sched->done_service) + sched->done_service(svc); +- /* svc->scheduler can be set to NULL only by caller */ + } + + +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch b/queue-6.6/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch new file mode 100644 index 0000000000..d40fc75d8f --- /dev/null +++ b/queue-6.6/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch @@ -0,0 +1,75 @@ +From e20bb720112d604a637b91bf2b42a93a8cd0232f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 00:00:00 +0000 +Subject: ksmbd: fix NULL-deref of opinfo->conn in oplock/lease break notifiers + +From: Gil Portnoy + +[ Upstream commit b003086d76968298f22e7cf62239833b5a3a06b1 ] + +smb2_oplock_break_noti() and smb2_lease_break_noti() read opinfo->conn +into a local with neither READ_ONCE() nor a NULL check. Both run from +oplock_break() after opinfo_get_list() has dropped ci->m_lock, so a +concurrent SMB2 LOGOFF (session_fd_check()) can set op->conn = NULL +under ci->m_lock within that window. ksmbd_conn_r_count_inc(conn) then +writes through NULL at offset 0xc4 -- a remotely triggerable oops. + +Guard both reads the way compare_guid_key() already does: read +opinfo->conn with READ_ONCE() and return early if it is NULL, before +allocating the work struct so nothing leaks. A NULL conn means the +client is gone and the break is moot, so return 0; oplock_break() treats +that as success and runs the normal teardown. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Assisted-by: Henry (Claude):claude-opus-4 +Signed-off-by: Gil Portnoy +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/oplock.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index 5302c30a4a91d7..bba17ea84023e2 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -714,11 +714,16 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) + */ + static int smb2_oplock_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct oplock_break_info *br_info; + int ret = 0; +- struct ksmbd_work *work = ksmbd_alloc_work_struct(); ++ struct ksmbd_work *work; ++ ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; + ++ work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; + +@@ -818,11 +823,15 @@ static void __smb2_lease_break_noti(struct work_struct *wk) + */ + static int smb2_lease_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct ksmbd_work *work; + struct lease_break_info *br_info; + struct lease *lease = opinfo->o_lease; + ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; ++ + work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.6/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch b/queue-6.6/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch new file mode 100644 index 0000000000..01cd60b3f2 --- /dev/null +++ b/queue-6.6/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch @@ -0,0 +1,79 @@ +From c14972b8c3909516081c00eaac66c9a40acdeec3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:00:13 +0800 +Subject: net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr + +From: Yizhou Zhao + +[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ] + +In mrp_pdu_parse_vecattr(), vector attribute events are encoded three +per byte and valen tracks the number of events left to process. + +The parser decrements valen after processing the first and second events +from each event byte, but not after processing the third one. When valen +is exactly a multiple of three, the loop continues after the last valid +event and consumes the next byte as a new event byte, applying a +spurious event to the MRP applicant state. + +Additionally, when valen is zero the parser unconditionally consumes +attrlen bytes as FirstValue and advances the offset, even though per +IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of +zero and no FirstValue or Vector fields. This corrupts the offset for +subsequent PDU parsing. + +Also, when valen exceeds three the loop crosses byte boundaries but +the attribute value is not incremented between the last event of one +byte and the first event of the next. This causes the first event of +the next byte to use the same attribute value as the third event +rather than the next consecutive value. + +Decrement valen after processing the third event, skip FirstValue +consumption when valen is zero, and increment the attribute value at +the end of each loop iteration. + +Fixes: febf018d2234 ("net/802: Implement Multiple Registration Protocol (MRP)") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Link: https://patch.msgid.link/20260603060016.21522-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/mrp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/802/mrp.c b/net/802/mrp.c +index eafc21ecc287d9..a58e697e182a8f 100644 +--- a/net/802/mrp.c ++++ b/net/802/mrp.c +@@ -702,6 +702,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) & + MRP_VECATTR_HDR_LEN_MASK); + ++ /* If valen is 0, only a LeaveAllEvent is present; FirstValue and ++ * Vector fields are absent per IEEE 802.1ak. ++ */ ++ if (valen == 0) ++ return 0; ++ + /* The VectorAttribute structure in a PDU carries event information + * about one or more attributes having consecutive values. Only the + * value for the first attribute is contained in the structure. So +@@ -752,6 +758,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + vaevents %= __MRP_VECATTR_EVENT_MAX; + vaevent = vaevents; + mrp_pdu_parse_vecattr_event(app, skb, vaevent); ++ valen--; ++ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue, ++ mrp_cb(skb)->mh->attrlen); + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/net-annotate-sk-sk_write_space-for-udp-sockmap.patch b/queue-6.6/net-annotate-sk-sk_write_space-for-udp-sockmap.patch new file mode 100644 index 0000000000..15f374bcfd --- /dev/null +++ b/queue-6.6/net-annotate-sk-sk_write_space-for-udp-sockmap.patch @@ -0,0 +1,60 @@ +From bee60c5535c91e722b8f498e113b0b5a159ebdd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:39:23 +0000 +Subject: net: Annotate sk->sk_write_space() for UDP SOCKMAP. + +From: Kuniyuki Iwashima + +[ Upstream commit b748765019fe9e9234660327090fc1a9665cdbdd ] + +UDP TX skb->destructor() is sock_wfree(), and UDP holds lock_sock() +only for UDP_CORK / MSG_MORE sendmsg(). + +Otherwise, sk->sk_write_space() may be read locklessly while SOCKMAP +rewrites sk->sk_write_space(). + +Let's use WRITE_ONCE() and READ_ONCE() for sk->sk_write_space(). + +Note that the write side is annotated by commit 2ef2b20cf4e0 +("net: annotate data-races around sk->sk_{data_ready,write_space}"). + +Fixes: 7b98cd42b049 ("bpf: sockmap: Add UDP support") +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Jakub Sitnicki +Link: https://patch.msgid.link/20260529193941.3897256-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 8e4c87a39dc87b..267f771dda1cc2 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2499,8 +2499,12 @@ void sock_wfree(struct sk_buff *skb) + bool free; + + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { ++ void (*sk_write_space)(struct sock *sk); ++ ++ sk_write_space = READ_ONCE(sk->sk_write_space); ++ + if (sock_flag(sk, SOCK_RCU_FREE) && +- sk->sk_write_space == sock_def_write_space) { ++ sk_write_space == sock_def_write_space) { + rcu_read_lock(); + free = refcount_sub_and_test(len, &sk->sk_wmem_alloc); + sock_def_write_space_wfree(sk); +@@ -2515,7 +2519,7 @@ void sock_wfree(struct sk_buff *skb) + * after sk_write_space() call + */ + WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc)); +- sk->sk_write_space(sk); ++ sk_write_space(sk); + len = 1; + } + /* +-- +2.53.0 + diff --git a/queue-6.6/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch b/queue-6.6/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch new file mode 100644 index 0000000000..0c62c4590a --- /dev/null +++ b/queue-6.6/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch @@ -0,0 +1,48 @@ +From 267525423e65517c9f4cc007c0334a89c0a68516 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:21:05 +0200 +Subject: net: ethernet: mtk_eth_soc: Fix use-after-free in metadata dst + teardown + +From: Lorenzo Bianconi + +[ Upstream commit 80df409e1a483676826a6c66e693dba6ac507751 ] + +mtk_free_dev() calls metadata_dst_free() which frees the metadata_dst +with kfree() immediately, bypassing the RCU grace period. +In the RX path, skb_dst_set_noref() sets a non-refcounted pointer from +the skb to the metadata_dst. This function requires RCU read-side +protection and the dst must remain valid until all RCU readers complete. +Since metadata_dst_free() calls kfree() directly, a use-after-free can +occur if any skb still holds a noref pointer to the dst when the driver +tears it down. +Replace metadata_dst_free() with dst_release() which properly goes +through the refcount path: when the refcount drops to zero, it schedules +the actual free via call_rcu_hurry(), ensuring all RCU readers have +completed before the memory is freed. + +Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260602-airoha-mtk-metadata-uaf-fix-v1-2-3aaa99d83351@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 74cb96dbff9ee4..6de783fe116ce8 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4246,7 +4246,7 @@ static int mtk_free_dev(struct mtk_eth *eth) + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { + if (!eth->dsa_meta[i]) + break; +- metadata_dst_free(eth->dsa_meta[i]); ++ dst_release(ð->dsa_meta[i]->dst); + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch b/queue-6.6/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch new file mode 100644 index 0000000000..a4445acc54 --- /dev/null +++ b/queue-6.6/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch @@ -0,0 +1,62 @@ +From c836fb663d2b8fb548ee5339c8c9cd28ca379d57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 06:18:57 +0000 +Subject: net: fec: fix pinctrl default state restore order on resume + +From: Tapio Reijonen + +[ Upstream commit b455410146bf723c7ebcb49ecd5becc0d6611482 ] + +In fec_resume(), fec_enet_clk_enable() is called before +pinctrl_pm_select_default_state() in the non-WoL path, inverting the +ordering used in fec_suspend() which correctly switches to the sleep +pinctrl state before disabling clocks. + +For PHYs with the PHY_RST_AFTER_CLK_EN flag (e.g. TI DP83848 or +SMSC LAN87xx), fec_enet_clk_enable() triggers a hardware reset pulse +via the phy-reset GPIO. With the GPIO pin still in sleep pinctrl state +at that point, the GPIO write has no physical effect and the PHY never +receives the required reset after clock enable, leading to unreliable +link establishment after system resume. + +Fix by restoring the default pinctrl state before enabling clocks, +making resume the proper mirror of suspend. The call is made +unconditionally: fec_suspend() only switches to the sleep pinctrl state +on the non-WoL path and leaves the pins in the default state when WoL +is enabled, so on a WoL resume the device is already in the default +state and pinctrl_pm_select_default_state() is a no-op. + +Fixes: de40ed31b3c5 ("net: fec: add Wake-on-LAN support") +Signed-off-by: Tapio Reijonen +Reviewed-by: Wei Fang +Link: https://patch.msgid.link/20260529-b4-fec-resume-pinctrl-order-v3-1-6eda0f592fca@vaisala.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/fec_main.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 7efe4e81cf320b..49297b83c3fdb8 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -4734,6 +4734,7 @@ static int __maybe_unused fec_resume(struct device *dev) + if (fep->rpm_active) + pm_runtime_force_resume(dev); + ++ pinctrl_pm_select_default_state(&fep->pdev->dev); + ret = fec_enet_clk_enable(ndev, true); + if (ret) { + rtnl_unlock(); +@@ -4750,8 +4751,6 @@ static int __maybe_unused fec_resume(struct device *dev) + val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; +- } else { +- pinctrl_pm_select_default_state(&fep->pdev->dev); + } + fec_restart(ndev); + netif_tx_lock_bh(ndev); +-- +2.53.0 + diff --git a/queue-6.6/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch b/queue-6.6/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch new file mode 100644 index 0000000000..b2b2d1c1fa --- /dev/null +++ b/queue-6.6/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch @@ -0,0 +1,58 @@ +From 8bea8d1f5e6b6c0897f179772065cf82cd0d5ab7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:31:58 +0800 +Subject: net: garp: fix unsigned integer underflow in garp_pdu_parse_attr + +From: Yizhou Zhao + +[ Upstream commit 16e408e607a94b646fb14a2a98422c6877ae4b3c ] + +The receive-side GARP attribute parser computes dlen with reversed +operands: + + dlen = sizeof(*ga) - ga->len; + +ga->len is the on-wire attribute length and includes the GARP attribute +header. For normal attributes with data, ga->len is larger than +sizeof(*ga), so the subtraction underflows in unsigned arithmetic. + +The resulting value is later passed to garp_attr_lookup(), whose length +argument is u8. After truncation, the parsed data length usually no +longer matches the length stored for locally registered attributes, so +received Join/Leave events are ignored. This breaks the GARP receive path +for common attributes, such as GVRP VLAN registration attributes. + +Compute the data length as the attribute length minus the header length. + +Fixes: eca9ebac651f ("net: Add GARP applicant-only participant") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260527083200.42861-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/garp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/802/garp.c b/net/802/garp.c +index ab24b21fbb4938..d263f8ffdceec3 100644 +--- a/net/802/garp.c ++++ b/net/802/garp.c +@@ -452,7 +452,7 @@ static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); +- dlen = sizeof(*ga) - ga->len; ++ dlen = ga->len - sizeof(*ga); + + if (attrtype > app->app->maxattr) + return 0; +-- +2.53.0 + diff --git a/queue-6.6/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch b/queue-6.6/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch new file mode 100644 index 0000000000..7442fb172f --- /dev/null +++ b/queue-6.6/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch @@ -0,0 +1,99 @@ +From c77bf7e98c1342279812ecdb4562647dc56193b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 21:03:00 +0000 +Subject: net: lan743x: permit VLAN-tagged packets up to configured MTU + +From: David Thompson + +[ Upstream commit 8173d22b211f615015f7b35f48ab11a6dd78dc99 ] + +VLAN-tagged interfaces on lan743x devices were previously unreachable via +SSH and failed to respond to large ping packets (e.g. "ping -s 1469" given +MTU=1500). In these scenarios, "ethtool -S" reports non-zero "RX Oversize +Frame Errors". According to Microchip AN2948, the MAC_RX FSE (VLAN field +size enforcement) bit determines whether frames with VLAN tags exceeding +the base MTU plus tag length are discarded. + +The driver must set the MAC_RX.FSE bit before setting MAC_RX.RXEN to allow +VLAN-tagged frames up to the interface MTU, preventing them from being +treated as oversized. As a result, both the base and VLAN-tagged interfaces +can use the same MTU without receive errors. + +Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") +Signed-off-by: David Thompson +Reviewed-by: Thangaraj Samynathan +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz # lan7430 on arm64 (RevPi +Link: https://patch.msgid.link/20260529210300.433135-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 32 +++++++++++++++++++ + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 8910928b38498b..50abc227f6f160 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1255,6 +1255,36 @@ static void lan743x_mac_set_address(struct lan743x_adapter *adapter, + "MAC address set to %pM\n", addr); + } + ++static void lan743x_mac_rx_enable_fse(struct lan743x_adapter *adapter) ++{ ++ u32 mac_rx; ++ bool rxen; ++ ++ mac_rx = lan743x_csr_read(adapter, MAC_RX); ++ if (mac_rx & MAC_RX_FSE_) ++ return; ++ ++ rxen = mac_rx & MAC_RX_RXEN_; ++ if (rxen) { ++ mac_rx &= ~MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, ++ 1, 1000, 20000, 100); ++ } ++ ++ /* Per AN2948, hardware prevents modification of the FSE bit while the ++ * MAC receiver is enabled (RXEN bit set). Use separate register write ++ * to assert the FSE bit before enabling the RXEN bit in MAC_RX ++ */ ++ mac_rx |= MAC_RX_FSE_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ ++ if (rxen) { ++ mac_rx |= MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ } ++} ++ + static int lan743x_mac_init(struct lan743x_adapter *adapter) + { + bool mac_address_valid = true; +@@ -1294,6 +1324,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter) + lan743x_mac_set_address(adapter, adapter->mac_address); + eth_hw_addr_set(netdev, adapter->mac_address); + ++ lan743x_mac_rx_enable_fse(adapter); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index b6c83c68241e63..f1d346db85ea04 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -180,6 +180,7 @@ + #define MAC_RX (0x104) + #define MAC_RX_MAX_SIZE_SHIFT_ (16) + #define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) ++#define MAC_RX_FSE_ BIT(2) + #define MAC_RX_RXD_ BIT(1) + #define MAC_RX_RXEN_ BIT(0) + +-- +2.53.0 + diff --git a/queue-6.6/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch b/queue-6.6/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch new file mode 100644 index 0000000000..69005143c3 --- /dev/null +++ b/queue-6.6/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch @@ -0,0 +1,106 @@ +From f353969d2745945d7e590ff6a1e37bc58c999394 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 12:08:12 -0400 +Subject: net/sched: act_api: use RCU with deferred freeing for action + lifecycle + +From: Jamal Hadi Salim + +[ Upstream commit 5057e1aca011e51ef51498c940ef96f3d3e8a305 ] + +When NEWTFILTER and DELFILTER are run concurrently it is possible to create a +race with an associated action. + +Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: + + 0: mutex_lock() <-- holds the idr lock + 0: rcu_read_lock() + 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) + 0: mutex_unlock() <-- releases the idr lock + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) <-- Action removed from IDR + 1: mutex_unlock() <-- mutex released allowing us to delete the action + 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory + +This patch fixes the race condition between NEWTFILTER and DELFILTER by +adding struct rcu_head to tc_action used in the deferral and introducing a +call_rcu() in the delete path to defer the final kfree(). + +Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +but also modernization/simplification to directly use kfree_rcu(). + +Let's illustrate the new restored code path: + + 0: rcu_read_lock() + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) + 1: mutex_unlock() + 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period + 0: p = idr_find(idr, index) + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 + 1: rcu_read_unlock() <-- release so freeing can run after grace period + +After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. +CPU0's subsequent idr_find() will return NULL, and even if it still held a +stale pointer, the immediate kfree() is now deferred until after the RCU grace +period, so no UAF can occur. + +Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +Suggested-by: Jakub Kicinski +Reported-by: Kyle Zeng +Tested-by: Victor Nogueira +Tested-by: syzbot@syzkaller.appspotmail.com +Signed-off-by: Jamal Hadi Salim +Tested-by: Kyle Zeng +Reviewed-by: Pedro Tammela +Reviewed-by: Eric Dumazet +Reviewed-by: Victor Nogueira +Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/act_api.h | 1 + + net/sched/act_api.c | 7 +------ + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/net/act_api.h b/include/net/act_api.h +index 8db6994c90eec1..56f49351fd5177 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -42,6 +42,7 @@ struct tc_action { + struct tc_cookie __rcu *user_cookie; + struct tcf_chain __rcu *goto_chain; + u32 tcfa_flags; ++ struct rcu_head tcfa_rcu; + u8 hw_stats; + u8 used_hw_stats; + bool used_hw_stats_valid; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index e509ac28c49299..bed04ae3003c43 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -112,11 +112,6 @@ struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action, + } + EXPORT_SYMBOL(tcf_action_set_ctrlact); + +-/* XXX: For standalone actions, we don't need a RCU grace period either, because +- * actions are always connected to filters and filters are already destroyed in +- * RCU callbacks, so after a RCU grace period actions are already disconnected +- * from filters. Readers later can not find us. +- */ + static void free_tcf(struct tc_action *p) + { + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); +@@ -129,7 +124,7 @@ static void free_tcf(struct tc_action *p) + if (chain) + tcf_chain_put_by_act(chain); + +- kfree(p); ++ kfree_rcu(p, tcfa_rcu); + } + + static void offload_action_hw_count_set(struct tc_action *act, +-- +2.53.0 + diff --git a/queue-6.6/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch b/queue-6.6/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch new file mode 100644 index 0000000000..a8d0246a47 --- /dev/null +++ b/queue-6.6/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch @@ -0,0 +1,58 @@ +From fa0486205d37ca40722a4c3d6a34d876f4ee0778 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 12:29:10 +0000 +Subject: netfilter: bridge: make ebt_snat ARP rewrite writable + +From: Yiming Qian + +[ Upstream commit 67ba971ae02514d85818fe0c32549ab4bfa3bf49 ] + +The ebtables SNAT target keeps the Ethernet source address rewrite +behind skb_ensure_writable(skb, 0). This is intentional: at the bridge +ebtables hooks the Ethernet header is addressed through +skb_mac_header()/eth_hdr(), while skb->data points at the Ethernet +payload. Asking skb_ensure_writable() for ETH_HLEN bytes would check +the payload, not the Ethernet header, and would reintroduce the small +packet regression fixed by commit 63137bc5882a. + +However, the optional ARP sender hardware address rewrite is different. +It writes through skb_store_bits() at an offset relative to skb->data: + + skb_store_bits(skb, sizeof(struct arphdr), info->mac, ETH_ALEN) + +skb_header_pointer() only safely reads the ARP header; it does not make +the later sender hardware address range writable. If that range is +still held in a nonlinear skb fragment backed by a splice-imported file +page, skb_store_bits() maps the frag page and copies the new MAC address +directly into it. + +Ensure the ARP SHA range is writable before reading the ARP header and +before calling skb_store_bits(). + +Fixes: 63137bc5882a ("netfilter: ebtables: Fixes dropping of small packets in bridge nat") +Reported-by: Yiming Qian +Signed-off-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_snat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c +index 7dfbcdfc30e5d2..c9e229af0366b8 100644 +--- a/net/bridge/netfilter/ebt_snat.c ++++ b/net/bridge/netfilter/ebt_snat.c +@@ -31,6 +31,9 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) + const struct arphdr *ap; + struct arphdr _ah; + ++ if (skb_ensure_writable(skb, sizeof(_ah) + ETH_ALEN)) ++ return EBT_DROP; ++ + ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch b/queue-6.6/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch new file mode 100644 index 0000000000..ec8be24d7a --- /dev/null +++ b/queue-6.6/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch @@ -0,0 +1,50 @@ +From 8883579051e59faefa0e33682fbe0422682d7e75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:20:19 +0200 +Subject: netfilter: conntrack_irc: fix possible out-of-bounds read + +From: Florian Westphal + +[ Upstream commit 66eba0ffce3b7e11449946b4cbbef8ea36112f56 ] + +When parsing fails after we've matched the command string we +should bail out instead of trying to match a different command. + +This helper should be deprecated, given prevalence of TLS I doubt it has +any relevance in 2026. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Closes: https://sashiko.dev/#/patchset/20260525182924.28456-1-fw%40strlen.de +Signed-off-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_irc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c +index 5703846bea3b69..0f50ea92ced9df 100644 +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -208,7 +208,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + pr_debug("unable to parse dcc command\n"); +- continue; ++ goto out; + } + + pr_debug("DCC bound ip/port: %pI4:%u\n", +@@ -222,7 +222,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); +- continue; ++ goto out; + } + + exp = nf_ct_expect_alloc(ct); +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch b/queue-6.6/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch new file mode 100644 index 0000000000..5ba8251440 --- /dev/null +++ b/queue-6.6/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch @@ -0,0 +1,96 @@ +From b9853b57bbf89b54d15dbc65d321de2a56f8a43b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:09:19 +0800 +Subject: netfilter: nft_ct: bail out on template ct in get eval + +From: Jiayuan Chen + +[ Upstream commit 3027ecbdb5fdf9200251c21d4818e4c447ef78e1 ] + +I noticed this issue while looking at a historic syzbot report [1]. + +A rule like the one below is enough to trigger the bug: + + table ip t { + chain pre { + type filter hook prerouting priority raw; + ct zone set 1 + ct original saddr 1.2.3.4 accept + } + } + +The first expression attaches a per-cpu template ct via +nft_ct_set_zone_eval() (nf_ct_tmpl_alloc -> kzalloc, tuple is all +zero, nf_ct_l3num(ct) == 0). The next expression then calls +nft_ct_get_eval() on the same skb, treats the template as a real ct +and hits the 16-byte memcpy path. With dreg at NFT_REG32_15 this +overflows past struct nft_regs on the kernel stack; with smaller +dreg values it silently clobbers adjacent registers. + +Reject template ct at the eval entry and in nft_ct_get_fast_eval(), +mirroring the check nft_ct_set_eval() already has. Additionally, +bound the address copy in NFT_CT_SRC / NFT_CT_DST by priv->len +instead of by nf_ct_l3num(ct): nf_ct_get_tuple() zeroes the tuple +before pkt_to_tuple() fills in only the protocol-relevant leading +bytes, so the trailing bytes of tuple->{src,dst}.u3.all are +well-defined zero. priv->len is validated at rule load, so the +copy size is now bounded by the destination register rather than +by an untrusted field on the conntrack. + +[1]: https://syzkaller.appspot.com/bug?id=389cf09cb72926114fce90dc85a2c3231dcb647c + +Fixes: 45d9bcda21f4 ("netfilter: nf_tables: validate len in nft_validate_data_load()") +Suggested-by: Florian Westphal +Signed-off-by: Jiayuan Chen +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_ct.c | 8 +++----- + net/netfilter/nft_ct_fast.c | 2 +- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c +index 83c963e668ffe0..e83aa87a348e7d 100644 +--- a/net/netfilter/nft_ct.c ++++ b/net/netfilter/nft_ct.c +@@ -78,7 +78,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + break; + } + +- if (ct == NULL) ++ if (!ct || nf_ct_is_template(ct)) + goto err; + + switch (priv->key) { +@@ -180,12 +180,10 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + tuple = &ct->tuplehash[priv->dir].tuple; + switch (priv->key) { + case NFT_CT_SRC: +- memcpy(dest, tuple->src.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->src.u3.all, priv->len); + return; + case NFT_CT_DST: +- memcpy(dest, tuple->dst.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->dst.u3.all, priv->len); + return; + case NFT_CT_PROTO_SRC: + nft_reg_store16(dest, (__force u16)tuple->src.u.all); +diff --git a/net/netfilter/nft_ct_fast.c b/net/netfilter/nft_ct_fast.c +index e684c8a9184877..ecf7b3a404be26 100644 +--- a/net/netfilter/nft_ct_fast.c ++++ b/net/netfilter/nft_ct_fast.c +@@ -30,7 +30,7 @@ void nft_ct_get_fast_eval(const struct nft_expr *expr, + break; + } + +- if (!ct) { ++ if (!ct || nf_ct_is_template(ct)) { + regs->verdict.code = NFT_BREAK; + return; + } +-- +2.53.0 + diff --git a/queue-6.6/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch b/queue-6.6/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch new file mode 100644 index 0000000000..1f2488c049 --- /dev/null +++ b/queue-6.6/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch @@ -0,0 +1,113 @@ +From 1c347da9d6cf2a53112f096b961599ebede38fc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 23:58:31 +0200 +Subject: netfilter: synproxy: add mutex to guard hook reference counting + +From: Fernando Fernandez Mancera + +[ Upstream commit 2fcba19caaeb2a33017459d3430f057967bb91b6 ] + +As the synproxy infrastructure register netfilter hooks on-demand when a +user adds the first iptables target or nftables expression, if done +concurrently they can race each other. + +Introduce a mutex to serialize the refcount control blocks access from +both frontends. While a per namespace mutex might be more efficient, it +is not needed for target/expression like SYNPROXY. + +Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index f5a52075691faa..500a90311ed505 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -21,6 +21,8 @@ + #include + #include + ++static DEFINE_MUTEX(synproxy_mutex); ++ + unsigned int synproxy_net_id; + EXPORT_SYMBOL_GPL(synproxy_net_id); + +@@ -768,26 +770,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = { + + int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref4 == 0) { + err = nf_register_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref4++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init); + + void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref4--; + if (snet->hook_ref4 == 0) + nf_unregister_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini); + +@@ -1192,27 +1199,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = { + int + nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref6 == 0) { + err = nf_register_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref6++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init); + + void + nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref6--; + if (snet->hook_ref6 == 0) + nf_unregister_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini); + #endif /* CONFIG_IPV6 */ +-- +2.53.0 + diff --git a/queue-6.6/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch b/queue-6.6/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..04e36e1b22 --- /dev/null +++ b/queue-6.6/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch @@ -0,0 +1,41 @@ +From fbed5eccdaae33b9f4780e806a94db504d865da3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 12:47:17 +0200 +Subject: netfilter: xt_NFQUEUE: prefer raw_smp_processor_id + +From: Fernando Fernandez Mancera + +[ Upstream commit c6c5327dd18bec1e1bbf139b2cf5ae53608a9d30 ] + +With PREEMPT_RCU this triggers a splat because smp_processor_id() can be +preempted while inside a RCU critical section. If xt_NFQUEUE target is +invoked via nft_compat_eval() path, we are inside a RCU critical +section. + +Just use the raw version instead. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_NFQUEUE.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index 466da23e36ff47..b32d153e3a1862 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -91,7 +91,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) + + if (info->queues_total > 1) { + if (info->flags & NFQ_FLAG_CPU_FANOUT) { +- int cpu = smp_processor_id(); ++ int cpu = raw_smp_processor_id(); + + queue = info->queuenum + cpu % info->queues_total; + } else { +-- +2.53.0 + diff --git a/queue-6.6/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch b/queue-6.6/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch new file mode 100644 index 0000000000..3ba360667b --- /dev/null +++ b/queue-6.6/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch @@ -0,0 +1,119 @@ +From ade889b3d4b22a008d2bd39504bcf2d2603d786c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 10:28:53 +0530 +Subject: octeontx2-af: npc: Fix CPT channel mask in npc_install_flow + +From: Nithin Dabilpuram + +[ Upstream commit 1d31eb27e570daa04f5373345f9ac98c95863be9 ] + +Use the CPT-aware NIX channel mask in the npc_install_flow path so that +when the host PF installs steering rules in kernel for a VF used from +userspace (e.g. DPDK), MCAM entries see the same channel mask semantics as +other RX paths. + +Fixes: 56bcef528bd8 ("octeontx2-af: Use npc_install_flow API for promisc and broadcast entries") +Cc: Naveen Mamindlapalli +Signed-off-by: Nithin Dabilpuram +Signed-off-by: Ratheesh Kannoth +Link: https://patch.msgid.link/20260602045853.1558530-1-rkannoth@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + + .../ethernet/marvell/octeontx2/af/rvu_npc.c | 32 +++++++++---------- + .../marvell/octeontx2/af/rvu_npc_fs.c | 2 +- + 3 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index 9fbc071ef29b0c..11d25404d57166 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -933,6 +933,7 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int lf, + int slot); + int rvu_cpt_ctx_flush(struct rvu *rvu, u16 pcifunc); + int rvu_cpt_init(struct rvu *rvu); ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu); + + #define NDC_AF_BANK_MASK GENMASK_ULL(7, 0) + #define NDC_AF_BANK_LINE_MASK GENMASK_ULL(31, 16) +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index 9b8a6046e6dff0..65ad7476e60983 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -609,6 +609,19 @@ static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + NPC_AF_MCAMEX_BANKX_ACTION(index, bank)); + } + ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu) ++{ ++ /* For cn10k the upper two bits of the channel number are ++ * cpt channel number. with masking out these bits in the ++ * mcam entry, same entry used for NIX will allow packets ++ * received from cpt for parsing. ++ */ ++ if (!is_rvu_otx2(rvu)) ++ return NIX_CHAN_CPT_X2P_MASK; ++ else ++ return 0xFFFu; ++} ++ + void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + int nixlf, u64 chan, u8 *mac_addr) + { +@@ -652,7 +665,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + eth_broadcast_addr((u8 *)&req.mask.dmac); + req.features = BIT_ULL(NPC_DMAC); + req.channel = chan; +- req.chan_mask = 0xFFFU; ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.intf = pfvf->nix_rx_intf; + req.op = action.op; + req.hdr.pcifunc = 0; /* AF is requester */ +@@ -722,11 +735,7 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc, + * mcam entry, same entry used for NIX will allow packets + * received from cpt for parsing. + */ +- if (!is_rvu_otx2(rvu)) { +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- } else { +- req.chan_mask = 0xFFFU; +- } ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + + if (chan_cnt > 1) { + if (!is_power_of_2(chan_cnt)) { +@@ -915,16 +924,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf, + ether_addr_copy(req.mask.dmac, mac_addr); + req.features = BIT_ULL(NPC_DMAC); + +- /* For cn10k the upper two bits of the channel number are +- * cpt channel number. with masking out these bits in the +- * mcam entry, same entry used for NIX will allow packets +- * received from cpt for parsing. +- */ +- if (!is_rvu_otx2(rvu)) +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- else +- req.chan_mask = 0xFFFU; +- ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.channel = chan; + req.intf = pfvf->nix_rx_intf; + req.entry = index; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +index 0f4e462d39c2ea..b0ec4757b10835 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +@@ -1354,7 +1354,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, + + /* ignore chan_mask in case pf func is not AF, revisit later */ + if (!is_pffunc_af(req->hdr.pcifunc)) +- req->chan_mask = 0xFFF; ++ req->chan_mask = rvu_get_cpt_chan_mask(rvu); + + err = npc_check_unsupported_flows(rvu, req->features, req->intf); + if (err) +-- +2.53.0 + diff --git a/queue-6.6/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch b/queue-6.6/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch new file mode 100644 index 0000000000..1e04230483 --- /dev/null +++ b/queue-6.6/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch @@ -0,0 +1,58 @@ +From a316e6de01140387b8979a9115b96261c0b8cf59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 16:03:20 +0200 +Subject: pcnet32: stop holding device spin lock during napi_complete_done + +From: Oscar Maes + +[ Upstream commit 73bf3cca7de6a73f53b6a52dc3b1c82ae5667a4d ] + +napi_complete_done may call gro_flush_normal (though not currently, as GRO +is unsupported at the moment), which may result in packet TX. This will +eventually result in calling pcnet32_start_xmit - resulting in a deadlock +while trying to re-acquire the already locked spin lock. + +It is safe to split the spinlock block into two, because the hardware +registers are still protected from concurrent access, and the two blocks +perform unrelated operations that don't need to happen atomically. + +Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()") +Reviewed-by: Andrew Lunn +Signed-off-by: Oscar Maes +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/pcnet32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c +index 72db9f9e7beeae..81cb83caf62a15 100644 +--- a/drivers/net/ethernet/amd/pcnet32.c ++++ b/drivers/net/ethernet/amd/pcnet32.c +@@ -1403,8 +1403,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + pcnet32_restart(dev, CSR0_START); + netif_wake_queue(dev); + } ++ spin_unlock_irqrestore(&lp->lock, flags); + + if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a->read_csr(ioaddr, CSR3); + val &= 0x00ff; +@@ -1412,9 +1414,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + + /* Set interrupt enable. */ + lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN); ++ spin_unlock_irqrestore(&lp->lock, flags); + } + +- spin_unlock_irqrestore(&lp->lock, flags); + return work_done; + } + +-- +2.53.0 + diff --git a/queue-6.6/ptp-vclock-switch-from-rcu-to-srcu.patch b/queue-6.6/ptp-vclock-switch-from-rcu-to-srcu.patch new file mode 100644 index 0000000000..693ea98f00 --- /dev/null +++ b/queue-6.6/ptp-vclock-switch-from-rcu-to-srcu.patch @@ -0,0 +1,85 @@ +From b67f6fcf4974611a75d6d508761f32139539f9b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:11:47 +0200 +Subject: ptp: vclock: Switch from RCU to SRCU + +From: Kurt Kanzenbach + +[ Upstream commit 672bd0519e27c357c43b7f8c0d653fce3817d06e ] + +The usage of PTP vClocks leads immediately to the following issues with +ptp4l with LOCKDEP and DEBUG_ATOMIC_SLEEP enabled: "BUG: sleeping function +called from invalid context". + +ptp_convert_timestamp() acquires a mutex_t within a RCU read section. This +is illegal, because acquiring a mutex_t can result in voluntary scheduling +request which is not allowed within a RCU read section. + +Replace the RCU usage with SRCU where sleeping is allowed. + +Reported-by: Florian Zeitz +Closes: https://lore.kernel.org/all/00a8cce8-410e-4038-98af-49be6d93d7bd@schettke.com/ +Fixes: 67d93ffc0f3c ("ptp: vclock: use mutex to fix "sleep on atomic" bug") +Signed-off-by: Kurt Kanzenbach +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260529-vclock_rcu-v2-1-02a5531fab92@linutronix.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_vclock.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c +index 7d08ff3b30fc27..a88c4245937321 100644 +--- a/drivers/ptp/ptp_vclock.c ++++ b/drivers/ptp/ptp_vclock.c +@@ -19,6 +19,8 @@ static DEFINE_SPINLOCK(vclock_hash_lock); + + static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8); + ++DEFINE_STATIC_SRCU(vclock_srcu); ++ + static void ptp_vclock_hash_add(struct ptp_vclock *vclock) + { + spin_lock(&vclock_hash_lock); +@@ -37,7 +39,7 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock) + + spin_unlock(&vclock_hash_lock); + +- synchronize_rcu(); ++ synchronize_srcu(&vclock_srcu); + } + + static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +@@ -276,14 +278,16 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + { + unsigned int hash = vclock_index % HASH_SIZE(vclock_hash); + struct ptp_vclock *vclock; +- u64 ns; + u64 vclock_ns = 0; ++ int srcu_idx; ++ u64 ns; + + ns = ktime_to_ns(*hwtstamp); + +- rcu_read_lock(); ++ srcu_idx = srcu_read_lock(&vclock_srcu); + +- hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) { ++ hlist_for_each_entry_srcu(vclock, &vclock_hash[hash], vclock_hash_node, ++ srcu_read_lock_held(&vclock_srcu)) { + if (vclock->clock->index != vclock_index) + continue; + +@@ -294,7 +298,7 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + break; + } + +- rcu_read_unlock(); ++ srcu_read_unlock(&vclock_srcu, srcu_idx); + + return ns_to_ktime(vclock_ns); + } +-- +2.53.0 + diff --git a/queue-6.6/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch b/queue-6.6/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch new file mode 100644 index 0000000000..45ffd7a841 --- /dev/null +++ b/queue-6.6/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch @@ -0,0 +1,87 @@ +From dd12614d9fe07c5b69a599282360e960d8206b31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:11:44 -0400 +Subject: sctp: purge outqueue on stale COOKIE-ECHO handling + +From: Xin Long + +[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ] + +sctp_stream_update() is only invoked when the association is moved into +COOKIE_WAIT during association setup/reconfiguration. In this path, the +outbound stream scheduler state (stream->out_curr) is expected to be +clean, since no user data should have been transmitted yet unless the +state machine has already partially progressed. + +However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a +Stale Cookie ERROR is received, the association is rolled back from +COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already +have been queued and even bundled with the COOKIE-ECHO chunk. + +During the rollback, sctp_stream_update() frees the old stream table +and installs a new one, but it does not invalidate stream->out_curr. +As a result, out_curr may still point to a freed sctp_stream_out +entry from the previous stream state. + +Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on +stream->out_curr->ext, which can lead to use-after-free once the old +stream state has been released via sctp_stream_free(). + +This results in crashes such as (reported by Yuqi): + + BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140 + Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312 + CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted + 7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full) + sctp_sched_fcfs_dequeue+0x13a/0x140 + sctp_outq_flush+0x1603/0x33e0 + sctp_do_sm+0x31c9/0x5d30 + sctp_assoc_bh_rcv+0x392/0x6f0 + sctp_inq_push+0x1db/0x270 + sctp_rcv+0x138d/0x3c10 + +Fix this by fully purging the association outqueue when handling the +Stale Cookie case. This ensures all pending transmit and retransmit +state is dropped, and any scheduler cached pointers are invalidated, +making it safe to rebuild stream state during COOKIE_WAIT restart. + +Updating only stream->out_curr would be insufficient, since queued +and retransmittable data would still reference the old stream state and +trigger later use-after-free in dequeue paths. + +Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Reported-by: Yuqi Xu +Reported-by: Ren Wei +Signed-off-by: Xin Long +Link: https://patch.msgid.link/94318159b9052907a6cbb7256aee8b5f8dfbfccb.1780510304.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 5e9449b0c7907e..583d83dcb8426e 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2597,11 +2597,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + +- /* If we've sent any data bundled with COOKIE-ECHO we will need to +- * resend +- */ +- sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, +- SCTP_TRANSPORT(asoc->peer.primary_path)); ++ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index 239da65d79..8814bbb948 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -207,3 +207,38 @@ bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch rdma-rxe-fix-trying-to-register-non-static-key-in-rx.patch hwmon-pmbus-core-protect-regulator-operations-with-m.patch disable-wattribute-alias-for-clang-23-and-newer.patch +tee-optee-prevent-use-after-free-when-the-client-exi.patch +ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch +netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch +ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch +netfilter-synproxy-add-mutex-to-guard-hook-reference.patch +netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch +netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch +netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch +dm-cache-policy-smq-check-allocation-under-invalidat.patch +net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch +6lowpan-fix-off-by-one-in-multicast-context-address-.patch +drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch +pcnet32-stop-holding-device-spin-lock-during-napi_co.patch +net-annotate-sk-sk_write_space-for-udp-sockmap.patch +hsr-remove-warn_once-in-hsr_addr_is_self.patch +net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch +net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch +net-fec-fix-pinctrl-default-state-restore-order-on-r.patch +bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch +bluetooth-mgmt-validate-advertising-tlv-before-type-.patch +bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch +bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch +bluetooth-bnep-reject-short-frames-before-parsing.patch +bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch +bluetooth-mgmt-fix-backward-compatibility-with-users.patch +ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch +ptp-vclock-switch-from-rcu-to-srcu.patch +net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch +octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch +vxlan-vnifilter-send-notification-on-vni-add.patch +vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch +ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch +ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch +net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch +sctp-purge-outqueue-on-stale-cookie-echo-handling.patch diff --git a/queue-6.6/tee-optee-prevent-use-after-free-when-the-client-exi.patch b/queue-6.6/tee-optee-prevent-use-after-free-when-the-client-exi.patch new file mode 100644 index 0000000000..951d17496e --- /dev/null +++ b/queue-6.6/tee-optee-prevent-use-after-free-when-the-client-exi.patch @@ -0,0 +1,287 @@ +From 8d863acc11fd07ab88aeb2494b63588e7942d816 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:24:06 -0800 +Subject: tee: optee: prevent use-after-free when the client exits before the + supplicant + +From: Amirreza Zarrabi + +[ Upstream commit 387a926ee166814611acecb960207fe2f3c4fd3e ] + +Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the +client wait as killable so it can be interrupted during shutdown or +after a supplicant crash. This changes the original lifetime expectations: +the client task can now terminate while the supplicant is still processing +its request. + +If the client exits first it removes the request from its queue and +kfree()s it, while the request ID remains in supp->idr. A subsequent +lookup on the supplicant path then dereferences freed memory, leading to +a use-after-free. + +Serialise access to the request with supp->mutex: + + * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while + looking up and touching the request. + * Let optee_supp_thrd_req() notice that the client has terminated and + signal optee_supp_send() accordingly. + +With these changes the request cannot be freed while the supplicant still +has a reference, eliminating the race. + +Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") +Signed-off-by: Amirreza Zarrabi +Tested-by: Ox Yeh +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/supp.c | 107 +++++++++++++++++++++++++++------------ + 1 file changed, 74 insertions(+), 33 deletions(-) + +diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c +index d0f397c9024201..2386bbd38ce78b 100644 +--- a/drivers/tee/optee/supp.c ++++ b/drivers/tee/optee/supp.c +@@ -10,7 +10,11 @@ + struct optee_supp_req { + struct list_head link; + ++ int id; ++ + bool in_queue; ++ bool processed; ++ + u32 func; + u32 ret; + size_t num_params; +@@ -19,6 +23,9 @@ struct optee_supp_req { + struct completion c; + }; + ++/* It is temporary request used for revoked pending request in supp->idr. */ ++#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) ++ + void optee_supp_init(struct optee_supp *supp) + { + memset(supp, 0, sizeof(*supp)); +@@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) + { + int id; + struct optee_supp_req *req; +- struct optee_supp_req *req_tmp; + + mutex_lock(&supp->mutex); + +- /* Abort all request retrieved by supplicant */ ++ /* Abort all request */ + idr_for_each_entry(&supp->idr, req, id) { + idr_remove(&supp->idr, id); +- req->ret = TEEC_ERROR_COMMUNICATION; +- complete(&req->c); +- } ++ /* Skip if request was already marked invalid */ ++ if (IS_ERR(req)) ++ continue; + +- /* Abort all queued requests */ +- list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { +- list_del(&req->link); +- req->in_queue = false; ++ /* For queued requests where supplicant has not seen it */ ++ if (req->in_queue) { ++ list_del(&req->link); ++ req->in_queue = false; ++ } ++ ++ req->processed = true; + req->ret = TEEC_ERROR_COMMUNICATION; + complete(&req->c); + } +@@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + + /* Insert the request in the request list */ + mutex_lock(&supp->mutex); ++ req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); ++ if (req->id < 0) { ++ mutex_unlock(&supp->mutex); ++ kfree(req); ++ return TEEC_ERROR_OUT_OF_MEMORY; ++ } ++ + list_add_tail(&req->link, &supp->reqs); + req->in_queue = true; ++ req->processed = false; + mutex_unlock(&supp->mutex); + + /* Tell an eventual waiter there's a new request */ +@@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + if (wait_for_completion_killable(&req->c)) { + mutex_lock(&supp->mutex); + if (req->in_queue) { ++ /* Supplicant has not seen this request yet. */ ++ idr_remove(&supp->idr, req->id); + list_del(&req->link); + req->in_queue = false; ++ ++ ret = TEEC_ERROR_COMMUNICATION; ++ } else if (req->processed) { ++ /* ++ * Supplicant has processed this request. Ignore the ++ * kill signal for now and submit the result. req is not ++ * in supp->reqs (removed by supp_pop_entry()) nor in ++ * supp->idr (removed by supp_pop_req()). ++ */ ++ ret = req->ret; ++ } else { ++ /* ++ * Supplicant is in the middle of processing this ++ * request. Replace req with INVALID_REQ_PTR so that ++ * the ID remains busy, causing optee_supp_send() to ++ * fail on the next call to supp_pop_req() with this ID. ++ */ ++ idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); ++ ret = TEEC_ERROR_COMMUNICATION; + } ++ + mutex_unlock(&supp->mutex); +- req->ret = TEEC_ERROR_COMMUNICATION; ++ } else { ++ ret = req->ret; + } + +- ret = req->ret; + kfree(req); + + return ret; + } + + static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, +- int num_params, int *id) ++ int num_params) + { + struct optee_supp_req *req; + +@@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, + return ERR_PTR(-EINVAL); + } + +- *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); +- if (*id < 0) +- return ERR_PTR(-ENOMEM); +- + list_del(&req->link); + req->in_queue = false; + +@@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + struct optee_supp_req *req = NULL; +- int id; + size_t num_meta; + int rc; + +@@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + + while (true) { + mutex_lock(&supp->mutex); +- req = supp_pop_entry(supp, *num_params - num_meta, &id); ++ req = supp_pop_entry(supp, *num_params - num_meta); ++ if (req) ++ break; /* Keep mutex held. */ + mutex_unlock(&supp->mutex); + +- if (req) { +- if (IS_ERR(req)) +- return PTR_ERR(req); +- break; +- } +- + /* + * If we didn't get a request we'll block in + * wait_for_completion() to avoid needless spinning. +@@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + return -ERESTARTSYS; + } + ++ /* supp->mutex held and req != NULL. */ ++ ++ if (IS_ERR(req)) { ++ mutex_unlock(&supp->mutex); ++ return PTR_ERR(req); ++ } ++ + if (num_meta) { + /* + * tee-supplicant support meta parameters -> requsts can be +@@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + */ + param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; +- param->u.value.a = id; ++ param->u.value.a = req->id; + param->u.value.b = 0; + param->u.value.c = 0; + } else { +- mutex_lock(&supp->mutex); +- supp->req_id = id; +- mutex_unlock(&supp->mutex); ++ supp->req_id = req->id; + } + + *func = req->func; +@@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + ++ mutex_unlock(&supp->mutex); + return 0; + } + +@@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, + if (!req) + return ERR_PTR(-ENOENT); + ++ /* optee_supp_thrd_req() already returned to optee. */ ++ if (IS_ERR(req)) ++ goto failed_req; ++ + if ((num_params - nm) != req->num_params) + return ERR_PTR(-EINVAL); + ++ *num_meta = nm; ++failed_req: + idr_remove(&supp->idr, id); + supp->req_id = -1; +- *num_meta = nm; + + return req; + } +@@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + + mutex_lock(&supp->mutex); + req = supp_pop_req(supp, num_params, param, &num_meta); +- mutex_unlock(&supp->mutex); +- + if (IS_ERR(req)) { +- /* Something is wrong, let supplicant restart. */ ++ mutex_unlock(&supp->mutex); ++ /* Something is wrong, let supplicant handel it. */ + return PTR_ERR(req); + } + +@@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + } + } + req->ret = ret; +- ++ req->processed = true; + /* Let the requesting thread continue */ + complete(&req->c); ++ mutex_unlock(&supp->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch b/queue-6.6/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch new file mode 100644 index 0000000000..a82152c335 --- /dev/null +++ b/queue-6.6/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch @@ -0,0 +1,55 @@ +From 74189dbae90365313b57e12f51c47a3c1df59d02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:37 -0700 +Subject: vxlan: vnifilter: fix spurious notification on VNI update + +From: Andy Roulin + +[ Upstream commit 84683b5b60c7274e2c8f7f413d39d78d3db5540f ] + +When a VNI is re-added with the same attributes (e.g. same group or no +group), vxlan_vni_update() sends a spurious RTM_NEWTUNNEL notification +even though nothing changed. + +The bug is that 'if (changed)' tests whether the pointer is non-NULL, +not the bool value it points to. Since every caller passes a valid +pointer, the condition is always true and the notification fires +unconditionally. + +Fix by dereferencing the pointer: 'if (*changed)'. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 + # bridge vni add vni 1000 dev vxlan100 # spurious notification + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-3-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 1ab78a8bb9e011..272fa31ef07454 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -671,7 +671,7 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan, + if (ret) + return ret; + +- if (changed) ++ if (*changed) + vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/vxlan-vnifilter-send-notification-on-vni-add.patch b/queue-6.6/vxlan-vnifilter-send-notification-on-vni-add.patch new file mode 100644 index 0000000000..05b35416fe --- /dev/null +++ b/queue-6.6/vxlan-vnifilter-send-notification-on-vni-add.patch @@ -0,0 +1,69 @@ +From baffd49b11485678cf5de56cedeff4fbe8cb1a23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:36 -0700 +Subject: vxlan: vnifilter: send notification on VNI add + +From: Andy Roulin + +[ Upstream commit aa6ca1c5c338907817374b59f7551fd855a88754 ] + +When a new VNI is added to a vxlan device with vnifilter enabled, +no RTM_NEWTUNNEL notification is sent to userspace. This means +'bridge monitor vni' never shows VNI add events, even though +VNI delete events are reported correctly. + +The bug is in vxlan_vni_add(), where the notification is guarded by +'if (changed)'. The 'changed' flag is set by vxlan_vni_update_group() +only when the multicast group or remote IP is modified, but for a +new VNI added without a group (e.g. in L3 VxLAN interface scenarios), +the function returns early without setting changed=true. Since this +is a new VNI, the notification should be sent unconditionally. + +The notification is not guarded by the return value of +vxlan_vni_update_group() because, at this point, the VNI has already +been inserted into the hash table and list with no rollback on error. +The VNI will be visible in 'bridge vni show' regardless, so userspace +should be informed. This is consistent with vxlan_vni_del() which also +notifies unconditionally. + +The 'if (changed)' guard remains correct in vxlan_vni_update(), which +handles the case where a VNI already exists and is being re-added -- +there, we only want to notify if the group/remote actually changed. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 # no notification + # bridge vni delete vni 1000 dev vxlan100 # notification received + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Reported-by: Chirag Shah +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-2-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 06d19e90eadb59..1ab78a8bb9e011 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -769,8 +769,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, + err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed, + extack); + +- if (changed) +- vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); ++ vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return err; + } +-- +2.53.0 + diff --git a/queue-7.0/6lowpan-fix-off-by-one-in-multicast-context-address-.patch b/queue-7.0/6lowpan-fix-off-by-one-in-multicast-context-address-.patch new file mode 100644 index 0000000000..90058ca6a0 --- /dev/null +++ b/queue-7.0/6lowpan-fix-off-by-one-in-multicast-context-address-.patch @@ -0,0 +1,67 @@ +From 3a2b003a87afe82302489a2704319c2e61dc8a44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:18:01 +0800 +Subject: 6lowpan: fix off-by-one in multicast context address compression + +From: Yizhou Zhao + +[ Upstream commit 2a58899d11009bffc7b4b32a571858f381121837 ] + +The second memcpy in lowpan_iphc_mcast_ctx_addr_compress() uses +&data[1] as destination and &ipaddr->s6_addr[11] as source, but +both should be offset by one: &data[2] and &ipaddr->s6_addr[12] +respectively. + +This off-by-one has two consequences: +1. data[1] is overwritten with s6_addr[11], corrupting the RIID + field in the compressed multicast address +2. data[5] is never written, so uninitialized kernel stack memory + is transmitted over the network via lowpan_push_hc_data(), + leaking kernel stack contents + +The correct inline data layout must match what the decompression +function lowpan_uncompress_multicast_ctx_daddr() expects: + data[0..1] = s6_addr[1..2] (flags/scope + RIID) + data[2..5] = s6_addr[12..15] (group ID) + +Also zero-initialize the data array as a defensive measure against +similar bugs in the future. + +Fixes: 5609c185f24d ("6lowpan: iphc: add support for stateful compression") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Acked-by: Alexander Aring +Link: https://patch.msgid.link/20260527081806.42747-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/6lowpan/iphc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c +index e116d308a8df6d..37eaff3f7b6940 100644 +--- a/net/6lowpan/iphc.c ++++ b/net/6lowpan/iphc.c +@@ -1086,12 +1086,12 @@ static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, + const struct lowpan_iphc_ctx *ctx, + const struct in6_addr *ipaddr) + { +- u8 data[6]; ++ u8 data[6] = {}; + + /* flags/scope, reserved (RIID) */ + memcpy(data, &ipaddr->s6_addr[1], 2); + /* group ID */ +- memcpy(&data[1], &ipaddr->s6_addr[11], 4); ++ memcpy(&data[2], &ipaddr->s6_addr[12], 4); + lowpan_push_hc_data(hc_ptr, data, 6); + + return LOWPAN_IPHC_DAM_00; +-- +2.53.0 + diff --git a/queue-7.0/af_unix-fix-inq_len-update-problem-in-partial-read.patch b/queue-7.0/af_unix-fix-inq_len-update-problem-in-partial-read.patch new file mode 100644 index 0000000000..bd2dcbafbc --- /dev/null +++ b/queue-7.0/af_unix-fix-inq_len-update-problem-in-partial-read.patch @@ -0,0 +1,60 @@ +From a86c442ef196fc179f43a72e5760089d3aa479b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 19:36:39 +0800 +Subject: af_unix: Fix inq_len update problem in partial read + +From: Jianyu Li + +[ Upstream commit c1f07a7f2d47aeb9878301e7bb36bc1c2bc2be8e ] + +Currently inq_len is updated only when the whole skb is consumed. +If only part of the data is read, following SIOCINQ query would +get value greater than what actually left. + +This change update inq_len timely in unix_stream_read_generic(), +and adjust unix_stream_read_skb() accordingly to prevent +repetitive update. + +Fixes: f4e1fb04c123 ("af_unix: Use cached value for SOCK_STREAM in unix_inq_len().") +Signed-off-by: Jianyu Li +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260601113640.231897-2-jianyu.li@mediatek.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index c3d68bf26ce19b..62ec16c8ab2ede 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2882,7 +2882,7 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor) + return -EAGAIN; + } + +- WRITE_ONCE(u->inq_len, u->inq_len - skb->len); ++ WRITE_ONCE(u->inq_len, u->inq_len - unix_skb_len(skb)); + + #if IS_ENABLED(CONFIG_AF_UNIX_OOB) + if (skb == u->oob_skb) { +@@ -3059,11 +3059,12 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, + unix_detach_fds(&scm, skb); + } + +- if (unix_skb_len(skb)) +- break; +- + spin_lock(&sk->sk_receive_queue.lock); +- WRITE_ONCE(u->inq_len, u->inq_len - skb->len); ++ WRITE_ONCE(u->inq_len, u->inq_len - chunk); ++ if (unix_skb_len(skb)) { ++ spin_unlock(&sk->sk_receive_queue.lock); ++ break; ++ } + __skb_unlink(skb, &sk->sk_receive_queue); + spin_unlock(&sk->sk_receive_queue.lock); + +-- +2.53.0 + diff --git a/queue-7.0/arm-dts-gemini-fix-partition-offsets.patch b/queue-7.0/arm-dts-gemini-fix-partition-offsets.patch new file mode 100644 index 0000000000..518a21d74f --- /dev/null +++ b/queue-7.0/arm-dts-gemini-fix-partition-offsets.patch @@ -0,0 +1,54 @@ +From afc5f89fda6c6410c927f0721dfdce1f8e39f7d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 10:25:26 +0200 +Subject: ARM: dts: gemini: Fix partition offsets + +From: Linus Walleij + +[ Upstream commit 66ac2df408ede627aaae588d4ce7e611dd25b4f9 ] + +These FIS partition offsets were never right: the comment clearly +states the FIS index is at 0xfe0000 and 0x7f * 0x200000 is +0xfe0000. + +Tested on the iTian SQ201. + +Fixes: d88b11ef91b1 ("ARM: dts: Fix up SQ201 flash access") +Fixes: b5a923f8c739 ("ARM: dts: gemini: Switch to redboot partition parsing") +Signed-off-by: Linus Walleij +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/gemini/gemini-sl93512r.dts | 2 +- + arch/arm/boot/dts/gemini/gemini-sq201.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/gemini/gemini-sl93512r.dts b/arch/arm/boot/dts/gemini/gemini-sl93512r.dts +index 4992ec276de92e..341dec9b636a8b 100644 +--- a/arch/arm/boot/dts/gemini/gemini-sl93512r.dts ++++ b/arch/arm/boot/dts/gemini/gemini-sl93512r.dts +@@ -146,7 +146,7 @@ flash@30000000 { + partitions { + compatible = "redboot-fis"; + /* Eraseblock at 0xfe0000 */ +- fis-index-block = <0x1fc>; ++ fis-index-block = <0x7f>; + }; + }; + +diff --git a/arch/arm/boot/dts/gemini/gemini-sq201.dts b/arch/arm/boot/dts/gemini/gemini-sq201.dts +index f8c6f6e5cdea6a..bfd1e8581ad67c 100644 +--- a/arch/arm/boot/dts/gemini/gemini-sq201.dts ++++ b/arch/arm/boot/dts/gemini/gemini-sq201.dts +@@ -134,7 +134,7 @@ flash@30000000 { + partitions { + compatible = "redboot-fis"; + /* Eraseblock at 0xfe0000 */ +- fis-index-block = <0x1fc>; ++ fis-index-block = <0x7f>; + }; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch b/queue-7.0/arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch new file mode 100644 index 0000000000..4552f2a05d --- /dev/null +++ b/queue-7.0/arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch @@ -0,0 +1,56 @@ +From 7f160e39baa43187760ad16bf5283a35df59b8ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:53:29 +0200 +Subject: ARM: dts: microchip: sam9x7: fix GMAC clock configuration + +From: Mihai Sain + +[ Upstream commit 765aaba18413a66f6c8fe8416336ca9b3dd98a79 ] + +The GMAC node incorrectly listed four clocks, including a separate tx_clk +and a TSU GCK clock sourced from ID 67. According to the SAM9X7 clocking +scheme, the GMAC uses only three clocks: HCLK, PCLK, and the TSU GCK +derived from the GMAC peripheral clock (ID 24). + +Remove the unused tx_clk, update the clock-names accordingly, and correct +the assigned clock to use GCK 24 instead of GCK 67. This aligns the device +tree with the actual hardware clock topology and prevents misconfiguration +of the GMAC clock tree. + +[root@SAM9X75 ~]$ cat /sys/kernel/debug/clk/clk_summary | grep gmac + +gmac_gclk 1 1 1 266666666 0 0 50000 Y f802c000.ethernet tsu_clk + f802c000.ethernet tsu_clk +gmac_clk 2 2 0 266666666 0 0 50000 Y f802c000.ethernet hclk + f802c000.ethernet pclk + +Fixes: 41af45af8bc3 ("ARM: dts: at91: sam9x7: add device tree for SoC") +Signed-off-by: Mihai Sain +Link: https://lore.kernel.org/r/20260309075329.1528-5-mihai.sain@microchip.com +[claudiu.beznea: massaged the patch description] +Signed-off-by: Claudiu Beznea +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/microchip/sam9x7.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/microchip/sam9x7.dtsi b/arch/arm/boot/dts/microchip/sam9x7.dtsi +index d242d7a934d0fa..c680a5033b6b4e 100644 +--- a/arch/arm/boot/dts/microchip/sam9x7.dtsi ++++ b/arch/arm/boot/dts/microchip/sam9x7.dtsi +@@ -990,9 +990,9 @@ gmac: ethernet@f802c000 { + <62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */ + <63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */ + <64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */ +- clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>, <&pmc PMC_TYPE_GCK 67>; +- clock-names = "hclk", "pclk", "tx_clk", "tsu_clk"; +- assigned-clocks = <&pmc PMC_TYPE_GCK 67>; ++ clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>; ++ clock-names = "hclk", "pclk", "tsu_clk"; ++ assigned-clocks = <&pmc PMC_TYPE_GCK 24>; + assigned-clock-rates = <266666666>; + status = "disabled"; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch b/queue-7.0/arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch new file mode 100644 index 0000000000..014efa8a75 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch @@ -0,0 +1,53 @@ +From 7f0e8e0b7952a2ac957d31089cbe48677c6b42ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 21:53:37 -0300 +Subject: arm64: dts: qcom: x1-dell-thena: remove i2c20 (battery SMBus) and + reserve its pins + +From: Val Packett + +[ Upstream commit 4b15b03166cc5d28e9912287b1f9b6607c8710ec ] + +i2c20 is used by the battmgr service on the ADSP to communicate with the +SBS interface of the battery. Initializing it from Linux would break the +battmgr functionality when booted in EL2. Mark those pins as reserved. + +Fixes: e7733b42111c ("arm64: dts: qcom: Add support for Dell Inspiron 7441 / Latitude 7455") +Reviewed-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312005731.12488-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +index 217ca8c7d81dae..488129bb1ae198 100644 +--- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +@@ -982,12 +982,6 @@ &i2c8 { + status = "okay"; + }; + +-&i2c20 { +- clock-frequency = <400000>; +- +- status = "okay"; +-}; +- + &lpass_tlmm { + spkr_01_sd_n_active: spkr-01-sd-n-active-state { + pins = "gpio12"; +@@ -1308,6 +1302,7 @@ right_tweeter: speaker@0,1 { + &tlmm { + gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */ + <76 4>, /* SPI19 (TZ Protected) */ ++ <80 2>, /* I2C20 (Battery SMBus) */ + <238 1>; /* UFS Reset */ + + cam_rgb_default: cam-rgb-default-state { +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch b/queue-7.0/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch new file mode 100644 index 0000000000..9c7c9e88e8 --- /dev/null +++ b/queue-7.0/bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch @@ -0,0 +1,72 @@ +From 6d6e869cb048ce84601bd21f0c8d40f0b14e9ea7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:39:53 +0800 +Subject: Bluetooth: bnep: fix incorrect length parsing in bnep_rx_frame() + extension handling + +From: Dudu Lu + +[ Upstream commit 72b8deccff17a7644e0367e1aaf1a36cfb014324 ] + +In bnep_rx_frame(), the BNEP_FILTER_NET_TYPE_SET and +BNEP_FILTER_MULTI_ADDR_SET extension header parsing has two bugs: + +1) The 2-byte length field is read with *(u16 *)(skb->data + 1), which + performs a native-endian read. The BNEP protocol specifies this field + in big-endian (network byte order), and the same file correctly uses + get_unaligned_be16() for the identical fields in + bnep_ctrl_set_netfilter() and bnep_ctrl_set_mcfilter(). + +2) The length is multiplied by 2, but unlike BNEP_SETUP_CONN_REQ where + the length byte counts UUID pairs (requiring * 2 for two UUIDs per + entry), the filter extension length field already represents the total + data size in bytes. This is confirmed by bnep_ctrl_set_netfilter() + which reads the same field as a byte count and divides by 4 to get + the number of filter entries. + + The bogus * 2 means skb_pull advances twice as far as it should, + either dropping valid data from the next header or causing the pull + to fail entirely when the doubled length exceeds the remaining skb. + +Fix by splitting the pull into two steps: first use skb_pull_data() to +safely pull and validate the 3-byte fixed header (ctrl type + length), +then pull the variable-length data using the properly decoded length. + +Fixes: bf8b9a9cb77b ("Bluetooth: bnep: Add support to extended headers of control frames") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: 6770d3a8acdf ("Bluetooth: bnep: reject short frames before parsing") +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index b3cef7a4db5412..0de5df690bd0b2 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -330,11 +330,18 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + goto badframe; + break; + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: +- /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */ +- if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2)) ++ case BNEP_FILTER_NET_TYPE_SET: { ++ u8 *hdr; ++ ++ /* Pull ctrl type (1 b) + len (2 b) */ ++ hdr = skb_pull_data(skb, 3); ++ if (!hdr) ++ goto badframe; ++ /* Pull data (len bytes); length is big-endian */ ++ if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) + goto badframe; + break; ++ } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-bnep-reject-short-frames-before-parsing.patch b/queue-7.0/bluetooth-bnep-reject-short-frames-before-parsing.patch new file mode 100644 index 0000000000..15943a3517 --- /dev/null +++ b/queue-7.0/bluetooth-bnep-reject-short-frames-before-parsing.patch @@ -0,0 +1,170 @@ +From 69a2362aa638fabd25463cfe8d2bc07eb3fbd719 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 11:22:09 +0800 +Subject: Bluetooth: bnep: reject short frames before parsing + +From: Zhang Cen + +[ Upstream commit 6770d3a8acdf9151769180cc3710346c4cfbe6f0 ] + +A BNEP peer can send a short BNEP SDU. bnep_rx_frame() reads the +packet type byte immediately and, for control packets, reads the control +opcode and setup UUID-size byte before proving that those bytes are +present. bnep_rx_control() also dereferences the control opcode without +rejecting an empty control payload. + +Use skb_pull_data() for the fixed fields in bnep_rx_frame() so a NULL +return gates each dereference. Split the control handler so the frame +path can pass an opcode that has already been pulled, and keep the +byte-buffer wrapper for extension control payloads. + +For BNEP_SETUP_CONN_REQ, name the UUID-size byte before pulling the +setup payload. struct bnep_setup_conn_req carries destination and source +service UUIDs after that byte, each uuid_size bytes, so the parser now +documents that tuple explicitly instead of leaving the pull length as an +opaque multiplication. + +Validation reproduced this kernel report: +KASAN slab-out-of-bounds in bnep_rx_frame.isra.0+0x130c/0x1790 +The buggy address belongs to the object at ffff88800c0f7908 which belongs +to the cache kmalloc-8 of size 8 +The buggy address is located 0 bytes to the right of allocated 1-byte +region [ffff88800c0f7908, ffff88800c0f7909) +Read of size 1 +Call trace: + dump_stack_lvl+0xb3/0x140 (?:?) + print_address_description+0x57/0x3a0 (?:?) + bnep_rx_frame+0x130c/0x1790 (net/bluetooth/bnep/core.c:306) + print_report+0xb9/0x2b0 (?:?) + __virt_addr_valid+0x1ba/0x3a0 (?:?) + srso_alias_return_thunk+0x5/0xfbef5 (?:?) + kasan_addr_to_slab+0x21/0x60 (?:?) + kasan_report+0xe0/0x110 (?:?) + process_one_work+0xfce/0x17e0 (kernel/workqueue.c:3200) + worker_thread+0x65c/0xe40 (?:?) + __kthread_parkme+0x184/0x230 (?:?) + kthread+0x35e/0x470 (?:?) + _raw_spin_unlock_irq+0x28/0x50 (?:?) + ret_from_fork+0x586/0x870 (?:?) + __switch_to+0x74f/0xdc0 (?:?) + ret_from_fork_asm+0x1a/0x30 (?:?) + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/bnep/core.c | 57 ++++++++++++++++++++++++--------------- + 1 file changed, 36 insertions(+), 21 deletions(-) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index 0de5df690bd0b2..5c5f53ff30e8e5 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -206,14 +206,11 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) + return 0; + } + +-static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++static int bnep_rx_control_cmd(struct bnep_session *s, u8 cmd, void *data, ++ int len) + { +- u8 cmd = *(u8 *)data; + int err = 0; + +- data++; +- len--; +- + switch (cmd) { + case BNEP_CMD_NOT_UNDERSTOOD: + case BNEP_SETUP_CONN_RSP: +@@ -254,6 +251,14 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) + return err; + } + ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ if (len < 1) ++ return -EILSEQ; ++ ++ return bnep_rx_control_cmd(s, *(u8 *)data, data + 1, len - 1); ++} ++ + static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) + { + struct bnep_ext_hdr *h; +@@ -299,19 +304,26 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + { + struct net_device *dev = s->dev; + struct sk_buff *nskb; ++ u8 *data; + u8 type, ctrl_type; + + dev->stats.rx_bytes += skb->len; + +- type = *(u8 *) skb->data; +- skb_pull(skb, 1); +- ctrl_type = *(u8 *)skb->data; ++ data = skb_pull_data(skb, sizeof(type)); ++ if (!data) ++ goto badframe; ++ type = *data; + + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) + goto badframe; + + if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { +- if (bnep_rx_control(s, skb->data, skb->len) < 0) { ++ data = skb_pull_data(skb, sizeof(ctrl_type)); ++ if (!data) ++ goto badframe; ++ ctrl_type = *data; ++ ++ if (bnep_rx_control_cmd(s, ctrl_type, skb->data, skb->len) < 0) { + dev->stats.tx_errors++; + kfree_skb(skb); + return 0; +@@ -324,24 +336,27 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + + /* Verify and pull ctrl message since it's already processed */ + switch (ctrl_type) { +- case BNEP_SETUP_CONN_REQ: +- /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */ +- if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2)) ++ case BNEP_SETUP_CONN_REQ: { ++ u8 uuid_size; ++ ++ /* Pull uuid_size and the dst/src service UUIDs. */ ++ data = skb_pull_data(skb, sizeof(uuid_size)); ++ if (!data) ++ goto badframe; ++ uuid_size = *data; ++ if (!skb_pull(skb, uuid_size + uuid_size)) + goto badframe; + break; ++ } + case BNEP_FILTER_MULTI_ADDR_SET: +- case BNEP_FILTER_NET_TYPE_SET: { +- u8 *hdr; +- +- /* Pull ctrl type (1 b) + len (2 b) */ +- hdr = skb_pull_data(skb, 3); +- if (!hdr) ++ case BNEP_FILTER_NET_TYPE_SET: ++ /* Pull: len (2 b), data (len bytes) */ ++ data = skb_pull_data(skb, sizeof(u16)); ++ if (!data) + goto badframe; +- /* Pull data (len bytes); length is big-endian */ +- if (!skb_pull(skb, get_unaligned_be16(&hdr[1]))) ++ if (!skb_pull(skb, get_unaligned_be16(data))) + goto badframe; + break; +- } + default: + kfree_skb(skb); + return 0; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch b/queue-7.0/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch new file mode 100644 index 0000000000..78ba7806c8 --- /dev/null +++ b/queue-7.0/bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch @@ -0,0 +1,58 @@ +From 97c2378cab696f413155914b3ddfc82def7b9ae5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 08:54:26 +0530 +Subject: Bluetooth: fix memory leak in error path of hci_alloc_dev() + +From: Bharath Reddy + +[ Upstream commit 37b3009bf5976e8ab77c8b9a9bc3bbd7ff49e37f ] + +Early failures in Bluetooth HCI UART configuration leak SRCU percpu +memory. + +When device initialization fails before hci_register_dev() completes, +the HCI_UNREGISTER flag is never set. As a result, when the device +reference count reaches zero, bt_host_release() evaluates this flag as +false and falls back to a direct kfree(hdev). + +Because hci_release_dev() is bypassed, the SRCU struct initialized +early in hci_alloc_dev() is never cleaned up, resulting in a leak of +percpu memory. + +Fix the leak by explicitly calling cleanup_srcu_struct() in the +fallback (unregistered) branch of bt_host_release() before freeing +the device. + +Reported-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=535ecc844591e50588a5 +Tested-by: syzbot+535ecc844591e50588a5@syzkaller.appspotmail.com +Fixes: 1d6123102e9f ("Bluetooth: hci_core: Fix use-after-free in vhci_flush()") +Signed-off-by: Bharath Reddy +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sysfs.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c +index 041ce9adc378ae..8957ce7c21b76c 100644 +--- a/net/bluetooth/hci_sysfs.c ++++ b/net/bluetooth/hci_sysfs.c +@@ -83,10 +83,12 @@ static void bt_host_release(struct device *dev) + { + struct hci_dev *hdev = to_hci_dev(dev); + +- if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) ++ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + hci_release_dev(hdev); +- else ++ } else { ++ cleanup_srcu_struct(&hdev->srcu); + kfree(hdev); ++ } + module_put(THIS_MODULE); + } + +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-iso-fix-a-use-after-free-of-the-hci_conn-p.patch b/queue-7.0/bluetooth-iso-fix-a-use-after-free-of-the-hci_conn-p.patch new file mode 100644 index 0000000000..50d9cd2286 --- /dev/null +++ b/queue-7.0/bluetooth-iso-fix-a-use-after-free-of-the-hci_conn-p.patch @@ -0,0 +1,48 @@ +From a7e58d3d636a0a157ef84216335f4832960d0d10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 14:52:09 -0400 +Subject: Bluetooth: ISO: Fix a use-after-free of the hci_conn pointer + +From: Luiz Augusto von Dentz + +[ Upstream commit f50331f2a1441ec49988832c3a95f2edacc47322 ] + +In iso_sock_rebind_bc(), the bis pointer is cached, then the socket lock is +dropped: + bis = iso_pi(sk)->conn->hcon; + /* Release the socket before lookups since that requires hci_dev_lock + * which shall not be acquired while holding sock_lock for proper + * ordering. + */ + release_sock(sk); + hci_dev_lock(bis->hdev); + +During the unlocked window, could a concurrent close() destroy the connection +and free the bis structure, causing hci_dev_lock(bis->hdev) to access memory +after it is freed, fix this by using the hdev reference which was safely +acquired via iso_conn_get_hdev(). + +Fixes: d3413703d5f8 ("Bluetooth: ISO: Add support to bind to trigger PAST") +Reported-by: Sashiko +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 2363b6135c6f1b..05a3f1e554fe67 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -1090,7 +1090,7 @@ static int iso_sock_rebind_bc(struct sock *sk, struct sockaddr_iso *sa, + * ordering. + */ + release_sock(sk); +- hci_dev_lock(bis->hdev); ++ hci_dev_lock(hdev); + lock_sock(sk); + + if (!iso_pi(sk)->conn || iso_pi(sk)->conn->hcon != bis) { +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch b/queue-7.0/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch new file mode 100644 index 0000000000..26d6d7d714 --- /dev/null +++ b/queue-7.0/bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch @@ -0,0 +1,157 @@ +From c57b2f2f5ec21a8f73d63b92cdca6f9069a6cfae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 20:19:07 +0900 +Subject: Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls + +From: SeungJu Cheon + +[ Upstream commit 9ca7053d6215d89c33f28893bfd1625a32919d3f ] + +iso_connect_bis(), iso_connect_cis(), iso_listen_bis(), and +iso_conn_big_sync() call hci_get_route() using iso_pi(sk)->dst, +iso_pi(sk)->src, and iso_pi(sk)->src_type without holding lock_sock(). + +These fields may be modified concurrently by connect() or setsockopt() +on the same socket, resulting in data-races reported by KCSAN. + +Fix this by snapshotting the required fields under lock_sock() before +calling hci_get_route(). + +BUG: KCSAN: data-race in memcmp+0x45/0xb0 + +race at unknown origin, with read to 0xffff8880122135cf of 1 bytes +by task 333 on cpu 1: + memcmp+0x45/0xb0 + hci_get_route+0x27e/0x490 + iso_connect_cis+0x4c/0xa10 + iso_sock_connect+0x60e/0xb30 + __sys_connect_file+0xbd/0xe0 + __sys_connect+0xe0/0x110 + __x64_sys_connect+0x40/0x50 + x64_sys_call+0xcad/0x1c60 + do_syscall_64+0x133/0x590 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: 241f51931c35 ("Bluetooth: ISO: Avoid circular locking dependency") +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 60 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 44 insertions(+), 16 deletions(-) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 05a3f1e554fe67..34e4803313d130 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -337,12 +337,20 @@ static int iso_connect_bis(struct sock *sk) + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type, bc_sid; + int err; + +- BT_DBG("%pMR (SID 0x%2.2x)", &iso_pi(sk)->src, iso_pi(sk)->bc_sid); ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ bc_sid = iso_pi(sk)->bc_sid; ++ release_sock(sk); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ BT_DBG("%pMR (SID 0x%2.2x)", &src, bc_sid); ++ ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -434,12 +442,19 @@ static int iso_connect_cis(struct sock *sk) + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type; + int err; + +- BT_DBG("%pMR -> %pMR", &iso_pi(sk)->src, &iso_pi(sk)->dst); ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ release_sock(sk); ++ ++ BT_DBG("%pMR -> %pMR", &src, &dst); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -1220,18 +1235,25 @@ static int iso_sock_connect(struct socket *sock, struct sockaddr_unsized *addr, + + static int iso_listen_bis(struct sock *sk) + { +- struct hci_dev *hdev; +- int err = 0; + struct iso_conn *conn; + struct hci_conn *hcon; ++ struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type, bc_sid; ++ int err = 0; ++ ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ bc_sid = iso_pi(sk)->bc_sid; ++ release_sock(sk); + +- BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src, +- &iso_pi(sk)->dst, iso_pi(sk)->bc_sid); ++ BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &src, &dst, bc_sid); + + write_lock(&iso_sk_list.lock); + +- if (__iso_get_sock_listen_by_sid(&iso_pi(sk)->src, &iso_pi(sk)->dst, +- iso_pi(sk)->bc_sid)) ++ if (__iso_get_sock_listen_by_sid(&src, &dst, bc_sid)) + err = -EADDRINUSE; + + write_unlock(&iso_sk_list.lock); +@@ -1239,8 +1261,7 @@ static int iso_listen_bis(struct sock *sk) + if (err) + return err; + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + if (!hdev) + return -EHOSTUNREACH; + +@@ -1576,9 +1597,16 @@ static void iso_conn_big_sync(struct sock *sk) + { + int err; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ u8 src_type; ++ ++ lock_sock(sk); ++ bacpy(&src, &iso_pi(sk)->src); ++ bacpy(&dst, &iso_pi(sk)->dst); ++ src_type = iso_pi(sk)->src_type; ++ release_sock(sk); + +- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, +- iso_pi(sk)->src_type); ++ hdev = hci_get_route(&dst, &src, src_type); + + if (!hdev) + return; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch b/queue-7.0/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch new file mode 100644 index 0000000000..26fa1cd6b5 --- /dev/null +++ b/queue-7.0/bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch @@ -0,0 +1,36 @@ +From 0ff382f753907d73688003fbe6dbc5edc86a9a95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 14:45:42 -0400 +Subject: Bluetooth: ISO: Fix not releasing hdev reference on iso_conn_big_sync + +From: Luiz Augusto von Dentz + +[ Upstream commit 5cbf290b79351971f20c7a533247e8d58a3f970c ] + +hci_get_route() returns a reference-counted hci_dev pointer via +hci_dev_hold(). The function exits normally or with an error without ever +releasing it. + +Fixes: 07a9342b94a9 ("Bluetooth: ISO: Send BIG Create Sync via hci_sync") +Reported-by: Sashiko +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index a6bd608cbda69d..2363b6135c6f1b 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -1603,6 +1603,7 @@ static void iso_conn_big_sync(struct sock *sk) + + release_sock(sk); + hci_dev_unlock(hdev); ++ hci_dev_put(hdev); + } + + static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-mgmt-fix-backward-compatibility-with-users.patch b/queue-7.0/bluetooth-mgmt-fix-backward-compatibility-with-users.patch new file mode 100644 index 0000000000..d17cea17ea --- /dev/null +++ b/queue-7.0/bluetooth-mgmt-fix-backward-compatibility-with-users.patch @@ -0,0 +1,43 @@ +From cf931e2c7a943feeb0868202fe89f320fd391d9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:48:34 -0400 +Subject: Bluetooth: MGMT: Fix backward compatibility with userspace + +From: Luiz Augusto von Dentz + +[ Upstream commit 149324fc762c2a7acef9c26790566f81f475e51f ] + +bluetoothd has a bug with makes it send extra bytes as part of +MGMT_OP_ADD_EXT_ADV_DATA which are now being checked to be the +exact the expected length, relax this so only when the expected +length is greater than the data length to cause an error since +that would result in accessing invalid memory, otherwise just +ignore the extra bytes. + +Link: https://lore.kernel.org/linux-bluetooth/20260602204749.210857-1-luiz.dentz@gmail.com/T/#u +Fixes: d3f7d17960ed ("Bluetooth: MGMT: validate Add Extended Advertising Data length") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 027b266ccc747c..f4aa814a039759 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -9114,8 +9114,9 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data, + + BT_DBG("%s", hdev->name); + +- expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len); +- if (expected_len != data_len) ++ expected_len = struct_size(cp, data, cp->adv_data_len + ++ cp->scan_rsp_len); ++ if (expected_len > data_len) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_INVALID_PARAMS); + +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch b/queue-7.0/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch new file mode 100644 index 0000000000..84afcfcff3 --- /dev/null +++ b/queue-7.0/bluetooth-mgmt-validate-advertising-tlv-before-type-.patch @@ -0,0 +1,73 @@ +From 7b42deebfbef9a0efb3b72a0e7393f00ff1241e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 17:45:06 +0800 +Subject: Bluetooth: MGMT: validate advertising TLV before type checks + +From: Zhang Cen + +[ Upstream commit de23fb62259aa01d294f77238ae3b835eb674413 ] + +tlv_data_is_valid() reads each advertising data field length from +data[i], then inspects data[i + 1] for managed EIR types before +checking that the current field still fits inside the supplied buffer. + +A malformed field whose length byte is the last byte of the buffer can +therefore make the parser read one byte past the advertising data. + +KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING +request reached that path: + + BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid() + Read of size 1 + Call trace: + tlv_data_is_valid() + add_advertising() + hci_mgmt_cmd() + hci_sock_sendmsg() + +Move the existing element-length check before any type-octet inspection +so each non-empty element is proven to contain its type byte before the +parser looks at data[i + 1]. + +Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check") +Reviewed-by: Paul Menzel +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index de5bd6b637b205..027b266ccc747c 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -8638,6 +8638,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (!cur_len) + continue; + ++ /* If the current field length would exceed the total data ++ * length, then it's invalid. ++ */ ++ if (i + cur_len >= len) ++ return false; ++ + if (data[i + 1] == EIR_FLAGS && + (!is_adv_data || flags_managed(adv_flags))) + return false; +@@ -8654,12 +8660,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, + if (data[i + 1] == EIR_APPEARANCE && + appearance_managed(adv_flags)) + return false; +- +- /* If the current field length would exceed the total data +- * length, then it's invalid. +- */ +- if (i + cur_len >= len) +- return false; + } + + return true; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch b/queue-7.0/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch new file mode 100644 index 0000000000..442e6baa2b --- /dev/null +++ b/queue-7.0/bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch @@ -0,0 +1,126 @@ +From d0766b2711ddc80630c3f27eaf06fab67655d30d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 15:56:41 +0800 +Subject: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() + +From: Zhang Cen + +[ Upstream commit 43c441edacf953b39517a44f5e5e10a93618b226 ] + +rfcomm_get_sock_by_channel() scans rfcomm_sk_list under the list lock, +but returns the selected listener after dropping that lock without +taking a reference. rfcomm_connect_ind() then locks the listener, +queues a child socket on it, and may notify it after unlocking it. + +The buggy scenario involves two paths, with each column showing the +order within that path: + +rfcomm_connect_ind(): listener close: + 1. Find parent in 1. close() enters + rfcomm_get_sock_by_channel() rfcomm_sock_release(). + 2. Drop rfcomm_sk_list.lock 2. rfcomm_sock_shutdown() + without pinning parent. closes the listener. + 3. Call lock_sock(parent) and 3. rfcomm_sock_kill() + bt_accept_enqueue(parent, unlinks and puts parent. + sk, true). + 4. Read parent flags and may 4. parent can be freed. + call sk_state_change(). + +If close wins the race, parent can be freed before +rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or the +deferred-setup callback. + +Take a reference on the listener before leaving rfcomm_sk_list.lock. +After lock_sock() succeeds, recheck that it is still in BT_LISTEN +before queueing a child, cache the deferred-setup bit while the parent +is locked, and drop the reference after the last parent use. + +KASAN reported a slab-use-after-free in lock_sock_nested() from +rfcomm_connect_ind(), with the freeing stack going through +rfcomm_sock_kill() and rfcomm_sock_release(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Zhang Cen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index bd7d959c6e9eb8..805ed5d28ed668 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) + } + + /* Find socket with channel and source bdaddr. +- * Returns closest match. ++ * Returns closest match with an extra reference held. + */ + static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) + { +@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t * + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ +- if (!bacmp(&rfcomm_pi(sk)->src, src)) ++ if (!bacmp(&rfcomm_pi(sk)->src, src)) { ++ sock_hold(sk); + break; ++ } + + /* Closest match */ +- if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) ++ if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) { ++ if (sk1) ++ sock_put(sk1); ++ + sk1 = sk; ++ sock_hold(sk1); ++ } + } + } + ++ if (sk && sk1) ++ sock_put(sk1); ++ + read_unlock(&rfcomm_sk_list.lock); + + return sk ? sk : sk1; +@@ -941,6 +951,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + { + struct sock *sk, *parent; + bdaddr_t src, dst; ++ bool defer_setup = false; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); +@@ -954,6 +965,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + + lock_sock(parent); + ++ if (parent->sk_state != BT_LISTEN) ++ goto done; ++ ++ defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -981,9 +997,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * + done: + release_sock(parent); + +- if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) ++ if (defer_setup) + parent->sk_state_change(parent); + ++ sock_put(parent); ++ + return result; + } + +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch b/queue-7.0/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch new file mode 100644 index 0000000000..d5c7e23fa6 --- /dev/null +++ b/queue-7.0/bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch @@ -0,0 +1,167 @@ +From c7f496bb94ed3d52beae4bc4143ffee4cc879bc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:04:43 +0900 +Subject: Bluetooth: RFCOMM: validate skb length in MCC handlers + +From: SeungJu Cheon + +[ Upstream commit 23882b828c3c8c51d0c946446a396b10abb3b16b ] + +The RFCOMM MCC handlers cast skb->data to protocol-specific structs +without validating skb->len first. A malicious remote device can send +truncated MCC frames and trigger out-of-bounds reads in these handlers. + +Fix this by using skb_pull_data() to validate and access the required +data before dereferencing it. + +rfcomm_recv_rpn() requires special handling since ETSI TS 07.10 allows +1-byte RPN requests. Handle this by validating only the DLCI byte first, +and validating the full struct only when len > 1. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Suggested-by: Muhammad Bilal +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/rfcomm/core.c | 67 +++++++++++++++++++++++++++---------- + 1 file changed, 49 insertions(+), 18 deletions(-) + +diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c +index 611a9a94151ecf..33d4d6fdf8681f 100644 +--- a/net/bluetooth/rfcomm/core.c ++++ b/net/bluetooth/rfcomm/core.c +@@ -1431,10 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) + + static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_pn *pn; + struct rfcomm_dlc *d; +- u8 dlci = pn->dlci; ++ u8 dlci; ++ ++ pn = skb_pull_data(skb, sizeof(*pn)); ++ if (!pn) ++ return -EILSEQ; + ++ dlci = pn->dlci; + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) +@@ -1483,8 +1488,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) + + static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) + { +- struct rfcomm_rpn *rpn = (void *) skb->data; +- u8 dlci = __get_dlci(rpn->dlci); ++ struct rfcomm_rpn *rpn; ++ u8 dlci; + + u8 bit_rate = 0; + u8 data_bits = 0; +@@ -1495,15 +1500,16 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + u8 xoff_char = 0; + u16 rpn_mask = RFCOMM_RPN_PM_ALL; + +- BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", +- dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, +- rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ if (len == 1) { ++ rpn = skb_pull_data(skb, 1); ++ if (!rpn) ++ return -EILSEQ; + +- if (!cr) +- return 0; ++ dlci = __get_dlci(rpn->dlci); ++ ++ if (!cr) ++ return 0; + +- if (len == 1) { +- /* This is a request, return default (according to ETSI TS 07.10) settings */ + bit_rate = RFCOMM_RPN_BR_9600; + data_bits = RFCOMM_RPN_DATA_8; + stop_bits = RFCOMM_RPN_STOP_1; +@@ -1514,6 +1520,19 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + goto rpn_out; + } + ++ rpn = skb_pull_data(skb, sizeof(*rpn)); ++ if (!rpn) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rpn->dlci); ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ + /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit, + * no parity, no flow control lines, normal XON/XOFF chars */ + +@@ -1589,9 +1608,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ + + static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_rls *rls = (void *) skb->data; +- u8 dlci = __get_dlci(rls->dlci); ++ struct rfcomm_rls *rls; ++ u8 dlci; + ++ rls = skb_pull_data(skb, sizeof(*rls)); ++ if (!rls) ++ return -EILSEQ; ++ ++ dlci = __get_dlci(rls->dlci); + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) +@@ -1608,10 +1632,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) + { +- struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_msc *msc; + struct rfcomm_dlc *d; +- u8 dlci = __get_dlci(msc->dlci); ++ u8 dlci; ++ ++ msc = skb_pull_data(skb, sizeof(*msc)); ++ if (!msc) ++ return -EILSEQ; + ++ dlci = __get_dlci(msc->dlci); + BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); + + d = rfcomm_dlc_get(s, dlci); +@@ -1644,17 +1673,19 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb + + static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) + { +- struct rfcomm_mcc *mcc = (void *) skb->data; ++ struct rfcomm_mcc *mcc; + u8 type, cr, len; + ++ mcc = skb_pull_data(skb, sizeof(*mcc)); ++ if (!mcc) ++ return -EILSEQ; ++ + cr = __test_cr(mcc->type); + type = __get_mcc_type(mcc->type); + len = __get_mcc_len(mcc->len); + + BT_DBG("%p type 0x%x cr %d", s, type, cr); + +- skb_pull(skb, 2); +- + switch (type) { + case RFCOMM_PN: + rfcomm_recv_pn(s, cr, skb); +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch b/queue-7.0/bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch new file mode 100644 index 0000000000..9c832a331c --- /dev/null +++ b/queue-7.0/bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch @@ -0,0 +1,96 @@ +From c986675b2cfe2eb5eecbae3df87716a828494a7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 20:19:08 +0900 +Subject: Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect + +From: SeungJu Cheon + +[ Upstream commit 4847c5bca22227100ae69e96af86618b6fd2671f ] + +sco_sock_connect() copies the destination address into sco_pi(sk)->dst +under lock_sock(), then releases the lock and calls sco_connect(), +which reads dst, src, setting, and codec without holding lock_sock() in +hci_get_route() and hci_connect_sco(). + +These fields may be modified concurrently by connect(), bind(), or +setsockopt() on the same socket, resulting in data-races reported by +KCSAN. + +Fix this by snapshotting dst, src, setting, and codec under lock_sock() +at the start of sco_connect() before passing them to hci_get_route() +and hci_connect_sco(). + +BUG: KCSAN: data-race in memcmp+0x45/0xb0 + +race at unknown origin, with read to 0xffff88800e6b0dd0 of 1 bytes +by task 315 on cpu 0: + memcmp+0x45/0xb0 + hci_connect_acl+0x1b7/0x6b0 + hci_connect_sco+0x4d/0xb30 + sco_sock_connect+0x27b/0xd60 + __sys_connect_file+0xbd/0xe0 + __sys_connect+0xe0/0x110 + __x64_sys_connect+0x40/0x50 + x64_sys_call+0xcad/0x1c60 + do_syscall_64+0x133/0x590 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm") +Signed-off-by: SeungJu Cheon +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/sco.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index 770b9d6fad88f9..47ff4b8d1ae2cd 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -312,11 +312,21 @@ static int sco_connect(struct sock *sk) + struct sco_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; ++ bdaddr_t src, dst; ++ struct bt_codec codec; ++ __u16 setting; + int err, type; + +- BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst); ++ lock_sock(sk); ++ bacpy(&src, &sco_pi(sk)->src); ++ bacpy(&dst, &sco_pi(sk)->dst); ++ setting = sco_pi(sk)->setting; ++ codec = sco_pi(sk)->codec; ++ release_sock(sk); ++ ++ BT_DBG("%pMR -> %pMR", &src, &dst); + +- hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR); ++ hdev = hci_get_route(&dst, &src, BDADDR_BREDR); + if (!hdev) + return -EHOSTUNREACH; + +@@ -327,7 +337,7 @@ static int sco_connect(struct sock *sk) + else + type = SCO_LINK; + +- switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) { ++ switch (setting & SCO_AIRMODE_MASK) { + case SCO_AIRMODE_TRANSP: + if (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev)) { + err = -EOPNOTSUPP; +@@ -336,8 +346,8 @@ static int sco_connect(struct sock *sk) + break; + } + +- hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst, +- sco_pi(sk)->setting, &sco_pi(sk)->codec, ++ hcon = hci_connect_sco(hdev, type, &dst, ++ setting, &codec, + READ_ONCE(sk->sk_sndtimeo)); + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); +-- +2.53.0 + diff --git a/queue-7.0/bonding-annotate-data-races-arcound-churn-variables.patch b/queue-7.0/bonding-annotate-data-races-arcound-churn-variables.patch new file mode 100644 index 0000000000..13d9cf685b --- /dev/null +++ b/queue-7.0/bonding-annotate-data-races-arcound-churn-variables.patch @@ -0,0 +1,120 @@ +From 4a9199a8e7987814d4f2738834e1c8efa60a8f11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 12:35:14 +0000 +Subject: bonding: annotate data-races arcound churn variables + +From: Eric Dumazet + +[ Upstream commit b47ff80f280e18ad2310f44293cc057d9b64ff11 ] + +These fields are updated asynchronously by the bonding state machine +in ad_churn_machine() while holding bond->mode_lock. + +bond_info_show_slave() and bond_fill_slave_info() read them without +bond->mode_lock being held, we need to add READ_ONCE() and +WRITE_ONCE() annotations. + +Note that AD_CHURN_MONITOR, AD_CHURN, and AD_NO_CHURN are defined +exclusively in (kernel private) include/net/bond_3ad.h header. + +They should be moved to include/uapi/linux/if_bonding.h or userspace +tools will have to hardcode their values. + +Fixes: 4916f2e2f3fc ("bonding: print churn state via netlink") +Fixes: 14c9551a32eb ("bonding: Implement port churn-machine (AD standard 43.4.17).") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260603123514.388226-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_3ad.c | 18 ++++++++++-------- + drivers/net/bonding/bond_netlink.c | 4 ++-- + drivers/net/bonding/bond_procfs.c | 8 ++++---- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index f0aa7d2f21717a..985ef66dc3331e 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -1386,8 +1386,8 @@ static void ad_churn_machine(struct port *port) + { + if (port->sm_vars & AD_PORT_CHURNED) { + port->sm_vars &= ~AD_PORT_CHURNED; +- port->sm_churn_actor_state = AD_CHURN_MONITOR; +- port->sm_churn_partner_state = AD_CHURN_MONITOR; ++ WRITE_ONCE(port->sm_churn_actor_state, AD_CHURN_MONITOR); ++ WRITE_ONCE(port->sm_churn_partner_state, AD_CHURN_MONITOR); + port->sm_churn_actor_timer_counter = + __ad_timer_to_ticks(AD_ACTOR_CHURN_TIMER, 0); + port->sm_churn_partner_timer_counter = +@@ -1398,20 +1398,22 @@ static void ad_churn_machine(struct port *port) + !(--port->sm_churn_actor_timer_counter) && + port->sm_churn_actor_state == AD_CHURN_MONITOR) { + if (port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION) { +- port->sm_churn_actor_state = AD_NO_CHURN; ++ WRITE_ONCE(port->sm_churn_actor_state, AD_NO_CHURN); + } else { +- port->churn_actor_count++; +- port->sm_churn_actor_state = AD_CHURN; ++ WRITE_ONCE(port->churn_actor_count, ++ port->churn_actor_count + 1); ++ WRITE_ONCE(port->sm_churn_actor_state, AD_CHURN); + } + } + if (port->sm_churn_partner_timer_counter && + !(--port->sm_churn_partner_timer_counter) && + port->sm_churn_partner_state == AD_CHURN_MONITOR) { + if (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) { +- port->sm_churn_partner_state = AD_NO_CHURN; ++ WRITE_ONCE(port->sm_churn_partner_state, AD_NO_CHURN); + } else { +- port->churn_partner_count++; +- port->sm_churn_partner_state = AD_CHURN; ++ WRITE_ONCE(port->churn_partner_count, ++ port->churn_partner_count + 1); ++ WRITE_ONCE(port->sm_churn_partner_state, AD_CHURN); + } + } + } +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index c7d3e0602c831d..90365d3f7ebff7 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -82,10 +82,10 @@ static int bond_fill_slave_info(struct sk_buff *skb, + goto nla_put_failure_rcu; + + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, +- ad_port->sm_churn_actor_state)) ++ READ_ONCE(ad_port->sm_churn_actor_state))) + goto nla_put_failure_rcu; + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, +- ad_port->sm_churn_partner_state)) ++ READ_ONCE(ad_port->sm_churn_partner_state))) + goto nla_put_failure_rcu; + } + rcu_read_unlock(); +diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c +index 0c0146b7617721..62a5b40b43a28e 100644 +--- a/drivers/net/bonding/bond_procfs.c ++++ b/drivers/net/bonding/bond_procfs.c +@@ -220,13 +220,13 @@ static void bond_info_show_slave(struct seq_file *seq, + seq_printf(seq, "Aggregator ID: %d\n", + agg->aggregator_identifier); + seq_printf(seq, "Actor Churn State: %s\n", +- bond_3ad_churn_desc(port->sm_churn_actor_state)); ++ bond_3ad_churn_desc(READ_ONCE(port->sm_churn_actor_state))); + seq_printf(seq, "Partner Churn State: %s\n", +- bond_3ad_churn_desc(port->sm_churn_partner_state)); ++ bond_3ad_churn_desc(READ_ONCE(port->sm_churn_partner_state))); + seq_printf(seq, "Actor Churned Count: %d\n", +- port->churn_actor_count); ++ READ_ONCE(port->churn_actor_count)); + seq_printf(seq, "Partner Churned Count: %d\n", +- port->churn_partner_count); ++ READ_ONCE(port->churn_partner_count)); + + if (capable(CAP_NET_ADMIN)) { + seq_puts(seq, "details actor lacp pdu:\n"); +-- +2.53.0 + diff --git a/queue-7.0/devlink-release-nested-relation-on-devlink-free.patch b/queue-7.0/devlink-release-nested-relation-on-devlink-free.patch new file mode 100644 index 0000000000..5dcea78db6 --- /dev/null +++ b/queue-7.0/devlink-release-nested-relation-on-devlink-free.patch @@ -0,0 +1,49 @@ +From 546906d54553b51809b4d8fdfb66359dd375b6af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 22:14:10 +0300 +Subject: devlink: Release nested relation on devlink free + +From: Mark Bloch + +[ Upstream commit 3522b21fd7e1863d0734537737bd59f1b90d0190 ] + +devlink relation state is normally released from devl_unregister(), which +calls devlink_rel_put(). This misses devlink instances that get a nested +relation before registration and then fail probe before devl_register() is +reached. + +That flow can happen for SFs. The child devlink gets linked to its +parent before registration, then a later probe error calls devlink_free() +directly. Since the instance was never registered, devl_unregister() is not +called and devlink->rel is leaked. + +Release any pending relation from devlink_free() as well. The registered +path is unchanged because devl_unregister() already clears devlink->rel +before devlink_free() runs. + +Fixes: c137743bce02 ("devlink: introduce object and nested devlink relationship infra") +Signed-off-by: Mark Bloch +Reviewed-by: Jiri Pirko +Link: https://patch.msgid.link/20260528191411.3270532-1-mbloch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/devlink/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/devlink/core.c b/net/devlink/core.c +index d8e509a669bf6c..998ba9eae9aed6 100644 +--- a/net/devlink/core.c ++++ b/net/devlink/core.c +@@ -467,6 +467,8 @@ void devlink_free(struct devlink *devlink) + { + ASSERT_DEVLINK_NOT_REGISTERED(devlink); + ++ devlink_rel_put(devlink); ++ + WARN_ON(!list_empty(&devlink->trap_policer_list)); + WARN_ON(!list_empty(&devlink->trap_group_list)); + WARN_ON(!list_empty(&devlink->trap_list)); +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-policy-smq-check-allocation-under-invalidat.patch b/queue-7.0/dm-cache-policy-smq-check-allocation-under-invalidat.patch new file mode 100644 index 0000000000..393e95ced6 --- /dev/null +++ b/queue-7.0/dm-cache-policy-smq-check-allocation-under-invalidat.patch @@ -0,0 +1,71 @@ +From abe332d436a318357d723b15f8714c3a235c705b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:57:45 +0800 +Subject: dm cache policy smq: check allocation under invalidate lock + +From: Guangshuo Li + +[ Upstream commit d3f0a606b9f278ece8a0df626ded9c4044071235 ] + +commit 2d1f7b65f5de ("dm cache policy smq: fix missing locks in +invalidating cache blocks") added mq->lock around the destructive part of +smq_invalidate_mapping(), but left the e->allocated check outside the +critical section. + +That leaves a check-then-act race. Two concurrent invalidators can both +observe e->allocated as true before either of them takes mq->lock. The +first invalidator that acquires the lock removes the entry from the +queues and hash table and then calls free_entry(), which clears +e->allocated and puts the entry back on the free list. The second +invalidator can then acquire mq->lock and continue with the stale result +of the unlocked check. + +This can corrupt the SMQ queues or hash table by deleting an entry that +is no longer on those structures. It can also hit the allocation check in +free_entry() when the same entry is freed again. + +Move the allocation check under mq->lock so the predicate and the +destructive operations are serialized by the same lock. + +Fixes: 2d1f7b65f5de ("dm cache policy smq: fix missing locks in invalidating cache blocks") +Signed-off-by: Guangshuo Li +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index dd77a93fd68d2d..1ae304c2f5737c 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1590,18 +1590,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; +- +- if (!e->allocated) +- return -ENODATA; ++ int r = 0; + + spin_lock_irqsave(&mq->lock, flags); ++ if (!e->allocated) { ++ r = -ENODATA; ++ goto out; ++ } + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ ++out: + spin_unlock_irqrestore(&mq->lock, flags); + +- return 0; ++ return r; + } + + static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) +-- +2.53.0 + diff --git a/queue-7.0/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch b/queue-7.0/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch new file mode 100644 index 0000000000..3bc06b7b6a --- /dev/null +++ b/queue-7.0/drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch @@ -0,0 +1,53 @@ +From 03ac1513eb1348733fa0b65b0a7c708793211138 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 19:00:13 +0100 +Subject: drm/imx: Fix three kernel-doc warnings in dcss-scaler.c + +From: Yicong Hui + +[ Upstream commit ae0383e5a9a4b12d68c76c4769857def4665deff ] + +Fix the following W=1 kerneldoc warnings by adding the missing parameter +descriptions for @phase0_identity and @nn_interpolation in +dcss_scaler_filter_design() and @phase0_identity in +dcss_scaler_gaussian_filter() + +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:173 function parameter 'phase0_identity' not described in 'dcss_scaler_gaussian_filter' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'phase0_identity' not described in 'dcss_scaler_filter_design' +Warning: drivers/gpu/drm/imx/dcss/dcss-scaler.c:270 function parameter 'nn_interpolation' not described in 'dcss_scaler_filter_design' + +Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") +Signed-off-by: Yicong Hui +Reviewed-by: Laurentiu Palcu +Link: https://patch.msgid.link/20260406180013.2442096-1-yiconghui@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/dcss/dcss-scaler.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +index 32c3f46b21daea..5c7f8d952ec1a1 100644 +--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c ++++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c +@@ -166,6 +166,7 @@ static int exp_approx_q(int x) + * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter. + * @fc_q: fixed-point cutoff frequency normalized to range [0, 1] + * @use_5_taps: indicates whether to use 5 taps or 7 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output filter coefficients + */ + static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, +@@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, + * @src_length: length of input + * @dst_length: length of output + * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps ++ * @phase0_identity: whether to override phase 0 coefficients with identity filter + * @coef: output coefficients ++ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter + */ + static void dcss_scaler_filter_design(int src_length, int dst_length, + bool use_5_taps, bool phase0_identity, +-- +2.53.0 + diff --git a/queue-7.0/erofs-fix-use-after-free-on-sbi-sync_decompress.patch b/queue-7.0/erofs-fix-use-after-free-on-sbi-sync_decompress.patch new file mode 100644 index 0000000000..7de21f9c35 --- /dev/null +++ b/queue-7.0/erofs-fix-use-after-free-on-sbi-sync_decompress.patch @@ -0,0 +1,66 @@ +From b9ef6c08fb95f04ad97d307394d3f4efbbf74bcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:27:16 +0800 +Subject: erofs: fix use-after-free on sbi->sync_decompress + +From: Gao Xiang + +[ Upstream commit 1aee05e814d292064bf5fa15733741040cdc48ba ] + +z_erofs_decompress_kickoff() can race with filesystem unmount, causing +a use-after-free on sbi->sync_decompress. + +When I/O completes, z_erofs_endio() calls z_erofs_decompress_kickoff() +to queue z_erofs_decompressqueue_work() asynchronously. Then, after all +folios are unlocked, unmount workflow can proceed and sbi will be freed +before accessing to sbi->sync_decompress. + +Thread (unmount) I/O completion kworker + queue_work + z_erofs_decompressqueue_work + (all folios are unlocked) +cleanup_mnt + .. + erofs_kill_sb + erofs_sb_free + kfree(sbi) + access sbi->sync_decompress // UAF!! + +Fixes: 40452ffca3c1 ("erofs: add sysfs node to control sync decompression strategy") +Reported-by: syzbot+52bae5c495dbe261a0bc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=52bae5c495dbe261a0bc +Reviewed-by: Chao Yu +Reviewed-by: Jianan Huang +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index d7445e98312d80..50a5a1568370b0 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1457,6 +1457,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + if (atomic_add_return(bios, &io->pending_bios)) + return; + if (z_erofs_in_atomic()) { ++ /* See `sync_decompress` in sysfs-fs-erofs for more details */ ++ if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) ++ sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + #ifdef CONFIG_EROFS_FS_PCPU_KTHREAD + struct kthread_worker *worker; + +@@ -1473,9 +1476,6 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + #else + queue_work(z_erofs_workqueue, &io->u.work); + #endif +- /* See `sync_decompress` in sysfs-fs-erofs for more details */ +- if (sbi->sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) +- sbi->sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON; + return; + } + gfp_flag = memalloc_noio_save(); +-- +2.53.0 + diff --git a/queue-7.0/fwctl-bnxt_en-move-common-definitions-to-include-lin.patch b/queue-7.0/fwctl-bnxt_en-move-common-definitions-to-include-lin.patch new file mode 100644 index 0000000000..b9d7e85014 --- /dev/null +++ b/queue-7.0/fwctl-bnxt_en-move-common-definitions-to-include-lin.patch @@ -0,0 +1,185 @@ +From 2ddecb93293574d43586b459f5fbc119ed9cac43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 08:16:01 -0700 +Subject: fwctl/bnxt_en: Move common definitions to include/linux/bnxt/ + +From: Pavan Chebbi + +[ Upstream commit 7be18a1fa00eab5283b35c13e26c6b76fcaab9ce ] + +We have common definitions that are now going to be used +by more than one component outside of bnxt (bnxt_re and +fwctl) + +Move bnxt_ulp.h to include/linux/bnxt/ as ulp.h. + +Link: https://patch.msgid.link/r/20260314151605.932749-2-pavan.chebbi@broadcom.com +Reviewed-by: Andy Gospodarek +Reviewed-by: Leon Romanovsky +Cc: linux-rdma@vger.kernel.org +Signed-off-by: Pavan Chebbi +Signed-off-by: Jason Gunthorpe +Stable-dep-of: b6197b386677 ("Reapply "bnxt_en: bring back rtnl_lock() in the bnxt_open() path"") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/bnxt_re/debugfs.c | 2 +- + drivers/infiniband/hw/bnxt_re/main.c | 2 +- + drivers/infiniband/hw/bnxt_re/qplib_fp.c | 2 +- + drivers/infiniband/hw/bnxt_re/qplib_res.h | 2 +- + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- + drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 2 +- + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- + drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 2 +- + drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 2 +- + .../broadcom/bnxt/bnxt_ulp.h => include/linux/bnxt/ulp.h | 0 + 10 files changed, 9 insertions(+), 9 deletions(-) + rename drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h => include/linux/bnxt/ulp.h (100%) + +diff --git a/drivers/infiniband/hw/bnxt_re/debugfs.c b/drivers/infiniband/hw/bnxt_re/debugfs.c +index a2ad79c3bbd021..5fed2cf66be30a 100644 +--- a/drivers/infiniband/hw/bnxt_re/debugfs.c ++++ b/drivers/infiniband/hw/bnxt_re/debugfs.c +@@ -10,8 +10,8 @@ + #include + #include + #include ++#include + +-#include "bnxt_ulp.h" + #include "roce_hsi.h" + #include "qplib_res.h" + #include "qplib_sp.h" +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index b576f05e3b26b2..47afccddf55e57 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -55,8 +55,8 @@ + #include + #include + #include ++#include + +-#include "bnxt_ulp.h" + #include "roce_hsi.h" + #include "qplib_res.h" + #include "qplib_sp.h" +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +index 2d7932b3c492fa..b4c7b8f582ba9f 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + #include + + #include "roce_hsi.h" +@@ -55,7 +56,6 @@ + #include "qplib_sp.h" + #include "qplib_fp.h" + #include +-#include "bnxt_ulp.h" + #include "bnxt_re.h" + #include "ib_verbs.h" + +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h +index 9a5dcf97b6f440..0a4a03efeb0bab 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_res.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h +@@ -39,7 +39,7 @@ + #ifndef __BNXT_QPLIB_RES_H__ + #define __BNXT_QPLIB_RES_H__ + +-#include "bnxt_ulp.h" ++#include + + extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero; + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 3f775196ef8194..5d05084e32d93f 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -59,10 +59,10 @@ + #include + #include + #include ++#include + + #include "bnxt.h" + #include "bnxt_hwrm.h" +-#include "bnxt_ulp.h" + #include "bnxt_sriov.h" + #include "bnxt_ethtool.h" + #include "bnxt_dcb.h" +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +index 15de802bbac48e..230cd95d30a269 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +@@ -13,12 +13,12 @@ + #include + #include + #include ++#include + #include "bnxt.h" + #include "bnxt_hwrm.h" + #include "bnxt_vfr.h" + #include "bnxt_devlink.h" + #include "bnxt_ethtool.h" +-#include "bnxt_ulp.h" + #include "bnxt_ptp.h" + #include "bnxt_coredump.h" + #include "bnxt_nvm_defs.h" +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index 0407aa1b3190e4..ef646a3463b1ec 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -27,9 +27,9 @@ + #include + #include + #include ++#include + #include "bnxt.h" + #include "bnxt_hwrm.h" +-#include "bnxt_ulp.h" + #include "bnxt_xdp.h" + #include "bnxt_ptp.h" + #include "bnxt_ethtool.h" +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +index 7f9829287c4950..edcc002e4ca358 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +@@ -17,9 +17,9 @@ + #include + #include + #include ++#include + #include "bnxt.h" + #include "bnxt_hwrm.h" +-#include "bnxt_ulp.h" + #include "bnxt_sriov.h" + #include "bnxt_vfr.h" + #include "bnxt_ethtool.h" +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +index e1e82a72cf1bb8..11ced44ead29b3 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +@@ -22,10 +22,10 @@ + #include + #include + #include ++#include + + #include "bnxt.h" + #include "bnxt_hwrm.h" +-#include "bnxt_ulp.h" + + static DEFINE_IDA(bnxt_aux_dev_ids); + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/include/linux/bnxt/ulp.h +similarity index 100% +rename from drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +rename to include/linux/bnxt/ulp.h +-- +2.53.0 + diff --git a/queue-7.0/fwctl-bnxt_en-refactor-aux-bus-functions-to-be-more-.patch b/queue-7.0/fwctl-bnxt_en-refactor-aux-bus-functions-to-be-more-.patch new file mode 100644 index 0000000000..e1849c83e7 --- /dev/null +++ b/queue-7.0/fwctl-bnxt_en-refactor-aux-bus-functions-to-be-more-.patch @@ -0,0 +1,900 @@ +From ed63f826f1e2c50cdf03b171a3b233d7535c99b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 08:16:02 -0700 +Subject: fwctl/bnxt_en: Refactor aux bus functions to be more generic + +From: Pavan Chebbi + +[ Upstream commit 2c7c85c8c7881d57c5fa1114f4b0dbd7fc53a36f ] + +Up until now there was only one auxiliary device that bnxt +created and that was for RoCE driver. bnxt fwctl is also +going to use an aux bus device that bnxt should create. +This requires some nomenclature changes and refactoring of +the existing bnxt aux dev functions. + +Convert 'aux_priv' and 'edev' members of struct bnxt into +arrays where each element contains supported auxbus device's +data. Move struct bnxt_aux_priv from bnxt.h to ulp.h because +that is where it belongs. Make aux bus init/uninit/add/del +functions more generic which will loop through all the aux +device types. Make bnxt_ulp_start/stop functions (the only +other common functions applicable to any aux device) loop +through the aux devices to update their config and states. +Make callers of bnxt_ulp_start() call it only when there +are no errors. + +Also, as an improvement in code, bnxt_register_dev() can skip +unnecessary dereferencing of edev from bp, instead use the +edev pointer from the function parameter. + +Future patches will reuse these functions to add an aux bus +device for fwctl. + +Link: https://patch.msgid.link/r/20260314151605.932749-3-pavan.chebbi@broadcom.com +Reviewed-by: Andy Gospodarek +Reviewed-by: Leon Romanovsky +Signed-off-by: Pavan Chebbi +Signed-off-by: Jason Gunthorpe +Stable-dep-of: b6197b386677 ("Reapply "bnxt_en: bring back rtnl_lock() in the bnxt_open() path"") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 47 ++- + drivers/net/ethernet/broadcom/bnxt/bnxt.h | 19 +- + .../net/ethernet/broadcom/bnxt/bnxt_devlink.c | 8 +- + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- + drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 339 +++++++++++------- + include/linux/bnxt/ulp.h | 25 +- + 6 files changed, 273 insertions(+), 167 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 5d05084e32d93f..86e45352cec105 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -6896,7 +6896,8 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic) + #endif + if ((bp->flags & BNXT_FLAG_STRIP_VLAN) || def_vlan) + req->flags |= cpu_to_le32(VNIC_CFG_REQ_FLAGS_VLAN_STRIP_MODE); +- if (vnic->vnic_id == BNXT_VNIC_DEFAULT && bnxt_ulp_registered(bp->edev)) ++ if (vnic->vnic_id == BNXT_VNIC_DEFAULT && ++ bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA])) + req->flags |= cpu_to_le32(bnxt_get_roce_vnic_mode(bp)); + + return hwrm_req_send(bp, req); +@@ -8031,6 +8032,7 @@ static int bnxt_get_avail_msix(struct bnxt *bp, int num); + + static int __bnxt_reserve_rings(struct bnxt *bp) + { ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; + struct bnxt_hw_rings hwr = {0}; + int rx_rings, old_rx_rings, rc; + int cp = bp->cp_nr_rings; +@@ -8041,7 +8043,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp) + if (!bnxt_need_reserve_rings(bp)) + return 0; + +- if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(bp->edev)) { ++ if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) { + ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want); + if (!ulp_msix) + bnxt_set_ulp_stat_ctxs(bp, 0); +@@ -8094,8 +8096,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp) + } + rx_rings = min_t(int, rx_rings, hwr.grp); + hwr.cp = min_t(int, hwr.cp, bp->cp_nr_rings); +- if (bnxt_ulp_registered(bp->edev) && +- hwr.stat > bnxt_get_ulp_stat_ctxs(bp)) ++ if (bnxt_ulp_registered(edev) && hwr.stat > bnxt_get_ulp_stat_ctxs(bp)) + hwr.stat -= bnxt_get_ulp_stat_ctxs(bp); + hwr.cp = min_t(int, hwr.cp, hwr.stat); + rc = bnxt_trim_rings(bp, &rx_rings, &hwr.tx, hwr.cp, sh); +@@ -8139,7 +8140,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp) + !netif_is_rxfh_configured(bp->dev)) + bnxt_set_dflt_rss_indir_tbl(bp, NULL); + +- if (!bnxt_ulp_registered(bp->edev) && BNXT_NEW_RM(bp)) { ++ if (!bnxt_ulp_registered(edev) && BNXT_NEW_RM(bp)) { + int resv_msix, resv_ctx, ulp_ctxs; + struct bnxt_hw_resc *hw_resc; + +@@ -11496,6 +11497,7 @@ static void bnxt_clear_int_mode(struct bnxt *bp) + + int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) + { ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; + bool irq_cleared = false; + bool irq_change = false; + int tcs = bp->num_tc; +@@ -11505,7 +11507,7 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) + if (!bnxt_need_reserve_rings(bp)) + return 0; + +- if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(bp->edev)) { ++ if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) { + int ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want); + + if (ulp_msix > bp->ulp_num_msix_want) +@@ -14604,7 +14606,7 @@ static void bnxt_fw_echo_reply(struct bnxt *bp) + static void bnxt_ulp_restart(struct bnxt *bp) + { + bnxt_ulp_stop(bp); +- bnxt_ulp_start(bp, 0); ++ bnxt_ulp_start(bp); + } + + static void bnxt_sp_task(struct work_struct *work) +@@ -14761,7 +14763,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, + hwr.cp_p5 = hwr.tx + rx; + rc = bnxt_hwrm_check_rings(bp, &hwr); + if (!rc && pci_msix_can_alloc_dyn(bp->pdev)) { +- if (!bnxt_ulp_registered(bp->edev)) { ++ if (!bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA])) { + hwr.cp += bnxt_get_ulp_msix_num(bp); + hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp)); + } +@@ -15281,7 +15283,7 @@ static void bnxt_fw_reset_task(struct work_struct *work) + bnxt_dl_health_fw_status_update(bp, true); + } + netdev_unlock(bp->dev); +- bnxt_ulp_start(bp, 0); ++ bnxt_ulp_start(bp); + bnxt_reenable_sriov(bp); + netdev_lock(bp->dev); + bnxt_vf_reps_alloc(bp); +@@ -15303,7 +15305,8 @@ static void bnxt_fw_reset_task(struct work_struct *work) + bnxt_fw_reset_abort(bp, rc); + netdev_unlock(bp->dev); + ulp_start: +- bnxt_ulp_start(bp, rc); ++ if (!rc) ++ bnxt_ulp_start(bp); + } + + static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) +@@ -16344,12 +16347,13 @@ static void bnxt_remove_one(struct pci_dev *pdev) + if (BNXT_PF(bp)) + __bnxt_sriov_disable(bp); + +- bnxt_rdma_aux_device_del(bp); ++ bnxt_aux_devices_del(bp); + + unregister_netdev(dev); + bnxt_ptp_clear(bp); + +- bnxt_rdma_aux_device_uninit(bp); ++ bnxt_aux_devices_uninit(bp); ++ bnxt_auxdev_id_free(bp, bp->auxdev_id); + + bnxt_free_l2_filters(bp, true); + bnxt_free_ntp_fltrs(bp, true); +@@ -16946,7 +16950,9 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + bnxt_set_tpa_flags(bp); + bnxt_init_ring_params(bp); + bnxt_set_ring_params(bp); +- bnxt_rdma_aux_device_init(bp); ++ mutex_init(&bp->auxdev_lock); ++ if (!bnxt_auxdev_id_alloc(bp)) ++ bnxt_aux_devices_init(bp); + rc = bnxt_set_dflt_rings(bp, true); + if (rc) { + if (BNXT_VF(bp) && rc == -ENODEV) { +@@ -17011,7 +17017,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + + bnxt_dl_fw_reporters_create(bp); + +- bnxt_rdma_aux_device_add(bp); ++ bnxt_aux_devices_add(bp); + + bnxt_print_device_info(bp); + +@@ -17019,7 +17025,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + + return 0; + init_err_cleanup: +- bnxt_rdma_aux_device_uninit(bp); ++ bnxt_aux_devices_uninit(bp); ++ bnxt_auxdev_id_free(bp, bp->auxdev_id); + bnxt_dl_unregister(bp); + init_err_dl: + bnxt_shutdown_tc(bp); +@@ -17153,9 +17160,10 @@ static int bnxt_resume(struct device *device) + + resume_exit: + netdev_unlock(bp->dev); +- bnxt_ulp_start(bp, rc); +- if (!rc) ++ if (!rc) { ++ bnxt_ulp_start(bp); + bnxt_reenable_sriov(bp); ++ } + return rc; + } + +@@ -17335,9 +17343,10 @@ static void bnxt_io_resume(struct pci_dev *pdev) + netif_device_attach(netdev); + + netdev_unlock(netdev); +- bnxt_ulp_start(bp, err); +- if (!err) ++ if (!err) { ++ bnxt_ulp_start(bp); + bnxt_reenable_sriov(bp); ++ } + } + + static const struct pci_error_handlers bnxt_err_handler = { +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h +index 4bc7f7aeaab378..8899ef51bdcfec 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h +@@ -24,12 +24,12 @@ + #include + #include + #include +-#include + #include + #include + #include + #include + #include ++#include + #ifdef CONFIG_TEE_BNXT_FW + #include + #endif +@@ -2085,12 +2085,6 @@ struct bnxt_fw_health { + #define BNXT_FW_IF_RETRY 10 + #define BNXT_FW_SLOT_RESET_RETRY 4 + +-struct bnxt_aux_priv { +- struct auxiliary_device aux_dev; +- struct bnxt_en_dev *edev; +- int id; +-}; +- + enum board_idx { + BCM57301, + BCM57302, +@@ -2350,8 +2344,8 @@ struct bnxt { + #define BNXT_CHIP_P5_AND_MINUS(bp) \ + (BNXT_CHIP_P3(bp) || BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp)) + +- struct bnxt_aux_priv *aux_priv; +- struct bnxt_en_dev *edev; ++ struct bnxt_aux_priv *aux_priv[__BNXT_AUXDEV_MAX]; ++ struct bnxt_en_dev *edev[__BNXT_AUXDEV_MAX]; + + struct bnxt_napi **bnapi; + +@@ -2763,6 +2757,13 @@ struct bnxt { + struct bnxt_ctx_pg_info *fw_crash_mem; + u32 fw_crash_len; + struct bnxt_bs_trace_info bs_trace[BNXT_TRACE_MAX]; ++ int auxdev_id; ++ /* synchronize validity checks of available aux devices */ ++ struct mutex auxdev_lock; ++ u8 auxdev_state[__BNXT_AUXDEV_MAX]; ++#define BNXT_ADEV_STATE_NONE 0 ++#define BNXT_ADEV_STATE_INIT 1 ++#define BNXT_ADEV_STATE_ADD 2 + }; + + #define BNXT_NUM_RX_RING_STATS 8 +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +index 230cd95d30a269..835f2b413931c2 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +@@ -440,13 +440,13 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change, + "reload is unsupported while VFs are allocated or being configured"); + netdev_unlock(bp->dev); + rtnl_unlock(); +- bnxt_ulp_start(bp, 0); ++ bnxt_ulp_start(bp); + return -EOPNOTSUPP; + } + if (bp->dev->reg_state == NETREG_UNREGISTERED) { + netdev_unlock(bp->dev); + rtnl_unlock(); +- bnxt_ulp_start(bp, 0); ++ bnxt_ulp_start(bp); + return -ENODEV; + } + if (netif_running(bp->dev)) +@@ -578,8 +578,8 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti + } + netdev_unlock(bp->dev); + rtnl_unlock(); +- if (action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT) +- bnxt_ulp_start(bp, rc); ++ if (!rc && action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT) ++ bnxt_ulp_start(bp); + return rc; + } + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index ef646a3463b1ec..6596cd7447526e 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -5209,7 +5209,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, + + memset(buf, 0, sizeof(u64) * bp->num_tests); + if (etest->flags & ETH_TEST_FL_OFFLINE && +- bnxt_ulp_registered(bp->edev)) { ++ bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA])) { + etest->flags |= ETH_TEST_FL_FAILED; + netdev_warn(dev, "Offline tests cannot be run with RoCE driver loaded\n"); + return; +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +index 11ced44ead29b3..3705ef3a75c9ec 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +@@ -29,9 +29,32 @@ + + static DEFINE_IDA(bnxt_aux_dev_ids); + ++struct bnxt_aux_device { ++ const char *name; ++}; ++ ++static void bnxt_auxdev_set_state(struct bnxt *bp, int idx, int state) ++{ ++ bp->auxdev_state[idx] = state; ++} ++ ++static bool bnxt_auxdev_is_init(struct bnxt *bp, int idx) ++{ ++ return (bp->auxdev_state[idx] == BNXT_ADEV_STATE_INIT); ++} ++ ++static bool bnxt_auxdev_is_active(struct bnxt *bp, int idx) ++{ ++ return (bp->auxdev_state[idx] == BNXT_ADEV_STATE_ADD); ++} ++ ++static struct bnxt_aux_device bnxt_aux_devices[__BNXT_AUXDEV_MAX] = {{ ++ .name = "rdma", ++}}; ++ + static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent) + { +- struct bnxt_en_dev *edev = bp->edev; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; + int num_msix, i; + + if (!edev->ulp_tbl->msix_requested) { +@@ -51,61 +74,75 @@ static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent) + + int bnxt_get_ulp_msix_num(struct bnxt *bp) + { +- if (bp->edev) +- return bp->edev->ulp_num_msix_vec; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; ++ ++ if (edev) ++ return edev->ulp_num_msix_vec; + return 0; + } + + void bnxt_set_ulp_msix_num(struct bnxt *bp, int num) + { +- if (bp->edev) +- bp->edev->ulp_num_msix_vec = num; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; ++ ++ if (edev) ++ edev->ulp_num_msix_vec = num; + } + + int bnxt_get_ulp_msix_num_in_use(struct bnxt *bp) + { +- if (bnxt_ulp_registered(bp->edev)) +- return bp->edev->ulp_num_msix_vec; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; ++ ++ if (bnxt_ulp_registered(edev)) ++ return edev->ulp_num_msix_vec; + return 0; + } + + int bnxt_get_ulp_stat_ctxs(struct bnxt *bp) + { +- if (bp->edev) +- return bp->edev->ulp_num_ctxs; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; ++ ++ if (edev) ++ return edev->ulp_num_ctxs; + return 0; + } + + void bnxt_set_ulp_stat_ctxs(struct bnxt *bp, int num_ulp_ctx) + { +- if (bp->edev) +- bp->edev->ulp_num_ctxs = num_ulp_ctx; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; ++ ++ if (edev) ++ edev->ulp_num_ctxs = num_ulp_ctx; + } + + int bnxt_get_ulp_stat_ctxs_in_use(struct bnxt *bp) + { +- if (bnxt_ulp_registered(bp->edev)) +- return bp->edev->ulp_num_ctxs; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; ++ ++ if (bnxt_ulp_registered(edev)) ++ return edev->ulp_num_ctxs; + return 0; + } + + void bnxt_set_dflt_ulp_stat_ctxs(struct bnxt *bp) + { +- if (bp->edev) { +- bp->edev->ulp_num_ctxs = BNXT_MIN_ROCE_STAT_CTXS; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; ++ ++ if (edev) { ++ edev->ulp_num_ctxs = BNXT_MIN_ROCE_STAT_CTXS; + /* Reserve one additional stat_ctx for PF0 (except + * on 1-port NICs) as it also creates one stat_ctx + * for PF1 in case of RoCE bonding. + */ + if (BNXT_PF(bp) && !bp->pf.port_id && + bp->port_count > 1) +- bp->edev->ulp_num_ctxs++; ++ edev->ulp_num_ctxs++; + + /* Reserve one additional stat_ctx when the device is capable + * of supporting port mirroring on RDMA device. + */ + if (BNXT_MIRROR_ON_ROCE_CAP(bp)) +- bp->edev->ulp_num_ctxs++; ++ edev->ulp_num_ctxs++; + } + } + +@@ -141,7 +178,7 @@ int bnxt_register_dev(struct bnxt_en_dev *edev, + + edev->ulp_tbl->msix_requested = bnxt_get_ulp_msix_num(bp); + +- bnxt_fill_msix_vecs(bp, bp->edev->msix_entries); ++ bnxt_fill_msix_vecs(bp, edev->msix_entries); + exit: + mutex_unlock(&edev->en_dev_lock); + netdev_unlock(dev); +@@ -227,20 +264,27 @@ EXPORT_SYMBOL(bnxt_send_msg); + + void bnxt_ulp_stop(struct bnxt *bp) + { +- struct bnxt_aux_priv *aux_priv = bp->aux_priv; +- struct bnxt_en_dev *edev = bp->edev; ++ int i; + +- if (!edev) +- return; +- +- mutex_lock(&edev->en_dev_lock); +- if (!bnxt_ulp_registered(edev) || +- (edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) +- goto ulp_stop_exit; +- +- edev->flags |= BNXT_EN_FLAG_ULP_STOPPED; +- if (aux_priv) { ++ mutex_lock(&bp->auxdev_lock); ++ for (i = 0; i < __BNXT_AUXDEV_MAX; i++) { ++ struct bnxt_aux_priv *aux_priv; + struct auxiliary_device *adev; ++ struct bnxt_en_dev *edev; ++ ++ if (!bnxt_auxdev_is_active(bp, i)) ++ continue; ++ ++ aux_priv = bp->aux_priv[i]; ++ edev = bp->edev[i]; ++ mutex_lock(&edev->en_dev_lock); ++ if (!bnxt_ulp_registered(edev) || ++ (edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) { ++ mutex_unlock(&edev->en_dev_lock); ++ continue; ++ } ++ ++ edev->flags |= BNXT_EN_FLAG_ULP_STOPPED; + + adev = &aux_priv->aux_dev; + if (adev->dev.driver) { +@@ -251,29 +295,35 @@ void bnxt_ulp_stop(struct bnxt *bp) + edev->en_state = bp->state; + adrv->suspend(adev, pm); + } ++ mutex_unlock(&edev->en_dev_lock); + } +-ulp_stop_exit: +- mutex_unlock(&edev->en_dev_lock); ++ mutex_unlock(&bp->auxdev_lock); + } + +-void bnxt_ulp_start(struct bnxt *bp, int err) ++void bnxt_ulp_start(struct bnxt *bp) + { +- struct bnxt_aux_priv *aux_priv = bp->aux_priv; +- struct bnxt_en_dev *edev = bp->edev; ++ int i; + +- if (!edev || err) +- return; ++ mutex_lock(&bp->auxdev_lock); ++ for (i = 0; i < __BNXT_AUXDEV_MAX; i++) { ++ struct bnxt_aux_priv *aux_priv; ++ struct auxiliary_device *adev; ++ struct bnxt_en_dev *edev; + +- mutex_lock(&edev->en_dev_lock); +- if (!bnxt_ulp_registered(edev) || +- !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) +- goto ulp_start_exit; ++ if (!bnxt_auxdev_is_active(bp, i)) ++ continue; + +- if (edev->ulp_tbl->msix_requested) +- bnxt_fill_msix_vecs(bp, edev->msix_entries); ++ aux_priv = bp->aux_priv[i]; ++ edev = bp->edev[i]; ++ mutex_lock(&edev->en_dev_lock); ++ if (!bnxt_ulp_registered(edev) || ++ !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) { ++ goto clear_flag_continue; ++ } ++ ++ if (edev->ulp_tbl->msix_requested) ++ bnxt_fill_msix_vecs(bp, edev->msix_entries); + +- if (aux_priv) { +- struct auxiliary_device *adev; + + adev = &aux_priv->aux_dev; + if (adev->dev.driver) { +@@ -283,22 +333,23 @@ void bnxt_ulp_start(struct bnxt *bp, int err) + edev->en_state = bp->state; + adrv->resume(adev); + } ++clear_flag_continue: ++ edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED; ++ mutex_unlock(&edev->en_dev_lock); + } +-ulp_start_exit: +- edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED; +- mutex_unlock(&edev->en_dev_lock); ++ mutex_unlock(&bp->auxdev_lock); + } + + void bnxt_ulp_irq_stop(struct bnxt *bp) + { +- struct bnxt_en_dev *edev = bp->edev; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; + struct bnxt_ulp_ops *ops; + bool reset = false; + + if (!edev) + return; + +- if (bnxt_ulp_registered(bp->edev)) { ++ if (bnxt_ulp_registered(edev)) { + struct bnxt_ulp *ulp = edev->ulp_tbl; + + if (!ulp->msix_requested) +@@ -315,13 +366,13 @@ void bnxt_ulp_irq_stop(struct bnxt *bp) + + void bnxt_ulp_irq_restart(struct bnxt *bp, int err) + { +- struct bnxt_en_dev *edev = bp->edev; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; + struct bnxt_ulp_ops *ops; + + if (!edev) + return; + +- if (bnxt_ulp_registered(bp->edev)) { ++ if (bnxt_ulp_registered(edev)) { + struct bnxt_ulp *ulp = edev->ulp_tbl; + struct bnxt_msix_entry *ent = NULL; + +@@ -346,7 +397,7 @@ void bnxt_ulp_irq_restart(struct bnxt *bp, int err) + void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl) + { + u16 event_id = le16_to_cpu(cmpl->event_id); +- struct bnxt_en_dev *edev = bp->edev; ++ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; + struct bnxt_ulp_ops *ops; + struct bnxt_ulp *ulp; + +@@ -387,18 +438,21 @@ void bnxt_register_async_events(struct bnxt_en_dev *edev, + } + EXPORT_SYMBOL(bnxt_register_async_events); + +-void bnxt_rdma_aux_device_uninit(struct bnxt *bp) ++void bnxt_aux_devices_uninit(struct bnxt *bp) + { + struct bnxt_aux_priv *aux_priv; + struct auxiliary_device *adev; +- +- /* Skip if no auxiliary device init was done. */ +- if (!bp->aux_priv) +- return; +- +- aux_priv = bp->aux_priv; +- adev = &aux_priv->aux_dev; +- auxiliary_device_uninit(adev); ++ int idx; ++ ++ mutex_lock(&bp->auxdev_lock); ++ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) { ++ if (bnxt_auxdev_is_init(bp, idx)) { ++ aux_priv = bp->aux_priv[idx]; ++ adev = &aux_priv->aux_dev; ++ auxiliary_device_uninit(adev); ++ } ++ } ++ mutex_unlock(&bp->auxdev_lock); + } + + static void bnxt_aux_dev_release(struct device *dev) +@@ -407,20 +461,25 @@ static void bnxt_aux_dev_release(struct device *dev) + container_of(dev, struct bnxt_aux_priv, aux_dev.dev); + struct bnxt *bp = netdev_priv(aux_priv->edev->net); + +- ida_free(&bnxt_aux_dev_ids, aux_priv->id); + kfree(aux_priv->edev->ulp_tbl); +- bp->edev = NULL; ++ bp->edev[aux_priv->id] = NULL; + kfree(aux_priv->edev); ++ bp->aux_priv[aux_priv->id] = NULL; + kfree(aux_priv); +- bp->aux_priv = NULL; + } + +-void bnxt_rdma_aux_device_del(struct bnxt *bp) ++void bnxt_aux_devices_del(struct bnxt *bp) + { +- if (!bp->edev) +- return; ++ int idx; + +- auxiliary_device_delete(&bp->aux_priv->aux_dev); ++ mutex_lock(&bp->auxdev_lock); ++ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) { ++ if (bnxt_auxdev_is_active(bp, idx)) { ++ auxiliary_device_delete(&bp->aux_priv[idx]->aux_dev); ++ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT); ++ } ++ } ++ mutex_unlock(&bp->auxdev_lock); + } + + static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp) +@@ -450,83 +509,105 @@ static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp) + edev->bar0 = bp->bar0; + } + +-void bnxt_rdma_aux_device_add(struct bnxt *bp) ++void bnxt_aux_devices_add(struct bnxt *bp) + { + struct auxiliary_device *aux_dev; +- int rc; +- +- if (!bp->edev) +- return; +- +- aux_dev = &bp->aux_priv->aux_dev; +- rc = auxiliary_device_add(aux_dev); +- if (rc) { +- netdev_warn(bp->dev, "Failed to add auxiliary device for ROCE\n"); +- auxiliary_device_uninit(aux_dev); +- bp->flags &= ~BNXT_FLAG_ROCE_CAP; ++ int rc, idx; ++ ++ mutex_lock(&bp->auxdev_lock); ++ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) { ++ if (bnxt_auxdev_is_init(bp, idx)) { ++ aux_dev = &bp->aux_priv[idx]->aux_dev; ++ rc = auxiliary_device_add(aux_dev); ++ if (rc) { ++ netdev_warn(bp->dev, "Failed to add auxiliary device for ROCE\n"); ++ auxiliary_device_uninit(aux_dev); ++ if (idx == BNXT_AUXDEV_RDMA) ++ bp->flags &= ~BNXT_FLAG_ROCE_CAP; ++ continue; ++ } ++ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_ADD); ++ } + } ++ mutex_unlock(&bp->auxdev_lock); + } + +-void bnxt_rdma_aux_device_init(struct bnxt *bp) ++void bnxt_aux_devices_init(struct bnxt *bp) + { + struct auxiliary_device *aux_dev; + struct bnxt_aux_priv *aux_priv; + struct bnxt_en_dev *edev; + struct bnxt_ulp *ulp; +- int rc; ++ int rc, idx; ++ ++ mutex_lock(&bp->auxdev_lock); ++ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) { ++ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_NONE); ++ ++ if (idx == BNXT_AUXDEV_RDMA && ++ !(bp->flags & BNXT_FLAG_ROCE_CAP)) ++ continue; ++ ++ aux_priv = kzalloc_obj(*aux_priv); ++ if (!aux_priv) ++ goto next_auxdev; ++ ++ aux_dev = &aux_priv->aux_dev; ++ aux_dev->id = bp->auxdev_id; ++ aux_dev->name = bnxt_aux_devices[idx].name; ++ aux_dev->dev.parent = &bp->pdev->dev; ++ aux_dev->dev.release = bnxt_aux_dev_release; ++ ++ rc = auxiliary_device_init(aux_dev); ++ if (rc) { ++ kfree(aux_priv); ++ goto next_auxdev; ++ } ++ bp->aux_priv[idx] = aux_priv; + +- if (!(bp->flags & BNXT_FLAG_ROCE_CAP)) +- return; ++ /* From this point, all cleanup will happen via the .release ++ * callback & any error unwinding will need to include a call ++ * to auxiliary_device_uninit. ++ */ ++ edev = kzalloc_obj(*edev); ++ if (!edev) ++ goto aux_dev_uninit; + +- aux_priv = kzalloc_obj(*bp->aux_priv); +- if (!aux_priv) +- goto exit; ++ aux_priv->edev = edev; ++ bnxt_set_edev_info(edev, bp); + +- aux_priv->id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL); +- if (aux_priv->id < 0) { +- netdev_warn(bp->dev, +- "ida alloc failed for ROCE auxiliary device\n"); +- kfree(aux_priv); +- goto exit; +- } ++ ulp = kzalloc_obj(*ulp); ++ if (!ulp) ++ goto aux_dev_uninit; + +- aux_dev = &aux_priv->aux_dev; +- aux_dev->id = aux_priv->id; +- aux_dev->name = "rdma"; +- aux_dev->dev.parent = &bp->pdev->dev; +- aux_dev->dev.release = bnxt_aux_dev_release; ++ edev->ulp_tbl = ulp; ++ bp->edev[idx] = edev; ++ if (idx == BNXT_AUXDEV_RDMA) ++ bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp); ++ aux_priv->id = idx; ++ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT); + +- rc = auxiliary_device_init(aux_dev); +- if (rc) { +- ida_free(&bnxt_aux_dev_ids, aux_priv->id); +- kfree(aux_priv); +- goto exit; ++ continue; ++aux_dev_uninit: ++ auxiliary_device_uninit(aux_dev); ++next_auxdev: ++ if (idx == BNXT_AUXDEV_RDMA) ++ bp->flags &= ~BNXT_FLAG_ROCE_CAP; + } +- bp->aux_priv = aux_priv; +- +- /* From this point, all cleanup will happen via the .release callback & +- * any error unwinding will need to include a call to +- * auxiliary_device_uninit. +- */ +- edev = kzalloc_obj(*edev); +- if (!edev) +- goto aux_dev_uninit; +- +- aux_priv->edev = edev; +- +- ulp = kzalloc_obj(*ulp); +- if (!ulp) +- goto aux_dev_uninit; ++ mutex_unlock(&bp->auxdev_lock); ++} + +- edev->ulp_tbl = ulp; +- bp->edev = edev; +- bnxt_set_edev_info(edev, bp); +- bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp); ++int bnxt_auxdev_id_alloc(struct bnxt *bp) ++{ ++ bp->auxdev_id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL); ++ if (bp->auxdev_id < 0) ++ return bp->auxdev_id; + +- return; ++ return 0; ++} + +-aux_dev_uninit: +- auxiliary_device_uninit(aux_dev); +-exit: +- bp->flags &= ~BNXT_FLAG_ROCE_CAP; ++void bnxt_auxdev_id_free(struct bnxt *bp, int id) ++{ ++ if (bp->auxdev_id >= 0) ++ ida_free(&bnxt_aux_dev_ids, id); + } +diff --git a/include/linux/bnxt/ulp.h b/include/linux/bnxt/ulp.h +index 3c5b8a53f71507..1a4643c46f86fb 100644 +--- a/include/linux/bnxt/ulp.h ++++ b/include/linux/bnxt/ulp.h +@@ -10,6 +10,8 @@ + #ifndef BNXT_ULP_H + #define BNXT_ULP_H + ++#include ++ + #define BNXT_MIN_ROCE_CP_RINGS 2 + #define BNXT_MIN_ROCE_STAT_CTXS 1 + +@@ -20,6 +22,17 @@ + struct hwrm_async_event_cmpl; + struct bnxt; + ++enum bnxt_auxdev_type { ++ BNXT_AUXDEV_RDMA = 0, ++ __BNXT_AUXDEV_MAX ++}; ++ ++struct bnxt_aux_priv { ++ struct auxiliary_device aux_dev; ++ struct bnxt_en_dev *edev; ++ int id; ++}; ++ + struct bnxt_msix_entry { + u32 vector; + u32 ring_idx; +@@ -110,19 +123,21 @@ void bnxt_set_ulp_stat_ctxs(struct bnxt *bp, int num_ctxs); + int bnxt_get_ulp_stat_ctxs_in_use(struct bnxt *bp); + void bnxt_set_dflt_ulp_stat_ctxs(struct bnxt *bp); + void bnxt_ulp_stop(struct bnxt *bp); +-void bnxt_ulp_start(struct bnxt *bp, int err); ++void bnxt_ulp_start(struct bnxt *bp); + void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs); + void bnxt_ulp_irq_stop(struct bnxt *bp); + void bnxt_ulp_irq_restart(struct bnxt *bp, int err); + void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl); +-void bnxt_rdma_aux_device_uninit(struct bnxt *bp); +-void bnxt_rdma_aux_device_del(struct bnxt *bp); +-void bnxt_rdma_aux_device_add(struct bnxt *bp); +-void bnxt_rdma_aux_device_init(struct bnxt *bp); ++void bnxt_aux_devices_uninit(struct bnxt *bp); ++void bnxt_aux_devices_del(struct bnxt *bp); ++void bnxt_aux_devices_add(struct bnxt *bp); ++void bnxt_aux_devices_init(struct bnxt *bp); + int bnxt_register_dev(struct bnxt_en_dev *edev, struct bnxt_ulp_ops *ulp_ops, + void *handle); + void bnxt_unregister_dev(struct bnxt_en_dev *edev); + int bnxt_send_msg(struct bnxt_en_dev *edev, struct bnxt_fw_msg *fw_msg); + void bnxt_register_async_events(struct bnxt_en_dev *edev, + unsigned long *events_bmap, u16 max_id); ++int bnxt_auxdev_id_alloc(struct bnxt *bp); ++void bnxt_auxdev_id_free(struct bnxt *bp, int id); + #endif +-- +2.53.0 + diff --git a/queue-7.0/geneve-fix-length-used-in-gro-hint-udp-checksum-adju.patch b/queue-7.0/geneve-fix-length-used-in-gro-hint-udp-checksum-adju.patch new file mode 100644 index 0000000000..7ac23c68a8 --- /dev/null +++ b/queue-7.0/geneve-fix-length-used-in-gro-hint-udp-checksum-adju.patch @@ -0,0 +1,42 @@ +From 4a4a1490a5ea19986f17bd7a844c4757c1c1e95e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 16:47:00 +0200 +Subject: geneve: fix length used in GRO hint UDP checksum adjustment + +From: Antoine Tenart + +[ Upstream commit 1231623fd3b5aa6b41cce799ffb0d82e10914be4 ] + +In geneve_post_decap_hint the length used for adjusting the UDP checksum +should be 'skb->len - gro_hint->nested_tp_offset' (UDP length) instead +of 'skb->len - gro_hint->nested_nh_offset' (IP length). + +Fixes: fd0dd796576e ("geneve: use GRO hint option in the RX path") +Cc: Paolo Abeni +Reported-by: Sashiko +Closes: https://sashiko.dev/#/patchset/20260521131436.748832-1-jhs%40mojatatu.com +Signed-off-by: Antoine Tenart +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260529144713.780938-1-atenart@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/geneve.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c +index 01cdd06102e0db..8ea9482d52e538 100644 +--- a/drivers/net/geneve.c ++++ b/drivers/net/geneve.c +@@ -633,7 +633,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb, + uh = udp_hdr(skb); + uh->len = htons(skb->len - gro_hint->nested_tp_offset); + if (uh->check) { +- len = skb->len - gro_hint->nested_nh_offset; ++ len = skb->len - gro_hint->nested_tp_offset; + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; + if (gro_hint->nested_is_v6) + uh->check = ~udp_v6_check(len, &ipv6h->saddr, +-- +2.53.0 + diff --git a/queue-7.0/hsr-remove-warn_once-in-hsr_addr_is_self.patch b/queue-7.0/hsr-remove-warn_once-in-hsr_addr_is_self.patch new file mode 100644 index 0000000000..93dcd8a9f8 --- /dev/null +++ b/queue-7.0/hsr-remove-warn_once-in-hsr_addr_is_self.patch @@ -0,0 +1,109 @@ +From d8a67a0c83b1b152dfb15d59f6fbcceff3f7e9bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 30 May 2026 06:42:58 +0000 +Subject: hsr: Remove WARN_ONCE() in hsr_addr_is_self(). + +From: Kuniyuki Iwashima + +[ Upstream commit afd0f17ca46258cec3a5cc48b8df9327fe772490 ] + +syzbot reported the warning [0] in hsr_addr_is_self(), +whose assumption is simply wrong. + +hsr->self_node is cleared in hsr_del_self_node(), which +is called from hsr_dellink(). + +Since dev->rtnl_link_ops->dellink() is called before +unregister_netdevice_many(), there is a window when +user can find the device but without hsr->self_node. + +Let's remove WARN_ONCE() in hsr_addr_is_self(). + +[0]: +HSR: No self node +WARNING: net/hsr/hsr_framereg.c:39 at hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39, CPU#0: syz.4.16848/17220 +Modules linked in: +CPU: 0 UID: 0 PID: 17220 Comm: syz.4.16848 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} +Tainted: [L]=SOFTLOCKUP +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 +RIP: 0010:hsr_addr_is_self+0x211/0x3f0 net/hsr/hsr_framereg.c:39 +Code: 33 2f 41 0f b7 dd 89 ee 09 de 31 ff e8 c8 b4 c6 f6 09 dd 74 54 e8 0f b0 c6 f6 31 ed eb 53 e8 06 b0 c6 f6 48 8d 3d 2f 50 9c 04 <67> 48 0f b9 3a 31 ed eb 42 e8 c1 13 1f 00 89 c5 31 ff 89 c6 e8 96 +RSP: 0018:ffffc900041c70e0 EFLAGS: 00010283 +RAX: ffffffff8afdc6ca RBX: ffffffff8afdc4e6 RCX: 0000000000080000 +RDX: ffffc90010493000 RSI: 0000000000000948 RDI: ffffffff8f9a1700 +RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000 +R10: ffffc900041c71e8 R11: fffff52000838e3f R12: dffffc0000000000 +R13: ffff888041f9e3c0 R14: ffff888086ee3802 R15: 0000000000000000 +FS: 00007f6fe985d6c0(0000) GS:ffff888126176000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f80bd437dac CR3: 0000000025096000 CR4: 00000000003526f0 +DR0: ffffffffffffffff DR1: 00000000000001f8 DR2: 0000000000000002 +DR3: ffffffffefffff15 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +Call Trace: + + check_local_dest net/hsr/hsr_forward.c:592 [inline] + fill_frame_info net/hsr/hsr_forward.c:728 [inline] + hsr_forward_skb+0xa11/0x2a80 net/hsr/hsr_forward.c:739 + hsr_dev_xmit+0x253/0x370 net/hsr/hsr_device.c:236 + __netdev_start_xmit include/linux/netdevice.h:5368 [inline] + netdev_start_xmit include/linux/netdevice.h:5377 [inline] + xmit_one net/core/dev.c:3888 [inline] + dev_hard_start_xmit+0x2df/0x860 net/core/dev.c:3904 + __dev_queue_xmit+0x1428/0x3900 net/core/dev.c:4870 + neigh_output include/net/neighbour.h:556 [inline] + ip_finish_output2+0xcec/0x10b0 net/ipv4/ip_output.c:237 + ip_send_skb net/ipv4/ip_output.c:1510 [inline] + ip_push_pending_frames+0x8b/0x110 net/ipv4/ip_output.c:1530 + raw_sendmsg+0x1547/0x1a50 net/ipv4/raw.c:659 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x7da/0x9c0 net/socket.c:2698 + ___sys_sendmsg+0x2a5/0x360 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0x1c3/0x2a0 net/socket.c:2787 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f6feb62ce59 +Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 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 e8 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f6fe985d028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +RAX: ffffffffffffffda RBX: 00007f6feb8a6090 RCX: 00007f6feb62ce59 +RDX: 0000000000000000 RSI: 0000200000000000 RDI: 0000000000000004 +RBP: 00007f6feb6c2d6f R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 +R13: 00007f6feb8a6128 R14: 00007f6feb8a6090 R15: 00007ffcf01cc488 + + +Fixes: f266a683a480 ("net/hsr: Better frame dispatch") +Reported-by: syzbot+652670cf249077eb498b@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1a861e.b111c304.35cd64.0016.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260530064300.340793-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_framereg.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c +index f268e469af4f09..7f55e12edc8341 100644 +--- a/net/hsr/hsr_framereg.c ++++ b/net/hsr/hsr_framereg.c +@@ -35,10 +35,8 @@ bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr) + + rcu_read_lock(); + sn = rcu_dereference(hsr->self_node); +- if (!sn) { +- WARN_ONCE(1, "HSR: No self node\n"); ++ if (!sn) + goto out; +- } + + if (ether_addr_equal(addr, sn->macaddress_A) || + ether_addr_equal(addr, sn->macaddress_B)) +-- +2.53.0 + diff --git a/queue-7.0/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch b/queue-7.0/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch new file mode 100644 index 0000000000..5ca885c696 --- /dev/null +++ b/queue-7.0/ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch @@ -0,0 +1,56 @@ +From df9cf98bb3209402dc64068b9870ce0487e621d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 07:29:55 +0000 +Subject: ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit() + +From: Eric Dumazet + +[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ] + +The aoe driver (or similar) generates a non-IPv6 packet +(e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() +on a 6LoWPAN interface (configured by the user or test case). + +Since the packet is not IPv6, the 6LoWPAN header_ops->create function +(lowpan_header_create or header_create) returns early without initializing +the lowpan_addr_info structure in the skb headroom. + +In the transmit function (lowpan_xmit), the driver calls lowpan_header +(or setup_header) which unconditionally copies and uses the lowpan_addr_info +from the headroom, which contains uninitialized data. + +Fix this by dropping non IPv6 packets. + +A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit(). + +Fixes: 4dc315e267fe ("ieee802154: 6lowpan: move transmit functionality") +Reported-by: syzbot+f13c19f75e1097abd116@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6a1fd763.278b5b03.2bcf39.0049.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260603072955.4032221-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ieee802154/6lowpan/tx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c +index 0c07662b44c0ca..4df76ff50699ed 100644 +--- a/net/ieee802154/6lowpan/tx.c ++++ b/net/ieee802154/6lowpan/tx.c +@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) + + pr_debug("package xmit\n"); + ++ if (skb->protocol != htons(ETH_P_IPV6)) { ++ kfree_skb(skb); ++ return NET_XMIT_DROP; ++ } ++ + WARN_ON_ONCE(skb->len > IPV6_MIN_MTU); + + /* We must take a copy of the skb before we modify/replace the ipv6 +-- +2.53.0 + diff --git a/queue-7.0/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch b/queue-7.0/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch new file mode 100644 index 0000000000..b8ced33d1b --- /dev/null +++ b/queue-7.0/ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch @@ -0,0 +1,54 @@ +From 99777d39a256dd0a5578fe3c4f483a96630295e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 16:15:47 +0000 +Subject: ipv4: restrict IPOPT_SSRR and IPOPT_LSRR options + +From: Eric Dumazet + +[ Upstream commit d3915a1f5a4bc0ac911032903c3c6ab8df9fcc7c ] + +This patch restricts setting Loose Source and Record Route (LSRR) +and Strict Source and Record Route (SSRR) IP options to users +with CAP_NET_RAW capability. + +This prevents unprivileged applications from forcing packets to route +through attacker-controlled nodes to leak TCP ISN and possibly other +protocol information. + +While LSRR and SSRR are commonly filtered in many network environments, +they may still be supported and forwarded along some network paths. + +RFC 7126 (Recommendations on Filtering of IPv4 Packets Containing +IPv4 Options) recommend to drop these options in 4.3 and 4.4. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260602161547.2642155-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_options.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index be8815ce3ac242..09d745112c1526 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -530,6 +530,10 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp, + kfree(opt); + return -EINVAL; + } ++ if (opt->opt.srr && !ns_capable(net->user_ns, CAP_NET_RAW)) { ++ kfree(opt); ++ return -EPERM; ++ } + kfree(*optp); + *optp = opt; + return 0; +-- +2.53.0 + diff --git a/queue-7.0/ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch b/queue-7.0/ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch new file mode 100644 index 0000000000..447d7228c3 --- /dev/null +++ b/queue-7.0/ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch @@ -0,0 +1,124 @@ +From 65409163671bf0708082f51a9e8e4e0ef5fbf070 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 23:22:18 +0800 +Subject: ipv6: anycast: insert aca into global hash under idev->lock + +From: Jiayuan Chen + +[ Upstream commit f723ccaff2fb72b71ae8a9fd283f0dee4d9ae7a3 ] + +syzbot reported a splat [1]: a slab-use-after-free in +ipv6_chk_acast_addr(), which walks the global inet6_acaddr_lst[] hash +under RCU and dereferences a struct ifacaddr6 that has already been +freed while still linked in the hash, so a later reader walks into a +dangling node. + +In __ipv6_dev_ac_inc() the aca is allocated with refcount 1, then +aca_get() bumps it to 2 to keep it alive across the unlocked region. +It is published to idev->ac_list under idev->lock, but +ipv6_add_acaddr_hash() runs after write_unlock_bh(). A concurrent +teardown (ipv6_ac_destroy_dev() from addrconf_ifdown(), under RTNL) +can slip into that window: + + CPU0 __ipv6_dev_ac_inc CPU1 ipv6_ac_destroy_dev (RTNL) + ------------------------------ ------------------------------------ + aca_alloc() refcnt 1 + aca_get() refcnt 2 + write_lock_bh(idev->lock) + add aca to ac_list + write_unlock_bh(idev->lock) + write_lock_bh(idev->lock) + pull aca off ac_list + write_unlock_bh(idev->lock) + ipv6_del_acaddr_hash(aca) + hlist_del_init_rcu() is a no-op, + aca is not in the hash yet + aca_put() refcnt 2->1 + ipv6_add_acaddr_hash(aca) + aca now inserted into the hash + aca_put() refcnt 1->0 + call_rcu(aca_free_rcu) -> kfree(aca) + +The hash removal becomes a no-op because the insertion has not +happened yet, so once CPU0 inserts and drops the last reference, the +aca is freed while still linked in inet6_acaddr_lst[], and readers +dereference freed memory after the slab slot is reused. + +This window opened once RTNL stopped serializing the join path against +device teardown. Move ipv6_add_acaddr_hash() inside the idev->lock +section so the ac_list and hash insertions are atomic with respect to +teardown: a racing remover now either misses the aca entirely or finds +it in both lists. + +acaddr_hash_lock is now nested under idev->lock, which is acquired in +softirq context, so switch all acaddr_hash_lock sites to spin_lock_bh() +to avoid the irq lock inversion reported in [2]. + +[1] https://syzkaller.appspot.com/bug?extid=a01df04303c131efbf3a +[2] https://lore.kernel.org/netdev/6a194ef7.ba3b1513.1890b4.0000.GAE@google.com/ + +Reported-by: syzbot+819eb928d120d2bdad0e@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a191f87.ce022c6e.138e56.0003.GAE@google.com/T/ +Reviewed-by: Kuniyuki Iwashima +Fixes: eb1ac9ff6c4a ("ipv6: anycast: Don't hold RTNL for IPV6_JOIN_ANYCAST.") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260529152219.235475-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/anycast.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c +index 67a42e01dfc3f0..be6dac8a8566a1 100644 +--- a/net/ipv6/anycast.c ++++ b/net/ipv6/anycast.c +@@ -243,16 +243,16 @@ static void ipv6_add_acaddr_hash(struct net *net, struct ifacaddr6 *aca) + { + unsigned int hash = inet6_acaddr_hash(net, &aca->aca_addr); + +- spin_lock(&acaddr_hash_lock); ++ spin_lock_bh(&acaddr_hash_lock); + hlist_add_head_rcu(&aca->aca_addr_lst, &inet6_acaddr_lst[hash]); +- spin_unlock(&acaddr_hash_lock); ++ spin_unlock_bh(&acaddr_hash_lock); + } + + static void ipv6_del_acaddr_hash(struct ifacaddr6 *aca) + { +- spin_lock(&acaddr_hash_lock); ++ spin_lock_bh(&acaddr_hash_lock); + hlist_del_init_rcu(&aca->aca_addr_lst); +- spin_unlock(&acaddr_hash_lock); ++ spin_unlock_bh(&acaddr_hash_lock); + } + + static void aca_get(struct ifacaddr6 *aca) +@@ -371,10 +371,10 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) + aca->aca_next = idev->ac_list; + rcu_assign_pointer(idev->ac_list, aca); + +- write_unlock_bh(&idev->lock); +- + ipv6_add_acaddr_hash(net, aca); + ++ write_unlock_bh(&idev->lock); ++ + ip6_ins_rt(net, f6i); + + addrconf_join_solict(idev->dev, &aca->aca_addr); +@@ -649,8 +649,8 @@ void ipv6_anycast_cleanup(void) + { + int i; + +- spin_lock(&acaddr_hash_lock); ++ spin_lock_bh(&acaddr_hash_lock); + for (i = 0; i < IN6_ADDR_HSIZE; i++) + WARN_ON(!hlist_empty(&inet6_acaddr_lst[i])); +- spin_unlock(&acaddr_hash_lock); ++ spin_unlock_bh(&acaddr_hash_lock); + } +-- +2.53.0 + diff --git a/queue-7.0/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch b/queue-7.0/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch new file mode 100644 index 0000000000..c57410b605 --- /dev/null +++ b/queue-7.0/ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch @@ -0,0 +1,107 @@ +From c9d11fe24aba67d9adbd03e528b6adc93bb27b39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 13:18:11 +0300 +Subject: ipv6: mcast: Fix use-after-free when processing MLD queries + +From: Ido Schimmel + +[ Upstream commit 791c91dc7a9dfb2457d5e29b8216a6484b9c4b40 ] + +When processing an MLD query, a pointer to the multicast group address +is retrieved when initially parsing the packet. This pointer is later +dereferenced without being reloaded despite the fact that the skb header +might have been reallocated following the pskb_may_pull() calls, leading +to a use-after-free [1]. + +Fix by copying the multicast group address when the packet is initially +parsed. + +[1] +BUG: KASAN: slab-use-after-free in __mld_query_work (net/ipv6/mcast.c:1512) +Read of size 8 at addr ffff8881154b8e90 by task kworker/4:1/118 + +Workqueue: mld mld_query_work +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +print_address_description.constprop.0 (mm/kasan/report.c:378) +print_report (mm/kasan/report.c:482) +kasan_report (mm/kasan/report.c:595) +__mld_query_work (net/ipv6/mcast.c:1512) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + + +[...] + +Freed by task 118: +kasan_save_stack (mm/kasan/common.c:57) +kasan_save_track (mm/kasan/common.c:78) +kasan_save_free_info (mm/kasan/generic.c:584) +__kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285) +kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566) +pskb_expand_head (net/core/skbuff.c:2335) +__pskb_pull_tail (net/core/skbuff.c:2878 (discriminator 4)) +__mld_query_work (net/ipv6/mcast.c:1495 (discriminator 1)) +mld_query_work (net/ipv6/mcast.c:1563) +process_one_work (kernel/workqueue.c:3314) +worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478) +kthread (kernel/kthread.c:436) +ret_from_fork (arch/x86/kernel/process.c:158) +ret_from_fork_asm (arch/x86/entry/entry_64.S:245) + +Fixes: 97300b5fdfe2 ("[MCAST] IPv6: Check packet size when process Multicast") +Reported-by: Leo Lin +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260603101811.612594-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index 3330adcf26db24..d9b855d5191bf6 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1424,9 +1424,9 @@ void igmp6_event_query(struct sk_buff *skb) + static void __mld_query_work(struct sk_buff *skb) + { + struct mld2_query *mlh2 = NULL; +- const struct in6_addr *group; + unsigned long max_delay; + struct inet6_dev *idev; ++ struct in6_addr group; + struct ifmcaddr6 *ma; + struct mld_msg *mld; + int group_type; +@@ -1458,8 +1458,8 @@ static void __mld_query_work(struct sk_buff *skb) + goto kfree_skb; + + mld = (struct mld_msg *)icmp6_hdr(skb); +- group = &mld->mld_mca; +- group_type = ipv6_addr_type(group); ++ group = mld->mld_mca; ++ group_type = ipv6_addr_type(&group); + + if (group_type != IPV6_ADDR_ANY && + !(group_type&IPV6_ADDR_MULTICAST)) +@@ -1509,7 +1509,7 @@ static void __mld_query_work(struct sk_buff *skb) + } + } else { + for_each_mc_mclock(idev, ma) { +- if (!ipv6_addr_equal(group, &ma->mca_addr)) ++ if (!ipv6_addr_equal(&group, &ma->mca_addr)) + continue; + if (ma->mca_flags & MAF_TIMER_RUNNING) { + /* gsquery <- gsquery && mark */ +-- +2.53.0 + diff --git a/queue-7.0/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch b/queue-7.0/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch new file mode 100644 index 0000000000..76a0c61d74 --- /dev/null +++ b/queue-7.0/ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch @@ -0,0 +1,127 @@ +From 783e1c75875a65d9e173ee633ad7717facc56d79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 07:07:44 +0300 +Subject: ipvs: clear the svc scheduler ptr early on edit + +From: Julian Anastasov + +[ Upstream commit 193989cc6d80dd8e0460fb3992e69fa03bf0ff9b ] + +ip_vs_edit_service() while unbinding the old scheduler clears +the svc->scheduler ptr after the scheduler module initiates +RCU callbacks. This can cause packets to use the old +scheduler at the time when svc->sched_data is already freed +after RCU grace period. + +Fix it by clearing the ptr early in ip_vs_unbind_scheduler(), +before the done_service method schedules any RCU callbacks. + +Also, if the new scheduler fails to initialize when replacing +the old scheduler, try to restore the old scheduler while still +returning the error code. + +Link: https://sashiko.dev/#/patchset/20260519015506.634185-1-rosenp%40gmail.com +Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed") +Signed-off-by: Julian Anastasov +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/ip_vs.h | 3 +-- + net/netfilter/ipvs/ip_vs_ctl.c | 13 ++++++++----- + net/netfilter/ipvs/ip_vs_sched.c | 14 +++++++------- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +index 29a36709e7f35c..2163f32ef6abc1 100644 +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -1519,8 +1519,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); + int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched); ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc); + struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); + void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); + struct ip_vs_conn * +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index 2aaf50f52c8e8e..ff55ff6b8a4cba 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -1496,7 +1496,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, + if (ret_hooks >= 0) + ip_vs_unregister_hooks(ipvs, u->af); + if (svc != NULL) { +- ip_vs_unbind_scheduler(svc, sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_service_free(svc); + } + ip_vs_scheduler_put(sched); +@@ -1558,9 +1558,8 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + old_sched = rcu_dereference_protected(svc->scheduler, 1); + if (sched != old_sched) { + if (old_sched) { +- ip_vs_unbind_scheduler(svc, old_sched); +- RCU_INIT_POINTER(svc->scheduler, NULL); +- /* Wait all svc->sched_data users */ ++ ip_vs_unbind_scheduler(svc); ++ /* Wait all svc->scheduler/sched_data users */ + synchronize_rcu(); + } + /* Bind the new scheduler */ +@@ -1568,6 +1567,10 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) + ret = ip_vs_bind_scheduler(svc, sched); + if (ret) { + ip_vs_scheduler_put(sched); ++ /* Try to restore the old_sched */ ++ if (old_sched && ++ !ip_vs_bind_scheduler(svc, old_sched)) ++ old_sched = NULL; + goto out; + } + } +@@ -1624,7 +1627,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup) + + /* Unbind scheduler */ + old_sched = rcu_dereference_protected(svc->scheduler, 1); +- ip_vs_unbind_scheduler(svc, old_sched); ++ ip_vs_unbind_scheduler(svc); + ip_vs_scheduler_put(old_sched); + + /* Unbind persistence engine, keep svc->pe */ +diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c +index c6e421c4e29913..24adc38942a0d1 100644 +--- a/net/netfilter/ipvs/ip_vs_sched.c ++++ b/net/netfilter/ipvs/ip_vs_sched.c +@@ -56,19 +56,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, + /* + * Unbind a service with its scheduler + */ +-void ip_vs_unbind_scheduler(struct ip_vs_service *svc, +- struct ip_vs_scheduler *sched) ++void ip_vs_unbind_scheduler(struct ip_vs_service *svc) + { +- struct ip_vs_scheduler *cur_sched; ++ struct ip_vs_scheduler *sched; + +- cur_sched = rcu_dereference_protected(svc->scheduler, 1); +- /* This check proves that old 'sched' was installed */ +- if (!cur_sched) ++ sched = rcu_dereference_protected(svc->scheduler, 1); ++ if (!sched) + return; + ++ /* Reset the scheduler before initiating any RCU callbacks */ ++ rcu_assign_pointer(svc->scheduler, NULL); ++ smp_wmb(); /* paired with smp_rmb() in ip_vs_schedule() */ + if (sched->done_service) + sched->done_service(svc); +- /* svc->scheduler can be set to NULL only by caller */ + } + + +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch b/queue-7.0/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch new file mode 100644 index 0000000000..ab1348fd52 --- /dev/null +++ b/queue-7.0/ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch @@ -0,0 +1,75 @@ +From 0676d1aba2298e92d136d853b013c7ecf4db7c39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 00:00:00 +0000 +Subject: ksmbd: fix NULL-deref of opinfo->conn in oplock/lease break notifiers + +From: Gil Portnoy + +[ Upstream commit b003086d76968298f22e7cf62239833b5a3a06b1 ] + +smb2_oplock_break_noti() and smb2_lease_break_noti() read opinfo->conn +into a local with neither READ_ONCE() nor a NULL check. Both run from +oplock_break() after opinfo_get_list() has dropped ci->m_lock, so a +concurrent SMB2 LOGOFF (session_fd_check()) can set op->conn = NULL +under ci->m_lock within that window. ksmbd_conn_r_count_inc(conn) then +writes through NULL at offset 0xc4 -- a remotely triggerable oops. + +Guard both reads the way compare_guid_key() already does: read +opinfo->conn with READ_ONCE() and return early if it is NULL, before +allocating the work struct so nothing leaks. A NULL conn means the +client is gone and the break is moot, so return 0; oplock_break() treats +that as success and runs the normal teardown. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Assisted-by: Henry (Claude):claude-opus-4 +Signed-off-by: Gil Portnoy +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/oplock.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index f5ec1283b16edf..d09fa50ba03a29 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -714,11 +714,16 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) + */ + static int smb2_oplock_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct oplock_break_info *br_info; + int ret = 0; +- struct ksmbd_work *work = ksmbd_alloc_work_struct(); ++ struct ksmbd_work *work; ++ ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; + ++ work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; + +@@ -818,11 +823,15 @@ static void __smb2_lease_break_noti(struct work_struct *wk) + */ + static int smb2_lease_break_noti(struct oplock_info *opinfo) + { +- struct ksmbd_conn *conn = opinfo->conn; ++ struct ksmbd_conn *conn; + struct ksmbd_work *work; + struct lease_break_info *br_info; + struct lease *lease = opinfo->o_lease; + ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; ++ + work = ksmbd_alloc_work_struct(); + if (!work) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-7.0/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch b/queue-7.0/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch new file mode 100644 index 0000000000..fb6d026fd9 --- /dev/null +++ b/queue-7.0/l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch @@ -0,0 +1,176 @@ +From 548129a1d727b694a88b07a6207328064e66a157 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:36:29 +0000 +Subject: l2tp: pppol2tp: hold reference to session in pppol2tp_ioctl() + +From: Lee Jones + +[ Upstream commit a213a8950414c684999dcf03edeea6c46ede172e ] + +pppol2tp_ioctl() read sock->sk->sk_user_data directly without any +locks or reference counting. If a controllable sleep was induced during +copy_from_user() (e.g. via a userfaultfd page fault sleep), a concurrent +socket close could trigger pppol2tp_session_close() asynchronously. This +frees the l2tp_session structure via the l2tp_session_del_work workqueue. +Upon resuming, the ioctl thread dereferences the stale session pointer, +resulting in a Use-After-Free (UAF). + +Fix this by securely fetching the session reference using the RCU-safe, +refcounted helper pppol2tp_sock_to_session(sk) on entry. This locks the +session's refcount across the sleep. We structured the function to exit +via standard err breaks, guaranteeing that l2tp_session_put() is cleanly +called on all return paths to drop the reference. + +To preserve existing behavior we validate the session and its magic +signature only for the specific L2TP commands that require it. This +ensures that generic/unknown ioctls called on an unconnected socket +still return -ENOIOCTLCMD and correctly fall back to generic handlers +(e.g. in sock_do_ioctl()). + +Signed-off-by: Lee Jones +Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") +Link: https://patch.msgid.link/20260527133630.2120612-1-lee@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/l2tp/l2tp_ppp.c | 82 +++++++++++++++++++++++++++------------------ + 1 file changed, 50 insertions(+), 32 deletions(-) + +diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c +index ae4543d5597b66..8ff8bf45dc2231 100644 +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -1044,64 +1044,76 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, + { + struct pppol2tp_ioc_stats stats; + struct l2tp_session *session; ++ int err = 0; ++ ++ session = pppol2tp_sock_to_session(sock->sk); + ++ /* Validate session presence and magic integrity ONLY for commands ++ * that belong to L2TP and require a valid session. ++ */ + switch (cmd) { + case PPPIOCGMRU: + case PPPIOCGFLAGS: +- session = sock->sk->sk_user_data; ++ case PPPIOCSMRU: ++ case PPPIOCSFLAGS: ++ case PPPIOCGL2TPSTATS: + if (!session) + return -ENOTCONN; + +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) ++ if (session->magic != L2TP_SESSION_MAGIC) { ++ l2tp_session_put(session); + return -EBADF; ++ } ++ break; ++ default: ++ break; ++ } + ++ switch (cmd) { ++ case PPPIOCGMRU: ++ case PPPIOCGFLAGS: + /* Not defined for tunnels */ +- if (!session->session_id && !session->peer_session_id) +- return -ENOSYS; ++ if (!session->session_id && !session->peer_session_id) { ++ err = -ENOSYS; ++ break; ++ } + +- if (put_user(0, (int __user *)arg)) +- return -EFAULT; ++ if (put_user(0, (int __user *)arg)) { ++ err = -EFAULT; ++ break; ++ } + break; + + case PPPIOCSMRU: + case PPPIOCSFLAGS: +- session = sock->sk->sk_user_data; +- if (!session) +- return -ENOTCONN; +- +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) +- return -EBADF; +- + /* Not defined for tunnels */ +- if (!session->session_id && !session->peer_session_id) +- return -ENOSYS; ++ if (!session->session_id && !session->peer_session_id) { ++ err = -ENOSYS; ++ break; ++ } + +- if (!access_ok((int __user *)arg, sizeof(int))) +- return -EFAULT; ++ if (!access_ok((int __user *)arg, sizeof(int))) { ++ err = -EFAULT; ++ break; ++ } + break; + + case PPPIOCGL2TPSTATS: +- session = sock->sk->sk_user_data; +- if (!session) +- return -ENOTCONN; +- +- if (WARN_ON(session->magic != L2TP_SESSION_MAGIC)) +- return -EBADF; +- + /* Session 0 represents the parent tunnel */ + if (!session->session_id && !session->peer_session_id) { + u32 session_id; +- int err; + + if (copy_from_user(&stats, (void __user *)arg, +- sizeof(stats))) +- return -EFAULT; ++ sizeof(stats))) { ++ err = -EFAULT; ++ break; ++ } + + session_id = stats.session_id; + err = pppol2tp_tunnel_copy_stats(&stats, + session->tunnel); + if (err < 0) +- return err; ++ break; + + stats.session_id = session_id; + } else { +@@ -1111,15 +1123,21 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, + stats.tunnel_id = session->tunnel->tunnel_id; + stats.using_ipsec = l2tp_tunnel_uses_xfrm(session->tunnel); + +- if (copy_to_user((void __user *)arg, &stats, sizeof(stats))) +- return -EFAULT; ++ if (copy_to_user((void __user *)arg, &stats, sizeof(stats))) { ++ err = -EFAULT; ++ break; ++ } + break; + + default: +- return -ENOIOCTLCMD; ++ err = -ENOIOCTLCMD; ++ break; + } + +- return 0; ++ if (session) ++ l2tp_session_put(session); ++ ++ return err; + } + + /***************************************************************************** +-- +2.53.0 + diff --git a/queue-7.0/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch b/queue-7.0/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch new file mode 100644 index 0000000000..5863d004cc --- /dev/null +++ b/queue-7.0/net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch @@ -0,0 +1,79 @@ +From b744e60c9be3a652d01a727ffbe0505f8555199a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:00:13 +0800 +Subject: net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr + +From: Yizhou Zhao + +[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ] + +In mrp_pdu_parse_vecattr(), vector attribute events are encoded three +per byte and valen tracks the number of events left to process. + +The parser decrements valen after processing the first and second events +from each event byte, but not after processing the third one. When valen +is exactly a multiple of three, the loop continues after the last valid +event and consumes the next byte as a new event byte, applying a +spurious event to the MRP applicant state. + +Additionally, when valen is zero the parser unconditionally consumes +attrlen bytes as FirstValue and advances the offset, even though per +IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of +zero and no FirstValue or Vector fields. This corrupts the offset for +subsequent PDU parsing. + +Also, when valen exceeds three the loop crosses byte boundaries but +the attribute value is not incremented between the last event of one +byte and the first event of the next. This causes the first event of +the next byte to use the same attribute value as the third event +rather than the next consecutive value. + +Decrement valen after processing the third event, skip FirstValue +consumption when valen is zero, and increment the attribute value at +the end of each loop iteration. + +Fixes: febf018d2234 ("net/802: Implement Multiple Registration Protocol (MRP)") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Link: https://patch.msgid.link/20260603060016.21522-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/mrp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/802/mrp.c b/net/802/mrp.c +index ff0e80574e6b7b..160a3b14569cbd 100644 +--- a/net/802/mrp.c ++++ b/net/802/mrp.c +@@ -703,6 +703,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) & + MRP_VECATTR_HDR_LEN_MASK); + ++ /* If valen is 0, only a LeaveAllEvent is present; FirstValue and ++ * Vector fields are absent per IEEE 802.1ak. ++ */ ++ if (valen == 0) ++ return 0; ++ + /* The VectorAttribute structure in a PDU carries event information + * about one or more attributes having consecutive values. Only the + * value for the first attribute is contained in the structure. So +@@ -753,6 +759,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, + vaevents %= __MRP_VECATTR_EVENT_MAX; + vaevent = vaevents; + mrp_pdu_parse_vecattr_event(app, skb, vaevent); ++ valen--; ++ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue, ++ mrp_cb(skb)->mh->attrlen); + } + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch b/queue-7.0/net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch new file mode 100644 index 0000000000..145d1e3ab7 --- /dev/null +++ b/queue-7.0/net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch @@ -0,0 +1,47 @@ +From 07e6ea0a9cb66f770fba098955b0a2f43a00a166 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:21:04 +0200 +Subject: net: airoha: Fix use-after-free in metadata dst teardown + +From: Lorenzo Bianconi + +[ Upstream commit b38cae85d1c45ff189d7ecb6ac36f41cdc3d84d0 ] + +airoha_metadata_dst_free() runs metadata_dst_free() which frees the +metadata_dst with kfree() immediately, bypassing the RCU grace period. +In the RX path, skb_dst_set_noref() sets a non-refcounted pointer from +the skb to the metadata_dst. This function requires RCU read-side +protection and the dst must remain valid until all RCU readers complete. +Since metadata_dst_free() calls kfree() directly, an use-after-free can +occur if any skb still holds a noref pointer to the dst when the driver +tears it down. +Replace metadata_dst_free() with dst_release() which properly goes +through the refcount path: when the refcount drops to zero, it schedules +the actual free via call_rcu_hurry(), ensuring all RCU readers have +completed before the memory is freed. + +Fixes: af3cf757d5c9 ("net: airoha: Move DSA tag in DMA descriptor") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260602-airoha-mtk-metadata-uaf-fix-v1-1-3aaa99d83351@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 13f74335928660..698a305ca694c6 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2935,7 +2935,7 @@ static void airoha_metadata_dst_free(struct airoha_gdm_port *port) + if (!port->dsa_meta[i]) + continue; + +- metadata_dst_free(port->dsa_meta[i]); ++ dst_release(&port->dsa_meta[i]->dst); + } + } + +-- +2.53.0 + diff --git a/queue-7.0/net-annotate-sk-sk_write_space-for-udp-sockmap.patch b/queue-7.0/net-annotate-sk-sk_write_space-for-udp-sockmap.patch new file mode 100644 index 0000000000..442e14b89e --- /dev/null +++ b/queue-7.0/net-annotate-sk-sk_write_space-for-udp-sockmap.patch @@ -0,0 +1,60 @@ +From 3d941cedd822da23ef6bf06fc68f43591772ee04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:39:23 +0000 +Subject: net: Annotate sk->sk_write_space() for UDP SOCKMAP. + +From: Kuniyuki Iwashima + +[ Upstream commit b748765019fe9e9234660327090fc1a9665cdbdd ] + +UDP TX skb->destructor() is sock_wfree(), and UDP holds lock_sock() +only for UDP_CORK / MSG_MORE sendmsg(). + +Otherwise, sk->sk_write_space() may be read locklessly while SOCKMAP +rewrites sk->sk_write_space(). + +Let's use WRITE_ONCE() and READ_ONCE() for sk->sk_write_space(). + +Note that the write side is annotated by commit 2ef2b20cf4e0 +("net: annotate data-races around sk->sk_{data_ready,write_space}"). + +Fixes: 7b98cd42b049 ("bpf: sockmap: Add UDP support") +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Jakub Sitnicki +Link: https://patch.msgid.link/20260529193941.3897256-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 5976100a9d55a0..b197a795306392 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2673,8 +2673,12 @@ void sock_wfree(struct sk_buff *skb) + int old; + + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { ++ void (*sk_write_space)(struct sock *sk); ++ ++ sk_write_space = READ_ONCE(sk->sk_write_space); ++ + if (sock_flag(sk, SOCK_RCU_FREE) && +- sk->sk_write_space == sock_def_write_space) { ++ sk_write_space == sock_def_write_space) { + rcu_read_lock(); + free = __refcount_sub_and_test(len, &sk->sk_wmem_alloc, + &old); +@@ -2690,7 +2694,7 @@ void sock_wfree(struct sk_buff *skb) + * after sk_write_space() call + */ + WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc)); +- sk->sk_write_space(sk); ++ sk_write_space(sk); + len = 1; + } + /* +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch b/queue-7.0/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch new file mode 100644 index 0000000000..f333cffb90 --- /dev/null +++ b/queue-7.0/net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch @@ -0,0 +1,48 @@ +From e7086575ae3f8882dfe972b02a2bf17a81386ebf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:21:05 +0200 +Subject: net: ethernet: mtk_eth_soc: Fix use-after-free in metadata dst + teardown + +From: Lorenzo Bianconi + +[ Upstream commit 80df409e1a483676826a6c66e693dba6ac507751 ] + +mtk_free_dev() calls metadata_dst_free() which frees the metadata_dst +with kfree() immediately, bypassing the RCU grace period. +In the RX path, skb_dst_set_noref() sets a non-refcounted pointer from +the skb to the metadata_dst. This function requires RCU read-side +protection and the dst must remain valid until all RCU readers complete. +Since metadata_dst_free() calls kfree() directly, a use-after-free can +occur if any skb still holds a noref pointer to the dst when the driver +tears it down. +Replace metadata_dst_free() with dst_release() which properly goes +through the refcount path: when the refcount drops to zero, it schedules +the actual free via call_rcu_hurry(), ensuring all RCU readers have +completed before the memory is freed. + +Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260602-airoha-mtk-metadata-uaf-fix-v1-2-3aaa99d83351@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 796f79088f3662..2eca2b2a964fef 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4469,7 +4469,7 @@ static int mtk_free_dev(struct mtk_eth *eth) + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { + if (!eth->dsa_meta[i]) + break; +- metadata_dst_free(eth->dsa_meta[i]); ++ dst_release(ð->dsa_meta[i]->dst); + } + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch b/queue-7.0/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch new file mode 100644 index 0000000000..7fa8256636 --- /dev/null +++ b/queue-7.0/net-fec-fix-pinctrl-default-state-restore-order-on-r.patch @@ -0,0 +1,62 @@ +From c6ccbb159511bbfb862fa8c4fb0a83ec8b6ba2cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 06:18:57 +0000 +Subject: net: fec: fix pinctrl default state restore order on resume + +From: Tapio Reijonen + +[ Upstream commit b455410146bf723c7ebcb49ecd5becc0d6611482 ] + +In fec_resume(), fec_enet_clk_enable() is called before +pinctrl_pm_select_default_state() in the non-WoL path, inverting the +ordering used in fec_suspend() which correctly switches to the sleep +pinctrl state before disabling clocks. + +For PHYs with the PHY_RST_AFTER_CLK_EN flag (e.g. TI DP83848 or +SMSC LAN87xx), fec_enet_clk_enable() triggers a hardware reset pulse +via the phy-reset GPIO. With the GPIO pin still in sleep pinctrl state +at that point, the GPIO write has no physical effect and the PHY never +receives the required reset after clock enable, leading to unreliable +link establishment after system resume. + +Fix by restoring the default pinctrl state before enabling clocks, +making resume the proper mirror of suspend. The call is made +unconditionally: fec_suspend() only switches to the sleep pinctrl state +on the non-WoL path and leaves the pins in the default state when WoL +is enabled, so on a WoL resume the device is already in the default +state and pinctrl_pm_select_default_state() is a no-op. + +Fixes: de40ed31b3c5 ("net: fec: add Wake-on-LAN support") +Signed-off-by: Tapio Reijonen +Reviewed-by: Wei Fang +Link: https://patch.msgid.link/20260529-b4-fec-resume-pinctrl-order-v3-1-6eda0f592fca@vaisala.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/fec_main.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index f89aa94ce0202d..6ebde65d7f1b87 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -5594,6 +5594,7 @@ static int fec_resume(struct device *dev) + if (fep->rpm_active) + pm_runtime_force_resume(dev); + ++ pinctrl_pm_select_default_state(&fep->pdev->dev); + ret = fec_enet_clk_enable(ndev, true); + if (ret) { + rtnl_unlock(); +@@ -5610,8 +5611,6 @@ static int fec_resume(struct device *dev) + val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; +- } else { +- pinctrl_pm_select_default_state(&fep->pdev->dev); + } + fec_restart(ndev); + netif_tx_lock_bh(ndev); +-- +2.53.0 + diff --git a/queue-7.0/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch b/queue-7.0/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch new file mode 100644 index 0000000000..535a619b4f --- /dev/null +++ b/queue-7.0/net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch @@ -0,0 +1,58 @@ +From 4ea1ecbf654227622e401a3e1e3c36a4e45415dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:31:58 +0800 +Subject: net: garp: fix unsigned integer underflow in garp_pdu_parse_attr + +From: Yizhou Zhao + +[ Upstream commit 16e408e607a94b646fb14a2a98422c6877ae4b3c ] + +The receive-side GARP attribute parser computes dlen with reversed +operands: + + dlen = sizeof(*ga) - ga->len; + +ga->len is the on-wire attribute length and includes the GARP attribute +header. For normal attributes with data, ga->len is larger than +sizeof(*ga), so the subtraction underflows in unsigned arithmetic. + +The resulting value is later passed to garp_attr_lookup(), whose length +argument is u8. After truncation, the parsed data length usually no +longer matches the length stored for locally registered attributes, so +received Join/Leave events are ignored. This breaks the GARP receive path +for common attributes, such as GVRP VLAN registration attributes. + +Compute the data length as the attribute length minus the header length. + +Fixes: eca9ebac651f ("net: Add GARP applicant-only participant") +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Signed-off-by: Yizhou Zhao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260527083200.42861-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/802/garp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/802/garp.c b/net/802/garp.c +index 6f563b6797d99e..c7a39f298ad6ed 100644 +--- a/net/802/garp.c ++++ b/net/802/garp.c +@@ -453,7 +453,7 @@ static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, + if (!pskb_may_pull(skb, ga->len)) + return -1; + skb_pull(skb, ga->len); +- dlen = sizeof(*ga) - ga->len; ++ dlen = ga->len - sizeof(*ga); + + if (attrtype > app->app->maxattr) + return 0; +-- +2.53.0 + diff --git a/queue-7.0/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch b/queue-7.0/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch new file mode 100644 index 0000000000..ab49a89df9 --- /dev/null +++ b/queue-7.0/net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch @@ -0,0 +1,99 @@ +From 3f23e96e5d43f3ed96773fa97126a3230c5ded00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 21:03:00 +0000 +Subject: net: lan743x: permit VLAN-tagged packets up to configured MTU + +From: David Thompson + +[ Upstream commit 8173d22b211f615015f7b35f48ab11a6dd78dc99 ] + +VLAN-tagged interfaces on lan743x devices were previously unreachable via +SSH and failed to respond to large ping packets (e.g. "ping -s 1469" given +MTU=1500). In these scenarios, "ethtool -S" reports non-zero "RX Oversize +Frame Errors". According to Microchip AN2948, the MAC_RX FSE (VLAN field +size enforcement) bit determines whether frames with VLAN tags exceeding +the base MTU plus tag length are discarded. + +The driver must set the MAC_RX.FSE bit before setting MAC_RX.RXEN to allow +VLAN-tagged frames up to the interface MTU, preventing them from being +treated as oversized. As a result, both the base and VLAN-tagged interfaces +can use the same MTU without receive errors. + +Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") +Signed-off-by: David Thompson +Reviewed-by: Thangaraj Samynathan +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz # lan7430 on arm64 (RevPi +Link: https://patch.msgid.link/20260529210300.433135-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 32 +++++++++++++++++++ + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index f0b5dd752f084f..5af49b2b20245d 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1212,6 +1212,36 @@ static void lan743x_mac_set_address(struct lan743x_adapter *adapter, + "MAC address set to %pM\n", addr); + } + ++static void lan743x_mac_rx_enable_fse(struct lan743x_adapter *adapter) ++{ ++ u32 mac_rx; ++ bool rxen; ++ ++ mac_rx = lan743x_csr_read(adapter, MAC_RX); ++ if (mac_rx & MAC_RX_FSE_) ++ return; ++ ++ rxen = mac_rx & MAC_RX_RXEN_; ++ if (rxen) { ++ mac_rx &= ~MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, ++ 1, 1000, 20000, 100); ++ } ++ ++ /* Per AN2948, hardware prevents modification of the FSE bit while the ++ * MAC receiver is enabled (RXEN bit set). Use separate register write ++ * to assert the FSE bit before enabling the RXEN bit in MAC_RX ++ */ ++ mac_rx |= MAC_RX_FSE_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ ++ if (rxen) { ++ mac_rx |= MAC_RX_RXEN_; ++ lan743x_csr_write(adapter, MAC_RX, mac_rx); ++ } ++} ++ + static int lan743x_mac_init(struct lan743x_adapter *adapter) + { + bool mac_address_valid = true; +@@ -1251,6 +1281,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter) + lan743x_mac_set_address(adapter, adapter->mac_address); + eth_hw_addr_set(netdev, adapter->mac_address); + ++ lan743x_mac_rx_enable_fse(adapter); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 02a28b7091630d..b977256b742061 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -181,6 +181,7 @@ + #define MAC_RX (0x104) + #define MAC_RX_MAX_SIZE_SHIFT_ (16) + #define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) ++#define MAC_RX_FSE_ BIT(2) + #define MAC_RX_RXD_ BIT(1) + #define MAC_RX_RXEN_ BIT(0) + +-- +2.53.0 + diff --git a/queue-7.0/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch b/queue-7.0/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch new file mode 100644 index 0000000000..c83a78d9b9 --- /dev/null +++ b/queue-7.0/net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch @@ -0,0 +1,106 @@ +From 168436efcc100637ae89239206f2163c68f81ed0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 12:08:12 -0400 +Subject: net/sched: act_api: use RCU with deferred freeing for action + lifecycle + +From: Jamal Hadi Salim + +[ Upstream commit 5057e1aca011e51ef51498c940ef96f3d3e8a305 ] + +When NEWTFILTER and DELFILTER are run concurrently it is possible to create a +race with an associated action. + +Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: + + 0: mutex_lock() <-- holds the idr lock + 0: rcu_read_lock() + 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) + 0: mutex_unlock() <-- releases the idr lock + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) <-- Action removed from IDR + 1: mutex_unlock() <-- mutex released allowing us to delete the action + 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory + +This patch fixes the race condition between NEWTFILTER and DELFILTER by +adding struct rcu_head to tc_action used in the deferral and introducing a +call_rcu() in the delete path to defer the final kfree(). + +Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +but also modernization/simplification to directly use kfree_rcu(). + +Let's illustrate the new restored code path: + + 0: rcu_read_lock() + 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held + 1: idr_remove(idr, index) + 1: mutex_unlock() + 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period + 0: p = idr_find(idr, index) + 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 + 1: rcu_read_unlock() <-- release so freeing can run after grace period + +After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. +CPU0's subsequent idr_find() will return NULL, and even if it still held a +stale pointer, the immediate kfree() is now deferred until after the RCU grace +period, so no UAF can occur. + +Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") +Suggested-by: Jakub Kicinski +Reported-by: Kyle Zeng +Tested-by: Victor Nogueira +Tested-by: syzbot@syzkaller.appspotmail.com +Signed-off-by: Jamal Hadi Salim +Tested-by: Kyle Zeng +Reviewed-by: Pedro Tammela +Reviewed-by: Eric Dumazet +Reviewed-by: Victor Nogueira +Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/act_api.h | 1 + + net/sched/act_api.c | 7 +------ + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/net/act_api.h b/include/net/act_api.h +index d11b791079302f..fd2967ee08f7a6 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -45,6 +45,7 @@ struct tc_action { + struct tc_cookie __rcu *user_cookie; + struct tcf_chain __rcu *goto_chain; + u32 tcfa_flags; ++ struct rcu_head tcfa_rcu; + u8 hw_stats; + u8 used_hw_stats; + bool used_hw_stats_valid; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index 332fd9695e54a1..04ea11c90e0330 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -112,11 +112,6 @@ struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action, + } + EXPORT_SYMBOL(tcf_action_set_ctrlact); + +-/* XXX: For standalone actions, we don't need a RCU grace period either, because +- * actions are always connected to filters and filters are already destroyed in +- * RCU callbacks, so after a RCU grace period actions are already disconnected +- * from filters. Readers later can not find us. +- */ + static void free_tcf(struct tc_action *p) + { + struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1); +@@ -129,7 +124,7 @@ static void free_tcf(struct tc_action *p) + if (chain) + tcf_chain_put_by_act(chain); + +- kfree(p); ++ kfree_rcu(p, tcfa_rcu); + } + + static void offload_action_hw_count_set(struct tc_action *act, +-- +2.53.0 + diff --git a/queue-7.0/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch b/queue-7.0/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch new file mode 100644 index 0000000000..f9630742a6 --- /dev/null +++ b/queue-7.0/net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch @@ -0,0 +1,228 @@ +From 55fb75027cc77e69164865152a97768230b87766 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 08:32:21 -0400 +Subject: net/sched: fix pedit partial COW leading to page cache corruption +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rajat Gupta + +[ Upstream commit 899ee91156e57784090c5565e4f31bd7dbffbc5a ] + +tcf_pedit_act() computes the COW range for skb_ensure_writable() +once before the key loop using tcfp_off_max_hint, but the hint does +not account for the runtime header offset added by typed keys. This +can leave part of the write region un-COW'd. + +Fix by moving skb_ensure_writable() inside the per-key loop where +the actual write offset is known, and add overflow checking on the +offset arithmetic. For negative offsets (e.g. Ethernet header edits +at ingress), use skb_cow() to COW the headroom instead. Guard +offset_valid() against INT_MIN, where negation is undefined. + +Fixes: 8b796475fd78 ("net/sched: act_pedit: really ensure the skb is writable") +Reported-by: Yiming Qian +Reported-by: Keenan Dong +Reported-by: Han Guidong <2045gemini@gmail.com> +Reported-by: Zhang Cen +Reviewed-by: Han Guidong <2045gemini@gmail.com> +Tested-by: Han Guidong <2045gemini@gmail.com> +Reviewed-by: Davide Caratti +Tested-by: Davide Caratti +Reviewed-by: Toke Høiland-Jørgensen +Tested-by: Toke Høiland-Jørgensen +Reviewed-by: Victor Nogueira +Tested-by: Victor Nogueira +Acked-by: Jamal Hadi Salim +Signed-off-by: Rajat Gupta +Link: https://patch.msgid.link/20260531123221.48732-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tc_act/tc_pedit.h | 1 - + net/sched/act_pedit.c | 77 +++++++++++++++++++---------------- + 2 files changed, 41 insertions(+), 37 deletions(-) + +diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h +index f58ee15cd858cf..cb7b82f2cbc7fd 100644 +--- a/include/net/tc_act/tc_pedit.h ++++ b/include/net/tc_act/tc_pedit.h +@@ -15,7 +15,6 @@ struct tcf_pedit_parms { + struct tc_pedit_key *tcfp_keys; + struct tcf_pedit_key_ex *tcfp_keys_ex; + int action; +- u32 tcfp_off_max_hint; + unsigned char tcfp_nkeys; + unsigned char tcfp_flags; + struct rcu_head rcu; +diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c +index bc20f08a278901..bd3b1da3cd63b5 100644 +--- a/net/sched/act_pedit.c ++++ b/net/sched/act_pedit.c +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -242,7 +244,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + goto out_free_ex; + } + +- nparms->tcfp_off_max_hint = 0; + nparms->tcfp_flags = parm->flags; + nparms->tcfp_nkeys = parm->nkeys; + +@@ -268,14 +269,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + BITS_PER_TYPE(int) - 1, + nparms->tcfp_keys[i].shift); + +- /* The AT option can read a single byte, we can bound the actual +- * value with uchar max. +- */ +- cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift; +- +- /* Each key touches 4 bytes starting from the computed offset */ +- nparms->tcfp_off_max_hint = +- max(nparms->tcfp_off_max_hint, cur + 4); + } + + p = to_pedit(*a); +@@ -318,15 +311,12 @@ static void tcf_pedit_cleanup(struct tc_action *a) + call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu); + } + +-static bool offset_valid(struct sk_buff *skb, int offset) ++static bool offset_valid(struct sk_buff *skb, int offset, int len) + { +- if (offset > 0 && offset > skb->len) +- return false; +- +- if (offset < 0 && -offset > skb_headroom(skb)) ++ if (offset < -(int)skb_headroom(skb)) + return false; + +- return true; ++ return offset <= (int)skb->len - len; + } + + static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type) +@@ -393,18 +383,10 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + struct tcf_pedit_key_ex *tkey_ex; + struct tcf_pedit_parms *parms; + struct tc_pedit_key *tkey; +- u32 max_offset; + int i; + + parms = rcu_dereference_bh(p->parms); + +- max_offset = (skb_transport_header_was_set(skb) ? +- skb_transport_offset(skb) : +- skb_network_offset(skb)) + +- parms->tcfp_off_max_hint; +- if (skb_ensure_writable(skb, min(skb->len, max_offset))) +- goto done; +- + tcf_lastuse_update(&p->tcf_tm); + tcf_action_update_bstats(&p->common, skb); + +@@ -412,10 +394,11 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + tkey_ex = parms->tcfp_keys_ex; + + for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { ++ int write_offset, write_len; + int offset = tkey->off; + int hoffset = 0; +- u32 *ptr, hdata; +- u32 val; ++ u32 cur_val, val; ++ u32 *ptr; + int rc; + + if (tkey_ex) { +@@ -433,13 +416,15 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + + if (tkey->offmask) { + u8 *d, _d; ++ int at_offset; + +- if (!offset_valid(skb, hoffset + tkey->at)) { ++ if (check_add_overflow(hoffset, (int)tkey->at, &at_offset) || ++ !offset_valid(skb, at_offset, sizeof(_d))) { + pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n", + hoffset + tkey->at); + goto bad; + } +- d = skb_header_pointer(skb, hoffset + tkey->at, ++ d = skb_header_pointer(skb, at_offset, + sizeof(_d), &_d); + if (!d) + goto bad; +@@ -451,31 +436,51 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, + } + } + +- if (!offset_valid(skb, hoffset + offset)) { +- pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset); ++ if (check_add_overflow(hoffset, offset, &write_offset)) { ++ pr_info_ratelimited("tc action pedit offset overflow\n"); + goto bad; + } + +- ptr = skb_header_pointer(skb, hoffset + offset, +- sizeof(hdata), &hdata); +- if (!ptr) ++ if (!offset_valid(skb, write_offset, sizeof(*ptr))) { ++ pr_info_ratelimited("tc action pedit offset %d out of bounds\n", ++ write_offset); + goto bad; ++ } ++ ++ if (write_offset < 0) { ++ if (skb_cow(skb, -write_offset)) ++ goto bad; ++ if (write_offset + (int)sizeof(*ptr) > 0) { ++ if (skb_ensure_writable(skb, ++ min_t(int, skb->len, ++ write_offset + (int)sizeof(*ptr)))) ++ goto bad; ++ } ++ } else { ++ if (check_add_overflow(write_offset, (int)sizeof(*ptr), ++ &write_len)) ++ goto bad; ++ if (skb_ensure_writable(skb, min_t(int, skb->len, ++ write_len))) ++ goto bad; ++ } ++ ++ ptr = (u32 *)(skb->data + write_offset); ++ cur_val = get_unaligned(ptr); + /* just do it, baby */ + switch (cmd) { + case TCA_PEDIT_KEY_EX_CMD_SET: + val = tkey->val; + break; + case TCA_PEDIT_KEY_EX_CMD_ADD: +- val = (*ptr + tkey->val) & ~tkey->mask; ++ val = (cur_val + tkey->val) & ~tkey->mask; + break; + default: + pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd); + goto bad; + } + +- *ptr = ((*ptr & tkey->mask) ^ val); +- if (ptr == &hdata) +- skb_store_bits(skb, hoffset + offset, ptr, 4); ++ put_unaligned((cur_val & tkey->mask) ^ val, ptr); + } + + goto done; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch b/queue-7.0/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch new file mode 100644 index 0000000000..83b2719401 --- /dev/null +++ b/queue-7.0/netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch @@ -0,0 +1,58 @@ +From d38a6ce8cbc3bfc14ba87afe3cceb9c5ccc6580f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 12:29:10 +0000 +Subject: netfilter: bridge: make ebt_snat ARP rewrite writable + +From: Yiming Qian + +[ Upstream commit 67ba971ae02514d85818fe0c32549ab4bfa3bf49 ] + +The ebtables SNAT target keeps the Ethernet source address rewrite +behind skb_ensure_writable(skb, 0). This is intentional: at the bridge +ebtables hooks the Ethernet header is addressed through +skb_mac_header()/eth_hdr(), while skb->data points at the Ethernet +payload. Asking skb_ensure_writable() for ETH_HLEN bytes would check +the payload, not the Ethernet header, and would reintroduce the small +packet regression fixed by commit 63137bc5882a. + +However, the optional ARP sender hardware address rewrite is different. +It writes through skb_store_bits() at an offset relative to skb->data: + + skb_store_bits(skb, sizeof(struct arphdr), info->mac, ETH_ALEN) + +skb_header_pointer() only safely reads the ARP header; it does not make +the later sender hardware address range writable. If that range is +still held in a nonlinear skb fragment backed by a splice-imported file +page, skb_store_bits() maps the frag page and copies the new MAC address +directly into it. + +Ensure the ARP SHA range is writable before reading the ARP header and +before calling skb_store_bits(). + +Fixes: 63137bc5882a ("netfilter: ebtables: Fixes dropping of small packets in bridge nat") +Reported-by: Yiming Qian +Signed-off-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_snat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c +index 7dfbcdfc30e5d2..c9e229af0366b8 100644 +--- a/net/bridge/netfilter/ebt_snat.c ++++ b/net/bridge/netfilter/ebt_snat.c +@@ -31,6 +31,9 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par) + const struct arphdr *ap; + struct arphdr _ah; + ++ if (skb_ensure_writable(skb, sizeof(_ah) + ETH_ALEN)) ++ return EBT_DROP; ++ + ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch b/queue-7.0/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch new file mode 100644 index 0000000000..307dba166a --- /dev/null +++ b/queue-7.0/netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch @@ -0,0 +1,50 @@ +From d54aa43a229b3216ccc86b479b9719f262529bf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:20:19 +0200 +Subject: netfilter: conntrack_irc: fix possible out-of-bounds read + +From: Florian Westphal + +[ Upstream commit 66eba0ffce3b7e11449946b4cbbef8ea36112f56 ] + +When parsing fails after we've matched the command string we +should bail out instead of trying to match a different command. + +This helper should be deprecated, given prevalence of TLS I doubt it has +any relevance in 2026. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Closes: https://sashiko.dev/#/patchset/20260525182924.28456-1-fw%40strlen.de +Signed-off-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_irc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c +index b8e6d724acd155..064df01953ebf7 100644 +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -209,7 +209,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + pr_debug("unable to parse dcc command\n"); +- continue; ++ goto out; + } + + pr_debug("DCC bound ip/port: %pI4:%u\n", +@@ -223,7 +223,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); +- continue; ++ goto out; + } + + exp = nf_ct_expect_alloc(ct); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch b/queue-7.0/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch new file mode 100644 index 0000000000..97b493437e --- /dev/null +++ b/queue-7.0/netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch @@ -0,0 +1,96 @@ +From c3155e1c22b49028e5b70fb650becf751a9352f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:09:19 +0800 +Subject: netfilter: nft_ct: bail out on template ct in get eval + +From: Jiayuan Chen + +[ Upstream commit 3027ecbdb5fdf9200251c21d4818e4c447ef78e1 ] + +I noticed this issue while looking at a historic syzbot report [1]. + +A rule like the one below is enough to trigger the bug: + + table ip t { + chain pre { + type filter hook prerouting priority raw; + ct zone set 1 + ct original saddr 1.2.3.4 accept + } + } + +The first expression attaches a per-cpu template ct via +nft_ct_set_zone_eval() (nf_ct_tmpl_alloc -> kzalloc, tuple is all +zero, nf_ct_l3num(ct) == 0). The next expression then calls +nft_ct_get_eval() on the same skb, treats the template as a real ct +and hits the 16-byte memcpy path. With dreg at NFT_REG32_15 this +overflows past struct nft_regs on the kernel stack; with smaller +dreg values it silently clobbers adjacent registers. + +Reject template ct at the eval entry and in nft_ct_get_fast_eval(), +mirroring the check nft_ct_set_eval() already has. Additionally, +bound the address copy in NFT_CT_SRC / NFT_CT_DST by priv->len +instead of by nf_ct_l3num(ct): nf_ct_get_tuple() zeroes the tuple +before pkt_to_tuple() fills in only the protocol-relevant leading +bytes, so the trailing bytes of tuple->{src,dst}.u3.all are +well-defined zero. priv->len is validated at rule load, so the +copy size is now bounded by the destination register rather than +by an untrusted field on the conntrack. + +[1]: https://syzkaller.appspot.com/bug?id=389cf09cb72926114fce90dc85a2c3231dcb647c + +Fixes: 45d9bcda21f4 ("netfilter: nf_tables: validate len in nft_validate_data_load()") +Suggested-by: Florian Westphal +Signed-off-by: Jiayuan Chen +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_ct.c | 8 +++----- + net/netfilter/nft_ct_fast.c | 2 +- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c +index 272ce181180777..92b673f4582a2d 100644 +--- a/net/netfilter/nft_ct.c ++++ b/net/netfilter/nft_ct.c +@@ -78,7 +78,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + break; + } + +- if (ct == NULL) ++ if (!ct || nf_ct_is_template(ct)) + goto err; + + switch (priv->key) { +@@ -180,12 +180,10 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + tuple = &ct->tuplehash[priv->dir].tuple; + switch (priv->key) { + case NFT_CT_SRC: +- memcpy(dest, tuple->src.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->src.u3.all, priv->len); + return; + case NFT_CT_DST: +- memcpy(dest, tuple->dst.u3.all, +- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); ++ memcpy(dest, tuple->dst.u3.all, priv->len); + return; + case NFT_CT_PROTO_SRC: + nft_reg_store16(dest, (__force u16)tuple->src.u.all); +diff --git a/net/netfilter/nft_ct_fast.c b/net/netfilter/nft_ct_fast.c +index e684c8a9184877..ecf7b3a404be26 100644 +--- a/net/netfilter/nft_ct_fast.c ++++ b/net/netfilter/nft_ct_fast.c +@@ -30,7 +30,7 @@ void nft_ct_get_fast_eval(const struct nft_expr *expr, + break; + } + +- if (!ct) { ++ if (!ct || nf_ct_is_template(ct)) { + regs->verdict.code = NFT_BREAK; + return; + } +-- +2.53.0 + diff --git a/queue-7.0/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch b/queue-7.0/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch new file mode 100644 index 0000000000..7d9e61a513 --- /dev/null +++ b/queue-7.0/netfilter-synproxy-add-mutex-to-guard-hook-reference.patch @@ -0,0 +1,113 @@ +From 0ec0c0cd655b36ccd4068a207efc97a2cc6d5b13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 23:58:31 +0200 +Subject: netfilter: synproxy: add mutex to guard hook reference counting + +From: Fernando Fernandez Mancera + +[ Upstream commit 2fcba19caaeb2a33017459d3430f057967bb91b6 ] + +As the synproxy infrastructure register netfilter hooks on-demand when a +user adds the first iptables target or nftables expression, if done +concurrently they can race each other. + +Introduce a mutex to serialize the refcount control blocks access from +both frontends. While a per namespace mutex might be more efficient, it +is not needed for target/expression like SYNPROXY. + +Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 036c8586f49b75..ed00114f65f392 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -22,6 +22,8 @@ + #include + #include + ++static DEFINE_MUTEX(synproxy_mutex); ++ + unsigned int synproxy_net_id; + EXPORT_SYMBOL_GPL(synproxy_net_id); + +@@ -769,26 +771,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = { + + int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref4 == 0) { + err = nf_register_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref4++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init); + + void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref4--; + if (snet->hook_ref4 == 0) + nf_unregister_net_hooks(net, ipv4_synproxy_ops, + ARRAY_SIZE(ipv4_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini); + +@@ -1193,27 +1200,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = { + int + nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net) + { +- int err; ++ int err = 0; + ++ mutex_lock(&synproxy_mutex); + if (snet->hook_ref6 == 0) { + err = nf_register_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); + if (err) +- return err; ++ goto out; + } + + snet->hook_ref6++; +- return 0; ++out: ++ mutex_unlock(&synproxy_mutex); ++ return err; + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init); + + void + nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net) + { ++ mutex_lock(&synproxy_mutex); + snet->hook_ref6--; + if (snet->hook_ref6 == 0) + nf_unregister_net_hooks(net, ipv6_synproxy_ops, + ARRAY_SIZE(ipv6_synproxy_ops)); ++ mutex_unlock(&synproxy_mutex); + } + EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini); + #endif /* CONFIG_IPV6 */ +-- +2.53.0 + diff --git a/queue-7.0/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch b/queue-7.0/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..58204744e2 --- /dev/null +++ b/queue-7.0/netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch @@ -0,0 +1,41 @@ +From 5580c67ddb11434d5f0ef9e0f713d7a31fd924d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 12:47:17 +0200 +Subject: netfilter: xt_NFQUEUE: prefer raw_smp_processor_id + +From: Fernando Fernandez Mancera + +[ Upstream commit c6c5327dd18bec1e1bbf139b2cf5ae53608a9d30 ] + +With PREEMPT_RCU this triggers a splat because smp_processor_id() can be +preempted while inside a RCU critical section. If xt_NFQUEUE target is +invoked via nft_compat_eval() path, we are inside a RCU critical +section. + +Just use the raw version instead. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_NFQUEUE.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index 466da23e36ff47..b32d153e3a1862 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -91,7 +91,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) + + if (info->queues_total > 1) { + if (info->flags & NFQ_FLAG_CPU_FANOUT) { +- int cpu = smp_processor_id(); ++ int cpu = raw_smp_processor_id(); + + queue = info->queuenum + cpu % info->queues_total; + } else { +-- +2.53.0 + diff --git a/queue-7.0/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch b/queue-7.0/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch new file mode 100644 index 0000000000..068afffb76 --- /dev/null +++ b/queue-7.0/octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch @@ -0,0 +1,44 @@ +From 96dbbcd76edea442e324f5b656cbbd62041c319d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 17:07:05 +0530 +Subject: octeontx2-af: Fix initialization of mcam's entry2target_pffunc field + +From: Suman Ghosh + +[ Upstream commit 9a85ec3dc28b6df246801c19e4d9bae6297a25b0 ] + +NPC mcam entry stores a mapping between mcam entry and target pcifunc. +During initialization of this field, API kmalloc_array has been used which +caused some junk values to array. Whereas, the array is expected to be +initialized by 0. This patch fixes the same by using kcalloc instead of +kmalloc_array. + +Fixes: 55307fcb9258 ("octeontx2-af: Add mbox messages to install and delete MCAM rules") +Signed-off-by: Suman Ghosh +Signed-off-by: Subbaraya Sundeep +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/1780054625-17090-1-git-send-email-sbhatta@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index e28675fe189071..a0d2ed56186d8d 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -1932,8 +1932,8 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr) + goto free_entry_cntr_map; + + /* Alloc memory for saving target device of mcam rule */ +- mcam->entry2target_pffunc = kmalloc_array(mcam->total_entries, +- sizeof(u16), GFP_KERNEL); ++ mcam->entry2target_pffunc = kcalloc(mcam->total_entries, ++ sizeof(u16), GFP_KERNEL); + if (!mcam->entry2target_pffunc) + goto free_cntr_refcnt; + +-- +2.53.0 + diff --git a/queue-7.0/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch b/queue-7.0/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch new file mode 100644 index 0000000000..75a0d65d54 --- /dev/null +++ b/queue-7.0/octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch @@ -0,0 +1,119 @@ +From 037ab2919e057e97e7b28c7209b5a08d42b7ab7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 10:28:53 +0530 +Subject: octeontx2-af: npc: Fix CPT channel mask in npc_install_flow + +From: Nithin Dabilpuram + +[ Upstream commit 1d31eb27e570daa04f5373345f9ac98c95863be9 ] + +Use the CPT-aware NIX channel mask in the npc_install_flow path so that +when the host PF installs steering rules in kernel for a VF used from +userspace (e.g. DPDK), MCAM entries see the same channel mask semantics as +other RX paths. + +Fixes: 56bcef528bd8 ("octeontx2-af: Use npc_install_flow API for promisc and broadcast entries") +Cc: Naveen Mamindlapalli +Signed-off-by: Nithin Dabilpuram +Signed-off-by: Ratheesh Kannoth +Link: https://patch.msgid.link/20260602045853.1558530-1-rkannoth@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + + .../ethernet/marvell/octeontx2/af/rvu_npc.c | 32 +++++++++---------- + .../marvell/octeontx2/af/rvu_npc_fs.c | 2 +- + 3 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index 3f76ec6c5cf3b9..e31d7bc4a0e9c2 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -1138,6 +1138,7 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int lf, + int slot); + int rvu_cpt_ctx_flush(struct rvu *rvu, u16 pcifunc); + int rvu_cpt_init(struct rvu *rvu); ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu); + + #define NDC_AF_BANK_MASK GENMASK_ULL(7, 0) + #define NDC_AF_BANK_LINE_MASK GENMASK_ULL(31, 16) +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +index a0d2ed56186d8d..65aa6aeab8e782 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +@@ -599,6 +599,19 @@ void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, + NPC_AF_MCAMEX_BANKX_ACTION(index, bank), cfg); + } + ++u32 rvu_get_cpt_chan_mask(struct rvu *rvu) ++{ ++ /* For cn10k the upper two bits of the channel number are ++ * cpt channel number. with masking out these bits in the ++ * mcam entry, same entry used for NIX will allow packets ++ * received from cpt for parsing. ++ */ ++ if (!is_rvu_otx2(rvu)) ++ return NIX_CHAN_CPT_X2P_MASK; ++ else ++ return 0xFFFu; ++} ++ + void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + int nixlf, u64 chan, u8 *mac_addr) + { +@@ -642,7 +655,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, + eth_broadcast_addr((u8 *)&req.mask.dmac); + req.features = BIT_ULL(NPC_DMAC); + req.channel = chan; +- req.chan_mask = 0xFFFU; ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.intf = pfvf->nix_rx_intf; + req.op = action.op; + req.hdr.pcifunc = 0; /* AF is requester */ +@@ -712,11 +725,7 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc, + * mcam entry, same entry used for NIX will allow packets + * received from cpt for parsing. + */ +- if (!is_rvu_otx2(rvu)) { +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- } else { +- req.chan_mask = 0xFFFU; +- } ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + + if (chan_cnt > 1) { + if (!is_power_of_2(chan_cnt)) { +@@ -887,16 +896,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf, + ether_addr_copy(req.mask.dmac, mac_addr); + req.features = BIT_ULL(NPC_DMAC); + +- /* For cn10k the upper two bits of the channel number are +- * cpt channel number. with masking out these bits in the +- * mcam entry, same entry used for NIX will allow packets +- * received from cpt for parsing. +- */ +- if (!is_rvu_otx2(rvu)) +- req.chan_mask = NIX_CHAN_CPT_X2P_MASK; +- else +- req.chan_mask = 0xFFFU; +- ++ req.chan_mask = rvu_get_cpt_chan_mask(rvu); + req.channel = chan; + req.intf = pfvf->nix_rx_intf; + req.entry = index; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +index 1930b54e72f219..02663530368965 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +@@ -1470,7 +1470,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, + + /* ignore chan_mask in case pf func is not AF, revisit later */ + if (!is_pffunc_af(req->hdr.pcifunc)) +- req->chan_mask = 0xFFF; ++ req->chan_mask = rvu_get_cpt_chan_mask(rvu); + + err = npc_check_unsupported_flows(rvu, req->features, req->intf); + if (err) +-- +2.53.0 + diff --git a/queue-7.0/octeontx2-pf-fix-ndc-sync-operation-errors.patch b/queue-7.0/octeontx2-pf-fix-ndc-sync-operation-errors.patch new file mode 100644 index 0000000000..d7d68eb9dd --- /dev/null +++ b/queue-7.0/octeontx2-pf-fix-ndc-sync-operation-errors.patch @@ -0,0 +1,40 @@ +From 53fb34b1d49ef5da42e5992aa39dd0ffff9a198a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 17:07:57 +0530 +Subject: octeontx2-pf: Fix NDC sync operation errors + +From: Geetha sowjanya + +[ Upstream commit a910fb8f7b9e4c566db363e6c2ec378dc7153995 ] + +On system reboot "rvu_nicpf 0002:03:00.0: NDC sync operation failed" +error messages are shown, even if the operations is successful. +This is due to wrong if error check in ndc_syc() function. + +Fixes: 42c45ac1419c ("octeontx2-af: Sync NIX and NPA contexts from NDC to LLC/DRAM") +Signed-off-by: Geetha sowjanya +Signed-off-by: Subbaraya Sundeep +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/1780054677-17249-1-git-send-email-sbhatta@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index ee623476e5ff1a..f9fbf0c1764825 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3473,7 +3473,7 @@ static void otx2_ndc_sync(struct otx2_nic *pf) + req->nix_lf_rx_sync = 1; + req->npa_lf_sync = 1; + +- if (!otx2_sync_mbox_msg(mbox)) ++ if (otx2_sync_mbox_msg(mbox)) + dev_err(pf->dev, "NDC sync operation failed\n"); + + mutex_unlock(&mbox->lock); +-- +2.53.0 + diff --git a/queue-7.0/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch b/queue-7.0/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch new file mode 100644 index 0000000000..8ae1e4ae98 --- /dev/null +++ b/queue-7.0/pcnet32-stop-holding-device-spin-lock-during-napi_co.patch @@ -0,0 +1,58 @@ +From 558f30aae165073234f0ff1cf02b783e4b70fcfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 16:03:20 +0200 +Subject: pcnet32: stop holding device spin lock during napi_complete_done + +From: Oscar Maes + +[ Upstream commit 73bf3cca7de6a73f53b6a52dc3b1c82ae5667a4d ] + +napi_complete_done may call gro_flush_normal (though not currently, as GRO +is unsupported at the moment), which may result in packet TX. This will +eventually result in calling pcnet32_start_xmit - resulting in a deadlock +while trying to re-acquire the already locked spin lock. + +It is safe to split the spinlock block into two, because the hardware +registers are still protected from concurrent access, and the two blocks +perform unrelated operations that don't need to happen atomically. + +Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()") +Reviewed-by: Andrew Lunn +Signed-off-by: Oscar Maes +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/pcnet32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c +index 911808ab13a79d..4f3076d4ea34eb 100644 +--- a/drivers/net/ethernet/amd/pcnet32.c ++++ b/drivers/net/ethernet/amd/pcnet32.c +@@ -1407,8 +1407,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + pcnet32_restart(dev, CSR0_START); + netif_wake_queue(dev); + } ++ spin_unlock_irqrestore(&lp->lock, flags); + + if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a->read_csr(ioaddr, CSR3); + val &= 0x00ff; +@@ -1416,9 +1418,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) + + /* Set interrupt enable. */ + lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN); ++ spin_unlock_irqrestore(&lp->lock, flags); + } + +- spin_unlock_irqrestore(&lp->lock, flags); + return work_done; + } + +-- +2.53.0 + diff --git a/queue-7.0/ptp-vclock-switch-from-rcu-to-srcu.patch b/queue-7.0/ptp-vclock-switch-from-rcu-to-srcu.patch new file mode 100644 index 0000000000..5c102126c4 --- /dev/null +++ b/queue-7.0/ptp-vclock-switch-from-rcu-to-srcu.patch @@ -0,0 +1,85 @@ +From 363f8146b6afbbfe5f88932fa2a41ea4d1c73ed5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 19:11:47 +0200 +Subject: ptp: vclock: Switch from RCU to SRCU + +From: Kurt Kanzenbach + +[ Upstream commit 672bd0519e27c357c43b7f8c0d653fce3817d06e ] + +The usage of PTP vClocks leads immediately to the following issues with +ptp4l with LOCKDEP and DEBUG_ATOMIC_SLEEP enabled: "BUG: sleeping function +called from invalid context". + +ptp_convert_timestamp() acquires a mutex_t within a RCU read section. This +is illegal, because acquiring a mutex_t can result in voluntary scheduling +request which is not allowed within a RCU read section. + +Replace the RCU usage with SRCU where sleeping is allowed. + +Reported-by: Florian Zeitz +Closes: https://lore.kernel.org/all/00a8cce8-410e-4038-98af-49be6d93d7bd@schettke.com/ +Fixes: 67d93ffc0f3c ("ptp: vclock: use mutex to fix "sleep on atomic" bug") +Signed-off-by: Kurt Kanzenbach +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260529-vclock_rcu-v2-1-02a5531fab92@linutronix.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_vclock.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c +index 915a4f6defc945..84cb527f59ccc6 100644 +--- a/drivers/ptp/ptp_vclock.c ++++ b/drivers/ptp/ptp_vclock.c +@@ -19,6 +19,8 @@ static DEFINE_SPINLOCK(vclock_hash_lock); + + static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8); + ++DEFINE_STATIC_SRCU(vclock_srcu); ++ + static void ptp_vclock_hash_add(struct ptp_vclock *vclock) + { + spin_lock(&vclock_hash_lock); +@@ -37,7 +39,7 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock) + + spin_unlock(&vclock_hash_lock); + +- synchronize_rcu(); ++ synchronize_srcu(&vclock_srcu); + } + + static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +@@ -276,14 +278,16 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + { + unsigned int hash = vclock_index % HASH_SIZE(vclock_hash); + struct ptp_vclock *vclock; +- u64 ns; + u64 vclock_ns = 0; ++ int srcu_idx; ++ u64 ns; + + ns = ktime_to_ns(*hwtstamp); + +- rcu_read_lock(); ++ srcu_idx = srcu_read_lock(&vclock_srcu); + +- hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) { ++ hlist_for_each_entry_srcu(vclock, &vclock_hash[hash], vclock_hash_node, ++ srcu_read_lock_held(&vclock_srcu)) { + if (vclock->clock->index != vclock_index) + continue; + +@@ -294,7 +298,7 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) + break; + } + +- rcu_read_unlock(); ++ srcu_read_unlock(&vclock_srcu, srcu_idx); + + return ns_to_ktime(vclock_ns); + } +-- +2.53.0 + diff --git a/queue-7.0/reapply-bnxt_en-bring-back-rtnl_lock-in-the-bnxt_ope.patch b/queue-7.0/reapply-bnxt_en-bring-back-rtnl_lock-in-the-bnxt_ope.patch new file mode 100644 index 0000000000..ccb38ddcbc --- /dev/null +++ b/queue-7.0/reapply-bnxt_en-bring-back-rtnl_lock-in-the-bnxt_ope.patch @@ -0,0 +1,169 @@ +From 231d9e3d9d068d0908341b22ffa99cae310a5f73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 12:58:45 -0700 +Subject: Reapply "bnxt_en: bring back rtnl_lock() in the bnxt_open() path" + +From: Jakub Kicinski + +[ Upstream commit b6197b386677ae5268d4702e23849d9ad53051ad ] + +This reverts commit 850d9248d2eac662f869c766a598c877690c74e5. +This reapplies commit 325eb217e41f ("bnxt_en: bring back rtnl_lock() +in the bnxt_open() path"). + +Breno reports a lockdep warning in bnxt. During FW reset the driver +may end up calling netif_set_real_num_tx_queues() (if queue count +changes), so calls to bnxt_open() still require rtnl_lock. + + net/sched/sch_generic.c:1416 suspicious rcu_dereference_protected() usage! + + dev_qdisc_change_real_num_tx+0x54/0xe0 + netif_set_real_num_tx_queues+0x4ed/0xa80 + __bnxt_open_nic+0x9cb/0x3490 + bnxt_open+0x1cb/0x370 + bnxt_fw_reset_task+0x80d/0x1e80 + process_scheduled_works+0x9c1/0x13b0 + +The reverted commit was just an optimization / experiment +so let's go back to taking the lock. + +Reported-by: Breno Leitao +Link: https://lore.kernel.org/ah726OtFX-Qw3U-R@gmail.com +Fixes: 850d9248d2ea ("Revert "bnxt_en: bring back rtnl_lock() in the bnxt_open() path"") +Acked-by: Stanislav Fomichev +Reviewed-by: Michael Chan +Reviewed-by: Breno Leitao +Link: https://patch.msgid.link/20260603195845.2574426-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 36 ++++++++++++++++++----- + 1 file changed, 29 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 86e45352cec105..ff5501999b4df1 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -14290,13 +14290,28 @@ static void bnxt_unlock_sp(struct bnxt *bp) + netdev_unlock(bp->dev); + } + ++/* Same as bnxt_lock_sp() with additional rtnl_lock */ ++static void bnxt_rtnl_lock_sp(struct bnxt *bp) ++{ ++ clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); ++ rtnl_lock(); ++ netdev_lock(bp->dev); ++} ++ ++static void bnxt_rtnl_unlock_sp(struct bnxt *bp) ++{ ++ set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); ++ netdev_unlock(bp->dev); ++ rtnl_unlock(); ++} ++ + /* Only called from bnxt_sp_task() */ + static void bnxt_reset(struct bnxt *bp, bool silent) + { +- bnxt_lock_sp(bp); ++ bnxt_rtnl_lock_sp(bp); + if (test_bit(BNXT_STATE_OPEN, &bp->state)) + bnxt_reset_task(bp, silent); +- bnxt_unlock_sp(bp); ++ bnxt_rtnl_unlock_sp(bp); + } + + /* Only called from bnxt_sp_task() */ +@@ -14304,9 +14319,9 @@ static void bnxt_rx_ring_reset(struct bnxt *bp) + { + int i; + +- bnxt_lock_sp(bp); ++ bnxt_rtnl_lock_sp(bp); + if (!test_bit(BNXT_STATE_OPEN, &bp->state)) { +- bnxt_unlock_sp(bp); ++ bnxt_rtnl_unlock_sp(bp); + return; + } + /* Disable and flush TPA before resetting the RX ring */ +@@ -14345,7 +14360,7 @@ static void bnxt_rx_ring_reset(struct bnxt *bp) + } + if (bp->flags & BNXT_FLAG_TPA) + bnxt_set_tpa(bp, true); +- bnxt_unlock_sp(bp); ++ bnxt_rtnl_unlock_sp(bp); + } + + static void bnxt_fw_fatal_close(struct bnxt *bp) +@@ -15255,15 +15270,17 @@ static void bnxt_fw_reset_task(struct work_struct *work) + bp->fw_reset_state = BNXT_FW_RESET_STATE_OPENING; + fallthrough; + case BNXT_FW_RESET_STATE_OPENING: +- while (!netdev_trylock(bp->dev)) { ++ while (!rtnl_trylock()) { + bnxt_queue_fw_reset_work(bp, HZ / 10); + return; + } ++ netdev_lock(bp->dev); + rc = bnxt_open(bp->dev); + if (rc) { + netdev_err(bp->dev, "bnxt_open() failed during FW reset\n"); + bnxt_fw_reset_abort(bp, rc); + netdev_unlock(bp->dev); ++ rtnl_unlock(); + goto ulp_start; + } + +@@ -15283,6 +15300,7 @@ static void bnxt_fw_reset_task(struct work_struct *work) + bnxt_dl_health_fw_status_update(bp, true); + } + netdev_unlock(bp->dev); ++ rtnl_unlock(); + bnxt_ulp_start(bp); + bnxt_reenable_sriov(bp); + netdev_lock(bp->dev); +@@ -16272,7 +16290,7 @@ static int bnxt_queue_start(struct net_device *dev, + rc); + napi_enable_locked(&bnapi->napi); + bnxt_db_nq_arm(bp, &cpr->cp_db, cpr->cp_raw_cons); +- bnxt_reset_task(bp, true); ++ netif_close(dev); + return rc; + } + +@@ -17116,6 +17134,7 @@ static int bnxt_resume(struct device *device) + struct bnxt *bp = netdev_priv(dev); + int rc = 0; + ++ rtnl_lock(); + netdev_lock(dev); + rc = pci_enable_device(bp->pdev); + if (rc) { +@@ -17160,6 +17179,7 @@ static int bnxt_resume(struct device *device) + + resume_exit: + netdev_unlock(bp->dev); ++ rtnl_unlock(); + if (!rc) { + bnxt_ulp_start(bp); + bnxt_reenable_sriov(bp); +@@ -17326,6 +17346,7 @@ static void bnxt_io_resume(struct pci_dev *pdev) + int err; + + netdev_info(bp->dev, "PCI Slot Resume\n"); ++ rtnl_lock(); + netdev_lock(netdev); + + err = bnxt_hwrm_func_qcaps(bp); +@@ -17343,6 +17364,7 @@ static void bnxt_io_resume(struct pci_dev *pdev) + netif_device_attach(netdev); + + netdev_unlock(netdev); ++ rtnl_unlock(); + if (!err) { + bnxt_ulp_start(bp); + bnxt_reenable_sriov(bp); +-- +2.53.0 + diff --git a/queue-7.0/s390-bug-always-emit-format-word-in-__bug_entry.patch b/queue-7.0/s390-bug-always-emit-format-word-in-__bug_entry.patch new file mode 100644 index 0000000000..09cdf8b07d --- /dev/null +++ b/queue-7.0/s390-bug-always-emit-format-word-in-__bug_entry.patch @@ -0,0 +1,72 @@ +From b9d3af1479679b70f3a462db23ea7b21988c59ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 14:01:32 +0200 +Subject: s390/bug: Always emit format word in __BUG_ENTRY + +From: Jan Polensky + +[ Upstream commit 3daad7f60aa92d0307fa2b2edd38c886a09902f2 ] + +When CONFIG_DEBUG_BUGVERBOSE is disabled, the s390 __BUG_ENTRY() macro +omits the format string pointer, so the generated __bug_table entry no +longer matches struct bug_entry. + +With HAVE_ARCH_BUG_FORMAT enabled, the generic BUG infrastructure reads +bug_entry::format via bug_get_format(). If the format word is missing, +subsequent fields are read from the wrong offset, which may: +- Misinterpret flags (BUG vs WARN classification errors) +- Fault when dereferencing a misread format pointer + +The root cause is that __BUG_ENTRY() delegates format word emission to +__BUG_ENTRY_VERBOSE(), which is conditional on CONFIG_DEBUG_BUGVERBOSE. + +Fix this by moving the format field emission directly into __BUG_ENTRY() +so it is always emitted unconditionally. Remove the format parameter from +__BUG_ENTRY_VERBOSE() and keep only file/line emission conditional on +CONFIG_DEBUG_BUGVERBOSE. + +Fixes: 2b71b8ab9718 ("s390/bug: Use BUG_FORMAT for DEBUG_BUGVERBOSE_DETAILED") +Signed-off-by: Jan Polensky +Reviewed-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Signed-off-by: Sasha Levin +--- + arch/s390/include/asm/bug.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h +index 59017fd3d9358d..50a270edb02035 100644 +--- a/arch/s390/include/asm/bug.h ++++ b/arch/s390/include/asm/bug.h +@@ -12,12 +12,11 @@ + #if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS) + + #ifdef CONFIG_DEBUG_BUGVERBOSE +-#define __BUG_ENTRY_VERBOSE(format, file, line) \ +- " .long " format " - . # bug_entry::format\n" \ ++#define __BUG_ENTRY_VERBOSE(file, line) \ + " .long " file " - . # bug_entry::file\n" \ + " .short " line " # bug_entry::line\n" + #else +-#define __BUG_ENTRY_VERBOSE(format, file, line) ++#define __BUG_ENTRY_VERBOSE(file, line) + #endif + + #ifdef CONFIG_DEBUG_BUGVERBOSE_DETAILED +@@ -28,9 +27,10 @@ + + #define __BUG_ENTRY(format, file, line, flags, size) \ + " .section __bug_table,\"aw\"\n" \ +- "1: .long 0b - . # bug_entry::bug_addr\n" \ +- __BUG_ENTRY_VERBOSE(format, file, line) \ +- " .short "flags" # bug_entry::flags\n" \ ++ "1: .long 0b - . # bug_entry::bug_addr\n"\ ++ " .long " format " - . # bug_entry::format\n" \ ++ __BUG_ENTRY_VERBOSE(file, line) \ ++ " .short "flags" # bug_entry::flags\n" \ + " .org 1b+"size"\n" \ + " .previous" + +-- +2.53.0 + diff --git a/queue-7.0/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch b/queue-7.0/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch new file mode 100644 index 0000000000..36b5f1f682 --- /dev/null +++ b/queue-7.0/sctp-purge-outqueue-on-stale-cookie-echo-handling.patch @@ -0,0 +1,87 @@ +From b207cd94dca6bd50bed7a762986dbff96f5ec066 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:11:44 -0400 +Subject: sctp: purge outqueue on stale COOKIE-ECHO handling + +From: Xin Long + +[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ] + +sctp_stream_update() is only invoked when the association is moved into +COOKIE_WAIT during association setup/reconfiguration. In this path, the +outbound stream scheduler state (stream->out_curr) is expected to be +clean, since no user data should have been transmitted yet unless the +state machine has already partially progressed. + +However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a +Stale Cookie ERROR is received, the association is rolled back from +COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already +have been queued and even bundled with the COOKIE-ECHO chunk. + +During the rollback, sctp_stream_update() frees the old stream table +and installs a new one, but it does not invalidate stream->out_curr. +As a result, out_curr may still point to a freed sctp_stream_out +entry from the previous stream state. + +Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on +stream->out_curr->ext, which can lead to use-after-free once the old +stream state has been released via sctp_stream_free(). + +This results in crashes such as (reported by Yuqi): + + BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140 + Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312 + CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted + 7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full) + sctp_sched_fcfs_dequeue+0x13a/0x140 + sctp_outq_flush+0x1603/0x33e0 + sctp_do_sm+0x31c9/0x5d30 + sctp_assoc_bh_rcv+0x392/0x6f0 + sctp_inq_push+0x1db/0x270 + sctp_rcv+0x138d/0x3c10 + +Fix this by fully purging the association outqueue when handling the +Stale Cookie case. This ensures all pending transmit and retransmit +state is dropped, and any scheduler cached pointers are invalidated, +making it safe to rebuild stream state during COOKIE_WAIT restart. + +Updating only stream->out_curr would be insufficient, since queued +and retransmittable data would still reference the old stream state and +trigger later use-after-free in dequeue paths. + +Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Reported-by: Yuqi Xu +Reported-by: Ren Wei +Signed-off-by: Xin Long +Link: https://patch.msgid.link/94318159b9052907a6cbb7256aee8b5f8dfbfccb.1780510304.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 8e89a870780c49..9b23c11cbb9ea4 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2598,11 +2598,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + +- /* If we've sent any data bundled with COOKIE-ECHO we will need to +- * resend +- */ +- sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, +- SCTP_TRANSPORT(asoc->peer.primary_path)); ++ sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. +-- +2.53.0 + diff --git a/queue-7.0/sctp-validate-cached-peer-init-chunk-length-in-cooki.patch b/queue-7.0/sctp-validate-cached-peer-init-chunk-length-in-cooki.patch new file mode 100644 index 0000000000..5f72b614aa --- /dev/null +++ b/queue-7.0/sctp-validate-cached-peer-init-chunk-length-in-cooki.patch @@ -0,0 +1,61 @@ +From b7544ab193ada0d438c1a741d18cb532aaf12b7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 21:06:06 -0400 +Subject: sctp: validate cached peer INIT chunk length in COOKIE_ECHO + processing + +From: Xin Long + +[ Upstream commit 0861615c28de668669d748ef4eb913ea9262d13b ] + +When a listening SCTP server processes a COOKIE_ECHO chunk, the cached +peer INIT chunk embedded after the cookie is parsed and its parameters +are later walked by sctp_process_init() using sctp_walk_params(). + +However, the chunk header length of this cached INIT chunk was not +validated against the remaining buffer in the COOKIE_ECHO payload. If +the length field is inflated, the parameter walk can run beyond the +actual received data, leading to out-of-bounds reads and potential +memory corruption during later parameter handling (e.g. STATE_COOKIE +processing and kmemdup() copies). + +Add a bounds check in sctp_unpack_cookie() to ensure the cached INIT +chunk length does not exceed the available data in the COOKIE_ECHO +buffer before it is used. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Brian Geffon +Signed-off-by: Xin Long +Link: https://patch.msgid.link/eb60825fa22d6f9e663c7d4dbb69f397b5d34d42.1780362366.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_make_chunk.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index 2c0017d058d409..9014b095f52ddb 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -1730,6 +1730,7 @@ struct sctp_association *sctp_unpack_cookie( + struct sctp_signed_cookie *cookie; + struct sk_buff *skb = chunk->skb; + struct sctp_cookie *bear_cookie; ++ struct sctp_chunkhdr *ch; + enum sctp_scope scope; + unsigned int len; + ktime_t kt; +@@ -1759,6 +1760,10 @@ struct sctp_association *sctp_unpack_cookie( + cookie = chunk->subh.cookie_hdr; + bear_cookie = &cookie->c; + ++ ch = (struct sctp_chunkhdr *)(bear_cookie + 1); ++ if (ntohs(ch->length) > len - fixed_size) ++ goto malformed; ++ + /* Verify the cookie's MAC, if cookie authentication is enabled. */ + if (sctp_sk(ep->base.sk)->cookie_auth_enable) { + u8 mac[SHA256_DIGEST_SIZE]; +-- +2.53.0 + diff --git a/queue-7.0/series b/queue-7.0/series index e1fbbdd171..92f100faeb 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -1 +1,71 @@ bpf-free-reuseport-cbpf-prog-after-rcu-grace-period.patch +tee-optee-prevent-use-after-free-when-the-client-exi.patch +soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch +arm64-dts-qcom-x1-dell-thena-remove-i2c20-battery-sm.patch +arm-dts-microchip-sam9x7-fix-gmac-clock-configuratio.patch +soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch +tee-fix-tee_ioctl_object_invoke_arg-padding.patch +tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch +s390-bug-always-emit-format-word-in-__bug_entry.patch +arm-dts-gemini-fix-partition-offsets.patch +erofs-fix-use-after-free-on-sbi-sync_decompress.patch +wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch +ksmbd-fix-null-deref-of-opinfo-conn-in-oplock-lease-.patch +netfilter-xt_nfqueue-prefer-raw_smp_processor_id.patch +ipvs-clear-the-svc-scheduler-ptr-early-on-edit.patch +netfilter-synproxy-add-mutex-to-guard-hook-reference.patch +netfilter-conntrack_irc-fix-possible-out-of-bounds-r.patch +netfilter-nft_ct-bail-out-on-template-ct-in-get-eval.patch +netfilter-bridge-make-ebt_snat-arp-rewrite-writable.patch +dm-cache-policy-smq-check-allocation-under-invalidat.patch +net-sched-act_api-use-rcu-with-deferred-freeing-for-.patch +6lowpan-fix-off-by-one-in-multicast-context-address-.patch +l2tp-pppol2tp-hold-reference-to-session-in-pppol2tp_.patch +devlink-release-nested-relation-on-devlink-free.patch +drm-imx-fix-three-kernel-doc-warnings-in-dcss-scaler.patch +wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch +pcnet32-stop-holding-device-spin-lock-during-napi_co.patch +net-annotate-sk-sk_write_space-for-udp-sockmap.patch +tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch +hsr-remove-warn_once-in-hsr_addr_is_self.patch +net-garp-fix-unsigned-integer-underflow-in-garp_pdu_.patch +net-lan743x-permit-vlan-tagged-packets-up-to-configu.patch +net-fec-fix-pinctrl-default-state-restore-order-on-r.patch +ipv6-anycast-insert-aca-into-global-hash-under-idev-.patch +wifi-fix-leak-if-split-6-ghz-scanning-fails.patch +wifi-cfg80211-add-support-to-handle-incumbent-signal.patch +wifi-nl80211-split-out-uhr-operation-information.patch +wifi-cfg80211-enforce-he-eht-cap-oper-consistency.patch +bluetooth-rfcomm-hold-listener-socket-in-rfcomm_conn.patch +bluetooth-mgmt-validate-advertising-tlv-before-type-.patch +bluetooth-rfcomm-validate-skb-length-in-mcc-handlers.patch +bluetooth-bnep-fix-incorrect-length-parsing-in-bnep_.patch +bluetooth-bnep-reject-short-frames-before-parsing.patch +bluetooth-fix-memory-leak-in-error-path-of-hci_alloc.patch +bluetooth-iso-fix-not-releasing-hdev-reference-on-is.patch +bluetooth-iso-fix-a-use-after-free-of-the-hci_conn-p.patch +bluetooth-iso-fix-data-race-on-iso_pi-fields-in-hci_.patch +bluetooth-sco-fix-data-race-on-sco_pi-fields-in-sco_.patch +bluetooth-mgmt-fix-backward-compatibility-with-users.patch +xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch +octeontx2-pf-fix-ndc-sync-operation-errors.patch +octeontx2-af-fix-initialization-of-mcam-s-entry2targ.patch +af_unix-fix-inq_len-update-problem-in-partial-read.patch +ipv4-restrict-ipopt_ssrr-and-ipopt_lsrr-options.patch +ptp-vclock-switch-from-rcu-to-srcu.patch +net-airoha-fix-use-after-free-in-metadata-dst-teardo.patch +net-ethernet-mtk_eth_soc-fix-use-after-free-in-metad.patch +geneve-fix-length-used-in-gro-hint-udp-checksum-adju.patch +net-sched-fix-pedit-partial-cow-leading-to-page-cach.patch +sctp-validate-cached-peer-init-chunk-length-in-cooki.patch +octeontx2-af-npc-fix-cpt-channel-mask-in-npc_install.patch +vxlan-vnifilter-send-notification-on-vni-add.patch +vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch +ipv6-mcast-fix-use-after-free-when-processing-mld-qu.patch +ieee802154-6lowpan-only-accept-ipv6-packets-in-lowpa.patch +net-802-mrp-fix-vector-attribute-parsing-in-mrp_pdu_.patch +bonding-annotate-data-races-arcound-churn-variables.patch +sctp-purge-outqueue-on-stale-cookie-echo-handling.patch +fwctl-bnxt_en-move-common-definitions-to-include-lin.patch +fwctl-bnxt_en-refactor-aux-bus-functions-to-be-more-.patch +reapply-bnxt_en-bring-back-rtnl_lock-in-the-bnxt_ope.patch diff --git a/queue-7.0/soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch b/queue-7.0/soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch new file mode 100644 index 0000000000..02fac34852 --- /dev/null +++ b/queue-7.0/soc-qcom-ice-allow-explicit-votes-on-iface-clock-for.patch @@ -0,0 +1,87 @@ +From 86b585f24db968ee39fa9e12b6eb2b44b2864b55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:29:19 +0530 +Subject: soc: qcom: ice: Allow explicit votes on 'iface' clock for ICE + +From: Harshal Dev + +[ Upstream commit 0d5dc5818191b55e4364d04b1b898a14a2ccac38 ] + +Since Qualcomm inline-crypto engine (ICE) is now a dedicated driver +de-coupled from the QCOM UFS driver, it explicitly votes for its required +clocks during probe. For scenarios where the 'clk_ignore_unused' flag is +not passed on the kernel command line, to avoid potential unclocked ICE +hardware register access during probe the ICE driver should additionally +vote on the 'iface' clock. +Also update the suspend and resume callbacks to handle un-voting and voting +on the 'iface' clock. + +Fixes: 2afbf43a4aec6 ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver") +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Kuldeep Singh +Reviewed-by: Konrad Dybcio +Signed-off-by: Harshal Dev +Link: https://lore.kernel.org/r/20260416-qcom_ice_power_and_clk_vote-v5-2-5ccf5d7e2846@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ice.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index b203bc685cadd2..bf4ab2d9e5c036 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -108,6 +108,7 @@ struct qcom_ice { + void __iomem *base; + + struct clk *core_clk; ++ struct clk *iface_clk; + bool use_hwkm; + bool hwkm_init_complete; + u8 hwkm_version; +@@ -312,8 +313,13 @@ int qcom_ice_resume(struct qcom_ice *ice) + + err = clk_prepare_enable(ice->core_clk); + if (err) { +- dev_err(dev, "failed to enable core clock (%d)\n", +- err); ++ dev_err(dev, "Failed to enable core clock: %d\n", err); ++ return err; ++ } ++ ++ err = clk_prepare_enable(ice->iface_clk); ++ if (err) { ++ dev_err(dev, "Failed to enable iface clock: %d\n", err); + return err; + } + qcom_ice_hwkm_init(ice); +@@ -323,6 +329,7 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume); + + int qcom_ice_suspend(struct qcom_ice *ice) + { ++ clk_disable_unprepare(ice->iface_clk); + clk_disable_unprepare(ice->core_clk); + ice->hwkm_init_complete = false; + +@@ -579,11 +586,17 @@ static struct qcom_ice *qcom_ice_create(struct device *dev, + engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk"); + if (!engine->core_clk) + engine->core_clk = devm_clk_get_optional_enabled(dev, "ice"); ++ if (!engine->core_clk) ++ engine->core_clk = devm_clk_get_optional_enabled(dev, "core"); + if (!engine->core_clk) + engine->core_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(engine->core_clk)) + return ERR_CAST(engine->core_clk); + ++ engine->iface_clk = devm_clk_get_optional_enabled(dev, "iface"); ++ if (IS_ERR(engine->iface_clk)) ++ return ERR_CAST(engine->iface_clk); ++ + if (!qcom_ice_check_supported(engine)) + return ERR_PTR(-EOPNOTSUPP); + +-- +2.53.0 + diff --git a/queue-7.0/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch b/queue-7.0/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch new file mode 100644 index 0000000000..c3e05092a9 --- /dev/null +++ b/queue-7.0/soc-qcom-ice-return-enodev-if-the-ice-platform-devic.patch @@ -0,0 +1,44 @@ +From 6a8f0b614ab8736c07586f8a25225ff7f2f3ad53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 May 2026 19:22:18 +0530 +Subject: soc: qcom: ice: Return -ENODEV if the ICE platform device is not + found + +From: Manivannan Sadhasivam + +[ Upstream commit 5a4dc805a80e6fe303d6a4748cd451ea15987ffd ] + +By the time the consumer driver calls devm_of_qcom_ice_get(), all the +platform devices for ICE nodes would've been created by +of_platform_default_populate(). + +So for the absence of any platform device, -ENODEV should not returned, not +-EPROBE_DEFER. + +Fixes: 2afbf43a4aec ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver") +Tested-by: Sumit Garg # OP-TEE as TZ +Acked-by: Sumit Garg +Signed-off-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-2-2a595382185b@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ice.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index bf4ab2d9e5c036..6520e146d2ce06 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -657,7 +657,7 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev) + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_err(dev, "Cannot find device node %s\n", node->name); +- return ERR_PTR(-EPROBE_DEFER); ++ return ERR_PTR(-ENODEV); + } + + ice = platform_get_drvdata(pdev); +-- +2.53.0 + diff --git a/queue-7.0/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch b/queue-7.0/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch new file mode 100644 index 0000000000..53a958422c --- /dev/null +++ b/queue-7.0/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch @@ -0,0 +1,118 @@ +From 7a4f884b617eec97780f449af085df8c8b17aff7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 18:20:55 +0000 +Subject: tcp: Add preempt_{disable,enable}_nested() in reqsk_queue_hash_req(). + +From: Kuniyuki Iwashima + +[ Upstream commit e10902df24488ca722303133acfc82490f7d59ad ] + +syzbot reported a weird reqsk->rsk_refcnt underflow in +__inet_csk_reqsk_queue_drop(). + +The captured reqsk_put() in __inet_csk_reqsk_queue_drop() +is called only when it successfully removes reqsk from ehash. + +Moreover, reqsk_timer_handler() calls another reqsk_put() +after that. + +This indicates that the reqsk was missing both refcnts for +ehash and the timer itself. + +Since all the syzbot reports had PREEMPT_RT enabled, the only +possible scenario is that reqsk_queue_hash_req() is preempted +after mod_timer() and before refcount_set(), and then the timer +triggered after 1s aborts the reqsk due to its listener's close(). + +Let's wrap mod_timer() and refcount_set() with +preempt_disable_nested() and preempt_enable_nested(). + +Note that inet_ehash_insert() holds the normal spin_lock() +(mutex in PREEMPT_RT), so it must be called outside of +preempt_disable_nested(), but this is fine. + +The lookup path just ignores 0 sk_refcnt entries in ehash +and tries to create another reqsk, but this will fail at +inet_ehash_insert(). + +[0]: +refcount_t: underflow; use-after-free. +WARNING: lib/refcount.c:28 at refcount_warn_saturate+0xb2/0x110 lib/refcount.c:28, CPU#0: ktimers/0/16 +Modules linked in: +CPU: 0 UID: 0 PID: 16 Comm: ktimers/0 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} +Tainted: [L]=SOFTLOCKUP +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 +RIP: 0010:refcount_warn_saturate+0xb2/0x110 lib/refcount.c:28 +Code: e4 7d d1 0a 67 48 0f b9 3a eb 4a e8 38 3d 23 fd 48 8d 3d e1 7d d1 0a 67 48 0f b9 3a eb 37 e8 25 3d 23 fd 48 8d 3d de 7d d1 0a <67> 48 0f b9 3a eb 24 e8 12 3d 23 fd 48 8d 3d db 7d d1 0a 67 48 0f +RSP: 0000:ffffc90000157948 EFLAGS: 00010246 +RAX: ffffffff84a1301b RBX: 0000000000000003 RCX: ffff88801ca98000 +RDX: 0000000000000100 RSI: 0000000000000000 RDI: ffffffff8f72ae00 +RBP: ffffffff99ae3b01 R08: ffff88801ca98000 R09: 0000000000000005 +R10: 0000000000000100 R11: 0000000000000004 R12: ffff8880425ef568 +R13: ffff8880425ef4f8 R14: ffff8880425ef578 R15: 0000000000000000 +FS: 0000000000000000(0000) GS:ffff888126386000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f7b46710e9c CR3: 000000000dbb6000 CR4: 00000000003526f0 +Call Trace: + + __refcount_sub_and_test include/linux/refcount.h:400 [inline] + __refcount_dec_and_test include/linux/refcount.h:432 [inline] + refcount_dec_and_test include/linux/refcount.h:450 [inline] + reqsk_put include/net/request_sock.h:136 [inline] + __inet_csk_reqsk_queue_drop+0x3ce/0x440 net/ipv4/inet_connection_sock.c:1007 + reqsk_timer_handler+0x651/0xdf0 net/ipv4/inet_connection_sock.c:1137 + call_timer_fn+0x192/0x5e0 kernel/time/timer.c:1748 + expire_timers kernel/time/timer.c:1799 [inline] + __run_timers kernel/time/timer.c:2374 [inline] + __run_timer_base+0x6a3/0x9f0 kernel/time/timer.c:2386 + run_timer_base kernel/time/timer.c:2395 [inline] + run_timer_softirq+0x67/0x170 kernel/time/timer.c:2403 + handle_softirqs+0x1de/0x6d0 kernel/softirq.c:622 + __do_softirq kernel/softirq.c:656 [inline] + run_ktimerd+0x69/0x100 kernel/softirq.c:1151 + smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160 + kthread+0x388/0x470 kernel/kthread.c:436 + ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + + +Fixes: d2d6422f8bd1 ("x86: Allow to enable PREEMPT_RT.") +Reported-by: syzbot+e809069bc15f26300526@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a1a7bcf.0a9e871e.332604.000b.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260601182101.3183993-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index f1988fd503540d..d9f6c8d4d7e63a 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1151,6 +1151,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req) + /* The timer needs to be setup after a successful insertion. */ + req->timeout = tcp_timeout_init((struct sock *)req); + timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED); ++ ++ preempt_disable_nested(); ++ + mod_timer(&req->rsk_timer, jiffies + req->timeout); + + /* before letting lookups find us, make sure all req fields +@@ -1158,6 +1161,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req) + */ + smp_wmb(); + refcount_set(&req->rsk_refcnt, 2 + 1); ++ ++ preempt_enable_nested(); ++ + return true; + } + +-- +2.53.0 + diff --git a/queue-7.0/tee-fix-tee_ioctl_object_invoke_arg-padding.patch b/queue-7.0/tee-fix-tee_ioctl_object_invoke_arg-padding.patch new file mode 100644 index 0000000000..4b33d7e613 --- /dev/null +++ b/queue-7.0/tee-fix-tee_ioctl_object_invoke_arg-padding.patch @@ -0,0 +1,44 @@ +From b4a13900819795d886fdab77d8ddb3a535981e2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 11:17:23 +0100 +Subject: tee: fix tee_ioctl_object_invoke_arg padding + +From: Arnd Bergmann + +[ Upstream commit c15d7a2a11ea055bcecc0b538ae8ba79475637f9 ] + +The tee_ioctl_object_invoke_arg structure has padding on some +architectures but not on x86-32 and a few others: + +include/linux/tee.h:474:32: error: padding struct to align 'params' [-Werror=padded] + +I expect that all current users of this are on architectures that do +have implicit padding here (arm64, arm, x86, riscv), so make the padding +explicit in order to avoid surprises if this later gets used elsewhere. + +Fixes: d5b8b0fa1775 ("tee: add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF") +Signed-off-by: Arnd Bergmann +Reviewed-by: Jens Wiklander +Tested-by: Harshal Dev +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + include/uapi/linux/tee.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h +index cab5cadca8ef99..5203977ed35d1d 100644 +--- a/include/uapi/linux/tee.h ++++ b/include/uapi/linux/tee.h +@@ -470,6 +470,7 @@ struct tee_ioctl_object_invoke_arg { + __u32 op; + __u32 ret; + __u32 num_params; ++ __u32 :32; + /* num_params tells the actual number of element in params */ + struct tee_ioctl_param params[]; + }; +-- +2.53.0 + diff --git a/queue-7.0/tee-optee-prevent-use-after-free-when-the-client-exi.patch b/queue-7.0/tee-optee-prevent-use-after-free-when-the-client-exi.patch new file mode 100644 index 0000000000..a9112a9b11 --- /dev/null +++ b/queue-7.0/tee-optee-prevent-use-after-free-when-the-client-exi.patch @@ -0,0 +1,287 @@ +From 6247c1e67129ea3d63898c3959bcf6e6b5a2e824 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:24:06 -0800 +Subject: tee: optee: prevent use-after-free when the client exits before the + supplicant + +From: Amirreza Zarrabi + +[ Upstream commit 387a926ee166814611acecb960207fe2f3c4fd3e ] + +Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the +client wait as killable so it can be interrupted during shutdown or +after a supplicant crash. This changes the original lifetime expectations: +the client task can now terminate while the supplicant is still processing +its request. + +If the client exits first it removes the request from its queue and +kfree()s it, while the request ID remains in supp->idr. A subsequent +lookup on the supplicant path then dereferences freed memory, leading to +a use-after-free. + +Serialise access to the request with supp->mutex: + + * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while + looking up and touching the request. + * Let optee_supp_thrd_req() notice that the client has terminated and + signal optee_supp_send() accordingly. + +With these changes the request cannot be freed while the supplicant still +has a reference, eliminating the race. + +Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") +Signed-off-by: Amirreza Zarrabi +Tested-by: Ox Yeh +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/supp.c | 107 +++++++++++++++++++++++++++------------ + 1 file changed, 74 insertions(+), 33 deletions(-) + +diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c +index a3d11b1f90fa55..06747e90c2309b 100644 +--- a/drivers/tee/optee/supp.c ++++ b/drivers/tee/optee/supp.c +@@ -10,7 +10,11 @@ + struct optee_supp_req { + struct list_head link; + ++ int id; ++ + bool in_queue; ++ bool processed; ++ + u32 func; + u32 ret; + size_t num_params; +@@ -19,6 +23,9 @@ struct optee_supp_req { + struct completion c; + }; + ++/* It is temporary request used for revoked pending request in supp->idr. */ ++#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) ++ + void optee_supp_init(struct optee_supp *supp) + { + memset(supp, 0, sizeof(*supp)); +@@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) + { + int id; + struct optee_supp_req *req; +- struct optee_supp_req *req_tmp; + + mutex_lock(&supp->mutex); + +- /* Abort all request retrieved by supplicant */ ++ /* Abort all request */ + idr_for_each_entry(&supp->idr, req, id) { + idr_remove(&supp->idr, id); +- req->ret = TEEC_ERROR_COMMUNICATION; +- complete(&req->c); +- } ++ /* Skip if request was already marked invalid */ ++ if (IS_ERR(req)) ++ continue; + +- /* Abort all queued requests */ +- list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { +- list_del(&req->link); +- req->in_queue = false; ++ /* For queued requests where supplicant has not seen it */ ++ if (req->in_queue) { ++ list_del(&req->link); ++ req->in_queue = false; ++ } ++ ++ req->processed = true; + req->ret = TEEC_ERROR_COMMUNICATION; + complete(&req->c); + } +@@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + + /* Insert the request in the request list */ + mutex_lock(&supp->mutex); ++ req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); ++ if (req->id < 0) { ++ mutex_unlock(&supp->mutex); ++ kfree(req); ++ return TEEC_ERROR_OUT_OF_MEMORY; ++ } ++ + list_add_tail(&req->link, &supp->reqs); + req->in_queue = true; ++ req->processed = false; + mutex_unlock(&supp->mutex); + + /* Tell an eventual waiter there's a new request */ +@@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + if (wait_for_completion_killable(&req->c)) { + mutex_lock(&supp->mutex); + if (req->in_queue) { ++ /* Supplicant has not seen this request yet. */ ++ idr_remove(&supp->idr, req->id); + list_del(&req->link); + req->in_queue = false; ++ ++ ret = TEEC_ERROR_COMMUNICATION; ++ } else if (req->processed) { ++ /* ++ * Supplicant has processed this request. Ignore the ++ * kill signal for now and submit the result. req is not ++ * in supp->reqs (removed by supp_pop_entry()) nor in ++ * supp->idr (removed by supp_pop_req()). ++ */ ++ ret = req->ret; ++ } else { ++ /* ++ * Supplicant is in the middle of processing this ++ * request. Replace req with INVALID_REQ_PTR so that ++ * the ID remains busy, causing optee_supp_send() to ++ * fail on the next call to supp_pop_req() with this ID. ++ */ ++ idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); ++ ret = TEEC_ERROR_COMMUNICATION; + } ++ + mutex_unlock(&supp->mutex); +- req->ret = TEEC_ERROR_COMMUNICATION; ++ } else { ++ ret = req->ret; + } + +- ret = req->ret; + kfree(req); + + return ret; + } + + static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, +- int num_params, int *id) ++ int num_params) + { + struct optee_supp_req *req; + +@@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, + return ERR_PTR(-EINVAL); + } + +- *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); +- if (*id < 0) +- return ERR_PTR(-ENOMEM); +- + list_del(&req->link); + req->in_queue = false; + +@@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + struct optee_supp_req *req = NULL; +- int id; + size_t num_meta; + int rc; + +@@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + + while (true) { + mutex_lock(&supp->mutex); +- req = supp_pop_entry(supp, *num_params - num_meta, &id); ++ req = supp_pop_entry(supp, *num_params - num_meta); ++ if (req) ++ break; /* Keep mutex held. */ + mutex_unlock(&supp->mutex); + +- if (req) { +- if (IS_ERR(req)) +- return PTR_ERR(req); +- break; +- } +- + /* + * If we didn't get a request we'll block in + * wait_for_completion() to avoid needless spinning. +@@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + return -ERESTARTSYS; + } + ++ /* supp->mutex held and req != NULL. */ ++ ++ if (IS_ERR(req)) { ++ mutex_unlock(&supp->mutex); ++ return PTR_ERR(req); ++ } ++ + if (num_meta) { + /* + * tee-supplicant support meta parameters -> requsts can be +@@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + */ + param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; +- param->u.value.a = id; ++ param->u.value.a = req->id; + param->u.value.b = 0; + param->u.value.c = 0; + } else { +- mutex_lock(&supp->mutex); +- supp->req_id = id; +- mutex_unlock(&supp->mutex); ++ supp->req_id = req->id; + } + + *func = req->func; +@@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + ++ mutex_unlock(&supp->mutex); + return 0; + } + +@@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, + if (!req) + return ERR_PTR(-ENOENT); + ++ /* optee_supp_thrd_req() already returned to optee. */ ++ if (IS_ERR(req)) ++ goto failed_req; ++ + if ((num_params - nm) != req->num_params) + return ERR_PTR(-EINVAL); + ++ *num_meta = nm; ++failed_req: + idr_remove(&supp->idr, id); + supp->req_id = -1; +- *num_meta = nm; + + return req; + } +@@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + + mutex_lock(&supp->mutex); + req = supp_pop_req(supp, num_params, param, &num_meta); +- mutex_unlock(&supp->mutex); +- + if (IS_ERR(req)) { +- /* Something is wrong, let supplicant restart. */ ++ mutex_unlock(&supp->mutex); ++ /* Something is wrong, let supplicant handel it. */ + return PTR_ERR(req); + } + +@@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + } + } + req->ret = ret; +- ++ req->processed = true; + /* Let the requesting thread continue */ + complete(&req->c); ++ mutex_unlock(&supp->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch b/queue-7.0/tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch new file mode 100644 index 0000000000..487154f7ec --- /dev/null +++ b/queue-7.0/tee-qcomtee-add-missing-va_end-in-early-return-qcomt.patch @@ -0,0 +1,47 @@ +From da747286eb5a8b75af6f5ca36a36e5ccb1a4acad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 09:05:28 +0700 +Subject: tee: qcomtee: add missing va_end in early return + qcomtee_object_user_init() + +From: Robertus Diawan Chris + +[ Upstream commit 471c18323dfdfe7844e193b896a9267ae23a1026 ] + +qcomtee_object_user_init() is a variadic function and when the function +return because there's no dispatch callback in QCOMTEE_OBJECT_TYPE_CB +case, there's no va_end to cleanup "ap" object initialized by va_start +and that can cause undefined behavior. So make sure to use va_end before +returning the error code when there's no dispatch callback. + +This is reported by Coverity Scan as "Missing varargs init or cleanup". + +Fixes: d6e290837e50 ("tee: add Qualcomm TEE driver") +Signed-off-by: Robertus Diawan Chris +Reviewed-by: Amirreza Zarrabi +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/qcomtee/core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c +index b1cb50e434f00a..60fe3b5776e36d 100644 +--- a/drivers/tee/qcomtee/core.c ++++ b/drivers/tee/qcomtee/core.c +@@ -306,8 +306,10 @@ int qcomtee_object_user_init(struct qcomtee_object *object, + break; + case QCOMTEE_OBJECT_TYPE_CB: + object->ops = ops; +- if (!object->ops->dispatch) +- return -EINVAL; ++ if (!object->ops->dispatch) { ++ ret = -EINVAL; ++ break; ++ } + + /* If failed, "no-name". */ + object->name = kvasprintf_const(GFP_KERNEL, fmt, ap); +-- +2.53.0 + diff --git a/queue-7.0/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch b/queue-7.0/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch new file mode 100644 index 0000000000..e5037e822b --- /dev/null +++ b/queue-7.0/vxlan-vnifilter-fix-spurious-notification-on-vni-upd.patch @@ -0,0 +1,55 @@ +From 6852220ac7e18e2f200f92323ef92a14c22c3c35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:37 -0700 +Subject: vxlan: vnifilter: fix spurious notification on VNI update + +From: Andy Roulin + +[ Upstream commit 84683b5b60c7274e2c8f7f413d39d78d3db5540f ] + +When a VNI is re-added with the same attributes (e.g. same group or no +group), vxlan_vni_update() sends a spurious RTM_NEWTUNNEL notification +even though nothing changed. + +The bug is that 'if (changed)' tests whether the pointer is non-NULL, +not the bool value it points to. Since every caller passes a valid +pointer, the condition is always true and the notification fires +unconditionally. + +Fix by dereferencing the pointer: 'if (*changed)'. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 + # bridge vni add vni 1000 dev vxlan100 # spurious notification + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-3-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index f2a202d468928c..3e76f4e210944f 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -661,7 +661,7 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan, + if (ret) + return ret; + +- if (changed) ++ if (*changed) + vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/vxlan-vnifilter-send-notification-on-vni-add.patch b/queue-7.0/vxlan-vnifilter-send-notification-on-vni-add.patch new file mode 100644 index 0000000000..7aaae8dd75 --- /dev/null +++ b/queue-7.0/vxlan-vnifilter-send-notification-on-vni-add.patch @@ -0,0 +1,69 @@ +From 2907008a537e88db2dadbd21efd1e07ac37e4499 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 11:51:36 -0700 +Subject: vxlan: vnifilter: send notification on VNI add + +From: Andy Roulin + +[ Upstream commit aa6ca1c5c338907817374b59f7551fd855a88754 ] + +When a new VNI is added to a vxlan device with vnifilter enabled, +no RTM_NEWTUNNEL notification is sent to userspace. This means +'bridge monitor vni' never shows VNI add events, even though +VNI delete events are reported correctly. + +The bug is in vxlan_vni_add(), where the notification is guarded by +'if (changed)'. The 'changed' flag is set by vxlan_vni_update_group() +only when the multicast group or remote IP is modified, but for a +new VNI added without a group (e.g. in L3 VxLAN interface scenarios), +the function returns early without setting changed=true. Since this +is a new VNI, the notification should be sent unconditionally. + +The notification is not guarded by the return value of +vxlan_vni_update_group() because, at this point, the VNI has already +been inserted into the hash table and list with no rollback on error. +The VNI will be visible in 'bridge vni show' regardless, so userspace +should be informed. This is consistent with vxlan_vni_del() which also +notifies unconditionally. + +The 'if (changed)' guard remains correct in vxlan_vni_update(), which +handles the case where a VNI already exists and is being re-added -- +there, we only want to notify if the group/remote actually changed. + +Reproducer: + + # ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \ + nolearning external vnifilter + # ip link set vxlan100 up + # bridge monitor vni & + # bridge vni add vni 1000 dev vxlan100 # no notification + # bridge vni delete vni 1000 dev vxlan100 # notification received + +Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device") +Reported-by: Chirag Shah +Signed-off-by: Andy Roulin +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20260602185138.253265-2-aroulin@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_vnifilter.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 2042369379ffc6..f2a202d468928c 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -759,8 +759,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, + err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed, + extack); + +- if (changed) +- vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); ++ vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); + + return err; + } +-- +2.53.0 + diff --git a/queue-7.0/wifi-cfg80211-add-support-to-handle-incumbent-signal.patch b/queue-7.0/wifi-cfg80211-add-support-to-handle-incumbent-signal.patch new file mode 100644 index 0000000000..04c92c3229 --- /dev/null +++ b/queue-7.0/wifi-cfg80211-add-support-to-handle-incumbent-signal.patch @@ -0,0 +1,206 @@ +From ee5da4bbc2e26efe9ae7f6395268d89008d72b48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 08:50:26 +0530 +Subject: wifi: cfg80211: add support to handle incumbent signal detected event + from mac80211/driver + +From: Hari Chandrakanthan + +[ Upstream commit 6a584e336cefb230e2d981a464f4d85562eb750c ] + +When any incumbent signal is detected by an AP/mesh interface operating +in 6 GHz band, FCC mandates the AP/mesh to vacate the channels affected +by it [1]. + +Add a new API cfg80211_incumbent_signal_notify() that can be used +by mac80211 or drivers to notify the higher layers about the signal +interference event with the interference bitmap in which each bit +denotes the affected 20 MHz in the operating channel. + +Add support for the new nl80211 event and nl80211 attribute as well to +notify userspace on the details about the interference event. Userspace is +expected to process it and take further action - vacate the channel, or +reduce the bandwidth. + +[1] - https://apps.fcc.gov/kdb/GetAttachment.html?id=nXQiRC%2B4mfiA54Zha%2BrW4Q%3D%3D&desc=987594%20D02%20U-NII%206%20GHz%20EMC%20Measurement%20v03&tracking_number=277034 + +Signed-off-by: Hari Chandrakanthan +Signed-off-by: Amith A +Link: https://patch.msgid.link/20260216032027.2310956-2-amith.a@oss.qualcomm.com +Signed-off-by: Johannes Berg +Stable-dep-of: cb9959ab5f99 ("wifi: cfg80211: enforce HE/EHT cap/oper consistency") +Signed-off-by: Sasha Levin +--- + include/net/cfg80211.h | 23 +++++++++++++++++++++ + include/uapi/linux/nl80211.h | 19 +++++++++++++++++ + net/wireless/nl80211.c | 40 ++++++++++++++++++++++++++++++++++++ + net/wireless/trace.h | 19 +++++++++++++++++ + 4 files changed, 101 insertions(+) + +diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h +index fc01de19c7981a..2311d852e19ebc 100644 +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -10472,4 +10472,27 @@ cfg80211_s1g_get_primary_sibling(struct wiphy *wiphy, + return ieee80211_get_channel_khz(wiphy, sibling_1mhz_khz); + } + ++ ++/** ++ * cfg80211_incumbent_signal_notify - Notify userspace of incumbent signal detection ++ * @wiphy: the wiphy to use ++ * @chandef: channel definition in which the interference was detected ++ * @signal_interference_bitmap: bitmap indicating interference across 20 MHz segments ++ * @gfp: allocation context for message creation and multicast; pass GFP_ATOMIC ++ * if called from atomic context (e.g. firmware event handler), otherwise ++ * GFP_KERNEL ++ * ++ * Use this function to notify userspace when an incumbent signal is detected on ++ * the operating channel in the 6 GHz band. The notification includes the ++ * current channel definition and a bitmap representing interference across ++ * the operating bandwidth. Each bit in the bitmap corresponds to a 20 MHz ++ * segment, with the lowest bit representing the lowest frequency segment. ++ * Punctured sub-channels are included in the bitmap structure but are always ++ * set to zero since interference detection is not performed on them. ++ */ ++void cfg80211_incumbent_signal_notify(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef, ++ u32 signal_interference_bitmap, ++ gfp_t gfp); ++ + #endif /* __NET_CFG80211_H */ +diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h +index b63f718509060d..b53e2d78c7bb3f 100644 +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -1361,6 +1361,12 @@ + * user space that the NAN new cluster has been joined. The cluster ID is + * indicated by %NL80211_ATTR_MAC. + * ++ * @NL80211_CMD_INCUMBENT_SIGNAL_DETECT: Once any incumbent signal is detected ++ * on the operating channel in 6 GHz band, userspace is notified with the ++ * signal interference bitmap using ++ * %NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP. The current channel ++ * definition is also sent. ++ * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +@@ -1624,6 +1630,8 @@ enum nl80211_commands { + NL80211_CMD_NAN_NEXT_DW_NOTIFICATION, + NL80211_CMD_NAN_CLUSTER_JOINED, + ++ NL80211_CMD_INCUMBENT_SIGNAL_DETECT, ++ + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ +@@ -2984,6 +2992,15 @@ enum nl80211_commands { + * this feature during association. This is a flag attribute. + * Currently only supported in mac80211 drivers. + * ++ * @NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP: u32 attribute specifying ++ * the signal interference bitmap detected on the operating bandwidth for ++ * %NL80211_CMD_INCUMBENT_SIGNAL_DETECT. Each bit represents a 20 MHz ++ * segment, lowest bit corresponds to the lowest 20 MHz segment, in the ++ * operating bandwidth where the interference is detected. Punctured ++ * sub-channels are included in the bitmap structure; however, since ++ * interference detection is not performed on these sub-channels, their ++ * corresponding bits are consistently set to zero. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3557,6 +3574,8 @@ enum nl80211_attrs { + NL80211_ATTR_UHR_CAPABILITY, + NL80211_ATTR_DISABLE_UHR, + ++ NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index b94231c8441c48..d00357488ea8ea 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -21120,6 +21120,46 @@ void cfg80211_ch_switch_notify(struct net_device *dev, + } + EXPORT_SYMBOL(cfg80211_ch_switch_notify); + ++void cfg80211_incumbent_signal_notify(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef, ++ u32 signal_interference_bitmap, ++ gfp_t gfp) ++{ ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ struct sk_buff *msg; ++ void *hdr; ++ ++ trace_cfg80211_incumbent_signal_notify(wiphy, chandef, signal_interference_bitmap); ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ if (!msg) ++ return; ++ ++ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_INCUMBENT_SIGNAL_DETECT); ++ if (!hdr) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) ++ goto nla_put_failure; ++ ++ if (nl80211_send_chandef(msg, chandef)) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP, ++ signal_interference_bitmap)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ ++ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, ++ NL80211_MCGRP_MLME, gfp); ++ return; ++ ++nla_put_failure: ++ nlmsg_free(msg); ++} ++EXPORT_SYMBOL(cfg80211_incumbent_signal_notify); ++ + void cfg80211_ch_switch_started_notify(struct net_device *dev, + struct cfg80211_chan_def *chandef, + unsigned int link_id, u8 count, +diff --git a/net/wireless/trace.h b/net/wireless/trace.h +index 643ccf4f022722..352a57d8b96819 100644 +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -4225,6 +4225,25 @@ TRACE_EVENT(cfg80211_nan_cluster_joined, + WDEV_PR_ARG, __entry->cluster_id, + __entry->new_cluster ? " [new]" : "") + ); ++ ++TRACE_EVENT(cfg80211_incumbent_signal_notify, ++ TP_PROTO(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef, ++ u32 signal_interference_bitmap), ++ TP_ARGS(wiphy, chandef, signal_interference_bitmap), ++ TP_STRUCT__entry( ++ WIPHY_ENTRY ++ CHAN_DEF_ENTRY ++ __field(u32, signal_interference_bitmap) ++ ), ++ TP_fast_assign( ++ WIPHY_ASSIGN; ++ CHAN_DEF_ASSIGN(chandef); ++ __entry->signal_interference_bitmap = signal_interference_bitmap; ++ ), ++ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", signal_interference_bitmap=0x%x", ++ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->signal_interference_bitmap) ++); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH +-- +2.53.0 + diff --git a/queue-7.0/wifi-cfg80211-enforce-he-eht-cap-oper-consistency.patch b/queue-7.0/wifi-cfg80211-enforce-he-eht-cap-oper-consistency.patch new file mode 100644 index 0000000000..ba5757614f --- /dev/null +++ b/queue-7.0/wifi-cfg80211-enforce-he-eht-cap-oper-consistency.patch @@ -0,0 +1,42 @@ +From 9409bb870ab551164c0635f3f918a550680dbd66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 11:18:11 +0200 +Subject: wifi: cfg80211: enforce HE/EHT cap/oper consistency + +From: Johannes Berg + +[ Upstream commit cb9959ab5f99611d27a06586add84811fe8102dc ] + +Xiang Mei reports that mac80211 could crash if eht_cap is set +but eht_oper isn't. Rather than fixing that for the individual +user(s), enforce that both HE/EHT have consistent elements. + +Reported-by: Xiang Mei +Fixes: 22c64f37e1d4 ("wifi: mac80211: Update MCS15 support in link_conf") +Link: https://patch.msgid.link/20260603091812.101894-2-johannes@sipsolutions.net +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/nl80211.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index 84fcfb1e53a156..fe0c0c198b2526 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -6499,6 +6499,12 @@ static int nl80211_calculate_ap_params(struct cfg80211_ap_settings *params) + return -EINVAL; + } + ++ if (!!params->he_cap != !!params->he_oper) ++ return -EINVAL; ++ ++ if (!!params->eht_cap != !!params->eht_oper) ++ return -EINVAL; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-fix-leak-if-split-6-ghz-scanning-fails.patch b/queue-7.0/wifi-fix-leak-if-split-6-ghz-scanning-fails.patch new file mode 100644 index 0000000000..34a9a774e2 --- /dev/null +++ b/queue-7.0/wifi-fix-leak-if-split-6-ghz-scanning-fails.patch @@ -0,0 +1,79 @@ +From d609b22094b527fb93ea062425ed0e11af546306 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:41:56 +0300 +Subject: wifi: fix leak if split 6 GHz scanning fails + +From: Fedor Pchelkin + +[ Upstream commit e8694f7cc29287e843648d1075177b9a2000d957 ] + +rdev->int_scan_req is leaked if cfg80211_scan() fails. Note that it's +supposed to be released at ___cfg80211_scan_done() but this doesn't happen +as rdev->scan_req is NULL at that point, too, leading to the early return +from the freeing function. + +unreferenced object 0xffff8881161d0800 (size 512): + comm "wpa_supplicant", pid 379, jiffies 4294749765 + hex dump (first 32 bytes): + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 00 00 00 00 00 00 00 00 f0 81 13 16 81 88 ff ff ................ + backtrace (crc c867fdb6): + kmemleak_alloc+0x89/0x90 + __kmalloc_noprof+0x2fd/0x410 + cfg80211_scan+0x133/0x730 + nl80211_trigger_scan+0xc69/0x1cc0 + genl_family_rcv_msg_doit+0x204/0x2f0 + genl_rcv_msg+0x431/0x6b0 + netlink_rcv_skb+0x143/0x3f0 + genl_rcv+0x27/0x40 + netlink_unicast+0x4f6/0x820 + netlink_sendmsg+0x797/0xce0 + __sock_sendmsg+0xc4/0x160 + ____sys_sendmsg+0x5e4/0x890 + ___sys_sendmsg+0xf8/0x180 + __sys_sendmsg+0x136/0x1e0 + __x64_sys_sendmsg+0x76/0xc0 + x64_sys_call+0x13f0/0x17d0 + +Found by Linux Verification Center (linuxtesting.org). + +Fixes: c8cb5b854b40 ("nl80211/cfg80211: support 6 GHz scanning") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260601094157.92703-1-pchelkin@ispras.ru +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/scan.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 358cbc9e43d851..27a56ee2e8f0b3 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -1071,6 +1071,7 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev) + struct cfg80211_scan_request_int *request; + struct cfg80211_scan_request_int *rdev_req = rdev->scan_req; + u32 n_channels = 0, idx, i; ++ int err; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ)) { + rdev_req->req.first_part = true; +@@ -1100,8 +1101,14 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev) + + rdev_req->req.scan_6ghz = false; + rdev_req->req.first_part = true; ++ err = rdev_scan(rdev, request); ++ if (err) { ++ kfree(request); ++ return err; ++ } ++ + rdev->int_scan_req = request; +- return rdev_scan(rdev, request); ++ return 0; + } + + void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, +-- +2.53.0 + diff --git a/queue-7.0/wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch b/queue-7.0/wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch new file mode 100644 index 0000000000..95fde8b3dc --- /dev/null +++ b/queue-7.0/wifi-iwlwifi-mvm-don-t-support-the-reset-handshake-f.patch @@ -0,0 +1,45 @@ +From 3f686e202dae6cd32d719813370e85457b08028e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 08:57:05 +0300 +Subject: wifi: iwlwifi: mvm: don't support the reset handshake for old + firmwares + +From: Emmanuel Grumbach + +[ Upstream commit 0eaa1f245ac03ed0c6394159360532726f666811 ] + +-77.ucode doesn't contain the fixes for this flow it seems. +Don't use the firmware reset handshake even if the firmware claims +support for it. + +Fixes: 906d4eb84408 ("iwlwifi: support firmware reset handshake") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220600 +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260529085453.9307b81d9b02.I21bba9e649f4cd0e35d3ea6cd97a03258be5832f@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +index ae177477b20127..384bed95835d74 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +@@ -1416,6 +1416,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE); + ++ /* Those firmware versions claim to support the fw_reset_handshake ++ * but they are buggy. ++ */ ++ if (IWL_UCODE_MAJOR(mvm->fw->ucode_ver) <= 77) ++ trans->conf.fw_reset_handshake = false; ++ + trans->conf.queue_alloc_cmd_ver = + iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(DATA_PATH_GROUP, +-- +2.53.0 + diff --git a/queue-7.0/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch b/queue-7.0/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch new file mode 100644 index 0000000000..a70e9b43b7 --- /dev/null +++ b/queue-7.0/wifi-mac80211-limit-injected-antenna-index-in-ieee80.patch @@ -0,0 +1,61 @@ +From f4aa7232dac3a99d8f9a07db633511e8b3aa2c43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 06:47:21 +0530 +Subject: wifi: mac80211: limit injected antenna index in + ieee80211_parse_tx_radiotap + +From: Deepanshu Kartikey + +[ Upstream commit 6c0cf89f36ac0c0fd8687a4ccdce2efb23a9c663 ] + +When parsing the radiotap header of an injected frame, +ieee80211_parse_tx_radiotap() uses the IEEE80211_RADIOTAP_ANTENNA value +directly as a shift count: + + info->control.antennas |= BIT(*iterator.this_arg); + +*iterator.this_arg is an 8-bit value taken straight from the frame +supplied by userspace, so BIT() can be asked to shift by up to 255. That +is undefined behaviour on the unsigned long and is reported by UBSAN: + + UBSAN: shift-out-of-bounds in net/mac80211/tx.c:2174:30 + shift exponent 235 is too large for 64-bit type 'unsigned long' + Call Trace: + ieee80211_parse_tx_radiotap+0xadb/0x1950 net/mac80211/tx.c:2174 + ieee80211_monitor_start_xmit+0xb1f/0x1250 net/mac80211/tx.c:2451 + ... + packet_sendmsg+0x3eb6/0x50f0 net/packet/af_packet.c:3109 + +info->control.antennas is a 2-bit bitmap (u8 antennas:2), so only antenna +indices 0 and 1 can ever be represented. Ignore any larger value instead +of shifting out of bounds. + +Reported-by: syzbot+8e0622f6d9446420271f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8e0622f6d9446420271f +Fixes: ef246a1480cc ("wifi: mac80211: support antenna control in injection") +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20260531011721.102941-1-kartikey406@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/tx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index b7aedaab848386..d2ba2d81224f97 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -2172,7 +2172,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, + + case IEEE80211_RADIOTAP_ANTENNA: + /* this can appear multiple times, keep a bitmap */ +- info->control.antennas |= BIT(*iterator.this_arg); ++ /* control.antennas is only a 2-bit bitmap */ ++ if (*iterator.this_arg < 2) ++ info->control.antennas |= BIT(*iterator.this_arg); + break; + + case IEEE80211_RADIOTAP_DATA_RETRIES: +-- +2.53.0 + diff --git a/queue-7.0/wifi-nl80211-split-out-uhr-operation-information.patch b/queue-7.0/wifi-nl80211-split-out-uhr-operation-information.patch new file mode 100644 index 0000000000..23af1f7c2a --- /dev/null +++ b/queue-7.0/wifi-nl80211-split-out-uhr-operation-information.patch @@ -0,0 +1,108 @@ +From f34fec4b61e89d87bca7e681572d9547360071e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 22:17:09 +0100 +Subject: wifi: nl80211: split out UHR operation information + +From: Johannes Berg + +[ Upstream commit e4b993f2bca78357b430170574f8de7bc7874088 ] + +The beacon doesn't contain the full UHR operation, a number +of fields (such as NPCA) are only partially there. Add a new +attribute to contain the full information, so it's available +to the driver/mac80211. + +Link: https://patch.msgid.link/20260303221710.866bacf82639.Iafdf37fb0f4304bdcdb824977d61e17b38c47685@changeid +Signed-off-by: Johannes Berg +Stable-dep-of: cb9959ab5f99 ("wifi: cfg80211: enforce HE/EHT cap/oper consistency") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/nl80211.h | 6 ++++++ + net/wireless/nl80211.c | 26 ++++++++++++++++---------- + 2 files changed, 22 insertions(+), 10 deletions(-) + +diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h +index b53e2d78c7bb3f..b997e6c6fc4b38 100644 +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -3001,6 +3001,10 @@ enum nl80211_commands { + * interference detection is not performed on these sub-channels, their + * corresponding bits are consistently set to zero. + * ++ * @NL80211_ATTR_UHR_OPERATION: Full UHR Operation element, as it appears in ++ * association response etc., since it's abridged in the beacon. Used ++ * for START_AP etc. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3576,6 +3580,8 @@ enum nl80211_attrs { + + NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP, + ++ NL80211_ATTR_UHR_OPERATION, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index d00357488ea8ea..84fcfb1e53a156 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -341,6 +341,17 @@ static int validate_uhr_capa(const struct nlattr *attr, + return ieee80211_uhr_capa_size_ok(data, len, false); + } + ++static int validate_uhr_operation(const struct nlattr *attr, ++ struct netlink_ext_ack *extack) ++{ ++ const u8 *data = nla_data(attr); ++ unsigned int len = nla_len(attr); ++ ++ if (!ieee80211_uhr_oper_size_ok(data, len, false)) ++ return -EINVAL; ++ return 0; ++} ++ + /* policy for the attributes */ + static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR]; + +@@ -946,6 +957,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + [NL80211_ATTR_UHR_CAPABILITY] = + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_capa, 255), + [NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG }, ++ [NL80211_ATTR_UHR_OPERATION] = ++ NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_operation), + }; + + /* policy for the key attributes */ +@@ -6486,16 +6499,6 @@ static int nl80211_calculate_ap_params(struct cfg80211_ap_settings *params) + return -EINVAL; + } + +- cap = cfg80211_find_ext_elem(WLAN_EID_EXT_UHR_OPER, ies, ies_len); +- if (cap) { +- if (!cap->datalen) +- return -EINVAL; +- params->uhr_oper = (void *)(cap->data + 1); +- if (!ieee80211_uhr_oper_size_ok((const u8 *)params->uhr_oper, +- cap->datalen - 1, true)) +- return -EINVAL; +- } +- + return 0; + } + +@@ -6928,6 +6931,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) + if (err) + goto out; + ++ if (info->attrs[NL80211_ATTR_UHR_OPERATION]) ++ params->uhr_oper = nla_data(info->attrs[NL80211_ATTR_UHR_OPERATION]); ++ + err = nl80211_validate_ap_phy_operation(params); + if (err) + goto out; +-- +2.53.0 + diff --git a/queue-7.0/xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch b/queue-7.0/xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch new file mode 100644 index 0000000000..94e0b4e7b9 --- /dev/null +++ b/queue-7.0/xsk-cache-csum_start-csum_offset-to-fix-toctou-in-xs.patch @@ -0,0 +1,73 @@ +From 122e19483ae12798b6f95014817fec16b2a38bde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 30 May 2026 12:26:30 +0800 +Subject: xsk: cache csum_start/csum_offset to fix TOCTOU in xsk_skb_metadata() + +From: Jason Xing + +[ Upstream commit 22ba97ea9cc1f63a0d0244fae38057ed452b6ac7 ] + +The TX metadata area resides in the UMEM buffer which is memory-mapped +and concurrently writable by userspace. In xsk_skb_metadata(), +csum_start and csum_offset are read from shared memory for bounds +validation, then read again for skb assignment. A malicious userspace +application can race to overwrite these values between the two reads, +bypassing the bounds check and causing out-of-bounds memory access +during checksum computation in the transmit path. + +Fix this by reading csum_start and csum_offset into local variables +once, then using the local copies for both validation and assignment. + +Note that other metadata fields (flags, launch_time) and the cached +csum fields may be mutually inconsistent due to concurrent userspace +writes, but this is benign: the only security-critical invariant is +that each field's validated value is the same one used, which local +caching guarantees. + +Closes: https://lore.kernel.org/all/20260503200927.73EA1C2BCB4@smtp.kernel.org/ +Reviewed-by: Maciej Fijalkowski +Signed-off-by: Jason Xing +Acked-by: Stanislav Fomichev +Fixes: 48eb03dd2630 ("xsk: Add TX timestamp and TX checksum offload support") +Link: https://patch.msgid.link/20260530042630.80626-1-kerneljasonxing@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/xdp/xsk.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c +index c8ef9e427c9cd5..db0fb2203af63c 100644 +--- a/net/xdp/xsk.c ++++ b/net/xdp/xsk.c +@@ -683,6 +683,7 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer, + u32 hr) + { + struct xsk_tx_metadata *meta = NULL; ++ u16 csum_start, csum_offset; + + if (unlikely(pool->tx_metadata_len == 0)) + return -EINVAL; +@@ -692,13 +693,15 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer, + return -EINVAL; + + if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) { +- if (unlikely(meta->request.csum_start + +- meta->request.csum_offset + ++ csum_start = READ_ONCE(meta->request.csum_start); ++ csum_offset = READ_ONCE(meta->request.csum_offset); ++ ++ if (unlikely(csum_start + csum_offset + + sizeof(__sum16) > desc->len)) + return -EINVAL; + +- skb->csum_start = hr + meta->request.csum_start; +- skb->csum_offset = meta->request.csum_offset; ++ skb->csum_start = hr + csum_start; ++ skb->csum_offset = csum_offset; + skb->ip_summed = CHECKSUM_PARTIAL; + + if (unlikely(pool->tx_sw_csum)) { +-- +2.53.0 +