From: Sasha Levin Date: Wed, 3 Jun 2026 01:32:16 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=c79decdda23c7b7581a8d1815477f5d99b1217fe;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch b/queue-5.10/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch new file mode 100644 index 0000000000..cb2f959851 --- /dev/null +++ b/queue-5.10/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch @@ -0,0 +1,112 @@ +From 9092c214fb76e695a77cc426b15e3a8282c4ebd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 13:51:47 -0300 +Subject: ASoC: Intel: bytcht_es8316: Fix MCLK leak on init errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit afb2a3a9d8369d18122a0d7cd294eba9a98259c6 ] + +byt_cht_es8316_init() enables MCLK before configuring the codec sysclk +and creating the headset jack. If either of those later steps fails, the +function returns without disabling MCLK, leaving the clock enabled after +card registration fails. + +Track whether this driver enabled MCLK and disable it on the init error +paths. Add the matching DAI link exit callback so the same clock enable +is also balanced when ASoC cleans up a successfully initialized link. + +Fixes: a03bdaa565cb ("ASoC: Intel: add machine driver for BYT/CHT + ES8316") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-asoc-bytcht-es8316-mclk-leak-v1-1-b4a11cdc2afd@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_es8316.c | 29 ++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index a258a410dd8dfe..ebb63194c44317 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -39,6 +39,7 @@ struct byt_cht_es8316_private { + struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; + bool speaker_en; ++ bool mclk_enabled; + }; + + enum { +@@ -169,6 +170,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + }, + }; + ++static void byt_cht_es8316_disable_mclk(struct byt_cht_es8316_private *priv) ++{ ++ if (!priv->mclk_enabled) ++ return; ++ ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++} ++ + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + { + struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component; +@@ -225,12 +235,14 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); ++ else ++ priv->mclk_enabled = true; + + ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + ret = snd_soc_card_jack_new(card, "Headset", +@@ -239,13 +251,25 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; ++ ++err_disable_mclk: ++ byt_cht_es8316_disable_mclk(priv); ++ return ret; ++} ++ ++static void byt_cht_es8316_exit(struct snd_soc_pcm_runtime *runtime) ++{ ++ struct snd_soc_card *card = runtime->card; ++ struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); ++ ++ byt_cht_es8316_disable_mclk(priv); + } + + static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -359,6 +383,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, ++ .exit = byt_cht_es8316_exit, + SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), + }, + }; +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch b/queue-5.10/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch new file mode 100644 index 0000000000..60c8e51686 --- /dev/null +++ b/queue-5.10/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch @@ -0,0 +1,40 @@ +From 99097967b8448ea12a6eb9c660d3e25919ada1a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 11:21:39 +0800 +Subject: Bluetooth: 6lowpan: check skb_clone() return value in + send_mcast_pkt() + +From: Zhao Dongdong + +[ Upstream commit 3c40d381ce04f9575a5d8b542898183c3b4b38dc ] + +The skb_clone() function can return NULL if memory allocation fails. +send_mcast_pkt() calls skb_clone() without checking the return value, which +can lead to a NULL pointer dereference in send_pkt() when it dereferences +skb->data. +Add a NULL check after skb_clone() and skip the peer if the clone fails. + +Fixes: 18722c247023 ("Bluetooth: Enable 6LoWPAN support for BT LE devices") +Signed-off-by: Zhao Dongdong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/6lowpan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index 9486d66863264f..4ab9a31163b8b9 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -514,6 +514,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) + int ret; + + local_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!local_skb) ++ continue; + + BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p", + netdev->name, +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch b/queue-5.10/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch new file mode 100644 index 0000000000..f9fd9ed21d --- /dev/null +++ b/queue-5.10/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch @@ -0,0 +1,62 @@ +From 6de26b442267ad5e492d04210eda6dc221d170dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:51:52 +0800 +Subject: Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success + +From: Zhenghang Xiao + +[ Upstream commit 00e1950716c6ed67d74777b2db286b0fa23b4be9 ] + +l2cap_ecred_reconf_rsp() returns early on success without clearing +chan->ident. Every other L2CAP response handler (l2cap_ecred_conn_rsp, +l2cap_le_connect_rsp, l2cap_config_rsp) clears chan->ident after a +successful transaction to prevent the channel from matching subsequent +responses with the recycled ident value. + +A remote attacker that completed a reconfiguration as the peer can +replay a failure response with the stale ident, causing the kernel to +match and destroy the already-established channel via +l2cap_chan_del(chan, ECONNRESET). + +Clear chan->ident for all matching channels on success, and harden the +failure path by using l2cap_chan_hold_unless_zero() consistent with +other L2CAP handlers (l2cap_le_command_rej, __l2cap_get_chan_by_ident). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 45e1e8192e3b63..f30624d20bb09c 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6432,14 +6432,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + + BT_DBG("result 0x%4.4x", result); + +- if (!result) ++ if (!result) { ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ if (chan->ident == cmd->ident) ++ chan->ident = 0; ++ } + return 0; ++ } + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + if (chan->ident != cmd->ident) + continue; + +- l2cap_chan_hold(chan); ++ if (!l2cap_chan_hold_unless_zero(chan)) ++ continue; + l2cap_chan_lock(chan); + + l2cap_chan_del(chan, ECONNRESET); +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch b/queue-5.10/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch new file mode 100644 index 0000000000..99a7242553 --- /dev/null +++ b/queue-5.10/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch @@ -0,0 +1,82 @@ +From 97edb9709a81e78c204c6860da277bb0d1ca6831 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 12:09:42 -0400 +Subject: Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp + +From: Luiz Augusto von Dentz + +[ Upstream commit 41c2713b204e6cb6a94587bc6bf6935107df5479 ] + +If dcid is received for an already-assigned destination CID the spec +requires that both channels to be discarded, but calling l2cap_chan_del +may invalidate the tmp cursor created by list_for_each_entry_safe and +in fact it is the wrong procedure as the chan->dcid may be assigned +previously it really needs to be disconnected. + +Calling l2cap_chan_clone directly may still lead to l2cap_chan_del so +instead schedule l2cap_chan_timeout with delay 0 to close the channel +asynchronously. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index f30624d20bb09c..89e770f359ef20 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6232,6 +6232,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct l2cap_chan *orig; + u16 dcid; + + if (chan->ident != cmd->ident || +@@ -6253,8 +6254,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + + BT_DBG("dcid[%d] 0x%4.4x", i, dcid); + ++ orig = __l2cap_get_chan_by_dcid(conn, dcid); ++ + /* Check if dcid is already in use */ +- if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { ++ if (dcid && orig) { + /* If a device receives a + * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an + * already-assigned Destination CID, then both the +@@ -6263,10 +6266,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + */ + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); +- chan = __l2cap_get_chan_by_dcid(conn, dcid); +- l2cap_chan_lock(chan); +- l2cap_chan_del(chan, ECONNRESET); +- l2cap_chan_unlock(chan); ++ ++ /* Check that the dcid channel mode is ++ * L2CAP_MODE_EXT_FLOWCTL since this procedure is only ++ * valid for that mode and shouldn't disconnect a dcid ++ * in other modes. ++ */ ++ if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) { ++ l2cap_chan_lock(orig); ++ /* Disconnect the original channel as it may be ++ * considered connected since dcid has already ++ * been assigned; don't call l2cap_chan_close ++ * directly since that could lead to ++ * l2cap_chan_del and then removing the channel ++ * from the list while we're iterating over it. ++ */ ++ __set_chan_timer(orig, 0); ++ l2cap_chan_unlock(orig); ++ } + continue; + } + +-- +2.53.0 + diff --git a/queue-5.10/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch b/queue-5.10/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch new file mode 100644 index 0000000000..c492073dd1 --- /dev/null +++ b/queue-5.10/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch @@ -0,0 +1,48 @@ +From 8387223e3a1ab5fa9a207ab58062fb01bcd83491 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 12:21:47 +0000 +Subject: ipv4: free net->ipv4.sysctl_local_reserved_ports after + unregister_net_sysctl_table() + +From: Eric Dumazet + +[ Upstream commit 87a1e0fe7776da7ab411be332b4be58ac8840d10 ] + +ipv4_sysctl_exit_net() is currently freeing net->ipv4.sysctl_local_reserved_ports +too soon. + +Only after unregister_net_sysctl_table() we can be sure no threads can possibly +use the sysctls, including /proc/sys/net/ipv4/ip_local_reserved_ports. + +Fixes: 122ff243f5f1 ("ipv4: make ip_local_reserved_ports per netns") +Reported-by: Ji'an Zhou +Signed-off-by: Eric Dumazet +Cc: Cong Wang +Reviewed-by: Jason Xing +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521122147.3584624-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/sysctl_net_ipv4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 59ba518a85b9c9..56c60af2a32f25 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -1362,10 +1362,10 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net) + { + struct ctl_table *table; + +- kfree(net->ipv4.sysctl_local_reserved_ports); + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); ++ kfree(net->ipv4.sysctl_local_reserved_ports); + } + + static __net_initdata struct pernet_operations ipv4_sysctl_ops = { +-- +2.53.0 + diff --git a/queue-5.10/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch b/queue-5.10/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch new file mode 100644 index 0000000000..57fc587fe3 --- /dev/null +++ b/queue-5.10/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch @@ -0,0 +1,62 @@ +From 7683b3ae63a7c9806a2d9fed11de389935ce74c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 21:10:31 +0530 +Subject: ipv6: rpl: fix hdrlen overflow in ipv6_rpl_srh_decompress() + +From: Rahul Chandelkar + +[ Upstream commit 9d5e7a46a9f6d8f503b41bfefef70659845f1679 ] + +ipv6_rpl_srh_decompress() computes: + + outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3); + +hdrlen is __u8. For n >= 127 the result exceeds 255 and silently +truncates. With n=127 (cmpri=15, cmpre=15, pad=0, hdrlen=16): + + (128 * 16) >> 3 = 256, truncated to 0 as __u8 + +The caller in ipv6_rpl_srh_rcv() then places the compressed header +at buf + ((ohdr->hdrlen + 1) << 3). With hdrlen=0 this is buf + 8, +but the decompressed region occupies buf[0..2055] (8-byte header +plus 128 full addresses). The compressed header overlaps the +decompressed data, and ipv6_rpl_srh_compress() writes into this +overlap, corrupting the routing header of the forwarded packet. + +The existing guard at exthdrs.c:546 checks (n + 1) > 255, which +prevents n+1 from overflowing unsigned char (the segments_left +field), but does not prevent the computed hdrlen from overflowing +__u8. n=127 passes because 128 <= 255, yet hdrlen=256 does not +fit. + +Tighten the bound to (n + 1) > 127. This caps n at 126, giving +hdrlen = (127 * 16) >> 3 = 254, which fits in __u8. The compressed +header then lands at buf + ((254 + 1) << 3) = buf + 2040, exactly +past the decompressed region (buf[0..2039]). No overlap. 127 +segments is well beyond any realistic RPL deployment. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Signed-off-by: Rahul Chandelkar +Link: https://patch.msgid.link/20260525154031.2290876-1-rc@rexion.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/exthdrs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 924f3d7901f09c..1bef03e2d8fc98 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -544,7 +544,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + * unsigned char which is segments_left field. Should not be + * higher than that. + */ +- if (r || (n + 1) > 255) { ++ if (r || (n + 1) > 127) { + kfree_skb(skb); + return -1; + } +-- +2.53.0 + diff --git a/queue-5.10/kernel-fork-validate-exit_signal-in-kernel_clone.patch b/queue-5.10/kernel-fork-validate-exit_signal-in-kernel_clone.patch new file mode 100644 index 0000000000..4c30f726b6 --- /dev/null +++ b/queue-5.10/kernel-fork-validate-exit_signal-in-kernel_clone.patch @@ -0,0 +1,116 @@ +From a0005d47f58bc6f93e86a11077474ff6486760e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 20:49:56 +0530 +Subject: kernel/fork: validate exit_signal in kernel_clone() + +From: Deepanshu Kartikey + +[ Upstream commit 09e7827e785729f391c8d46dc71becce70d296ab ] + +When a child process exits, it sends exit_signal to its parent via +do_notify_parent(). The clone() syscall constructs exit_signal as: + +(lower_32_bits(clone_flags) & CSIGNAL) + +CSIGNAL is 0xff, so values in the range 65-255 are possible. However, +valid_signal() only accepts signals up to _NSIG (64 on x86_64). A +non-zero non-valid exit_signal acts the same as exit_signal == 0: the +parent process is not signaled when the child terminates. + +The syzkaller reproducer triggers this by calling clone() with flags=0x80, +resulting in exit_signal = (0x80 & CSIGNAL) = 128, which exceeds _NSIG and +is not a valid signal. + +The v1 of this patch added the check only in the clone() syscall handler, +which is incomplete. kernel_clone() has other callers such as +sys_ia32_clone() which would remain unprotected. Move the check to +kernel_clone() to cover all callers. + +Since the valid_signal() check is now in kernel_clone() and covers all +callers including clone3(), the same check in copy_clone_args_from_user() +becomes redundant and is removed. The higher 32bits check for clone3() is +kept as it is clone3() specific. + +Note that this is a user-visible change: previously, passing an invalid +exit_signal to clone() was silently accepted. The man page for clone() +does not document any defined behavior for invalid exit_signal values, so +rejecting them with -EINVAL is the correct behavior. It is unlikely that +any sane application relies on passing an invalid exit_signal. + +[oleg@redhat.com: the comment above kernel_clone() should be updated] + Link: https://lore.kernel.org/abwvgU17W8wuW2-J@redhat.com +Link: https://lore.kernel.org/20260316151956.563558-1-kartikey406@gmail.com +Fixes: 3f2c788a1314 ("fork: prevent accidental access to clone3 features") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Oleg Nesterov +Reported-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=bbe6b99feefc3a0842de +Tested-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20260307064202.353405-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20260316104536.558108-1-kartikey406@gmail.com/T/ [v2] +Acked-by: Oleg Nesterov +Acked-by: Michal Hocko +Cc: Ben Segall +Cc: Christian Brauner +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Cc: Tetsuo Handa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 531de2d1b3bfeb..d35416380c6344 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -2535,8 +2535,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node) + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. +- * +- * args->exit_signal is expected to be checked for sanity by the caller. + */ + pid_t kernel_clone(struct kernel_clone_args *args) + { +@@ -2561,6 +2559,9 @@ pid_t kernel_clone(struct kernel_clone_args *args) + (args->pidfd == args->parent_tid)) + return -EINVAL; + ++ if (!valid_signal(args->exit_signal)) ++ return -EINVAL; ++ + /* + * Determine whether and which event to report to ptracer. When + * called from kernel_thread or CLONE_UNTRACED is explicitly +@@ -2737,11 +2738,9 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs, + return -EINVAL; + + /* +- * Verify that higher 32bits of exit_signal are unset and that +- * it is a valid signal ++ * Verify that higher 32bits of exit_signal are unset + */ +- if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) || +- !valid_signal(args.exit_signal))) ++ if (unlikely(args.exit_signal & ~((u64)CSIGNAL))) + return -EINVAL; + + if ((args.flags & CLONE_INTO_CGROUP) && +-- +2.53.0 + diff --git a/queue-5.10/net-iucv-fix-locking-in-.getsockopt.patch b/queue-5.10/net-iucv-fix-locking-in-.getsockopt.patch new file mode 100644 index 0000000000..9d6cebbe0c --- /dev/null +++ b/queue-5.10/net-iucv-fix-locking-in-.getsockopt.patch @@ -0,0 +1,87 @@ +From 200d1491cb96e9d7785abdab3eda2a5a4047d664 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 07:11:45 -0700 +Subject: net/iucv: fix locking in .getsockopt + +From: Breno Leitao + +[ Upstream commit 3589d20a666caf30ad100c960a2de7de390fce88 ] + +Mirror iucv_sock_setsockopt() and wrap the whole switch in +lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock +becomes redundant and is removed. + +Any AF_IUCV HIPER user can potentially crash the kernel by racing +recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences +iucv->hs_dev->mtu after iucv_sock_close() (called from the racing +recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference +oops. + +Suggested-by: Stanislav Fomichev +Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size") +Signed-off-by: Breno Leitao +Reviewed-by: Alexandra Winter +Tested-by: Alexandra Winter +Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/iucv/af_iucv.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index 3d0424e4ae6c9c..8c08f07ce46551 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1550,7 +1550,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + unsigned int val; +- int len; ++ int len, rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; +@@ -1563,26 +1563,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + + len = min_t(unsigned int, len, sizeof(int)); + ++ rc = 0; ++ ++ lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: +- lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ +- release_sock(sk); + break; + case SO_MSGSIZE: +- if (sk->sk_state == IUCV_OPEN) +- return -EBADFD; ++ if (sk->sk_state == IUCV_OPEN) { ++ rc = -EBADFD; ++ break; ++ } + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; + default: +- return -ENOPROTOOPT; ++ rc = -ENOPROTOOPT; ++ break; + } ++ release_sock(sk); ++ ++ if (rc) ++ return rc; + + if (put_user(len, optlen)) + return -EFAULT; +-- +2.53.0 + diff --git a/queue-5.10/net-netlink-don-t-set-nsid-on-local-notifications.patch b/queue-5.10/net-netlink-don-t-set-nsid-on-local-notifications.patch new file mode 100644 index 0000000000..6f2d0de171 --- /dev/null +++ b/queue-5.10/net-netlink-don-t-set-nsid-on-local-notifications.patch @@ -0,0 +1,82 @@ +From 6a11c8990d2307fb8af17ef7e5915d8464a1986a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:36 +0200 +Subject: net: netlink: don't set nsid on local notifications + +From: Ilya Maximets + +[ Upstream commit 88b126b39f9757e9debc322d4679239e9af089c7 ] + +In most cases, notifications on sockets with NETLINK_LISTEN_ALL_NSID +do not contain NSID in their ancillary data in case the event is local +to the listener. + +However, when a self-referential NSID is allocated for a namespace, +every local notification starts sending this ID to the user space. + +This is problematic, because the listener cannot tell if those +notifications are local or not anymore without making extra requests +to figure out if the provided NSID is local or not. The listener +can also not figure out the local NSID beforehand as it can be +allocated at any point in time by other processes, changing the +structure of the future notifications for everyone. + +The value is practically not useful, since it's the namespace's own +ID that the application has to obtain from other sources in order to +figure out if it's the same or not. So, for the application it's +just an extra busy work with no benefits. Moreover, applications +that do not know about this quirk may be mishandling notifications +with NSID set as notifications from remote namespaces. This is the +case for ovs-vswitchd and the iproute2's 'ip monitor' that stops +printing 'current' and starts printing the nsid number mid-session. + +Lack of clear documentation for this behavior is also not helping. + +A search though open-source projects doesn't reveal any projects +that use NETNSA_NSID_NOT_ASSIGNED and rely on metadata to contain +self-referential NSIDs (expected, since the value is not useful). +Quite the opposite, as already mentioned, there are few applications +that rely on NSID to not be present in local events. + +Since the value is not useful and actively harmful in some cases, +let's not report it for local events, making the notifications more +consistent. + +Also adding some blank lines for readability. + +Fixes: 59324cf35aba ("netlink: allow to listen "all" netns") +Reported-by: Matteo Perin +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-3-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index e8301a36926275..e091b65c9d2b8c 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1478,10 +1478,14 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ + NETLINK_CB(p->skb2).nsid_is_set = false; +- NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); +- if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) +- NETLINK_CB(p->skb2).nsid_is_set = true; ++ if (!net_eq(sock_net(sk), p->net)) { ++ NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); ++ if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) ++ NETLINK_CB(p->skb2).nsid_is_set = true; ++ } ++ + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { + netlink_overrun(sk); +-- +2.53.0 + diff --git a/queue-5.10/net-netlink-fix-sending-unassigned-nsid-after-assign.patch b/queue-5.10/net-netlink-fix-sending-unassigned-nsid-after-assign.patch new file mode 100644 index 0000000000..8f7876bfa0 --- /dev/null +++ b/queue-5.10/net-netlink-fix-sending-unassigned-nsid-after-assign.patch @@ -0,0 +1,45 @@ +From e1c9cea05f136a683f0b2f38c317ccfc608060f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:35 +0200 +Subject: net: netlink: fix sending unassigned nsid after assigned one + +From: Ilya Maximets + +[ Upstream commit 70f8592ee90585272018a725054b6eb2ab7e99ca ] + +If the current skb is not shared, it is re-used directly for all the +sockets subscribed to the notification. If we have remote all-nsid +socket receiving a message first, then the 'nsid_is_set' will be +set to 'true'. If the nsid is NOT_ASSIGNED for the next socket in +the list, the 'nsid_is_set' will remain 'true' and the negative value +is be delivered to the user space. All subsequent nsid values will be +delivered as well, since there is no code path that sets the flag +back to 'false'. + +Fix that by always dropping the flag to 'false' first. + +Fixes: 7212462fa6fd ("netlink: don't send unknown nsid") +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-2-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 42b7b8574f0994..e8301a36926275 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1478,6 +1478,7 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ NETLINK_CB(p->skb2).nsid_is_set = false; + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) + NETLINK_CB(p->skb2).nsid_is_set = true; +-- +2.53.0 + diff --git a/queue-5.10/net-sched-revert-net-sched-restrict-conditions-for-a.patch b/queue-5.10/net-sched-revert-net-sched-restrict-conditions-for-a.patch new file mode 100644 index 0000000000..b70abc07ea --- /dev/null +++ b/queue-5.10/net-sched-revert-net-sched-restrict-conditions-for-a.patch @@ -0,0 +1,102 @@ +From 6108f7bd8568b3eef23632da7db59c43bbbd6681 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:49 -0400 +Subject: net/sched: Revert "net/sched: Restrict conditions for adding + duplicating netems to qdisc tree" + +From: Jamal Hadi Salim + +[ Upstream commit eda0b7f203bb166c98d1418b204135bd566ac83b ] + +This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. + +The original patch rejects any tree containing two netems when +either has duplication set, even when they sit on unrelated classes +of the same classful parent. That broke configurations that have +worked since netem was introduced. + +The re-entrancy problem the original commit was trying to solve is +handled by later patch using tc_depth flag. + +Doing this revert will (re)expose the original bug with multiple +netem duplication. When this patch is backported make sure +and get the full series. + +Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") +Reported-by: Ji-Soo Chung +Reported-by: Gerlinde +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 +Reported-by: zyc zyc +Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ +Reported-by: Manas Ghandat +Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 40 ---------------------------------------- + 1 file changed, 40 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 3e3bced82c564d..3dc6411b0a33c7 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -985,41 +985,6 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, + return 0; + } + +-static const struct Qdisc_class_ops netem_class_ops; +- +-static int check_netem_in_tree(struct Qdisc *sch, bool duplicates, +- struct netlink_ext_ack *extack) +-{ +- struct Qdisc *root, *q; +- unsigned int i; +- +- root = qdisc_root_sleeping(sch); +- +- if (sch != root && root->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(root))->duplicate) +- goto err; +- } +- +- if (!qdisc_dev(root)) +- return 0; +- +- hash_for_each(qdisc_dev(root)->qdisc_hash, i, q, hash) { +- if (sch != q && q->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(q))->duplicate) +- goto err; +- } +- } +- +- return 0; +- +-err: +- NL_SET_ERR_MSG(extack, +- "netem: cannot mix duplicating netems with other netems in tree"); +- return -EINVAL; +-} +- + /* Parse netlink message to set options */ + static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +@@ -1087,11 +1052,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + q->gap = qopt->gap; + q->counter = 0; + q->loss = qopt->loss; +- +- ret = check_netem_in_tree(sch, qopt->duplicate, extack); +- if (ret) +- goto unlock; +- + q->duplicate = qopt->duplicate; + + /* for compatibility with earlier versions. +-- +2.53.0 + diff --git a/queue-5.10/net-smc-do-not-re-initialize-smc-hashtables.patch b/queue-5.10/net-smc-do-not-re-initialize-smc-hashtables.patch new file mode 100644 index 0000000000..e8b00e5bfd --- /dev/null +++ b/queue-5.10/net-smc-do-not-re-initialize-smc-hashtables.patch @@ -0,0 +1,59 @@ +From c7d3001ab6725bfcfb1afea386cd399ac7757355 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 16:56:39 +0200 +Subject: net/smc: Do not re-initialize smc hashtables + +From: Alexandra Winter + +[ Upstream commit 9e4389b0038781f19f97895186ed941ff8ac1678 ] + +INIT_HLIST_HEAD(&smc_v*_hashinfo.ht) are called after smc_nl_init(), +proto_register() and sock_register(). This can lead to smc_v*_hashinfo.ht +being reset even though hash entries already exist and are being used, +possibly resulting in a corrupted list. + +Remove unnecessary and dangerous re-initialisation of smc_v*_hashinfo.ht in +smc_init(); it is implicitly initialised to zero anyhow. Add +HLIST_HEAD_INIT to the definitions for clarity. + +Fixes: f16a7dd5cf27 ("smc: netlink interface for SMC sockets") +Suggested-by: Halil Pasic +Signed-off-by: Alexandra Winter +Acked-by: Halil Pasic +Reviewed-by: Mahanta Jambigi +Link: https://patch.msgid.link/20260521145639.10317-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index d64cfd651c7a16..8e1e38bc0df4b0 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -71,10 +71,12 @@ static void smc_set_keepalive(struct sock *sk, int val) + + static struct smc_hashinfo smc_v4_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + static struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + int smc_hash_sk(struct sock *sk) +@@ -2586,8 +2588,6 @@ static int __init smc_init(void) + pr_err("%s: sock_register fails with %d\n", __func__, rc); + goto out_proto6; + } +- INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); +- INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); + + rc = smc_ib_register_client(); + if (rc) { +-- +2.53.0 + diff --git a/queue-5.10/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch b/queue-5.10/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch new file mode 100644 index 0000000000..f3a4a27b11 --- /dev/null +++ b/queue-5.10/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch @@ -0,0 +1,107 @@ +From 726842b11ce35b013de3eccf92eb12f6977b88d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 22:52:07 +0200 +Subject: netfilter: ebtables: fix OOB read in compat_mtw_from_user + +From: Florian Westphal + +[ Upstream commit f438d1786d657d57790c5d138d6db3fc9fdac392 ] + +Luxiao Xu says: + + The function compat_mtw_from_user() converts ebtables extensions from + 32-bit user structures to kernel native structures. However, it lacks + proper validation of the user-supplied match_size/target_size. + + When certain extensions are processed, the kernel-side translation + logic may perform memory accesses based on the extension's expected + size. If the user provides a size smaller than what the extension + requires, it results in an out-of-bounds read as reported by KASAN. + + This fix introduces a check to ensure match_size is at least as large + as the extension's required compatsize. This covers matches, watchers, + and targets, while maintaining compatibility with standard targets. + +AFAIU this is relevant for matches that need to go though +match->compat_from_user() call. Those that use plain memcpy with the +user-provided size are ok because the caller checks that size vs the +start of the next rule entry offset (which itself is checked vs. total +size copied from userspace). + +The ->compat_from_user() callbacks assume they can read compatsize bytes, +so they need this extra check. + +Based on an earlier patch from Luxiao Xu. + +Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 14a06d8b1a2d0e..e86695f1ed95b6 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1838,6 +1838,25 @@ enum compat_mwt { + EBT_COMPAT_TARGET, + }; + ++static bool match_size_ok(const struct xt_match *match, unsigned int match_size) ++{ ++ u16 csize; ++ ++ if (match->matchsize == -1) /* cannot validate ebt_among */ ++ return true; ++ ++ csize = match->compatsize ? : match->matchsize; ++ ++ return match_size >= csize; ++} ++ ++static bool tgt_size_ok(const struct xt_target *tgt, unsigned int tgt_size) ++{ ++ u16 csize = tgt->compatsize ? : tgt->targetsize; ++ ++ return tgt_size >= csize; ++} ++ + static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + enum compat_mwt compat_mwt, + struct ebt_entries_buf_state *state, +@@ -1863,6 +1882,11 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + if (IS_ERR(match)) + return PTR_ERR(match); + ++ if (!match_size_ok(match, match_size)) { ++ module_put(match->me); ++ return -EINVAL; ++ } ++ + off = ebt_compat_match_offset(match, match_size); + if (dst) { + if (match->compat_from_user) +@@ -1882,6 +1906,12 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + mwt->u.revision); + if (IS_ERR(wt)) + return PTR_ERR(wt); ++ ++ if (!tgt_size_ok(wt, match_size)) { ++ module_put(wt->me); ++ return -EINVAL; ++ } ++ + off = xt_compat_target_offset(wt); + + if (dst) { +-- +2.53.0 + diff --git a/queue-5.10/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch b/queue-5.10/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch new file mode 100644 index 0000000000..3ffe854198 --- /dev/null +++ b/queue-5.10/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch @@ -0,0 +1,68 @@ +From a423456ef8237a1b0351d7014b8346e020b59428 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 12:36:14 -0700 +Subject: netfilter: synproxy: refresh tcphdr after skb_ensure_writable + +From: Chris Mason + +[ Upstream commit 92170e6afe927ab2792a3f71902845789c8e31b1 ] + +synproxy_tstamp_adjust() rewrites the TCP timestamp option in place +and then patches the TCP checksum via inet_proto_csum_replace4() on +the caller-supplied tcphdr pointer. Both ipv4_synproxy_hook() and +ipv6_synproxy_hook() obtain that pointer with skb_header_pointer() +before calling in, so it may either alias skb->head directly or +point at the caller's on-stack _tcph buffer. + +Between obtaining the pointer and using it, the function calls +skb_ensure_writable(skb, optend), which on a cloned or non-linear +skb invokes pskb_expand_head() and frees the old skb->head. After +that point the cached th is stale: + + caller (ipv[46]_synproxy_hook) + th = skb_header_pointer(skb, ..., &_tcph) + synproxy_tstamp_adjust(skb, protoff, th, ...) + skb_ensure_writable(skb, optend) + pskb_expand_head() /* kfree(old skb->head) */ + ... + inet_proto_csum_replace4(&th->check, ...) + /* writes into freed head, or + into the caller's stack copy + leaving the on-wire checksum + stale */ + +The option bytes are written through skb->data and are fine; only +the checksum update goes through th and so lands in the wrong +place. The result is either a write into freed slab memory or a +packet leaving with a checksum that does not match its payload. + +Fix by re-deriving th from skb->data + protoff immediately after +skb_ensure_writable() succeeds, so the subsequent checksum update +targets the linear, writable header. + +Fixes: 48b1de4c110a ("netfilter: add SYNPROXY core/target") +Assisted-by: kres (claude-opus-4-7) +Signed-off-by: Chris Mason +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 2dfc5dae065638..0a97b1a0f53e45 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -199,6 +199,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + if (skb_ensure_writable(skb, optend)) + return 0; + ++ th = (struct tcphdr *)(skb->data + protoff); ++ + while (optoff < optend) { + unsigned char *op = skb->data + optoff; + +-- +2.53.0 + diff --git a/queue-5.10/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch b/queue-5.10/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..a92e3a831a --- /dev/null +++ b/queue-5.10/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch @@ -0,0 +1,48 @@ +From b0a577765533a520b2c41a8309930711a56a96f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 20:10:08 +0200 +Subject: netfilter: xt_cpu: prefer raw_smp_processor_id + +From: Florian Westphal + +[ Upstream commit c376f07e16c02239ed44cabb97145d03f65b4d15 ] + +With PREEMPT_RCU we get splat: + +BUG: using smp_processor_id() in preemptible [..] +caller is cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 +CPU: 1 .. Comm: syz.3.1377 #0 PREEMPT(full) +Call Trace: + + dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 + check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 + cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 + [..] + +Just use raw version instead. +This is similar to 14d14a5d2957 ("netfilter: nft_meta: use raw_smp_processor_id()"). + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reported-by: syzbot+690d3e3ffa7335ac10eb@syzkaller.appspotmail.com +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c +index 3bdc302a0f9137..9cb259902a586b 100644 +--- a/net/netfilter/xt_cpu.c ++++ b/net/netfilter/xt_cpu.c +@@ -34,7 +34,7 @@ static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_cpu_info *info = par->matchinfo; + +- return (info->cpu == smp_processor_id()) ^ info->invert; ++ return (info->cpu == raw_smp_processor_id()) ^ info->invert; + } + + static struct xt_match cpu_mt_reg __read_mostly = { +-- +2.53.0 + diff --git a/queue-5.10/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch b/queue-5.10/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch new file mode 100644 index 0000000000..51abcfa670 --- /dev/null +++ b/queue-5.10/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch @@ -0,0 +1,40 @@ +From 2e53644607b94bed67568d7d64845dc3525c39ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:41 +0000 +Subject: nfc: llcp: Fix use-after-free in llcp_sock_release() + +From: Lee Jones + +[ Upstream commit f4268b466190dae95a7585f69b4f1f8ad097632c ] + +llcp_sock_release() unconditionally unlinks the socket from the local +sockets list. However, if the socket is still in connecting state, it +is on the connecting list. + +Fix this by checking the socket state and unlinking from the correct list. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Signed-off-by: Lee Jones +Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index dc96d751eb278f..57dea580c02912 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -628,6 +628,8 @@ static int llcp_sock_release(struct socket *sock) + + if (sock->type == SOCK_RAW) + nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else if (sk->sk_state == LLCP_CONNECTING) ++ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + else + nfc_llcp_sock_unlink(&local->sockets, sk); + +-- +2.53.0 + diff --git a/queue-5.10/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch b/queue-5.10/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch new file mode 100644 index 0000000000..f04dd3a778 --- /dev/null +++ b/queue-5.10/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch @@ -0,0 +1,67 @@ +From 22e49b9395b9e8ee28179cd4097f4c14c6bc9d1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:42 +0000 +Subject: nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() + +From: Lee Jones + +[ Upstream commit b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 ] + +A race condition exists in the NFC LLCP connection state machine where +the connection acceptance packet (CC) can be processed concurrently with +socket release. This can lead to a use-after-free of the socket object. + +When nfc_llcp_recv_cc() moves the socket from the connecting_sockets +list to the sockets list, it does so without holding the socket lock. +If llcp_sock_release() is executing concurrently, it might have already +unlinked the socket and dropped its references, which can result in +nfc_llcp_recv_cc() linking a freed socket into the live list. + +Fix this by holding lock_sock() during the state transition and list +movement in nfc_llcp_recv_cc(). After acquiring the lock, check if +the socket is still hashed to ensure it hasn't already been unlinked +and marked for destruction by the release path. This aligns the locking +pattern with recv_hdlc() and recv_disc(). + +Fixes: a69f32af86e3 ("NFC: Socket linked list") +Signed-off-by: Lee Jones +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index e04634f22b49f4..c7de44637e0187 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -1225,6 +1225,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + + sk = &llcp_sock->sk; + ++ lock_sock(sk); ++ ++ /* Check if socket was destroyed whilst waiting for the lock */ ++ if (!sk_hashed(sk)) { ++ release_sock(sk); ++ nfc_llcp_sock_put(llcp_sock); ++ return; ++ } ++ + /* Unlink from connecting and link to the client array */ + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + nfc_llcp_sock_link(&local->sockets, sk); +@@ -1236,6 +1245,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + ++ release_sock(sk); ++ + nfc_llcp_sock_put(llcp_sock); + } + +-- +2.53.0 + diff --git a/queue-5.10/nfc-llcp-protect-nfc_llcp_sock_unlink-calls.patch b/queue-5.10/nfc-llcp-protect-nfc_llcp_sock_unlink-calls.patch new file mode 100644 index 0000000000..5cf14bd2ed --- /dev/null +++ b/queue-5.10/nfc-llcp-protect-nfc_llcp_sock_unlink-calls.patch @@ -0,0 +1,53 @@ +From f10f48b7faffd49b71f57136c74e78144f3c2f18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Mar 2022 20:25:22 +0100 +Subject: nfc: llcp: protect nfc_llcp_sock_unlink() calls + +From: Krzysztof Kozlowski + +[ Upstream commit a06b8044169f6d5c3eb34772c13d2c0c1b205352 ] + +nfc_llcp_sock_link() is called in all paths (bind/connect) as a last +action, still protected with lock_sock(). When cleaning up in +llcp_sock_release(), call nfc_llcp_sock_unlink() in a mirrored way: +earlier and still under the lock_sock(). + +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: David S. Miller +Stable-dep-of: f4268b466190 ("nfc: llcp: Fix use-after-free in llcp_sock_release()") +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index 6e1fba2084930e..dc96d751eb278f 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -626,6 +626,11 @@ static int llcp_sock_release(struct socket *sock) + } + } + ++ if (sock->type == SOCK_RAW) ++ nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else ++ nfc_llcp_sock_unlink(&local->sockets, sk); ++ + if (llcp_sock->reserved_ssap < LLCP_SAP_MAX) + nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); + +@@ -638,11 +643,6 @@ static int llcp_sock_release(struct socket *sock) + if (sk->sk_state == LLCP_DISCONNECTING) + return err; + +- if (sock->type == SOCK_RAW) +- nfc_llcp_sock_unlink(&local->raw_sockets, sk); +- else +- nfc_llcp_sock_unlink(&local->sockets, sk); +- + out: + sock_orphan(sk); + sock_put(sk); +-- +2.53.0 + diff --git a/queue-5.10/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch b/queue-5.10/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch new file mode 100644 index 0000000000..8df818fb9b --- /dev/null +++ b/queue-5.10/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch @@ -0,0 +1,83 @@ +From 38f6064f86d9a5679bd76961f4f70c45327d83f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 May 2026 19:55:18 +0800 +Subject: nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems + +From: Carl Lee + +[ Upstream commit f23bf992d65a42007c517b060ca35cebdea3525a ] + +Some ACPI-based platforms report incorrect IRQ trigger types (e.g. +IRQF_TRIGGER_HIGH), which can lead to interrupt storms. + +Use the historically working rising-edge trigger on ACPI systems to +avoid this regression. + +Device Tree-based systems continue to use the firmware-provided +trigger type. + +Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") +Signed-off-by: Carl Lee +Tested-by: Bartosz Golaszewski +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Mark Pearson +Tested-by: Mark Pearson +Tested-by: Luca Stefani +Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index 237b344a30bbd8..989b4a0e5b1982 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -268,6 +269,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client, + { + struct device *dev = &client->dev; + struct nxp_nci_i2c_phy *phy; ++ unsigned long irqflags; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +@@ -304,9 +306,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client, + if (r < 0) + return r; + ++ /* ++ * ACPI platforms may report incorrect IRQ trigger types ++ * (e.g. level-high), which can lead to interrupt storms. ++ * ++ * Use the historically stable rising-edge trigger for ACPI devices. ++ * ++ * On non-ACPI systems (e.g. Device Tree), prefer the firmware- ++ * provided trigger type, falling back to rising-edge if not set. ++ */ ++ if (ACPI_COMPANION(dev)) { ++ irqflags = IRQF_TRIGGER_RISING; ++ } else { ++ irqflags = irq_get_trigger_type(client->irq); ++ if (!irqflags) ++ irqflags = IRQF_TRIGGER_RISING; ++ } ++ + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, +- IRQF_ONESHOT, ++ irqflags | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); +-- +2.53.0 + diff --git a/queue-5.10/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch b/queue-5.10/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch new file mode 100644 index 0000000000..b7d66f9195 --- /dev/null +++ b/queue-5.10/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch @@ -0,0 +1,50 @@ +From 19ad278c66758b38a247e8ae918b93d14526c765 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 11:24:11 +0800 +Subject: sctp: fix race between sctp_wait_for_connect and peeloff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit f14fe6395a8b3d961a61e138ad7b36ba3626dd4e ] + +sctp_wait_for_connect() drops and re-acquires the socket lock while +waiting for the association to reach ESTABLISHED state. During this +window, another thread can peeloff the association to a new socket via +getsockopt(SCTP_SOCKOPT_PEELOFF), changing asoc->base.sk. After +re-acquiring the old socket lock, sctp_wait_for_connect() returns +success without noticing the migration — the caller then accesses +the association under the wrong lock in sctp_datamsg_from_user(). + +Add the same sk != asoc->base.sk check that sctp_wait_for_sndbuf() +already has, returning an error if the association was migrated while +we slept. + +Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") +Signed-off-by: Zhenghang Xiao +Acked-by: Xin Long +Link: https://patch.msgid.link/20260527032411.60959-1-kipreyyy@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 8c7bdf01e32a17..150235d861411d 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9133,6 +9133,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) + release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + + *timeo_p = current_timeo; + } +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index f27a9a696b..c4aa23cf6e 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -2,3 +2,28 @@ alsa-usb-audio-fix-null-pointer-dereference-on-point.patch net-sched-cls_fw-fix-null-dereference-of-old-filters.patch phy-renesas-rcar-gen3-usb2-fix-the-use-of-msleep-dur.patch net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch +nfc-llcp-protect-nfc_llcp_sock_unlink-calls.patch +nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch +nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch +xfrm-check-for-underflow-in-xfrm_state_mtu.patch +nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch +kernel-fork-validate-exit_signal-in-kernel_clone.patch +netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch +netfilter-xt_cpu-prefer-raw_smp_processor_id.patch +netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch +tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch +net-netlink-fix-sending-unassigned-nsid-after-assign.patch +net-netlink-don-t-set-nsid-on-local-notifications.patch +net-smc-do-not-re-initialize-smc-hashtables.patch +net-iucv-fix-locking-in-.getsockopt.patch +ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch +asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch +tunnels-load-network-headers-after-skb_cow-in-iptunn.patch +vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch +tunnels-do-not-assume-transport-header-in-iptunnel_p.patch +bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch +ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch +net-sched-revert-net-sched-restrict-conditions-for-a.patch +bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch +bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch +sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch diff --git a/queue-5.10/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch b/queue-5.10/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch new file mode 100644 index 0000000000..1424eef938 --- /dev/null +++ b/queue-5.10/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch @@ -0,0 +1,54 @@ +From df2478f5320d5c625cdb8ee9859c75537f567e6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:00:21 -0700 +Subject: tun: free page on short-frame rejection in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit f4feb1e20058e407cb00f45aff47f5b7e19a6bbf ] + +tun_xdp_one() returns -EINVAL on a frame shorter than ETH_HLEN without +freeing the page that vhost_net_build_xdp() allocated for it. +tun_sendmsg() discards that -EINVAL and still returns total_len, so +vhost_tx_batch() takes the success path and never frees the page; each +short frame in a batch leaks one page-frag chunk. + +A local process that can open /dev/net/tun and /dev/vhost-net can hit +this path: it attaches a tun/tap device as the vhost-net backend and +feeds TX descriptors whose length minus the virtio-net header is below +ETH_HLEN. Each kick leaks the page-frag chunks for that batch, and a +tight submission loop exhausts host memory and triggers an OOM panic. +Free the page before returning -EINVAL, matching the XDP-program error +path in the same function. + +Fixes: 049584807f1d ("tun: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260520160020.375349-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 3a89f9457fa242..930086d79f97c8 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2472,8 +2472,10 @@ static int tun_xdp_one(struct tun_struct *tun, + bool skb_xdp = false; + struct page *page; + +- if (unlikely(datasize < ETH_HLEN)) ++ if (unlikely(datasize < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + return -EINVAL; ++ } + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { +-- +2.53.0 + diff --git a/queue-5.10/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch b/queue-5.10/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch new file mode 100644 index 0000000000..daefb91b77 --- /dev/null +++ b/queue-5.10/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch @@ -0,0 +1,67 @@ +From b1d31f837a05d19b580fbd4d11ad8b16c23ae3da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 11:55:12 +0000 +Subject: tunnels: do not assume transport header in + iptunnel_pmtud_check_icmp() + +From: Eric Dumazet + +[ Upstream commit 509323077ef79a26ba0c60bb556e45c12c398b2d ] + +In some cases, iptunnel_pmtud_check_icmp() can be called while +skb transport header is not set. + +This triggers an out-of-bound access, because +(typeof(skb->transport_header))~0U is 65535. + +Access the icmp header based on IPv4 network header, +after making sure icmp->type is present in skb linear part. + +Note that iptunnel_pmtud_check_icmpv6()) is fine. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Reported-by: Damiano Melotti +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 05c7bb78fe96f0..712555c56a1836 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -262,7 +262,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + { +- const struct icmphdr *icmph = icmp_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); + + if (mtu < 576 || iph->frag_off != htons(IP_DF)) +@@ -273,9 +272,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr)) + return 0; + +- if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type)) +- return 0; ++ if (iph->protocol == IPPROTO_ICMP) { ++ const struct icmphdr *icmph; + ++ if (!pskb_network_may_pull(skb, iph->ihl * 4 + ++ offsetofend(struct icmphdr, type))) ++ return 0; ++ iph = ip_hdr(skb); ++ icmph = (void *)iph + iph->ihl * 4; ++ if (icmp_is_err(icmph->type)) ++ return 0; ++ } + return iptunnel_pmtud_build_icmp(skb, mtu); + } + +-- +2.53.0 + diff --git a/queue-5.10/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch b/queue-5.10/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch new file mode 100644 index 0000000000..c8ea3755da --- /dev/null +++ b/queue-5.10/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch @@ -0,0 +1,87 @@ +From 104f0ec2a40c4cb7e2488e0b61727ba290002e30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +From: Eric Dumazet + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 3cdb546dbc8d71..05c7bb78fe96f0 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -208,7 +208,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -218,7 +217,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -290,7 +289,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -305,7 +304,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -316,6 +314,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.53.0 + diff --git a/queue-5.10/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch b/queue-5.10/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch new file mode 100644 index 0000000000..fa838b102c --- /dev/null +++ b/queue-5.10/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch @@ -0,0 +1,54 @@ +From 5d7a85504c75a4d224003957fc78eea9483778e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:36:42 +0000 +Subject: vxlan: do not reuse cached ip_hdr() value after + skb_tunnel_check_pmtu() + +From: Eric Dumazet + +[ Upstream commit 7d9ef0cb271555d8cf39fefe6c981e1493b25ecf ] + +skb_tunnel_check_pmtu() can change skb->head. + +Reusing old_iph afer skb_tunnel_check_pmtu() can cause an UAF. + +Use instead ip_hdr(skb) as done in drivers/net/bareudp.c +and drivers/net/geneve.c. + +Found by Sashiko. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525203642.2389723-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index 5e5dfa9579d3aa..053cc74bd904f8 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2752,7 +2752,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), + vni, md, flags, udp_sum); +@@ -2815,7 +2815,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip6_dst_hoplimit(ndst); + skb_scrub_packet(skb, xnet); + err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), +-- +2.53.0 + diff --git a/queue-5.10/xfrm-check-for-underflow-in-xfrm_state_mtu.patch b/queue-5.10/xfrm-check-for-underflow-in-xfrm_state_mtu.patch new file mode 100644 index 0000000000..919142f905 --- /dev/null +++ b/queue-5.10/xfrm-check-for-underflow-in-xfrm_state_mtu.patch @@ -0,0 +1,85 @@ +From 6ca4502d79e333e839a77e9c00308b99bf3d9ba3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 10:49:14 -0600 +Subject: xfrm: Check for underflow in xfrm_state_mtu + +From: David Ahern + +[ Upstream commit 742b04d0550b0ec89dcbc99537ec88653bd1ad90 ] + +Leo Lin reported OOB write issue in esp component: + + xfrm_state_mtu() returns u32 but performs its arithmetic in unsigned + modulo-2^32 space using an attacker-influenced "header_len + authsize + + net_adj" subtracted from a small "mtu" argument. A nobody user can + install an IPv4 ESP tunnel SA with a large authentication key + (XFRMA_ALG_AUTH_TRUNC, e.g. hmac(sha512), 64-byte key, 64-byte trunc), + configure a small interface MTU (68 bytes), and set XFRMA_TFCPAD to a + large value. When a single UDP datagram is then sent through the + tunnel, xfrm_state_mtu() underflows to a near-2^32 value, and + esp_output() consumes it as a signed int via: + + padto = min(x->tfcpad, xfrm_state_mtu(x, mtu_cached)) + esp.tfclen = padto - skb->len (assigned to int) + + esp.tfclen ends up negative (e.g. -207). It is sign-extended to size_t + when passed to memset() inside esp_output_fill_trailer(), producing a + ~16 EB write of zeroes at skb_tail_pointer(skb). KASAN logs it as + "Write of size 18446744073709551537 at addr ffff888...". + +Check for underflow and return 1. This causes the sendmsg attempt to +fail with ENETUNREACH. + +Fixes: c5c252389374 ("[XFRM]: Optimize MTU calculation") +Reported-by: Leo Lin +Assisted-by: Codex:26.506.31004 +Signed-off-by: David Ahern +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_state.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index 02d1d8d1fdea40..5f407f4f8eee7a 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -2549,10 +2549,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + const struct xfrm_type *type = READ_ONCE(x->type); + struct crypto_aead *aead; + u32 blksize, net_adj = 0; ++ u32 overhead, payload_mtu; + + if (x->km.state != XFRM_STATE_VALID || +- !type || type->proto != IPPROTO_ESP) ++ !type || type->proto != IPPROTO_ESP) { ++ if (mtu <= x->props.header_len) ++ return 1; + return mtu - x->props.header_len; ++ } + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); +@@ -2572,8 +2576,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + break; + } + +- return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - +- net_adj) & ~(blksize - 1)) + net_adj - 2; ++ overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj; ++ if (mtu <= overhead) ++ return 1; ++ ++ payload_mtu = mtu - overhead; ++ payload_mtu &= ~(blksize - 1); ++ if (payload_mtu <= 2) ++ return 1; ++ ++ return payload_mtu + net_adj - 2; ++ + } + EXPORT_SYMBOL_GPL(xfrm_state_mtu); + +-- +2.53.0 + diff --git a/queue-5.15/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch b/queue-5.15/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch new file mode 100644 index 0000000000..ba64f28c5a --- /dev/null +++ b/queue-5.15/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch @@ -0,0 +1,47 @@ +From 5215ae9a41b85629ca1fa2761ed7d70b5ffd1247 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 09:24:00 -0300 +Subject: ASoC: codecs: simple-mux: Fix enum control bounds check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit f63ad68e18d774a5d15cd7e405ead63f6b322679 ] + +simple_mux_control_put() rejects values greater than e->items, but +enum control values are zero based. For the two-entry mux used by this +driver, valid values are 0 and 1, so value 2 must be rejected as well. + +Accepting e->items can store an invalid mux state, pass it to the GPIO +setter, and pass it on to the DAPM mux update path where it is used as +an index into the enum text array. + +Use the same >= e->items check used by the ASoC enum helpers. + +Fixes: 342fbb7578d1 ("ASoC: add simple-mux") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260527-asoc-simple-mux-enum-bounds-v1-1-3f805b9fc671@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/simple-mux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c +index e0a09dadfa7cf0..344bc61b9dc26a 100644 +--- a/sound/soc/codecs/simple-mux.c ++++ b/sound/soc/codecs/simple-mux.c +@@ -40,7 +40,7 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + +- if (ucontrol->value.enumerated.item[0] > e->items) ++ if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + if (priv->mux == ucontrol->value.enumerated.item[0]) +-- +2.53.0 + diff --git a/queue-5.15/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch b/queue-5.15/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch new file mode 100644 index 0000000000..8059dd4de0 --- /dev/null +++ b/queue-5.15/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch @@ -0,0 +1,112 @@ +From ca7ba65fe7ca81e0707eebe2bbc9c70d09349e9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 13:51:47 -0300 +Subject: ASoC: Intel: bytcht_es8316: Fix MCLK leak on init errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit afb2a3a9d8369d18122a0d7cd294eba9a98259c6 ] + +byt_cht_es8316_init() enables MCLK before configuring the codec sysclk +and creating the headset jack. If either of those later steps fails, the +function returns without disabling MCLK, leaving the clock enabled after +card registration fails. + +Track whether this driver enabled MCLK and disable it on the init error +paths. Add the matching DAI link exit callback so the same clock enable +is also balanced when ASoC cleans up a successfully initialized link. + +Fixes: a03bdaa565cb ("ASoC: Intel: add machine driver for BYT/CHT + ES8316") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-asoc-bytcht-es8316-mclk-leak-v1-1-b4a11cdc2afd@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_es8316.c | 29 ++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index 923e69c7695c29..d54bc667175f50 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -39,6 +39,7 @@ struct byt_cht_es8316_private { + struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; + bool speaker_en; ++ bool mclk_enabled; + }; + + enum { +@@ -169,6 +170,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + }, + }; + ++static void byt_cht_es8316_disable_mclk(struct byt_cht_es8316_private *priv) ++{ ++ if (!priv->mclk_enabled) ++ return; ++ ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++} ++ + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + { + struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component; +@@ -225,12 +235,14 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); ++ else ++ priv->mclk_enabled = true; + + ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + ret = snd_soc_card_jack_new(card, "Headset", +@@ -239,13 +251,25 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; ++ ++err_disable_mclk: ++ byt_cht_es8316_disable_mclk(priv); ++ return ret; ++} ++ ++static void byt_cht_es8316_exit(struct snd_soc_pcm_runtime *runtime) ++{ ++ struct snd_soc_card *card = runtime->card; ++ struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); ++ ++ byt_cht_es8316_disable_mclk(priv); + } + + static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -355,6 +379,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, ++ .exit = byt_cht_es8316_exit, + SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), + }, + }; +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch b/queue-5.15/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch new file mode 100644 index 0000000000..b8c800b3f7 --- /dev/null +++ b/queue-5.15/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch @@ -0,0 +1,40 @@ +From dcf2ae8fc417a0f33b793bdc44d2146907b40e58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 11:21:39 +0800 +Subject: Bluetooth: 6lowpan: check skb_clone() return value in + send_mcast_pkt() + +From: Zhao Dongdong + +[ Upstream commit 3c40d381ce04f9575a5d8b542898183c3b4b38dc ] + +The skb_clone() function can return NULL if memory allocation fails. +send_mcast_pkt() calls skb_clone() without checking the return value, which +can lead to a NULL pointer dereference in send_pkt() when it dereferences +skb->data. +Add a NULL check after skb_clone() and skip the peer if the clone fails. + +Fixes: 18722c247023 ("Bluetooth: Enable 6LoWPAN support for BT LE devices") +Signed-off-by: Zhao Dongdong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/6lowpan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index b70d3a38fdedc1..26bc594182ea08 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -485,6 +485,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) + int ret; + + local_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!local_skb) ++ continue; + + BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p", + netdev->name, +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch b/queue-5.15/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch new file mode 100644 index 0000000000..29e3a7c4d6 --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch @@ -0,0 +1,62 @@ +From 88b80890252e34db534c76091b0327a9044aa673 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:51:52 +0800 +Subject: Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success + +From: Zhenghang Xiao + +[ Upstream commit 00e1950716c6ed67d74777b2db286b0fa23b4be9 ] + +l2cap_ecred_reconf_rsp() returns early on success without clearing +chan->ident. Every other L2CAP response handler (l2cap_ecred_conn_rsp, +l2cap_le_connect_rsp, l2cap_config_rsp) clears chan->ident after a +successful transaction to prevent the channel from matching subsequent +responses with the recycled ident value. + +A remote attacker that completed a reconfiguration as the peer can +replay a failure response with the stale ident, causing the kernel to +match and destroy the already-established channel via +l2cap_chan_del(chan, ECONNRESET). + +Clear chan->ident for all matching channels on success, and harden the +failure path by using l2cap_chan_hold_unless_zero() consistent with +other L2CAP handlers (l2cap_le_command_rej, __l2cap_get_chan_by_ident). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index a5db427c13de20..7e3825c1b10b95 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6422,14 +6422,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + + BT_DBG("result 0x%4.4x", result); + +- if (!result) ++ if (!result) { ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ if (chan->ident == cmd->ident) ++ chan->ident = 0; ++ } + return 0; ++ } + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + if (chan->ident != cmd->ident) + continue; + +- l2cap_chan_hold(chan); ++ if (!l2cap_chan_hold_unless_zero(chan)) ++ continue; + l2cap_chan_lock(chan); + + l2cap_chan_del(chan, ECONNRESET); +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch b/queue-5.15/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch new file mode 100644 index 0000000000..16bc06b81e --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch @@ -0,0 +1,82 @@ +From 393ffffe6c1927eb8f839bcd3400df8ec5d105fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 12:09:42 -0400 +Subject: Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp + +From: Luiz Augusto von Dentz + +[ Upstream commit 41c2713b204e6cb6a94587bc6bf6935107df5479 ] + +If dcid is received for an already-assigned destination CID the spec +requires that both channels to be discarded, but calling l2cap_chan_del +may invalidate the tmp cursor created by list_for_each_entry_safe and +in fact it is the wrong procedure as the chan->dcid may be assigned +previously it really needs to be disconnected. + +Calling l2cap_chan_clone directly may still lead to l2cap_chan_del so +instead schedule l2cap_chan_timeout with delay 0 to close the channel +asynchronously. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 7e3825c1b10b95..38ac75f85144be 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6222,6 +6222,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct l2cap_chan *orig; + u16 dcid; + + if (chan->ident != cmd->ident || +@@ -6243,8 +6244,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + + BT_DBG("dcid[%d] 0x%4.4x", i, dcid); + ++ orig = __l2cap_get_chan_by_dcid(conn, dcid); ++ + /* Check if dcid is already in use */ +- if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { ++ if (dcid && orig) { + /* If a device receives a + * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an + * already-assigned Destination CID, then both the +@@ -6253,10 +6256,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + */ + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); +- chan = __l2cap_get_chan_by_dcid(conn, dcid); +- l2cap_chan_lock(chan); +- l2cap_chan_del(chan, ECONNRESET); +- l2cap_chan_unlock(chan); ++ ++ /* Check that the dcid channel mode is ++ * L2CAP_MODE_EXT_FLOWCTL since this procedure is only ++ * valid for that mode and shouldn't disconnect a dcid ++ * in other modes. ++ */ ++ if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) { ++ l2cap_chan_lock(orig); ++ /* Disconnect the original channel as it may be ++ * considered connected since dcid has already ++ * been assigned; don't call l2cap_chan_close ++ * directly since that could lead to ++ * l2cap_chan_del and then removing the channel ++ * from the list while we're iterating over it. ++ */ ++ __set_chan_timer(orig, 0); ++ l2cap_chan_unlock(orig); ++ } + continue; + } + +-- +2.53.0 + diff --git a/queue-5.15/bonding-refuse-to-enslave-can-devices.patch b/queue-5.15/bonding-refuse-to-enslave-can-devices.patch new file mode 100644 index 0000000000..de8ba87416 --- /dev/null +++ b/queue-5.15/bonding-refuse-to-enslave-can-devices.patch @@ -0,0 +1,74 @@ +From 8f9b352ebc74f13c003ce2ca2a71bc360c4453eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:33:19 +0200 +Subject: bonding: refuse to enslave CAN devices + +From: Oliver Hartkopp + +[ Upstream commit 8ba68464e4787b6a7ec938826e16124df20fd23d ] + +syzbot reported a kernel paging request crash in +can_rx_unregister() inside net/can/af_can.c. The crash occurs +because a virtual CAN device (vxcan) is being enslaved to a +bonding master. + +During the enslavement process, the bonding driver mutates +and modifies the network device states to fit an Ethernet-like +aggregation model. However, CAN devices operate on a completely +different Layer 2 architecture, relying on the CAN mid-layer +private data structure (can_ml_priv) instead of standard +Ethernet structures. Since bonding does not initialize or +maintain these CAN structures, subsequent operations on the +half-enslaved interface (such as closing associated sockets +via isotp_release) lead to a null-pointer dereference when +accessing the CAN receiver lists. + +Bonding CAN interfaces is architecturally invalid as CAN lacks +MAC addresses, ARP capabilities, and standard Ethernet +link-layer mechanisms. While generic loopback devices are +blocked globally in net/core/dev.c, virtual CAN devices +bypass this check because they do not carry the IFF_LOOPBACK +flag, despite acting as local software-loopbacks. + +Fix this by explicitly blocking network devices of type +ARPHRD_CAN from being enslaved at the very beginning of +bond_enslave(). This prevents illegal state mutations, +eliminates the resulting KASAN crashes, and avoids potential +memory leaks from incomplete socket cleanups. + +As the CAN support has been added a long time after bonding +the Fixes-tag points to the introduction of ARPHRD_CAN that +would have needed a specific handling in bonding_main.c. + +Fixes: cd05acfe65ed ("[CAN]: Allocate protocol numbers for PF_CAN") +Reported-by: syzbot+8ed98cbd0161632bce95@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8ed98cbd0161632bce95 +Signed-off-by: Oliver Hartkopp +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260526-bonding-candev-v1-1-ba1df400918a@hartkopp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 5321d9dca698a9..42ad34b308b924 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1776,6 +1776,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, + int link_reporting; + int res = 0, i; + ++ if (slave_dev->type == ARPHRD_CAN) { ++ BOND_NL_ERR(bond_dev, extack, ++ "CAN devices cannot be enslaved"); ++ return -EPERM; ++ } ++ + if (slave_dev->flags & IFF_MASTER && + !netif_is_bond_master(slave_dev)) { + BOND_NL_ERR(bond_dev, extack, +-- +2.53.0 + diff --git a/queue-5.15/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch b/queue-5.15/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch new file mode 100644 index 0000000000..0ebf6995e6 --- /dev/null +++ b/queue-5.15/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch @@ -0,0 +1,62 @@ +From c6f88ca06d9276170efdf68cdf9eba8377a9fbb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:33 -0700 +Subject: ethtool: eeprom: add more safeties to EEPROM Netlink fallback + +From: Jakub Kicinski + +[ Upstream commit 67cfdd9210b99f260b3e0afeb9525e0acc7be31e ] + +The Netlink fallback path for reading module EEPROM +(fallback_set_params()) validates that offset < eeprom_len, +but does not check that offset + length stays within eeprom_len. +The ioctl equivalent (ethtool_get_any_eeprom() in ioctl.c) has +always enforced both bounds: + + if (eeprom.offset + eeprom.len > total_len) + return -EINVAL; + +This could lead to surprises in both drivers and device FW. +Add the missing offset + length validation to fallback_set_params(), +mirroring the ioctl. + +Similarly - ethtool core in general, and ethtool_get_any_eeprom() +in particular tries to zero-init all buffers passed to the drivers +to avoid any extra work of zeroing things out. eeprom_fallback() +uses a plain kmalloc(), change it to zalloc. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-11-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 49c0a2a77f02de..6ce40f95d8aba5 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -43,6 +43,9 @@ static int fallback_set_params(struct eeprom_req_info *request, + if (offset >= modinfo->eeprom_len) + return -EINVAL; + ++ if (length > modinfo->eeprom_len - offset) ++ return -EINVAL; ++ + eeprom->cmd = ETHTOOL_GMODULEEEPROM; + eeprom->len = length; + eeprom->offset = offset; +@@ -69,7 +72,7 @@ static int eeprom_fallback(struct eeprom_req_info *request, + if (err < 0) + return err; + +- data = kmalloc(eeprom.len, GFP_KERNEL); ++ data = kzalloc(eeprom.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + err = ethtool_get_module_eeprom_call(dev, &eeprom, data); +-- +2.53.0 + diff --git a/queue-5.15/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch b/queue-5.15/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch new file mode 100644 index 0000000000..1489bd3b69 --- /dev/null +++ b/queue-5.15/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch @@ -0,0 +1,78 @@ +From 12476c61f034d6d453c15c5ba72225947eb33f30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:45 +0200 +Subject: gpio: rockchip: convert bank->clk to devm_clk_get_enabled() + +From: Marco Scardovi + +[ Upstream commit 3e46c18d5d87f063a93ae0fe7662fbf6660459d5 ] + +The bank->clk was previously obtained via of_clk_get() and manually +prepared/enabled. However, it was missing a corresponding clk_put() in +both the error paths and the remove function, leading to a reference leak. + +Convert the allocation to devm_clk_get_enabled(), which also properly +propagates failures from clk_prepare_enable() that were previously ignored. + +The GPIO bank device uses the same OF node as the previous of_clk_get() +call, so devm_clk_get_enabled(dev, NULL) correctly resolves the same +clock provider entry. + +Fix the reference leak and simplify the code by removing the manual +clk_disable_unprepare() calls in the probe error paths and in the +remove function. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index d331745da1a3a8..df2eefc1554a01 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -649,11 +649,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + if (!bank->irq) + return -EINVAL; + +- bank->clk = of_clk_get(bank->of_node, 0); ++ bank->clk = devm_clk_get_enabled(bank->dev, NULL); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + +- clk_prepare_enable(bank->clk); + id = readl(bank->reg_base + gpio_regs_v2.version_id); + + /* If not gpio v2, that is default to v1. */ +@@ -663,7 +662,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + bank->db_clk = of_clk_get(bank->of_node, 1); + if (IS_ERR(bank->db_clk)) { + dev_err(bank->dev, "cannot find debounce clk\n"); +- clk_disable_unprepare(bank->clk); + return -EINVAL; + } + } else { +@@ -737,7 +735,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev) + + ret = rockchip_gpiolib_register(bank); + if (ret) { +- clk_disable_unprepare(bank->clk); + mutex_unlock(&bank->deferred_lock); + return ret; + } +@@ -773,7 +770,6 @@ static int rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + +- clk_disable_unprepare(bank->clk); + gpiochip_remove(&bank->gpio_chip); + + return 0; +-- +2.53.0 + diff --git a/queue-5.15/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch b/queue-5.15/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch new file mode 100644 index 0000000000..74351db6fb --- /dev/null +++ b/queue-5.15/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch @@ -0,0 +1,48 @@ +From 31fe5d6f53e55b29e3de2edf56e7154850a00b43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 12:21:47 +0000 +Subject: ipv4: free net->ipv4.sysctl_local_reserved_ports after + unregister_net_sysctl_table() + +From: Eric Dumazet + +[ Upstream commit 87a1e0fe7776da7ab411be332b4be58ac8840d10 ] + +ipv4_sysctl_exit_net() is currently freeing net->ipv4.sysctl_local_reserved_ports +too soon. + +Only after unregister_net_sysctl_table() we can be sure no threads can possibly +use the sysctls, including /proc/sys/net/ipv4/ip_local_reserved_ports. + +Fixes: 122ff243f5f1 ("ipv4: make ip_local_reserved_ports per netns") +Reported-by: Ji'an Zhou +Signed-off-by: Eric Dumazet +Cc: Cong Wang +Reviewed-by: Jason Xing +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521122147.3584624-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/sysctl_net_ipv4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 1f22e72074fdca..a7d335ab000403 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -1415,10 +1415,10 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net) + { + struct ctl_table *table; + +- kfree(net->ipv4.sysctl_local_reserved_ports); + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); ++ kfree(net->ipv4.sysctl_local_reserved_ports); + } + + static __net_initdata struct pernet_operations ipv4_sysctl_ops = { +-- +2.53.0 + diff --git a/queue-5.15/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch b/queue-5.15/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch new file mode 100644 index 0000000000..de29628137 --- /dev/null +++ b/queue-5.15/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch @@ -0,0 +1,62 @@ +From 6ccd6c9272c29323b347031d382d5abaff1371b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 21:10:31 +0530 +Subject: ipv6: rpl: fix hdrlen overflow in ipv6_rpl_srh_decompress() + +From: Rahul Chandelkar + +[ Upstream commit 9d5e7a46a9f6d8f503b41bfefef70659845f1679 ] + +ipv6_rpl_srh_decompress() computes: + + outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3); + +hdrlen is __u8. For n >= 127 the result exceeds 255 and silently +truncates. With n=127 (cmpri=15, cmpre=15, pad=0, hdrlen=16): + + (128 * 16) >> 3 = 256, truncated to 0 as __u8 + +The caller in ipv6_rpl_srh_rcv() then places the compressed header +at buf + ((ohdr->hdrlen + 1) << 3). With hdrlen=0 this is buf + 8, +but the decompressed region occupies buf[0..2055] (8-byte header +plus 128 full addresses). The compressed header overlaps the +decompressed data, and ipv6_rpl_srh_compress() writes into this +overlap, corrupting the routing header of the forwarded packet. + +The existing guard at exthdrs.c:546 checks (n + 1) > 255, which +prevents n+1 from overflowing unsigned char (the segments_left +field), but does not prevent the computed hdrlen from overflowing +__u8. n=127 passes because 128 <= 255, yet hdrlen=256 does not +fit. + +Tighten the bound to (n + 1) > 127. This caps n at 126, giving +hdrlen = (127 * 16) >> 3 = 254, which fits in __u8. The compressed +header then lands at buf + ((254 + 1) << 3) = buf + 2040, exactly +past the decompressed region (buf[0..2039]). No overlap. 127 +segments is well beyond any realistic RPL deployment. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Signed-off-by: Rahul Chandelkar +Link: https://patch.msgid.link/20260525154031.2290876-1-rc@rexion.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/exthdrs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 343b957e6337ab..a25dfa59ca2196 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -557,7 +557,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + * unsigned char which is segments_left field. Should not be + * higher than that. + */ +- if (r || (n + 1) > 255) { ++ if (r || (n + 1) > 127) { + kfree_skb(skb); + return -1; + } +-- +2.53.0 + diff --git a/queue-5.15/kernel-fork-validate-exit_signal-in-kernel_clone.patch b/queue-5.15/kernel-fork-validate-exit_signal-in-kernel_clone.patch new file mode 100644 index 0000000000..e376e672c0 --- /dev/null +++ b/queue-5.15/kernel-fork-validate-exit_signal-in-kernel_clone.patch @@ -0,0 +1,116 @@ +From a672b7dc40692524e3cd2127ccf43f1bb8109361 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 20:49:56 +0530 +Subject: kernel/fork: validate exit_signal in kernel_clone() + +From: Deepanshu Kartikey + +[ Upstream commit 09e7827e785729f391c8d46dc71becce70d296ab ] + +When a child process exits, it sends exit_signal to its parent via +do_notify_parent(). The clone() syscall constructs exit_signal as: + +(lower_32_bits(clone_flags) & CSIGNAL) + +CSIGNAL is 0xff, so values in the range 65-255 are possible. However, +valid_signal() only accepts signals up to _NSIG (64 on x86_64). A +non-zero non-valid exit_signal acts the same as exit_signal == 0: the +parent process is not signaled when the child terminates. + +The syzkaller reproducer triggers this by calling clone() with flags=0x80, +resulting in exit_signal = (0x80 & CSIGNAL) = 128, which exceeds _NSIG and +is not a valid signal. + +The v1 of this patch added the check only in the clone() syscall handler, +which is incomplete. kernel_clone() has other callers such as +sys_ia32_clone() which would remain unprotected. Move the check to +kernel_clone() to cover all callers. + +Since the valid_signal() check is now in kernel_clone() and covers all +callers including clone3(), the same check in copy_clone_args_from_user() +becomes redundant and is removed. The higher 32bits check for clone3() is +kept as it is clone3() specific. + +Note that this is a user-visible change: previously, passing an invalid +exit_signal to clone() was silently accepted. The man page for clone() +does not document any defined behavior for invalid exit_signal values, so +rejecting them with -EINVAL is the correct behavior. It is unlikely that +any sane application relies on passing an invalid exit_signal. + +[oleg@redhat.com: the comment above kernel_clone() should be updated] + Link: https://lore.kernel.org/abwvgU17W8wuW2-J@redhat.com +Link: https://lore.kernel.org/20260316151956.563558-1-kartikey406@gmail.com +Fixes: 3f2c788a1314 ("fork: prevent accidental access to clone3 features") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Oleg Nesterov +Reported-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=bbe6b99feefc3a0842de +Tested-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20260307064202.353405-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20260316104536.558108-1-kartikey406@gmail.com/T/ [v2] +Acked-by: Oleg Nesterov +Acked-by: Michal Hocko +Cc: Ben Segall +Cc: Christian Brauner +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Cc: Tetsuo Handa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index eb772b1e819f2f..faf9d68fae3029 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -2632,8 +2632,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node) + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. +- * +- * args->exit_signal is expected to be checked for sanity by the caller. + */ + pid_t kernel_clone(struct kernel_clone_args *args) + { +@@ -2658,6 +2656,9 @@ pid_t kernel_clone(struct kernel_clone_args *args) + (args->pidfd == args->parent_tid)) + return -EINVAL; + ++ if (!valid_signal(args->exit_signal)) ++ return -EINVAL; ++ + /* + * Determine whether and which event to report to ptracer. When + * called from kernel_thread or CLONE_UNTRACED is explicitly +@@ -2834,11 +2835,9 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs, + return -EINVAL; + + /* +- * Verify that higher 32bits of exit_signal are unset and that +- * it is a valid signal ++ * Verify that higher 32bits of exit_signal are unset + */ +- if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) || +- !valid_signal(args.exit_signal))) ++ if (unlikely(args.exit_signal & ~((u64)CSIGNAL))) + return -EINVAL; + + if ((args.flags & CLONE_INTO_CGROUP) && +-- +2.53.0 + diff --git a/queue-5.15/net-iucv-fix-locking-in-.getsockopt.patch b/queue-5.15/net-iucv-fix-locking-in-.getsockopt.patch new file mode 100644 index 0000000000..498c6c70d6 --- /dev/null +++ b/queue-5.15/net-iucv-fix-locking-in-.getsockopt.patch @@ -0,0 +1,87 @@ +From b1ae81f8dddb681b2eddf3193864b1b66a2997ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 07:11:45 -0700 +Subject: net/iucv: fix locking in .getsockopt + +From: Breno Leitao + +[ Upstream commit 3589d20a666caf30ad100c960a2de7de390fce88 ] + +Mirror iucv_sock_setsockopt() and wrap the whole switch in +lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock +becomes redundant and is removed. + +Any AF_IUCV HIPER user can potentially crash the kernel by racing +recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences +iucv->hs_dev->mtu after iucv_sock_close() (called from the racing +recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference +oops. + +Suggested-by: Stanislav Fomichev +Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size") +Signed-off-by: Breno Leitao +Reviewed-by: Alexandra Winter +Tested-by: Alexandra Winter +Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/iucv/af_iucv.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index e6cb3e1cbbf9b8..3188d719a2e42d 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1533,7 +1533,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + unsigned int val; +- int len; ++ int len, rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; +@@ -1546,26 +1546,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + + len = min_t(unsigned int, len, sizeof(int)); + ++ rc = 0; ++ ++ lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: +- lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ +- release_sock(sk); + break; + case SO_MSGSIZE: +- if (sk->sk_state == IUCV_OPEN) +- return -EBADFD; ++ if (sk->sk_state == IUCV_OPEN) { ++ rc = -EBADFD; ++ break; ++ } + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; + default: +- return -ENOPROTOOPT; ++ rc = -ENOPROTOOPT; ++ break; + } ++ release_sock(sk); ++ ++ if (rc) ++ return rc; + + if (put_user(len, optlen)) + return -EFAULT; +-- +2.53.0 + diff --git a/queue-5.15/net-netlink-don-t-set-nsid-on-local-notifications.patch b/queue-5.15/net-netlink-don-t-set-nsid-on-local-notifications.patch new file mode 100644 index 0000000000..2e13dd7364 --- /dev/null +++ b/queue-5.15/net-netlink-don-t-set-nsid-on-local-notifications.patch @@ -0,0 +1,82 @@ +From 8e997f36f06cd4000c395ddafafad1bf52c0ae8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:36 +0200 +Subject: net: netlink: don't set nsid on local notifications + +From: Ilya Maximets + +[ Upstream commit 88b126b39f9757e9debc322d4679239e9af089c7 ] + +In most cases, notifications on sockets with NETLINK_LISTEN_ALL_NSID +do not contain NSID in their ancillary data in case the event is local +to the listener. + +However, when a self-referential NSID is allocated for a namespace, +every local notification starts sending this ID to the user space. + +This is problematic, because the listener cannot tell if those +notifications are local or not anymore without making extra requests +to figure out if the provided NSID is local or not. The listener +can also not figure out the local NSID beforehand as it can be +allocated at any point in time by other processes, changing the +structure of the future notifications for everyone. + +The value is practically not useful, since it's the namespace's own +ID that the application has to obtain from other sources in order to +figure out if it's the same or not. So, for the application it's +just an extra busy work with no benefits. Moreover, applications +that do not know about this quirk may be mishandling notifications +with NSID set as notifications from remote namespaces. This is the +case for ovs-vswitchd and the iproute2's 'ip monitor' that stops +printing 'current' and starts printing the nsid number mid-session. + +Lack of clear documentation for this behavior is also not helping. + +A search though open-source projects doesn't reveal any projects +that use NETNSA_NSID_NOT_ASSIGNED and rely on metadata to contain +self-referential NSIDs (expected, since the value is not useful). +Quite the opposite, as already mentioned, there are few applications +that rely on NSID to not be present in local events. + +Since the value is not useful and actively harmful in some cases, +let's not report it for local events, making the notifications more +consistent. + +Also adding some blank lines for readability. + +Fixes: 59324cf35aba ("netlink: allow to listen "all" netns") +Reported-by: Matteo Perin +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-3-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 12e765fcbd747d..731c53178eb559 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1482,10 +1482,14 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ + NETLINK_CB(p->skb2).nsid_is_set = false; +- NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); +- if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) +- NETLINK_CB(p->skb2).nsid_is_set = true; ++ if (!net_eq(sock_net(sk), p->net)) { ++ NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); ++ if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) ++ NETLINK_CB(p->skb2).nsid_is_set = true; ++ } ++ + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { + netlink_overrun(sk); +-- +2.53.0 + diff --git a/queue-5.15/net-netlink-fix-sending-unassigned-nsid-after-assign.patch b/queue-5.15/net-netlink-fix-sending-unassigned-nsid-after-assign.patch new file mode 100644 index 0000000000..3de140ef4d --- /dev/null +++ b/queue-5.15/net-netlink-fix-sending-unassigned-nsid-after-assign.patch @@ -0,0 +1,45 @@ +From 1c2e8ff9678997ab9d9e9fafcda4a7065d1b13b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:35 +0200 +Subject: net: netlink: fix sending unassigned nsid after assigned one + +From: Ilya Maximets + +[ Upstream commit 70f8592ee90585272018a725054b6eb2ab7e99ca ] + +If the current skb is not shared, it is re-used directly for all the +sockets subscribed to the notification. If we have remote all-nsid +socket receiving a message first, then the 'nsid_is_set' will be +set to 'true'. If the nsid is NOT_ASSIGNED for the next socket in +the list, the 'nsid_is_set' will remain 'true' and the negative value +is be delivered to the user space. All subsequent nsid values will be +delivered as well, since there is no code path that sets the flag +back to 'false'. + +Fix that by always dropping the flag to 'false' first. + +Fixes: 7212462fa6fd ("netlink: don't send unknown nsid") +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-2-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 65eb164d00c40d..12e765fcbd747d 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1482,6 +1482,7 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ NETLINK_CB(p->skb2).nsid_is_set = false; + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) + NETLINK_CB(p->skb2).nsid_is_set = true; +-- +2.53.0 + diff --git a/queue-5.15/net-sched-revert-net-sched-restrict-conditions-for-a.patch b/queue-5.15/net-sched-revert-net-sched-restrict-conditions-for-a.patch new file mode 100644 index 0000000000..a32070751c --- /dev/null +++ b/queue-5.15/net-sched-revert-net-sched-restrict-conditions-for-a.patch @@ -0,0 +1,102 @@ +From 15fbd43e1439577d25c3a1604fdc2ef8e46d0a66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:49 -0400 +Subject: net/sched: Revert "net/sched: Restrict conditions for adding + duplicating netems to qdisc tree" + +From: Jamal Hadi Salim + +[ Upstream commit eda0b7f203bb166c98d1418b204135bd566ac83b ] + +This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. + +The original patch rejects any tree containing two netems when +either has duplication set, even when they sit on unrelated classes +of the same classful parent. That broke configurations that have +worked since netem was introduced. + +The re-entrancy problem the original commit was trying to solve is +handled by later patch using tc_depth flag. + +Doing this revert will (re)expose the original bug with multiple +netem duplication. When this patch is backported make sure +and get the full series. + +Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") +Reported-by: Ji-Soo Chung +Reported-by: Gerlinde +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 +Reported-by: zyc zyc +Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ +Reported-by: Manas Ghandat +Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 40 ---------------------------------------- + 1 file changed, 40 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 3e3bced82c564d..3dc6411b0a33c7 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -985,41 +985,6 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, + return 0; + } + +-static const struct Qdisc_class_ops netem_class_ops; +- +-static int check_netem_in_tree(struct Qdisc *sch, bool duplicates, +- struct netlink_ext_ack *extack) +-{ +- struct Qdisc *root, *q; +- unsigned int i; +- +- root = qdisc_root_sleeping(sch); +- +- if (sch != root && root->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(root))->duplicate) +- goto err; +- } +- +- if (!qdisc_dev(root)) +- return 0; +- +- hash_for_each(qdisc_dev(root)->qdisc_hash, i, q, hash) { +- if (sch != q && q->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(q))->duplicate) +- goto err; +- } +- } +- +- return 0; +- +-err: +- NL_SET_ERR_MSG(extack, +- "netem: cannot mix duplicating netems with other netems in tree"); +- return -EINVAL; +-} +- + /* Parse netlink message to set options */ + static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +@@ -1087,11 +1052,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + q->gap = qopt->gap; + q->counter = 0; + q->loss = qopt->loss; +- +- ret = check_netem_in_tree(sch, qopt->duplicate, extack); +- if (ret) +- goto unlock; +- + q->duplicate = qopt->duplicate; + + /* for compatibility with earlier versions. +-- +2.53.0 + diff --git a/queue-5.15/net-smc-do-not-re-initialize-smc-hashtables.patch b/queue-5.15/net-smc-do-not-re-initialize-smc-hashtables.patch new file mode 100644 index 0000000000..f21b5aba93 --- /dev/null +++ b/queue-5.15/net-smc-do-not-re-initialize-smc-hashtables.patch @@ -0,0 +1,59 @@ +From ad78b70f116d7974dfa0ebc4c03c6b86f8a79984 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 16:56:39 +0200 +Subject: net/smc: Do not re-initialize smc hashtables + +From: Alexandra Winter + +[ Upstream commit 9e4389b0038781f19f97895186ed941ff8ac1678 ] + +INIT_HLIST_HEAD(&smc_v*_hashinfo.ht) are called after smc_nl_init(), +proto_register() and sock_register(). This can lead to smc_v*_hashinfo.ht +being reset even though hash entries already exist and are being used, +possibly resulting in a corrupted list. + +Remove unnecessary and dangerous re-initialisation of smc_v*_hashinfo.ht in +smc_init(); it is implicitly initialised to zero anyhow. Add +HLIST_HEAD_INIT to the definitions for clarity. + +Fixes: f16a7dd5cf27 ("smc: netlink interface for SMC sockets") +Suggested-by: Halil Pasic +Signed-off-by: Alexandra Winter +Acked-by: Halil Pasic +Reviewed-by: Mahanta Jambigi +Link: https://patch.msgid.link/20260521145639.10317-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 5425c46a2e7c71..6b60a5dd240dd1 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -123,10 +123,12 @@ static struct sock *smc_tcp_syn_recv_sock(const struct sock *sk, + + static struct smc_hashinfo smc_v4_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + static struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + int smc_hash_sk(struct sock *sk) +@@ -2938,8 +2940,6 @@ static int __init smc_init(void) + pr_err("%s: sock_register fails with %d\n", __func__, rc); + goto out_proto6; + } +- INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); +- INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); + + rc = smc_ib_register_client(); + if (rc) { +-- +2.53.0 + diff --git a/queue-5.15/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch b/queue-5.15/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch new file mode 100644 index 0000000000..7de0a2b4d5 --- /dev/null +++ b/queue-5.15/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch @@ -0,0 +1,107 @@ +From 2a0697060f2a0682a13e9dbc26b0cc2b9dd12ddc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 22:52:07 +0200 +Subject: netfilter: ebtables: fix OOB read in compat_mtw_from_user + +From: Florian Westphal + +[ Upstream commit f438d1786d657d57790c5d138d6db3fc9fdac392 ] + +Luxiao Xu says: + + The function compat_mtw_from_user() converts ebtables extensions from + 32-bit user structures to kernel native structures. However, it lacks + proper validation of the user-supplied match_size/target_size. + + When certain extensions are processed, the kernel-side translation + logic may perform memory accesses based on the extension's expected + size. If the user provides a size smaller than what the extension + requires, it results in an out-of-bounds read as reported by KASAN. + + This fix introduces a check to ensure match_size is at least as large + as the extension's required compatsize. This covers matches, watchers, + and targets, while maintaining compatibility with standard targets. + +AFAIU this is relevant for matches that need to go though +match->compat_from_user() call. Those that use plain memcpy with the +user-provided size are ok because the caller checks that size vs the +start of the next rule entry offset (which itself is checked vs. total +size copied from userspace). + +The ->compat_from_user() callbacks assume they can read compatsize bytes, +so they need this extra check. + +Based on an earlier patch from Luxiao Xu. + +Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index c74efcc2b4996d..2083facfc87d9b 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1951,6 +1951,25 @@ enum compat_mwt { + EBT_COMPAT_TARGET, + }; + ++static bool match_size_ok(const struct xt_match *match, unsigned int match_size) ++{ ++ u16 csize; ++ ++ if (match->matchsize == -1) /* cannot validate ebt_among */ ++ return true; ++ ++ csize = match->compatsize ? : match->matchsize; ++ ++ return match_size >= csize; ++} ++ ++static bool tgt_size_ok(const struct xt_target *tgt, unsigned int tgt_size) ++{ ++ u16 csize = tgt->compatsize ? : tgt->targetsize; ++ ++ return tgt_size >= csize; ++} ++ + static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + enum compat_mwt compat_mwt, + struct ebt_entries_buf_state *state, +@@ -1976,6 +1995,11 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + if (IS_ERR(match)) + return PTR_ERR(match); + ++ if (!match_size_ok(match, match_size)) { ++ module_put(match->me); ++ return -EINVAL; ++ } ++ + off = ebt_compat_match_offset(match, match_size); + if (dst) { + if (match->compat_from_user) +@@ -1995,6 +2019,12 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + mwt->u.revision); + if (IS_ERR(wt)) + return PTR_ERR(wt); ++ ++ if (!tgt_size_ok(wt, match_size)) { ++ module_put(wt->me); ++ return -EINVAL; ++ } ++ + off = xt_compat_target_offset(wt); + + if (dst) { +-- +2.53.0 + diff --git a/queue-5.15/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch b/queue-5.15/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch new file mode 100644 index 0000000000..aa958e54e8 --- /dev/null +++ b/queue-5.15/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch @@ -0,0 +1,68 @@ +From 0899af06dcf89b63877fa69450af6847b0c75547 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 12:36:14 -0700 +Subject: netfilter: synproxy: refresh tcphdr after skb_ensure_writable + +From: Chris Mason + +[ Upstream commit 92170e6afe927ab2792a3f71902845789c8e31b1 ] + +synproxy_tstamp_adjust() rewrites the TCP timestamp option in place +and then patches the TCP checksum via inet_proto_csum_replace4() on +the caller-supplied tcphdr pointer. Both ipv4_synproxy_hook() and +ipv6_synproxy_hook() obtain that pointer with skb_header_pointer() +before calling in, so it may either alias skb->head directly or +point at the caller's on-stack _tcph buffer. + +Between obtaining the pointer and using it, the function calls +skb_ensure_writable(skb, optend), which on a cloned or non-linear +skb invokes pskb_expand_head() and frees the old skb->head. After +that point the cached th is stale: + + caller (ipv[46]_synproxy_hook) + th = skb_header_pointer(skb, ..., &_tcph) + synproxy_tstamp_adjust(skb, protoff, th, ...) + skb_ensure_writable(skb, optend) + pskb_expand_head() /* kfree(old skb->head) */ + ... + inet_proto_csum_replace4(&th->check, ...) + /* writes into freed head, or + into the caller's stack copy + leaving the on-wire checksum + stale */ + +The option bytes are written through skb->data and are fine; only +the checksum update goes through th and so lands in the wrong +place. The result is either a write into freed slab memory or a +packet leaving with a checksum that does not match its payload. + +Fix by re-deriving th from skb->data + protoff immediately after +skb_ensure_writable() succeeds, so the subsequent checksum update +targets the linear, writable header. + +Fixes: 48b1de4c110a ("netfilter: add SYNPROXY core/target") +Assisted-by: kres (claude-opus-4-7) +Signed-off-by: Chris Mason +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 049a88f0380117..cdb2c3e23af7ee 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -199,6 +199,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + if (skb_ensure_writable(skb, optend)) + return 0; + ++ th = (struct tcphdr *)(skb->data + protoff); ++ + while (optoff < optend) { + unsigned char *op = skb->data + optoff; + +-- +2.53.0 + diff --git a/queue-5.15/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch b/queue-5.15/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..6e8304b14e --- /dev/null +++ b/queue-5.15/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch @@ -0,0 +1,48 @@ +From 2f7ee612f3843e6f212e651de546b55665281a55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 20:10:08 +0200 +Subject: netfilter: xt_cpu: prefer raw_smp_processor_id + +From: Florian Westphal + +[ Upstream commit c376f07e16c02239ed44cabb97145d03f65b4d15 ] + +With PREEMPT_RCU we get splat: + +BUG: using smp_processor_id() in preemptible [..] +caller is cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 +CPU: 1 .. Comm: syz.3.1377 #0 PREEMPT(full) +Call Trace: + + dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 + check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 + cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 + [..] + +Just use raw version instead. +This is similar to 14d14a5d2957 ("netfilter: nft_meta: use raw_smp_processor_id()"). + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reported-by: syzbot+690d3e3ffa7335ac10eb@syzkaller.appspotmail.com +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c +index 3bdc302a0f9137..9cb259902a586b 100644 +--- a/net/netfilter/xt_cpu.c ++++ b/net/netfilter/xt_cpu.c +@@ -34,7 +34,7 @@ static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_cpu_info *info = par->matchinfo; + +- return (info->cpu == smp_processor_id()) ^ info->invert; ++ return (info->cpu == raw_smp_processor_id()) ^ info->invert; + } + + static struct xt_match cpu_mt_reg __read_mostly = { +-- +2.53.0 + diff --git a/queue-5.15/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch b/queue-5.15/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch new file mode 100644 index 0000000000..fcaa03287e --- /dev/null +++ b/queue-5.15/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch @@ -0,0 +1,40 @@ +From 1da7769db462443217ed66ce6646363125c03e5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:41 +0000 +Subject: nfc: llcp: Fix use-after-free in llcp_sock_release() + +From: Lee Jones + +[ Upstream commit f4268b466190dae95a7585f69b4f1f8ad097632c ] + +llcp_sock_release() unconditionally unlinks the socket from the local +sockets list. However, if the socket is still in connecting state, it +is on the connecting list. + +Fix this by checking the socket state and unlinking from the correct list. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Signed-off-by: Lee Jones +Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index 6e1fba2084930e..54af85d939c6b9 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -640,6 +640,8 @@ static int llcp_sock_release(struct socket *sock) + + if (sock->type == SOCK_RAW) + nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else if (sk->sk_state == LLCP_CONNECTING) ++ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + else + nfc_llcp_sock_unlink(&local->sockets, sk); + +-- +2.53.0 + diff --git a/queue-5.15/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch b/queue-5.15/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch new file mode 100644 index 0000000000..906565f885 --- /dev/null +++ b/queue-5.15/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch @@ -0,0 +1,67 @@ +From 652fe46e2b45d2433a29cb76584eea98e082c2f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:42 +0000 +Subject: nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() + +From: Lee Jones + +[ Upstream commit b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 ] + +A race condition exists in the NFC LLCP connection state machine where +the connection acceptance packet (CC) can be processed concurrently with +socket release. This can lead to a use-after-free of the socket object. + +When nfc_llcp_recv_cc() moves the socket from the connecting_sockets +list to the sockets list, it does so without holding the socket lock. +If llcp_sock_release() is executing concurrently, it might have already +unlinked the socket and dropped its references, which can result in +nfc_llcp_recv_cc() linking a freed socket into the live list. + +Fix this by holding lock_sock() during the state transition and list +movement in nfc_llcp_recv_cc(). After acquiring the lock, check if +the socket is still hashed to ensure it hasn't already been unlinked +and marked for destruction by the release path. This aligns the locking +pattern with recv_hdlc() and recv_disc(). + +Fixes: a69f32af86e3 ("NFC: Socket linked list") +Signed-off-by: Lee Jones +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index e04634f22b49f4..c7de44637e0187 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -1225,6 +1225,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + + sk = &llcp_sock->sk; + ++ lock_sock(sk); ++ ++ /* Check if socket was destroyed whilst waiting for the lock */ ++ if (!sk_hashed(sk)) { ++ release_sock(sk); ++ nfc_llcp_sock_put(llcp_sock); ++ return; ++ } ++ + /* Unlink from connecting and link to the client array */ + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + nfc_llcp_sock_link(&local->sockets, sk); +@@ -1236,6 +1245,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + ++ release_sock(sk); ++ + nfc_llcp_sock_put(llcp_sock); + } + +-- +2.53.0 + diff --git a/queue-5.15/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch b/queue-5.15/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch new file mode 100644 index 0000000000..97e6765ba5 --- /dev/null +++ b/queue-5.15/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch @@ -0,0 +1,83 @@ +From 7ce95e17969c2ef6813c3c45d94a553315dce89b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 May 2026 19:55:18 +0800 +Subject: nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems + +From: Carl Lee + +[ Upstream commit f23bf992d65a42007c517b060ca35cebdea3525a ] + +Some ACPI-based platforms report incorrect IRQ trigger types (e.g. +IRQF_TRIGGER_HIGH), which can lead to interrupt storms. + +Use the historically working rising-edge trigger on ACPI systems to +avoid this regression. + +Device Tree-based systems continue to use the firmware-provided +trigger type. + +Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") +Signed-off-by: Carl Lee +Tested-by: Bartosz Golaszewski +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Mark Pearson +Tested-by: Mark Pearson +Tested-by: Luca Stefani +Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index 22c498860c03d5..a0e665f958c4d5 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -268,6 +269,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client, + { + struct device *dev = &client->dev; + struct nxp_nci_i2c_phy *phy; ++ unsigned long irqflags; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +@@ -304,9 +306,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client, + if (r < 0) + return r; + ++ /* ++ * ACPI platforms may report incorrect IRQ trigger types ++ * (e.g. level-high), which can lead to interrupt storms. ++ * ++ * Use the historically stable rising-edge trigger for ACPI devices. ++ * ++ * On non-ACPI systems (e.g. Device Tree), prefer the firmware- ++ * provided trigger type, falling back to rising-edge if not set. ++ */ ++ if (ACPI_COMPANION(dev)) { ++ irqflags = IRQF_TRIGGER_RISING; ++ } else { ++ irqflags = irq_get_trigger_type(client->irq); ++ if (!irqflags) ++ irqflags = IRQF_TRIGGER_RISING; ++ } ++ + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, +- IRQF_ONESHOT, ++ irqflags | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); +-- +2.53.0 + diff --git a/queue-5.15/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch b/queue-5.15/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch new file mode 100644 index 0000000000..ee6b89ebfd --- /dev/null +++ b/queue-5.15/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch @@ -0,0 +1,50 @@ +From a27b84367bd322f2b53cd168f454ab479cb9e934 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 11:24:11 +0800 +Subject: sctp: fix race between sctp_wait_for_connect and peeloff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit f14fe6395a8b3d961a61e138ad7b36ba3626dd4e ] + +sctp_wait_for_connect() drops and re-acquires the socket lock while +waiting for the association to reach ESTABLISHED state. During this +window, another thread can peeloff the association to a new socket via +getsockopt(SCTP_SOCKOPT_PEELOFF), changing asoc->base.sk. After +re-acquiring the old socket lock, sctp_wait_for_connect() returns +success without noticing the migration — the caller then accesses +the association under the wrong lock in sctp_datamsg_from_user(). + +Add the same sk != asoc->base.sk check that sctp_wait_for_sndbuf() +already has, returning an error if the association was migrated while +we slept. + +Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") +Signed-off-by: Zhenghang Xiao +Acked-by: Xin Long +Link: https://patch.msgid.link/20260527032411.60959-1-kipreyyy@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 11040232ee937b..136b122d87c5a6 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9369,6 +9369,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) + release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + + *timeo_p = current_timeo; + } +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index b08d13ad77..1b2dcdd146 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -4,3 +4,31 @@ net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch drm-remove-plane-hsub-vsub-alignment-requirement-for.patch dmaengine-idxd-fix-not-releasing-workqueue-on-.relea.patch net-cpsw_new-fix-potential-unregister-of-netdev-that.patch +nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch +nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch +xfrm-check-for-underflow-in-xfrm_state_mtu.patch +nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch +kernel-fork-validate-exit_signal-in-kernel_clone.patch +netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch +netfilter-xt_cpu-prefer-raw_smp_processor_id.patch +netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch +tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch +net-netlink-fix-sending-unassigned-nsid-after-assign.patch +net-netlink-don-t-set-nsid-on-local-notifications.patch +net-smc-do-not-re-initialize-smc-hashtables.patch +net-iucv-fix-locking-in-.getsockopt.patch +ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch +asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch +tunnels-load-network-headers-after-skb_cow-in-iptunn.patch +vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch +tunnels-do-not-assume-transport-header-in-iptunnel_p.patch +asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch +bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch +bonding-refuse-to-enslave-can-devices.patch +ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch +ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch +net-sched-revert-net-sched-restrict-conditions-for-a.patch +bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch +bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch +gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch +sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch diff --git a/queue-5.15/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch b/queue-5.15/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch new file mode 100644 index 0000000000..40a02f696f --- /dev/null +++ b/queue-5.15/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch @@ -0,0 +1,54 @@ +From 5429844329f1004c49595dabfd07861f21710708 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:00:21 -0700 +Subject: tun: free page on short-frame rejection in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit f4feb1e20058e407cb00f45aff47f5b7e19a6bbf ] + +tun_xdp_one() returns -EINVAL on a frame shorter than ETH_HLEN without +freeing the page that vhost_net_build_xdp() allocated for it. +tun_sendmsg() discards that -EINVAL and still returns total_len, so +vhost_tx_batch() takes the success path and never frees the page; each +short frame in a batch leaks one page-frag chunk. + +A local process that can open /dev/net/tun and /dev/vhost-net can hit +this path: it attaches a tun/tap device as the vhost-net backend and +feeds TX descriptors whose length minus the virtio-net header is below +ETH_HLEN. Each kick leaks the page-frag chunks for that batch, and a +tight submission loop exhausts host memory and triggers an OOM panic. +Free the page before returning -EINVAL, matching the XDP-program error +path in the same function. + +Fixes: 049584807f1d ("tun: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260520160020.375349-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 5c9e7d0beffa26..803cb4722dbf4a 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2422,8 +2422,10 @@ static int tun_xdp_one(struct tun_struct *tun, + bool skb_xdp = false; + struct page *page; + +- if (unlikely(datasize < ETH_HLEN)) ++ if (unlikely(datasize < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + return -EINVAL; ++ } + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { +-- +2.53.0 + diff --git a/queue-5.15/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch b/queue-5.15/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch new file mode 100644 index 0000000000..086052e998 --- /dev/null +++ b/queue-5.15/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch @@ -0,0 +1,67 @@ +From 8249b8fe86dec818a6318d68f03ebe8f26e89ef6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 11:55:12 +0000 +Subject: tunnels: do not assume transport header in + iptunnel_pmtud_check_icmp() + +From: Eric Dumazet + +[ Upstream commit 509323077ef79a26ba0c60bb556e45c12c398b2d ] + +In some cases, iptunnel_pmtud_check_icmp() can be called while +skb transport header is not set. + +This triggers an out-of-bound access, because +(typeof(skb->transport_header))~0U is 65535. + +Access the icmp header based on IPv4 network header, +after making sure icmp->type is present in skb linear part. + +Note that iptunnel_pmtud_check_icmpv6()) is fine. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Reported-by: Damiano Melotti +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 4d80bbcd15d5a4..f535b875a02b88 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -262,7 +262,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + { +- const struct icmphdr *icmph = icmp_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); + + if (mtu < 576 || iph->frag_off != htons(IP_DF)) +@@ -273,9 +272,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr)) + return 0; + +- if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type)) +- return 0; ++ if (iph->protocol == IPPROTO_ICMP) { ++ const struct icmphdr *icmph; + ++ if (!pskb_network_may_pull(skb, iph->ihl * 4 + ++ offsetofend(struct icmphdr, type))) ++ return 0; ++ iph = ip_hdr(skb); ++ icmph = (void *)iph + iph->ihl * 4; ++ if (icmp_is_err(icmph->type)) ++ return 0; ++ } + return iptunnel_pmtud_build_icmp(skb, mtu); + } + +-- +2.53.0 + diff --git a/queue-5.15/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch b/queue-5.15/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch new file mode 100644 index 0000000000..fd0bebb52c --- /dev/null +++ b/queue-5.15/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch @@ -0,0 +1,87 @@ +From ee4436d0931a8ff123078311a8193abd52e3cd76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +From: Eric Dumazet + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 3737188ba4e1e5..4d80bbcd15d5a4 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -208,7 +208,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -218,7 +217,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -290,7 +289,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -305,7 +304,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -316,6 +314,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.53.0 + diff --git a/queue-5.15/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch b/queue-5.15/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch new file mode 100644 index 0000000000..fdc0a5bc6b --- /dev/null +++ b/queue-5.15/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch @@ -0,0 +1,54 @@ +From cd0e8f185705b7c38723c084e49eebd54f644098 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:36:42 +0000 +Subject: vxlan: do not reuse cached ip_hdr() value after + skb_tunnel_check_pmtu() + +From: Eric Dumazet + +[ Upstream commit 7d9ef0cb271555d8cf39fefe6c981e1493b25ecf ] + +skb_tunnel_check_pmtu() can change skb->head. + +Reusing old_iph afer skb_tunnel_check_pmtu() can cause an UAF. + +Use instead ip_hdr(skb) as done in drivers/net/bareudp.c +and drivers/net/geneve.c. + +Found by Sashiko. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525203642.2389723-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index bd2b44071781ca..7967b429dfcf5f 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2753,7 +2753,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), + vni, md, flags, udp_sum); +@@ -2816,7 +2816,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip6_dst_hoplimit(ndst); + skb_scrub_packet(skb, xnet); + err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), +-- +2.53.0 + diff --git a/queue-5.15/xfrm-check-for-underflow-in-xfrm_state_mtu.patch b/queue-5.15/xfrm-check-for-underflow-in-xfrm_state_mtu.patch new file mode 100644 index 0000000000..9ab1fce871 --- /dev/null +++ b/queue-5.15/xfrm-check-for-underflow-in-xfrm_state_mtu.patch @@ -0,0 +1,85 @@ +From 1c7e2d114626b6cb876e8e6707895c38d83bdaa8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 10:49:14 -0600 +Subject: xfrm: Check for underflow in xfrm_state_mtu + +From: David Ahern + +[ Upstream commit 742b04d0550b0ec89dcbc99537ec88653bd1ad90 ] + +Leo Lin reported OOB write issue in esp component: + + xfrm_state_mtu() returns u32 but performs its arithmetic in unsigned + modulo-2^32 space using an attacker-influenced "header_len + authsize + + net_adj" subtracted from a small "mtu" argument. A nobody user can + install an IPv4 ESP tunnel SA with a large authentication key + (XFRMA_ALG_AUTH_TRUNC, e.g. hmac(sha512), 64-byte key, 64-byte trunc), + configure a small interface MTU (68 bytes), and set XFRMA_TFCPAD to a + large value. When a single UDP datagram is then sent through the + tunnel, xfrm_state_mtu() underflows to a near-2^32 value, and + esp_output() consumes it as a signed int via: + + padto = min(x->tfcpad, xfrm_state_mtu(x, mtu_cached)) + esp.tfclen = padto - skb->len (assigned to int) + + esp.tfclen ends up negative (e.g. -207). It is sign-extended to size_t + when passed to memset() inside esp_output_fill_trailer(), producing a + ~16 EB write of zeroes at skb_tail_pointer(skb). KASAN logs it as + "Write of size 18446744073709551537 at addr ffff888...". + +Check for underflow and return 1. This causes the sendmsg attempt to +fail with ENETUNREACH. + +Fixes: c5c252389374 ("[XFRM]: Optimize MTU calculation") +Reported-by: Leo Lin +Assisted-by: Codex:26.506.31004 +Signed-off-by: David Ahern +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_state.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index f7f568bfb93a80..9593fcc7508c94 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -2581,10 +2581,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + const struct xfrm_type *type = READ_ONCE(x->type); + struct crypto_aead *aead; + u32 blksize, net_adj = 0; ++ u32 overhead, payload_mtu; + + if (x->km.state != XFRM_STATE_VALID || +- !type || type->proto != IPPROTO_ESP) ++ !type || type->proto != IPPROTO_ESP) { ++ if (mtu <= x->props.header_len) ++ return 1; + return mtu - x->props.header_len; ++ } + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); +@@ -2604,8 +2608,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + break; + } + +- return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - +- net_adj) & ~(blksize - 1)) + net_adj - 2; ++ overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj; ++ if (mtu <= overhead) ++ return 1; ++ ++ payload_mtu = mtu - overhead; ++ payload_mtu &= ~(blksize - 1); ++ if (payload_mtu <= 2) ++ return 1; ++ ++ return payload_mtu + net_adj - 2; ++ + } + EXPORT_SYMBOL_GPL(xfrm_state_mtu); + +-- +2.53.0 + diff --git a/queue-6.1/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch b/queue-6.1/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch new file mode 100644 index 0000000000..fd4197c56d --- /dev/null +++ b/queue-6.1/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch @@ -0,0 +1,47 @@ +From 86f15fb7b3bcaa9307a6962b5201b5f93ea6b5b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 09:24:00 -0300 +Subject: ASoC: codecs: simple-mux: Fix enum control bounds check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit f63ad68e18d774a5d15cd7e405ead63f6b322679 ] + +simple_mux_control_put() rejects values greater than e->items, but +enum control values are zero based. For the two-entry mux used by this +driver, valid values are 0 and 1, so value 2 must be rejected as well. + +Accepting e->items can store an invalid mux state, pass it to the GPIO +setter, and pass it on to the DAPM mux update path where it is used as +an index into the enum text array. + +Use the same >= e->items check used by the ASoC enum helpers. + +Fixes: 342fbb7578d1 ("ASoC: add simple-mux") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260527-asoc-simple-mux-enum-bounds-v1-1-3f805b9fc671@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/simple-mux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c +index d30c0d24d90a65..c5aa58c6e7bae6 100644 +--- a/sound/soc/codecs/simple-mux.c ++++ b/sound/soc/codecs/simple-mux.c +@@ -40,7 +40,7 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + +- if (ucontrol->value.enumerated.item[0] > e->items) ++ if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + if (priv->mux == ucontrol->value.enumerated.item[0]) +-- +2.53.0 + diff --git a/queue-6.1/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch b/queue-6.1/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch new file mode 100644 index 0000000000..ce67f0bb78 --- /dev/null +++ b/queue-6.1/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch @@ -0,0 +1,112 @@ +From 6676b3b2d8abbdf90a58f3d3e887db52017ed1ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 13:51:47 -0300 +Subject: ASoC: Intel: bytcht_es8316: Fix MCLK leak on init errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit afb2a3a9d8369d18122a0d7cd294eba9a98259c6 ] + +byt_cht_es8316_init() enables MCLK before configuring the codec sysclk +and creating the headset jack. If either of those later steps fails, the +function returns without disabling MCLK, leaving the clock enabled after +card registration fails. + +Track whether this driver enabled MCLK and disable it on the init error +paths. Add the matching DAI link exit callback so the same clock enable +is also balanced when ASoC cleans up a successfully initialized link. + +Fixes: a03bdaa565cb ("ASoC: Intel: add machine driver for BYT/CHT + ES8316") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-asoc-bytcht-es8316-mclk-leak-v1-1-b4a11cdc2afd@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_es8316.c | 29 ++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index fa2c3981dacac9..ff3642e8c132f8 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -39,6 +39,7 @@ struct byt_cht_es8316_private { + struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; + bool speaker_en; ++ bool mclk_enabled; + }; + + enum { +@@ -169,6 +170,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + }, + }; + ++static void byt_cht_es8316_disable_mclk(struct byt_cht_es8316_private *priv) ++{ ++ if (!priv->mclk_enabled) ++ return; ++ ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++} ++ + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + { + struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component; +@@ -225,12 +235,14 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); ++ else ++ priv->mclk_enabled = true; + + ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset", +@@ -239,13 +251,25 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; ++ ++err_disable_mclk: ++ byt_cht_es8316_disable_mclk(priv); ++ return ret; ++} ++ ++static void byt_cht_es8316_exit(struct snd_soc_pcm_runtime *runtime) ++{ ++ struct snd_soc_card *card = runtime->card; ++ struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); ++ ++ byt_cht_es8316_disable_mclk(priv); + } + + static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -355,6 +379,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, ++ .exit = byt_cht_es8316_exit, + SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), + }, + }; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch b/queue-6.1/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch new file mode 100644 index 0000000000..bfbf375758 --- /dev/null +++ b/queue-6.1/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch @@ -0,0 +1,40 @@ +From d4fd1b935a27d91a39dec9c29069b4f02909647d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 11:21:39 +0800 +Subject: Bluetooth: 6lowpan: check skb_clone() return value in + send_mcast_pkt() + +From: Zhao Dongdong + +[ Upstream commit 3c40d381ce04f9575a5d8b542898183c3b4b38dc ] + +The skb_clone() function can return NULL if memory allocation fails. +send_mcast_pkt() calls skb_clone() without checking the return value, which +can lead to a NULL pointer dereference in send_pkt() when it dereferences +skb->data. +Add a NULL check after skb_clone() and skip the peer if the clone fails. + +Fixes: 18722c247023 ("Bluetooth: Enable 6LoWPAN support for BT LE devices") +Signed-off-by: Zhao Dongdong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/6lowpan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index 347361ff0cc878..dc3d1d5326e96a 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -485,6 +485,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) + int ret; + + local_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!local_skb) ++ continue; + + BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p", + netdev->name, +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch b/queue-6.1/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch new file mode 100644 index 0000000000..707921c721 --- /dev/null +++ b/queue-6.1/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch @@ -0,0 +1,62 @@ +From 04075e492b5bd67fee72be4528f851b3ead2a771 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:51:52 +0800 +Subject: Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success + +From: Zhenghang Xiao + +[ Upstream commit 00e1950716c6ed67d74777b2db286b0fa23b4be9 ] + +l2cap_ecred_reconf_rsp() returns early on success without clearing +chan->ident. Every other L2CAP response handler (l2cap_ecred_conn_rsp, +l2cap_le_connect_rsp, l2cap_config_rsp) clears chan->ident after a +successful transaction to prevent the channel from matching subsequent +responses with the recycled ident value. + +A remote attacker that completed a reconfiguration as the peer can +replay a failure response with the stale ident, causing the kernel to +match and destroy the already-established channel via +l2cap_chan_del(chan, ECONNRESET). + +Clear chan->ident for all matching channels on success, and harden the +failure path by using l2cap_chan_hold_unless_zero() consistent with +other L2CAP handlers (l2cap_le_command_rej, __l2cap_get_chan_by_ident). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 21f63ca434e3fd..a3ee31f2fa2880 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6454,14 +6454,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + + BT_DBG("result 0x%4.4x", result); + +- if (!result) ++ if (!result) { ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ if (chan->ident == cmd->ident) ++ chan->ident = 0; ++ } + return 0; ++ } + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + if (chan->ident != cmd->ident) + continue; + +- l2cap_chan_hold(chan); ++ if (!l2cap_chan_hold_unless_zero(chan)) ++ continue; + l2cap_chan_lock(chan); + + l2cap_chan_del(chan, ECONNRESET); +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch b/queue-6.1/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch new file mode 100644 index 0000000000..25de3c12fd --- /dev/null +++ b/queue-6.1/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch @@ -0,0 +1,82 @@ +From 093c62d66dd253d45c07ce26aa6ad7e6dfea7a2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 12:09:42 -0400 +Subject: Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp + +From: Luiz Augusto von Dentz + +[ Upstream commit 41c2713b204e6cb6a94587bc6bf6935107df5479 ] + +If dcid is received for an already-assigned destination CID the spec +requires that both channels to be discarded, but calling l2cap_chan_del +may invalidate the tmp cursor created by list_for_each_entry_safe and +in fact it is the wrong procedure as the chan->dcid may be assigned +previously it really needs to be disconnected. + +Calling l2cap_chan_clone directly may still lead to l2cap_chan_del so +instead schedule l2cap_chan_timeout with delay 0 to close the channel +asynchronously. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index a3ee31f2fa2880..8031f83b10832e 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6254,6 +6254,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct l2cap_chan *orig; + u16 dcid; + + if (chan->ident != cmd->ident || +@@ -6275,8 +6276,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + + BT_DBG("dcid[%d] 0x%4.4x", i, dcid); + ++ orig = __l2cap_get_chan_by_dcid(conn, dcid); ++ + /* Check if dcid is already in use */ +- if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { ++ if (dcid && orig) { + /* If a device receives a + * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an + * already-assigned Destination CID, then both the +@@ -6285,10 +6288,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + */ + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); +- chan = __l2cap_get_chan_by_dcid(conn, dcid); +- l2cap_chan_lock(chan); +- l2cap_chan_del(chan, ECONNRESET); +- l2cap_chan_unlock(chan); ++ ++ /* Check that the dcid channel mode is ++ * L2CAP_MODE_EXT_FLOWCTL since this procedure is only ++ * valid for that mode and shouldn't disconnect a dcid ++ * in other modes. ++ */ ++ if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) { ++ l2cap_chan_lock(orig); ++ /* Disconnect the original channel as it may be ++ * considered connected since dcid has already ++ * been assigned; don't call l2cap_chan_close ++ * directly since that could lead to ++ * l2cap_chan_del and then removing the channel ++ * from the list while we're iterating over it. ++ */ ++ __set_chan_timer(orig, 0); ++ l2cap_chan_unlock(orig); ++ } + continue; + } + +-- +2.53.0 + diff --git a/queue-6.1/bonding-refuse-to-enslave-can-devices.patch b/queue-6.1/bonding-refuse-to-enslave-can-devices.patch new file mode 100644 index 0000000000..6cf5d8f008 --- /dev/null +++ b/queue-6.1/bonding-refuse-to-enslave-can-devices.patch @@ -0,0 +1,74 @@ +From 569e72048542af72775f2bb22a0a150fe87e678f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:33:19 +0200 +Subject: bonding: refuse to enslave CAN devices + +From: Oliver Hartkopp + +[ Upstream commit 8ba68464e4787b6a7ec938826e16124df20fd23d ] + +syzbot reported a kernel paging request crash in +can_rx_unregister() inside net/can/af_can.c. The crash occurs +because a virtual CAN device (vxcan) is being enslaved to a +bonding master. + +During the enslavement process, the bonding driver mutates +and modifies the network device states to fit an Ethernet-like +aggregation model. However, CAN devices operate on a completely +different Layer 2 architecture, relying on the CAN mid-layer +private data structure (can_ml_priv) instead of standard +Ethernet structures. Since bonding does not initialize or +maintain these CAN structures, subsequent operations on the +half-enslaved interface (such as closing associated sockets +via isotp_release) lead to a null-pointer dereference when +accessing the CAN receiver lists. + +Bonding CAN interfaces is architecturally invalid as CAN lacks +MAC addresses, ARP capabilities, and standard Ethernet +link-layer mechanisms. While generic loopback devices are +blocked globally in net/core/dev.c, virtual CAN devices +bypass this check because they do not carry the IFF_LOOPBACK +flag, despite acting as local software-loopbacks. + +Fix this by explicitly blocking network devices of type +ARPHRD_CAN from being enslaved at the very beginning of +bond_enslave(). This prevents illegal state mutations, +eliminates the resulting KASAN crashes, and avoids potential +memory leaks from incomplete socket cleanups. + +As the CAN support has been added a long time after bonding +the Fixes-tag points to the introduction of ARPHRD_CAN that +would have needed a specific handling in bonding_main.c. + +Fixes: cd05acfe65ed ("[CAN]: Allocate protocol numbers for PF_CAN") +Reported-by: syzbot+8ed98cbd0161632bce95@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8ed98cbd0161632bce95 +Signed-off-by: Oliver Hartkopp +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260526-bonding-candev-v1-1-ba1df400918a@hartkopp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index e9e2dec1dcb131..0e078252b52a98 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1848,6 +1848,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, + int link_reporting; + int res = 0, i; + ++ if (slave_dev->type == ARPHRD_CAN) { ++ BOND_NL_ERR(bond_dev, extack, ++ "CAN devices cannot be enslaved"); ++ return -EPERM; ++ } ++ + if (slave_dev->flags & IFF_MASTER && + !netif_is_bond_master(slave_dev)) { + BOND_NL_ERR(bond_dev, extack, +-- +2.53.0 + diff --git a/queue-6.1/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch b/queue-6.1/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch new file mode 100644 index 0000000000..80add7837b --- /dev/null +++ b/queue-6.1/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch @@ -0,0 +1,62 @@ +From 0390598b033bcf7f29952077b262ac1327599c47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:33 -0700 +Subject: ethtool: eeprom: add more safeties to EEPROM Netlink fallback + +From: Jakub Kicinski + +[ Upstream commit 67cfdd9210b99f260b3e0afeb9525e0acc7be31e ] + +The Netlink fallback path for reading module EEPROM +(fallback_set_params()) validates that offset < eeprom_len, +but does not check that offset + length stays within eeprom_len. +The ioctl equivalent (ethtool_get_any_eeprom() in ioctl.c) has +always enforced both bounds: + + if (eeprom.offset + eeprom.len > total_len) + return -EINVAL; + +This could lead to surprises in both drivers and device FW. +Add the missing offset + length validation to fallback_set_params(), +mirroring the ioctl. + +Similarly - ethtool core in general, and ethtool_get_any_eeprom() +in particular tries to zero-init all buffers passed to the drivers +to avoid any extra work of zeroing things out. eeprom_fallback() +uses a plain kmalloc(), change it to zalloc. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-11-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 49c0a2a77f02de..6ce40f95d8aba5 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -43,6 +43,9 @@ static int fallback_set_params(struct eeprom_req_info *request, + if (offset >= modinfo->eeprom_len) + return -EINVAL; + ++ if (length > modinfo->eeprom_len - offset) ++ return -EINVAL; ++ + eeprom->cmd = ETHTOOL_GMODULEEEPROM; + eeprom->len = length; + eeprom->offset = offset; +@@ -69,7 +72,7 @@ static int eeprom_fallback(struct eeprom_req_info *request, + if (err < 0) + return err; + +- data = kmalloc(eeprom.len, GFP_KERNEL); ++ data = kzalloc(eeprom.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + err = ethtool_get_module_eeprom_call(dev, &eeprom, data); +-- +2.53.0 + diff --git a/queue-6.1/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch b/queue-6.1/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch new file mode 100644 index 0000000000..7728a3500e --- /dev/null +++ b/queue-6.1/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch @@ -0,0 +1,78 @@ +From 1ffd821641663944469346fbac362cf6b6e8116f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:45 +0200 +Subject: gpio: rockchip: convert bank->clk to devm_clk_get_enabled() + +From: Marco Scardovi + +[ Upstream commit 3e46c18d5d87f063a93ae0fe7662fbf6660459d5 ] + +The bank->clk was previously obtained via of_clk_get() and manually +prepared/enabled. However, it was missing a corresponding clk_put() in +both the error paths and the remove function, leading to a reference leak. + +Convert the allocation to devm_clk_get_enabled(), which also properly +propagates failures from clk_prepare_enable() that were previously ignored. + +The GPIO bank device uses the same OF node as the previous of_clk_get() +call, so devm_clk_get_enabled(dev, NULL) correctly resolves the same +clock provider entry. + +Fix the reference leak and simplify the code by removing the manual +clk_disable_unprepare() calls in the probe error paths and in the +remove function. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index bf301b2d18b8f1..147d2fda4fe120 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -647,11 +647,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + if (!bank->irq) + return -EINVAL; + +- bank->clk = of_clk_get(bank->of_node, 0); ++ bank->clk = devm_clk_get_enabled(bank->dev, NULL); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + +- clk_prepare_enable(bank->clk); + id = readl(bank->reg_base + gpio_regs_v2.version_id); + + /* If not gpio v2, that is default to v1. */ +@@ -661,7 +660,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + bank->db_clk = of_clk_get(bank->of_node, 1); + if (IS_ERR(bank->db_clk)) { + dev_err(bank->dev, "cannot find debounce clk\n"); +- clk_disable_unprepare(bank->clk); + return -EINVAL; + } + } else { +@@ -735,7 +733,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev) + + ret = rockchip_gpiolib_register(bank); + if (ret) { +- clk_disable_unprepare(bank->clk); + mutex_unlock(&bank->deferred_lock); + return ret; + } +@@ -776,7 +773,6 @@ static int rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + +- clk_disable_unprepare(bank->clk); + gpiochip_remove(&bank->gpio_chip); + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch b/queue-6.1/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch new file mode 100644 index 0000000000..739c1aea8c --- /dev/null +++ b/queue-6.1/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch @@ -0,0 +1,48 @@ +From 63fafc9c26c6336ea6bc00bdb6ad06f7f2f371b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 12:21:47 +0000 +Subject: ipv4: free net->ipv4.sysctl_local_reserved_ports after + unregister_net_sysctl_table() + +From: Eric Dumazet + +[ Upstream commit 87a1e0fe7776da7ab411be332b4be58ac8840d10 ] + +ipv4_sysctl_exit_net() is currently freeing net->ipv4.sysctl_local_reserved_ports +too soon. + +Only after unregister_net_sysctl_table() we can be sure no threads can possibly +use the sysctls, including /proc/sys/net/ipv4/ip_local_reserved_ports. + +Fixes: 122ff243f5f1 ("ipv4: make ip_local_reserved_ports per netns") +Reported-by: Ji'an Zhou +Signed-off-by: Eric Dumazet +Cc: Cong Wang +Reviewed-by: Jason Xing +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521122147.3584624-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/sysctl_net_ipv4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 6b4c9b0fc9abb7..ef17d0f95a9da5 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -1449,10 +1449,10 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net) + { + struct ctl_table *table; + +- kfree(net->ipv4.sysctl_local_reserved_ports); + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); ++ kfree(net->ipv4.sysctl_local_reserved_ports); + } + + static __net_initdata struct pernet_operations ipv4_sysctl_ops = { +-- +2.53.0 + diff --git a/queue-6.1/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch b/queue-6.1/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch new file mode 100644 index 0000000000..366fc41e15 --- /dev/null +++ b/queue-6.1/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch @@ -0,0 +1,49 @@ +From 14cd9def271cd39d43881ac55b6ef3bb8988eb82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:31 +0800 +Subject: ipv6: fix possible infinite loop in fib6_select_path() + +From: Jiayuan Chen + +[ Upstream commit 9c7da87c2dc860bb17ca1ece942495d28b1ce3b9 ] + +Found while auditing the same pattern Sashiko reported in +rt6_fill_node() [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&first->fib6_siblings) +without waiting for RCU readers; first->fib6_siblings.next then +still points into the old ring and this softirq-side walker never +reaches &first->fib6_siblings as its terminator. fib6_purge_rt() +always WRITE_ONCE()s first->fib6_nsiblings to 0 before +list_del_rcu(), so an inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 0e96f7cb21a297..2b861eacee30e4 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -486,6 +486,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res, + const struct fib6_nh *nh = sibling->fib6_nh; + int nh_upper_bound; + ++ if (!READ_ONCE(first->fib6_nsiblings)) ++ break; ++ + nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); + if (hash > nh_upper_bound) + continue; +-- +2.53.0 + diff --git a/queue-6.1/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch b/queue-6.1/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch new file mode 100644 index 0000000000..32f3310342 --- /dev/null +++ b/queue-6.1/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch @@ -0,0 +1,47 @@ +From bc635bfda0f2d9086fd4fcf9c9fd736a9f92a20c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:30 +0800 +Subject: ipv6: fix possible infinite loop in rt6_fill_node() + +From: Jiayuan Chen + +[ Upstream commit 9f72412bcf60144f252b0d6205106abf14344abc ] + +Sashiko reported this issue [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&rt->fib6_siblings) +without waiting for RCU readers; rt->fib6_siblings.next then still +points into the old ring and this softirq-side walker never reaches +&rt->fib6_siblings, causing a CPU stall. fib6_del_route() always +WRITE_ONCE()s rt->fib6_nsiblings to 0 before list_del_rcu(), so an +inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 987ef0954e2ea2..0e96f7cb21a297 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -5790,6 +5790,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, + + goto nla_put_failure; + } ++ if (!READ_ONCE(rt->fib6_nsiblings)) ++ break; + } + + rcu_read_unlock(); +-- +2.53.0 + diff --git a/queue-6.1/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch b/queue-6.1/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch new file mode 100644 index 0000000000..6c0c5787a3 --- /dev/null +++ b/queue-6.1/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch @@ -0,0 +1,62 @@ +From fc08ca2f450c85073a0bdb2150bf886682099420 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 21:10:31 +0530 +Subject: ipv6: rpl: fix hdrlen overflow in ipv6_rpl_srh_decompress() + +From: Rahul Chandelkar + +[ Upstream commit 9d5e7a46a9f6d8f503b41bfefef70659845f1679 ] + +ipv6_rpl_srh_decompress() computes: + + outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3); + +hdrlen is __u8. For n >= 127 the result exceeds 255 and silently +truncates. With n=127 (cmpri=15, cmpre=15, pad=0, hdrlen=16): + + (128 * 16) >> 3 = 256, truncated to 0 as __u8 + +The caller in ipv6_rpl_srh_rcv() then places the compressed header +at buf + ((ohdr->hdrlen + 1) << 3). With hdrlen=0 this is buf + 8, +but the decompressed region occupies buf[0..2055] (8-byte header +plus 128 full addresses). The compressed header overlaps the +decompressed data, and ipv6_rpl_srh_compress() writes into this +overlap, corrupting the routing header of the forwarded packet. + +The existing guard at exthdrs.c:546 checks (n + 1) > 255, which +prevents n+1 from overflowing unsigned char (the segments_left +field), but does not prevent the computed hdrlen from overflowing +__u8. n=127 passes because 128 <= 255, yet hdrlen=256 does not +fit. + +Tighten the bound to (n + 1) > 127. This caps n at 126, giving +hdrlen = (127 * 16) >> 3 = 254, which fits in __u8. The compressed +header then lands at buf + ((254 + 1) << 3) = buf + 2040, exactly +past the decompressed region (buf[0..2039]). No overlap. 127 +segments is well beyond any realistic RPL deployment. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Signed-off-by: Rahul Chandelkar +Link: https://patch.msgid.link/20260525154031.2290876-1-rc@rexion.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/exthdrs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 826ef36aa2bcc0..13e57e3f7d7981 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -564,7 +564,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + * unsigned char which is segments_left field. Should not be + * higher than that. + */ +- if (r || (n + 1) > 255) { ++ if (r || (n + 1) > 127) { + kfree_skb(skb); + return -1; + } +-- +2.53.0 + diff --git a/queue-6.1/kernel-fork-validate-exit_signal-in-kernel_clone.patch b/queue-6.1/kernel-fork-validate-exit_signal-in-kernel_clone.patch new file mode 100644 index 0000000000..8f74d4f6de --- /dev/null +++ b/queue-6.1/kernel-fork-validate-exit_signal-in-kernel_clone.patch @@ -0,0 +1,116 @@ +From b8ed18def3adb8737a3547e5363196f58fd7c05e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 20:49:56 +0530 +Subject: kernel/fork: validate exit_signal in kernel_clone() + +From: Deepanshu Kartikey + +[ Upstream commit 09e7827e785729f391c8d46dc71becce70d296ab ] + +When a child process exits, it sends exit_signal to its parent via +do_notify_parent(). The clone() syscall constructs exit_signal as: + +(lower_32_bits(clone_flags) & CSIGNAL) + +CSIGNAL is 0xff, so values in the range 65-255 are possible. However, +valid_signal() only accepts signals up to _NSIG (64 on x86_64). A +non-zero non-valid exit_signal acts the same as exit_signal == 0: the +parent process is not signaled when the child terminates. + +The syzkaller reproducer triggers this by calling clone() with flags=0x80, +resulting in exit_signal = (0x80 & CSIGNAL) = 128, which exceeds _NSIG and +is not a valid signal. + +The v1 of this patch added the check only in the clone() syscall handler, +which is incomplete. kernel_clone() has other callers such as +sys_ia32_clone() which would remain unprotected. Move the check to +kernel_clone() to cover all callers. + +Since the valid_signal() check is now in kernel_clone() and covers all +callers including clone3(), the same check in copy_clone_args_from_user() +becomes redundant and is removed. The higher 32bits check for clone3() is +kept as it is clone3() specific. + +Note that this is a user-visible change: previously, passing an invalid +exit_signal to clone() was silently accepted. The man page for clone() +does not document any defined behavior for invalid exit_signal values, so +rejecting them with -EINVAL is the correct behavior. It is unlikely that +any sane application relies on passing an invalid exit_signal. + +[oleg@redhat.com: the comment above kernel_clone() should be updated] + Link: https://lore.kernel.org/abwvgU17W8wuW2-J@redhat.com +Link: https://lore.kernel.org/20260316151956.563558-1-kartikey406@gmail.com +Fixes: 3f2c788a1314 ("fork: prevent accidental access to clone3 features") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Oleg Nesterov +Reported-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=bbe6b99feefc3a0842de +Tested-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20260307064202.353405-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20260316104536.558108-1-kartikey406@gmail.com/T/ [v2] +Acked-by: Oleg Nesterov +Acked-by: Michal Hocko +Cc: Ben Segall +Cc: Christian Brauner +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Cc: Tetsuo Handa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index db2a9016f636f4..9931ee7e1dfa4a 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -2717,8 +2717,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node) + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. +- * +- * args->exit_signal is expected to be checked for sanity by the caller. + */ + pid_t kernel_clone(struct kernel_clone_args *args) + { +@@ -2743,6 +2741,9 @@ pid_t kernel_clone(struct kernel_clone_args *args) + (args->pidfd == args->parent_tid)) + return -EINVAL; + ++ if (!valid_signal(args->exit_signal)) ++ return -EINVAL; ++ + /* + * Determine whether and which event to report to ptracer. When + * called from kernel_thread or CLONE_UNTRACED is explicitly +@@ -2943,11 +2944,9 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs, + return -EINVAL; + + /* +- * Verify that higher 32bits of exit_signal are unset and that +- * it is a valid signal ++ * Verify that higher 32bits of exit_signal are unset + */ +- if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) || +- !valid_signal(args.exit_signal))) ++ if (unlikely(args.exit_signal & ~((u64)CSIGNAL))) + return -EINVAL; + + if ((args.flags & CLONE_INTO_CGROUP) && +-- +2.53.0 + diff --git a/queue-6.1/net-hsr-fix-potential-oob-access-in-supervision-fram.patch b/queue-6.1/net-hsr-fix-potential-oob-access-in-supervision-fram.patch new file mode 100644 index 0000000000..bae0095ff4 --- /dev/null +++ b/queue-6.1/net-hsr-fix-potential-oob-access-in-supervision-fram.patch @@ -0,0 +1,48 @@ +From 0b29ab076e6420d94cdf71344843273ac24c035c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 15:03:30 +0200 +Subject: net: hsr: fix potential OOB access in supervision frame handling + +From: Luka Gejak + +[ Upstream commit f229426072fc865654a60978bb7fda790a051ff3 ] + +Ensure the entire TLV header is linearized before access by adding +sizeof(struct hsr_sup_tlv) to the pskb_may_pull() calls. Without this, +a truncated frame could cause an out-of-bounds access. + +Fixes: eafaa88b3eb7 ("net: hsr: Add support for redbox supervision frames") +Signed-off-by: Luka Gejak +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260523130330.61880-1-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_forward.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c +index 3852fd99509f04..7a596c4f603e2d 100644 +--- a/net/hsr/hsr_forward.c ++++ b/net/hsr/hsr_forward.c +@@ -84,7 +84,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* Get next tlv */ + total_length += hsr_sup_tag->tlv.HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + skb_pull(skb, total_length); + hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data; +@@ -100,7 +100,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* make sure another tlv follows */ + total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tlv->HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + + /* get next tlv */ +-- +2.53.0 + diff --git a/queue-6.1/net-iucv-fix-locking-in-.getsockopt.patch b/queue-6.1/net-iucv-fix-locking-in-.getsockopt.patch new file mode 100644 index 0000000000..91d6e9bdf3 --- /dev/null +++ b/queue-6.1/net-iucv-fix-locking-in-.getsockopt.patch @@ -0,0 +1,87 @@ +From 277a6dc2ceb871eeb57e47f85f1a96b4074d627f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 07:11:45 -0700 +Subject: net/iucv: fix locking in .getsockopt + +From: Breno Leitao + +[ Upstream commit 3589d20a666caf30ad100c960a2de7de390fce88 ] + +Mirror iucv_sock_setsockopt() and wrap the whole switch in +lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock +becomes redundant and is removed. + +Any AF_IUCV HIPER user can potentially crash the kernel by racing +recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences +iucv->hs_dev->mtu after iucv_sock_close() (called from the racing +recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference +oops. + +Suggested-by: Stanislav Fomichev +Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size") +Signed-off-by: Breno Leitao +Reviewed-by: Alexandra Winter +Tested-by: Alexandra Winter +Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/iucv/af_iucv.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index 0f660b1d3bd51c..e9a9bb0dee065a 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1539,7 +1539,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + unsigned int val; +- int len; ++ int len, rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; +@@ -1552,26 +1552,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + + len = min_t(unsigned int, len, sizeof(int)); + ++ rc = 0; ++ ++ lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: +- lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ +- release_sock(sk); + break; + case SO_MSGSIZE: +- if (sk->sk_state == IUCV_OPEN) +- return -EBADFD; ++ if (sk->sk_state == IUCV_OPEN) { ++ rc = -EBADFD; ++ break; ++ } + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; + default: +- return -ENOPROTOOPT; ++ rc = -ENOPROTOOPT; ++ break; + } ++ release_sock(sk); ++ ++ if (rc) ++ return rc; + + if (put_user(len, optlen)) + return -EFAULT; +-- +2.53.0 + diff --git a/queue-6.1/net-mana-add-null-guards-in-teardown-path-to-prevent.patch b/queue-6.1/net-mana-add-null-guards-in-teardown-path-to-prevent.patch new file mode 100644 index 0000000000..19f4ace88d --- /dev/null +++ b/queue-6.1/net-mana-add-null-guards-in-teardown-path-to-prevent.patch @@ -0,0 +1,148 @@ +From 887318a634db628011b9fada12068b88c78a2c19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 01:08:24 -0700 +Subject: net: mana: Add NULL guards in teardown path to prevent panic on + attach failure + +From: Dipayaan Roy + +[ Upstream commit 17bfe0a8c014ee1d542ad352cd6a0a505361664a ] + +When queue allocation fails partway through, the error cleanup frees +and NULLs apc->tx_qp and apc->rxqs. Multiple teardown paths such as +mana_remove(), mana_change_mtu() recovery, and internal error handling +in mana_alloc_queues() can subsequently call into functions that +dereference these pointers without NULL checks: + +- mana_chn_setxdp() dereferences apc->rxqs[0], causing a NULL pointer + dereference panic (CR2: 0000000000000000 at mana_chn_setxdp+0x26). +- mana_destroy_vport() iterates apc->rxqs without a NULL check. +- mana_fence_rqs() iterates apc->rxqs without a NULL check. +- mana_dealloc_queues() iterates apc->tx_qp without a NULL check. + +Add NULL guards for apc->rxqs in mana_fence_rqs(), +mana_destroy_vport(), and before the mana_chn_setxdp() call. Add a +NULL guard for apc->tx_qp in mana_dealloc_queues() to skip TX queue +draining when TX queues were never allocated or already freed. + +Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)") +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260525081129.1230035-2-dipayanroy@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 70 +++++++++++-------- + 1 file changed, 41 insertions(+), 29 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 3f46a6edcee521..0f84cc4586f02e 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -914,6 +914,9 @@ static void mana_fence_rqs(struct mana_port_context *apc) + struct mana_rxq *rxq; + int err; + ++ if (!apc->rxqs) ++ return; ++ + for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { + rxq = apc->rxqs[rxq_idx]; + err = mana_fence_rq(apc, rxq); +@@ -1815,13 +1818,16 @@ static void mana_destroy_vport(struct mana_port_context *apc) + struct mana_rxq *rxq; + u32 rxq_idx; + +- for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { +- rxq = apc->rxqs[rxq_idx]; +- if (!rxq) +- continue; ++ if (apc->rxqs) { + +- mana_destroy_rxq(apc, rxq, true); +- apc->rxqs[rxq_idx] = NULL; ++ for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { ++ rxq = apc->rxqs[rxq_idx]; ++ if (!rxq) ++ continue; ++ ++ mana_destroy_rxq(apc, rxq, true); ++ apc->rxqs[rxq_idx] = NULL; ++ } + } + + mana_destroy_txq(apc); +@@ -2010,7 +2016,8 @@ static int mana_dealloc_queues(struct net_device *ndev) + if (apc->port_is_up) + return -EINVAL; + +- mana_chn_setxdp(apc, NULL); ++ if (apc->rxqs) ++ mana_chn_setxdp(apc, NULL); + + if (gd->gdma_context->is_pf) + mana_pf_deregister_filter(apc); +@@ -2028,33 +2035,38 @@ static int mana_dealloc_queues(struct net_device *ndev) + * number of queues. + */ + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- tsleep = 1000; +- while (atomic_read(&txq->pending_sends) > 0 && +- time_before(jiffies, timeout)) { +- usleep_range(tsleep, tsleep + 1000); +- tsleep <<= 1; +- } +- if (atomic_read(&txq->pending_sends)) { +- err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); +- if (err) { +- netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", +- err, atomic_read(&txq->pending_sends), +- txq->gdma_txq_id); ++ if (apc->tx_qp) { ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ tsleep = 1000; ++ while (atomic_read(&txq->pending_sends) > 0 && ++ time_before(jiffies, timeout)) { ++ usleep_range(tsleep, tsleep + 1000); ++ tsleep <<= 1; ++ } ++ if (atomic_read(&txq->pending_sends)) { ++ err = ++ pcie_flr(to_pci_dev(gd->gdma_context->dev)); ++ if (err) { ++ netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", ++ err, ++ atomic_read(&txq->pending_sends), ++ txq->gdma_txq_id); ++ } ++ break; + } +- break; + } +- } + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- while ((skb = skb_dequeue(&txq->pending_skbs))) { +- mana_unmap_skb(skb, apc); +- dev_kfree_skb_any(skb); ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ while ((skb = skb_dequeue(&txq->pending_skbs))) { ++ mana_unmap_skb(skb, apc); ++ dev_kfree_skb_any(skb); ++ } ++ atomic_set(&txq->pending_sends, 0); + } +- atomic_set(&txq->pending_sends, 0); + } ++ + /* We're 100% sure the queues can no longer be woken up, because + * we're sure now mana_poll_tx_cq() can't be running. + */ +-- +2.53.0 + diff --git a/queue-6.1/net-netlink-don-t-set-nsid-on-local-notifications.patch b/queue-6.1/net-netlink-don-t-set-nsid-on-local-notifications.patch new file mode 100644 index 0000000000..19f53a35ba --- /dev/null +++ b/queue-6.1/net-netlink-don-t-set-nsid-on-local-notifications.patch @@ -0,0 +1,82 @@ +From 87583f214a963aadfd305bd6e219b3164ca2a4f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:36 +0200 +Subject: net: netlink: don't set nsid on local notifications + +From: Ilya Maximets + +[ Upstream commit 88b126b39f9757e9debc322d4679239e9af089c7 ] + +In most cases, notifications on sockets with NETLINK_LISTEN_ALL_NSID +do not contain NSID in their ancillary data in case the event is local +to the listener. + +However, when a self-referential NSID is allocated for a namespace, +every local notification starts sending this ID to the user space. + +This is problematic, because the listener cannot tell if those +notifications are local or not anymore without making extra requests +to figure out if the provided NSID is local or not. The listener +can also not figure out the local NSID beforehand as it can be +allocated at any point in time by other processes, changing the +structure of the future notifications for everyone. + +The value is practically not useful, since it's the namespace's own +ID that the application has to obtain from other sources in order to +figure out if it's the same or not. So, for the application it's +just an extra busy work with no benefits. Moreover, applications +that do not know about this quirk may be mishandling notifications +with NSID set as notifications from remote namespaces. This is the +case for ovs-vswitchd and the iproute2's 'ip monitor' that stops +printing 'current' and starts printing the nsid number mid-session. + +Lack of clear documentation for this behavior is also not helping. + +A search though open-source projects doesn't reveal any projects +that use NETNSA_NSID_NOT_ASSIGNED and rely on metadata to contain +self-referential NSIDs (expected, since the value is not useful). +Quite the opposite, as already mentioned, there are few applications +that rely on NSID to not be present in local events. + +Since the value is not useful and actively harmful in some cases, +let's not report it for local events, making the notifications more +consistent. + +Also adding some blank lines for readability. + +Fixes: 59324cf35aba ("netlink: allow to listen "all" netns") +Reported-by: Matteo Perin +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-3-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index f502a57ad5470e..f5d4eba785d03c 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1473,10 +1473,14 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ + NETLINK_CB(p->skb2).nsid_is_set = false; +- NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); +- if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) +- NETLINK_CB(p->skb2).nsid_is_set = true; ++ if (!net_eq(sock_net(sk), p->net)) { ++ NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); ++ if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) ++ NETLINK_CB(p->skb2).nsid_is_set = true; ++ } ++ + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { + netlink_overrun(sk); +-- +2.53.0 + diff --git a/queue-6.1/net-netlink-fix-sending-unassigned-nsid-after-assign.patch b/queue-6.1/net-netlink-fix-sending-unassigned-nsid-after-assign.patch new file mode 100644 index 0000000000..67f7b27e12 --- /dev/null +++ b/queue-6.1/net-netlink-fix-sending-unassigned-nsid-after-assign.patch @@ -0,0 +1,45 @@ +From 7b8fa930fb47141bf44e3402249e442349265a97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:35 +0200 +Subject: net: netlink: fix sending unassigned nsid after assigned one + +From: Ilya Maximets + +[ Upstream commit 70f8592ee90585272018a725054b6eb2ab7e99ca ] + +If the current skb is not shared, it is re-used directly for all the +sockets subscribed to the notification. If we have remote all-nsid +socket receiving a message first, then the 'nsid_is_set' will be +set to 'true'. If the nsid is NOT_ASSIGNED for the next socket in +the list, the 'nsid_is_set' will remain 'true' and the negative value +is be delivered to the user space. All subsequent nsid values will be +delivered as well, since there is no code path that sets the flag +back to 'false'. + +Fix that by always dropping the flag to 'false' first. + +Fixes: 7212462fa6fd ("netlink: don't send unknown nsid") +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-2-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 8c441c98ba5630..f502a57ad5470e 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1473,6 +1473,7 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ NETLINK_CB(p->skb2).nsid_is_set = false; + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) + NETLINK_CB(p->skb2).nsid_is_set = true; +-- +2.53.0 + diff --git a/queue-6.1/net-sched-revert-net-sched-restrict-conditions-for-a.patch b/queue-6.1/net-sched-revert-net-sched-restrict-conditions-for-a.patch new file mode 100644 index 0000000000..9983b8d4a8 --- /dev/null +++ b/queue-6.1/net-sched-revert-net-sched-restrict-conditions-for-a.patch @@ -0,0 +1,102 @@ +From f0782e00e36a05e61adcdd37cb84129da8466d7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:49 -0400 +Subject: net/sched: Revert "net/sched: Restrict conditions for adding + duplicating netems to qdisc tree" + +From: Jamal Hadi Salim + +[ Upstream commit eda0b7f203bb166c98d1418b204135bd566ac83b ] + +This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. + +The original patch rejects any tree containing two netems when +either has duplication set, even when they sit on unrelated classes +of the same classful parent. That broke configurations that have +worked since netem was introduced. + +The re-entrancy problem the original commit was trying to solve is +handled by later patch using tc_depth flag. + +Doing this revert will (re)expose the original bug with multiple +netem duplication. When this patch is backported make sure +and get the full series. + +Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") +Reported-by: Ji-Soo Chung +Reported-by: Gerlinde +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 +Reported-by: zyc zyc +Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ +Reported-by: Manas Ghandat +Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 40 ---------------------------------------- + 1 file changed, 40 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 2c47bd8dba6478..3bebe8043cfaf5 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -984,41 +984,6 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, + return 0; + } + +-static const struct Qdisc_class_ops netem_class_ops; +- +-static int check_netem_in_tree(struct Qdisc *sch, bool duplicates, +- struct netlink_ext_ack *extack) +-{ +- struct Qdisc *root, *q; +- unsigned int i; +- +- root = qdisc_root_sleeping(sch); +- +- if (sch != root && root->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(root))->duplicate) +- goto err; +- } +- +- if (!qdisc_dev(root)) +- return 0; +- +- hash_for_each(qdisc_dev(root)->qdisc_hash, i, q, hash) { +- if (sch != q && q->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(q))->duplicate) +- goto err; +- } +- } +- +- return 0; +- +-err: +- NL_SET_ERR_MSG(extack, +- "netem: cannot mix duplicating netems with other netems in tree"); +- return -EINVAL; +-} +- + /* Parse netlink message to set options */ + static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +@@ -1083,11 +1048,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + q->gap = qopt->gap; + q->counter = 0; + q->loss = qopt->loss; +- +- ret = check_netem_in_tree(sch, qopt->duplicate, extack); +- if (ret) +- goto unlock; +- + q->duplicate = qopt->duplicate; + + /* for compatibility with earlier versions. +-- +2.53.0 + diff --git a/queue-6.1/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch b/queue-6.1/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch new file mode 100644 index 0000000000..1e868be2b8 --- /dev/null +++ b/queue-6.1/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch @@ -0,0 +1,64 @@ +From 38bf0156ae6705225351535aa395c6dd24a7f70c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:43:53 +0100 +Subject: net: skbuff: fix pskb_carve leaking zcopy pages + +From: Pavel Begunkov + +[ Upstream commit ff6e798c2eac3ebd0501ad7e796f583fab928de8 ] + +When SKBFL_MANAGED_FRAG_REFS is set, frag pages are not refcounted but +their lifetime is controlled by the attached ubuf_info. To make a copy +of the skb_shared_info, we either should clear the flag and reference +the frags, or keep the flag and have frags unreferenced. + +pskb_carve_inside_header() and pskb_carve_inside_nonlinear() don't +follow the rule and thus can leak page references. Let's clear +SKBFL_MANAGED_FRAG_REFS from the original skb to fix it. It's the +simplest way to address it, but there are more performant ways to do +that if it ever becomes a problem. + +Link: https://lore.kernel.org/all/20260523085809.26331-1-nvminh232@clc.fitus.edu.vn/ +Fixes: 753f1ca4e1e50 ("net: introduce managed frags infrastructure") +Reported-by: Minh Nguyen +Reported-by: Willem de Bruijn +Signed-off-by: Pavel Begunkov +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/1e2086aa69217d7f9c8da3d38f5be7160f1b4cd1.1779993185.git.asml.silence@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 8bc4b26de5e538..41b2aaed7a14aa 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6232,6 +6232,11 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, + skb_copy_from_linear_data_offset(skb, off, data, new_hlen); + skb->len -= off; + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), + offsetof(struct skb_shared_info, +@@ -6344,6 +6349,11 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, + return -ENOMEM; + size = SKB_WITH_OVERHEAD(size); + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0])); + if (skb_orphan_frags(skb, gfp_mask)) { +-- +2.53.0 + diff --git a/queue-6.1/net-smc-do-not-re-initialize-smc-hashtables.patch b/queue-6.1/net-smc-do-not-re-initialize-smc-hashtables.patch new file mode 100644 index 0000000000..bee0c31d37 --- /dev/null +++ b/queue-6.1/net-smc-do-not-re-initialize-smc-hashtables.patch @@ -0,0 +1,59 @@ +From 2a6427b72ba9dcb901fec45dc4de27ea66c17565 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 16:56:39 +0200 +Subject: net/smc: Do not re-initialize smc hashtables + +From: Alexandra Winter + +[ Upstream commit 9e4389b0038781f19f97895186ed941ff8ac1678 ] + +INIT_HLIST_HEAD(&smc_v*_hashinfo.ht) are called after smc_nl_init(), +proto_register() and sock_register(). This can lead to smc_v*_hashinfo.ht +being reset even though hash entries already exist and are being used, +possibly resulting in a corrupted list. + +Remove unnecessary and dangerous re-initialisation of smc_v*_hashinfo.ht in +smc_init(); it is implicitly initialised to zero anyhow. Add +HLIST_HEAD_INIT to the definitions for clarity. + +Fixes: f16a7dd5cf27 ("smc: netlink interface for SMC sockets") +Suggested-by: Halil Pasic +Signed-off-by: Alexandra Winter +Acked-by: Halil Pasic +Reviewed-by: Mahanta Jambigi +Link: https://patch.msgid.link/20260521145639.10317-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index b0f8eca077b893..012a7da967441d 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -180,10 +180,12 @@ static bool smc_hs_congested(const struct sock *sk) + + static struct smc_hashinfo smc_v4_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + static struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + int smc_hash_sk(struct sock *sk) +@@ -3495,8 +3497,6 @@ static int __init smc_init(void) + pr_err("%s: sock_register fails with %d\n", __func__, rc); + goto out_proto6; + } +- INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); +- INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); + + rc = smc_ib_register_client(); + if (rc) { +-- +2.53.0 + diff --git a/queue-6.1/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch b/queue-6.1/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch new file mode 100644 index 0000000000..f8c3483f64 --- /dev/null +++ b/queue-6.1/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch @@ -0,0 +1,107 @@ +From 3dfaa74871b35bb24db1992f864ad737da52a802 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 22:52:07 +0200 +Subject: netfilter: ebtables: fix OOB read in compat_mtw_from_user + +From: Florian Westphal + +[ Upstream commit f438d1786d657d57790c5d138d6db3fc9fdac392 ] + +Luxiao Xu says: + + The function compat_mtw_from_user() converts ebtables extensions from + 32-bit user structures to kernel native structures. However, it lacks + proper validation of the user-supplied match_size/target_size. + + When certain extensions are processed, the kernel-side translation + logic may perform memory accesses based on the extension's expected + size. If the user provides a size smaller than what the extension + requires, it results in an out-of-bounds read as reported by KASAN. + + This fix introduces a check to ensure match_size is at least as large + as the extension's required compatsize. This covers matches, watchers, + and targets, while maintaining compatibility with standard targets. + +AFAIU this is relevant for matches that need to go though +match->compat_from_user() call. Those that use plain memcpy with the +user-provided size are ok because the caller checks that size vs the +start of the next rule entry offset (which itself is checked vs. total +size copied from userspace). + +The ->compat_from_user() callbacks assume they can read compatsize bytes, +so they need this extra check. + +Based on an earlier patch from Luxiao Xu. + +Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index f99e348c8f37fa..bc69406d103df6 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1952,6 +1952,25 @@ enum compat_mwt { + EBT_COMPAT_TARGET, + }; + ++static bool match_size_ok(const struct xt_match *match, unsigned int match_size) ++{ ++ u16 csize; ++ ++ if (match->matchsize == -1) /* cannot validate ebt_among */ ++ return true; ++ ++ csize = match->compatsize ? : match->matchsize; ++ ++ return match_size >= csize; ++} ++ ++static bool tgt_size_ok(const struct xt_target *tgt, unsigned int tgt_size) ++{ ++ u16 csize = tgt->compatsize ? : tgt->targetsize; ++ ++ return tgt_size >= csize; ++} ++ + static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + enum compat_mwt compat_mwt, + struct ebt_entries_buf_state *state, +@@ -1977,6 +1996,11 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + if (IS_ERR(match)) + return PTR_ERR(match); + ++ if (!match_size_ok(match, match_size)) { ++ module_put(match->me); ++ return -EINVAL; ++ } ++ + off = ebt_compat_match_offset(match, match_size); + if (dst) { + if (match->compat_from_user) +@@ -1996,6 +2020,12 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + mwt->u.revision); + if (IS_ERR(wt)) + return PTR_ERR(wt); ++ ++ if (!tgt_size_ok(wt, match_size)) { ++ module_put(wt->me); ++ return -EINVAL; ++ } ++ + off = xt_compat_target_offset(wt); + + if (dst) { +-- +2.53.0 + diff --git a/queue-6.1/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch b/queue-6.1/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch new file mode 100644 index 0000000000..ba02a3a4d0 --- /dev/null +++ b/queue-6.1/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch @@ -0,0 +1,68 @@ +From ab8e73dd82db0bae81cac0f2b54f4cb37bc6849d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 12:36:14 -0700 +Subject: netfilter: synproxy: refresh tcphdr after skb_ensure_writable + +From: Chris Mason + +[ Upstream commit 92170e6afe927ab2792a3f71902845789c8e31b1 ] + +synproxy_tstamp_adjust() rewrites the TCP timestamp option in place +and then patches the TCP checksum via inet_proto_csum_replace4() on +the caller-supplied tcphdr pointer. Both ipv4_synproxy_hook() and +ipv6_synproxy_hook() obtain that pointer with skb_header_pointer() +before calling in, so it may either alias skb->head directly or +point at the caller's on-stack _tcph buffer. + +Between obtaining the pointer and using it, the function calls +skb_ensure_writable(skb, optend), which on a cloned or non-linear +skb invokes pskb_expand_head() and frees the old skb->head. After +that point the cached th is stale: + + caller (ipv[46]_synproxy_hook) + th = skb_header_pointer(skb, ..., &_tcph) + synproxy_tstamp_adjust(skb, protoff, th, ...) + skb_ensure_writable(skb, optend) + pskb_expand_head() /* kfree(old skb->head) */ + ... + inet_proto_csum_replace4(&th->check, ...) + /* writes into freed head, or + into the caller's stack copy + leaving the on-wire checksum + stale */ + +The option bytes are written through skb->data and are fine; only +the checksum update goes through th and so lands in the wrong +place. The result is either a write into freed slab memory or a +packet leaving with a checksum that does not match its payload. + +Fix by re-deriving th from skb->data + protoff immediately after +skb_ensure_writable() succeeds, so the subsequent checksum update +targets the linear, writable header. + +Fixes: 48b1de4c110a ("netfilter: add SYNPROXY core/target") +Assisted-by: kres (claude-opus-4-7) +Signed-off-by: Chris Mason +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 16915f8eef2b16..f5a52075691faa 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -199,6 +199,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + if (skb_ensure_writable(skb, optend)) + return 0; + ++ th = (struct tcphdr *)(skb->data + protoff); ++ + while (optoff < optend) { + unsigned char *op = skb->data + optoff; + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch b/queue-6.1/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..297e2176ef --- /dev/null +++ b/queue-6.1/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch @@ -0,0 +1,48 @@ +From ac92733db8b1e88939556d09b9dc735b73ae25eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 20:10:08 +0200 +Subject: netfilter: xt_cpu: prefer raw_smp_processor_id + +From: Florian Westphal + +[ Upstream commit c376f07e16c02239ed44cabb97145d03f65b4d15 ] + +With PREEMPT_RCU we get splat: + +BUG: using smp_processor_id() in preemptible [..] +caller is cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 +CPU: 1 .. Comm: syz.3.1377 #0 PREEMPT(full) +Call Trace: + + dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 + check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 + cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 + [..] + +Just use raw version instead. +This is similar to 14d14a5d2957 ("netfilter: nft_meta: use raw_smp_processor_id()"). + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reported-by: syzbot+690d3e3ffa7335ac10eb@syzkaller.appspotmail.com +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c +index 3bdc302a0f9137..9cb259902a586b 100644 +--- a/net/netfilter/xt_cpu.c ++++ b/net/netfilter/xt_cpu.c +@@ -34,7 +34,7 @@ static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_cpu_info *info = par->matchinfo; + +- return (info->cpu == smp_processor_id()) ^ info->invert; ++ return (info->cpu == raw_smp_processor_id()) ^ info->invert; + } + + static struct xt_match cpu_mt_reg __read_mostly = { +-- +2.53.0 + diff --git a/queue-6.1/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch b/queue-6.1/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch new file mode 100644 index 0000000000..1df779b259 --- /dev/null +++ b/queue-6.1/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch @@ -0,0 +1,40 @@ +From c32c38996dfd259ee827a46098b263a72fd3261c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:41 +0000 +Subject: nfc: llcp: Fix use-after-free in llcp_sock_release() + +From: Lee Jones + +[ Upstream commit f4268b466190dae95a7585f69b4f1f8ad097632c ] + +llcp_sock_release() unconditionally unlinks the socket from the local +sockets list. However, if the socket is still in connecting state, it +is on the connecting list. + +Fix this by checking the socket state and unlinking from the correct list. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Signed-off-by: Lee Jones +Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index cd0fd26196b8b6..6cdcc49a58bcd5 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -633,6 +633,8 @@ static int llcp_sock_release(struct socket *sock) + + if (sock->type == SOCK_RAW) + nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else if (sk->sk_state == LLCP_CONNECTING) ++ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + else + nfc_llcp_sock_unlink(&local->sockets, sk); + +-- +2.53.0 + diff --git a/queue-6.1/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch b/queue-6.1/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch new file mode 100644 index 0000000000..d093f73326 --- /dev/null +++ b/queue-6.1/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch @@ -0,0 +1,67 @@ +From d4e4ff599f7d61e66989494fc457d98a740ca2cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:42 +0000 +Subject: nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() + +From: Lee Jones + +[ Upstream commit b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 ] + +A race condition exists in the NFC LLCP connection state machine where +the connection acceptance packet (CC) can be processed concurrently with +socket release. This can lead to a use-after-free of the socket object. + +When nfc_llcp_recv_cc() moves the socket from the connecting_sockets +list to the sockets list, it does so without holding the socket lock. +If llcp_sock_release() is executing concurrently, it might have already +unlinked the socket and dropped its references, which can result in +nfc_llcp_recv_cc() linking a freed socket into the live list. + +Fix this by holding lock_sock() during the state transition and list +movement in nfc_llcp_recv_cc(). After acquiring the lock, check if +the socket is still hashed to ensure it hasn't already been unlinked +and marked for destruction by the release path. This aligns the locking +pattern with recv_hdlc() and recv_disc(). + +Fixes: a69f32af86e3 ("NFC: Socket linked list") +Signed-off-by: Lee Jones +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index d9562840fa180b..62b0f2d6686eb8 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -1216,6 +1216,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + + sk = &llcp_sock->sk; + ++ lock_sock(sk); ++ ++ /* Check if socket was destroyed whilst waiting for the lock */ ++ if (!sk_hashed(sk)) { ++ release_sock(sk); ++ nfc_llcp_sock_put(llcp_sock); ++ return; ++ } ++ + /* Unlink from connecting and link to the client array */ + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + nfc_llcp_sock_link(&local->sockets, sk); +@@ -1227,6 +1236,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + ++ release_sock(sk); ++ + nfc_llcp_sock_put(llcp_sock); + } + +-- +2.53.0 + diff --git a/queue-6.1/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch b/queue-6.1/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch new file mode 100644 index 0000000000..fb8b1bf4b2 --- /dev/null +++ b/queue-6.1/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch @@ -0,0 +1,83 @@ +From f0d02dec96b3c85b336ad9ff6d259d0688281009 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 May 2026 19:55:18 +0800 +Subject: nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems + +From: Carl Lee + +[ Upstream commit f23bf992d65a42007c517b060ca35cebdea3525a ] + +Some ACPI-based platforms report incorrect IRQ trigger types (e.g. +IRQF_TRIGGER_HIGH), which can lead to interrupt storms. + +Use the historically working rising-edge trigger on ACPI systems to +avoid this regression. + +Device Tree-based systems continue to use the firmware-provided +trigger type. + +Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") +Signed-off-by: Carl Lee +Tested-by: Bartosz Golaszewski +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Mark Pearson +Tested-by: Mark Pearson +Tested-by: Luca Stefani +Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index f256c85888229a..9b9ca3ced856b4 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -268,6 +269,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client, + { + struct device *dev = &client->dev; + struct nxp_nci_i2c_phy *phy; ++ unsigned long irqflags; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +@@ -304,9 +306,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client, + if (r < 0) + return r; + ++ /* ++ * ACPI platforms may report incorrect IRQ trigger types ++ * (e.g. level-high), which can lead to interrupt storms. ++ * ++ * Use the historically stable rising-edge trigger for ACPI devices. ++ * ++ * On non-ACPI systems (e.g. Device Tree), prefer the firmware- ++ * provided trigger type, falling back to rising-edge if not set. ++ */ ++ if (ACPI_COMPANION(dev)) { ++ irqflags = IRQF_TRIGGER_RISING; ++ } else { ++ irqflags = irq_get_trigger_type(client->irq); ++ if (!irqflags) ++ irqflags = IRQF_TRIGGER_RISING; ++ } ++ + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, +- IRQF_ONESHOT, ++ irqflags | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); +-- +2.53.0 + diff --git a/queue-6.1/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch b/queue-6.1/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch new file mode 100644 index 0000000000..90f3e9e54c --- /dev/null +++ b/queue-6.1/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch @@ -0,0 +1,50 @@ +From 87a75459a2341fcf236e5a31f9cddef2f14f909f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 11:24:11 +0800 +Subject: sctp: fix race between sctp_wait_for_connect and peeloff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit f14fe6395a8b3d961a61e138ad7b36ba3626dd4e ] + +sctp_wait_for_connect() drops and re-acquires the socket lock while +waiting for the association to reach ESTABLISHED state. During this +window, another thread can peeloff the association to a new socket via +getsockopt(SCTP_SOCKOPT_PEELOFF), changing asoc->base.sk. After +re-acquiring the old socket lock, sctp_wait_for_connect() returns +success without noticing the migration — the caller then accesses +the association under the wrong lock in sctp_datamsg_from_user(). + +Add the same sk != asoc->base.sk check that sctp_wait_for_sndbuf() +already has, returning an error if the association was migrated while +we slept. + +Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") +Signed-off-by: Zhenghang Xiao +Acked-by: Xin Long +Link: https://patch.msgid.link/20260527032411.60959-1-kipreyyy@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index b544f403f7ca8f..867a426867a7d1 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9364,6 +9364,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) + release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + + *timeo_p = current_timeo; + } +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 55f8f58b1d..460625468f 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -3,3 +3,39 @@ net-mctp-ensure-our-nlmsg-responses-are-initialised.patch net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch drm-remove-plane-hsub-vsub-alignment-requirement-for.patch net-cpsw_new-fix-potential-unregister-of-netdev-that.patch +nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch +nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch +xfrm-check-for-underflow-in-xfrm_state_mtu.patch +nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch +tools-bootconfig-cleanup-bootconfig-footer-size-calc.patch +tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch +kernel-fork-validate-exit_signal-in-kernel_clone.patch +netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch +netfilter-xt_cpu-prefer-raw_smp_processor_id.patch +netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch +tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch +tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch +net-netlink-fix-sending-unassigned-nsid-after-assign.patch +net-netlink-don-t-set-nsid-on-local-notifications.patch +net-smc-do-not-re-initialize-smc-hashtables.patch +net-iucv-fix-locking-in-.getsockopt.patch +ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch +asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch +net-hsr-fix-potential-oob-access-in-supervision-fram.patch +tunnels-load-network-headers-after-skb_cow-in-iptunn.patch +vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch +tunnels-do-not-assume-transport-header-in-iptunnel_p.patch +asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch +bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch +bonding-refuse-to-enslave-can-devices.patch +ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch +ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch +net-sched-revert-net-sched-restrict-conditions-for-a.patch +bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch +bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch +gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch +net-mana-add-null-guards-in-teardown-path-to-prevent.patch +sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch +ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch +ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch +net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch diff --git a/queue-6.1/tools-bootconfig-cleanup-bootconfig-footer-size-calc.patch b/queue-6.1/tools-bootconfig-cleanup-bootconfig-footer-size-calc.patch new file mode 100644 index 0000000000..1cabe8858c --- /dev/null +++ b/queue-6.1/tools-bootconfig-cleanup-bootconfig-footer-size-calc.patch @@ -0,0 +1,101 @@ +From ac0eebf10a72887064f430ccaeb21d016f6fefb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Jul 2025 11:24:17 +0900 +Subject: tools/bootconfig: Cleanup bootconfig footer size calculations + +From: Masami Hiramatsu (Google) + +[ Upstream commit 26dda57695090e05c1a99c3e8f802f862d1ac474 ] + +There are many same pattern of 8 + BOOTCONFIG_MAGIC_LEN for calculating +the size of bootconfig footer. Use BOOTCONFIG_FOOTER_SIZE macro to +clean up those magic numbers. + +Link: https://lore.kernel.org/all/175211425693.2591046.16029516706923643510.stgit@mhiramat.tok.corp.google.com/ + +Signed-off-by: Masami Hiramatsu (Google) +Stable-dep-of: f42d01aadced ("tools/bootconfig: Fix buf leaks in apply_xbc") +Signed-off-by: Sasha Levin +--- + tools/bootconfig/main.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c +index 32cf48f2da9a1d..d302235f6b9743 100644 +--- a/tools/bootconfig/main.c ++++ b/tools/bootconfig/main.c +@@ -16,6 +16,10 @@ + + #define pr_err(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) + ++/* Bootconfig footer is [size][csum][BOOTCONFIG_MAGIC]. */ ++#define BOOTCONFIG_FOOTER_SIZE \ ++ (sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN) ++ + static int xbc_show_value(struct xbc_node *node, bool semicolon) + { + const char *val, *eol; +@@ -188,7 +192,7 @@ static int load_xbc_from_initrd(int fd, char **buf) + if (ret < 0) + return -errno; + +- if (stat.st_size < 8 + BOOTCONFIG_MAGIC_LEN) ++ if (stat.st_size < BOOTCONFIG_FOOTER_SIZE) + return 0; + + if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) +@@ -201,7 +205,7 @@ static int load_xbc_from_initrd(int fd, char **buf) + if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0) + return 0; + +- if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0) ++ if (lseek(fd, -BOOTCONFIG_FOOTER_SIZE, SEEK_END) < 0) + return pr_errno("Failed to lseek for size", -errno); + + if (read(fd, &size, sizeof(uint32_t)) < 0) +@@ -213,12 +217,12 @@ static int load_xbc_from_initrd(int fd, char **buf) + csum = le32toh(csum); + + /* Wrong size error */ +- if (stat.st_size < size + 8 + BOOTCONFIG_MAGIC_LEN) { ++ if (stat.st_size < size + BOOTCONFIG_FOOTER_SIZE) { + pr_err("bootconfig size is too big\n"); + return -E2BIG; + } + +- if (lseek(fd, stat.st_size - (size + 8 + BOOTCONFIG_MAGIC_LEN), ++ if (lseek(fd, stat.st_size - (size + BOOTCONFIG_FOOTER_SIZE), + SEEK_SET) < 0) + return pr_errno("Failed to lseek", -errno); + +@@ -349,7 +353,7 @@ static int delete_xbc(const char *path) + ret = fstat(fd, &stat); + if (!ret) + ret = ftruncate(fd, stat.st_size +- - size - 8 - BOOTCONFIG_MAGIC_LEN); ++ - size - BOOTCONFIG_FOOTER_SIZE); + if (ret) + ret = -errno; + } /* Ignore if there is no boot config in initrd */ +@@ -379,8 +383,7 @@ static int apply_xbc(const char *path, const char *xbc_path) + csum = xbc_calc_checksum(buf, size); + + /* Backup the bootconfig data */ +- data = calloc(size + BOOTCONFIG_ALIGN + +- sizeof(uint32_t) + sizeof(uint32_t) + BOOTCONFIG_MAGIC_LEN, 1); ++ data = calloc(size + BOOTCONFIG_ALIGN + BOOTCONFIG_FOOTER_SIZE, 1); + if (!data) + return -ENOMEM; + memcpy(data, buf, size); +@@ -428,7 +431,7 @@ static int apply_xbc(const char *path, const char *xbc_path) + } + + /* To align up the total size to BOOTCONFIG_ALIGN, get padding size */ +- total_size = stat.st_size + size + sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN; ++ total_size = stat.st_size + size + BOOTCONFIG_FOOTER_SIZE; + pad = ((total_size + BOOTCONFIG_ALIGN - 1) & (~BOOTCONFIG_ALIGN_MASK)) - total_size; + size += pad; + +-- +2.53.0 + diff --git a/queue-6.1/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch b/queue-6.1/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch new file mode 100644 index 0000000000..1eb49df8f7 --- /dev/null +++ b/queue-6.1/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch @@ -0,0 +1,40 @@ +From 5d57c3fbd9d27d7268cda74dca1bc7cf324a97b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 11:01:26 +0800 +Subject: tools/bootconfig: Fix buf leaks in apply_xbc + +From: Hongtao Lee + +[ Upstream commit f42d01aadcedd7bbf4f9a466cabe25c1781dedad ] + +If data calloc failed, free the buf before return. + +Link: https://lore.kernel.org/all/20260520030126.147782-1-lihongtao@kylinos.cn/ + +Fixes: 950313ebf79c ("tools: bootconfig: Add bootconfig command") +Signed-off-by: Hongtao Lee +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + tools/bootconfig/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c +index d302235f6b9743..49573044e93a58 100644 +--- a/tools/bootconfig/main.c ++++ b/tools/bootconfig/main.c +@@ -384,8 +384,10 @@ static int apply_xbc(const char *path, const char *xbc_path) + + /* Backup the bootconfig data */ + data = calloc(size + BOOTCONFIG_ALIGN + BOOTCONFIG_FOOTER_SIZE, 1); +- if (!data) ++ if (!data) { ++ free(buf); + return -ENOMEM; ++ } + memcpy(data, buf, size); + + /* Check the data format */ +-- +2.53.0 + diff --git a/queue-6.1/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch b/queue-6.1/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch new file mode 100644 index 0000000000..b8454bdaa3 --- /dev/null +++ b/queue-6.1/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch @@ -0,0 +1,47 @@ +From bb188f576f0edabc4130f514c78a24e7688ab500 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 09:33:13 -0700 +Subject: tun: free page on build_skb failure in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit aa8963fdce667a42fb7f0bdd2909fadcab02f9a8 ] + +When build_skb() fails in tun_xdp_one(), the function sets ret to +-ENOMEM and jumps to the out label, which returns without freeing the +page that vhost_net_build_xdp() allocated for the frame. As with the +short-frame rejection path, tun_sendmsg() discards the per-buffer error +and still returns total_len, so vhost_tx_batch() takes the success path +and never frees the page. Each build_skb() failure in a batch leaks one +page-frag chunk. + +Free the page before taking the error path, matching the put_page() the +other error exits of tun_xdp_one() already perform. + +Fixes: 043d222f93ab ("tuntap: accept an array of XDP buffs through sendmsg()") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260521163312.1479805-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 1ad6af74de7c3f..e8f8c7d5df29ec 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2494,6 +2494,7 @@ static int tun_xdp_one(struct tun_struct *tun, + build: + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { ++ put_page(virt_to_head_page(xdp->data)); + ret = -ENOMEM; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.1/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch b/queue-6.1/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch new file mode 100644 index 0000000000..05d8a9730f --- /dev/null +++ b/queue-6.1/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch @@ -0,0 +1,54 @@ +From 5c440911e85062918a527b28e9134ebfe175ca0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:00:21 -0700 +Subject: tun: free page on short-frame rejection in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit f4feb1e20058e407cb00f45aff47f5b7e19a6bbf ] + +tun_xdp_one() returns -EINVAL on a frame shorter than ETH_HLEN without +freeing the page that vhost_net_build_xdp() allocated for it. +tun_sendmsg() discards that -EINVAL and still returns total_len, so +vhost_tx_batch() takes the success path and never frees the page; each +short frame in a batch leaks one page-frag chunk. + +A local process that can open /dev/net/tun and /dev/vhost-net can hit +this path: it attaches a tun/tap device as the vhost-net backend and +feeds TX descriptors whose length minus the virtio-net header is below +ETH_HLEN. Each kick leaks the page-frag chunks for that batch, and a +tight submission loop exhausts host memory and triggers an OOM panic. +Free the page before returning -EINVAL, matching the XDP-program error +path in the same function. + +Fixes: 049584807f1d ("tun: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260520160020.375349-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 03478ae3ff2448..1ad6af74de7c3f 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2448,8 +2448,10 @@ static int tun_xdp_one(struct tun_struct *tun, + bool skb_xdp = false; + struct page *page; + +- if (unlikely(datasize < ETH_HLEN)) ++ if (unlikely(datasize < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + return -EINVAL; ++ } + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { +-- +2.53.0 + diff --git a/queue-6.1/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch b/queue-6.1/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch new file mode 100644 index 0000000000..9070de67ef --- /dev/null +++ b/queue-6.1/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch @@ -0,0 +1,67 @@ +From c2d1652243c2106030b888d049b0723b0595a461 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 11:55:12 +0000 +Subject: tunnels: do not assume transport header in + iptunnel_pmtud_check_icmp() + +From: Eric Dumazet + +[ Upstream commit 509323077ef79a26ba0c60bb556e45c12c398b2d ] + +In some cases, iptunnel_pmtud_check_icmp() can be called while +skb transport header is not set. + +This triggers an out-of-bound access, because +(typeof(skb->transport_header))~0U is 65535. + +Access the icmp header based on IPv4 network header, +after making sure icmp->type is present in skb linear part. + +Note that iptunnel_pmtud_check_icmpv6()) is fine. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Reported-by: Damiano Melotti +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 5fb437f040ace7..9f6f1b435d8d72 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -262,7 +262,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + { +- const struct icmphdr *icmph = icmp_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); + + if (mtu < 576 || iph->frag_off != htons(IP_DF)) +@@ -273,9 +272,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr)) + return 0; + +- if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type)) +- return 0; ++ if (iph->protocol == IPPROTO_ICMP) { ++ const struct icmphdr *icmph; + ++ if (!pskb_network_may_pull(skb, iph->ihl * 4 + ++ offsetofend(struct icmphdr, type))) ++ return 0; ++ iph = ip_hdr(skb); ++ icmph = (void *)iph + iph->ihl * 4; ++ if (icmp_is_err(icmph->type)) ++ return 0; ++ } + return iptunnel_pmtud_build_icmp(skb, mtu); + } + +-- +2.53.0 + diff --git a/queue-6.1/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch b/queue-6.1/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch new file mode 100644 index 0000000000..8330e6b6c7 --- /dev/null +++ b/queue-6.1/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch @@ -0,0 +1,87 @@ +From 631f31b7f9b3d6112d874c23a3166f4d820f43d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +From: Eric Dumazet + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 75e3d7501752df..5fb437f040ace7 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -208,7 +208,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -218,7 +217,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -290,7 +289,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -305,7 +304,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -316,6 +314,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.53.0 + diff --git a/queue-6.1/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch b/queue-6.1/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch new file mode 100644 index 0000000000..07fd35b3de --- /dev/null +++ b/queue-6.1/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch @@ -0,0 +1,54 @@ +From a7a6e641fe6fc96f9df30d1a1d9f9746487e304d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:36:42 +0000 +Subject: vxlan: do not reuse cached ip_hdr() value after + skb_tunnel_check_pmtu() + +From: Eric Dumazet + +[ Upstream commit 7d9ef0cb271555d8cf39fefe6c981e1493b25ecf ] + +skb_tunnel_check_pmtu() can change skb->head. + +Reusing old_iph afer skb_tunnel_check_pmtu() can cause an UAF. + +Use instead ip_hdr(skb) as done in drivers/net/bareudp.c +and drivers/net/geneve.c. + +Found by Sashiko. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525203642.2389723-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index 6ad59c8afdcfc1..9d7ebf8aa79f66 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2682,7 +2682,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), + vni, md, flags, udp_sum); +@@ -2745,7 +2745,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip6_dst_hoplimit(ndst); + skb_scrub_packet(skb, xnet); + err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), +-- +2.53.0 + diff --git a/queue-6.1/xfrm-check-for-underflow-in-xfrm_state_mtu.patch b/queue-6.1/xfrm-check-for-underflow-in-xfrm_state_mtu.patch new file mode 100644 index 0000000000..be68ad0d9b --- /dev/null +++ b/queue-6.1/xfrm-check-for-underflow-in-xfrm_state_mtu.patch @@ -0,0 +1,85 @@ +From 79e34564ad0557d657a7f43b3bf7be9cf7ee3c9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 10:49:14 -0600 +Subject: xfrm: Check for underflow in xfrm_state_mtu + +From: David Ahern + +[ Upstream commit 742b04d0550b0ec89dcbc99537ec88653bd1ad90 ] + +Leo Lin reported OOB write issue in esp component: + + xfrm_state_mtu() returns u32 but performs its arithmetic in unsigned + modulo-2^32 space using an attacker-influenced "header_len + authsize + + net_adj" subtracted from a small "mtu" argument. A nobody user can + install an IPv4 ESP tunnel SA with a large authentication key + (XFRMA_ALG_AUTH_TRUNC, e.g. hmac(sha512), 64-byte key, 64-byte trunc), + configure a small interface MTU (68 bytes), and set XFRMA_TFCPAD to a + large value. When a single UDP datagram is then sent through the + tunnel, xfrm_state_mtu() underflows to a near-2^32 value, and + esp_output() consumes it as a signed int via: + + padto = min(x->tfcpad, xfrm_state_mtu(x, mtu_cached)) + esp.tfclen = padto - skb->len (assigned to int) + + esp.tfclen ends up negative (e.g. -207). It is sign-extended to size_t + when passed to memset() inside esp_output_fill_trailer(), producing a + ~16 EB write of zeroes at skb_tail_pointer(skb). KASAN logs it as + "Write of size 18446744073709551537 at addr ffff888...". + +Check for underflow and return 1. This causes the sendmsg attempt to +fail with ENETUNREACH. + +Fixes: c5c252389374 ("[XFRM]: Optimize MTU calculation") +Reported-by: Leo Lin +Assisted-by: Codex:26.506.31004 +Signed-off-by: David Ahern +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_state.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index 7dd536d5f43f3a..f3661d2946e6ef 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -2577,10 +2577,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + const struct xfrm_type *type = READ_ONCE(x->type); + struct crypto_aead *aead; + u32 blksize, net_adj = 0; ++ u32 overhead, payload_mtu; + + if (x->km.state != XFRM_STATE_VALID || +- !type || type->proto != IPPROTO_ESP) ++ !type || type->proto != IPPROTO_ESP) { ++ if (mtu <= x->props.header_len) ++ return 1; + return mtu - x->props.header_len; ++ } + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); +@@ -2600,8 +2604,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + break; + } + +- return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - +- net_adj) & ~(blksize - 1)) + net_adj - 2; ++ overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj; ++ if (mtu <= overhead) ++ return 1; ++ ++ payload_mtu = mtu - overhead; ++ payload_mtu &= ~(blksize - 1); ++ if (payload_mtu <= 2) ++ return 1; ++ ++ return payload_mtu + net_adj - 2; ++ + } + EXPORT_SYMBOL_GPL(xfrm_state_mtu); + +-- +2.53.0 + diff --git a/queue-6.12/accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch b/queue-6.12/accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch new file mode 100644 index 0000000000..c5935962a6 --- /dev/null +++ b/queue-6.12/accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch @@ -0,0 +1,40 @@ +From 4c9ad76d387005dffad998dac23b2459ec145dc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 10:14:42 +0300 +Subject: accel/ivpu: prevent uninitialized data bug in debugfs + +From: Dan Carpenter + +[ Upstream commit 44e151be23deb788d9f6124de93823faf6e04e99 ] + +The simple_write_to_buffer() will only initialize data starting from +the *pos offset so if it's non-zero then the first part of the buffer +uninitialized. Really, if *pos is non-zero then this code won't work +so just check for that at the start of the function. + +Fixes: 320323d2e545 ("accel/ivpu: Add debugfs interface for setting HWS priority bands") +Signed-off-by: Dan Carpenter +Reviewed-by: Karol Wachowski +Signed-off-by: Karol Wachowski +Link: https://patch.msgid.link/ahP24m6Mii9EDL7Q@stanley.mountain +Signed-off-by: Sasha Levin +--- + drivers/accel/ivpu/ivpu_debugfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c +index df89c1c0da6dd7..1da4ce6a99cd9b 100644 +--- a/drivers/accel/ivpu/ivpu_debugfs.c ++++ b/drivers/accel/ivpu/ivpu_debugfs.c +@@ -447,7 +447,7 @@ priority_bands_fops_write(struct file *file, const char __user *user_buf, size_t + u32 band; + int ret; + +- if (size >= sizeof(buf)) ++ if (*pos != 0 || size >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, pos, user_buf, size); +-- +2.53.0 + diff --git a/queue-6.12/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch b/queue-6.12/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch new file mode 100644 index 0000000000..9662962dc4 --- /dev/null +++ b/queue-6.12/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch @@ -0,0 +1,84 @@ +From e2bfb6d6bb3939d07c524c14d0bbbacb36dc8c36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 22:09:40 -0300 +Subject: ALSA: pcm: oss: Fix setup list UAF on proc write error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 4cc54bdd54b337e77115be5b55577d1c58608eae ] + +snd_pcm_oss_proc_write() links a newly allocated setup entry into the +OSS setup list before duplicating the task name. If the task-name +allocation fails, the error path frees the already linked entry and +leaves setup_list pointing at freed memory. + +A later OSS device open can then walk the stale list entry in +snd_pcm_oss_look_for_setup() and dereference freed memory. + +Allocate the task name and initialize the setup entry before publishing +the entry on setup_list. Also fetch the initial proc read iterator only +after taking setup_mutex, so all setup_list traversal follows the same +list lifetime rules. + +Reported-by: syzbot+8e498074a794999eb41c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a1062b7.170a0220.35b2b7.0003.GAE@google.com +Closes: https://syzkaller.appspot.com/bug?extid=8e498074a794999eb41c +Fixes: 060d77b9c04a ("[ALSA] Fix / clean up PCM-OSS setup hooks") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260522-alsa-pcm-oss-setup-uaf-v1-1-40bdcc4d17e8@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/oss/pcm_oss.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index daa7cda98ae6f6..a65a3b8d04b8cb 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -2966,8 +2966,10 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) + { + struct snd_pcm_str *pstr = entry->private_data; +- struct snd_pcm_oss_setup *setup = pstr->oss.setup_list; ++ struct snd_pcm_oss_setup *setup; ++ + guard(mutex)(&pstr->oss.setup_mutex); ++ setup = pstr->oss.setup_list; + while (setup) { + snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n", + setup->task_name, +@@ -3052,6 +3054,13 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, + buffer->error = -ENOMEM; + return; + } ++ template.task_name = kstrdup(task_name, GFP_KERNEL); ++ if (!template.task_name) { ++ kfree(setup); ++ buffer->error = -ENOMEM; ++ return; ++ } ++ *setup = template; + if (pstr->oss.setup_list == NULL) + pstr->oss.setup_list = setup; + else { +@@ -3059,12 +3068,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, + setup1->next; setup1 = setup1->next); + setup1->next = setup; + } +- template.task_name = kstrdup(task_name, GFP_KERNEL); +- if (! template.task_name) { +- kfree(setup); +- buffer->error = -ENOMEM; +- return; +- } ++ continue; + } + *setup = template; + } +-- +2.53.0 + diff --git a/queue-6.12/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch b/queue-6.12/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch new file mode 100644 index 0000000000..732c7cb6f4 --- /dev/null +++ b/queue-6.12/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch @@ -0,0 +1,47 @@ +From 9722d73d4801f84157614d8954bec2c2b9bdc203 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 09:24:00 -0300 +Subject: ASoC: codecs: simple-mux: Fix enum control bounds check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit f63ad68e18d774a5d15cd7e405ead63f6b322679 ] + +simple_mux_control_put() rejects values greater than e->items, but +enum control values are zero based. For the two-entry mux used by this +driver, valid values are 0 and 1, so value 2 must be rejected as well. + +Accepting e->items can store an invalid mux state, pass it to the GPIO +setter, and pass it on to the DAPM mux update path where it is used as +an index into the enum text array. + +Use the same >= e->items check used by the ASoC enum helpers. + +Fixes: 342fbb7578d1 ("ASoC: add simple-mux") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260527-asoc-simple-mux-enum-bounds-v1-1-3f805b9fc671@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/simple-mux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c +index 240af0563283e5..4c94087a246e16 100644 +--- a/sound/soc/codecs/simple-mux.c ++++ b/sound/soc/codecs/simple-mux.c +@@ -49,7 +49,7 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + +- if (ucontrol->value.enumerated.item[0] > e->items) ++ if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + if (priv->mux == ucontrol->value.enumerated.item[0]) +-- +2.53.0 + diff --git a/queue-6.12/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch b/queue-6.12/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch new file mode 100644 index 0000000000..a6cccea92f --- /dev/null +++ b/queue-6.12/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch @@ -0,0 +1,112 @@ +From 5e5c472d24ad493061f66fe89eb7267232ccc545 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 13:51:47 -0300 +Subject: ASoC: Intel: bytcht_es8316: Fix MCLK leak on init errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit afb2a3a9d8369d18122a0d7cd294eba9a98259c6 ] + +byt_cht_es8316_init() enables MCLK before configuring the codec sysclk +and creating the headset jack. If either of those later steps fails, the +function returns without disabling MCLK, leaving the clock enabled after +card registration fails. + +Track whether this driver enabled MCLK and disable it on the init error +paths. Add the matching DAI link exit callback so the same clock enable +is also balanced when ASoC cleans up a successfully initialized link. + +Fixes: a03bdaa565cb ("ASoC: Intel: add machine driver for BYT/CHT + ES8316") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-asoc-bytcht-es8316-mclk-leak-v1-1-b4a11cdc2afd@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_es8316.c | 29 ++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index 7975dc0ceb3518..676c08247cfcb9 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -40,6 +40,7 @@ struct byt_cht_es8316_private { + struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; + bool speaker_en; ++ bool mclk_enabled; + }; + + enum { +@@ -170,6 +171,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + }, + }; + ++static void byt_cht_es8316_disable_mclk(struct byt_cht_es8316_private *priv) ++{ ++ if (!priv->mclk_enabled) ++ return; ++ ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++} ++ + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + { + struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; +@@ -226,12 +236,14 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); ++ else ++ priv->mclk_enabled = true; + + ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(runtime, 0), 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset", +@@ -240,13 +252,25 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; ++ ++err_disable_mclk: ++ byt_cht_es8316_disable_mclk(priv); ++ return ret; ++} ++ ++static void byt_cht_es8316_exit(struct snd_soc_pcm_runtime *runtime) ++{ ++ struct snd_soc_card *card = runtime->card; ++ struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); ++ ++ byt_cht_es8316_disable_mclk(priv); + } + + static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -356,6 +380,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, ++ .exit = byt_cht_es8316_exit, + SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), + }, + }; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch b/queue-6.12/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch new file mode 100644 index 0000000000..057ab3bd7e --- /dev/null +++ b/queue-6.12/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch @@ -0,0 +1,40 @@ +From 847aa47b30c596764ef8708a2a20ce10ca5f3f42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 11:21:39 +0800 +Subject: Bluetooth: 6lowpan: check skb_clone() return value in + send_mcast_pkt() + +From: Zhao Dongdong + +[ Upstream commit 3c40d381ce04f9575a5d8b542898183c3b4b38dc ] + +The skb_clone() function can return NULL if memory allocation fails. +send_mcast_pkt() calls skb_clone() without checking the return value, which +can lead to a NULL pointer dereference in send_pkt() when it dereferences +skb->data. +Add a NULL check after skb_clone() and skip the peer if the clone fails. + +Fixes: 18722c247023 ("Bluetooth: Enable 6LoWPAN support for BT LE devices") +Signed-off-by: Zhao Dongdong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/6lowpan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index e5186a438290ae..03f0b5d27b60d3 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -485,6 +485,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) + int ret; + + local_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!local_skb) ++ continue; + + BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p", + netdev->name, +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch b/queue-6.12/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch new file mode 100644 index 0000000000..d14f5e704c --- /dev/null +++ b/queue-6.12/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch @@ -0,0 +1,57 @@ +From c03e703dbdffb14ce5981c3217312da176b23f7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 10:50:58 -0300 +Subject: Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close + +From: Heitor Alves de Siqueira + +[ Upstream commit 525daaea459fc215f432de1b8debbd9144bf97b0 ] + +Since hci_dev_close_sync() can now be called during the reset path, we +should also set HCI_CMD_DRAIN_WORKQUEUE. This avoids queuing timeouts +while the hdev workqueue is being drained. + +Fixes: 877afadad2dc ("Bluetooth: When HCI work queue is drained, only queue chained work") +Signed-off-by: Heitor Alves de Siqueira +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sync.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index fbcb3bbfef4fde..f6e133756bd9ba 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -5223,6 +5223,12 @@ int hci_dev_close_sync(struct hci_dev *hdev) + + bt_dev_dbg(hdev, ""); + ++ /* Set HCI_DRAIN_WORKQUEUE flag to prevent queuing work during ++ * reset/close. See hci_cmd_work() and handle_cmd_cnt_and_timer(). ++ */ ++ hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); ++ synchronize_rcu(); ++ + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + disable_delayed_work(&hdev->power_off); + disable_delayed_work(&hdev->ncmd_timer); +@@ -5246,6 +5252,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) + + if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { + cancel_delayed_work_sync(&hdev->cmd_timer); ++ hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + return err; + } + +@@ -5345,6 +5352,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) + /* Clear flags */ + hdev->flags &= BIT(HCI_RAW); + hci_dev_clear_volatile_flags(hdev); ++ hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch b/queue-6.12/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch new file mode 100644 index 0000000000..4093baebf8 --- /dev/null +++ b/queue-6.12/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch @@ -0,0 +1,62 @@ +From 02ad67cbd0668dcb120eee25ed7f55b3e99520a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:51:52 +0800 +Subject: Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success + +From: Zhenghang Xiao + +[ Upstream commit 00e1950716c6ed67d74777b2db286b0fa23b4be9 ] + +l2cap_ecred_reconf_rsp() returns early on success without clearing +chan->ident. Every other L2CAP response handler (l2cap_ecred_conn_rsp, +l2cap_le_connect_rsp, l2cap_config_rsp) clears chan->ident after a +successful transaction to prevent the channel from matching subsequent +responses with the recycled ident value. + +A remote attacker that completed a reconfiguration as the peer can +replay a failure response with the stale ident, causing the kernel to +match and destroy the already-established channel via +l2cap_chan_del(chan, ECONNRESET). + +Clear chan->ident for all matching channels on success, and harden the +failure path by using l2cap_chan_hold_unless_zero() consistent with +other L2CAP handlers (l2cap_le_command_rej, __l2cap_get_chan_by_ident). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index b24e4d8130ddb1..9de5d545966d60 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5392,14 +5392,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + + BT_DBG("result 0x%4.4x", result); + +- if (!result) ++ if (!result) { ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ if (chan->ident == cmd->ident) ++ chan->ident = 0; ++ } + return 0; ++ } + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + if (chan->ident != cmd->ident) + continue; + +- l2cap_chan_hold(chan); ++ if (!l2cap_chan_hold_unless_zero(chan)) ++ continue; + l2cap_chan_lock(chan); + + l2cap_chan_del(chan, ECONNRESET); +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch b/queue-6.12/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch new file mode 100644 index 0000000000..862561e201 --- /dev/null +++ b/queue-6.12/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch @@ -0,0 +1,82 @@ +From c1acc8473ff9e3ae3fd224360f8981462a6a97c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 12:09:42 -0400 +Subject: Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp + +From: Luiz Augusto von Dentz + +[ Upstream commit 41c2713b204e6cb6a94587bc6bf6935107df5479 ] + +If dcid is received for an already-assigned destination CID the spec +requires that both channels to be discarded, but calling l2cap_chan_del +may invalidate the tmp cursor created by list_for_each_entry_safe and +in fact it is the wrong procedure as the chan->dcid may be assigned +previously it really needs to be disconnected. + +Calling l2cap_chan_clone directly may still lead to l2cap_chan_del so +instead schedule l2cap_chan_timeout with delay 0 to close the channel +asynchronously. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 9de5d545966d60..f0b0f347ebc10a 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5194,6 +5194,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct l2cap_chan *orig; + u16 dcid; + + if (chan->ident != cmd->ident || +@@ -5215,8 +5216,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + + BT_DBG("dcid[%d] 0x%4.4x", i, dcid); + ++ orig = __l2cap_get_chan_by_dcid(conn, dcid); ++ + /* Check if dcid is already in use */ +- if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { ++ if (dcid && orig) { + /* If a device receives a + * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an + * already-assigned Destination CID, then both the +@@ -5225,10 +5228,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + */ + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); +- chan = __l2cap_get_chan_by_dcid(conn, dcid); +- l2cap_chan_lock(chan); +- l2cap_chan_del(chan, ECONNRESET); +- l2cap_chan_unlock(chan); ++ ++ /* Check that the dcid channel mode is ++ * L2CAP_MODE_EXT_FLOWCTL since this procedure is only ++ * valid for that mode and shouldn't disconnect a dcid ++ * in other modes. ++ */ ++ if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) { ++ l2cap_chan_lock(orig); ++ /* Disconnect the original channel as it may be ++ * considered connected since dcid has already ++ * been assigned; don't call l2cap_chan_close ++ * directly since that could lead to ++ * l2cap_chan_del and then removing the channel ++ * from the list while we're iterating over it. ++ */ ++ __set_chan_timer(orig, 0); ++ l2cap_chan_unlock(orig); ++ } + continue; + } + +-- +2.53.0 + diff --git a/queue-6.12/bonding-refuse-to-enslave-can-devices.patch b/queue-6.12/bonding-refuse-to-enslave-can-devices.patch new file mode 100644 index 0000000000..bd487bd616 --- /dev/null +++ b/queue-6.12/bonding-refuse-to-enslave-can-devices.patch @@ -0,0 +1,74 @@ +From b54fbe3c1b9b0b52f9b4cee559d51a479d4e18e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:33:19 +0200 +Subject: bonding: refuse to enslave CAN devices + +From: Oliver Hartkopp + +[ Upstream commit 8ba68464e4787b6a7ec938826e16124df20fd23d ] + +syzbot reported a kernel paging request crash in +can_rx_unregister() inside net/can/af_can.c. The crash occurs +because a virtual CAN device (vxcan) is being enslaved to a +bonding master. + +During the enslavement process, the bonding driver mutates +and modifies the network device states to fit an Ethernet-like +aggregation model. However, CAN devices operate on a completely +different Layer 2 architecture, relying on the CAN mid-layer +private data structure (can_ml_priv) instead of standard +Ethernet structures. Since bonding does not initialize or +maintain these CAN structures, subsequent operations on the +half-enslaved interface (such as closing associated sockets +via isotp_release) lead to a null-pointer dereference when +accessing the CAN receiver lists. + +Bonding CAN interfaces is architecturally invalid as CAN lacks +MAC addresses, ARP capabilities, and standard Ethernet +link-layer mechanisms. While generic loopback devices are +blocked globally in net/core/dev.c, virtual CAN devices +bypass this check because they do not carry the IFF_LOOPBACK +flag, despite acting as local software-loopbacks. + +Fix this by explicitly blocking network devices of type +ARPHRD_CAN from being enslaved at the very beginning of +bond_enslave(). This prevents illegal state mutations, +eliminates the resulting KASAN crashes, and avoids potential +memory leaks from incomplete socket cleanups. + +As the CAN support has been added a long time after bonding +the Fixes-tag points to the introduction of ARPHRD_CAN that +would have needed a specific handling in bonding_main.c. + +Fixes: cd05acfe65ed ("[CAN]: Allocate protocol numbers for PF_CAN") +Reported-by: syzbot+8ed98cbd0161632bce95@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8ed98cbd0161632bce95 +Signed-off-by: Oliver Hartkopp +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260526-bonding-candev-v1-1-ba1df400918a@hartkopp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 1b2cd7f870353c..c6b114946d9a5a 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1927,6 +1927,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, + int link_reporting; + int res = 0, i; + ++ if (slave_dev->type == ARPHRD_CAN) { ++ BOND_NL_ERR(bond_dev, extack, ++ "CAN devices cannot be enslaved"); ++ return -EPERM; ++ } ++ + if (slave_dev->flags & IFF_MASTER && + !netif_is_bond_master(slave_dev)) { + BOND_NL_ERR(bond_dev, extack, +-- +2.53.0 + diff --git a/queue-6.12/cxl-test-update-mock-dev-array-before-calling-platfo.patch b/queue-6.12/cxl-test-update-mock-dev-array-before-calling-platfo.patch new file mode 100644 index 0000000000..e0cf81104b --- /dev/null +++ b/queue-6.12/cxl-test-update-mock-dev-array-before-calling-platfo.patch @@ -0,0 +1,272 @@ +From acdb4ee2828f711306d28baa05e6e3605db0dc70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 20:14:57 +0800 +Subject: cxl/test: Update mock dev array before calling platform_device_add() + +From: Li Ming + +[ Upstream commit d90f236f8b9e354848bd226f581db27755ab901d ] + +CXL test environment hits the following error sometimes. + + cxl_mem mem9: endpoint7 failed probe + +All mock memdevs are platform firmware devices added by cxl_test module, +and cxl_test module also provides a platform device driver for them to +create a memdev device to CXL subsystem. cxl_test module uses +cxl_rcd/mem_single/mem arrays to store different types of mock memdevs. +CXL drivers calls registered mock functions for a mock memdev by +checking if a given memdev is in these arrays. + +When cxl_test module adds these mock memdevs, it always calls +platform_device_add() before adding them to a suitable mock memdev +array. However, there is a small window where CXL drivers calls mock +function for a added memdev before it added to a mock memdev array. In +above case, cxl endpoint driver considers a added memdev was not a mock +memdev, then calling devm_cxl_endpoint_decoders_setup() for it rather +than mock_endpoint_decoders_setup(). + +An appropriate solution is that adding a new mock device to a mock +device array before calling platform_device_add() for it. It can +guarantee the new mock device is visible to CXL subsystem. + +This patch introduces a new helped called cxl_mock_platform_device_add() +to handle the issue, and uses the function for all mock devices addition. + +Fixes: 3a2b97b3210b ("cxl/test: Improve init-order fidelity relative to real-world systems") +Signed-off-by: Li Ming +Tested-by: Alison Schofield +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260520121457.234404-1-ming.li@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + tools/testing/cxl/test/cxl.c | 105 ++++++++++++++--------------------- + 1 file changed, 43 insertions(+), 62 deletions(-) + +diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c +index 050725afa45d16..0d0c434426e7bf 100644 +--- a/tools/testing/cxl/test/cxl.c ++++ b/tools/testing/cxl/test/cxl.c +@@ -1058,6 +1058,23 @@ static void mock_companion(struct acpi_device *adev, struct device *dev) + #define SZ_64G (SZ_32G * 2) + #endif + ++static int cxl_mock_platform_device_add(struct platform_device *pdev, ++ struct platform_device **ppdev) ++{ ++ int rc; ++ ++ if (ppdev) ++ *ppdev = pdev; ++ rc = platform_device_add(pdev); ++ if (rc) { ++ platform_device_put(pdev); ++ if (ppdev) ++ *ppdev = NULL; ++ } ++ ++ return rc; ++} ++ + static __init int cxl_rch_topo_init(void) + { + int rc, i; +@@ -1072,13 +1089,10 @@ static __init int cxl_rch_topo_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_rch[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_rch[i] = pdev; + mock_pci_bus[idx].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "firmware_node"); +@@ -1130,13 +1144,10 @@ static __init int cxl_single_topo_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_hb_single[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_hb_single[i] = pdev; + mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "physical_node"); +@@ -1155,12 +1166,9 @@ static __init int cxl_single_topo_init(void) + goto err_port; + pdev->dev.parent = &bridge->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_root_single[i]); ++ if (rc) + goto err_port; +- } +- cxl_root_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++) { +@@ -1173,12 +1181,9 @@ static __init int cxl_single_topo_init(void) + goto err_uport; + pdev->dev.parent = &root_port->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_swu_single[i]); ++ if (rc) + goto err_uport; +- } +- cxl_swu_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++) { +@@ -1192,12 +1197,9 @@ static __init int cxl_single_topo_init(void) + goto err_dport; + pdev->dev.parent = &uport->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_swd_single[i]); ++ if (rc) + goto err_dport; +- } +- cxl_swd_single[i] = pdev; + } + + return 0; +@@ -1270,12 +1272,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &dport->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_mem[i]); ++ if (rc) + goto err_mem; +- } +- cxl_mem[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) { +@@ -1288,12 +1287,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &dport->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_mem_single[i]); ++ if (rc) + goto err_single; +- } +- cxl_mem_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) { +@@ -1307,12 +1303,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &rch->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_rcd[i]); ++ if (rc) + goto err_rcd; +- } +- cxl_rcd[i] = pdev; + } + + return 0; +@@ -1373,13 +1366,10 @@ static __init int cxl_test_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_host_bridge[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_host_bridge[i] = pdev; + mock_pci_bus[i].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "physical_node"); +@@ -1397,12 +1387,9 @@ static __init int cxl_test_init(void) + goto err_port; + pdev->dev.parent = &bridge->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_root_port[i]); ++ if (rc) + goto err_port; +- } +- cxl_root_port[i] = pdev; + } + + BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port)); +@@ -1415,12 +1402,9 @@ static __init int cxl_test_init(void) + goto err_uport; + pdev->dev.parent = &root_port->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_switch_uport[i]); ++ if (rc) + goto err_uport; +- } +- cxl_switch_uport[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) { +@@ -1433,12 +1417,9 @@ static __init int cxl_test_init(void) + goto err_dport; + pdev->dev.parent = &uport->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_switch_dport[i]); ++ if (rc) + goto err_dport; +- } +- cxl_switch_dport[i] = pdev; + } + + rc = cxl_single_topo_init(); +@@ -1456,9 +1437,9 @@ static __init int cxl_test_init(void) + mock_companion(&acpi0017_mock, &cxl_acpi->dev); + acpi0017_mock.dev.bus = &platform_bus_type; + +- rc = platform_device_add(cxl_acpi); ++ rc = cxl_mock_platform_device_add(cxl_acpi, NULL); + if (rc) +- goto err_root; ++ goto err_rch; + + rc = cxl_mem_init(); + if (rc) +-- +2.53.0 + diff --git a/queue-6.12/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch b/queue-6.12/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch new file mode 100644 index 0000000000..65cd72a112 --- /dev/null +++ b/queue-6.12/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch @@ -0,0 +1,52 @@ +From 648671bc8093e3ce79abced8f849bce032120898 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:10 -0700 +Subject: ethtool: cmis: fix u16-to-u8 truncation of msleep_pre_rpl + +From: Jakub Kicinski + +[ Upstream commit 3e8c3d464c36bb342fe377b026577c7ec27fdbb4 ] + +ethtool_cmis_cdb_compose_args() accepts msleep_pre_rpl as u16 but stores +it into the u8 field ethtool_cmis_cdb_cmd_args::msleep_pre_rpl, silently +truncating values >= 256. Seven of the nine call sites pass 1000 ms +(it's the third argument from the end). + +Fixes: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-8-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h +index 3e7c293af78c4d..aa32a675b8f8d2 100644 +--- a/net/ethtool/cmis.h ++++ b/net/ethtool/cmis.h +@@ -59,9 +59,9 @@ struct ethtool_cmis_cdb_request { + * struct ethtool_cmis_cdb_cmd_args - CDB commands execution arguments + * @req: CDB command fields as described in the CMIS standard. + * @max_duration: Maximum duration time for command completion in msec. ++ * @msleep_pre_rpl: Waiting time before checking reply in msec. + * @read_write_len_ext: Allowable additional number of byte octets to the LPL + * in a READ or a WRITE commands. +- * @msleep_pre_rpl: Waiting time before checking reply in msec. + * @rpl_exp_len: Expected reply length in bytes. + * @flags: Validation flags for CDB commands. + * @err_msg: Error message to be sent to user space. +@@ -69,8 +69,8 @@ struct ethtool_cmis_cdb_request { + struct ethtool_cmis_cdb_cmd_args { + struct ethtool_cmis_cdb_request req; + u16 max_duration; ++ u16 msleep_pre_rpl; + u8 read_write_len_ext; +- u8 msleep_pre_rpl; + u8 rpl_exp_len; + u8 flags; + char *err_msg; +-- +2.53.0 + diff --git a/queue-6.12/ethtool-cmis-require-exact-cdb-reply-length.patch b/queue-6.12/ethtool-cmis-require-exact-cdb-reply-length.patch new file mode 100644 index 0000000000..f96549f1af --- /dev/null +++ b/queue-6.12/ethtool-cmis-require-exact-cdb-reply-length.patch @@ -0,0 +1,70 @@ +From 3a4007ec8ec1e03a9ff89f57f73ee84e04c25d89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:09 -0700 +Subject: ethtool: cmis: require exact CDB reply length + +From: Jakub Kicinski + +[ Upstream commit 6c3f999a9d1338c6c89a9ff4549eafe72bc2e7b1 ] + +Malicious SFP module could respond with rpl_len longer than +what cmis_cdb_process_reply() expected, leading to OOB writes. +Malicious HW is a bit theoretical but some modules may just +be buggy and/or the reads may occasionally get corrupted, +so let's protect the kernel. + +The existing check protects from short replies. We need to +protect from long ones, too. All callers that pass a non-zero +rpl_exp_len cast the reply payload to a fixed-layout struct +and read fields at fixed offsets, with no version negotiation +or short-reply handling: + + - cmis_cdb_validate_password() + - cmis_cdb_module_features_get() + - cmis_fw_update_fw_mng_features_get() + +so let's assume that responses longer than expected do not +have to be handled gracefully here. Add a warning message +to make the debug easier in case my understanding is wrong... + +Note that page_data->length (argument of kmalloc) comes from +last arg to ethtool_cmis_page_init() which is rpl_exp_len. + +Note2 that AIs also like to point out overflows in args->req.payload +itself (which is a fixed-size 120 B buffer, on the stack), +but callers should be reading structs defined by the standard, +so protecting from requests for more data than max seem like +defensive programming. + +Fixes: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands") +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-7-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_cdb.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c +index 8bf99295bfbe96..690002366d965a 100644 +--- a/net/ethtool/cmis_cdb.c ++++ b/net/ethtool/cmis_cdb.c +@@ -508,8 +508,13 @@ static int cmis_cdb_process_reply(struct net_device *dev, + } + + rpl = (struct ethtool_cmis_cdb_rpl *)page_data->data; +- if ((args->rpl_exp_len > rpl->hdr.rpl_len + rpl_hdr_len) || +- !rpl->hdr.rpl_chk_code) { ++ if (rpl->hdr.rpl_len != args->rpl_exp_len) { ++ netdev_warn(dev, "CDB reply length mismatch, expected %u got %u\n", ++ args->rpl_exp_len, rpl->hdr.rpl_len); ++ err = -EIO; ++ goto out; ++ } ++ if (!rpl->hdr.rpl_chk_code) { + err = -EIO; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.12/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch b/queue-6.12/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch new file mode 100644 index 0000000000..2626435424 --- /dev/null +++ b/queue-6.12/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch @@ -0,0 +1,48 @@ +From fcc4acaaba061fd1a5f467a29e8275b8fa2e553d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:12 -0700 +Subject: ethtool: cmis: validate fw->size against start_cmd_payload_size + +From: Jakub Kicinski + +[ Upstream commit d5551f4c1800dc714cec86647bdd651ae0de923e ] + +cmis_fw_update_start_download() copies start_cmd_payload_size bytes +from the firmware blob into the CDB LPL vendor_data[] payload without +validating that the FW has enough data. + +Since the start_cmd_payload_size can only be ~120B an image too short +is most likely corrupted, so reject it. + +Fixes: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-10-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_fw_update.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index 560bafd4d16864..9c6d9571cf24db 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -129,6 +129,14 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, + u8 lpl_len; + int err; + ++ if (fw_update->fw->size < vendor_data_size) { ++ ethnl_module_fw_flash_ntf_err(fw_update->dev, ++ &fw_update->ntf_params, ++ "Firmware image too small for module's start payload", ++ NULL); ++ return -EINVAL; ++ } ++ + pl.image_size = cpu_to_be32(fw_update->fw->size); + memcpy(pl.vendor_data, fw_update->fw->data, vendor_data_size); + +-- +2.53.0 + diff --git a/queue-6.12/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch b/queue-6.12/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch new file mode 100644 index 0000000000..5a679e0d03 --- /dev/null +++ b/queue-6.12/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch @@ -0,0 +1,96 @@ +From d367668456b5ef08aa2d63a9210126855a598733 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:11 -0700 +Subject: ethtool: cmis: validate start_cmd_payload_size from module + +From: Jakub Kicinski + +[ Upstream commit 12c2496a71f82f63617971ca9b730dffa05cf58b ] + +The CMIS firmware update code reads start_cmd_payload_size from +the module's FW Management Features CDB reply and uses it directly +as the byte count for memcpy. The destination buffer is 112 bytes +(ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - 8). So a malicious +module (or corrupted response) can cause a OOB write later on in +cmis_fw_update_start_download(). + +Let's error out. If modules that expect longer LPL writes actually +exist we should revisit. + +struct cmis_cdb_start_fw_download_pl's definition has to move, +no change there. + +Fixes: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-9-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_fw_update.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index 48aef6220f0094..560bafd4d16864 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -43,6 +43,20 @@ enum cmis_cdb_fw_write_mechanism { + CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11, + }; + ++/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard ++ * revision 5.2. ++ * struct cmis_cdb_start_fw_download_pl is a structured layout of the ++ * flat array, ethtool_cmis_cdb_request::payload. ++ */ ++struct cmis_cdb_start_fw_download_pl { ++ __struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */, ++ __be32 image_size; ++ __be32 resv1; ++ ); ++ u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - ++ sizeof(struct cmis_cdb_start_fw_download_pl_h)]; ++}; ++ + static int + cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + struct net_device *dev, +@@ -85,6 +99,14 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + */ + cdb->read_write_len_ext = rpl->read_write_len_ext; + fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size; ++ if (fw_mng->start_cmd_payload_size > ++ sizeof_field(struct cmis_cdb_start_fw_download_pl, vendor_data)) { ++ ethnl_module_fw_flash_ntf_err(dev, ntf_params, ++ "Start cmd payload size exceeds max LPL payload", ++ NULL); ++ return -EINVAL; ++ } ++ + fw_mng->write_mechanism = + rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ? + CMIS_CDB_FW_WRITE_MECHANISM_LPL : +@@ -96,20 +118,6 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + return 0; + } + +-/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard +- * revision 5.2. +- * struct cmis_cdb_start_fw_download_pl is a structured layout of the +- * flat array, ethtool_cmis_cdb_request::payload. +- */ +-struct cmis_cdb_start_fw_download_pl { +- __struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */, +- __be32 image_size; +- __be32 resv1; +- ); +- u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - +- sizeof(struct cmis_cdb_start_fw_download_pl_h)]; +-}; +- + static int + cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, + struct ethtool_cmis_fw_update_params *fw_update, +-- +2.53.0 + diff --git a/queue-6.12/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch b/queue-6.12/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch new file mode 100644 index 0000000000..415e4ff36d --- /dev/null +++ b/queue-6.12/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch @@ -0,0 +1,45 @@ +From 6ebe6f5cd207f3de29da77f0f70dc68965c22876 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:24 -0700 +Subject: ethtool: coalesce: cap profile updates at NET_DIM_PARAMS_NUM_PROFILES + +From: Jakub Kicinski + +[ Upstream commit 7281b096b072f6c6e30420e3467d738f2e4c4b57 ] + +ethnl_update_profile() walks the ETHTOOL_A_PROFILE_IRQ_MODERATION +nest list with an index 'i' and writes new_profile[i++] without +bounding i. The destination is kmemdup()'d at NET_DIM_PARAMS_NUM_PROFILES +entries (5), but the Netlink nest count is entirely user-controlled. +Netlink policies do not have support for constraining the number +of nested entries (or number of multi-attr entries). + +Fixes: f750dfe825b9 ("ethtool: provide customized dim profile management") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/coalesce.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ethtool/coalesce.c b/net/ethtool/coalesce.c +index 3e18ca1ccc5ef6..cace02d964cb21 100644 +--- a/net/ethtool/coalesce.c ++++ b/net/ethtool/coalesce.c +@@ -463,6 +463,12 @@ static int ethnl_update_profile(struct net_device *dev, + + nla_for_each_nested_type(nest, ETHTOOL_A_PROFILE_IRQ_MODERATION, + nests, rem) { ++ if (i >= NET_DIM_PARAMS_NUM_PROFILES) { ++ NL_SET_BAD_ATTR(extack, nest); ++ ret = -E2BIG; ++ goto err_out; ++ } ++ + ret = nla_parse_nested(tb, len_irq_moder - 1, nest, + coalesce_irq_moderation_policy, + extack); +-- +2.53.0 + diff --git a/queue-6.12/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch b/queue-6.12/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch new file mode 100644 index 0000000000..3fba19b137 --- /dev/null +++ b/queue-6.12/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch @@ -0,0 +1,48 @@ +From a13b6bf690bfd0087cc339710797feaef6f6d5b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:32 -0700 +Subject: ethtool: eeprom: add missing ethnl_ops_begin() / _complete() during + fallback + +From: Jakub Kicinski + +[ Upstream commit 2376586f85f972fefe701f095bb37dcfe7405d21 ] + +All ethtool driver op calls should be sandwiched between +ethnl_ops_begin() / ethnl_ops_complete(). In Netlink eeprom code, +if the paged access failed we fall back to old API, but we +first call _complete() and the fallback never does its own +ethnl_ops_begin(). Move the fallback into the _begin() / _complete() +section. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-10-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 3b8209e930fd3a..03cb418a15823b 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -140,12 +140,11 @@ static int eeprom_prepare_data(const struct ethnl_req_info *req_base, + return 0; + + err_ops: ++ if (ret == -EOPNOTSUPP) ++ ret = eeprom_fallback(request, reply); + ethnl_ops_complete(dev); + err_free: + kfree(page_data.data); +- +- if (ret == -EOPNOTSUPP) +- return eeprom_fallback(request, reply); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.12/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch b/queue-6.12/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch new file mode 100644 index 0000000000..9dee1be383 --- /dev/null +++ b/queue-6.12/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch @@ -0,0 +1,62 @@ +From eace429d42bbff2aa2557fa49842b196eb23a680 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:33 -0700 +Subject: ethtool: eeprom: add more safeties to EEPROM Netlink fallback + +From: Jakub Kicinski + +[ Upstream commit 67cfdd9210b99f260b3e0afeb9525e0acc7be31e ] + +The Netlink fallback path for reading module EEPROM +(fallback_set_params()) validates that offset < eeprom_len, +but does not check that offset + length stays within eeprom_len. +The ioctl equivalent (ethtool_get_any_eeprom() in ioctl.c) has +always enforced both bounds: + + if (eeprom.offset + eeprom.len > total_len) + return -EINVAL; + +This could lead to surprises in both drivers and device FW. +Add the missing offset + length validation to fallback_set_params(), +mirroring the ioctl. + +Similarly - ethtool core in general, and ethtool_get_any_eeprom() +in particular tries to zero-init all buffers passed to the drivers +to avoid any extra work of zeroing things out. eeprom_fallback() +uses a plain kmalloc(), change it to zalloc. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-11-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 03cb418a15823b..80af38a6c76acf 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -43,6 +43,9 @@ static int fallback_set_params(struct eeprom_req_info *request, + if (offset >= modinfo->eeprom_len) + return -EINVAL; + ++ if (length > modinfo->eeprom_len - offset) ++ return -EINVAL; ++ + eeprom->cmd = ETHTOOL_GMODULEEEPROM; + eeprom->len = length; + eeprom->offset = offset; +@@ -68,7 +71,7 @@ static int eeprom_fallback(struct eeprom_req_info *request, + if (err < 0) + return err; + +- data = kmalloc(eeprom.len, GFP_KERNEL); ++ data = kzalloc(eeprom.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + err = ethtool_get_module_eeprom_call(dev, &eeprom, data); +-- +2.53.0 + diff --git a/queue-6.12/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch b/queue-6.12/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch new file mode 100644 index 0000000000..a592edcb95 --- /dev/null +++ b/queue-6.12/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch @@ -0,0 +1,43 @@ +From c9c55cdbc9d68d28c4942b316acd0c34051b286f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:26 -0700 +Subject: ethtool: linkstate: fix unbalanced ethnl_ops_complete() on PHY lookup + error + +From: Jakub Kicinski + +[ Upstream commit 596c51ed9e125b12c4d85b4530dfd4c7847634b7 ] + +linkstate_prepare_data() calls ethnl_req_get_phydev() before +ethnl_ops_begin(), but routes its error path through "goto out" +which calls ethnl_ops_complete(). + +Fixes: fe55b1d401c6 ("ethtool: linkstate: migrate linkstate functions to support multi-PHY setups") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-4-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/linkstate.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/linkstate.c b/net/ethtool/linkstate.c +index 05a5f72c99fab1..3dc52a39d34525 100644 +--- a/net/ethtool/linkstate.c ++++ b/net/ethtool/linkstate.c +@@ -105,10 +105,8 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base, + + phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER, + info->extack); +- if (IS_ERR(phydev)) { +- ret = PTR_ERR(phydev); +- goto out; +- } ++ if (IS_ERR(phydev)) ++ return PTR_ERR(phydev); + + ret = ethnl_ops_begin(dev); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-6.12/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch b/queue-6.12/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch new file mode 100644 index 0000000000..5b4838f176 --- /dev/null +++ b/queue-6.12/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch @@ -0,0 +1,50 @@ +From ecce56fee8e68bba693ca2a51c13cb0a8d90ae9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:05 -0700 +Subject: ethtool: module: avoid leaking a netdev ref on module flash errors + +From: Jakub Kicinski + +[ Upstream commit fb7f511d62692661846c47f199e0afe25c2982db ] + +module_flash_fw_schedule() is missing undo for setting +the "in_progress" flag and taking the netdev reference. +Delay taking these, the device can't disappear while +we are holding rtnl_lock. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-3-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 6988e07bdcd6d4..76d13ef4ba0427 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -318,8 +318,6 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + if (err < 0) + goto err_release_firmware; + +- dev->ethtool->module_fw_flash_in_progress = true; +- netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL); + fw_update->dev = dev; + fw_update->ntf_params.portid = info->snd_portid; + fw_update->ntf_params.seq = info->snd_seq; +@@ -334,6 +332,9 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + if (err < 0) + goto err_release_firmware; + ++ dev->ethtool->module_fw_flash_in_progress = true; ++ netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL); ++ + schedule_work(&module_fw->work); + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch b/queue-6.12/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch new file mode 100644 index 0000000000..be67e2d108 --- /dev/null +++ b/queue-6.12/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch @@ -0,0 +1,56 @@ +From 97b374a40553467f255faf43f38484155f16857f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:07 -0700 +Subject: ethtool: module: check fw_flash_in_progress under rtnl_lock + +From: Jakub Kicinski + +[ Upstream commit 504eaefa44c8dec50f7499edcb36d24f3aefab2a ] + +ethnl_set_module_validate() inspects module_fw_flash_in_progress +but validate is meant for _input_ validation, not state validation. +rtnl_lock is not held, yet. Move the check into ethnl_set_module(). + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 76d13ef4ba0427..ab1e8a83acd0b1 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -119,12 +119,6 @@ ethnl_set_module_validate(struct ethnl_req_info *req_info, + if (!tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]) + return 0; + +- if (req_info->dev->ethtool->module_fw_flash_in_progress) { +- NL_SET_ERR_MSG(info->extack, +- "Module firmware flashing is in progress"); +- return -EBUSY; +- } +- + if (!ops->get_module_power_mode || !ops->set_module_power_mode) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY], +@@ -147,6 +141,12 @@ ethnl_set_module(struct ethnl_req_info *req_info, struct genl_info *info) + + ops = dev->ethtool_ops; + ++ if (dev->ethtool->module_fw_flash_in_progress) { ++ NL_SET_ERR_MSG(info->extack, ++ "Module firmware flashing is in progress"); ++ return -EBUSY; ++ } ++ + power_new.policy = nla_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]); + ret = ops->get_module_power_mode(dev, &power, info->extack); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-6.12/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch b/queue-6.12/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch new file mode 100644 index 0000000000..0b0971aa94 --- /dev/null +++ b/queue-6.12/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch @@ -0,0 +1,105 @@ +From e1fa51ed09dcfa83fcecf69b928831a72149f740 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:08 -0700 +Subject: ethtool: module: fix cleanup if socket used for flashing multiple + devices + +From: Jakub Kicinski + +[ Upstream commit 760d04ebad5c4304f22c0d2251c9623b87a117c8 ] + +When a single Netlink socket issues MODULE_FW_FLASH_ACT against multiple +devices, ethnl_sock_priv_set() overwrites sk_priv->dev on each call, +retaining only the last one. The socket priv is used on socket close, +to walk the global work list and mark the uncompleted flashing work +as "orphaned". Otherwise if another socket reuses the PID it will +unexpectedly receive the flashing notifications. + +Don't record the device, record net pointer instead. The purpose of +the dev is to scope the work to a netns, anyway. If we store netns +the overrides are safe/a nop since all flashed devices must be in +the same netns as the socket. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 9 ++++----- + net/ethtool/netlink.c | 4 ++-- + net/ethtool/netlink.h | 4 ++-- + 3 files changed, 8 insertions(+), 9 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index ab1e8a83acd0b1..5a08c320b4660d 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -282,11 +282,9 @@ void ethnl_module_fw_flash_sock_destroy(struct ethnl_sock_priv *sk_priv) + + spin_lock(&module_fw_flash_work_list_lock); + list_for_each_entry(work, &module_fw_flash_work_list, list) { +- if (work->fw_update.dev == sk_priv->dev && +- work->fw_update.ntf_params.portid == sk_priv->portid) { ++ if (work->fw_update.ntf_params.portid == sk_priv->portid && ++ dev_net(work->fw_update.dev) == sk_priv->net) + work->fw_update.ntf_params.closed_sock = true; +- break; +- } + } + spin_unlock(&module_fw_flash_work_list_lock); + } +@@ -323,7 +321,8 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + fw_update->ntf_params.seq = info->snd_seq; + fw_update->ntf_params.closed_sock = false; + +- err = ethnl_sock_priv_set(skb, dev, fw_update->ntf_params.portid, ++ err = ethnl_sock_priv_set(skb, dev_net(dev), ++ fw_update->ntf_params.portid, + ETHTOOL_SOCK_TYPE_MODULE_FW_FLASH); + if (err < 0) + goto err_release_firmware; +diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c +index a52be67139d0ac..409b4109940b7c 100644 +--- a/net/ethtool/netlink.c ++++ b/net/ethtool/netlink.c +@@ -50,7 +50,7 @@ const struct nla_policy ethnl_header_policy_phy_stats[] = { + [ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1), + }; + +-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, ++int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid, + enum ethnl_sock_type type) + { + struct ethnl_sock_priv *sk_priv; +@@ -59,7 +59,7 @@ int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, + if (IS_ERR(sk_priv)) + return PTR_ERR(sk_priv); + +- sk_priv->dev = dev; ++ sk_priv->net = net; + sk_priv->portid = portid; + sk_priv->type = type; + +diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h +index 5e176938d6d228..11843bd10bcade 100644 +--- a/net/ethtool/netlink.h ++++ b/net/ethtool/netlink.h +@@ -315,12 +315,12 @@ enum ethnl_sock_type { + }; + + struct ethnl_sock_priv { +- struct net_device *dev; ++ struct net *net; + u32 portid; + enum ethnl_sock_type type; + }; + +-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, ++int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid, + enum ethnl_sock_type type); + + /** +-- +2.53.0 + diff --git a/queue-6.12/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch b/queue-6.12/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch new file mode 100644 index 0000000000..4f3ebe866c --- /dev/null +++ b/queue-6.12/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch @@ -0,0 +1,59 @@ +From d87e38cb504e75d198e622156e79c9804c30b718 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:27 -0700 +Subject: ethtool: pse-pd: fix missing ethnl_ops_complete() + +From: Jakub Kicinski + +[ Upstream commit ab5bf428fb6bd361163c7247b92750d1d24ca2ed ] + +pse_prepare_data() is missing ethnl_ops_complete() if +ethnl_req_get_phydev() returned an error. Move getting +phydev up so that we don't have to worry about this +(similar order to linkstate_prepare_data()). + +Note that phydev may still be NULL (this is checked in +pse_get_pse_attributes()), the goal isn't really to avoid +the _begin() / _complete() calls, only to simplify the error +handling. + +While at it propagate the original error. Why this code +overrides the error with -ENODEV but !phydev generates +-EOPNOTSUPP is unclear to me... + +Fixes: 31748765bed3 ("net: ethtool: pse-pd: Target the command to the requested PHY") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/pse-pd.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c +index 71843de832cca7..01517c53113def 100644 +--- a/net/ethtool/pse-pd.c ++++ b/net/ethtool/pse-pd.c +@@ -60,14 +60,14 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base, + struct phy_device *phydev; + int ret; + +- ret = ethnl_ops_begin(dev); +- if (ret < 0) +- return ret; +- + phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER, + info->extack); + if (IS_ERR(phydev)) +- return -ENODEV; ++ return PTR_ERR(phydev); ++ ++ ret = ethnl_ops_begin(dev); ++ if (ret < 0) ++ return ret; + + ret = pse_get_pse_attributes(phydev, info->extack, data); + +-- +2.53.0 + diff --git a/queue-6.12/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch b/queue-6.12/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch new file mode 100644 index 0000000000..ec00a0cd12 --- /dev/null +++ b/queue-6.12/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch @@ -0,0 +1,47 @@ +From cc79b6df73ae96027b1531931f0e6aa6c979ca41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:46 -0700 +Subject: ethtool: rss: fix hkey leak when indir_size is 0 + +From: Jakub Kicinski + +[ Upstream commit 78ccf1a70c6378e1f5073a8c2209b5129067b925 ] + +rss_get_data_alloc() allocates a single buffer that backs both the +indirection table and the hash key, but only assigned data->indir_table +when indir_size was nonzero. The expectation was that no driver +implements RSS without supporting indirection table but apparently +enic does just that (it's the only such in-tree driver). +enic has get_rxfh_key_size but no get_rxfh_indir_size. +data->indir_table stays as NULL, hkey gets set but rss_get_data_free() +kfree(data->indir_table) is a nop and the allocation leaks. + +Always store the allocation base in data->indir_table so the free path +is unambiguous. No caller treats indir_table as a sentinel; everything +keys off indir_size. + +Fixes: 7112a04664bf ("ethtool: add netlink based get rss support") +Link: https://patch.msgid.link/20260522230647.1705600-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 8aa45f3fdfdf08..3570d58c5cca6d 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -78,8 +78,7 @@ rss_prepare_get(const struct rss_req_info *request, struct net_device *dev, + goto out_ops; + } + +- if (data->indir_size) +- data->indir_table = (u32 *)rss_config; ++ data->indir_table = (u32 *)rss_config; + if (data->hkey_size) + data->hkey = rss_config + indir_bytes; + +-- +2.53.0 + diff --git a/queue-6.12/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch b/queue-6.12/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch new file mode 100644 index 0000000000..aa9f0b40a8 --- /dev/null +++ b/queue-6.12/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch @@ -0,0 +1,42 @@ +From 2f5ec54271a0eada7e7c8c5e819d0923c0b17ce8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:31 -0700 +Subject: ethtool: strset: fix header attribute index in ethnl_req_get_phydev() + +From: Jakub Kicinski + +[ Upstream commit a8d8bef6b45bf7cc0b1f6110c5cd8d0160a9bad7 ] + +strset_prepare_data() passes ETHTOOL_A_HEADER_FLAGS (3) as the header +attribute to ethnl_req_get_phydev(). This is incorrect, in the main +attr space 3 is ETHTOOL_A_STRSET_COUNTS_ONLY, not the request +header attr. The correct constant is ETHTOOL_A_STRSET_HEADER (1). + +ethnl_req_get_phydev() only uses this value for the extack, +so this is not a "functionally visible"(?) bug. + +Fixes: e96c93aa4be9 ("net: ethtool: strset: Allow querying phy stats by index") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-9-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/strset.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c +index b9400d18f01d58..73597f0bc923a3 100644 +--- a/net/ethtool/strset.c ++++ b/net/ethtool/strset.c +@@ -299,7 +299,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base, + return 0; + } + +- phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS, ++ phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STRSET_HEADER, + info->extack); + + /* phydev can be NULL, check for errors only */ +-- +2.53.0 + diff --git a/queue-6.12/gpio-mxc-fix-irq_high-handling.patch b/queue-6.12/gpio-mxc-fix-irq_high-handling.patch new file mode 100644 index 0000000000..8a413baf4b --- /dev/null +++ b/queue-6.12/gpio-mxc-fix-irq_high-handling.patch @@ -0,0 +1,38 @@ +From d06b6fb2d6a16285e12b133c9a3e2efd9f1e060f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:01 +0200 +Subject: gpio: mxc: fix irq_high handling + +From: Alexander Stein + +[ Upstream commit dac917ed5aead741004db8d0d5151dd577802df8 ] + +If port->irq_high is -1 (fsl,imx21-gpio compatible) and gpio_idx is >= 16 +enable_irq_wake() is called with -1 which is wrong. + +Fixes: 5f6d1998adeb ("gpio: mxc: release the parent IRQ in runtime suspend") +Signed-off-by: Alexander Stein +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260526063504.25916-1-alexander.stein@ew.tq-group.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mxc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c +index 3cdc2b218a86af..a8ab78ae7fa30c 100644 +--- a/drivers/gpio/gpio-mxc.c ++++ b/drivers/gpio/gpio-mxc.c +@@ -473,7 +473,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) + * the handler is needed only once, but doing it for every port + * is more robust and easier. + */ +- port->irq_high = -1; ++ port->irq_high = 0; + port->mx_irq_handler = mx2_gpio_irq_handler; + } else + port->mx_irq_handler = mx3_gpio_irq_handler; +-- +2.53.0 + diff --git a/queue-6.12/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch b/queue-6.12/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch new file mode 100644 index 0000000000..65d61253f4 --- /dev/null +++ b/queue-6.12/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch @@ -0,0 +1,78 @@ +From d1aae623768e071f3095ecc7b4a0b90aa914e851 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:45 +0200 +Subject: gpio: rockchip: convert bank->clk to devm_clk_get_enabled() + +From: Marco Scardovi + +[ Upstream commit 3e46c18d5d87f063a93ae0fe7662fbf6660459d5 ] + +The bank->clk was previously obtained via of_clk_get() and manually +prepared/enabled. However, it was missing a corresponding clk_put() in +both the error paths and the remove function, leading to a reference leak. + +Convert the allocation to devm_clk_get_enabled(), which also properly +propagates failures from clk_prepare_enable() that were previously ignored. + +The GPIO bank device uses the same OF node as the previous of_clk_get() +call, so devm_clk_get_enabled(dev, NULL) correctly resolves the same +clock provider entry. + +Fix the reference leak and simplify the code by removing the manual +clk_disable_unprepare() calls in the probe error paths and in the +remove function. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index 4e2132c80be32a..052713bd8d07a9 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -647,11 +647,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + if (!bank->irq) + return -EINVAL; + +- bank->clk = of_clk_get(bank->of_node, 0); ++ bank->clk = devm_clk_get_enabled(bank->dev, NULL); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + +- clk_prepare_enable(bank->clk); + id = readl(bank->reg_base + gpio_regs_v2.version_id); + + /* If not gpio v2, that is default to v1. */ +@@ -661,7 +660,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + bank->db_clk = of_clk_get(bank->of_node, 1); + if (IS_ERR(bank->db_clk)) { + dev_err(bank->dev, "cannot find debounce clk\n"); +- clk_disable_unprepare(bank->clk); + return -EINVAL; + } + } else { +@@ -735,7 +733,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev) + + ret = rockchip_gpiolib_register(bank); + if (ret) { +- clk_disable_unprepare(bank->clk); + mutex_unlock(&bank->deferred_lock); + return ret; + } +@@ -776,7 +773,6 @@ static void rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + +- clk_disable_unprepare(bank->clk); + gpiochip_remove(&bank->gpio_chip); + } + +-- +2.53.0 + diff --git a/queue-6.12/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch b/queue-6.12/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch new file mode 100644 index 0000000000..0c97a0249e --- /dev/null +++ b/queue-6.12/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch @@ -0,0 +1,49 @@ +From e8a0ef3e4d01ecf7c6b89f1ef4a52b96e3fc1fc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 10:15:16 +0300 +Subject: gpio: virtuser: Fix uninitialized data bug in + gpio_virtuser_direction_do_write() + +From: Dan Carpenter + +[ Upstream commit 8a122b5e72cc0043705f0d524bcd15f0c0b3ec15 ] + +If *ppos is non-zero (user-space write split over multiple calls to +write()) then simple_write_to_buffer() won't initialize the start of the +buffer. Really, non-zero values for *ppos aren't going to work at all. +Check for that and return -EINVAL at the start of the function. + +Fixes: 91581c4b3f29 ("gpio: virtuser: new virtual testing driver for the GPIO API") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/ahP3BJWWy-m_qI0X@stanley.mountain +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-virtuser.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c +index 8a313dd624c26e..ff1977b2699144 100644 +--- a/drivers/gpio/gpio-virtuser.c ++++ b/drivers/gpio/gpio-virtuser.c +@@ -400,7 +400,7 @@ static ssize_t gpio_virtuser_direction_do_write(struct file *file, + char buf[32], *trimmed; + int ret, dir, val = 0; + +- if (count >= sizeof(buf)) ++ if (*ppos != 0 || count >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +@@ -627,7 +627,7 @@ static ssize_t gpio_virtuser_consumer_write(struct file *file, + char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 2]; + int ret; + +- if (count >= sizeof(buf)) ++ if (*ppos != 0 || count >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, GPIO_VIRTUSER_NAME_BUF_LEN, ppos, +-- +2.53.0 + diff --git a/queue-6.12/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch b/queue-6.12/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch new file mode 100644 index 0000000000..90f577c003 --- /dev/null +++ b/queue-6.12/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch @@ -0,0 +1,48 @@ +From b85bcdd734c195cd86e91ea415c8cb2b48d20683 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 12:21:47 +0000 +Subject: ipv4: free net->ipv4.sysctl_local_reserved_ports after + unregister_net_sysctl_table() + +From: Eric Dumazet + +[ Upstream commit 87a1e0fe7776da7ab411be332b4be58ac8840d10 ] + +ipv4_sysctl_exit_net() is currently freeing net->ipv4.sysctl_local_reserved_ports +too soon. + +Only after unregister_net_sysctl_table() we can be sure no threads can possibly +use the sysctls, including /proc/sys/net/ipv4/ip_local_reserved_ports. + +Fixes: 122ff243f5f1 ("ipv4: make ip_local_reserved_ports per netns") +Reported-by: Ji'an Zhou +Signed-off-by: Eric Dumazet +Cc: Cong Wang +Reviewed-by: Jason Xing +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521122147.3584624-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/sysctl_net_ipv4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 8d411cce0aedc1..35a6e7d8f52f7e 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -1630,10 +1630,10 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net) + { + const struct ctl_table *table; + +- kfree(net->ipv4.sysctl_local_reserved_ports); + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); ++ kfree(net->ipv4.sysctl_local_reserved_ports); + } + + static __net_initdata struct pernet_operations ipv4_sysctl_ops = { +-- +2.53.0 + diff --git a/queue-6.12/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch b/queue-6.12/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch new file mode 100644 index 0000000000..1987652786 --- /dev/null +++ b/queue-6.12/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch @@ -0,0 +1,49 @@ +From 0c667bf1831d8bd1afb0b20048bae0657bc19b0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:31 +0800 +Subject: ipv6: fix possible infinite loop in fib6_select_path() + +From: Jiayuan Chen + +[ Upstream commit 9c7da87c2dc860bb17ca1ece942495d28b1ce3b9 ] + +Found while auditing the same pattern Sashiko reported in +rt6_fill_node() [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&first->fib6_siblings) +without waiting for RCU readers; first->fib6_siblings.next then +still points into the old ring and this softirq-side walker never +reaches &first->fib6_siblings as its terminator. fib6_purge_rt() +always WRITE_ONCE()s first->fib6_nsiblings to 0 before +list_del_rcu(), so an inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index c73218fd82c615..9e7470e8154429 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -482,6 +482,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res, + const struct fib6_nh *nh = sibling->fib6_nh; + int nh_upper_bound; + ++ if (!READ_ONCE(first->fib6_nsiblings)) ++ break; ++ + nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); + if (hash > nh_upper_bound) + continue; +-- +2.53.0 + diff --git a/queue-6.12/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch b/queue-6.12/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch new file mode 100644 index 0000000000..929a9686d5 --- /dev/null +++ b/queue-6.12/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch @@ -0,0 +1,47 @@ +From eadfc481d6f6a107bce2837ee1f4423d95b0730a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:30 +0800 +Subject: ipv6: fix possible infinite loop in rt6_fill_node() + +From: Jiayuan Chen + +[ Upstream commit 9f72412bcf60144f252b0d6205106abf14344abc ] + +Sashiko reported this issue [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&rt->fib6_siblings) +without waiting for RCU readers; rt->fib6_siblings.next then still +points into the old ring and this softirq-side walker never reaches +&rt->fib6_siblings, causing a CPU stall. fib6_del_route() always +WRITE_ONCE()s rt->fib6_nsiblings to 0 before list_del_rcu(), so an +inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 31c9e3b73f2da1..c73218fd82c615 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -5812,6 +5812,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, + + goto nla_put_failure; + } ++ if (!READ_ONCE(rt->fib6_nsiblings)) ++ break; + } + + rcu_read_unlock(); +-- +2.53.0 + diff --git a/queue-6.12/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch b/queue-6.12/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch new file mode 100644 index 0000000000..e40e5717c8 --- /dev/null +++ b/queue-6.12/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch @@ -0,0 +1,62 @@ +From 5fe5a7749f8348b1f29eecadcf936692b1efc613 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 21:10:31 +0530 +Subject: ipv6: rpl: fix hdrlen overflow in ipv6_rpl_srh_decompress() + +From: Rahul Chandelkar + +[ Upstream commit 9d5e7a46a9f6d8f503b41bfefef70659845f1679 ] + +ipv6_rpl_srh_decompress() computes: + + outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3); + +hdrlen is __u8. For n >= 127 the result exceeds 255 and silently +truncates. With n=127 (cmpri=15, cmpre=15, pad=0, hdrlen=16): + + (128 * 16) >> 3 = 256, truncated to 0 as __u8 + +The caller in ipv6_rpl_srh_rcv() then places the compressed header +at buf + ((ohdr->hdrlen + 1) << 3). With hdrlen=0 this is buf + 8, +but the decompressed region occupies buf[0..2055] (8-byte header +plus 128 full addresses). The compressed header overlaps the +decompressed data, and ipv6_rpl_srh_compress() writes into this +overlap, corrupting the routing header of the forwarded packet. + +The existing guard at exthdrs.c:546 checks (n + 1) > 255, which +prevents n+1 from overflowing unsigned char (the segments_left +field), but does not prevent the computed hdrlen from overflowing +__u8. n=127 passes because 128 <= 255, yet hdrlen=256 does not +fit. + +Tighten the bound to (n + 1) > 127. This caps n at 126, giving +hdrlen = (127 * 16) >> 3 = 254, which fits in __u8. The compressed +header then lands at buf + ((254 + 1) << 3) = buf + 2040, exactly +past the decompressed region (buf[0..2039]). No overlap. 127 +segments is well beyond any realistic RPL deployment. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Signed-off-by: Rahul Chandelkar +Link: https://patch.msgid.link/20260525154031.2290876-1-rc@rexion.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/exthdrs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 5ef6fbc66beb11..43e34fe448ffe5 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -546,7 +546,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + * unsigned char which is segments_left field. Should not be + * higher than that. + */ +- if (r || (n + 1) > 255) { ++ if (r || (n + 1) > 127) { + kfree_skb(skb); + return -1; + } +-- +2.53.0 + diff --git a/queue-6.12/kernel-fork-validate-exit_signal-in-kernel_clone.patch b/queue-6.12/kernel-fork-validate-exit_signal-in-kernel_clone.patch new file mode 100644 index 0000000000..92079d7824 --- /dev/null +++ b/queue-6.12/kernel-fork-validate-exit_signal-in-kernel_clone.patch @@ -0,0 +1,116 @@ +From a82d548757479b3ca17d9a83621823a9b630a9c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 20:49:56 +0530 +Subject: kernel/fork: validate exit_signal in kernel_clone() + +From: Deepanshu Kartikey + +[ Upstream commit 09e7827e785729f391c8d46dc71becce70d296ab ] + +When a child process exits, it sends exit_signal to its parent via +do_notify_parent(). The clone() syscall constructs exit_signal as: + +(lower_32_bits(clone_flags) & CSIGNAL) + +CSIGNAL is 0xff, so values in the range 65-255 are possible. However, +valid_signal() only accepts signals up to _NSIG (64 on x86_64). A +non-zero non-valid exit_signal acts the same as exit_signal == 0: the +parent process is not signaled when the child terminates. + +The syzkaller reproducer triggers this by calling clone() with flags=0x80, +resulting in exit_signal = (0x80 & CSIGNAL) = 128, which exceeds _NSIG and +is not a valid signal. + +The v1 of this patch added the check only in the clone() syscall handler, +which is incomplete. kernel_clone() has other callers such as +sys_ia32_clone() which would remain unprotected. Move the check to +kernel_clone() to cover all callers. + +Since the valid_signal() check is now in kernel_clone() and covers all +callers including clone3(), the same check in copy_clone_args_from_user() +becomes redundant and is removed. The higher 32bits check for clone3() is +kept as it is clone3() specific. + +Note that this is a user-visible change: previously, passing an invalid +exit_signal to clone() was silently accepted. The man page for clone() +does not document any defined behavior for invalid exit_signal values, so +rejecting them with -EINVAL is the correct behavior. It is unlikely that +any sane application relies on passing an invalid exit_signal. + +[oleg@redhat.com: the comment above kernel_clone() should be updated] + Link: https://lore.kernel.org/abwvgU17W8wuW2-J@redhat.com +Link: https://lore.kernel.org/20260316151956.563558-1-kartikey406@gmail.com +Fixes: 3f2c788a1314 ("fork: prevent accidental access to clone3 features") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Oleg Nesterov +Reported-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=bbe6b99feefc3a0842de +Tested-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20260307064202.353405-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20260316104536.558108-1-kartikey406@gmail.com/T/ [v2] +Acked-by: Oleg Nesterov +Acked-by: Michal Hocko +Cc: Ben Segall +Cc: Christian Brauner +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Cc: Tetsuo Handa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index c4955cffcb6f4e..1f306743832b3e 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -2773,8 +2773,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node) + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. +- * +- * args->exit_signal is expected to be checked for sanity by the caller. + */ + pid_t kernel_clone(struct kernel_clone_args *args) + { +@@ -2799,6 +2797,9 @@ pid_t kernel_clone(struct kernel_clone_args *args) + (args->pidfd == args->parent_tid)) + return -EINVAL; + ++ if (!valid_signal(args->exit_signal)) ++ return -EINVAL; ++ + /* + * Determine whether and which event to report to ptracer. When + * called from kernel_thread or CLONE_UNTRACED is explicitly +@@ -2999,11 +3000,9 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs, + return -EINVAL; + + /* +- * Verify that higher 32bits of exit_signal are unset and that +- * it is a valid signal ++ * Verify that higher 32bits of exit_signal are unset + */ +- if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) || +- !valid_signal(args.exit_signal))) ++ if (unlikely(args.exit_signal & ~((u64)CSIGNAL))) + return -EINVAL; + + if ((args.flags & CLONE_INTO_CGROUP) && +-- +2.53.0 + diff --git a/queue-6.12/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch b/queue-6.12/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch new file mode 100644 index 0000000000..1bfd76f837 --- /dev/null +++ b/queue-6.12/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch @@ -0,0 +1,110 @@ +From da3f684ae417a67b4727c5f4f7fd96d3860085bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 10:48:54 +0200 +Subject: kunit: fix use-after-free in debugfs when using kunit.filter + +From: Florian Schmaus + +[ Upstream commit fb6988b83b4cafe8db63999c1ddff1b7c66d2ff5 ] + +When the kernel is booted with a kunit filter (e.g., +kunit.filter="speed!=slow"), the kunit executor dynamically allocates +copies of the filtered test suites using kmalloc/kmemdup. + +During the initial boot execution, kunit_debugfs_create_suite() creates +debugfs files (such as /sys/kernel/debug/kunit//run) and +permanently stores a pointer to the dynamically allocated suite in the +inode's i_private field. + +Previously, the executor freed this dynamically allocated suite_set +immediately after executing the boot-time tests. Because the debugfs +nodes were not destroyed, any subsequent interaction with the debugfs +`run` file from userspace triggered a use-after-free (UAF). On systems +with architectural capabilities, like CHERI RISC-V, this resulted in +an immediate fatal hardware exception due to the invalidation of the +capability tags on the reclaimed memory. On other architectures, it +resulted in silent memory corruption. + +Fix this UAF by properly coupling the lifetime of the filtered suite +memory allocation to the lifetime of the kunit subsystem and its +associated VFS nodes. Ownership of the boot-time suite_set is now +transferred to a global tracker ('kunit_boot_suites'), and the memory +is cleanly released in kunit_exit() during module teardown. + +Link: https://lore.kernel.org/r/20260507084854.233984-1-florian.schmaus@codasip.com +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: Florian Schmaus +Reviewed-by: Martin Kaiser +Reviewed-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + include/kunit/test.h | 1 + + lib/kunit/executor.c | 19 ++++++++++++++++--- + lib/kunit/test.c | 1 + + 3 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/include/kunit/test.h b/include/kunit/test.h +index 34b71e42fb107c..6132faa314fcb8 100644 +--- a/include/kunit/test.h ++++ b/include/kunit/test.h +@@ -547,6 +547,7 @@ unsigned long kunit_vm_mmap(struct kunit *test, struct file *file, + unsigned long offset); + + void kunit_cleanup(struct kunit *test); ++void kunit_free_boot_suites(void); + + void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...); + +diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c +index 34b7b6833df3d5..7cd1c87eb2edfb 100644 +--- a/lib/kunit/executor.c ++++ b/lib/kunit/executor.c +@@ -15,6 +15,16 @@ extern struct kunit_suite * const __kunit_suites_end[]; + extern struct kunit_suite * const __kunit_init_suites_start[]; + extern struct kunit_suite * const __kunit_init_suites_end[]; + ++static struct kunit_suite_set kunit_boot_suites; ++ ++void kunit_free_boot_suites(void) ++{ ++ if (kunit_boot_suites.start) { ++ kunit_free_suite_set(kunit_boot_suites); ++ kunit_boot_suites = (struct kunit_suite_set){ NULL, NULL }; ++ } ++} ++ + static char *action_param; + + module_param_named(action, action_param, charp, 0400); +@@ -392,9 +402,12 @@ int kunit_run_all_tests(void) + pr_err("kunit executor: unknown action '%s'\n", action_param); + + free_out: +- if (filter_glob_param || filter_param) +- kunit_free_suite_set(suite_set); +- else if (init_num_suites > 0) ++ if (filter_glob_param || filter_param) { ++ if (err) ++ kunit_free_suite_set(suite_set); ++ else ++ kunit_boot_suites = suite_set; ++ } else if (init_num_suites > 0) + /* Don't use kunit_free_suite_set because suites aren't individually allocated */ + kfree(suite_set.start); + +diff --git a/lib/kunit/test.c b/lib/kunit/test.c +index 089c832e3cdbd5..b808826e6de2cf 100644 +--- a/lib/kunit/test.c ++++ b/lib/kunit/test.c +@@ -954,6 +954,7 @@ static void __exit kunit_exit(void) + kunit_bus_shutdown(); + + kunit_debugfs_cleanup(); ++ kunit_free_boot_suites(); + } + module_exit(kunit_exit); + +-- +2.53.0 + diff --git a/queue-6.12/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch b/queue-6.12/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch new file mode 100644 index 0000000000..88de68c22a --- /dev/null +++ b/queue-6.12/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch @@ -0,0 +1,102 @@ +From 4f491a1ffae73fe0d638ea5ee51e151c69b23ab5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 14:06:40 +0200 +Subject: net: Avoid checksumming unreadable skb tail on trim +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Björn Töpel + +[ Upstream commit 2e357f002c61fd76fd8f12468744a06a5ec48eaa ] + +pskb_trim_rcsum_slow() keeps CHECKSUM_COMPLETE valid by subtracting +the checksum of the bytes removed from the skb tail. That assumes the +removed bytes can be read. + +io_uring zcrx skbs may contain unreadable net_iov frags. With fbnic +header/data split, small TCP/IPv4 packets can carry Ethernet padding +in such a frag. ip_rcv_core() trims the skb to iph->tot_len before TCP +sees it, and the CHECKSUM_COMPLETE adjustment then calls +skb_checksum() on the padding. + +This is exposed by IPv4 because small TCP/IPv4 frames can be shorter +than the Ethernet minimum payload. TCP/IPv6 frames are large enough in +the normal zcrx path, so they do not hit the same padding trim. + +Keep the existing checksum adjustment for readable skbs. If the +remaining packet is fully linear, drop CHECKSUM_COMPLETE and let the +stack validate the packet after trimming. If unreadable payload would +remain, fail the trim; the checksum cannot be adjusted without reading +the trimmed tail. + +Also clear skb->unreadable when trimming removes all frags. + +Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags") +Signed-off-by: Björn Töpel +Reviewed-by: Breno Leitao +Link: https://patch.msgid.link/20260522120643.242974-1-bjorn@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 31 +++++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index aa9e9148847363..8c9f026182a6f0 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -2765,6 +2765,8 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) + skb->data_len = 0; + skb_set_tail_pointer(skb, len); + } ++ if (!skb_shinfo(skb)->nr_frags && !skb_has_frag_list(skb)) ++ skb->unreadable = 0; + + if (!skb->sk || skb->destructor == sock_edemux) + skb_condense(skb); +@@ -2772,16 +2774,37 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) + } + EXPORT_SYMBOL(___pskb_trim); + ++static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len) ++{ ++ int delta = skb->len - len; ++ ++ if (skb_frags_readable(skb)) { ++ skb->csum = csum_block_sub(skb->csum, ++ skb_checksum(skb, len, delta, 0), ++ len); ++ return 0; ++ } ++ ++ if (len > skb_headlen(skb)) ++ return -EFAULT; ++ ++ /* The trimmed bytes are unreadable, but the remaining packet can be ++ * checksummed by software after trimming. ++ */ ++ skb->ip_summed = CHECKSUM_NONE; ++ return 0; ++} ++ + /* Note : use pskb_trim_rcsum() instead of calling this directly + */ + int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len) + { + if (skb->ip_summed == CHECKSUM_COMPLETE) { +- int delta = skb->len - len; ++ int err; + +- skb->csum = csum_block_sub(skb->csum, +- skb_checksum(skb, len, delta, 0), +- len); ++ err = pskb_trim_rcsum_complete(skb, len); ++ if (err) ++ return err; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + int hdlen = (len > skb_headlen(skb)) ? skb_headlen(skb) : len; + int offset = skb_checksum_start_offset(skb) + skb->csum_offset; +-- +2.53.0 + diff --git a/queue-6.12/net-ethtool-add-new-parameters-and-a-function-to-sup.patch b/queue-6.12/net-ethtool-add-new-parameters-and-a-function-to-sup.patch new file mode 100644 index 0000000000..7ad55f8f15 --- /dev/null +++ b/queue-6.12/net-ethtool-add-new-parameters-and-a-function-to-sup.patch @@ -0,0 +1,203 @@ +From ef3d0abad78355d2c1d9a1832b2540b666451d9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Oct 2024 13:53:46 +0300 +Subject: net: ethtool: Add new parameters and a function to support EPL + +From: Danielle Ratson + +[ Upstream commit edc344568922eb9588e77ba49de1ef0cb9a2ff1c ] + +In the CMIS specification for pluggable modules, LPL (Local Payload) and +EPL (Extended Payload) are two types of data payloads used for managing +various functions and features of the module. + +EPL payloads are used for more complex and extensive management +functions that require a larger amount of data, so writing firmware +blocks using EPL is much more efficient. + +Currently, only LPL payload is supported for writing firmware blocks to +the module. + +Add EPL related parameters to the function ethtool_cmis_cdb_compose_args() +and add a specific function for calculating the maximum allowable length +extension for EPL. Both will be used in the next patch to add support for +writing firmware blocks using EPL. + +Signed-off-by: Danielle Ratson +Reviewed-by: Petr Machata +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Stable-dep-of: 12c2496a71f8 ("ethtool: cmis: validate start_cmd_payload_size from module") +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis.h | 12 +++++++----- + net/ethtool/cmis_cdb.c | 32 +++++++++++++++++++++----------- + net/ethtool/cmis_fw_update.c | 17 ++++++++++------- + 3 files changed, 38 insertions(+), 23 deletions(-) + +diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h +index aa32a675b8f8d2..e11e47b3f2fc8f 100644 +--- a/net/ethtool/cmis.h ++++ b/net/ethtool/cmis.h +@@ -96,13 +96,15 @@ struct ethtool_cmis_cdb_rpl { + u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH]; + }; + +-u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs); ++u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs); ++u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs); + + void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args, +- enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl, +- u8 lpl_len, u16 max_duration, +- u8 read_write_len_ext, u16 msleep_pre_rpl, +- u8 rpl_exp_len, u8 flags); ++ enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl, ++ u8 lpl_len, u8 *epl, u16 epl_len, ++ u16 max_duration, u8 read_write_len_ext, ++ u16 msleep_pre_rpl, u8 rpl_exp_len, ++ u8 flags); + + void ethtool_cmis_cdb_check_completion_flag(u8 cmis_rev, u8 *flags); + +diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c +index 690002366d965a..31142e239cf6b2 100644 +--- a/net/ethtool/cmis_cdb.c ++++ b/net/ethtool/cmis_cdb.c +@@ -11,25 +11,34 @@ + * min(i, 15) byte octets where i specifies the allowable additional number of + * byte octets in a READ or a WRITE. + */ +-u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs) ++u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs) + { + return 8 * (1 + min_t(u8, num_of_byte_octs, 15)); + } + ++/* For accessing the EPL field on page 9Fh, the allowable length extension is ++ * min(i, 255) byte octets where i specifies the allowable additional number of ++ * byte octets in a READ or a WRITE. ++ */ ++u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs) ++{ ++ return 8 * (1 + min_t(u8, num_of_byte_octs, 255)); ++} ++ + void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args, +- enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl, +- u8 lpl_len, u16 max_duration, +- u8 read_write_len_ext, u16 msleep_pre_rpl, +- u8 rpl_exp_len, u8 flags) ++ enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl, ++ u8 lpl_len, u8 *epl, u16 epl_len, ++ u16 max_duration, u8 read_write_len_ext, ++ u16 msleep_pre_rpl, u8 rpl_exp_len, u8 flags) + { + args->req.id = cpu_to_be16(cmd); + args->req.lpl_len = lpl_len; +- if (pl) +- memcpy(args->req.payload, pl, args->req.lpl_len); ++ if (lpl) ++ memcpy(args->req.payload, lpl, args->req.lpl_len); + + args->max_duration = max_duration; + args->read_write_len_ext = +- ethtool_cmis_get_max_payload_size(read_write_len_ext); ++ ethtool_cmis_get_max_lpl_size(read_write_len_ext); + args->msleep_pre_rpl = msleep_pre_rpl; + args->rpl_exp_len = rpl_exp_len; + args->flags = flags; +@@ -183,7 +192,7 @@ cmis_cdb_validate_password(struct ethtool_cmis_cdb *cdb, + } + + ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_QUERY_STATUS, +- (u8 *)&qs_pl, sizeof(qs_pl), 0, ++ (u8 *)&qs_pl, sizeof(qs_pl), NULL, 0, 0, + cdb->read_write_len_ext, 1000, + sizeof(*rpl), + CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); +@@ -245,8 +254,9 @@ static int cmis_cdb_module_features_get(struct ethtool_cmis_cdb *cdb, + ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags); + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_MODULE_FEATURES, +- NULL, 0, 0, cdb->read_write_len_ext, +- 1000, sizeof(*rpl), flags); ++ NULL, 0, NULL, 0, 0, ++ cdb->read_write_len_ext, 1000, ++ sizeof(*rpl), flags); + + err = ethtool_cmis_cdb_execute_cmd(dev, &args); + if (err < 0) { +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index 655ff5224ffa30..a514127985d44e 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -54,7 +54,8 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags); + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES, +- NULL, 0, cdb->max_completion_time, ++ NULL, 0, NULL, 0, ++ cdb->max_completion_time, + cdb->read_write_len_ext, 1000, + sizeof(*rpl), flags); + +@@ -122,7 +123,7 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, + + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD, +- (u8 *)&pl, lpl_len, ++ (u8 *)&pl, lpl_len, NULL, 0, + fw_mng->max_duration_start, + cdb->read_write_len_ext, 1000, 0, + CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); +@@ -158,7 +159,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, + int err; + + max_lpl_len = min_t(u32, +- ethtool_cmis_get_max_payload_size(cdb->read_write_len_ext), ++ ethtool_cmis_get_max_lpl_size(cdb->read_write_len_ext), + ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH); + max_block_size = + max_lpl_len - sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl, +@@ -183,7 +184,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, + + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL, +- (u8 *)&pl, lpl_len, ++ (u8 *)&pl, lpl_len, NULL, 0, + fw_mng->max_duration_write, + cdb->read_write_len_ext, 1, 0, + CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); +@@ -212,7 +213,8 @@ cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb, + + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD, +- NULL, 0, fw_mng->max_duration_complete, ++ NULL, 0, NULL, 0, ++ fw_mng->max_duration_complete, + cdb->read_write_len_ext, 1000, 0, + CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); + +@@ -294,7 +296,7 @@ cmis_fw_update_run_image(struct ethtool_cmis_cdb *cdb, struct net_device *dev, + int err; + + ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE, +- (u8 *)&pl, sizeof(pl), ++ (u8 *)&pl, sizeof(pl), NULL, 0, + cdb->max_completion_time, + cdb->read_write_len_ext, 1000, 0, + CDB_F_MODULE_STATE_VALID); +@@ -326,7 +328,8 @@ cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb, + + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE, +- NULL, 0, cdb->max_completion_time, ++ NULL, 0, NULL, 0, ++ cdb->max_completion_time, + cdb->read_write_len_ext, 1000, 0, + CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); + +-- +2.53.0 + diff --git a/queue-6.12/net-ethtool-add-support-for-writing-firmware-blocks-.patch b/queue-6.12/net-ethtool-add-support-for-writing-firmware-blocks-.patch new file mode 100644 index 0000000000..8c64c86cb7 --- /dev/null +++ b/queue-6.12/net-ethtool-add-support-for-writing-firmware-blocks-.patch @@ -0,0 +1,323 @@ +From 72b43e32aa56e2172e3d7423bf34884e809aea85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Oct 2024 13:53:47 +0300 +Subject: net: ethtool: Add support for writing firmware blocks using EPL + payload + +From: Danielle Ratson + +[ Upstream commit 9a3b0d078bd825613c0821bf7bf5a2e1d8d60057 ] + +In the CMIS specification for pluggable modules, LPL (Local Payload) and +EPL (Extended Payload) are two types of data payloads used for managing +various functions and features of the module. + +EPL payloads are used for more complex and extensive management +functions that require a larger amount of data, so writing firmware +blocks using EPL is much more efficient. + +Currently, only LPL payload is supported for writing firmware blocks to +the module. + +Add support for writing firmware block using EPL payload, both to +support modules that supports only EPL write mechanism, and to optimize +the flashing process of modules that support LPL and EPL. + +Signed-off-by: Danielle Ratson +Reviewed-by: Petr Machata +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Stable-dep-of: 12c2496a71f8 ("ethtool: cmis: validate start_cmd_payload_size from module") +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis.h | 4 ++ + net/ethtool/cmis_cdb.c | 66 ++++++++++++++++++++++++-- + net/ethtool/cmis_fw_update.c | 91 ++++++++++++++++++++++++++++++++---- + 3 files changed, 148 insertions(+), 13 deletions(-) + +diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h +index e11e47b3f2fc8f..1ab96bdd2c6f92 100644 +--- a/net/ethtool/cmis.h ++++ b/net/ethtool/cmis.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0-only */ + + #define ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH 120 ++#define ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH 2048 + #define ETHTOOL_CMIS_CDB_CMD_PAGE 0x9F + #define ETHTOOL_CMIS_CDB_PAGE_I2C_ADDR 0x50 + +@@ -23,6 +24,7 @@ enum ethtool_cmis_cdb_cmd_id { + ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES = 0x0041, + ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD = 0x0101, + ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL = 0x0103, ++ ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL = 0x0104, + ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD = 0x0107, + ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE = 0x0109, + ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE = 0x010A, +@@ -38,6 +40,7 @@ enum ethtool_cmis_cdb_cmd_id { + * @resv1: Added to match the CMIS standard request continuity. + * @resv2: Added to match the CMIS standard request continuity. + * @payload: Payload for the CDB commands. ++ * @epl: Extended payload for the CDB commands. + */ + struct ethtool_cmis_cdb_request { + __be16 id; +@@ -49,6 +52,7 @@ struct ethtool_cmis_cdb_request { + u8 resv2; + u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH]; + ); ++ u8 *epl; /* Everything above this field checksummed. */ + }; + + #define CDB_F_COMPLETION_VALID BIT(0) +diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c +index 31142e239cf6b2..606d88df31f235 100644 +--- a/net/ethtool/cmis_cdb.c ++++ b/net/ethtool/cmis_cdb.c +@@ -33,12 +33,19 @@ void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args, + { + args->req.id = cpu_to_be16(cmd); + args->req.lpl_len = lpl_len; +- if (lpl) ++ if (lpl) { + memcpy(args->req.payload, lpl, args->req.lpl_len); ++ args->read_write_len_ext = ++ ethtool_cmis_get_max_lpl_size(read_write_len_ext); ++ } ++ if (epl) { ++ args->req.epl_len = cpu_to_be16(epl_len); ++ args->req.epl = epl; ++ args->read_write_len_ext = ++ ethtool_cmis_get_max_epl_size(read_write_len_ext); ++ } + + args->max_duration = max_duration; +- args->read_write_len_ext = +- ethtool_cmis_get_max_lpl_size(read_write_len_ext); + args->msleep_pre_rpl = msleep_pre_rpl; + args->rpl_exp_len = rpl_exp_len; + args->flags = flags; +@@ -561,6 +568,49 @@ __ethtool_cmis_cdb_execute_cmd(struct net_device *dev, + return err; + } + ++#define CMIS_CDB_EPL_PAGE_START 0xA0 ++#define CMIS_CDB_EPL_PAGE_END 0xAF ++#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START 128 ++#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END 255 ++ ++static int ++ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev, ++ struct ethtool_cmis_cdb_cmd_args *args, ++ struct ethtool_module_eeprom *page_data) ++{ ++ u16 epl_len = be16_to_cpu(args->req.epl_len); ++ u32 bytes_written = 0; ++ u8 page; ++ int err; ++ ++ for (page = CMIS_CDB_EPL_PAGE_START; ++ page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len; page++) { ++ u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START; ++ ++ while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END && ++ bytes_written < epl_len) { ++ u32 bytes_left = epl_len - bytes_written; ++ u16 space_left, bytes_to_write; ++ ++ space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END - offset + 1; ++ bytes_to_write = min_t(u16, bytes_left, ++ min_t(u16, space_left, ++ args->read_write_len_ext)); ++ ++ err = __ethtool_cmis_cdb_execute_cmd(dev, page_data, ++ page, offset, ++ bytes_to_write, ++ args->req.epl + bytes_written); ++ if (err < 0) ++ return err; ++ ++ offset += bytes_to_write; ++ bytes_written += bytes_to_write; ++ } ++ } ++ return 0; ++} ++ + static u8 cmis_cdb_calc_checksum(const void *data, size_t size) + { + const u8 *bytes = (const u8 *)data; +@@ -582,7 +632,9 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev, + int err; + + args->req.chk_code = +- cmis_cdb_calc_checksum(&args->req, sizeof(args->req)); ++ cmis_cdb_calc_checksum(&args->req, ++ offsetof(struct ethtool_cmis_cdb_request, ++ epl)); + + if (args->req.lpl_len > args->read_write_len_ext) { + args->err_msg = "LPL length is longer than CDB read write length extension allows"; +@@ -604,6 +656,12 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev, + if (err < 0) + return err; + ++ if (args->req.epl_len) { ++ err = ethtool_cmis_cdb_execute_epl_cmd(dev, args, &page_data); ++ if (err < 0) ++ return err; ++ } ++ + offset = CMIS_CDB_CMD_ID_OFFSET + + offsetof(struct ethtool_cmis_cdb_request, id); + err = __ethtool_cmis_cdb_execute_cmd(dev, &page_data, +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index a514127985d44e..48aef6220f0094 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -9,6 +9,7 @@ + + struct cmis_fw_update_fw_mng_features { + u8 start_cmd_payload_size; ++ u8 write_mechanism; + u16 max_duration_start; + u16 max_duration_write; + u16 max_duration_complete; +@@ -36,7 +37,9 @@ struct cmis_cdb_fw_mng_features_rpl { + }; + + enum cmis_cdb_fw_write_mechanism { ++ CMIS_CDB_FW_WRITE_MECHANISM_NONE = 0x00, + CMIS_CDB_FW_WRITE_MECHANISM_LPL = 0x01, ++ CMIS_CDB_FW_WRITE_MECHANISM_EPL = 0x10, + CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11, + }; + +@@ -68,10 +71,9 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + } + + rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload; +- if (!(rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL || +- rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_BOTH)) { ++ if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) { + ethnl_module_fw_flash_ntf_err(dev, ntf_params, +- "Write LPL is not supported", ++ "CDB write mechanism is not supported", + NULL); + return -EOPNOTSUPP; + } +@@ -83,6 +85,10 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + */ + cdb->read_write_len_ext = rpl->read_write_len_ext; + fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size; ++ fw_mng->write_mechanism = ++ rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ? ++ CMIS_CDB_FW_WRITE_MECHANISM_LPL : ++ CMIS_CDB_FW_WRITE_MECHANISM_EPL; + fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start); + fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write); + fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete); +@@ -149,9 +155,9 @@ struct cmis_cdb_write_fw_block_lpl_pl { + }; + + static int +-cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, +- struct ethtool_cmis_fw_update_params *fw_update, +- struct cmis_fw_update_fw_mng_features *fw_mng) ++cmis_fw_update_write_image_lpl(struct ethtool_cmis_cdb *cdb, ++ struct ethtool_cmis_fw_update_params *fw_update, ++ struct cmis_fw_update_fw_mng_features *fw_mng) + { + u8 start = fw_mng->start_cmd_payload_size; + u32 offset, max_block_size, max_lpl_len; +@@ -202,6 +208,67 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, + return 0; + } + ++struct cmis_cdb_write_fw_block_epl_pl { ++ u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH]; ++}; ++ ++static int ++cmis_fw_update_write_image_epl(struct ethtool_cmis_cdb *cdb, ++ struct ethtool_cmis_fw_update_params *fw_update, ++ struct cmis_fw_update_fw_mng_features *fw_mng) ++{ ++ u8 start = fw_mng->start_cmd_payload_size; ++ u32 image_size = fw_update->fw->size; ++ u32 offset, lpl_len; ++ int err; ++ ++ lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl, ++ block_address); ++ ++ for (offset = start; offset < image_size; ++ offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) { ++ struct cmis_cdb_write_fw_block_lpl_pl lpl = { ++ .block_address = cpu_to_be32(offset - start), ++ }; ++ struct cmis_cdb_write_fw_block_epl_pl *epl; ++ struct ethtool_cmis_cdb_cmd_args args = {}; ++ u32 epl_len; ++ ++ ethnl_module_fw_flash_ntf_in_progress(fw_update->dev, ++ &fw_update->ntf_params, ++ offset - start, ++ image_size); ++ ++ epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH, ++ image_size - offset); ++ epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL); ++ if (!epl) ++ return -ENOMEM; ++ ++ memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len); ++ ++ ethtool_cmis_cdb_compose_args(&args, ++ ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL, ++ (u8 *)&lpl, lpl_len, (u8 *)epl, ++ epl_len, ++ fw_mng->max_duration_write, ++ cdb->read_write_len_ext, 1, 0, ++ CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); ++ ++ err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args); ++ kfree(epl); ++ if (err < 0) { ++ ethnl_module_fw_flash_ntf_err(fw_update->dev, ++ &fw_update->ntf_params, ++ "Write FW block EPL command failed", ++ args.err_msg); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ + static int + cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb, + struct net_device *dev, +@@ -238,9 +305,15 @@ cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb, + if (err < 0) + return err; + +- err = cmis_fw_update_write_image(cdb, fw_update, fw_mng); +- if (err < 0) +- return err; ++ if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) { ++ err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng); ++ if (err < 0) ++ return err; ++ } else { ++ err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng); ++ if (err < 0) ++ return err; ++ } + + err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng, + &fw_update->ntf_params); +-- +2.53.0 + diff --git a/queue-6.12/net-handshake-drain-pending-requests-at-net-namespac.patch b/queue-6.12/net-handshake-drain-pending-requests-at-net-namespac.patch new file mode 100644 index 0000000000..518c8da372 --- /dev/null +++ b/queue-6.12/net-handshake-drain-pending-requests-at-net-namespac.patch @@ -0,0 +1,112 @@ +From b31d1fc4e428f49c68f4bf59c55cd6c35c252205 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:22 -0400 +Subject: net/handshake: Drain pending requests at net namespace exit + +From: Chuck Lever + +[ Upstream commit ea5fe6a73ca57e5150b8a38b341aef2636eb72f0 ] + +The arguments to list_splice_init() in handshake_net_exit() are +reversed. The call moves the local empty "requests" list onto +hn->hn_requests, leaving the local list empty, so the subsequent +drain loop runs zero iterations. Pending handshake requests that +had not yet been accepted are not torn down when the net namespace +is destroyed; each one keeps a reference on a socket file and on +the handshake_req allocation. + +Pass the source and destination in the documented order +(list_splice_init(list, head) moves list onto head) so the pending +list is transferred to the local scratch list and drained through +handshake_complete(). + +Fixing the splice direction exposes a list-corruption race. After +the splice each req->hr_list still has non-empty link pointers, +threading the stack-local scratch list rather than hn_requests. +A concurrent handshake_req_cancel() -- for example, from sunrpc's +TLS timeout on a kernel socket whose netns reference was not +taken -- finds the request through the rhashtable, calls +remove_pending(), and sees !list_empty(&req->hr_list). +__remove_pending_locked() then list_del_init()s an entry off the +scratch list while the drain iterates, corrupting it. The same +call arriving after the drain loop has run list_del() on an +entry hits LIST_POISON instead. + +Have remove_pending() check HANDSHAKE_F_NET_DRAINING under +hn_lock and report not-found when drain is in progress. The +drain has already taken ownership; handshake_complete()'s existing +test_and_set on HANDSHAKE_F_REQ_COMPLETED still arbitrates +between drain and cancel for who calls the consumer's hp_done. Use +list_del_init() rather than list_del() in the drain so req->hr_list +does not carry LIST_POISON after drain releases the entry. + +The DRAINING guard in remove_pending() makes cancel return false, +but cancel still falls through to test_and_set_bit on +HANDSHAKE_F_REQ_COMPLETED and drops the request's hr_file reference. +Without another pin, if that is the last reference, sk_destruct frees +the request while it is still linked on the drain loop's local list. +Pin each request's hr_file under hn_lock before releasing the list, +and drop that drain pin after the loop finishes with the request. + +Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-8-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/handshake/netlink.c | 10 ++++++++-- + net/handshake/request.c | 5 ++++- + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 86a12c9125d403..e49041cc0f9d70 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -205,13 +205,19 @@ static void __net_exit handshake_net_exit(struct net *net) + */ + spin_lock_bh(&hn->hn_lock); + set_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags); +- list_splice_init(&requests, &hn->hn_requests); ++ list_splice_init(&hn->hn_requests, &requests); ++ list_for_each_entry(req, &requests, hr_list) ++ get_file(req->hr_file); + spin_unlock_bh(&hn->hn_lock); + + while (!list_empty(&requests)) { ++ struct file *file; ++ + req = list_first_entry(&requests, struct handshake_req, hr_list); +- list_del(&req->hr_list); ++ file = req->hr_file; ++ list_del_init(&req->hr_list); + handshake_complete(req, -ETIMEDOUT, NULL); ++ fput(file); + } + } + +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 35bc6290e12033..96f80e0df67b50 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -163,13 +163,16 @@ static void __remove_pending_locked(struct handshake_net *hn, + * otherwise %false. + * + * If @req was on a pending list, it has not yet been accepted. ++ * Returns %false when the net namespace is draining; the drain ++ * loop has taken ownership of the pending list. + */ + static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) + { + bool ret = false; + + spin_lock_bh(&hn->hn_lock); +- if (!list_empty(&req->hr_list)) { ++ if (!test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags) && ++ !list_empty(&req->hr_list)) { + __remove_pending_locked(hn, req); + ret = true; + } +-- +2.53.0 + diff --git a/queue-6.12/net-handshake-pass-negative-errno-through-handshake_.patch b/queue-6.12/net-handshake-pass-negative-errno-through-handshake_.patch new file mode 100644 index 0000000000..b538c19d23 --- /dev/null +++ b/queue-6.12/net-handshake-pass-negative-errno-through-handshake_.patch @@ -0,0 +1,212 @@ +From 1616ec410d95511eda4e449b2797c511fb5f7bf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:17 -0400 +Subject: net/handshake: Pass negative errno through handshake_complete() + +From: Chuck Lever + +[ Upstream commit 6b22d433aa13f68e3cd9534ca9a5f4277bfa01c2 ] + +handshake_complete() declares status as unsigned int and +tls_handshake_done() negates that value (-status) before handing +it to the TLS consumer. Consumers match on negative errno +constants -- xs_tls_handshake_done() has + + switch (status) { + case 0: + case -EACCES: + case -ETIMEDOUT: + lower_transport->xprt_err = status; + break; + default: + lower_transport->xprt_err = -EACCES; + } + +so the API as designed expects callers to pass positive errno +values that the tlshd shim then negates. + +Three internal callers in handshake_nl_accept_doit(), the +net-exit drain, and a kunit test follow kernel convention and +pass negative errnos -- -EIO, -ETIMEDOUT, -ETIMEDOUT. The +implicit conversion to unsigned int turns -ETIMEDOUT into +0xFFFFFF92; the subsequent -status in tls_handshake_done() +wraps back to 110, the consumer's switch falls through, and +the xprt reports -EACCES on what should be -ETIMEDOUT or -EIO. + +Fix the API rather than the call sites. The natural kernel +convention is negative errno in, negative errno out. Change +handshake_complete() and hp_done to take int status, drop the +negation in tls_handshake_done(), and negate once in +handshake_nl_done_doit() where status arrives from the wire +as an unsigned netlink attribute. The three internal callers +were already correct under that convention and need no change. + +At the same wire boundary, declare MAX_ERRNO as the netlink +policy upper bound for HANDSHAKE_A_DONE_STATUS. Attribute +validation rejects out-of-range values before +handshake_nl_done_doit() runs, and negating a bounded u32 there +stays within int range -- closing the UBSAN-visible signed- +integer overflow that an unconstrained u32 would invoke. + +Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-3-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + Documentation/netlink/specs/handshake.yaml | 8 ++++++++ + net/handshake/genl.c | 3 ++- + net/handshake/genl.h | 1 + + net/handshake/handshake-test.c | 2 +- + net/handshake/handshake.h | 4 ++-- + net/handshake/netlink.c | 2 +- + net/handshake/request.c | 2 +- + net/handshake/tlshd.c | 4 ++-- + 8 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml +index b934cc513e3d6f..090fc11da4604a 100644 +--- a/Documentation/netlink/specs/handshake.yaml ++++ b/Documentation/netlink/specs/handshake.yaml +@@ -12,6 +12,12 @@ protocol: genetlink + doc: Netlink protocol to request a transport layer security handshake. + + definitions: ++ - ++ type: const ++ name: max-errno ++ value: 4095 ++ header: linux/err.h ++ scope: kernel + - + type: enum + name: handler-class +@@ -77,6 +83,8 @@ attribute-sets: + - + name: status + type: u32 ++ checks: ++ max: max-errno + - + name: sockfd + type: s32 +diff --git a/net/handshake/genl.c b/net/handshake/genl.c +index f55d14d7b7269d..a5fa8b27f22423 100644 +--- a/net/handshake/genl.c ++++ b/net/handshake/genl.c +@@ -9,6 +9,7 @@ + #include "genl.h" + + #include ++#include + + /* HANDSHAKE_CMD_ACCEPT - do */ + static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HANDLER_CLASS + 1] = { +@@ -17,7 +18,7 @@ static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HAN + + /* HANDSHAKE_CMD_DONE - do */ + static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_REMOTE_AUTH + 1] = { +- [HANDSHAKE_A_DONE_STATUS] = { .type = NLA_U32, }, ++ [HANDSHAKE_A_DONE_STATUS] = NLA_POLICY_MAX(NLA_U32, MAX_ERRNO), + [HANDSHAKE_A_DONE_SOCKFD] = { .type = NLA_S32, }, + [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .type = NLA_U32, }, + }; +diff --git a/net/handshake/genl.h b/net/handshake/genl.h +index ae72a596f6cc3e..684e5fd684481b 100644 +--- a/net/handshake/genl.h ++++ b/net/handshake/genl.h +@@ -10,6 +10,7 @@ + #include + + #include ++#include + + int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info); + int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info); +diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c +index 34fd1d9b2db861..a331b308aaa240 100644 +--- a/net/handshake/handshake-test.c ++++ b/net/handshake/handshake-test.c +@@ -25,7 +25,7 @@ static int test_accept_func(struct handshake_req *req, struct genl_info *info, + return 0; + } + +-static void test_done_func(struct handshake_req *req, unsigned int status, ++static void test_done_func(struct handshake_req *req, int status, + struct genl_info *info) + { + } +diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h +index a48163765a7a1d..2289b0e274f40a 100644 +--- a/net/handshake/handshake.h ++++ b/net/handshake/handshake.h +@@ -57,7 +57,7 @@ struct handshake_proto { + int (*hp_accept)(struct handshake_req *req, + struct genl_info *info, int fd); + void (*hp_done)(struct handshake_req *req, +- unsigned int status, ++ int status, + struct genl_info *info); + void (*hp_destroy)(struct handshake_req *req); + }; +@@ -86,7 +86,7 @@ struct handshake_req *handshake_req_hash_lookup(struct sock *sk); + struct handshake_req *handshake_req_next(struct handshake_net *hn, int class); + int handshake_req_submit(struct socket *sock, struct handshake_req *req, + gfp_t flags); +-void handshake_complete(struct handshake_req *req, unsigned int status, ++void handshake_complete(struct handshake_req *req, int status, + struct genl_info *info); + bool handshake_req_cancel(struct sock *sk); + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 394e270cc505cb..d8211e0ba75c69 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -161,7 +161,7 @@ int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info) + + status = -EIO; + if (info->attrs[HANDSHAKE_A_DONE_STATUS]) +- status = nla_get_u32(info->attrs[HANDSHAKE_A_DONE_STATUS]); ++ status = -(int)nla_get_u32(info->attrs[HANDSHAKE_A_DONE_STATUS]); + + handshake_complete(req, status, info); + sockfd_put(sock); +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 75562f6629e050..2f58d74f16554b 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -285,7 +285,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + } + EXPORT_SYMBOL(handshake_req_submit); + +-void handshake_complete(struct handshake_req *req, unsigned int status, ++void handshake_complete(struct handshake_req *req, int status, + struct genl_info *info) + { + struct sock *sk = req->hr_sk; +diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c +index fd71ef2d18ceb2..5464e57c347b9c 100644 +--- a/net/handshake/tlshd.c ++++ b/net/handshake/tlshd.c +@@ -93,7 +93,7 @@ static void tls_handshake_remote_peerids(struct tls_handshake_req *treq, + * + */ + static void tls_handshake_done(struct handshake_req *req, +- unsigned int status, struct genl_info *info) ++ int status, struct genl_info *info) + { + struct tls_handshake_req *treq = handshake_req_private(req); + +@@ -104,7 +104,7 @@ static void tls_handshake_done(struct handshake_req *req, + if (!status) + set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags); + +- treq->th_consumer_done(treq->th_consumer_data, -status, ++ treq->th_consumer_done(treq->th_consumer_data, status, + treq->th_peerid[0]); + } + +-- +2.53.0 + diff --git a/queue-6.12/net-handshake-take-a-long-lived-file-reference-at-su.patch b/queue-6.12/net-handshake-take-a-long-lived-file-reference-at-su.patch new file mode 100644 index 0000000000..4ce3a51580 --- /dev/null +++ b/queue-6.12/net-handshake-take-a-long-lived-file-reference-at-su.patch @@ -0,0 +1,187 @@ +From 3285d576d858e0fd808c19cd043f6dc5649577fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:18 -0400 +Subject: net/handshake: Take a long-lived file reference at submit + +From: Chuck Lever + +[ Upstream commit 09dba37eee70d0596e26645015f1aa95a9848e9d ] + +handshake_nl_accept_doit() needs the file pointer backing +req->hr_sk->sk_socket to survive the window between +handshake_req_next() and the subsequent FD_PREPARE() and get_file(). +The submit-side sock_hold() does not provide that. sk_refcnt keeps +struct sock alive, but struct socket is owned by sock->file: when +the consumer fputs the last file reference, sock_release() tears +the socket down regardless of any sock_hold. + +Add an hr_file pointer to struct handshake_req and acquire an +explicit reference on sock->file during handshake_req_submit(). +handshake_complete() and handshake_req_cancel() release the +reference on the completion-bit-winning path. + +The submit error path must also release the file reference, but +after rhashtable insertion a concurrent handshake_req_cancel() can +discover the request and race the error path. Gate the error-path +cleanup -- sk_destruct restoration, fput, and request destruction +-- with test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED), the same +serialization handshake_complete() and handshake_req_cancel() +already use. When cancel has already claimed ownership, the submit +error path returns without touching the request; socket teardown +handles final destruction. + +The accept-side dereferences are not yet retargeted; that change +comes in the next patch. + +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-4-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Stable-dep-of: ea5fe6a73ca5 ("net/handshake: Drain pending requests at net namespace exit") +Signed-off-by: Sasha Levin +--- + net/handshake/handshake.h | 2 ++ + net/handshake/netlink.c | 6 ------ + net/handshake/request.c | 42 ++++++++++++++++++++++++++++++++------- + 3 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h +index 2289b0e274f40a..da61cadd1ad3e7 100644 +--- a/net/handshake/handshake.h ++++ b/net/handshake/handshake.h +@@ -24,6 +24,7 @@ enum hn_flags_bits { + HANDSHAKE_F_NET_DRAINING, + }; + ++struct file; + struct handshake_proto; + + /* One handshake request */ +@@ -32,6 +33,7 @@ struct handshake_req { + struct rhash_head hr_rhash; + unsigned long hr_flags; + const struct handshake_proto *hr_proto; ++ struct file *hr_file; + struct sock *hr_sk; + void (*hr_odestruct)(struct sock *sk); + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index d8211e0ba75c69..86a12c9125d403 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -211,12 +211,6 @@ static void __net_exit handshake_net_exit(struct net *net) + while (!list_empty(&requests)) { + req = list_first_entry(&requests, struct handshake_req, hr_list); + list_del(&req->hr_list); +- +- /* +- * Requests on this list have not yet been +- * accepted, so they do not have an fd to put. +- */ +- + handshake_complete(req, -ETIMEDOUT, NULL); + } + } +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 62efb7e32730ea..35bc6290e12033 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -215,9 +216,16 @@ EXPORT_SYMBOL_IF_KUNIT(handshake_req_next); + * A zero return value from handshake_req_submit() means that + * exactly one subsequent completion callback is guaranteed. + * +- * A negative return value from handshake_req_submit() means that +- * no completion callback will be done and that @req has been +- * destroyed. ++ * A negative return value from handshake_req_submit() guarantees that ++ * no completion callback will occur and that @req is no longer owned by ++ * the caller. If cancellation wins the completion race after the request ++ * has been published, final destruction is deferred until socket teardown. ++ * ++ * The caller must hold a reference on @sock->file for the duration ++ * of this call. Once the request is published to the accept side, a ++ * concurrent completion or cancellation may release the request's pin on ++ * @sock->file; the caller's reference is what keeps @sock->sk valid until ++ * handshake_req_submit() returns. + */ + int handshake_req_submit(struct socket *sock, struct handshake_req *req, + gfp_t flags) +@@ -236,6 +244,14 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + kfree(req); + return -EINVAL; + } ++ ++ /* ++ * Pin sock->file for the lifetime of the request so the ++ * accept side does not race a consumer that releases the ++ * socket while a handshake is pending. ++ */ ++ req->hr_file = get_file(sock->file); ++ + req->hr_odestruct = req->hr_sk->sk_destruct; + req->hr_sk->sk_destruct = handshake_sk_destruct; + +@@ -267,7 +283,11 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + goto out_err; + } + +- /* Prevent socket release while a handshake request is pending */ ++ /* ++ * Pin struct sock so sk_destruct does not run until the ++ * handshake completion path releases it; struct socket is ++ * held separately via hr_file above. ++ */ + sock_hold(req->hr_sk); + + trace_handshake_submit(net, req, req->hr_sk); +@@ -276,10 +296,13 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + out_unlock: + spin_unlock_bh(&hn->hn_lock); + out_err: +- /* Restore original destructor so socket teardown still runs on failure */ +- req->hr_sk->sk_destruct = req->hr_odestruct; + trace_handshake_submit_err(net, req, req->hr_sk, ret); +- handshake_req_destroy(req); ++ if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { ++ /* Restore original destructor so socket teardown still runs. */ ++ req->hr_sk->sk_destruct = req->hr_odestruct; ++ fput(req->hr_file); ++ handshake_req_destroy(req); ++ } + return ret; + } + EXPORT_SYMBOL(handshake_req_submit); +@@ -291,11 +314,15 @@ void handshake_complete(struct handshake_req *req, int status, + struct net *net = sock_net(sk); + + if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { ++ struct file *file = req->hr_file; ++ + trace_handshake_complete(net, req, sk, status); + req->hr_proto->hp_done(req, status, info); + + /* Handshake request is no longer pending */ + sock_put(sk); ++ ++ fput(file); + } + } + EXPORT_SYMBOL_IF_KUNIT(handshake_complete); +@@ -344,6 +371,7 @@ bool handshake_req_cancel(struct sock *sk) + + /* Handshake request is no longer pending */ + sock_put(sk); ++ fput(req->hr_file); + return true; + } + EXPORT_SYMBOL(handshake_req_cancel); +-- +2.53.0 + diff --git a/queue-6.12/net-handshake-use-spin_lock_bh-for-hn_lock.patch b/queue-6.12/net-handshake-use-spin_lock_bh-for-hn_lock.patch new file mode 100644 index 0000000000..e35ed91bee --- /dev/null +++ b/queue-6.12/net-handshake-use-spin_lock_bh-for-hn_lock.patch @@ -0,0 +1,138 @@ +From 5c0599665b076e2fc881cd31a2fcefc2561a6b45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:15 -0400 +Subject: net/handshake: Use spin_lock_bh for hn_lock + +From: Chuck Lever + +[ Upstream commit cc993e0927ec8bd98ea33377ada03295fcda0f24 ] + +nvmet_tcp_state_change(), a socket callback that runs in BH context, +can reach handshake_req_cancel() via nvmet_tcp_schedule_release_queue() +and tls_handshake_cancel(). handshake_req_cancel() acquires +hn->hn_lock with plain spin_lock(). If a process-context thread on +the same CPU holds hn->hn_lock when a softirq invokes the cancel path, +the lock attempt deadlocks. This is the only caller that invokes +tls_handshake_cancel() from BH context; every other consumer calls it +from process context. + +Deferring the cancel to process context in the NVMe target is not +straightforward: nvmet_tcp_schedule_release_queue() must call +tls_handshake_cancel() atomically with its state transition to +DISCONNECTING. If the cancel were deferred, the handshake completion +callback could fire in the window before the cancel runs, observe the +unexpected state, and return without dropping its kref on the queue. +Reworking that interlock is considerably more invasive than hardening +the handshake lock. Convert all hn->hn_lock acquisitions from +spin_lock/spin_unlock to spin_lock_bh/spin_unlock_bh so the lock is +never taken with softirqs enabled. + +Fixes: 675b453e0241 ("nvmet-tcp: enable TLS handshake upcall") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-1-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/handshake/netlink.c | 4 ++-- + net/handshake/request.c | 14 +++++++------- + net/handshake/tlshd.c | 2 ++ + 3 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 7e46d130dce2cd..394e270cc505cb 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -203,10 +203,10 @@ static void __net_exit handshake_net_exit(struct net *net) + * accepted and are in progress will be destroyed when + * the socket is closed. + */ +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + set_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags); + list_splice_init(&requests, &hn->hn_requests); +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + while (!list_empty(&requests)) { + req = list_first_entry(&requests, struct handshake_req, hr_list); +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 5df102534a596f..75562f6629e050 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -168,12 +168,12 @@ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) + { + bool ret = false; + +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + if (!list_empty(&req->hr_list)) { + __remove_pending_locked(hn, req); + ret = true; + } +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + return ret; + } +@@ -183,7 +183,7 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + struct handshake_req *req, *pos; + + req = NULL; +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + list_for_each_entry(pos, &hn->hn_requests, hr_list) { + if (pos->hr_proto->hp_handler_class != class) + continue; +@@ -191,7 +191,7 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + req = pos; + break; + } +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + return req; + } +@@ -250,7 +250,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max) + goto out_err; + +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + ret = -EOPNOTSUPP; + if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags)) + goto out_unlock; +@@ -259,7 +259,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + goto out_unlock; + if (!__add_pending_locked(hn, req)) + goto out_unlock; +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + ret = handshake_genl_notify(net, req->hr_proto, flags); + if (ret) { +@@ -275,7 +275,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + return 0; + + out_unlock: +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + out_err: + /* Restore original destructor so socket teardown still runs on failure */ + req->hr_sk->sk_destruct = req->hr_odestruct; +diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c +index 822507b87447c0..fd71ef2d18ceb2 100644 +--- a/net/handshake/tlshd.c ++++ b/net/handshake/tlshd.c +@@ -419,6 +419,8 @@ EXPORT_SYMBOL(tls_server_hello_psk); + * Request cancellation races with request completion. To determine + * who won, callers examine the return value from this function. + * ++ * Context: May be called from process or softirq context. ++ * + * Return values: + * %true - Uncompleted handshake request was canceled + * %false - Handshake request already completed or not found +-- +2.53.0 + diff --git a/queue-6.12/net-hsr-fix-potential-oob-access-in-supervision-fram.patch b/queue-6.12/net-hsr-fix-potential-oob-access-in-supervision-fram.patch new file mode 100644 index 0000000000..9d950a60ef --- /dev/null +++ b/queue-6.12/net-hsr-fix-potential-oob-access-in-supervision-fram.patch @@ -0,0 +1,48 @@ +From 4453632aeb4955287c7963dcadf7e21ab15260db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 15:03:30 +0200 +Subject: net: hsr: fix potential OOB access in supervision frame handling + +From: Luka Gejak + +[ Upstream commit f229426072fc865654a60978bb7fda790a051ff3 ] + +Ensure the entire TLV header is linearized before access by adding +sizeof(struct hsr_sup_tlv) to the pskb_may_pull() calls. Without this, +a truncated frame could cause an out-of-bounds access. + +Fixes: eafaa88b3eb7 ("net: hsr: Add support for redbox supervision frames") +Signed-off-by: Luka Gejak +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260523130330.61880-1-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_forward.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c +index fa97405c517c70..e3037741a74895 100644 +--- a/net/hsr/hsr_forward.c ++++ b/net/hsr/hsr_forward.c +@@ -84,7 +84,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* Get next tlv */ + total_length += hsr_sup_tag->tlv.HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + skb_pull(skb, total_length); + hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data; +@@ -100,7 +100,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* make sure another tlv follows */ + total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tlv->HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + + /* get next tlv */ +-- +2.53.0 + diff --git a/queue-6.12/net-introduce-skb-tc-depth-field-to-track-packet-loo.patch b/queue-6.12/net-introduce-skb-tc-depth-field-to-track-packet-loo.patch new file mode 100644 index 0000000000..7e7567a385 --- /dev/null +++ b/queue-6.12/net-introduce-skb-tc-depth-field-to-track-packet-loo.patch @@ -0,0 +1,95 @@ +From 90e38873af8af2d4ba92f811b83ad66bc4b1a203 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:48 -0400 +Subject: net: Introduce skb tc depth field to track packet loops + +From: Jamal Hadi Salim + +[ Upstream commit 98b34f3e8c3492cfc89ff943c9d92b4d52863d1d ] + +Add a 2-bit per-skb tc depth field to track packet loops across the stack. + +The previous per-CPU loop counters like MIRRED_NEST_LIMIT +assume a single call stack and lose state in two cases: +1) When a packet is queued and reprocessed later (e.g., egress->ingress + via backlog), the per-cpu state is gone by the time it is dequeued. +2) With XPS/RPS a packet may arrive on one CPU and be processed on + another. + +A per-skb field solves both by travelling with the packet itself. + +The field fits in existing padding, using 2 bits that were previously a +hole: + +pahole before(-) and after (+) diff looks like: + __u8 slow_gro:1; /* 132: 3 1 */ + __u8 csum_not_inet:1; /* 132: 4 1 */ + __u8 unreadable:1; /* 132: 5 1 */ + + __u8 tc_depth:2; /* 132: 6 1 */ + + - /* XXX 2 bits hole, try to pack */ + /* XXX 1 byte hole, try to pack */ + + __u16 tc_index; /* 134 2 */ + +There used to be a ttl field which was removed as part of tc_verd in commit +aec745e2c520 ("net-tc: remove unused tc_verd fields"). It was already +unused by that time, due to remove earlier in commit c19ae86a510c ("tc: remove +unused redirect ttl"). + +The first user of this field is netem, which increments tc_depth on +duplicated packets before re-enqueueing them at the root qdisc. On +re-entry, netem skips duplication for any skb with tc_depth already set, +bounding recursion to a single level regardless of tree topology. + +The other user is mirred which increments it on each pass +and limits to depth to MIRRED_DEFER_LIMIT (3). + +The new field was called ttl in earlier versions of this patch +but renamed to tc_depth to avoid confusion with IP ttl. + +Note (looking at you Sashiko! Dont ignore me and continue bringing this up): +1. Since both mirred and netem utilize the same 2-bit tc_depth field it is + possible when netem and mirred are used together that netem qdisc to skip + the duplication step. This is a known trade-off, as a 2-bit field cannot + independently track both features' recursion depths and it is not considered + sane to have a setup that addresses both features on at the same time. + +2. skb_scrub_packet does not clear tc_depth. This means a packet's loop history + is preserved even across namespaces. While this might be restrictive for + some topologies, it is also design intent to provide robustness against loops + across namespaces. + +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-2-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Stable-dep-of: e80ad525fc7e ("net/sched: act_mirred: Fix return code in early mirred redirect error paths") +Signed-off-by: Sasha Levin +--- + include/linux/skbuff.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 4344724a978212..107a8c3ff07fa2 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -802,6 +802,7 @@ enum skb_tstamp_type { + * @_sk_redir: socket redirection information for skmsg + * @_nfct: Associated connection, if any (with nfctinfo bits) + * @skb_iif: ifindex of device we arrived on ++ * @tc_depth: counter for packet duplication + * @tc_index: Traffic control index + * @hash: the packet hash + * @queue_mapping: Queue mapping for multiqueue devices +@@ -1011,6 +1012,7 @@ struct sk_buff { + __u8 csum_not_inet:1; + #endif + __u8 unreadable:1; ++ __u8 tc_depth:2; + #if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS) + __u16 tc_index; /* traffic control index */ + #endif +-- +2.53.0 + diff --git a/queue-6.12/net-iucv-fix-locking-in-.getsockopt.patch b/queue-6.12/net-iucv-fix-locking-in-.getsockopt.patch new file mode 100644 index 0000000000..0ba5202b8d --- /dev/null +++ b/queue-6.12/net-iucv-fix-locking-in-.getsockopt.patch @@ -0,0 +1,87 @@ +From e2a2f772df0da114de96941796e67fd0b4ad4059 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 07:11:45 -0700 +Subject: net/iucv: fix locking in .getsockopt + +From: Breno Leitao + +[ Upstream commit 3589d20a666caf30ad100c960a2de7de390fce88 ] + +Mirror iucv_sock_setsockopt() and wrap the whole switch in +lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock +becomes redundant and is removed. + +Any AF_IUCV HIPER user can potentially crash the kernel by racing +recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences +iucv->hs_dev->mtu after iucv_sock_close() (called from the racing +recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference +oops. + +Suggested-by: Stanislav Fomichev +Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size") +Signed-off-by: Breno Leitao +Reviewed-by: Alexandra Winter +Tested-by: Alexandra Winter +Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/iucv/af_iucv.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index 7929df08d4e023..1a0b41fcea8131 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1537,7 +1537,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + unsigned int val; +- int len; ++ int len, rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; +@@ -1550,26 +1550,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + + len = min_t(unsigned int, len, sizeof(int)); + ++ rc = 0; ++ ++ lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: +- lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ +- release_sock(sk); + break; + case SO_MSGSIZE: +- if (sk->sk_state == IUCV_OPEN) +- return -EBADFD; ++ if (sk->sk_state == IUCV_OPEN) { ++ rc = -EBADFD; ++ break; ++ } + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; + default: +- return -ENOPROTOOPT; ++ rc = -ENOPROTOOPT; ++ break; + } ++ release_sock(sk); ++ ++ if (rc) ++ return rc; + + if (put_user(len, optlen)) + return -EFAULT; +-- +2.53.0 + diff --git a/queue-6.12/net-mana-add-null-guards-in-teardown-path-to-prevent.patch b/queue-6.12/net-mana-add-null-guards-in-teardown-path-to-prevent.patch new file mode 100644 index 0000000000..fe676c4ba7 --- /dev/null +++ b/queue-6.12/net-mana-add-null-guards-in-teardown-path-to-prevent.patch @@ -0,0 +1,148 @@ +From 2b3bd98e4234b3cfbc959a8502ffa7f5525f648b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 01:08:24 -0700 +Subject: net: mana: Add NULL guards in teardown path to prevent panic on + attach failure + +From: Dipayaan Roy + +[ Upstream commit 17bfe0a8c014ee1d542ad352cd6a0a505361664a ] + +When queue allocation fails partway through, the error cleanup frees +and NULLs apc->tx_qp and apc->rxqs. Multiple teardown paths such as +mana_remove(), mana_change_mtu() recovery, and internal error handling +in mana_alloc_queues() can subsequently call into functions that +dereference these pointers without NULL checks: + +- mana_chn_setxdp() dereferences apc->rxqs[0], causing a NULL pointer + dereference panic (CR2: 0000000000000000 at mana_chn_setxdp+0x26). +- mana_destroy_vport() iterates apc->rxqs without a NULL check. +- mana_fence_rqs() iterates apc->rxqs without a NULL check. +- mana_dealloc_queues() iterates apc->tx_qp without a NULL check. + +Add NULL guards for apc->rxqs in mana_fence_rqs(), +mana_destroy_vport(), and before the mana_chn_setxdp() call. Add a +NULL guard for apc->tx_qp in mana_dealloc_queues() to skip TX queue +draining when TX queues were never allocated or already freed. + +Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)") +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260525081129.1230035-2-dipayanroy@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 70 +++++++++++-------- + 1 file changed, 41 insertions(+), 29 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index e527139936dee4..0e4b0ac4acf86b 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -1304,6 +1304,9 @@ static void mana_fence_rqs(struct mana_port_context *apc) + struct mana_rxq *rxq; + int err; + ++ if (!apc->rxqs) ++ return; ++ + for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { + rxq = apc->rxqs[rxq_idx]; + err = mana_fence_rq(apc, rxq); +@@ -2324,13 +2327,16 @@ static void mana_destroy_vport(struct mana_port_context *apc) + struct mana_rxq *rxq; + u32 rxq_idx; + +- for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { +- rxq = apc->rxqs[rxq_idx]; +- if (!rxq) +- continue; ++ if (apc->rxqs) { + +- mana_destroy_rxq(apc, rxq, true); +- apc->rxqs[rxq_idx] = NULL; ++ for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { ++ rxq = apc->rxqs[rxq_idx]; ++ if (!rxq) ++ continue; ++ ++ mana_destroy_rxq(apc, rxq, true); ++ apc->rxqs[rxq_idx] = NULL; ++ } + } + + mana_destroy_txq(apc); +@@ -2633,7 +2639,8 @@ static int mana_dealloc_queues(struct net_device *ndev) + if (apc->port_is_up) + return -EINVAL; + +- mana_chn_setxdp(apc, NULL); ++ if (apc->rxqs) ++ mana_chn_setxdp(apc, NULL); + + if (gd->gdma_context->is_pf) + mana_pf_deregister_filter(apc); +@@ -2651,33 +2658,38 @@ static int mana_dealloc_queues(struct net_device *ndev) + * number of queues. + */ + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- tsleep = 1000; +- while (atomic_read(&txq->pending_sends) > 0 && +- time_before(jiffies, timeout)) { +- usleep_range(tsleep, tsleep + 1000); +- tsleep <<= 1; +- } +- if (atomic_read(&txq->pending_sends)) { +- err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); +- if (err) { +- netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", +- err, atomic_read(&txq->pending_sends), +- txq->gdma_txq_id); ++ if (apc->tx_qp) { ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ tsleep = 1000; ++ while (atomic_read(&txq->pending_sends) > 0 && ++ time_before(jiffies, timeout)) { ++ usleep_range(tsleep, tsleep + 1000); ++ tsleep <<= 1; ++ } ++ if (atomic_read(&txq->pending_sends)) { ++ err = ++ pcie_flr(to_pci_dev(gd->gdma_context->dev)); ++ if (err) { ++ netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", ++ err, ++ atomic_read(&txq->pending_sends), ++ txq->gdma_txq_id); ++ } ++ break; + } +- break; + } +- } + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- while ((skb = skb_dequeue(&txq->pending_skbs))) { +- mana_unmap_skb(skb, apc); +- dev_kfree_skb_any(skb); ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ while ((skb = skb_dequeue(&txq->pending_skbs))) { ++ mana_unmap_skb(skb, apc); ++ dev_kfree_skb_any(skb); ++ } ++ atomic_set(&txq->pending_sends, 0); + } +- atomic_set(&txq->pending_sends, 0); + } ++ + /* We're 100% sure the queues can no longer be woken up, because + * we're sure now mana_poll_tx_cq() can't be running. + */ +-- +2.53.0 + diff --git a/queue-6.12/net-netlink-don-t-set-nsid-on-local-notifications.patch b/queue-6.12/net-netlink-don-t-set-nsid-on-local-notifications.patch new file mode 100644 index 0000000000..c3fcfd0d17 --- /dev/null +++ b/queue-6.12/net-netlink-don-t-set-nsid-on-local-notifications.patch @@ -0,0 +1,82 @@ +From 840c55ccee1c046b863d71aec99dbb4728047aed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:36 +0200 +Subject: net: netlink: don't set nsid on local notifications + +From: Ilya Maximets + +[ Upstream commit 88b126b39f9757e9debc322d4679239e9af089c7 ] + +In most cases, notifications on sockets with NETLINK_LISTEN_ALL_NSID +do not contain NSID in their ancillary data in case the event is local +to the listener. + +However, when a self-referential NSID is allocated for a namespace, +every local notification starts sending this ID to the user space. + +This is problematic, because the listener cannot tell if those +notifications are local or not anymore without making extra requests +to figure out if the provided NSID is local or not. The listener +can also not figure out the local NSID beforehand as it can be +allocated at any point in time by other processes, changing the +structure of the future notifications for everyone. + +The value is practically not useful, since it's the namespace's own +ID that the application has to obtain from other sources in order to +figure out if it's the same or not. So, for the application it's +just an extra busy work with no benefits. Moreover, applications +that do not know about this quirk may be mishandling notifications +with NSID set as notifications from remote namespaces. This is the +case for ovs-vswitchd and the iproute2's 'ip monitor' that stops +printing 'current' and starts printing the nsid number mid-session. + +Lack of clear documentation for this behavior is also not helping. + +A search though open-source projects doesn't reveal any projects +that use NETNSA_NSID_NOT_ASSIGNED and rely on metadata to contain +self-referential NSIDs (expected, since the value is not useful). +Quite the opposite, as already mentioned, there are few applications +that rely on NSID to not be present in local events. + +Since the value is not useful and actively harmful in some cases, +let's not report it for local events, making the notifications more +consistent. + +Also adding some blank lines for readability. + +Fixes: 59324cf35aba ("netlink: allow to listen "all" netns") +Reported-by: Matteo Perin +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-3-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 287b4f921c607e..e250d4a3d03097 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1477,10 +1477,14 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ + NETLINK_CB(p->skb2).nsid_is_set = false; +- NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); +- if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) +- NETLINK_CB(p->skb2).nsid_is_set = true; ++ if (!net_eq(sock_net(sk), p->net)) { ++ NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); ++ if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) ++ NETLINK_CB(p->skb2).nsid_is_set = true; ++ } ++ + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { + netlink_overrun(sk); +-- +2.53.0 + diff --git a/queue-6.12/net-netlink-fix-sending-unassigned-nsid-after-assign.patch b/queue-6.12/net-netlink-fix-sending-unassigned-nsid-after-assign.patch new file mode 100644 index 0000000000..12ec1c3c8a --- /dev/null +++ b/queue-6.12/net-netlink-fix-sending-unassigned-nsid-after-assign.patch @@ -0,0 +1,45 @@ +From 87ccc21623c7194078b291a9a5397cb505f4703d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:35 +0200 +Subject: net: netlink: fix sending unassigned nsid after assigned one + +From: Ilya Maximets + +[ Upstream commit 70f8592ee90585272018a725054b6eb2ab7e99ca ] + +If the current skb is not shared, it is re-used directly for all the +sockets subscribed to the notification. If we have remote all-nsid +socket receiving a message first, then the 'nsid_is_set' will be +set to 'true'. If the nsid is NOT_ASSIGNED for the next socket in +the list, the 'nsid_is_set' will remain 'true' and the negative value +is be delivered to the user space. All subsequent nsid values will be +delivered as well, since there is no code path that sets the flag +back to 'false'. + +Fix that by always dropping the flag to 'false' first. + +Fixes: 7212462fa6fd ("netlink: don't send unknown nsid") +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-2-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 8b060465a2be1a..287b4f921c607e 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1477,6 +1477,7 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ NETLINK_CB(p->skb2).nsid_is_set = false; + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) + NETLINK_CB(p->skb2).nsid_is_set = true; +-- +2.53.0 + diff --git a/queue-6.12/net-sched-act_mirred-add-loop-detection.patch b/queue-6.12/net-sched-act_mirred-add-loop-detection.patch new file mode 100644 index 0000000000..4d27030bf0 --- /dev/null +++ b/queue-6.12/net-sched-act_mirred-add-loop-detection.patch @@ -0,0 +1,170 @@ +From 05b0fe4883ca44e8dae070151229f3ada6ff0ba6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Oct 2025 17:19:04 +0000 +Subject: net/sched: act_mirred: add loop detection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit fe946a751d9b52b7c45ca34899723b314b79b249 ] + +Commit 0f022d32c3ec ("net/sched: Fix mirred deadlock on device recursion") +added code in the fast path, even when act_mirred is not used. + +Prepare its revert by implementing loop detection in act_mirred. + +Adds an array of device pointers in struct netdev_xmit. + +tcf_mirred_is_act_redirect() can detect if the array +already contains the target device. + +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Toke Høiland-Jørgensen +Tested-by: Jamal Hadi Salim +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20251014171907.3554413-4-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: e80ad525fc7e ("net/sched: act_mirred: Fix return code in early mirred redirect error paths") +Signed-off-by: Sasha Levin +--- + include/linux/netdevice_xmit.h | 9 ++++- + net/sched/act_mirred.c | 62 +++++++++++++--------------------- + 2 files changed, 31 insertions(+), 40 deletions(-) + +diff --git a/include/linux/netdevice_xmit.h b/include/linux/netdevice_xmit.h +index 848735b3a7c02d..59726e6cd2cc67 100644 +--- a/include/linux/netdevice_xmit.h ++++ b/include/linux/netdevice_xmit.h +@@ -2,6 +2,12 @@ + #ifndef _LINUX_NETDEVICE_XMIT_H + #define _LINUX_NETDEVICE_XMIT_H + ++#if IS_ENABLED(CONFIG_NET_ACT_MIRRED) ++#define MIRRED_NEST_LIMIT 4 ++#endif ++ ++struct net_device; ++ + struct netdev_xmit { + u16 recursion; + u8 more; +@@ -9,7 +15,8 @@ struct netdev_xmit { + u8 skip_txqueue; + #endif + #if IS_ENABLED(CONFIG_NET_ACT_MIRRED) +- u8 sched_mirred_nest; ++ u8 sched_mirred_nest; ++ struct net_device *sched_mirred_dev[MIRRED_NEST_LIMIT]; + #endif + }; + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index 18d9378a9c1134..35812b6808e0a8 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -29,31 +29,6 @@ + static LIST_HEAD(mirred_list); + static DEFINE_SPINLOCK(mirred_list_lock); + +-#define MIRRED_NEST_LIMIT 4 +- +-#ifndef CONFIG_PREEMPT_RT +-static u8 tcf_mirred_nest_level_inc_return(void) +-{ +- return __this_cpu_inc_return(softnet_data.xmit.sched_mirred_nest); +-} +- +-static void tcf_mirred_nest_level_dec(void) +-{ +- __this_cpu_dec(softnet_data.xmit.sched_mirred_nest); +-} +- +-#else +-static u8 tcf_mirred_nest_level_inc_return(void) +-{ +- return current->net_xmit.sched_mirred_nest++; +-} +- +-static void tcf_mirred_nest_level_dec(void) +-{ +- current->net_xmit.sched_mirred_nest--; +-} +-#endif +- + static bool tcf_mirred_is_act_redirect(int action) + { + return action == TCA_EGRESS_REDIR || action == TCA_INGRESS_REDIR; +@@ -439,44 +414,53 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + { + struct tcf_mirred *m = to_mirred(a); + int retval = READ_ONCE(m->tcf_action); +- unsigned int nest_level; ++ struct netdev_xmit *xmit; + bool m_mac_header_xmit; + struct net_device *dev; +- int m_eaction; ++ int i, m_eaction; + u32 blockid; + +- nest_level = tcf_mirred_nest_level_inc_return(); +- if (unlikely(nest_level > MIRRED_NEST_LIMIT)) { ++#ifdef CONFIG_PREEMPT_RT ++ xmit = ¤t->net_xmit; ++#else ++ xmit = this_cpu_ptr(&softnet_data.xmit); ++#endif ++ if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT)) { + net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n", + netdev_name(skb->dev)); +- retval = TC_ACT_SHOT; +- goto dec_nest_level; ++ return TC_ACT_SHOT; + } + + tcf_lastuse_update(&m->tcf_tm); + tcf_action_update_bstats(&m->common, skb); + + blockid = READ_ONCE(m->tcfm_blockid); +- if (blockid) { +- retval = tcf_blockcast(skb, m, blockid, res, retval); +- goto dec_nest_level; +- } ++ if (blockid) ++ return tcf_blockcast(skb, m, blockid, res, retval); + + dev = rcu_dereference_bh(m->tcfm_dev); + if (unlikely(!dev)) { + pr_notice_once("tc mirred: target device is gone\n"); + tcf_action_inc_overlimit_qstats(&m->common); +- goto dec_nest_level; ++ return retval; + } ++ for (i = 0; i < xmit->sched_mirred_nest; i++) { ++ if (xmit->sched_mirred_dev[i] != dev) ++ continue; ++ pr_notice_once("tc mirred: loop on device %s\n", ++ netdev_name(dev)); ++ tcf_action_inc_overlimit_qstats(&m->common); ++ return retval; ++ } ++ ++ xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; + + m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); + m_eaction = READ_ONCE(m->tcfm_eaction); + + retval = tcf_mirred_to_dev(skb, m, dev, m_mac_header_xmit, m_eaction, + retval); +- +-dec_nest_level: +- tcf_mirred_nest_level_dec(); ++ xmit->sched_mirred_nest--; + + return retval; + } +-- +2.53.0 + diff --git a/queue-6.12/net-sched-act_mirred-fix-return-code-in-early-mirred.patch b/queue-6.12/net-sched-act_mirred-fix-return-code-in-early-mirred.patch new file mode 100644 index 0000000000..072145ef28 --- /dev/null +++ b/queue-6.12/net-sched-act_mirred-fix-return-code-in-early-mirred.patch @@ -0,0 +1,99 @@ +From 0dbbbc2ab2ba3d6976cc0d0913a7e17b77f2ec3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:54 -0400 +Subject: net/sched: act_mirred: Fix return code in early mirred redirect error + paths + +From: Victor Nogueira + +[ Upstream commit e80ad525fc7e8c933ad78478c5dda286cfd55c60 ] + +Since retval is set as TC_ACT_STOLEN in the mirred redirect case, returning +retval in cases where redirect failed will make the callers not register +the skb as being dropped. + +Fix this by returning TC_ACT_SHOT instead in such scenarios. + +Fixes: 16085e48cb48 ("net/sched: act_mirred: Create function tcf_mirred_to_dev and improve readability") +Reported-by: Sashiko +Closes: https://sashiko.dev/#/patchset/20260413082027.2244884-1-hxzene%40gmail.com +Signed-off-by: Victor Nogueira +Link: https://patch.msgid.link/20260525122556.973584-8-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index ae9b307ad66e0d..41b731176dfe77 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -363,7 +363,8 @@ static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m, + dev_is_mac_header_xmit(dev_prev), + m_eaction, retval); + +- return retval; ++ /* If the packet wasn't redirected, we have to register as a drop */ ++ return TC_ACT_SHOT; + } + + static int tcf_blockcast_mirror(struct sk_buff *skb, struct tcf_mirred *m, +@@ -403,7 +404,7 @@ static int tcf_blockcast(struct sk_buff *skb, struct tcf_mirred *m, + block = tcf_block_lookup(dev_net(skb->dev), blockid); + if (!block || xa_empty(&block->ports)) { + tcf_action_inc_overlimit_qstats(&m->common); +- return retval; ++ return is_redirect ? TC_ACT_SHOT : retval; + } + + if (is_redirect) +@@ -421,8 +422,8 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + { + struct tcf_mirred *m = to_mirred(a); + int retval = READ_ONCE(m->tcf_action); ++ bool m_mac_header_xmit, is_redirect; + struct netdev_xmit *xmit; +- bool m_mac_header_xmit; + struct net_device *dev; + bool want_ingress; + int i, m_eaction; +@@ -447,11 +448,13 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + if (blockid) + return tcf_blockcast(skb, m, blockid, res, retval); + ++ is_redirect = tcf_mirred_is_act_redirect(m_eaction); ++ + dev = rcu_dereference_bh(m->tcfm_dev); + if (unlikely(!dev)) { + pr_notice_once("tc mirred: target device is gone\n"); + tcf_action_inc_overlimit_qstats(&m->common); +- return retval; ++ goto err_out; + } + + m_eaction = READ_ONCE(m->tcfm_eaction); +@@ -463,7 +466,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + pr_notice_once("tc mirred: loop on device %s\n", + netdev_name(dev)); + tcf_action_inc_overlimit_qstats(&m->common); +- return retval; ++ goto err_out; + } + xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; + } +@@ -476,6 +479,11 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + xmit->sched_mirred_nest--; + + return retval; ++ ++err_out: ++ if (is_redirect) ++ retval = TC_ACT_SHOT; ++ return retval; + } + + static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets, +-- +2.53.0 + diff --git a/queue-6.12/net-sched-act_mirred-move-the-recursion-counter-stru.patch b/queue-6.12/net-sched-act_mirred-move-the-recursion-counter-stru.patch new file mode 100644 index 0000000000..0dd38f551c --- /dev/null +++ b/queue-6.12/net-sched-act_mirred-move-the-recursion-counter-stru.patch @@ -0,0 +1,99 @@ +From e1bd679da06931529a67c291b565cee93887021a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 May 2025 11:27:31 +0200 +Subject: net/sched: act_mirred: Move the recursion counter struct netdev_xmit + +From: Sebastian Andrzej Siewior + +[ Upstream commit 7fe70c06a182a140be9996b02256d907e114479a ] + +mirred_nest_level is a per-CPU variable and relies on disabled BH for its +locking. Without per-CPU locking in local_bh_disable() on PREEMPT_RT +this data structure requires explicit locking. + +Move mirred_nest_level to struct netdev_xmit as u8, provide wrappers. + +Cc: Jamal Hadi Salim +Cc: Cong Wang +Cc: Jiri Pirko +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Juri Lelli +Link: https://patch.msgid.link/20250512092736.229935-11-bigeasy@linutronix.de +Signed-off-by: Paolo Abeni +Stable-dep-of: e80ad525fc7e ("net/sched: act_mirred: Fix return code in early mirred redirect error paths") +Signed-off-by: Sasha Levin +--- + include/linux/netdevice_xmit.h | 3 +++ + net/sched/act_mirred.c | 28 +++++++++++++++++++++++++--- + 2 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/include/linux/netdevice_xmit.h b/include/linux/netdevice_xmit.h +index 38325e07029685..848735b3a7c02d 100644 +--- a/include/linux/netdevice_xmit.h ++++ b/include/linux/netdevice_xmit.h +@@ -8,6 +8,9 @@ struct netdev_xmit { + #ifdef CONFIG_NET_EGRESS + u8 skip_txqueue; + #endif ++#if IS_ENABLED(CONFIG_NET_ACT_MIRRED) ++ u8 sched_mirred_nest; ++#endif + }; + + #endif +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index b1b0049d7a0e9d..18d9378a9c1134 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -30,7 +30,29 @@ static LIST_HEAD(mirred_list); + static DEFINE_SPINLOCK(mirred_list_lock); + + #define MIRRED_NEST_LIMIT 4 +-static DEFINE_PER_CPU(unsigned int, mirred_nest_level); ++ ++#ifndef CONFIG_PREEMPT_RT ++static u8 tcf_mirred_nest_level_inc_return(void) ++{ ++ return __this_cpu_inc_return(softnet_data.xmit.sched_mirred_nest); ++} ++ ++static void tcf_mirred_nest_level_dec(void) ++{ ++ __this_cpu_dec(softnet_data.xmit.sched_mirred_nest); ++} ++ ++#else ++static u8 tcf_mirred_nest_level_inc_return(void) ++{ ++ return current->net_xmit.sched_mirred_nest++; ++} ++ ++static void tcf_mirred_nest_level_dec(void) ++{ ++ current->net_xmit.sched_mirred_nest--; ++} ++#endif + + static bool tcf_mirred_is_act_redirect(int action) + { +@@ -423,7 +445,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + int m_eaction; + u32 blockid; + +- nest_level = __this_cpu_inc_return(mirred_nest_level); ++ nest_level = tcf_mirred_nest_level_inc_return(); + if (unlikely(nest_level > MIRRED_NEST_LIMIT)) { + net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n", + netdev_name(skb->dev)); +@@ -454,7 +476,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + retval); + + dec_nest_level: +- __this_cpu_dec(mirred_nest_level); ++ tcf_mirred_nest_level_dec(); + + return retval; + } +-- +2.53.0 + diff --git a/queue-6.12/net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch b/queue-6.12/net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch new file mode 100644 index 0000000000..4a9b5db549 --- /dev/null +++ b/queue-6.12/net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch @@ -0,0 +1,136 @@ +From 3baa1fb4063a7688344267fcbce344fced937bc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:52 -0400 +Subject: net/sched: Fix ethx:ingress -> ethy:egress -> ethx:ingress mirred + loop + +From: Jamal Hadi Salim + +[ Upstream commit db875221ab08d213a83bf30196ae8b64d55a3403 ] + +When mirred redirects to ingress (from either ingress or egress) the loop +state from sched_mirred_dev array dev is lost because of 1) the packet +deferral into the backlog and 2) the fact the sched_mirred_dev array is +cleared. In such cases, if there was a loop we won't discover it. + +Here's a simple test to reproduce: +ip a add dev port0 10.10.10.11/24 + +tc qdisc add dev port0 clsact +tc filter add dev port0 egress protocol ip \ + prio 10 matchall action mirred ingress redirect dev port1 + +tc qdisc add dev port1 clsact +tc filter add dev port1 ingress protocol ip \ + prio 10 matchall action mirred egress redirect dev port0 + +ping -c 1 -W0.01 10.10.10.10 + +Fixes: fe946a751d9b ("net/sched: act_mirred: add loop detection") +Tested-by: Victor Nogueira +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-6-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Stable-dep-of: e80ad525fc7e ("net/sched: act_mirred: Fix return code in early mirred redirect error paths") +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 47 +++++++++++++++++++++++++++--------------- + 1 file changed, 30 insertions(+), 17 deletions(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index 35812b6808e0a8..ae9b307ad66e0d 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -26,6 +26,10 @@ + #include + #include + ++#define MIRRED_DEFER_LIMIT 3 ++_Static_assert(MIRRED_DEFER_LIMIT <= 3, ++ "MIRRED_DEFER_LIMIT exceeds tc_depth bitfield width"); ++ + static LIST_HEAD(mirred_list); + static DEFINE_SPINLOCK(mirred_list_lock); + +@@ -234,12 +238,15 @@ tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb) + { + int err; + +- if (!want_ingress) ++ if (!want_ingress) { + err = tcf_dev_queue_xmit(skb, dev_queue_xmit); +- else if (!at_ingress) +- err = netif_rx(skb); +- else +- err = netif_receive_skb(skb); ++ } else { ++ skb->tc_depth++; ++ if (!at_ingress) ++ err = netif_rx(skb); ++ else ++ err = netif_receive_skb(skb); ++ } + + return err; + } +@@ -417,6 +424,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + struct netdev_xmit *xmit; + bool m_mac_header_xmit; + struct net_device *dev; ++ bool want_ingress; + int i, m_eaction; + u32 blockid; + +@@ -425,7 +433,8 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + #else + xmit = this_cpu_ptr(&softnet_data.xmit); + #endif +- if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT)) { ++ if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT || ++ skb->tc_depth >= MIRRED_DEFER_LIMIT)) { + net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n", + netdev_name(skb->dev)); + return TC_ACT_SHOT; +@@ -444,23 +453,27 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + tcf_action_inc_overlimit_qstats(&m->common); + return retval; + } +- for (i = 0; i < xmit->sched_mirred_nest; i++) { +- if (xmit->sched_mirred_dev[i] != dev) +- continue; +- pr_notice_once("tc mirred: loop on device %s\n", +- netdev_name(dev)); +- tcf_action_inc_overlimit_qstats(&m->common); +- return retval; +- } + +- xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; ++ m_eaction = READ_ONCE(m->tcfm_eaction); ++ want_ingress = tcf_mirred_act_wants_ingress(m_eaction); ++ if (!want_ingress) { ++ for (i = 0; i < xmit->sched_mirred_nest; i++) { ++ if (xmit->sched_mirred_dev[i] != dev) ++ continue; ++ pr_notice_once("tc mirred: loop on device %s\n", ++ netdev_name(dev)); ++ tcf_action_inc_overlimit_qstats(&m->common); ++ return retval; ++ } ++ xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; ++ } + + m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); +- m_eaction = READ_ONCE(m->tcfm_eaction); + + retval = tcf_mirred_to_dev(skb, m, dev, m_mac_header_xmit, m_eaction, + retval); +- xmit->sched_mirred_nest--; ++ if (!want_ingress) ++ xmit->sched_mirred_nest--; + + return retval; + } +-- +2.53.0 + diff --git a/queue-6.12/net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch b/queue-6.12/net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch new file mode 100644 index 0000000000..554070de1e --- /dev/null +++ b/queue-6.12/net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch @@ -0,0 +1,71 @@ +From 17b4e7dc1eb95443953d4bd2d4fea853e48dc36a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:51 -0400 +Subject: net/sched: fix packet loop on netem when duplicate is on + +From: Jamal Hadi Salim + +[ Upstream commit 9552b11e3edabc97cfcd9f29103d5afbce7ae183 ] + +When netem duplicates a packet it re-enqueues the copy at the root qdisc. +If another netem sits in the tree the copy can be duplicated +again, recursing until the stack or memory is exhausted. + +The original duplication guard temporarily zeroed q->duplicate around +the re-enqueue, but that does not cover all cases because it is +per-qdisc state shared across all concurrent enqueue paths +and is not safe without additional locking. + +Use the skb tc_depth field introduced in an earlier patch: + - increment it on the duplicate before re-enqueue + - skip duplication for any skb whose tc_depth is already non-zero. + +This marks the packet itself rather than mutating qdisc state, +therefore it is safe regardless of tree topology or concurrency. + +Fixes: 0afb51e72855 ("[PKT_SCHED]: netem: reinsert for duplication") +Reported-by: William Liu +Reported-by: Savino Dicanosa +Closes: https://lore.kernel.org/netdev/8DuRWwfqjoRDLDmBMlIfbrsZg9Gx50DHJc1ilxsEBNe2D6NMoigR_eIRIG0LOjMc3r10nUUZtArXx4oZBIdUfZQrwjcQhdinnMis_0G7VEk=@willsroot.io/ +Co-developed-by: Victor Nogueira +Signed-off-by: Victor Nogueira +Reviewed-by: William Liu +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-5-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 1fdebf2ab7ee46..136b7d81296eff 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -459,7 +459,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + skb->prev = NULL; + + /* Random duplication */ +- if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor, &q->prng)) ++ if (q->duplicate && skb->tc_depth == 0 && ++ q->duplicate >= get_crandom(&q->dup_cor, &q->prng)) + ++count; + + /* Drop packet? */ +@@ -538,11 +539,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + */ + if (skb2) { + struct Qdisc *rootq = qdisc_root_bh(sch); +- u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ + +- q->duplicate = 0; ++ skb2->tc_depth++; /* prevent duplicating a dup... */ + rootq->enqueue(skb2, rootq, to_free); +- q->duplicate = dupsave; + skb2 = NULL; + } + +-- +2.53.0 + diff --git a/queue-6.12/net-sched-revert-net-sched-restrict-conditions-for-a.patch b/queue-6.12/net-sched-revert-net-sched-restrict-conditions-for-a.patch new file mode 100644 index 0000000000..9081d5677d --- /dev/null +++ b/queue-6.12/net-sched-revert-net-sched-restrict-conditions-for-a.patch @@ -0,0 +1,102 @@ +From 73f565fe71ea2136ff92eb2bac6514e173d7debc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:49 -0400 +Subject: net/sched: Revert "net/sched: Restrict conditions for adding + duplicating netems to qdisc tree" + +From: Jamal Hadi Salim + +[ Upstream commit eda0b7f203bb166c98d1418b204135bd566ac83b ] + +This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. + +The original patch rejects any tree containing two netems when +either has duplication set, even when they sit on unrelated classes +of the same classful parent. That broke configurations that have +worked since netem was introduced. + +The re-entrancy problem the original commit was trying to solve is +handled by later patch using tc_depth flag. + +Doing this revert will (re)expose the original bug with multiple +netem duplication. When this patch is backported make sure +and get the full series. + +Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") +Reported-by: Ji-Soo Chung +Reported-by: Gerlinde +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 +Reported-by: zyc zyc +Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ +Reported-by: Manas Ghandat +Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 40 ---------------------------------------- + 1 file changed, 40 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 498c18d7d9c39b..1fdebf2ab7ee46 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1005,41 +1005,6 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, + return 0; + } + +-static const struct Qdisc_class_ops netem_class_ops; +- +-static int check_netem_in_tree(struct Qdisc *sch, bool duplicates, +- struct netlink_ext_ack *extack) +-{ +- struct Qdisc *root, *q; +- unsigned int i; +- +- root = qdisc_root_sleeping(sch); +- +- if (sch != root && root->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(root))->duplicate) +- goto err; +- } +- +- if (!qdisc_dev(root)) +- return 0; +- +- hash_for_each(qdisc_dev(root)->qdisc_hash, i, q, hash) { +- if (sch != q && q->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(q))->duplicate) +- goto err; +- } +- } +- +- return 0; +- +-err: +- NL_SET_ERR_MSG(extack, +- "netem: cannot mix duplicating netems with other netems in tree"); +- return -EINVAL; +-} +- + /* Parse netlink message to set options */ + static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +@@ -1116,11 +1081,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + q->gap = qopt->gap; + q->counter = 0; + q->loss = qopt->loss; +- +- ret = check_netem_in_tree(sch, qopt->duplicate, extack); +- if (ret) +- goto unlock; +- + q->duplicate = qopt->duplicate; + + /* for compatibility with earlier versions. +-- +2.53.0 + diff --git a/queue-6.12/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch b/queue-6.12/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch new file mode 100644 index 0000000000..1011920b8b --- /dev/null +++ b/queue-6.12/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch @@ -0,0 +1,64 @@ +From bd33ff9a6462c8f47edb5a624bede3a0f5cab6dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:43:53 +0100 +Subject: net: skbuff: fix pskb_carve leaking zcopy pages + +From: Pavel Begunkov + +[ Upstream commit ff6e798c2eac3ebd0501ad7e796f583fab928de8 ] + +When SKBFL_MANAGED_FRAG_REFS is set, frag pages are not refcounted but +their lifetime is controlled by the attached ubuf_info. To make a copy +of the skb_shared_info, we either should clear the flag and reference +the frags, or keep the flag and have frags unreferenced. + +pskb_carve_inside_header() and pskb_carve_inside_nonlinear() don't +follow the rule and thus can leak page references. Let's clear +SKBFL_MANAGED_FRAG_REFS from the original skb to fix it. It's the +simplest way to address it, but there are more performant ways to do +that if it ever becomes a problem. + +Link: https://lore.kernel.org/all/20260523085809.26331-1-nvminh232@clc.fitus.edu.vn/ +Fixes: 753f1ca4e1e50 ("net: introduce managed frags infrastructure") +Reported-by: Minh Nguyen +Reported-by: Willem de Bruijn +Signed-off-by: Pavel Begunkov +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/1e2086aa69217d7f9c8da3d38f5be7160f1b4cd1.1779993185.git.asml.silence@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 8c9f026182a6f0..c8653ed1991ae0 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6689,6 +6689,11 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, + skb_copy_from_linear_data_offset(skb, off, data, new_hlen); + skb->len -= off; + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), + offsetof(struct skb_shared_info, +@@ -6801,6 +6806,11 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, + return -ENOMEM; + size = SKB_WITH_OVERHEAD(size); + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0])); + if (skb_orphan_frags(skb, gfp_mask)) { +-- +2.53.0 + diff --git a/queue-6.12/net-smc-do-not-re-initialize-smc-hashtables.patch b/queue-6.12/net-smc-do-not-re-initialize-smc-hashtables.patch new file mode 100644 index 0000000000..e04e490590 --- /dev/null +++ b/queue-6.12/net-smc-do-not-re-initialize-smc-hashtables.patch @@ -0,0 +1,59 @@ +From 6f8d315da8edbeca5a96360e65f25bbe546c3bde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 16:56:39 +0200 +Subject: net/smc: Do not re-initialize smc hashtables + +From: Alexandra Winter + +[ Upstream commit 9e4389b0038781f19f97895186ed941ff8ac1678 ] + +INIT_HLIST_HEAD(&smc_v*_hashinfo.ht) are called after smc_nl_init(), +proto_register() and sock_register(). This can lead to smc_v*_hashinfo.ht +being reset even though hash entries already exist and are being used, +possibly resulting in a corrupted list. + +Remove unnecessary and dangerous re-initialisation of smc_v*_hashinfo.ht in +smc_init(); it is implicitly initialised to zero anyhow. Add +HLIST_HEAD_INIT to the definitions for clarity. + +Fixes: f16a7dd5cf27 ("smc: netlink interface for SMC sockets") +Suggested-by: Halil Pasic +Signed-off-by: Alexandra Winter +Acked-by: Halil Pasic +Reviewed-by: Mahanta Jambigi +Link: https://patch.msgid.link/20260521145639.10317-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index c96abb1386be4b..6f3469ad54a165 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -187,10 +187,12 @@ static bool smc_hs_congested(const struct sock *sk) + + struct smc_hashinfo smc_v4_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + int smc_hash_sk(struct sock *sk) +@@ -3594,8 +3596,6 @@ static int __init smc_init(void) + pr_err("%s: sock_register fails with %d\n", __func__, rc); + goto out_proto6; + } +- INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); +- INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); + + rc = smc_ib_register_client(); + if (rc) { +-- +2.53.0 + diff --git a/queue-6.12/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch b/queue-6.12/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch new file mode 100644 index 0000000000..8af1234b8b --- /dev/null +++ b/queue-6.12/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch @@ -0,0 +1,107 @@ +From 93d5aa2ceb11b27e7ae2c6ea1e0f2865c1cb4667 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 22:52:07 +0200 +Subject: netfilter: ebtables: fix OOB read in compat_mtw_from_user + +From: Florian Westphal + +[ Upstream commit f438d1786d657d57790c5d138d6db3fc9fdac392 ] + +Luxiao Xu says: + + The function compat_mtw_from_user() converts ebtables extensions from + 32-bit user structures to kernel native structures. However, it lacks + proper validation of the user-supplied match_size/target_size. + + When certain extensions are processed, the kernel-side translation + logic may perform memory accesses based on the extension's expected + size. If the user provides a size smaller than what the extension + requires, it results in an out-of-bounds read as reported by KASAN. + + This fix introduces a check to ensure match_size is at least as large + as the extension's required compatsize. This covers matches, watchers, + and targets, while maintaining compatibility with standard targets. + +AFAIU this is relevant for matches that need to go though +match->compat_from_user() call. Those that use plain memcpy with the +user-provided size are ok because the caller checks that size vs the +start of the next rule entry offset (which itself is checked vs. total +size copied from userspace). + +The ->compat_from_user() callbacks assume they can read compatsize bytes, +so they need this extra check. + +Based on an earlier patch from Luxiao Xu. + +Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index a461c59ad28595..1bc7b5d8f76d7a 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1952,6 +1952,25 @@ enum compat_mwt { + EBT_COMPAT_TARGET, + }; + ++static bool match_size_ok(const struct xt_match *match, unsigned int match_size) ++{ ++ u16 csize; ++ ++ if (match->matchsize == -1) /* cannot validate ebt_among */ ++ return true; ++ ++ csize = match->compatsize ? : match->matchsize; ++ ++ return match_size >= csize; ++} ++ ++static bool tgt_size_ok(const struct xt_target *tgt, unsigned int tgt_size) ++{ ++ u16 csize = tgt->compatsize ? : tgt->targetsize; ++ ++ return tgt_size >= csize; ++} ++ + static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + enum compat_mwt compat_mwt, + struct ebt_entries_buf_state *state, +@@ -1977,6 +1996,11 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + if (IS_ERR(match)) + return PTR_ERR(match); + ++ if (!match_size_ok(match, match_size)) { ++ module_put(match->me); ++ return -EINVAL; ++ } ++ + off = ebt_compat_match_offset(match, match_size); + if (dst) { + if (match->compat_from_user) +@@ -1996,6 +2020,12 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + mwt->u.revision); + if (IS_ERR(wt)) + return PTR_ERR(wt); ++ ++ if (!tgt_size_ok(wt, match_size)) { ++ module_put(wt->me); ++ return -EINVAL; ++ } ++ + off = xt_compat_target_offset(wt); + + if (dst) { +-- +2.53.0 + diff --git a/queue-6.12/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch b/queue-6.12/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch new file mode 100644 index 0000000000..bbffcf624c --- /dev/null +++ b/queue-6.12/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch @@ -0,0 +1,68 @@ +From a3f3f69a35f27105f687f284f50ac318b03783e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 12:36:14 -0700 +Subject: netfilter: synproxy: refresh tcphdr after skb_ensure_writable + +From: Chris Mason + +[ Upstream commit 92170e6afe927ab2792a3f71902845789c8e31b1 ] + +synproxy_tstamp_adjust() rewrites the TCP timestamp option in place +and then patches the TCP checksum via inet_proto_csum_replace4() on +the caller-supplied tcphdr pointer. Both ipv4_synproxy_hook() and +ipv6_synproxy_hook() obtain that pointer with skb_header_pointer() +before calling in, so it may either alias skb->head directly or +point at the caller's on-stack _tcph buffer. + +Between obtaining the pointer and using it, the function calls +skb_ensure_writable(skb, optend), which on a cloned or non-linear +skb invokes pskb_expand_head() and frees the old skb->head. After +that point the cached th is stale: + + caller (ipv[46]_synproxy_hook) + th = skb_header_pointer(skb, ..., &_tcph) + synproxy_tstamp_adjust(skb, protoff, th, ...) + skb_ensure_writable(skb, optend) + pskb_expand_head() /* kfree(old skb->head) */ + ... + inet_proto_csum_replace4(&th->check, ...) + /* writes into freed head, or + into the caller's stack copy + leaving the on-wire checksum + stale */ + +The option bytes are written through skb->data and are fine; only +the checksum update goes through th and so lands in the wrong +place. The result is either a write into freed slab memory or a +packet leaving with a checksum that does not match its payload. + +Fix by re-deriving th from skb->data + protoff immediately after +skb_ensure_writable() succeeds, so the subsequent checksum update +targets the linear, writable header. + +Fixes: 48b1de4c110a ("netfilter: add SYNPROXY core/target") +Assisted-by: kres (claude-opus-4-7) +Signed-off-by: Chris Mason +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 3fa3f5dfb26444..6a851ac4dd048f 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -199,6 +199,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + if (skb_ensure_writable(skb, optend)) + return 0; + ++ th = (struct tcphdr *)(skb->data + protoff); ++ + while (optoff < optend) { + unsigned char *op = skb->data + optoff; + +-- +2.53.0 + diff --git a/queue-6.12/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch b/queue-6.12/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..1f8c2d9e0e --- /dev/null +++ b/queue-6.12/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch @@ -0,0 +1,48 @@ +From 474ca2dd9fd541b704fc995088c7265004a9d169 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 20:10:08 +0200 +Subject: netfilter: xt_cpu: prefer raw_smp_processor_id + +From: Florian Westphal + +[ Upstream commit c376f07e16c02239ed44cabb97145d03f65b4d15 ] + +With PREEMPT_RCU we get splat: + +BUG: using smp_processor_id() in preemptible [..] +caller is cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 +CPU: 1 .. Comm: syz.3.1377 #0 PREEMPT(full) +Call Trace: + + dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 + check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 + cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 + [..] + +Just use raw version instead. +This is similar to 14d14a5d2957 ("netfilter: nft_meta: use raw_smp_processor_id()"). + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reported-by: syzbot+690d3e3ffa7335ac10eb@syzkaller.appspotmail.com +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c +index 3bdc302a0f9137..9cb259902a586b 100644 +--- a/net/netfilter/xt_cpu.c ++++ b/net/netfilter/xt_cpu.c +@@ -34,7 +34,7 @@ static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_cpu_info *info = par->matchinfo; + +- return (info->cpu == smp_processor_id()) ^ info->invert; ++ return (info->cpu == raw_smp_processor_id()) ^ info->invert; + } + + static struct xt_match cpu_mt_reg __read_mostly = { +-- +2.53.0 + diff --git a/queue-6.12/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch b/queue-6.12/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch new file mode 100644 index 0000000000..c072d44419 --- /dev/null +++ b/queue-6.12/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch @@ -0,0 +1,40 @@ +From e32f9da0e5e8c98559a32bdd7f4bfb97ef8472b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:41 +0000 +Subject: nfc: llcp: Fix use-after-free in llcp_sock_release() + +From: Lee Jones + +[ Upstream commit f4268b466190dae95a7585f69b4f1f8ad097632c ] + +llcp_sock_release() unconditionally unlinks the socket from the local +sockets list. However, if the socket is still in connecting state, it +is on the connecting list. + +Fix this by checking the socket state and unlinking from the correct list. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Signed-off-by: Lee Jones +Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index 57a2f97004e172..915929cd724f90 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -633,6 +633,8 @@ static int llcp_sock_release(struct socket *sock) + + if (sock->type == SOCK_RAW) + nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else if (sk->sk_state == LLCP_CONNECTING) ++ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + else + nfc_llcp_sock_unlink(&local->sockets, sk); + +-- +2.53.0 + diff --git a/queue-6.12/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch b/queue-6.12/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch new file mode 100644 index 0000000000..c38296823e --- /dev/null +++ b/queue-6.12/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch @@ -0,0 +1,67 @@ +From bca7cd838c840b754401ac406e03bd90bd1ba27e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:42 +0000 +Subject: nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() + +From: Lee Jones + +[ Upstream commit b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 ] + +A race condition exists in the NFC LLCP connection state machine where +the connection acceptance packet (CC) can be processed concurrently with +socket release. This can lead to a use-after-free of the socket object. + +When nfc_llcp_recv_cc() moves the socket from the connecting_sockets +list to the sockets list, it does so without holding the socket lock. +If llcp_sock_release() is executing concurrently, it might have already +unlinked the socket and dropped its references, which can result in +nfc_llcp_recv_cc() linking a freed socket into the live list. + +Fix this by holding lock_sock() during the state transition and list +movement in nfc_llcp_recv_cc(). After acquiring the lock, check if +the socket is still hashed to ensure it hasn't already been unlinked +and marked for destruction by the release path. This aligns the locking +pattern with recv_hdlc() and recv_disc(). + +Fixes: a69f32af86e3 ("NFC: Socket linked list") +Signed-off-by: Lee Jones +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index d9562840fa180b..62b0f2d6686eb8 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -1216,6 +1216,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + + sk = &llcp_sock->sk; + ++ lock_sock(sk); ++ ++ /* Check if socket was destroyed whilst waiting for the lock */ ++ if (!sk_hashed(sk)) { ++ release_sock(sk); ++ nfc_llcp_sock_put(llcp_sock); ++ return; ++ } ++ + /* Unlink from connecting and link to the client array */ + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + nfc_llcp_sock_link(&local->sockets, sk); +@@ -1227,6 +1236,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + ++ release_sock(sk); ++ + nfc_llcp_sock_put(llcp_sock); + } + +-- +2.53.0 + diff --git a/queue-6.12/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch b/queue-6.12/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch new file mode 100644 index 0000000000..c12e27293c --- /dev/null +++ b/queue-6.12/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch @@ -0,0 +1,83 @@ +From b693df0a9400e622e7eb02304badec065ed62734 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 May 2026 19:55:18 +0800 +Subject: nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems + +From: Carl Lee + +[ Upstream commit f23bf992d65a42007c517b060ca35cebdea3525a ] + +Some ACPI-based platforms report incorrect IRQ trigger types (e.g. +IRQF_TRIGGER_HIGH), which can lead to interrupt storms. + +Use the historically working rising-edge trigger on ACPI systems to +avoid this regression. + +Device Tree-based systems continue to use the firmware-provided +trigger type. + +Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") +Signed-off-by: Carl Lee +Tested-by: Bartosz Golaszewski +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Mark Pearson +Tested-by: Mark Pearson +Tested-by: Luca Stefani +Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index b3d34433bd14a0..a6c08175d9dd93 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -267,6 +268,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + { + struct device *dev = &client->dev; + struct nxp_nci_i2c_phy *phy; ++ unsigned long irqflags; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +@@ -303,9 +305,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + if (r < 0) + return r; + ++ /* ++ * ACPI platforms may report incorrect IRQ trigger types ++ * (e.g. level-high), which can lead to interrupt storms. ++ * ++ * Use the historically stable rising-edge trigger for ACPI devices. ++ * ++ * On non-ACPI systems (e.g. Device Tree), prefer the firmware- ++ * provided trigger type, falling back to rising-edge if not set. ++ */ ++ if (ACPI_COMPANION(dev)) { ++ irqflags = IRQF_TRIGGER_RISING; ++ } else { ++ irqflags = irq_get_trigger_type(client->irq); ++ if (!irqflags) ++ irqflags = IRQF_TRIGGER_RISING; ++ } ++ + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, +- IRQF_ONESHOT, ++ irqflags | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); +-- +2.53.0 + diff --git a/queue-6.12/nvme-tcp-store-negative-errno-in-queue-tls_err.patch b/queue-6.12/nvme-tcp-store-negative-errno-in-queue-tls_err.patch new file mode 100644 index 0000000000..52e063aa60 --- /dev/null +++ b/queue-6.12/nvme-tcp-store-negative-errno-in-queue-tls_err.patch @@ -0,0 +1,52 @@ +From 3e8c69447edbddd4321f2494b202a2fdacc9cd1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:16 -0400 +Subject: nvme-tcp: store negative errno in queue->tls_err + +From: Chuck Lever + +[ Upstream commit 9015985b5eb1a90eb86caf5bce1dfcf1aa38f8ad ] + +nvme_tcp_tls_done() assigns queue->tls_err in three branches. The +ENOKEY lookup failure and the EOPNOTSUPP initializer both store +negative errnos. The third branch, reached when the handshake +layer reports a non-zero status, stores -status. + +The handshake layer delivers status to the consumer callback as a +negative errno; the other in-tree consumers -- +xs_tls_handshake_done() and the nvmet target callback -- treat +their status argument that way. The extra negation in +nvme_tcp_tls_done() flips the sign, leaving tls_err as a positive +value (for instance, +EIO), which nvme_tcp_start_tls() then +returns to its caller. + +Drop the extra negation so queue->tls_err uniformly carries a +negative errno on failure. + +Fixes: be8e82caa685 ("nvme-tcp: enable TLS handshake upcall") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Reviewed-by: Alistair Francis +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-2-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/tcp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 77df3432dfb78e..31406438e3ff2d 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1719,7 +1719,7 @@ static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid) + qid, pskid, status); + + if (status) { +- queue->tls_err = -status; ++ queue->tls_err = status; + goto out_complete; + } + +-- +2.53.0 + diff --git a/queue-6.12/remove-pointless-includes-of-linux-fdtable.h.patch b/queue-6.12/remove-pointless-includes-of-linux-fdtable.h.patch new file mode 100644 index 0000000000..a13dbc4548 --- /dev/null +++ b/queue-6.12/remove-pointless-includes-of-linux-fdtable.h.patch @@ -0,0 +1,228 @@ +From 6e90a97da649cd482a91d91e149892fe6ebc14d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 2 Jun 2024 23:58:44 -0400 +Subject: remove pointless includes of + +From: Al Viro + +[ Upstream commit be5498cac2ddb112c5bd7433d5e834a1a2493427 ] + +some of those used to be needed, some had been cargo-culted for +no reason... + +Reviewed-by: Christian Brauner +Signed-off-by: Al Viro +Stable-dep-of: ea5fe6a73ca5 ("net/handshake: Drain pending requests at net namespace exit") +Signed-off-by: Sasha Levin +--- + fs/fcntl.c | 1 - + fs/file_table.c | 1 - + fs/notify/fanotify/fanotify.c | 1 - + fs/notify/fanotify/fanotify_user.c | 1 - + fs/overlayfs/copy_up.c | 1 - + fs/proc/base.c | 1 - + io_uring/io_uring.c | 1 - + kernel/bpf/bpf_inode_storage.c | 1 - + kernel/bpf/bpf_task_storage.c | 1 - + kernel/bpf/token.c | 1 - + kernel/exit.c | 1 - + kernel/module/dups.c | 1 - + kernel/module/kmod.c | 1 - + kernel/umh.c | 1 - + net/handshake/request.c | 1 - + security/apparmor/domain.c | 1 - + 16 files changed, 16 deletions(-) + +diff --git a/fs/fcntl.c b/fs/fcntl.c +index 3d89de31066ae0..a7947a615db6b4 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -12,7 +12,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/fs/file_table.c b/fs/file_table.c +index f7661a70874640..2a08bc93b0b9c1 100644 +--- a/fs/file_table.c ++++ b/fs/file_table.c +@@ -9,7 +9,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index bb00e1e1683838..4d86a05258b970 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -1,6 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0 + #include +-#include + #include + #include + #include +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 93c1619cdad659..b89ad128bf09cf 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1,7 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + #include + #include +-#include + #include + #include + #include +diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c +index 57f635d050eb5a..75e804bc152ccf 100644 +--- a/fs/overlayfs/copy_up.c ++++ b/fs/overlayfs/copy_up.c +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + #include + #include "overlayfs.h" +diff --git a/fs/proc/base.c b/fs/proc/base.c +index d060af34a6e837..704cf6a0612ede 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -58,7 +58,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index eef59b9eccfab1..e515aeafa87813 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -51,7 +51,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/kernel/bpf/bpf_inode_storage.c b/kernel/bpf/bpf_inode_storage.c +index 29da6d3838f678..e16e79f8cd6dc3 100644 +--- a/kernel/bpf/bpf_inode_storage.c ++++ b/kernel/bpf/bpf_inode_storage.c +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + + DEFINE_BPF_STORAGE_CACHE(inode_cache); +diff --git a/kernel/bpf/bpf_task_storage.c b/kernel/bpf/bpf_task_storage.c +index adf6dfe0ba68a4..1eb9852a9f8ebb 100644 +--- a/kernel/bpf/bpf_task_storage.c ++++ b/kernel/bpf/bpf_task_storage.c +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + + DEFINE_BPF_STORAGE_CACHE(task_cache); +diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c +index dcbec1a0dfb33f..26057aa1350398 100644 +--- a/kernel/bpf/token.c ++++ b/kernel/bpf/token.c +@@ -1,6 +1,5 @@ + #include + #include +-#include + #include + #include + #include +diff --git a/kernel/exit.c b/kernel/exit.c +index b91124b2d334ee..e798078f958c89 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/kernel/module/dups.c b/kernel/module/dups.c +index 9a92f2f8c9d382..bd2149fbe11738 100644 +--- a/kernel/module/dups.c ++++ b/kernel/module/dups.c +@@ -18,7 +18,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/kernel/module/kmod.c b/kernel/module/kmod.c +index 0800d989169219..25f25381251281 100644 +--- a/kernel/module/kmod.c ++++ b/kernel/module/kmod.c +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/kernel/umh.c b/kernel/umh.c +index ff1f13a27d29fd..be923427077731 100644 +--- a/kernel/umh.c ++++ b/kernel/umh.c +@@ -13,7 +13,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 2f58d74f16554b..62efb7e32730ea 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -13,7 +13,6 @@ + #include + #include + #include +-#include + #include + + #include +diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c +index cccd61cca509ce..fbfb1d48dc88f2 100644 +--- a/security/apparmor/domain.c ++++ b/security/apparmor/domain.c +@@ -9,7 +9,6 @@ + */ + + #include +-#include + #include + #include + #include +-- +2.53.0 + diff --git a/queue-6.12/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch b/queue-6.12/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch new file mode 100644 index 0000000000..337f139066 --- /dev/null +++ b/queue-6.12/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch @@ -0,0 +1,80 @@ +From 9049be25251be93e9fc5e207468e8262b9c5dd80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 14:09:41 -0400 +Subject: scsi: core: Run queues for all non-SDEV_DEL devices from + scsi_run_host_queues + +From: David Jeffery + +[ Upstream commit 7205b58702273baf21d6ba7992e6ba15852325f7 ] + +While a SCSI host is in a recovery state, scsi_mq_requeue_cmd() will not +set the requeue list for a requeued command to be kicked in the future. +The expectation is a call to scsi_run_host_queues() will kick all SCSI +devices once the recovery state is cleared. + +However, scsi_run_host_queues() uses shost_for_each_device() which uses +scsi_device_get() and so will ignore devices in a partially removed +state like SDEV_CANCEL. But these devices may also have requeued +requests, leaving their requests stuck from not being kicked and causing +the removal process of the device to hang. + +scsi_run_host_queues() needs to run against more devices than the macro +shost_for_each_device() allows. Instead of using the too limiting +scsi_device_get() state checks, only ignore devices in SDEV_DEL state or +when unable to acquire a reference. Attempt to run the queues for all +other devices when scsi_run_host_queues() is called. + +Fixes: 8b566edbdbfb ("scsi: core: Only kick the requeue list if necessary") +Signed-off-by: David Jeffery +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260515180941.9698-1-djeffery@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/scsi_lib.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index 55717fd3234be2..d63d10d53a2aad 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -569,10 +569,33 @@ void scsi_requeue_run_queue(struct work_struct *work) + + void scsi_run_host_queues(struct Scsi_Host *shost) + { +- struct scsi_device *sdev; ++ struct scsi_device *sdev, *prev = NULL; ++ unsigned long flags; + +- shost_for_each_device(sdev, shost) ++ spin_lock_irqsave(shost->host_lock, flags); ++ __shost_for_each_device(sdev, shost) { ++ /* ++ * Only skip devices so deep into removal they will never need ++ * another kick to their queues. Thus scsi_device_get() cannot ++ * be used as it would skip devices in SDEV_CANCEL state which ++ * may need a queue kick. ++ */ ++ if (sdev->sdev_state == SDEV_DEL || ++ !get_device(&sdev->sdev_gendev)) ++ continue; ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ ++ if (prev) ++ put_device(&prev->sdev_gendev); + scsi_run_queue(sdev->request_queue); ++ ++ prev = sdev; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ if (prev) ++ put_device(&prev->sdev_gendev); + } + + static void scsi_uninit_cmd(struct scsi_cmnd *cmd) +-- +2.53.0 + diff --git a/queue-6.12/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch b/queue-6.12/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch new file mode 100644 index 0000000000..d1fd241453 --- /dev/null +++ b/queue-6.12/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch @@ -0,0 +1,50 @@ +From 42356ccefc100500180c57c828a8ec882d195912 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 11:24:11 +0800 +Subject: sctp: fix race between sctp_wait_for_connect and peeloff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit f14fe6395a8b3d961a61e138ad7b36ba3626dd4e ] + +sctp_wait_for_connect() drops and re-acquires the socket lock while +waiting for the association to reach ESTABLISHED state. During this +window, another thread can peeloff the association to a new socket via +getsockopt(SCTP_SOCKOPT_PEELOFF), changing asoc->base.sk. After +re-acquiring the old socket lock, sctp_wait_for_connect() returns +success without noticing the migration — the caller then accesses +the association under the wrong lock in sctp_datamsg_from_user(). + +Add the same sk != asoc->base.sk check that sctp_wait_for_sndbuf() +already has, returning an error if the association was migrated while +we slept. + +Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") +Signed-off-by: Zhenghang Xiao +Acked-by: Xin Long +Link: https://patch.msgid.link/20260527032411.60959-1-kipreyyy@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 6b562dd1aae110..3e80cf4e63ff00 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9377,6 +9377,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) + release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + + *timeo_p = current_timeo; + } +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index b5232c9bf7..b5c21368e9 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -21,3 +21,74 @@ arm64-debug-split-brk64-exception-entry.patch arm64-debug-split-bkpt32-exception-entry.patch arm64-debug-remove-debug-exception-registration-infr.patch arm64-debug-always-unmask-interrupts-in-el0_softstp.patch +nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch +nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch +xfrm-check-for-underflow-in-xfrm_state_mtu.patch +nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch +kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch +kernel-fork-validate-exit_signal-in-kernel_clone.patch +netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch +netfilter-xt_cpu-prefer-raw_smp_processor_id.patch +netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch +tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch +tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch +vsock-keep-poll-shutdown-state-consistent.patch +net-netlink-fix-sending-unassigned-nsid-after-assign.patch +net-netlink-don-t-set-nsid-on-local-notifications.patch +net-smc-do-not-re-initialize-smc-hashtables.patch +net-iucv-fix-locking-in-.getsockopt.patch +scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch +ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch +alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch +asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch +net-hsr-fix-potential-oob-access-in-supervision-fram.patch +accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch +gpio-mxc-fix-irq_high-handling.patch +net-avoid-checksumming-unreadable-skb-tail-on-trim.patch +ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch +ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch +ethtool-module-check-fw_flash_in_progress-under-rtnl.patch +ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch +ethtool-cmis-require-exact-cdb-reply-length.patch +ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch +net-ethtool-add-new-parameters-and-a-function-to-sup.patch +net-ethtool-add-support-for-writing-firmware-blocks-.patch +ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch +ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch +cxl-test-update-mock-dev-array-before-calling-platfo.patch +tunnels-load-network-headers-after-skb_cow-in-iptunn.patch +vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch +tunnels-do-not-assume-transport-header-in-iptunnel_p.patch +asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch +bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch +bonding-refuse-to-enslave-can-devices.patch +ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch +ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch +ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch +ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch +ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch +ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch +ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch +net-sched-revert-net-sched-restrict-conditions-for-a.patch +net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch +net-sched-act_mirred-move-the-recursion-counter-stru.patch +net-sched-act_mirred-add-loop-detection.patch +net-introduce-skb-tc-depth-field-to-track-packet-loo.patch +net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch +net-sched-act_mirred-fix-return-code-in-early-mirred.patch +net-handshake-use-spin_lock_bh-for-hn_lock.patch +nvme-tcp-store-negative-errno-in-queue-tls_err.patch +net-handshake-pass-negative-errno-through-handshake_.patch +remove-pointless-includes-of-linux-fdtable.h.patch +net-handshake-take-a-long-lived-file-reference-at-su.patch +net-handshake-drain-pending-requests-at-net-namespac.patch +bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch +bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch +bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch +gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch +gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch +net-mana-add-null-guards-in-teardown-path-to-prevent.patch +sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch +ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch +ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch +net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch diff --git a/queue-6.12/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch b/queue-6.12/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch new file mode 100644 index 0000000000..19b04139eb --- /dev/null +++ b/queue-6.12/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch @@ -0,0 +1,47 @@ +From 534fe6142d2aef1ed2d9b9c49b1bc163fc996bc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 09:33:13 -0700 +Subject: tun: free page on build_skb failure in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit aa8963fdce667a42fb7f0bdd2909fadcab02f9a8 ] + +When build_skb() fails in tun_xdp_one(), the function sets ret to +-ENOMEM and jumps to the out label, which returns without freeing the +page that vhost_net_build_xdp() allocated for the frame. As with the +short-frame rejection path, tun_sendmsg() discards the per-buffer error +and still returns total_len, so vhost_tx_batch() takes the success path +and never frees the page. Each build_skb() failure in a batch leaks one +page-frag chunk. + +Free the page before taking the error path, matching the put_page() the +other error exits of tun_xdp_one() already perform. + +Fixes: 043d222f93ab ("tuntap: accept an array of XDP buffs through sendmsg()") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260521163312.1479805-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 19c33d21bab947..d53e60823bf1bb 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2505,6 +2505,7 @@ static int tun_xdp_one(struct tun_struct *tun, + build: + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { ++ put_page(virt_to_head_page(xdp->data)); + ret = -ENOMEM; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.12/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch b/queue-6.12/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch new file mode 100644 index 0000000000..05fd716958 --- /dev/null +++ b/queue-6.12/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch @@ -0,0 +1,54 @@ +From a94901bacf88feabd0a93461d058b8ff3054afdc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:00:21 -0700 +Subject: tun: free page on short-frame rejection in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit f4feb1e20058e407cb00f45aff47f5b7e19a6bbf ] + +tun_xdp_one() returns -EINVAL on a frame shorter than ETH_HLEN without +freeing the page that vhost_net_build_xdp() allocated for it. +tun_sendmsg() discards that -EINVAL and still returns total_len, so +vhost_tx_batch() takes the success path and never frees the page; each +short frame in a batch leaks one page-frag chunk. + +A local process that can open /dev/net/tun and /dev/vhost-net can hit +this path: it attaches a tun/tap device as the vhost-net backend and +feeds TX descriptors whose length minus the virtio-net header is below +ETH_HLEN. Each kick leaks the page-frag chunks for that batch, and a +tight submission loop exhausts host memory and triggers an OOM panic. +Free the page before returning -EINVAL, matching the XDP-program error +path in the same function. + +Fixes: 049584807f1d ("tun: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260520160020.375349-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index fb9d425eff8c1b..19c33d21bab947 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2459,8 +2459,10 @@ static int tun_xdp_one(struct tun_struct *tun, + bool skb_xdp = false; + struct page *page; + +- if (unlikely(datasize < ETH_HLEN)) ++ if (unlikely(datasize < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + return -EINVAL; ++ } + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { +-- +2.53.0 + diff --git a/queue-6.12/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch b/queue-6.12/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch new file mode 100644 index 0000000000..8cb5b4aa9d --- /dev/null +++ b/queue-6.12/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch @@ -0,0 +1,67 @@ +From ca4fa88756439e4c7f039038925258b39133573d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 11:55:12 +0000 +Subject: tunnels: do not assume transport header in + iptunnel_pmtud_check_icmp() + +From: Eric Dumazet + +[ Upstream commit 509323077ef79a26ba0c60bb556e45c12c398b2d ] + +In some cases, iptunnel_pmtud_check_icmp() can be called while +skb transport header is not set. + +This triggers an out-of-bound access, because +(typeof(skb->transport_header))~0U is 65535. + +Access the icmp header based on IPv4 network header, +after making sure icmp->type is present in skb linear part. + +Note that iptunnel_pmtud_check_icmpv6()) is fine. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Reported-by: Damiano Melotti +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index cf496644d3df6c..d0ceb86e1687a7 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -278,7 +278,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + { +- const struct icmphdr *icmph = icmp_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); + + if (mtu < 576 || iph->frag_off != htons(IP_DF)) +@@ -289,9 +288,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr)) + return 0; + +- if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type)) +- return 0; ++ if (iph->protocol == IPPROTO_ICMP) { ++ const struct icmphdr *icmph; + ++ if (!pskb_network_may_pull(skb, iph->ihl * 4 + ++ offsetofend(struct icmphdr, type))) ++ return 0; ++ iph = ip_hdr(skb); ++ icmph = (void *)iph + iph->ihl * 4; ++ if (icmp_is_err(icmph->type)) ++ return 0; ++ } + return iptunnel_pmtud_build_icmp(skb, mtu); + } + +-- +2.53.0 + diff --git a/queue-6.12/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch b/queue-6.12/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch new file mode 100644 index 0000000000..bca22cb706 --- /dev/null +++ b/queue-6.12/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch @@ -0,0 +1,87 @@ +From 05efa6e70f6d6d1eac6923e85881c5fa1d20e3c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +From: Eric Dumazet + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 507f2f9ec400ce..cf496644d3df6c 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -210,7 +210,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -224,7 +224,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -234,7 +233,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -306,7 +305,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -321,7 +320,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -332,6 +330,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.53.0 + diff --git a/queue-6.12/vsock-keep-poll-shutdown-state-consistent.patch b/queue-6.12/vsock-keep-poll-shutdown-state-consistent.patch new file mode 100644 index 0000000000..a6fd3bd9a1 --- /dev/null +++ b/queue-6.12/vsock-keep-poll-shutdown-state-consistent.patch @@ -0,0 +1,247 @@ +From 5ba4d0d23a92c610446fe70f0cdf079e429f86f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 00:56:36 +0800 +Subject: vsock: keep poll shutdown state consistent + +From: Ziyu Zhang + +[ Upstream commit aae9d8a5528b8ee9ff8dc5d3558b8a9f852a724a ] + +vsock_poll() reads vsk->peer_shutdown before taking the socket lock +to set EPOLLHUP and EPOLLRDHUP, then reads it again after taking +the lock to report EOF readability. A shutdown packet can update +peer_shutdown while poll is waiting for the lock, so one poll invocation +can report EOF readability without the corresponding HUP/RDHUP bits. + +For connectible sockets, take one peer_shutdown snapshot after +lock_sock() and use it for all peer-shutdown-derived poll bits. For +datagram sockets, which do not take lock_sock() in poll(), take one +lockless READ_ONCE() snapshot and pair it with WRITE_ONCE() on the +writer side. + +This keeps the peer-shutdown-derived bits internally consistent for each +poll pass. + +Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") +Signed-off-by: Ziyu Zhang +Link: https://patch.msgid.link/20260519165636.62542-1-ziyuzhang201@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/af_vsock.c | 49 ++++++++++++++++--------- + net/vmw_vsock/hyperv_transport.c | 9 +++-- + net/vmw_vsock/virtio_transport_common.c | 14 ++++--- + net/vmw_vsock/vmci_transport.c | 8 ++-- + 4 files changed, 52 insertions(+), 28 deletions(-) + +diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c +index 1db7a1f8e55f6d..f03e00cae028a5 100644 +--- a/net/vmw_vsock/af_vsock.c ++++ b/net/vmw_vsock/af_vsock.c +@@ -523,7 +523,7 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) + */ + sock_reset_flag(sk, SOCK_DONE); + sk->sk_state = TCP_CLOSE; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + } + + if (sk->sk_type == SOCK_SEQPACKET) { +@@ -814,7 +814,7 @@ static struct sock *__vsock_create(struct net *net, + vsk->rejected = false; + vsk->sent_request = false; + vsk->ignore_connecting_rst = false; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout); + INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work); + +@@ -1099,6 +1099,25 @@ static int vsock_shutdown(struct socket *sock, int mode) + return err; + } + ++static __poll_t vsock_poll_shutdown(struct sock *sk, u32 peer_shutdown) ++{ ++ __poll_t mask = 0; ++ ++ /* INET sockets treat local write shutdown and peer write shutdown as a ++ * case of EPOLLHUP set. ++ */ ++ if (sk->sk_shutdown == SHUTDOWN_MASK || ++ ((sk->sk_shutdown & SEND_SHUTDOWN) && ++ (peer_shutdown & SEND_SHUTDOWN))) ++ mask |= EPOLLHUP; ++ ++ if (sk->sk_shutdown & RCV_SHUTDOWN || ++ peer_shutdown & SEND_SHUTDOWN) ++ mask |= EPOLLRDHUP; ++ ++ return mask; ++} ++ + static __poll_t vsock_poll(struct file *file, struct socket *sock, + poll_table *wait) + { +@@ -1116,24 +1135,17 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + /* Signify that there has been an error on this socket. */ + mask |= EPOLLERR; + +- /* INET sockets treat local write shutdown and peer write shutdown as a +- * case of EPOLLHUP set. +- */ +- if ((sk->sk_shutdown == SHUTDOWN_MASK) || +- ((sk->sk_shutdown & SEND_SHUTDOWN) && +- (vsk->peer_shutdown & SEND_SHUTDOWN))) { +- mask |= EPOLLHUP; +- } +- +- if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { +- mask |= EPOLLRDHUP; +- } +- + if (sk_is_readable(sk)) + mask |= EPOLLIN | EPOLLRDNORM; + + if (sock->type == SOCK_DGRAM) { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ ++ /* DGRAM sockets do not take lock_sock() in poll(), so use one ++ * lockless snapshot for all shutdown-derived mask bits. ++ */ ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); ++ + /* For datagram sockets we can read if there is something in + * the queue and write as long as the socket isn't shutdown for + * sending. +@@ -1148,6 +1160,7 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + + } else if (sock_type_connectible(sk->sk_type)) { + const struct vsock_transport *transport; ++ u32 peer_shutdown; + + lock_sock(sk); + +@@ -1180,8 +1193,10 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + * terminated should also be considered read, and we check the + * shutdown flag for that. + */ ++ peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); + if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { ++ peer_shutdown & SEND_SHUTDOWN) { + mask |= EPOLLIN | EPOLLRDNORM; + } + +diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c +index 34871ed1a099c6..865e004ee286f2 100644 +--- a/net/vmw_vsock/hyperv_transport.c ++++ b/net/vmw_vsock/hyperv_transport.c +@@ -264,7 +264,7 @@ static void hvs_do_close_lock_held(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -593,7 +593,9 @@ static int hvs_update_recv_data(struct hvsock *hvs) + return -EIO; + + if (payload_len == 0) +- hvs->vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(hvs->vsk->peer_shutdown, ++ READ_ONCE(hvs->vsk->peer_shutdown) | ++ SEND_SHUTDOWN); + + hvs->recv_data_len = payload_len; + hvs->recv_data_off = 0; +@@ -704,7 +706,8 @@ static s64 hvs_stream_has_data(struct vsock_sock *vsk) + ret = 1; + break; + case 0: +- vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | SEND_SHUTDOWN); + ret = 0; + break; + default: /* -1 */ +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index c182886136b445..b588ccd133eaa7 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -1234,7 +1234,7 @@ static void virtio_transport_do_close(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -1437,12 +1437,15 @@ virtio_transport_recv_connected(struct sock *sk, + case VIRTIO_VSOCK_OP_CREDIT_UPDATE: + sk->sk_write_space(sk); + break; +- case VIRTIO_VSOCK_OP_SHUTDOWN: ++ case VIRTIO_VSOCK_OP_SHUTDOWN: { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_RCV) +- vsk->peer_shutdown |= RCV_SHUTDOWN; ++ peer_shutdown |= RCV_SHUTDOWN; + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_SEND) +- vsk->peer_shutdown |= SEND_SHUTDOWN; +- if (vsk->peer_shutdown == SHUTDOWN_MASK) { ++ peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, peer_shutdown); ++ if (peer_shutdown == SHUTDOWN_MASK) { + if (vsock_stream_has_data(vsk) <= 0 && !sock_flag(sk, SOCK_DONE)) { + (void)virtio_transport_reset(vsk, NULL); + virtio_transport_do_close(vsk, true); +@@ -1457,6 +1460,7 @@ virtio_transport_recv_connected(struct sock *sk, + if (le32_to_cpu(virtio_vsock_hdr(skb)->flags)) + sk->sk_state_change(sk); + break; ++ } + case VIRTIO_VSOCK_OP_RST: + virtio_transport_do_close(vsk, true); + break; +diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c +index 4cd11f355e9d6b..443125e48f2481 100644 +--- a/net/vmw_vsock/vmci_transport.c ++++ b/net/vmw_vsock/vmci_transport.c +@@ -811,7 +811,7 @@ static void vmci_transport_handle_detach(struct sock *sk) + /* On a detach the peer will not be sending or receiving + * anymore. + */ +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + + /* We should not be sending anymore since the peer won't be + * there to receive, but we can still receive if there is data +@@ -1534,7 +1534,9 @@ static int vmci_transport_recv_connected(struct sock *sk, + if (pkt->u.mode) { + vsk = vsock_sk(sk); + +- vsk->peer_shutdown |= pkt->u.mode; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | ++ pkt->u.mode); + sk->sk_state_change(sk); + } + break; +@@ -1551,7 +1553,7 @@ static int vmci_transport_recv_connected(struct sock *sk, + * a clean shutdown. + */ + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + +-- +2.53.0 + diff --git a/queue-6.12/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch b/queue-6.12/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch new file mode 100644 index 0000000000..af8017612e --- /dev/null +++ b/queue-6.12/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch @@ -0,0 +1,54 @@ +From 7a38673e85f230e726cc7061e8841f05b8f951f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:36:42 +0000 +Subject: vxlan: do not reuse cached ip_hdr() value after + skb_tunnel_check_pmtu() + +From: Eric Dumazet + +[ Upstream commit 7d9ef0cb271555d8cf39fefe6c981e1493b25ecf ] + +skb_tunnel_check_pmtu() can change skb->head. + +Reusing old_iph afer skb_tunnel_check_pmtu() can cause an UAF. + +Use instead ip_hdr(skb) as done in drivers/net/bareudp.c +and drivers/net/geneve.c. + +Found by Sashiko. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525203642.2389723-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index ed428293b0e579..765d25eee2fe48 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2541,7 +2541,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), + vni, md, flags, udp_sum); +@@ -2601,7 +2601,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip6_dst_hoplimit(ndst); + skb_scrub_packet(skb, xnet); + err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), +-- +2.53.0 + diff --git a/queue-6.12/xfrm-check-for-underflow-in-xfrm_state_mtu.patch b/queue-6.12/xfrm-check-for-underflow-in-xfrm_state_mtu.patch new file mode 100644 index 0000000000..d7d41d56dc --- /dev/null +++ b/queue-6.12/xfrm-check-for-underflow-in-xfrm_state_mtu.patch @@ -0,0 +1,85 @@ +From 12d3f6f2c51d183a3c95830ff09315181c474972 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 10:49:14 -0600 +Subject: xfrm: Check for underflow in xfrm_state_mtu + +From: David Ahern + +[ Upstream commit 742b04d0550b0ec89dcbc99537ec88653bd1ad90 ] + +Leo Lin reported OOB write issue in esp component: + + xfrm_state_mtu() returns u32 but performs its arithmetic in unsigned + modulo-2^32 space using an attacker-influenced "header_len + authsize + + net_adj" subtracted from a small "mtu" argument. A nobody user can + install an IPv4 ESP tunnel SA with a large authentication key + (XFRMA_ALG_AUTH_TRUNC, e.g. hmac(sha512), 64-byte key, 64-byte trunc), + configure a small interface MTU (68 bytes), and set XFRMA_TFCPAD to a + large value. When a single UDP datagram is then sent through the + tunnel, xfrm_state_mtu() underflows to a near-2^32 value, and + esp_output() consumes it as a signed int via: + + padto = min(x->tfcpad, xfrm_state_mtu(x, mtu_cached)) + esp.tfclen = padto - skb->len (assigned to int) + + esp.tfclen ends up negative (e.g. -207). It is sign-extended to size_t + when passed to memset() inside esp_output_fill_trailer(), producing a + ~16 EB write of zeroes at skb_tail_pointer(skb). KASAN logs it as + "Write of size 18446744073709551537 at addr ffff888...". + +Check for underflow and return 1. This causes the sendmsg attempt to +fail with ENETUNREACH. + +Fixes: c5c252389374 ("[XFRM]: Optimize MTU calculation") +Reported-by: Leo Lin +Assisted-by: Codex:26.506.31004 +Signed-off-by: David Ahern +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_state.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index 6a92d88f9e0363..4823a9c054ae2b 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -3022,10 +3022,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + const struct xfrm_type *type = READ_ONCE(x->type); + struct crypto_aead *aead; + u32 blksize, net_adj = 0; ++ u32 overhead, payload_mtu; + + if (x->km.state != XFRM_STATE_VALID || +- !type || type->proto != IPPROTO_ESP) ++ !type || type->proto != IPPROTO_ESP) { ++ if (mtu <= x->props.header_len) ++ return 1; + return mtu - x->props.header_len; ++ } + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); +@@ -3045,8 +3049,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + break; + } + +- return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - +- net_adj) & ~(blksize - 1)) + net_adj - 2; ++ overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj; ++ if (mtu <= overhead) ++ return 1; ++ ++ payload_mtu = mtu - overhead; ++ payload_mtu &= ~(blksize - 1); ++ if (payload_mtu <= 2) ++ return 1; ++ ++ return payload_mtu + net_adj - 2; ++ + } + EXPORT_SYMBOL_GPL(xfrm_state_mtu); + +-- +2.53.0 + diff --git a/queue-6.18/accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch b/queue-6.18/accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch new file mode 100644 index 0000000000..3b569870a9 --- /dev/null +++ b/queue-6.18/accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch @@ -0,0 +1,86 @@ +From c94e9cdde08e0e5aa81516381ab511097f6da71b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 00:00:00 +0530 +Subject: accel/rocket: fix UAF via dangling GEM handle in create_bo + +From: Dhabaleshwar Das + +[ Upstream commit f706e6a4ce75585af979aec3dcbdce68bc76306b ] + +rocket_ioctl_create_bo() inserts a GEM handle into the file's IDR via +drm_gem_handle_create() early on, then performs several operations that +can fail (sgt allocation, drm_mm insert, iommu_map). If any fail after +the handle is live, the error path calls drm_gem_shmem_object_free() +which kfree's the object without removing the handle from the IDR. + +This leaves a dangling handle pointing to freed slab memory. Any +subsequent ioctl using that handle (PREP_BO, FINI_BO, SUBMIT) calls +drm_gem_object_lookup() and dereferences freed memory (UAF). + +Fix by moving drm_gem_handle_create() to after all fallible operations +succeed, matching the pattern used by panfrost, lima, and etnaviv. + +Also fix drm_mm_insert_node_generic() whose return value was silently +overwritten by iommu_map_sgtable() on the next line. Add the missing +error check. + +[tomeu: Move handle creation to the very end] + +Fixes: 658ebeac3351 ("accel/rocket: Add IOCTL for BO creation") +Reported-by: Dhabaleshwar Das +Signed-off-by: Dhabaleshwar Das +Reviewed-by: Tomeu Vizoso +Link: https://patch.msgid.link/20260521165720.2113571-1-tomeu@tomeuvizoso.net +Signed-off-by: Tomeu Vizoso +Signed-off-by: Sasha Levin +--- + drivers/accel/rocket/rocket_gem.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/accel/rocket/rocket_gem.c b/drivers/accel/rocket/rocket_gem.c +index c3c86e1abd25a3..b1b24d60973e82 100644 +--- a/drivers/accel/rocket/rocket_gem.c ++++ b/drivers/accel/rocket/rocket_gem.c +@@ -78,11 +78,6 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * + rkt_obj->size = args->size; + rkt_obj->offset = 0; + +- ret = drm_gem_handle_create(file, gem_obj, &args->handle); +- drm_gem_object_put(gem_obj); +- if (ret) +- goto err; +- + sgt = drm_gem_shmem_get_pages_sgt(shmem_obj); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); +@@ -94,6 +89,8 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * + rkt_obj->size, PAGE_SIZE, + 0, 0); + mutex_unlock(&rocket_priv->mm_lock); ++ if (ret) ++ goto err; + + ret = iommu_map_sgtable(rocket_priv->domain->domain, + rkt_obj->mm.start, +@@ -111,8 +108,18 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * + args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); + args->dma_address = rkt_obj->mm.start; + ++ ret = drm_gem_handle_create(file, gem_obj, &args->handle); ++ if (ret) ++ goto err_unmap; ++ ++ drm_gem_object_put(gem_obj); ++ + return 0; + ++err_unmap: ++ iommu_unmap(rocket_priv->domain->domain, ++ rkt_obj->mm.start, rkt_obj->size); ++ + err_remove_node: + mutex_lock(&rocket_priv->mm_lock); + drm_mm_remove_node(&rkt_obj->mm); +-- +2.53.0 + diff --git a/queue-6.18/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch b/queue-6.18/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch new file mode 100644 index 0000000000..28cdb994a2 --- /dev/null +++ b/queue-6.18/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch @@ -0,0 +1,84 @@ +From 8353904ca767496700211f3e492511b0b8b5d53f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 22:09:40 -0300 +Subject: ALSA: pcm: oss: Fix setup list UAF on proc write error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 4cc54bdd54b337e77115be5b55577d1c58608eae ] + +snd_pcm_oss_proc_write() links a newly allocated setup entry into the +OSS setup list before duplicating the task name. If the task-name +allocation fails, the error path frees the already linked entry and +leaves setup_list pointing at freed memory. + +A later OSS device open can then walk the stale list entry in +snd_pcm_oss_look_for_setup() and dereference freed memory. + +Allocate the task name and initialize the setup entry before publishing +the entry on setup_list. Also fetch the initial proc read iterator only +after taking setup_mutex, so all setup_list traversal follows the same +list lifetime rules. + +Reported-by: syzbot+8e498074a794999eb41c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a1062b7.170a0220.35b2b7.0003.GAE@google.com +Closes: https://syzkaller.appspot.com/bug?extid=8e498074a794999eb41c +Fixes: 060d77b9c04a ("[ALSA] Fix / clean up PCM-OSS setup hooks") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260522-alsa-pcm-oss-setup-uaf-v1-1-40bdcc4d17e8@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/oss/pcm_oss.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index 9b5a3def8d2ce9..59d5153d111329 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -2965,8 +2965,10 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) + { + struct snd_pcm_str *pstr = entry->private_data; +- struct snd_pcm_oss_setup *setup = pstr->oss.setup_list; ++ struct snd_pcm_oss_setup *setup; ++ + guard(mutex)(&pstr->oss.setup_mutex); ++ setup = pstr->oss.setup_list; + while (setup) { + snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n", + setup->task_name, +@@ -3051,6 +3053,13 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, + buffer->error = -ENOMEM; + return; + } ++ template.task_name = kstrdup(task_name, GFP_KERNEL); ++ if (!template.task_name) { ++ kfree(setup); ++ buffer->error = -ENOMEM; ++ return; ++ } ++ *setup = template; + if (pstr->oss.setup_list == NULL) + pstr->oss.setup_list = setup; + else { +@@ -3058,12 +3067,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, + setup1->next; setup1 = setup1->next); + setup1->next = setup; + } +- template.task_name = kstrdup(task_name, GFP_KERNEL); +- if (! template.task_name) { +- kfree(setup); +- buffer->error = -ENOMEM; +- return; +- } ++ continue; + } + *setup = template; + } +-- +2.53.0 + diff --git a/queue-6.18/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch b/queue-6.18/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch new file mode 100644 index 0000000000..1e0b66c50d --- /dev/null +++ b/queue-6.18/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch @@ -0,0 +1,47 @@ +From de0181ab0dd485dbdac3966b2dae85da7aa3818f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 09:24:00 -0300 +Subject: ASoC: codecs: simple-mux: Fix enum control bounds check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit f63ad68e18d774a5d15cd7e405ead63f6b322679 ] + +simple_mux_control_put() rejects values greater than e->items, but +enum control values are zero based. For the two-entry mux used by this +driver, valid values are 0 and 1, so value 2 must be rejected as well. + +Accepting e->items can store an invalid mux state, pass it to the GPIO +setter, and pass it on to the DAPM mux update path where it is used as +an index into the enum text array. + +Use the same >= e->items check used by the ASoC enum helpers. + +Fixes: 342fbb7578d1 ("ASoC: add simple-mux") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260527-asoc-simple-mux-enum-bounds-v1-1-3f805b9fc671@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/simple-mux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c +index 3906964401557d..cedd181ffdaf46 100644 +--- a/sound/soc/codecs/simple-mux.c ++++ b/sound/soc/codecs/simple-mux.c +@@ -51,7 +51,7 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + +- if (ucontrol->value.enumerated.item[0] > e->items) ++ if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + if (priv->mux == ucontrol->value.enumerated.item[0]) +-- +2.53.0 + diff --git a/queue-6.18/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch b/queue-6.18/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch new file mode 100644 index 0000000000..7bfba61a74 --- /dev/null +++ b/queue-6.18/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch @@ -0,0 +1,112 @@ +From 8c7c2adfae177c0e9b05e5f4613a983cc37ac25a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 13:51:47 -0300 +Subject: ASoC: Intel: bytcht_es8316: Fix MCLK leak on init errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit afb2a3a9d8369d18122a0d7cd294eba9a98259c6 ] + +byt_cht_es8316_init() enables MCLK before configuring the codec sysclk +and creating the headset jack. If either of those later steps fails, the +function returns without disabling MCLK, leaving the clock enabled after +card registration fails. + +Track whether this driver enabled MCLK and disable it on the init error +paths. Add the matching DAI link exit callback so the same clock enable +is also balanced when ASoC cleans up a successfully initialized link. + +Fixes: a03bdaa565cb ("ASoC: Intel: add machine driver for BYT/CHT + ES8316") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-asoc-bytcht-es8316-mclk-leak-v1-1-b4a11cdc2afd@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_es8316.c | 29 ++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index 3b5f63112237ea..25044c0f4703b0 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -40,6 +40,7 @@ struct byt_cht_es8316_private { + struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; + bool speaker_en; ++ bool mclk_enabled; + }; + + enum { +@@ -170,6 +171,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + }, + }; + ++static void byt_cht_es8316_disable_mclk(struct byt_cht_es8316_private *priv) ++{ ++ if (!priv->mclk_enabled) ++ return; ++ ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++} ++ + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + { + struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; +@@ -226,12 +236,14 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); ++ else ++ priv->mclk_enabled = true; + + ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(runtime, 0), 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset", +@@ -240,13 +252,25 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; ++ ++err_disable_mclk: ++ byt_cht_es8316_disable_mclk(priv); ++ return ret; ++} ++ ++static void byt_cht_es8316_exit(struct snd_soc_pcm_runtime *runtime) ++{ ++ struct snd_soc_card *card = runtime->card; ++ struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); ++ ++ byt_cht_es8316_disable_mclk(priv); + } + + static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -352,6 +376,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + | SND_SOC_DAIFMT_CBC_CFC, + .be_hw_params_fixup = byt_cht_es8316_codec_fixup, + .init = byt_cht_es8316_init, ++ .exit = byt_cht_es8316_exit, + SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), + }, + }; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch b/queue-6.18/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch new file mode 100644 index 0000000000..4b77ef84f7 --- /dev/null +++ b/queue-6.18/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch @@ -0,0 +1,40 @@ +From 649cc6a649e6978e5cd04d99322d93ec4b3fac2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 11:21:39 +0800 +Subject: Bluetooth: 6lowpan: check skb_clone() return value in + send_mcast_pkt() + +From: Zhao Dongdong + +[ Upstream commit 3c40d381ce04f9575a5d8b542898183c3b4b38dc ] + +The skb_clone() function can return NULL if memory allocation fails. +send_mcast_pkt() calls skb_clone() without checking the return value, which +can lead to a NULL pointer dereference in send_pkt() when it dereferences +skb->data. +Add a NULL check after skb_clone() and skip the peer if the clone fails. + +Fixes: 18722c247023 ("Bluetooth: Enable 6LoWPAN support for BT LE devices") +Signed-off-by: Zhao Dongdong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/6lowpan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index 2c21ae8abadc22..038f01600eebab 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -486,6 +486,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) + int ret; + + local_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!local_skb) ++ continue; + + BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p", + netdev->name, +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch b/queue-6.18/bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch new file mode 100644 index 0000000000..e490314935 --- /dev/null +++ b/queue-6.18/bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch @@ -0,0 +1,38 @@ +From 3718dc220ef216425944f12fa86b221d0faa97bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 10:50:59 -0300 +Subject: Bluetooth: hci_sync: Reset device counters in hci_dev_close_sync() + +From: Heitor Alves de Siqueira + +[ Upstream commit cdf88b35e06f1b385f7f6228060ae541d44fbb72 ] + +Before resetting or closing the device, protocol counters should also be +zeroed. + +Fixes: d0b137062b2d ("Bluetooth: hci_sync: Rework init stages") +Signed-off-by: Heitor Alves de Siqueira +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sync.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 73e429c41e17b5..277de808ebeb5a 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -5338,6 +5338,10 @@ int hci_dev_close_sync(struct hci_dev *hdev) + /* Reset device */ + skb_queue_purge(&hdev->cmd_q); + atomic_set(&hdev->cmd_cnt, 1); ++ hdev->acl_cnt = 0; ++ hdev->sco_cnt = 0; ++ hdev->le_cnt = 0; ++ hdev->iso_cnt = 0; + if (hci_test_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE) && + !auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { + set_bit(HCI_INIT, &hdev->flags); +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch b/queue-6.18/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch new file mode 100644 index 0000000000..461f9e9644 --- /dev/null +++ b/queue-6.18/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch @@ -0,0 +1,57 @@ +From dec5788e45a54c53a1973b4d0b1f946cf1667526 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 10:50:58 -0300 +Subject: Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close + +From: Heitor Alves de Siqueira + +[ Upstream commit 525daaea459fc215f432de1b8debbd9144bf97b0 ] + +Since hci_dev_close_sync() can now be called during the reset path, we +should also set HCI_CMD_DRAIN_WORKQUEUE. This avoids queuing timeouts +while the hdev workqueue is being drained. + +Fixes: 877afadad2dc ("Bluetooth: When HCI work queue is drained, only queue chained work") +Signed-off-by: Heitor Alves de Siqueira +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sync.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index f498ab28f1aa06..73e429c41e17b5 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -5246,6 +5246,12 @@ int hci_dev_close_sync(struct hci_dev *hdev) + + bt_dev_dbg(hdev, ""); + ++ /* Set HCI_DRAIN_WORKQUEUE flag to prevent queuing work during ++ * reset/close. See hci_cmd_work() and handle_cmd_cnt_and_timer(). ++ */ ++ hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); ++ synchronize_rcu(); ++ + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + disable_delayed_work(&hdev->power_off); + disable_delayed_work(&hdev->ncmd_timer); +@@ -5269,6 +5275,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) + + if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { + cancel_delayed_work_sync(&hdev->cmd_timer); ++ hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + return err; + } + +@@ -5368,6 +5375,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) + /* Clear flags */ + hdev->flags &= BIT(HCI_RAW); + hci_dev_clear_volatile_flags(hdev); ++ hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch b/queue-6.18/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch new file mode 100644 index 0000000000..d1e6ba4624 --- /dev/null +++ b/queue-6.18/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch @@ -0,0 +1,62 @@ +From 1aa026fff16eb15eb249ca0fd40da386c5ca0ce9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:51:52 +0800 +Subject: Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success + +From: Zhenghang Xiao + +[ Upstream commit 00e1950716c6ed67d74777b2db286b0fa23b4be9 ] + +l2cap_ecred_reconf_rsp() returns early on success without clearing +chan->ident. Every other L2CAP response handler (l2cap_ecred_conn_rsp, +l2cap_le_connect_rsp, l2cap_config_rsp) clears chan->ident after a +successful transaction to prevent the channel from matching subsequent +responses with the recycled ident value. + +A remote attacker that completed a reconfiguration as the peer can +replay a failure response with the stale ident, causing the kernel to +match and destroy the already-established channel via +l2cap_chan_del(chan, ECONNRESET). + +Clear chan->ident for all matching channels on success, and harden the +failure path by using l2cap_chan_hold_unless_zero() consistent with +other L2CAP handlers (l2cap_le_command_rej, __l2cap_get_chan_by_ident). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 87ebe81277c510..57f5e3c7429e79 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5466,14 +5466,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + + BT_DBG("result 0x%4.4x", result); + +- if (!result) ++ if (!result) { ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ if (chan->ident == cmd->ident) ++ chan->ident = 0; ++ } + return 0; ++ } + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + if (chan->ident != cmd->ident) + continue; + +- l2cap_chan_hold(chan); ++ if (!l2cap_chan_hold_unless_zero(chan)) ++ continue; + l2cap_chan_lock(chan); + + l2cap_chan_del(chan, ECONNRESET); +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch b/queue-6.18/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch new file mode 100644 index 0000000000..17cc8b088a --- /dev/null +++ b/queue-6.18/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch @@ -0,0 +1,82 @@ +From 4e9d3d16c00ca5768b40166cd201a5a1bf3dc7fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 12:09:42 -0400 +Subject: Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp + +From: Luiz Augusto von Dentz + +[ Upstream commit 41c2713b204e6cb6a94587bc6bf6935107df5479 ] + +If dcid is received for an already-assigned destination CID the spec +requires that both channels to be discarded, but calling l2cap_chan_del +may invalidate the tmp cursor created by list_for_each_entry_safe and +in fact it is the wrong procedure as the chan->dcid may be assigned +previously it really needs to be disconnected. + +Calling l2cap_chan_clone directly may still lead to l2cap_chan_del so +instead schedule l2cap_chan_timeout with delay 0 to close the channel +asynchronously. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 57f5e3c7429e79..9805908e6c6a06 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5268,6 +5268,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct l2cap_chan *orig; + u16 dcid; + + if (chan->ident != cmd->ident || +@@ -5289,8 +5290,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + + BT_DBG("dcid[%d] 0x%4.4x", i, dcid); + ++ orig = __l2cap_get_chan_by_dcid(conn, dcid); ++ + /* Check if dcid is already in use */ +- if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { ++ if (dcid && orig) { + /* If a device receives a + * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an + * already-assigned Destination CID, then both the +@@ -5299,10 +5302,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + */ + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); +- chan = __l2cap_get_chan_by_dcid(conn, dcid); +- l2cap_chan_lock(chan); +- l2cap_chan_del(chan, ECONNRESET); +- l2cap_chan_unlock(chan); ++ ++ /* Check that the dcid channel mode is ++ * L2CAP_MODE_EXT_FLOWCTL since this procedure is only ++ * valid for that mode and shouldn't disconnect a dcid ++ * in other modes. ++ */ ++ if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) { ++ l2cap_chan_lock(orig); ++ /* Disconnect the original channel as it may be ++ * considered connected since dcid has already ++ * been assigned; don't call l2cap_chan_close ++ * directly since that could lead to ++ * l2cap_chan_del and then removing the channel ++ * from the list while we're iterating over it. ++ */ ++ __set_chan_timer(orig, 0); ++ l2cap_chan_unlock(orig); ++ } + continue; + } + +-- +2.53.0 + diff --git a/queue-6.18/bonding-refuse-to-enslave-can-devices.patch b/queue-6.18/bonding-refuse-to-enslave-can-devices.patch new file mode 100644 index 0000000000..88b81e29a0 --- /dev/null +++ b/queue-6.18/bonding-refuse-to-enslave-can-devices.patch @@ -0,0 +1,74 @@ +From 02ee1f8764feca89889e41fbf621bb3e98a6c705 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:33:19 +0200 +Subject: bonding: refuse to enslave CAN devices + +From: Oliver Hartkopp + +[ Upstream commit 8ba68464e4787b6a7ec938826e16124df20fd23d ] + +syzbot reported a kernel paging request crash in +can_rx_unregister() inside net/can/af_can.c. The crash occurs +because a virtual CAN device (vxcan) is being enslaved to a +bonding master. + +During the enslavement process, the bonding driver mutates +and modifies the network device states to fit an Ethernet-like +aggregation model. However, CAN devices operate on a completely +different Layer 2 architecture, relying on the CAN mid-layer +private data structure (can_ml_priv) instead of standard +Ethernet structures. Since bonding does not initialize or +maintain these CAN structures, subsequent operations on the +half-enslaved interface (such as closing associated sockets +via isotp_release) lead to a null-pointer dereference when +accessing the CAN receiver lists. + +Bonding CAN interfaces is architecturally invalid as CAN lacks +MAC addresses, ARP capabilities, and standard Ethernet +link-layer mechanisms. While generic loopback devices are +blocked globally in net/core/dev.c, virtual CAN devices +bypass this check because they do not carry the IFF_LOOPBACK +flag, despite acting as local software-loopbacks. + +Fix this by explicitly blocking network devices of type +ARPHRD_CAN from being enslaved at the very beginning of +bond_enslave(). This prevents illegal state mutations, +eliminates the resulting KASAN crashes, and avoids potential +memory leaks from incomplete socket cleanups. + +As the CAN support has been added a long time after bonding +the Fixes-tag points to the introduction of ARPHRD_CAN that +would have needed a specific handling in bonding_main.c. + +Fixes: cd05acfe65ed ("[CAN]: Allocate protocol numbers for PF_CAN") +Reported-by: syzbot+8ed98cbd0161632bce95@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8ed98cbd0161632bce95 +Signed-off-by: Oliver Hartkopp +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260526-bonding-candev-v1-1-ba1df400918a@hartkopp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 8b1422dda4c080..2132acff2e52c4 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1860,6 +1860,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, + struct sockaddr_storage ss; + int res = 0, i; + ++ if (slave_dev->type == ARPHRD_CAN) { ++ BOND_NL_ERR(bond_dev, extack, ++ "CAN devices cannot be enslaved"); ++ return -EPERM; ++ } ++ + if (slave_dev->flags & IFF_MASTER && + !netif_is_bond_master(slave_dev)) { + BOND_NL_ERR(bond_dev, extack, +-- +2.53.0 + diff --git a/queue-6.18/bridge-fix-sleep-in-atomic-context-in-netlink-path.patch b/queue-6.18/bridge-fix-sleep-in-atomic-context-in-netlink-path.patch new file mode 100644 index 0000000000..1410819df4 --- /dev/null +++ b/queue-6.18/bridge-fix-sleep-in-atomic-context-in-netlink-path.patch @@ -0,0 +1,149 @@ +From 7ae34c99bb03e7437c026e5634f732cfa1a3f221 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 09:48:16 +0300 +Subject: bridge: Fix sleep in atomic context in netlink path + +From: Ido Schimmel + +[ Upstream commit 5eec4427b89c2fb2beac54920101e55a2f1c0c21 ] + +Since the introduction of the netlink configuration path for bridge +ports in commit 25c71c75ac87 ("bridge: bridge port parameters over +netlink"), br_setport() was always called with the bridge lock held +around it. Back then this decision made sense: The bridge lock protects +the STP state of the bridge and its ports and at that time the function +only processed three STP related netlink attributes (cost, priority and +state). + +Nowadays, br_setport() processes a lot more attributes and most of them +do not need the bridge lock: + +* Bridge flags: Only require RTNL. Read locklessly by the data path. + Annotations can be added in net-next. + +* FDB port flushing: Only requires the FDB lock. + +* Multicast attributes: Only require the multicast lock. + +* Group forward mask: Only requires RTNL. Read locklessly by the data + path. Annotations can be added in net-next. + +* Backup port and NHID: Only require RTNL. Read locklessly by the data + path. + +This is a problem as the bridge calls dev_set_promiscuity() when certain +bridge port flags change and this function can sleep since the commit +cited below, resulting in a splat such as [1]. + +Fix this by reducing the scope of the bridge lock and only take it when +processing the three STP related attributes that require it. This is +consistent with the multicast attributes where each attribute acquires +the multicast lock instead of having one critical section for all +relevant attributes. + +[1] +BUG: sleeping function called from invalid context at net/core/dev_addr_lists.c:1262 +in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 356, name: bridge +preempt_count: 201, expected: 0 +RCU nest depth: 0, expected: 0 +2 locks held by bridge/356: +#0: ffffffff919473a0 (rtnl_mutex){+.+.}-{4:4}, at: rtnetlink_rcv_msg (net/core/rtnetlink.c:80 net/core/rtnetlink.c:7002) +#1: ffff888115072d58 (&br->lock){+...}-{3:3}, at: br_setlink (./include/linux/spinlock.h:348 net/bridge/br_netlink.c:1117) +Preemption disabled at: + 0x0 +Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +__might_resched.cold (kernel/sched/core.c:9163) +netif_rx_mode_run (net/core/dev_addr_lists.c:1262) +netif_rx_mode_sync (net/core/dev_addr_lists.c:1428) +dev_set_promiscuity (net/core/dev_api.c:289) +br_manage_promisc (net/bridge/br_if.c:135 net/bridge/br_if.c:172) +br_port_flags_change (net/bridge/br_if.c:242 net/bridge/br_if.c:747) +br_setport (net/bridge/br_netlink.c:1000) +br_setlink (net/bridge/br_netlink.c:1118) +rtnl_bridge_setlink (net/core/rtnetlink.c:5572) +rtnetlink_rcv_msg (net/core/rtnetlink.c:7005) +netlink_rcv_skb (net/netlink/af_netlink.c:2550) +netlink_unicast (net/netlink/af_netlink.c:1318 net/netlink/af_netlink.c:1344) +netlink_sendmsg (net/netlink/af_netlink.c:1894) +__sock_sendmsg (net/socket.c:787 (discriminator 4) net/socket.c:802 (discriminator 4)) +____sys_sendmsg (net/socket.c:2698) +___sys_sendmsg (net/socket.c:2752) +__sys_sendmsg (net/socket.c:2784) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 78cd408356fe ("net: add missing instance lock to dev_set_promiscuity") +Reviewed-by: Nikolay Aleksandrov +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260526064818.272516-2-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/bridge/br_netlink.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c +index 4e2d53b2722104..6d5b2ef5f18d3d 100644 +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -1000,19 +1000,25 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[], + br_port_flags_change(p, changed_mask); + + if (tb[IFLA_BRPORT_COST]) { ++ spin_lock_bh(&p->br->lock); + err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST])); ++ spin_unlock_bh(&p->br->lock); + if (err) + return err; + } + + if (tb[IFLA_BRPORT_PRIORITY]) { ++ spin_lock_bh(&p->br->lock); + err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY])); ++ spin_unlock_bh(&p->br->lock); + if (err) + return err; + } + + if (tb[IFLA_BRPORT_STATE]) { ++ spin_lock_bh(&p->br->lock); + err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE])); ++ spin_unlock_bh(&p->br->lock); + if (err) + return err; + } +@@ -1114,9 +1120,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags, + if (err) + return err; + +- spin_lock_bh(&p->br->lock); + err = br_setport(p, tb, extack); +- spin_unlock_bh(&p->br->lock); + } else { + /* Binary compatibility with old RSTP */ + if (nla_len(protinfo) < sizeof(u8)) +@@ -1203,17 +1207,10 @@ static int br_port_slave_changelink(struct net_device *brdev, + struct nlattr *data[], + struct netlink_ext_ack *extack) + { +- struct net_bridge *br = netdev_priv(brdev); +- int ret; +- + if (!data) + return 0; + +- spin_lock_bh(&br->lock); +- ret = br_setport(br_port_get_rtnl(dev), data, extack); +- spin_unlock_bh(&br->lock); +- +- return ret; ++ return br_setport(br_port_get_rtnl(dev), data, extack); + } + + static int br_port_fill_slave_info(struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-6.18/bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch b/queue-6.18/bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch new file mode 100644 index 0000000000..6ef97d1200 --- /dev/null +++ b/queue-6.18/bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch @@ -0,0 +1,158 @@ +From ec010e21cbf9a8f3269aef3359f27e26e9969cd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 09:48:17 +0300 +Subject: bridge: Fix sleep in atomic context in sysfs path + +From: Ido Schimmel + +[ Upstream commit 6d34594cc619d0d4b07d5afcad8b5984f3526dcf ] + +Since the start of the git history, brport_store() always acquired the +bridge lock. Back then this decision made sense: The bridge lock +protects the STP state of the bridge and its ports and at that time the +function was only used by two STP related attributes (cost and +priority). + +Nowadays, brport_store() processes a lot more attributes and most of +them do not need the bridge lock: + +* Bridge flags: Only require RTNL. Read locklessly by the data path. + Annotations can be added in net-next. + +* FDB port flushing: Only requires the FDB lock. + +* Multicast attributes: Only require the multicast lock. + +* Group forward mask: Only requires RTNL. Read locklessly by the data + path. Annotations can be added in net-next. + +* Backup port: Only requires RTNL. Read locklessly by the data path. + +This is a problem as the bridge calls dev_set_promiscuity() when certain +bridge port flags change and this function can sleep since the commit +cited below, resulting in a splat such as [1]. + +Fix this by reducing the scope of the bridge lock and only take it when +processing the two STP related attributes that require it. Remove the +now stale comment from br_switchdev_set_port_flag(). The +SWITCHDEV_F_DEFER flag can be removed in net-next. + +[1] +BUG: sleeping function called from invalid context at net/core/dev_addr_lists.c:1262 +in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 372, name: bash +preempt_count: 201, expected: 0 +RCU nest depth: 0, expected: 0 +5 locks held by bash/372: +#0: ffff88810c51c3f0 (sb_writers#7){.+.+}-{0:0}, at: ksys_write (fs/read_write.c:740) +#1: ffff888115ce9480 (&of->mutex){+.+.}-{4:4}, at: kernfs_fop_write_iter (fs/kernfs/file.c:343) +#2: ffff88810b9fd330 (kn->active#37){.+.+}-{0:0}, at: kernfs_fop_write_iter (fs/kernfs/file.c:80 fs/kernfs/file.c:344) +#3: ffffffffa59473a0 (rtnl_mutex){+.+.}-{4:4}, at: brport_store (net/bridge/br_sysfs_if.c:326) +#4: ffff8881099d2d58 (&br->lock){+...}-{3:3}, at: brport_store (./include/linux/spinlock.h:348 net/bridge/br_sysfs_if.c:345) +Preemption disabled at: + 0x0 +Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +__might_resched.cold (kernel/sched/core.c:9163) +netif_rx_mode_run (net/core/dev_addr_lists.c:1262) +netif_rx_mode_sync (net/core/dev_addr_lists.c:1428) +dev_set_promiscuity (net/core/dev_api.c:289) +br_manage_promisc (net/bridge/br_if.c:135 net/bridge/br_if.c:172) +br_port_flags_change (net/bridge/br_if.c:242 net/bridge/br_if.c:747) +store_learning (net/bridge/br_sysfs_if.c:79 net/bridge/br_sysfs_if.c:235) +brport_store (net/bridge/br_sysfs_if.c:346) +kernfs_fop_write_iter (fs/kernfs/file.c:352) +new_sync_write (fs/read_write.c:595) +vfs_write (fs/read_write.c:688) +ksys_write (fs/read_write.c:740) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 78cd408356fe ("net: add missing instance lock to dev_set_promiscuity") +Reviewed-by: Nikolay Aleksandrov +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260526064818.272516-3-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/bridge/br_switchdev.c | 1 - + net/bridge/br_sysfs_if.c | 30 ++++++++++++++++++++++-------- + 2 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c +index fe3f7bbe86ee62..b5c6e314204f94 100644 +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -99,7 +99,6 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, + attr.u.brport_flags.val = flags; + attr.u.brport_flags.mask = mask; + +- /* We run from atomic context here */ + err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev, + &info.info, extack); + err = notifier_to_errno(err); +diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c +index 74fdd8105dca9e..3fe664fd1f5b82 100644 +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -86,16 +86,34 @@ static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) + return sprintf(buf, "%d\n", p->path_cost); + } + +-static BRPORT_ATTR(path_cost, 0644, +- show_path_cost, br_stp_set_path_cost); ++static int store_path_cost(struct net_bridge_port *p, unsigned long v) ++{ ++ int ret; ++ ++ spin_lock_bh(&p->br->lock); ++ ret = br_stp_set_path_cost(p, v); ++ spin_unlock_bh(&p->br->lock); ++ return ret; ++} ++ ++static BRPORT_ATTR(path_cost, 0644, show_path_cost, store_path_cost); + + static ssize_t show_priority(struct net_bridge_port *p, char *buf) + { + return sprintf(buf, "%d\n", p->priority); + } + +-static BRPORT_ATTR(priority, 0644, +- show_priority, br_stp_set_port_priority); ++static int store_priority(struct net_bridge_port *p, unsigned long v) ++{ ++ int ret; ++ ++ spin_lock_bh(&p->br->lock); ++ ret = br_stp_set_port_priority(p, v); ++ spin_unlock_bh(&p->br->lock); ++ return ret; ++} ++ ++static BRPORT_ATTR(priority, 0644, show_priority, store_priority); + + static ssize_t show_designated_root(struct net_bridge_port *p, char *buf) + { +@@ -334,17 +352,13 @@ static ssize_t brport_store(struct kobject *kobj, + ret = -ENOMEM; + goto out_unlock; + } +- spin_lock_bh(&p->br->lock); + ret = brport_attr->store_raw(p, buf_copy); +- spin_unlock_bh(&p->br->lock); + kfree(buf_copy); + } else if (brport_attr->store) { + val = simple_strtoul(buf, &endp, 0); + if (endp == buf) + goto out_unlock; +- spin_lock_bh(&p->br->lock); + ret = brport_attr->store(p, val); +- spin_unlock_bh(&p->br->lock); + } + + if (!ret) { +-- +2.53.0 + diff --git a/queue-6.18/cxl-test-update-mock-dev-array-before-calling-platfo.patch b/queue-6.18/cxl-test-update-mock-dev-array-before-calling-platfo.patch new file mode 100644 index 0000000000..416d59be2d --- /dev/null +++ b/queue-6.18/cxl-test-update-mock-dev-array-before-calling-platfo.patch @@ -0,0 +1,272 @@ +From 20bd511145f9c4b316a8031d166c461dbae99f6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 20:14:57 +0800 +Subject: cxl/test: Update mock dev array before calling platform_device_add() + +From: Li Ming + +[ Upstream commit d90f236f8b9e354848bd226f581db27755ab901d ] + +CXL test environment hits the following error sometimes. + + cxl_mem mem9: endpoint7 failed probe + +All mock memdevs are platform firmware devices added by cxl_test module, +and cxl_test module also provides a platform device driver for them to +create a memdev device to CXL subsystem. cxl_test module uses +cxl_rcd/mem_single/mem arrays to store different types of mock memdevs. +CXL drivers calls registered mock functions for a mock memdev by +checking if a given memdev is in these arrays. + +When cxl_test module adds these mock memdevs, it always calls +platform_device_add() before adding them to a suitable mock memdev +array. However, there is a small window where CXL drivers calls mock +function for a added memdev before it added to a mock memdev array. In +above case, cxl endpoint driver considers a added memdev was not a mock +memdev, then calling devm_cxl_endpoint_decoders_setup() for it rather +than mock_endpoint_decoders_setup(). + +An appropriate solution is that adding a new mock device to a mock +device array before calling platform_device_add() for it. It can +guarantee the new mock device is visible to CXL subsystem. + +This patch introduces a new helped called cxl_mock_platform_device_add() +to handle the issue, and uses the function for all mock devices addition. + +Fixes: 3a2b97b3210b ("cxl/test: Improve init-order fidelity relative to real-world systems") +Signed-off-by: Li Ming +Tested-by: Alison Schofield +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260520121457.234404-1-ming.li@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + tools/testing/cxl/test/cxl.c | 105 ++++++++++++++--------------------- + 1 file changed, 43 insertions(+), 62 deletions(-) + +diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c +index 2d135ca533d02b..5771c75bc58893 100644 +--- a/tools/testing/cxl/test/cxl.c ++++ b/tools/testing/cxl/test/cxl.c +@@ -1132,6 +1132,23 @@ static void mock_companion(struct acpi_device *adev, struct device *dev) + #define SZ_64G (SZ_32G * 2) + #endif + ++static int cxl_mock_platform_device_add(struct platform_device *pdev, ++ struct platform_device **ppdev) ++{ ++ int rc; ++ ++ if (ppdev) ++ *ppdev = pdev; ++ rc = platform_device_add(pdev); ++ if (rc) { ++ platform_device_put(pdev); ++ if (ppdev) ++ *ppdev = NULL; ++ } ++ ++ return rc; ++} ++ + static __init int cxl_rch_topo_init(void) + { + int rc, i; +@@ -1146,13 +1163,10 @@ static __init int cxl_rch_topo_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_rch[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_rch[i] = pdev; + mock_pci_bus[idx].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "firmware_node"); +@@ -1204,13 +1218,10 @@ static __init int cxl_single_topo_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_hb_single[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_hb_single[i] = pdev; + mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "physical_node"); +@@ -1229,12 +1240,9 @@ static __init int cxl_single_topo_init(void) + goto err_port; + pdev->dev.parent = &bridge->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_root_single[i]); ++ if (rc) + goto err_port; +- } +- cxl_root_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++) { +@@ -1247,12 +1255,9 @@ static __init int cxl_single_topo_init(void) + goto err_uport; + pdev->dev.parent = &root_port->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_swu_single[i]); ++ if (rc) + goto err_uport; +- } +- cxl_swu_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++) { +@@ -1266,12 +1271,9 @@ static __init int cxl_single_topo_init(void) + goto err_dport; + pdev->dev.parent = &uport->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_swd_single[i]); ++ if (rc) + goto err_dport; +- } +- cxl_swd_single[i] = pdev; + } + + return 0; +@@ -1344,12 +1346,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &dport->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_mem[i]); ++ if (rc) + goto err_mem; +- } +- cxl_mem[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) { +@@ -1362,12 +1361,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &dport->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_mem_single[i]); ++ if (rc) + goto err_single; +- } +- cxl_mem_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) { +@@ -1381,12 +1377,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &rch->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_rcd[i]); ++ if (rc) + goto err_rcd; +- } +- cxl_rcd[i] = pdev; + } + + return 0; +@@ -1451,13 +1444,10 @@ static __init int cxl_test_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_host_bridge[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_host_bridge[i] = pdev; + mock_pci_bus[i].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "physical_node"); +@@ -1475,12 +1465,9 @@ static __init int cxl_test_init(void) + goto err_port; + pdev->dev.parent = &bridge->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_root_port[i]); ++ if (rc) + goto err_port; +- } +- cxl_root_port[i] = pdev; + } + + BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port)); +@@ -1493,12 +1480,9 @@ static __init int cxl_test_init(void) + goto err_uport; + pdev->dev.parent = &root_port->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_switch_uport[i]); ++ if (rc) + goto err_uport; +- } +- cxl_switch_uport[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) { +@@ -1511,12 +1495,9 @@ static __init int cxl_test_init(void) + goto err_dport; + pdev->dev.parent = &uport->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_switch_dport[i]); ++ if (rc) + goto err_dport; +- } +- cxl_switch_dport[i] = pdev; + } + + rc = cxl_single_topo_init(); +@@ -1534,9 +1515,9 @@ static __init int cxl_test_init(void) + mock_companion(&acpi0017_mock, &cxl_acpi->dev); + acpi0017_mock.dev.bus = &platform_bus_type; + +- rc = platform_device_add(cxl_acpi); ++ rc = cxl_mock_platform_device_add(cxl_acpi, NULL); + if (rc) +- goto err_root; ++ goto err_rch; + + rc = cxl_mem_init(); + if (rc) +-- +2.53.0 + diff --git a/queue-6.18/drm-xe-restore-idledly-regiter-on-engine-reset.patch b/queue-6.18/drm-xe-restore-idledly-regiter-on-engine-reset.patch new file mode 100644 index 0000000000..710f2f16c4 --- /dev/null +++ b/queue-6.18/drm-xe-restore-idledly-regiter-on-engine-reset.patch @@ -0,0 +1,43 @@ +From 3e1f83ee7c1219adf3c5f51eada0ad850b451c88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 22:05:32 +0530 +Subject: drm/xe: Restore IDLEDLY regiter on engine reset + +From: Balasubramani Vivekanandan + +[ Upstream commit f657a6a3ba4c20bc01f5be3752d53498ee1bfe35 ] + +Wa_16023105232 programs the register IDLEDLY. The register is reset +whenever the engine is reset. Therefore it should be added to the GuC +save-restore register list for it to be restored after reset. + +Fixes: 7c53ff050ba8 ("drm/xe: Apply Wa_16023105232") +Reviewed-by: Matt Roper +Link: https://patch.msgid.link/20260522163531.1365540-2-balasubramani.vivekanandan@intel.com +Signed-off-by: Balasubramani Vivekanandan +(cherry picked from commit df1cfe24743a93b71eab27687e148ab8ae9b69e3) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_guc_ads.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c +index 0e2bece1d8b83b..db71823b253801 100644 +--- a/drivers/gpu/drm/xe/xe_guc_ads.c ++++ b/drivers/gpu/drm/xe/xe_guc_ads.c +@@ -772,6 +772,11 @@ static unsigned int guc_mmio_regset_write(struct xe_guc_ads *ads, + } + } + ++ if (XE_GT_WA(hwe->gt, 16023105232)) ++ guc_mmio_regset_write_one(ads, regset_map, ++ RING_IDLEDLY(hwe->mmio_base), ++ count++); ++ + return count; + } + +-- +2.53.0 + diff --git a/queue-6.18/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch b/queue-6.18/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch new file mode 100644 index 0000000000..fb67f8bfe3 --- /dev/null +++ b/queue-6.18/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch @@ -0,0 +1,52 @@ +From 71887194c285cba821f41e7f6293a7dbf281b6a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:10 -0700 +Subject: ethtool: cmis: fix u16-to-u8 truncation of msleep_pre_rpl + +From: Jakub Kicinski + +[ Upstream commit 3e8c3d464c36bb342fe377b026577c7ec27fdbb4 ] + +ethtool_cmis_cdb_compose_args() accepts msleep_pre_rpl as u16 but stores +it into the u8 field ethtool_cmis_cdb_cmd_args::msleep_pre_rpl, silently +truncating values >= 256. Seven of the nine call sites pass 1000 ms +(it's the third argument from the end). + +Fixes: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-8-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h +index 4a9a946cabf05d..778783a0f23c0b 100644 +--- a/net/ethtool/cmis.h ++++ b/net/ethtool/cmis.h +@@ -63,9 +63,9 @@ struct ethtool_cmis_cdb_request { + * struct ethtool_cmis_cdb_cmd_args - CDB commands execution arguments + * @req: CDB command fields as described in the CMIS standard. + * @max_duration: Maximum duration time for command completion in msec. ++ * @msleep_pre_rpl: Waiting time before checking reply in msec. + * @read_write_len_ext: Allowable additional number of byte octets to the LPL + * in a READ or a WRITE commands. +- * @msleep_pre_rpl: Waiting time before checking reply in msec. + * @rpl_exp_len: Expected reply length in bytes. + * @flags: Validation flags for CDB commands. + * @err_msg: Error message to be sent to user space. +@@ -73,8 +73,8 @@ struct ethtool_cmis_cdb_request { + struct ethtool_cmis_cdb_cmd_args { + struct ethtool_cmis_cdb_request req; + u16 max_duration; ++ u16 msleep_pre_rpl; + u8 read_write_len_ext; +- u8 msleep_pre_rpl; + u8 rpl_exp_len; + u8 flags; + char *err_msg; +-- +2.53.0 + diff --git a/queue-6.18/ethtool-cmis-require-exact-cdb-reply-length.patch b/queue-6.18/ethtool-cmis-require-exact-cdb-reply-length.patch new file mode 100644 index 0000000000..f2accae2f9 --- /dev/null +++ b/queue-6.18/ethtool-cmis-require-exact-cdb-reply-length.patch @@ -0,0 +1,70 @@ +From 01f3878a50dcd39f1707981a3568bc4e9a42a228 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:09 -0700 +Subject: ethtool: cmis: require exact CDB reply length + +From: Jakub Kicinski + +[ Upstream commit 6c3f999a9d1338c6c89a9ff4549eafe72bc2e7b1 ] + +Malicious SFP module could respond with rpl_len longer than +what cmis_cdb_process_reply() expected, leading to OOB writes. +Malicious HW is a bit theoretical but some modules may just +be buggy and/or the reads may occasionally get corrupted, +so let's protect the kernel. + +The existing check protects from short replies. We need to +protect from long ones, too. All callers that pass a non-zero +rpl_exp_len cast the reply payload to a fixed-layout struct +and read fields at fixed offsets, with no version negotiation +or short-reply handling: + + - cmis_cdb_validate_password() + - cmis_cdb_module_features_get() + - cmis_fw_update_fw_mng_features_get() + +so let's assume that responses longer than expected do not +have to be handled gracefully here. Add a warning message +to make the debug easier in case my understanding is wrong... + +Note that page_data->length (argument of kmalloc) comes from +last arg to ethtool_cmis_page_init() which is rpl_exp_len. + +Note2 that AIs also like to point out overflows in args->req.payload +itself (which is a fixed-size 120 B buffer, on the stack), +but callers should be reading structs defined by the standard, +so protecting from requests for more data than max seem like +defensive programming. + +Fixes: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands") +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-7-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_cdb.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c +index 3057576bc81e3d..fe156991d0becd 100644 +--- a/net/ethtool/cmis_cdb.c ++++ b/net/ethtool/cmis_cdb.c +@@ -513,8 +513,13 @@ static int cmis_cdb_process_reply(struct net_device *dev, + } + + rpl = (struct ethtool_cmis_cdb_rpl *)page_data->data; +- if ((args->rpl_exp_len > rpl->hdr.rpl_len + rpl_hdr_len) || +- !rpl->hdr.rpl_chk_code) { ++ if (rpl->hdr.rpl_len != args->rpl_exp_len) { ++ netdev_warn(dev, "CDB reply length mismatch, expected %u got %u\n", ++ args->rpl_exp_len, rpl->hdr.rpl_len); ++ err = -EIO; ++ goto out; ++ } ++ if (!rpl->hdr.rpl_chk_code) { + err = -EIO; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.18/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch b/queue-6.18/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch new file mode 100644 index 0000000000..4662398660 --- /dev/null +++ b/queue-6.18/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch @@ -0,0 +1,48 @@ +From 394f6b454fc4397492d529895d2821cd9ad0418c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:12 -0700 +Subject: ethtool: cmis: validate fw->size against start_cmd_payload_size + +From: Jakub Kicinski + +[ Upstream commit d5551f4c1800dc714cec86647bdd651ae0de923e ] + +cmis_fw_update_start_download() copies start_cmd_payload_size bytes +from the firmware blob into the CDB LPL vendor_data[] payload without +validating that the FW has enough data. + +Since the start_cmd_payload_size can only be ~120B an image too short +is most likely corrupted, so reject it. + +Fixes: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-10-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_fw_update.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index 16190c97e1f78c..291d04d2776a5c 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -130,6 +130,14 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, + u8 lpl_len; + int err; + ++ if (fw_update->fw->size < vendor_data_size) { ++ ethnl_module_fw_flash_ntf_err(fw_update->dev, ++ &fw_update->ntf_params, ++ "Firmware image too small for module's start payload", ++ NULL); ++ return -EINVAL; ++ } ++ + pl.image_size = cpu_to_be32(fw_update->fw->size); + memcpy(pl.vendor_data, fw_update->fw->data, vendor_data_size); + +-- +2.53.0 + diff --git a/queue-6.18/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch b/queue-6.18/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch new file mode 100644 index 0000000000..0134b9aff4 --- /dev/null +++ b/queue-6.18/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch @@ -0,0 +1,96 @@ +From d92ba0160dd4d91dd6678261f64f5ed7fd6b6b24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:11 -0700 +Subject: ethtool: cmis: validate start_cmd_payload_size from module + +From: Jakub Kicinski + +[ Upstream commit 12c2496a71f82f63617971ca9b730dffa05cf58b ] + +The CMIS firmware update code reads start_cmd_payload_size from +the module's FW Management Features CDB reply and uses it directly +as the byte count for memcpy. The destination buffer is 112 bytes +(ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - 8). So a malicious +module (or corrupted response) can cause a OOB write later on in +cmis_fw_update_start_download(). + +Let's error out. If modules that expect longer LPL writes actually +exist we should revisit. + +struct cmis_cdb_start_fw_download_pl's definition has to move, +no change there. + +Fixes: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-9-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_fw_update.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index df5f344209c47b..16190c97e1f78c 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -44,6 +44,20 @@ enum cmis_cdb_fw_write_mechanism { + CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11, + }; + ++/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard ++ * revision 5.2. ++ * struct cmis_cdb_start_fw_download_pl is a structured layout of the ++ * flat array, ethtool_cmis_cdb_request::payload. ++ */ ++struct cmis_cdb_start_fw_download_pl { ++ __struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */, ++ __be32 image_size; ++ __be32 resv1; ++ ); ++ u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - ++ sizeof(struct cmis_cdb_start_fw_download_pl_h)]; ++}; ++ + static int + cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + struct net_device *dev, +@@ -86,6 +100,14 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + */ + cdb->read_write_len_ext = rpl->read_write_len_ext; + fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size; ++ if (fw_mng->start_cmd_payload_size > ++ sizeof_field(struct cmis_cdb_start_fw_download_pl, vendor_data)) { ++ ethnl_module_fw_flash_ntf_err(dev, ntf_params, ++ "Start cmd payload size exceeds max LPL payload", ++ NULL); ++ return -EINVAL; ++ } ++ + fw_mng->write_mechanism = + rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ? + CMIS_CDB_FW_WRITE_MECHANISM_LPL : +@@ -97,20 +119,6 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + return 0; + } + +-/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard +- * revision 5.2. +- * struct cmis_cdb_start_fw_download_pl is a structured layout of the +- * flat array, ethtool_cmis_cdb_request::payload. +- */ +-struct cmis_cdb_start_fw_download_pl { +- __struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */, +- __be32 image_size; +- __be32 resv1; +- ); +- u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - +- sizeof(struct cmis_cdb_start_fw_download_pl_h)]; +-}; +- + static int + cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, + struct ethtool_cmis_fw_update_params *fw_update, +-- +2.53.0 + diff --git a/queue-6.18/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch b/queue-6.18/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch new file mode 100644 index 0000000000..c9f6ce63af --- /dev/null +++ b/queue-6.18/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch @@ -0,0 +1,45 @@ +From 58d233b2ebb5dc1d314c3abf33a320e45d6294f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:24 -0700 +Subject: ethtool: coalesce: cap profile updates at NET_DIM_PARAMS_NUM_PROFILES + +From: Jakub Kicinski + +[ Upstream commit 7281b096b072f6c6e30420e3467d738f2e4c4b57 ] + +ethnl_update_profile() walks the ETHTOOL_A_PROFILE_IRQ_MODERATION +nest list with an index 'i' and writes new_profile[i++] without +bounding i. The destination is kmemdup()'d at NET_DIM_PARAMS_NUM_PROFILES +entries (5), but the Netlink nest count is entirely user-controlled. +Netlink policies do not have support for constraining the number +of nested entries (or number of multi-attr entries). + +Fixes: f750dfe825b9 ("ethtool: provide customized dim profile management") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/coalesce.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ethtool/coalesce.c b/net/ethtool/coalesce.c +index 3e18ca1ccc5ef6..cace02d964cb21 100644 +--- a/net/ethtool/coalesce.c ++++ b/net/ethtool/coalesce.c +@@ -463,6 +463,12 @@ static int ethnl_update_profile(struct net_device *dev, + + nla_for_each_nested_type(nest, ETHTOOL_A_PROFILE_IRQ_MODERATION, + nests, rem) { ++ if (i >= NET_DIM_PARAMS_NUM_PROFILES) { ++ NL_SET_BAD_ATTR(extack, nest); ++ ret = -E2BIG; ++ goto err_out; ++ } ++ + ret = nla_parse_nested(tb, len_irq_moder - 1, nest, + coalesce_irq_moderation_policy, + extack); +-- +2.53.0 + diff --git a/queue-6.18/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch b/queue-6.18/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch new file mode 100644 index 0000000000..1e58526350 --- /dev/null +++ b/queue-6.18/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch @@ -0,0 +1,48 @@ +From 637d92e057c693b4597c17b89fe97155723406b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:32 -0700 +Subject: ethtool: eeprom: add missing ethnl_ops_begin() / _complete() during + fallback + +From: Jakub Kicinski + +[ Upstream commit 2376586f85f972fefe701f095bb37dcfe7405d21 ] + +All ethtool driver op calls should be sandwiched between +ethnl_ops_begin() / ethnl_ops_complete(). In Netlink eeprom code, +if the paged access failed we fall back to old API, but we +first call _complete() and the fallback never does its own +ethnl_ops_begin(). Move the fallback into the _begin() / _complete() +section. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-10-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 3b8209e930fd3a..03cb418a15823b 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -140,12 +140,11 @@ static int eeprom_prepare_data(const struct ethnl_req_info *req_base, + return 0; + + err_ops: ++ if (ret == -EOPNOTSUPP) ++ ret = eeprom_fallback(request, reply); + ethnl_ops_complete(dev); + err_free: + kfree(page_data.data); +- +- if (ret == -EOPNOTSUPP) +- return eeprom_fallback(request, reply); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch b/queue-6.18/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch new file mode 100644 index 0000000000..4e9cdaa3cd --- /dev/null +++ b/queue-6.18/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch @@ -0,0 +1,62 @@ +From 32e6a7649ddbbac971ff8af78da3dfb63e930df2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:33 -0700 +Subject: ethtool: eeprom: add more safeties to EEPROM Netlink fallback + +From: Jakub Kicinski + +[ Upstream commit 67cfdd9210b99f260b3e0afeb9525e0acc7be31e ] + +The Netlink fallback path for reading module EEPROM +(fallback_set_params()) validates that offset < eeprom_len, +but does not check that offset + length stays within eeprom_len. +The ioctl equivalent (ethtool_get_any_eeprom() in ioctl.c) has +always enforced both bounds: + + if (eeprom.offset + eeprom.len > total_len) + return -EINVAL; + +This could lead to surprises in both drivers and device FW. +Add the missing offset + length validation to fallback_set_params(), +mirroring the ioctl. + +Similarly - ethtool core in general, and ethtool_get_any_eeprom() +in particular tries to zero-init all buffers passed to the drivers +to avoid any extra work of zeroing things out. eeprom_fallback() +uses a plain kmalloc(), change it to zalloc. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-11-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 03cb418a15823b..80af38a6c76acf 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -43,6 +43,9 @@ static int fallback_set_params(struct eeprom_req_info *request, + if (offset >= modinfo->eeprom_len) + return -EINVAL; + ++ if (length > modinfo->eeprom_len - offset) ++ return -EINVAL; ++ + eeprom->cmd = ETHTOOL_GMODULEEEPROM; + eeprom->len = length; + eeprom->offset = offset; +@@ -68,7 +71,7 @@ static int eeprom_fallback(struct eeprom_req_info *request, + if (err < 0) + return err; + +- data = kmalloc(eeprom.len, GFP_KERNEL); ++ data = kzalloc(eeprom.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + err = ethtool_get_module_eeprom_call(dev, &eeprom, data); +-- +2.53.0 + diff --git a/queue-6.18/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch b/queue-6.18/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch new file mode 100644 index 0000000000..54bf63e099 --- /dev/null +++ b/queue-6.18/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch @@ -0,0 +1,43 @@ +From 2f4548a2f2a530b33e8fcdf0f35b07c310a7ccd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:26 -0700 +Subject: ethtool: linkstate: fix unbalanced ethnl_ops_complete() on PHY lookup + error + +From: Jakub Kicinski + +[ Upstream commit 596c51ed9e125b12c4d85b4530dfd4c7847634b7 ] + +linkstate_prepare_data() calls ethnl_req_get_phydev() before +ethnl_ops_begin(), but routes its error path through "goto out" +which calls ethnl_ops_complete(). + +Fixes: fe55b1d401c6 ("ethtool: linkstate: migrate linkstate functions to support multi-PHY setups") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-4-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/linkstate.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/linkstate.c b/net/ethtool/linkstate.c +index 05a5f72c99fab1..3dc52a39d34525 100644 +--- a/net/ethtool/linkstate.c ++++ b/net/ethtool/linkstate.c +@@ -105,10 +105,8 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base, + + phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER, + info->extack); +- if (IS_ERR(phydev)) { +- ret = PTR_ERR(phydev); +- goto out; +- } ++ if (IS_ERR(phydev)) ++ return PTR_ERR(phydev); + + ret = ethnl_ops_begin(dev); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-6.18/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch b/queue-6.18/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch new file mode 100644 index 0000000000..a16fd120d5 --- /dev/null +++ b/queue-6.18/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch @@ -0,0 +1,50 @@ +From 0f4d67c484013322a6f85a0b0c9379a1e18bc8f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:05 -0700 +Subject: ethtool: module: avoid leaking a netdev ref on module flash errors + +From: Jakub Kicinski + +[ Upstream commit fb7f511d62692661846c47f199e0afe25c2982db ] + +module_flash_fw_schedule() is missing undo for setting +the "in_progress" flag and taking the netdev reference. +Delay taking these, the device can't disappear while +we are holding rtnl_lock. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-3-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 05e4c1d785656f..fb61bb47083e62 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -319,8 +319,6 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + if (err < 0) + goto err_release_firmware; + +- dev->ethtool->module_fw_flash_in_progress = true; +- netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL); + fw_update->dev = dev; + fw_update->ntf_params.portid = info->snd_portid; + fw_update->ntf_params.seq = info->snd_seq; +@@ -335,6 +333,9 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + if (err < 0) + goto err_release_firmware; + ++ dev->ethtool->module_fw_flash_in_progress = true; ++ netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL); ++ + schedule_work(&module_fw->work); + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch b/queue-6.18/ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch new file mode 100644 index 0000000000..7f2392eae4 --- /dev/null +++ b/queue-6.18/ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch @@ -0,0 +1,64 @@ +From 258ac0ffb852706b67725a68707387bdd7327d6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:06 -0700 +Subject: ethtool: module: avoid racy updates to dev->ethtool bitfield + +From: Jakub Kicinski + +[ Upstream commit 7a84b965ffc12030af63cd10a8f3a1123ff39b7a ] + +When reviewing other changes Gemini points out that we currently +update module_fw_flash_in_progress without holding any locks. +Since module_fw_flash_in_progress is part of a bitfield this +is not great, updates to other fields may be lost. + +We could use a bool and sprinkle some READ_ONCE/WRITE_ONCE here +but seems like the issue is rather than the work is an unusual +writer. The other writers already hold the right locks. So just +very briefly take these locks when the work completes. + +Note that nothing ever cancels the FW update work, so there's +no concern with deadlocks vs cancel. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-4-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index fb61bb47083e62..8929b7fb2fa79c 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -221,14 +221,22 @@ static void module_flash_fw_work_list_del(struct list_head *list) + static void module_flash_fw_work(struct work_struct *work) + { + struct ethtool_module_fw_flash *module_fw; ++ struct net_device *dev; + + module_fw = container_of(work, struct ethtool_module_fw_flash, work); ++ dev = module_fw->fw_update.dev; + + ethtool_cmis_fw_update(&module_fw->fw_update); + + module_flash_fw_work_list_del(&module_fw->list); +- module_fw->fw_update.dev->ethtool->module_fw_flash_in_progress = false; +- netdev_put(module_fw->fw_update.dev, &module_fw->dev_tracker); ++ ++ rtnl_lock(); ++ netdev_lock_ops(dev); ++ dev->ethtool->module_fw_flash_in_progress = false; ++ netdev_unlock_ops(dev); ++ rtnl_unlock(); ++ ++ netdev_put(dev, &module_fw->dev_tracker); + release_firmware(module_fw->fw_update.fw); + kfree(module_fw); + } +-- +2.53.0 + diff --git a/queue-6.18/ethtool-module-call-ethnl_ops_complete-on-module-fla.patch b/queue-6.18/ethtool-module-call-ethnl_ops_complete-on-module-fla.patch new file mode 100644 index 0000000000..0290755cd3 --- /dev/null +++ b/queue-6.18/ethtool-module-call-ethnl_ops_complete-on-module-fla.patch @@ -0,0 +1,42 @@ +From e477c2b51f6eba050ce3a011a7f097ff75cbe261 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:04 -0700 +Subject: ethtool: module: call ethnl_ops_complete() on module flash errors + +From: Jakub Kicinski + +[ Upstream commit 84371fb58423f997939aacdcbc02d128d76a54e5 ] + +When validate() fails we are skipping over ethnl_ops_complete() +even tho we already called ethnl_ops_begin(). + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 4d4e0a82579a2b..05e4c1d785656f 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -427,10 +427,11 @@ int ethnl_act_module_fw_flash(struct sk_buff *skb, struct genl_info *info) + + ret = ethnl_module_fw_flash_validate(dev, info->extack); + if (ret < 0) +- goto out_unlock; ++ goto out_complete; + + ret = module_flash_fw(dev, tb, skb, info); + ++out_complete: + ethnl_ops_complete(dev); + + out_unlock: +-- +2.53.0 + diff --git a/queue-6.18/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch b/queue-6.18/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch new file mode 100644 index 0000000000..e9f86d83de --- /dev/null +++ b/queue-6.18/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch @@ -0,0 +1,56 @@ +From 6824894de8ebb2942bcfc2ea19ca807cd75c3800 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:07 -0700 +Subject: ethtool: module: check fw_flash_in_progress under rtnl_lock + +From: Jakub Kicinski + +[ Upstream commit 504eaefa44c8dec50f7499edcb36d24f3aefab2a ] + +ethnl_set_module_validate() inspects module_fw_flash_in_progress +but validate is meant for _input_ validation, not state validation. +rtnl_lock is not held, yet. Move the check into ethnl_set_module(). + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 8929b7fb2fa79c..202e4c25280a76 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -120,12 +120,6 @@ ethnl_set_module_validate(struct ethnl_req_info *req_info, + if (!tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]) + return 0; + +- if (req_info->dev->ethtool->module_fw_flash_in_progress) { +- NL_SET_ERR_MSG(info->extack, +- "Module firmware flashing is in progress"); +- return -EBUSY; +- } +- + if (!ops->get_module_power_mode || !ops->set_module_power_mode) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY], +@@ -148,6 +142,12 @@ ethnl_set_module(struct ethnl_req_info *req_info, struct genl_info *info) + + ops = dev->ethtool_ops; + ++ if (dev->ethtool->module_fw_flash_in_progress) { ++ NL_SET_ERR_MSG(info->extack, ++ "Module firmware flashing is in progress"); ++ return -EBUSY; ++ } ++ + power_new.policy = nla_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]); + ret = ops->get_module_power_mode(dev, &power, info->extack); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-6.18/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch b/queue-6.18/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch new file mode 100644 index 0000000000..e79abeabf1 --- /dev/null +++ b/queue-6.18/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch @@ -0,0 +1,105 @@ +From 632e6a08d5eb4ad328ab4ac446b37bf5bd72ffc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:08 -0700 +Subject: ethtool: module: fix cleanup if socket used for flashing multiple + devices + +From: Jakub Kicinski + +[ Upstream commit 760d04ebad5c4304f22c0d2251c9623b87a117c8 ] + +When a single Netlink socket issues MODULE_FW_FLASH_ACT against multiple +devices, ethnl_sock_priv_set() overwrites sk_priv->dev on each call, +retaining only the last one. The socket priv is used on socket close, +to walk the global work list and mark the uncompleted flashing work +as "orphaned". Otherwise if another socket reuses the PID it will +unexpectedly receive the flashing notifications. + +Don't record the device, record net pointer instead. The purpose of +the dev is to scope the work to a netns, anyway. If we store netns +the overrides are safe/a nop since all flashed devices must be in +the same netns as the socket. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 9 ++++----- + net/ethtool/netlink.c | 4 ++-- + net/ethtool/netlink.h | 4 ++-- + 3 files changed, 8 insertions(+), 9 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 202e4c25280a76..9a11e7def0029a 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -291,11 +291,9 @@ void ethnl_module_fw_flash_sock_destroy(struct ethnl_sock_priv *sk_priv) + + spin_lock(&module_fw_flash_work_list_lock); + list_for_each_entry(work, &module_fw_flash_work_list, list) { +- if (work->fw_update.dev == sk_priv->dev && +- work->fw_update.ntf_params.portid == sk_priv->portid) { ++ if (work->fw_update.ntf_params.portid == sk_priv->portid && ++ dev_net(work->fw_update.dev) == sk_priv->net) + work->fw_update.ntf_params.closed_sock = true; +- break; +- } + } + spin_unlock(&module_fw_flash_work_list_lock); + } +@@ -332,7 +330,8 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + fw_update->ntf_params.seq = info->snd_seq; + fw_update->ntf_params.closed_sock = false; + +- err = ethnl_sock_priv_set(skb, dev, fw_update->ntf_params.portid, ++ err = ethnl_sock_priv_set(skb, dev_net(dev), ++ fw_update->ntf_params.portid, + ETHTOOL_SOCK_TYPE_MODULE_FW_FLASH); + if (err < 0) + goto err_release_firmware; +diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c +index 2f813f25f07e1a..28577b878fd5b5 100644 +--- a/net/ethtool/netlink.c ++++ b/net/ethtool/netlink.c +@@ -52,7 +52,7 @@ const struct nla_policy ethnl_header_policy_phy_stats[] = { + [ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1), + }; + +-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, ++int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid, + enum ethnl_sock_type type) + { + struct ethnl_sock_priv *sk_priv; +@@ -61,7 +61,7 @@ int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, + if (IS_ERR(sk_priv)) + return PTR_ERR(sk_priv); + +- sk_priv->dev = dev; ++ sk_priv->net = net; + sk_priv->portid = portid; + sk_priv->type = type; + +diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h +index 1d4f9ecb3d263b..3923188097ac0a 100644 +--- a/net/ethtool/netlink.h ++++ b/net/ethtool/netlink.h +@@ -318,12 +318,12 @@ enum ethnl_sock_type { + }; + + struct ethnl_sock_priv { +- struct net_device *dev; ++ struct net *net; + u32 portid; + enum ethnl_sock_type type; + }; + +-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, ++int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid, + enum ethnl_sock_type type); + + /** +-- +2.53.0 + diff --git a/queue-6.18/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch b/queue-6.18/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch new file mode 100644 index 0000000000..4f340594b3 --- /dev/null +++ b/queue-6.18/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch @@ -0,0 +1,59 @@ +From 3cb77c4b69f235db9db4b6d178c7d4db595a5466 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:27 -0700 +Subject: ethtool: pse-pd: fix missing ethnl_ops_complete() + +From: Jakub Kicinski + +[ Upstream commit ab5bf428fb6bd361163c7247b92750d1d24ca2ed ] + +pse_prepare_data() is missing ethnl_ops_complete() if +ethnl_req_get_phydev() returned an error. Move getting +phydev up so that we don't have to worry about this +(similar order to linkstate_prepare_data()). + +Note that phydev may still be NULL (this is checked in +pse_get_pse_attributes()), the goal isn't really to avoid +the _begin() / _complete() calls, only to simplify the error +handling. + +While at it propagate the original error. Why this code +overrides the error with -ENODEV but !phydev generates +-EOPNOTSUPP is unclear to me... + +Fixes: 31748765bed3 ("net: ethtool: pse-pd: Target the command to the requested PHY") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/pse-pd.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c +index 24def9c9dd54bf..aa4514333d13bd 100644 +--- a/net/ethtool/pse-pd.c ++++ b/net/ethtool/pse-pd.c +@@ -61,14 +61,14 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base, + struct phy_device *phydev; + int ret; + +- ret = ethnl_ops_begin(dev); +- if (ret < 0) +- return ret; +- + phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER, + info->extack); + if (IS_ERR(phydev)) +- return -ENODEV; ++ return PTR_ERR(phydev); ++ ++ ret = ethnl_ops_begin(dev); ++ if (ret < 0) ++ return ret; + + ret = pse_get_pse_attributes(phydev, info->extack, data); + +-- +2.53.0 + diff --git a/queue-6.18/ethtool-rss-add-missing-errno-on-rss-context-delete.patch b/queue-6.18/ethtool-rss-add-missing-errno-on-rss-context-delete.patch new file mode 100644 index 0000000000..0e27efbf3f --- /dev/null +++ b/queue-6.18/ethtool-rss-add-missing-errno-on-rss-context-delete.patch @@ -0,0 +1,40 @@ +From 2b6a324a6092ff341b79d75115a7d89ebf559b74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:43 -0700 +Subject: ethtool: rss: add missing errno on RSS context delete + +From: Jakub Kicinski + +[ Upstream commit 3e6c6e9782ff8a8d8ded774b07ad4590cd61d04c ] + +Remember to set ret before jumping out if someone tries +to delete a context on a device which doesn't support +contexts. + +Fixes: fbe09277fa63 ("ethtool: rss: support removing contexts via Netlink") +Link: https://patch.msgid.link/20260522230647.1705600-3-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 926be5698ba4cc..688c0e4bba69db 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -1160,8 +1160,10 @@ int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info) + dev = req.dev; + ops = dev->ethtool_ops; + +- if (!ops->create_rxfh_context) ++ if (!ops->create_rxfh_context) { ++ ret = -EOPNOTSUPP; + goto exit_free_dev; ++ } + + rtnl_lock(); + netdev_lock_ops(dev); +-- +2.53.0 + diff --git a/queue-6.18/ethtool-rss-avoid-device-context-leak-on-reply-build.patch b/queue-6.18/ethtool-rss-avoid-device-context-leak-on-reply-build.patch new file mode 100644 index 0000000000..ed10604613 --- /dev/null +++ b/queue-6.18/ethtool-rss-avoid-device-context-leak-on-reply-build.patch @@ -0,0 +1,55 @@ +From 1b9d6536f1f48649c5b2f13cc9342ad80b9e35c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:47 -0700 +Subject: ethtool: rss: avoid device context leak on reply-build failure + +From: Jakub Kicinski + +[ Upstream commit 32a9ecde62731c9f7412507709192c84dafc38d1 ] + +We wait with filling the reply for new RSS context creation +until after the driver ->create_rxfh_context call. The driver +needs to fill some of the defaults in the context. The failure +of rss_fill_reply() is somewhat theoretical, but doesn't take +much effort to handle it properly. Call ->remove_rxfh_context(). + +If the driver's remove callback fails (some implementations like sfc +can return real command errors from firmware RPCs) - skip the xa_erase +and kfree, leaving the context in the xarray. This matches how +ethnl_rss_delete_doit() behaves. + +Fixes: a166ab7816c5 ("ethtool: rss: support creating contexts via Netlink") +Link: https://patch.msgid.link/20260522230647.1705600-7-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index f745ddec6fbab8..b122f67dbde1d6 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -1096,7 +1096,7 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) + ntf_fail |= rss_fill_reply(rsp, &req.base, &data.base); + if (WARN_ON(!hdr || ntf_fail)) { + ret = -EMSGSIZE; +- goto exit_unlock; ++ goto err_remove_ctx; + } + + genlmsg_end(rsp, hdr); +@@ -1124,6 +1124,10 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) + nlmsg_free(rsp); + return ret; + ++err_remove_ctx: ++ if (ops->remove_rxfh_context(dev, ctx, req.rss_context, NULL)) ++ /* leave the context on failure, like ethnl_rss_delete_doit() */ ++ goto exit_unlock; + err_ctx_id_free: + xa_erase(&dev->ethtool->rss_ctx, req.rss_context); + err_unlock_free_ctx: +-- +2.53.0 + diff --git a/queue-6.18/ethtool-rss-avoid-modifying-the-rss-context-response.patch b/queue-6.18/ethtool-rss-avoid-modifying-the-rss-context-response.patch new file mode 100644 index 0000000000..23443f789d --- /dev/null +++ b/queue-6.18/ethtool-rss-avoid-modifying-the-rss-context-response.patch @@ -0,0 +1,73 @@ +From a6b2877500f8710ed43af00422686dd004d58627 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:42 -0700 +Subject: ethtool: rss: avoid modifying the RSS context response + +From: Jakub Kicinski + +[ Upstream commit c75b6f6eaacd0b74b832414cc3b9289c3686e941 ] + +Gemini says that we're modifying the RSS_CREATE response skb. +I think it's right, the comment says that unicast() should +unshare the skb but I'm not entirely sure what I meant there. +netlink_trim() does a copy but only if skb is not well sized +(it's at least 2x larger than necessary for the payload). + +Fixes: a166ab7816c5 ("ethtool: rss: support creating contexts via Netlink") +Link: https://patch.msgid.link/20260522230647.1705600-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index da5934cceb0757..926be5698ba4cc 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -974,11 +974,17 @@ ethnl_rss_create_validate(struct net_device *dev, struct genl_info *info) + } + + static void +-ethnl_rss_create_send_ntf(struct sk_buff *rsp, struct net_device *dev) ++ethnl_rss_create_send_ntf(const struct sk_buff *rsp, struct net_device *dev) + { +- struct nlmsghdr *nlh = (void *)rsp->data; + struct genlmsghdr *genl_hdr; ++ struct nlmsghdr *nlh; ++ struct sk_buff *ntf; ++ ++ ntf = skb_copy_expand(rsp, 0, 0, GFP_KERNEL); ++ if (!ntf) ++ return; + ++ nlh = nlmsg_hdr(ntf); + /* Convert the reply into a notification */ + nlh->nlmsg_pid = 0; + nlh->nlmsg_seq = ethnl_bcast_seq_next(); +@@ -986,7 +992,7 @@ ethnl_rss_create_send_ntf(struct sk_buff *rsp, struct net_device *dev) + genl_hdr = nlmsg_data(nlh); + genl_hdr->cmd = ETHTOOL_MSG_RSS_CREATE_NTF; + +- ethnl_multicast(rsp, dev); ++ ethnl_multicast(ntf, dev); + } + + int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) +@@ -1094,12 +1100,8 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) + + genlmsg_end(rsp, hdr); + +- /* Use the same skb for the response and the notification, +- * genlmsg_reply() will copy the skb if it has elevated user count. +- */ +- skb_get(rsp); +- ret = genlmsg_reply(rsp, info); + ethnl_rss_create_send_ntf(rsp, dev); ++ ret = genlmsg_reply(rsp, info); + rsp = NULL; + + exit_unlock: +-- +2.53.0 + diff --git a/queue-6.18/ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch b/queue-6.18/ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch new file mode 100644 index 0000000000..f9ea8d9a1f --- /dev/null +++ b/queue-6.18/ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch @@ -0,0 +1,38 @@ +From e877edeca867eba255eda621fc0c9b87fe8ab13c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:44 -0700 +Subject: ethtool: rss: fix falsely ignoring indir table updates + +From: Jakub Kicinski + +[ Upstream commit 8d60141a32875248ef71d49c9920fa5e2aa40b29 ] + +rss_set_prep_indir() compares the new indirection table against the +current one to determine whether any update is needed. The memcmp +call passes data->indir_size as the length argument, but indir_size +is the number of u32 entries, not the byte count. + +Fixes: c0ae03588bbb ("ethtool: rss: initial RSS_SET (indirection table handling)") +Link: https://patch.msgid.link/20260522230647.1705600-4-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 688c0e4bba69db..4877655f724419 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -684,7 +684,7 @@ rss_set_prep_indir(struct net_device *dev, struct genl_info *info, + ethtool_rxfh_indir_default(i, num_rx_rings); + } + +- *mod |= memcmp(rxfh->indir, data->indir_table, data->indir_size); ++ *mod |= memcmp(rxfh->indir, data->indir_table, alloc_size); + + return 0; + +-- +2.53.0 + diff --git a/queue-6.18/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch b/queue-6.18/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch new file mode 100644 index 0000000000..1ae23d7873 --- /dev/null +++ b/queue-6.18/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch @@ -0,0 +1,47 @@ +From b52bc769fa7c9519a6067d3916c55c8b43371999 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:46 -0700 +Subject: ethtool: rss: fix hkey leak when indir_size is 0 + +From: Jakub Kicinski + +[ Upstream commit 78ccf1a70c6378e1f5073a8c2209b5129067b925 ] + +rss_get_data_alloc() allocates a single buffer that backs both the +indirection table and the hash key, but only assigned data->indir_table +when indir_size was nonzero. The expectation was that no driver +implements RSS without supporting indirection table but apparently +enic does just that (it's the only such in-tree driver). +enic has get_rxfh_key_size but no get_rxfh_indir_size. +data->indir_table stays as NULL, hkey gets set but rss_get_data_free() +kfree(data->indir_table) is a nop and the allocation leaks. + +Always store the allocation base in data->indir_table so the free path +is unambiguous. No caller treats indir_table as a sentinel; everything +keys off indir_size. + +Fixes: 7112a04664bf ("ethtool: add netlink based get rss support") +Link: https://patch.msgid.link/20260522230647.1705600-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 5416aec13b7fe7..f745ddec6fbab8 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -132,8 +132,7 @@ rss_get_data_alloc(struct net_device *dev, struct rss_reply_data *data) + if (!rss_config) + return -ENOMEM; + +- if (data->indir_size) +- data->indir_table = (u32 *)rss_config; ++ data->indir_table = (u32 *)rss_config; + if (data->hkey_size) + data->hkey = rss_config + indir_bytes; + +-- +2.53.0 + diff --git a/queue-6.18/ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch b/queue-6.18/ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch new file mode 100644 index 0000000000..fb4bad47ab --- /dev/null +++ b/queue-6.18/ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch @@ -0,0 +1,41 @@ +From 321c11d7e8206244e7a8a8b27c735a5fe32acc09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:45 -0700 +Subject: ethtool: rss: fix indir_table and hkey leak on get_rxfh failure + +From: Jakub Kicinski + +[ Upstream commit 266297692f97008ca48bc311775c087c59bd7fe3 ] + +rss_prepare_get() allocates the indirection table and hash key buffer +via rss_get_data_alloc(), then calls ops->get_rxfh() to populate them. +If get_rxfh() fails, the function returns an error without freeing +the allocation. + +Fixes: 4f038a6a02d2 ("net: ethtool: Don't call .cleanup_data when prepare_data fails") +Link: https://patch.msgid.link/20260522230647.1705600-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 4877655f724419..5416aec13b7fe7 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -168,8 +168,10 @@ rss_prepare_get(const struct rss_req_info *request, struct net_device *dev, + rxfh.key = data->hkey; + + ret = ops->get_rxfh(dev, &rxfh); +- if (ret) ++ if (ret) { ++ rss_get_data_free(data); + goto out_unlock; ++ } + + data->hfunc = rxfh.hfunc; + data->input_xfrm = rxfh.input_xfrm; +-- +2.53.0 + diff --git a/queue-6.18/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch b/queue-6.18/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch new file mode 100644 index 0000000000..6fa800ef27 --- /dev/null +++ b/queue-6.18/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch @@ -0,0 +1,42 @@ +From faabee6674234c8a1f1896028c1580f4f9618b42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:31 -0700 +Subject: ethtool: strset: fix header attribute index in ethnl_req_get_phydev() + +From: Jakub Kicinski + +[ Upstream commit a8d8bef6b45bf7cc0b1f6110c5cd8d0160a9bad7 ] + +strset_prepare_data() passes ETHTOOL_A_HEADER_FLAGS (3) as the header +attribute to ethnl_req_get_phydev(). This is incorrect, in the main +attr space 3 is ETHTOOL_A_STRSET_COUNTS_ONLY, not the request +header attr. The correct constant is ETHTOOL_A_STRSET_HEADER (1). + +ethnl_req_get_phydev() only uses this value for the extack, +so this is not a "functionally visible"(?) bug. + +Fixes: e96c93aa4be9 ("net: ethtool: strset: Allow querying phy stats by index") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-9-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/strset.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c +index f6a67109beda1b..872ca593b97668 100644 +--- a/net/ethtool/strset.c ++++ b/net/ethtool/strset.c +@@ -309,7 +309,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base, + return 0; + } + +- phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS, ++ phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STRSET_HEADER, + info->extack); + + /* phydev can be NULL, check for errors only */ +-- +2.53.0 + diff --git a/queue-6.18/ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch b/queue-6.18/ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch new file mode 100644 index 0000000000..06b3981b4b --- /dev/null +++ b/queue-6.18/ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch @@ -0,0 +1,42 @@ +From ea036757a9073fda66746ba73e5bd50e38672736 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:28 -0700 +Subject: ethtool: tsconfig: fix missing ethnl_ops_complete() + +From: Jakub Kicinski + +[ Upstream commit 6386bd772de64e6760306eb91c7e86163af6c22f ] + +tsconfig_prepare_data() calls ethnl_ops_begin(), we need to call +ethnl_ops_complete() before returning the error. + +Fixes: 6e9e2eed4f39 ("net: ethtool: Add support for tsconfig command to get/set hwtstamp config") +Reviewed-by: Vadim Fedorenko +Reviewed-by: Kory Maincent +Link: https://patch.msgid.link/20260526153533.2779187-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsconfig.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/tsconfig.c b/net/ethtool/tsconfig.c +index 041de8687472bd..a121928038b055 100644 +--- a/net/ethtool/tsconfig.c ++++ b/net/ethtool/tsconfig.c +@@ -69,8 +69,10 @@ static int tsconfig_prepare_data(const struct ethnl_req_info *req_base, + if (ret) + goto out; + +- if (ts_info.phc_index == -1) +- return -ENODEV; ++ if (ts_info.phc_index == -1) { ++ ret = -ENODEV; ++ goto out; ++ } + + data->hwprov_desc.index = ts_info.phc_index; + data->hwprov_desc.qualifier = ts_info.phc_qualifier; +-- +2.53.0 + diff --git a/queue-6.18/ethtool-tsconfig-fix-reply-error-handling.patch b/queue-6.18/ethtool-tsconfig-fix-reply-error-handling.patch new file mode 100644 index 0000000000..8ee195f447 --- /dev/null +++ b/queue-6.18/ethtool-tsconfig-fix-reply-error-handling.patch @@ -0,0 +1,55 @@ +From 183d1c373f0347a9aae5dcde9ea698c5db266276 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:25 -0700 +Subject: ethtool: tsconfig: fix reply error handling + +From: Jakub Kicinski + +[ Upstream commit a888bbd43940cada72f7686337741ce86d1cf869 ] + +A couple of trivial bugs in error handling in tsconfig_send_reply(). +If we failed to allocate rskb we need to set the error. +If we did allocate it but failed to send it - we need to remember +to free it. + +Fixes: 6e9e2eed4f39 ("net: ethtool: Add support for tsconfig command to get/set hwtstamp config") +Reviewed-by: Vadim Fedorenko +Reviewed-by: Kory Maincent +Link: https://patch.msgid.link/20260526153533.2779187-3-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsconfig.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/tsconfig.c b/net/ethtool/tsconfig.c +index 169b413b31fc5f..041de8687472bd 100644 +--- a/net/ethtool/tsconfig.c ++++ b/net/ethtool/tsconfig.c +@@ -224,16 +224,21 @@ static int tsconfig_send_reply(struct net_device *dev, struct genl_info *info) + reply_len = ret + ethnl_reply_header_size(); + rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_TSCONFIG_SET_REPLY, + ETHTOOL_A_TSCONFIG_HEADER, info, &reply_payload); +- if (!rskb) ++ if (!rskb) { ++ ret = -ENOMEM; + goto err_cleanup; ++ } + + ret = tsconfig_fill_reply(rskb, &req_info->base, &reply_data->base); + if (ret < 0) +- goto err_cleanup; ++ goto err_free_msg; + + genlmsg_end(rskb, reply_payload); + ret = genlmsg_reply(rskb, info); ++ rskb = NULL; + ++err_free_msg: ++ nlmsg_free(rskb); + err_cleanup: + kfree(reply_data); + kfree(req_info); +-- +2.53.0 + diff --git a/queue-6.18/ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch b/queue-6.18/ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch new file mode 100644 index 0000000000..928a48180e --- /dev/null +++ b/queue-6.18/ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch @@ -0,0 +1,49 @@ +From 07d3e946d4f9dfcf01e7ac59f9b5a9fb1ba8cb3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:30 -0700 +Subject: ethtool: tsinfo: don't pass ERR_PTR to genlmsg_cancel on prepare + failure + +From: Jakub Kicinski + +[ Upstream commit c3fc9976f686f9a95baf87db9d387f218fd65394 ] + +The goto err label leads to: + + genlmsg_cancel(skb, ehdr); + return ret; + +If ethnl_tsinfo_prepare_dump() failed, it has not started a genlmsg. +There's nothing to cancel, and passing an error pointer to +genlmsg_cancel() would cause a crash. + +Fixes: b9e3f7dc9ed9 ("net: ethtool: tsinfo: Enhance tsinfo to support several hwtstamp by net topology") +Reviewed-by: Maxime Chevallier +Reviewed-by: Kory Maincent +Link: https://patch.msgid.link/20260526153533.2779187-8-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsinfo.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/tsinfo.c b/net/ethtool/tsinfo.c +index fcc28fca526d82..53f12128a1a580 100644 +--- a/net/ethtool/tsinfo.c ++++ b/net/ethtool/tsinfo.c +@@ -405,10 +405,8 @@ static int ethnl_tsinfo_dump_one_netdev(struct sk_buff *skb, + continue; + + ehdr = ethnl_tsinfo_prepare_dump(skb, dev, reply_data, cb); +- if (IS_ERR(ehdr)) { +- ret = PTR_ERR(ehdr); +- goto err; +- } ++ if (IS_ERR(ehdr)) ++ return PTR_ERR(ehdr); + + reply_data->ts_info.phc_qualifier = ctx->pos_phcqualifier; + ret = ops->get_ts_info(dev, &reply_data->ts_info); +-- +2.53.0 + diff --git a/queue-6.18/ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch b/queue-6.18/ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch new file mode 100644 index 0000000000..329f26f5fd --- /dev/null +++ b/queue-6.18/ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch @@ -0,0 +1,75 @@ +From 7e2211ce4c08a8ec3a99d49949f93cda9aec2877 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:29 -0700 +Subject: ethtool: tsinfo: fix uninitialized stats on the by-PHC path + +From: Jakub Kicinski + +[ Upstream commit 1de405699c62c3a9544bcdcfb9eff8a01cfc7582 ] + +tsinfo_prepare_data() has two code paths: a "by-PHC" path for +user-specified hardware timestamping providers, and the old path. +Commit 89e281ebff72 ("ethtool: init tsinfo stats if requested") added +ethtool_stats_init() to mark stat slots as ETHTOOL_STAT_NOT_SET before +the driver callback populates them, but placed the call inside the +old-path block. + +When commit b9e3f7dc9ed9 ("net: ethtool: tsinfo: Enhance tsinfo to +support several hwtstamp by net topology") added the by-PHC early +return, it landed above the stats initialization. On that path +the stats array retains the zero-fill from ethnl_init_reply_data()'s +zalloc. This leads to the reply including a stats nest with four +zero-valued attributes that should have been absent. + +Reject GET requests for stats with HWTSTAMP_PROVIDER or dump. + +Fixes: b9e3f7dc9ed9 ("net: ethtool: tsinfo: Enhance tsinfo to support several hwtstamp by net topology") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-7-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsinfo.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/net/ethtool/tsinfo.c b/net/ethtool/tsinfo.c +index 8c654caa6805a5..fcc28fca526d82 100644 +--- a/net/ethtool/tsinfo.c ++++ b/net/ethtool/tsinfo.c +@@ -81,6 +81,11 @@ tsinfo_parse_request(struct ethnl_req_info *req_base, struct nlattr **tb, + if (!tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER]) + return 0; + ++ if (req_base->flags & ETHTOOL_FLAG_STATS) { ++ NL_SET_ERR_MSG(extack, "can't query statistics for a provider"); ++ return -EOPNOTSUPP; ++ } ++ + return ts_parse_hwtst_provider(tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER], + &req->hwprov_desc, extack, &mod); + } +@@ -521,6 +526,12 @@ int ethnl_tsinfo_start(struct netlink_callback *cb) + if (ret < 0) + goto free_reply_data; + ++ if (req_info->base.flags & ETHTOOL_FLAG_STATS) { ++ NL_SET_ERR_MSG(cb->extack, "stats not supported in dump"); ++ ret = -EOPNOTSUPP; ++ goto err_dev_put; ++ } ++ + ctx->req_info = req_info; + ctx->reply_data = reply_data; + ctx->pos_ifindex = 0; +@@ -530,6 +541,8 @@ int ethnl_tsinfo_start(struct netlink_callback *cb) + + return 0; + ++err_dev_put: ++ ethnl_parse_header_dev_put(&req_info->base); + free_reply_data: + kfree(reply_data); + free_req_info: +-- +2.53.0 + diff --git a/queue-6.18/gpio-adnp-fix-flow-control-regression-caused-by-scop.patch b/queue-6.18/gpio-adnp-fix-flow-control-regression-caused-by-scop.patch new file mode 100644 index 0000000000..1c110682a3 --- /dev/null +++ b/queue-6.18/gpio-adnp-fix-flow-control-regression-caused-by-scop.patch @@ -0,0 +1,43 @@ +From e9212538ef0e994373e57ded91eb1ed4cc781b2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 09:35:27 +0200 +Subject: gpio: adnp: fix flow control regression caused by scoped_guard() + +From: Bartosz Golaszewski + +[ Upstream commit a5c627d90809b793fc053849b3a00609db305776 ] + +scoped_guard() is implemented as a for loop. Using it to protect code +using the continue statement changes the flow as we now only break out +of the hidden loop inside scoped_guard(), not the original for loop. Use +a regular code block instead. + +Fixes: c7fe19ed3973 ("gpio: adnp: use lock guards for the I2C lock") +Reported-by: David Lechner +Closes: https://lore.kernel.org/all/cde2abb2-4cc8-4fc9-b34a-0c5d2b95779f@baylibre.com/ +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/20260522073527.9812-1-bartosz.golaszewski@oss.qualcomm.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-adnp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c +index e5ac2d2110137f..fe5bcaa90496aa 100644 +--- a/drivers/gpio/gpio-adnp.c ++++ b/drivers/gpio/gpio-adnp.c +@@ -237,7 +237,9 @@ static irqreturn_t adnp_irq(int irq, void *data) + unsigned long pending; + int err; + +- scoped_guard(mutex, &adnp->i2c_lock) { ++ { ++ guard(mutex)(&adnp->i2c_lock); ++ + err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); + if (err < 0) + continue; +-- +2.53.0 + diff --git a/queue-6.18/gpio-mxc-fix-irq_high-handling.patch b/queue-6.18/gpio-mxc-fix-irq_high-handling.patch new file mode 100644 index 0000000000..472b3b51d4 --- /dev/null +++ b/queue-6.18/gpio-mxc-fix-irq_high-handling.patch @@ -0,0 +1,38 @@ +From affb3074346d5d6b6f11ac84db0e0f739e483db5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:01 +0200 +Subject: gpio: mxc: fix irq_high handling + +From: Alexander Stein + +[ Upstream commit dac917ed5aead741004db8d0d5151dd577802df8 ] + +If port->irq_high is -1 (fsl,imx21-gpio compatible) and gpio_idx is >= 16 +enable_irq_wake() is called with -1 which is wrong. + +Fixes: 5f6d1998adeb ("gpio: mxc: release the parent IRQ in runtime suspend") +Signed-off-by: Alexander Stein +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260526063504.25916-1-alexander.stein@ew.tq-group.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mxc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c +index 441ba95b38cf9b..dbdf0f41b6bb91 100644 +--- a/drivers/gpio/gpio-mxc.c ++++ b/drivers/gpio/gpio-mxc.c +@@ -469,7 +469,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) + * the handler is needed only once, but doing it for every port + * is more robust and easier. + */ +- port->irq_high = -1; ++ port->irq_high = 0; + port->mx_irq_handler = mx2_gpio_irq_handler; + } else + port->mx_irq_handler = mx3_gpio_irq_handler; +-- +2.53.0 + diff --git a/queue-6.18/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch b/queue-6.18/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch new file mode 100644 index 0000000000..2cc17f2f4b --- /dev/null +++ b/queue-6.18/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch @@ -0,0 +1,78 @@ +From 8eca85a401d248a8643ce188954e2ed6c3117449 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:45 +0200 +Subject: gpio: rockchip: convert bank->clk to devm_clk_get_enabled() + +From: Marco Scardovi + +[ Upstream commit 3e46c18d5d87f063a93ae0fe7662fbf6660459d5 ] + +The bank->clk was previously obtained via of_clk_get() and manually +prepared/enabled. However, it was missing a corresponding clk_put() in +both the error paths and the remove function, leading to a reference leak. + +Convert the allocation to devm_clk_get_enabled(), which also properly +propagates failures from clk_prepare_enable() that were previously ignored. + +The GPIO bank device uses the same OF node as the previous of_clk_get() +call, so devm_clk_get_enabled(dev, NULL) correctly resolves the same +clock provider entry. + +Fix the reference leak and simplify the code by removing the manual +clk_disable_unprepare() calls in the probe error paths and in the +remove function. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index 0fff4a699f12d1..f910220141f712 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -656,11 +656,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + if (!bank->irq) + return -EINVAL; + +- bank->clk = of_clk_get(bank->of_node, 0); ++ bank->clk = devm_clk_get_enabled(bank->dev, NULL); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + +- clk_prepare_enable(bank->clk); + id = readl(bank->reg_base + gpio_regs_v2.version_id); + + switch (id) { +@@ -672,7 +671,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + bank->db_clk = of_clk_get(bank->of_node, 1); + if (IS_ERR(bank->db_clk)) { + dev_err(bank->dev, "cannot find debounce clk\n"); +- clk_disable_unprepare(bank->clk); + return -EINVAL; + } + break; +@@ -751,7 +749,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev) + + ret = rockchip_gpiolib_register(bank); + if (ret) { +- clk_disable_unprepare(bank->clk); + mutex_unlock(&bank->deferred_lock); + return ret; + } +@@ -792,7 +789,6 @@ static void rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + +- clk_disable_unprepare(bank->clk); + gpiochip_remove(&bank->gpio_chip); + } + +-- +2.53.0 + diff --git a/queue-6.18/gpio-rockchip-teardown-bugs-and-resource-leaks.patch b/queue-6.18/gpio-rockchip-teardown-bugs-and-resource-leaks.patch new file mode 100644 index 0000000000..4cf1fd8a63 --- /dev/null +++ b/queue-6.18/gpio-rockchip-teardown-bugs-and-resource-leaks.patch @@ -0,0 +1,88 @@ +From 7dc30495148ab049146bc3e38ccd9545b81a5e3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:46 +0200 +Subject: gpio: rockchip: teardown bugs and resource leaks + +From: Marco Scardovi + +[ Upstream commit 9500077678230e36d22bf16d2b9539c13e59a801 ] + +Address several teardown issues and resource leaks in the driver's remove +path and error handling: + +1. Debounce clock reference leak: The debounce clock (bank->db_clk) is + obtained using of_clk_get() which increments the clock's reference + count, but clk_put() is never called. Register a devm action to + cleanly release it on unbind. Note that of_clk_get(..., 1) remains + necessary over devm_clk_get() because the DT binding does not define + clock-names, precluding name-based lookup. + +2. Unregistered chained IRQ handler: The chained IRQ handler is not + disconnected in remove(). If a stray interrupt fires after the driver + is removed, the kernel attempts to execute a stale handler, leading + to a panic. Fix this by clearing the handler in remove(). + +3. IRQ domain leak: The linear IRQ domain and its generic chips are + allocated manually during probe but never removed. Remove the IRQ + domain during driver teardown to free the associated generic chips + and mappings. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-3-scardracs@disroot.org +[Bartosz: don't emit an error message on devres allocation failure] +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index f910220141f712..1ef0ba956cfd8c 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -638,10 +638,17 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank) + return ret; + } + ++static void rockchip_clk_put(void *data) ++{ ++ struct clk *clk = data; ++ ++ clk_put(clk); ++} ++ + static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + { + struct resource res; +- int id = 0; ++ int id = 0, ret; + + if (of_address_to_resource(bank->of_node, 0, &res)) { + dev_err(bank->dev, "cannot find IO resource for bank\n"); +@@ -673,6 +680,11 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + dev_err(bank->dev, "cannot find debounce clk\n"); + return -EINVAL; + } ++ ++ ret = devm_add_action_or_reset(bank->dev, rockchip_clk_put, ++ bank->db_clk); ++ if (ret) ++ return ret; + break; + case GPIO_TYPE_V1: + bank->gpio_regs = &gpio_regs_v1; +@@ -789,6 +801,9 @@ static void rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + ++ irq_set_chained_handler_and_data(bank->irq, NULL, NULL); ++ if (bank->domain) ++ irq_domain_remove(bank->domain); + gpiochip_remove(&bank->gpio_chip); + } + +-- +2.53.0 + diff --git a/queue-6.18/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch b/queue-6.18/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch new file mode 100644 index 0000000000..ca8d04be7e --- /dev/null +++ b/queue-6.18/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch @@ -0,0 +1,49 @@ +From f93379d15c9f67df6bab4a6a6fcc9ab5c2e15897 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 10:15:16 +0300 +Subject: gpio: virtuser: Fix uninitialized data bug in + gpio_virtuser_direction_do_write() + +From: Dan Carpenter + +[ Upstream commit 8a122b5e72cc0043705f0d524bcd15f0c0b3ec15 ] + +If *ppos is non-zero (user-space write split over multiple calls to +write()) then simple_write_to_buffer() won't initialize the start of the +buffer. Really, non-zero values for *ppos aren't going to work at all. +Check for that and return -EINVAL at the start of the function. + +Fixes: 91581c4b3f29 ("gpio: virtuser: new virtual testing driver for the GPIO API") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/ahP3BJWWy-m_qI0X@stanley.mountain +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-virtuser.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c +index 252fec5ea38354..1901b4ba558f0c 100644 +--- a/drivers/gpio/gpio-virtuser.c ++++ b/drivers/gpio/gpio-virtuser.c +@@ -399,7 +399,7 @@ static ssize_t gpio_virtuser_direction_do_write(struct file *file, + char buf[32], *trimmed; + int ret, dir, val = 0; + +- if (count >= sizeof(buf)) ++ if (*ppos != 0 || count >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +@@ -626,7 +626,7 @@ static ssize_t gpio_virtuser_consumer_write(struct file *file, + char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 2]; + int ret; + +- if (count >= sizeof(buf)) ++ if (*ppos != 0 || count >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, GPIO_VIRTUSER_NAME_BUF_LEN, ppos, +-- +2.53.0 + diff --git a/queue-6.18/hid-remove-duplicate-hid_warn_ratelimited-definition.patch b/queue-6.18/hid-remove-duplicate-hid_warn_ratelimited-definition.patch new file mode 100644 index 0000000000..d98c33042f --- /dev/null +++ b/queue-6.18/hid-remove-duplicate-hid_warn_ratelimited-definition.patch @@ -0,0 +1,43 @@ +From bbfd0abc8a18bc125d503b8190000180e8bec32d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 16:32:04 +0800 +Subject: HID: remove duplicate hid_warn_ratelimited definition + +From: Liu Kai + +[ Upstream commit dd2147375a8fe7c5bc3f1f1b1d3a9567c26faefa ] + +The hid_warn_ratelimited macro is defined twice in include/linux/hid.h: +- first one added by commit 4051ead99888 ("HID: rate-limit hid_warn to + prevent log flooding") +- second one added by commit 1d64624243af ("HID: core: Add + printk_ratelimited variants to hid_warn() etc")). + +The second definition is correctly grouped with other ratelimited macros. +Remove the duplicate definition. + +Fixes: 1d64624243af ("HID: core: Add printk_ratelimited variants to hid_warn() etc") +Signed-off-by: Liu Kai +[bentiss: edited commit message] +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + include/linux/hid.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/include/linux/hid.h b/include/linux/hid.h +index 204ada8d12e5c8..29561887bea8c0 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -1276,8 +1276,6 @@ void hid_quirks_exit(__u16 bus); + dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__) + #define hid_warn(hid, fmt, ...) \ + dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__) +-#define hid_warn_ratelimited(hid, fmt, ...) \ +- dev_warn_ratelimited(&(hid)->dev, fmt, ##__VA_ARGS__) + #define hid_info(hid, fmt, ...) \ + dev_info(&(hid)->dev, fmt, ##__VA_ARGS__) + #define hid_dbg(hid, fmt, ...) \ +-- +2.53.0 + diff --git a/queue-6.18/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch b/queue-6.18/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch new file mode 100644 index 0000000000..25118890cb --- /dev/null +++ b/queue-6.18/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch @@ -0,0 +1,48 @@ +From dfe1a80b8eaf7812fda563b7967c6bedb1ea2ae4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 12:21:47 +0000 +Subject: ipv4: free net->ipv4.sysctl_local_reserved_ports after + unregister_net_sysctl_table() + +From: Eric Dumazet + +[ Upstream commit 87a1e0fe7776da7ab411be332b4be58ac8840d10 ] + +ipv4_sysctl_exit_net() is currently freeing net->ipv4.sysctl_local_reserved_ports +too soon. + +Only after unregister_net_sysctl_table() we can be sure no threads can possibly +use the sysctls, including /proc/sys/net/ipv4/ip_local_reserved_ports. + +Fixes: 122ff243f5f1 ("ipv4: make ip_local_reserved_ports per netns") +Reported-by: Ji'an Zhou +Signed-off-by: Eric Dumazet +Cc: Cong Wang +Reviewed-by: Jason Xing +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521122147.3584624-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/sysctl_net_ipv4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 0f1dd75dbf37bf..ce9b077343cac2 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -1669,10 +1669,10 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net) + { + const struct ctl_table *table; + +- kfree(net->ipv4.sysctl_local_reserved_ports); + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); ++ kfree(net->ipv4.sysctl_local_reserved_ports); + } + + static __net_initdata struct pernet_operations ipv4_sysctl_ops = { +-- +2.53.0 + diff --git a/queue-6.18/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch b/queue-6.18/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch new file mode 100644 index 0000000000..f3ea215d68 --- /dev/null +++ b/queue-6.18/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch @@ -0,0 +1,49 @@ +From 9d3976e22d79e4a1b07dba67d3223218be4a3c71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:31 +0800 +Subject: ipv6: fix possible infinite loop in fib6_select_path() + +From: Jiayuan Chen + +[ Upstream commit 9c7da87c2dc860bb17ca1ece942495d28b1ce3b9 ] + +Found while auditing the same pattern Sashiko reported in +rt6_fill_node() [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&first->fib6_siblings) +without waiting for RCU readers; first->fib6_siblings.next then +still points into the old ring and this softirq-side walker never +reaches &first->fib6_siblings as its terminator. fib6_purge_rt() +always WRITE_ONCE()s first->fib6_nsiblings to 0 before +list_del_rcu(), so an inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index cf9546047b5749..f89220929c4e24 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -481,6 +481,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res, + const struct fib6_nh *nh = sibling->fib6_nh; + int nh_upper_bound; + ++ if (!READ_ONCE(first->fib6_nsiblings)) ++ break; ++ + nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); + if (hash > nh_upper_bound) + continue; +-- +2.53.0 + diff --git a/queue-6.18/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch b/queue-6.18/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch new file mode 100644 index 0000000000..1e7fd8e2c7 --- /dev/null +++ b/queue-6.18/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch @@ -0,0 +1,47 @@ +From 018bd9df99a7885b7085da96c09831b6160dd257 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:30 +0800 +Subject: ipv6: fix possible infinite loop in rt6_fill_node() + +From: Jiayuan Chen + +[ Upstream commit 9f72412bcf60144f252b0d6205106abf14344abc ] + +Sashiko reported this issue [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&rt->fib6_siblings) +without waiting for RCU readers; rt->fib6_siblings.next then still +points into the old ring and this softirq-side walker never reaches +&rt->fib6_siblings, causing a CPU stall. fib6_del_route() always +WRITE_ONCE()s rt->fib6_nsiblings to 0 before list_del_rcu(), so an +inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 446f4de7d6a227..cf9546047b5749 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -5892,6 +5892,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, + + goto nla_put_failure; + } ++ if (!READ_ONCE(rt->fib6_nsiblings)) ++ break; + } + + rcu_read_unlock(); +-- +2.53.0 + diff --git a/queue-6.18/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch b/queue-6.18/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch new file mode 100644 index 0000000000..470a42fbab --- /dev/null +++ b/queue-6.18/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch @@ -0,0 +1,62 @@ +From aa4e3aef2b26b8c1d3527389570d761e05a3dd25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 21:10:31 +0530 +Subject: ipv6: rpl: fix hdrlen overflow in ipv6_rpl_srh_decompress() + +From: Rahul Chandelkar + +[ Upstream commit 9d5e7a46a9f6d8f503b41bfefef70659845f1679 ] + +ipv6_rpl_srh_decompress() computes: + + outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3); + +hdrlen is __u8. For n >= 127 the result exceeds 255 and silently +truncates. With n=127 (cmpri=15, cmpre=15, pad=0, hdrlen=16): + + (128 * 16) >> 3 = 256, truncated to 0 as __u8 + +The caller in ipv6_rpl_srh_rcv() then places the compressed header +at buf + ((ohdr->hdrlen + 1) << 3). With hdrlen=0 this is buf + 8, +but the decompressed region occupies buf[0..2055] (8-byte header +plus 128 full addresses). The compressed header overlaps the +decompressed data, and ipv6_rpl_srh_compress() writes into this +overlap, corrupting the routing header of the forwarded packet. + +The existing guard at exthdrs.c:546 checks (n + 1) > 255, which +prevents n+1 from overflowing unsigned char (the segments_left +field), but does not prevent the computed hdrlen from overflowing +__u8. n=127 passes because 128 <= 255, yet hdrlen=256 does not +fit. + +Tighten the bound to (n + 1) > 127. This caps n at 126, giving +hdrlen = (127 * 16) >> 3 = 254, which fits in __u8. The compressed +header then lands at buf + ((254 + 1) << 3) = buf + 2040, exactly +past the decompressed region (buf[0..2039]). No overlap. 127 +segments is well beyond any realistic RPL deployment. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Signed-off-by: Rahul Chandelkar +Link: https://patch.msgid.link/20260525154031.2290876-1-rc@rexion.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/exthdrs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index d15e6094382094..830131b427f098 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -544,7 +544,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + * unsigned char which is segments_left field. Should not be + * higher than that. + */ +- if (r || (n + 1) > 255) { ++ if (r || (n + 1) > 127) { + kfree_skb(skb); + return -1; + } +-- +2.53.0 + diff --git a/queue-6.18/kernel-fork-validate-exit_signal-in-kernel_clone.patch b/queue-6.18/kernel-fork-validate-exit_signal-in-kernel_clone.patch new file mode 100644 index 0000000000..508285d2b9 --- /dev/null +++ b/queue-6.18/kernel-fork-validate-exit_signal-in-kernel_clone.patch @@ -0,0 +1,116 @@ +From fcca61d3635730759712bd3d6b18c31021219c96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 20:49:56 +0530 +Subject: kernel/fork: validate exit_signal in kernel_clone() + +From: Deepanshu Kartikey + +[ Upstream commit 09e7827e785729f391c8d46dc71becce70d296ab ] + +When a child process exits, it sends exit_signal to its parent via +do_notify_parent(). The clone() syscall constructs exit_signal as: + +(lower_32_bits(clone_flags) & CSIGNAL) + +CSIGNAL is 0xff, so values in the range 65-255 are possible. However, +valid_signal() only accepts signals up to _NSIG (64 on x86_64). A +non-zero non-valid exit_signal acts the same as exit_signal == 0: the +parent process is not signaled when the child terminates. + +The syzkaller reproducer triggers this by calling clone() with flags=0x80, +resulting in exit_signal = (0x80 & CSIGNAL) = 128, which exceeds _NSIG and +is not a valid signal. + +The v1 of this patch added the check only in the clone() syscall handler, +which is incomplete. kernel_clone() has other callers such as +sys_ia32_clone() which would remain unprotected. Move the check to +kernel_clone() to cover all callers. + +Since the valid_signal() check is now in kernel_clone() and covers all +callers including clone3(), the same check in copy_clone_args_from_user() +becomes redundant and is removed. The higher 32bits check for clone3() is +kept as it is clone3() specific. + +Note that this is a user-visible change: previously, passing an invalid +exit_signal to clone() was silently accepted. The man page for clone() +does not document any defined behavior for invalid exit_signal values, so +rejecting them with -EINVAL is the correct behavior. It is unlikely that +any sane application relies on passing an invalid exit_signal. + +[oleg@redhat.com: the comment above kernel_clone() should be updated] + Link: https://lore.kernel.org/abwvgU17W8wuW2-J@redhat.com +Link: https://lore.kernel.org/20260316151956.563558-1-kartikey406@gmail.com +Fixes: 3f2c788a1314 ("fork: prevent accidental access to clone3 features") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Oleg Nesterov +Reported-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=bbe6b99feefc3a0842de +Tested-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20260307064202.353405-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20260316104536.558108-1-kartikey406@gmail.com/T/ [v2] +Acked-by: Oleg Nesterov +Acked-by: Michal Hocko +Cc: Ben Segall +Cc: Christian Brauner +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Cc: Tetsuo Handa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 1215d3f52c6d21..521e9d2be6f097 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -2562,8 +2562,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node) + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. +- * +- * args->exit_signal is expected to be checked for sanity by the caller. + */ + pid_t kernel_clone(struct kernel_clone_args *args) + { +@@ -2588,6 +2586,9 @@ pid_t kernel_clone(struct kernel_clone_args *args) + (args->pidfd == args->parent_tid)) + return -EINVAL; + ++ if (!valid_signal(args->exit_signal)) ++ return -EINVAL; ++ + /* + * Determine whether and which event to report to ptracer. When + * called from kernel_thread or CLONE_UNTRACED is explicitly +@@ -2786,11 +2787,9 @@ static noinline int copy_clone_args_from_user(struct kernel_clone_args *kargs, + return -EINVAL; + + /* +- * Verify that higher 32bits of exit_signal are unset and that +- * it is a valid signal ++ * Verify that higher 32bits of exit_signal are unset + */ +- if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) || +- !valid_signal(args.exit_signal))) ++ if (unlikely(args.exit_signal & ~((u64)CSIGNAL))) + return -EINVAL; + + if ((args.flags & CLONE_INTO_CGROUP) && +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch b/queue-6.18/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch new file mode 100644 index 0000000000..fb97f1453b --- /dev/null +++ b/queue-6.18/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch @@ -0,0 +1,69 @@ +From 547624fcd83637e995485b6fef6128bcfe8c9539 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 22:07:16 +0900 +Subject: ksmbd: fix FSCTL permission bypass by adding a permission check for + FSCTL_SET_SPARSE + +From: Sean Shen + +[ Upstream commit cc57232cae23c0df91b4a59d0f519141ce9b5b02 ] + +FSCTL_SET_SPARSE in fsctl_set_sparse() modifies the file's sparse +attribute and saves it through xattr without any permission checks. + +This exposes two issues: + +1) A client on a read-only share can change the sparse attribute + on files it opened, even though the share is read-only. + Other FSCTL write operations already check + test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE), + but FSCTL_SET_SPARSE does not. + +2) Even on writable shares, clients without FILE_WRITE_DATA or + FILE_WRITE_ATTRIBUTES access should not modify the sparse + attribute. Similar handle-level checks exist in other functions + but are missing here. + +Add both share-level writable check and per-handle access check. +Use goto out on error to avoid leaking file references. + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: Namjae Jeon +Cc: Sergey Senozhatsky +Cc: Steve French +Signed-off-by: Sean Shen +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index da7b96707186e4..4689aac12c14ea 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -8203,9 +8203,20 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id, + int ret = 0; + __le32 old_fattr; + ++ if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { ++ ksmbd_debug(SMB, "User does not have write permission\n"); ++ return -EACCES; ++ } ++ + fp = ksmbd_lookup_fd_fast(work, id); + if (!fp) + return -ENOENT; ++ ++ if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_WRITE_ATTRIBUTES_LE))) { ++ ret = -EACCES; ++ goto out; ++ } ++ + idmap = file_mnt_idmap(fp->filp); + + old_fattr = fp->f_ci->m_fattr; +-- +2.53.0 + diff --git a/queue-6.18/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch b/queue-6.18/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch new file mode 100644 index 0000000000..7aa9feac5e --- /dev/null +++ b/queue-6.18/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch @@ -0,0 +1,110 @@ +From e3871ffbce2816ef17cf496c755149431883c879 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 10:48:54 +0200 +Subject: kunit: fix use-after-free in debugfs when using kunit.filter + +From: Florian Schmaus + +[ Upstream commit fb6988b83b4cafe8db63999c1ddff1b7c66d2ff5 ] + +When the kernel is booted with a kunit filter (e.g., +kunit.filter="speed!=slow"), the kunit executor dynamically allocates +copies of the filtered test suites using kmalloc/kmemdup. + +During the initial boot execution, kunit_debugfs_create_suite() creates +debugfs files (such as /sys/kernel/debug/kunit//run) and +permanently stores a pointer to the dynamically allocated suite in the +inode's i_private field. + +Previously, the executor freed this dynamically allocated suite_set +immediately after executing the boot-time tests. Because the debugfs +nodes were not destroyed, any subsequent interaction with the debugfs +`run` file from userspace triggered a use-after-free (UAF). On systems +with architectural capabilities, like CHERI RISC-V, this resulted in +an immediate fatal hardware exception due to the invalidation of the +capability tags on the reclaimed memory. On other architectures, it +resulted in silent memory corruption. + +Fix this UAF by properly coupling the lifetime of the filtered suite +memory allocation to the lifetime of the kunit subsystem and its +associated VFS nodes. Ownership of the boot-time suite_set is now +transferred to a global tracker ('kunit_boot_suites'), and the memory +is cleanly released in kunit_exit() during module teardown. + +Link: https://lore.kernel.org/r/20260507084854.233984-1-florian.schmaus@codasip.com +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: Florian Schmaus +Reviewed-by: Martin Kaiser +Reviewed-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + include/kunit/test.h | 1 + + lib/kunit/executor.c | 19 ++++++++++++++++--- + lib/kunit/test.c | 1 + + 3 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/include/kunit/test.h b/include/kunit/test.h +index 5ec5182b5e5751..aedffe2f2d49de 100644 +--- a/include/kunit/test.h ++++ b/include/kunit/test.h +@@ -613,6 +613,7 @@ unsigned long kunit_vm_mmap(struct kunit *test, struct file *file, + unsigned long offset); + + void kunit_cleanup(struct kunit *test); ++void kunit_free_boot_suites(void); + + void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...); + +diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c +index 0061d4c7e35170..9abaed8275845f 100644 +--- a/lib/kunit/executor.c ++++ b/lib/kunit/executor.c +@@ -15,6 +15,16 @@ extern struct kunit_suite * const __kunit_suites_end[]; + extern struct kunit_suite * const __kunit_init_suites_start[]; + extern struct kunit_suite * const __kunit_init_suites_end[]; + ++static struct kunit_suite_set kunit_boot_suites; ++ ++void kunit_free_boot_suites(void) ++{ ++ if (kunit_boot_suites.start) { ++ kunit_free_suite_set(kunit_boot_suites); ++ kunit_boot_suites = (struct kunit_suite_set){ NULL, NULL }; ++ } ++} ++ + static char *action_param; + + module_param_named(action, action_param, charp, 0400); +@@ -409,9 +419,12 @@ int kunit_run_all_tests(void) + pr_err("kunit executor: unknown action '%s'\n", action_param); + + free_out: +- if (filter_glob_param || filter_param) +- kunit_free_suite_set(suite_set); +- else if (init_num_suites > 0) ++ if (filter_glob_param || filter_param) { ++ if (err) ++ kunit_free_suite_set(suite_set); ++ else ++ kunit_boot_suites = suite_set; ++ } else if (init_num_suites > 0) + /* Don't use kunit_free_suite_set because suites aren't individually allocated */ + kfree(suite_set.start); + +diff --git a/lib/kunit/test.c b/lib/kunit/test.c +index 62eb529824c657..f0e1e02a98d8b3 100644 +--- a/lib/kunit/test.c ++++ b/lib/kunit/test.c +@@ -1056,6 +1056,7 @@ static void __exit kunit_exit(void) + kunit_bus_shutdown(); + + kunit_debugfs_cleanup(); ++ kunit_free_boot_suites(); + } + module_exit(kunit_exit); + +-- +2.53.0 + diff --git a/queue-6.18/media-rc-fix-race-between-unregister-and-urb-irq-cal.patch b/queue-6.18/media-rc-fix-race-between-unregister-and-urb-irq-cal.patch new file mode 100644 index 0000000000..31dbbacba4 --- /dev/null +++ b/queue-6.18/media-rc-fix-race-between-unregister-and-urb-irq-cal.patch @@ -0,0 +1,759 @@ +From e24b727294a59bbfbac7217b908b6364663d1f79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 10:33:26 +0000 +Subject: media: rc: fix race between unregister and urb/irq callbacks + +From: Sean Young + +[ Upstream commit dccc0c3ddf8f16071736f98a7d6dd46a2d43e037 ] + +Some rc device drivers have a race condition between rc_unregister_device() +and irq or urb callbacks. This is because rc_unregister_device() does two +things, it marks the device as unregistered so no new commands can be +issued and then it calls rc_free_device(). This means the driver has no +chance to cancel any pending urb callbacks or interrupts after the device +has been marked as unregistered. Those callbacks may access struct rc_dev +or its members (e.g. struct ir_raw_event_ctrl), which have been freed by +rc_free_device(). + +This change removes the implicit call to rc_free_device() from +rc_unregister_device(). This means that device drivers can call +rc_unregister_device() in their remove or disconnect function, then cancel +all the urbs and interrupts before explicitly calling rc_free_device(). + +Note this is an alternative fix for an issue found by Haotian Zhang, see +the Closes: tags. + +Reported-by: Haotian Zhang +Closes: https://lore.kernel.org/linux-media/20251114101432.2566-1-vulab@iscas.ac.cn/ +Closes: https://lore.kernel.org/linux-media/20251114101418.2548-1-vulab@iscas.ac.cn/ +Closes: https://lore.kernel.org/linux-media/20251114101346.2530-1-vulab@iscas.ac.cn/ +Closes: https://lore.kernel.org/linux-media/20251114090605.2413-1-vulab@iscas.ac.cn/ +Reviewed-by: Patrice Chotard +Signed-off-by: Sean Young +Signed-off-by: Hans Verkuil +Stable-dep-of: 646ebdd31058 ("media: rc: ttusbir: fix inverted error logic") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/sil-sii8620.c | 1 + + drivers/hid/hid-picolcd_cir.c | 1 + + drivers/media/cec/core/cec-core.c | 2 +- + drivers/media/common/siano/smsir.c | 1 + + drivers/media/i2c/ir-kbd-i2c.c | 2 ++ + drivers/media/pci/bt8xx/bttv-input.c | 3 ++- + drivers/media/pci/cx23885/cx23885-input.c | 1 + + drivers/media/pci/cx88/cx88-input.c | 3 ++- + drivers/media/pci/dm1105/dm1105.c | 1 + + drivers/media/pci/mantis/mantis_input.c | 1 + + drivers/media/pci/saa7134/saa7134-input.c | 1 + + drivers/media/pci/smipcie/smipcie-ir.c | 1 + + drivers/media/pci/ttpci/budget-ci.c | 1 + + drivers/media/rc/ati_remote.c | 6 +++--- + drivers/media/rc/ene_ir.c | 2 +- + drivers/media/rc/fintek-cir.c | 3 ++- + drivers/media/rc/igorplugusb.c | 1 + + drivers/media/rc/iguanair.c | 1 + + drivers/media/rc/img-ir/img-ir-hw.c | 3 ++- + drivers/media/rc/img-ir/img-ir-raw.c | 3 ++- + drivers/media/rc/imon.c | 3 ++- + drivers/media/rc/ir-hix5hd2.c | 2 +- + drivers/media/rc/ir_toy.c | 1 + + drivers/media/rc/ite-cir.c | 2 +- + drivers/media/rc/mceusb.c | 1 + + drivers/media/rc/rc-ir-raw.c | 5 ----- + drivers/media/rc/rc-loopback.c | 1 + + drivers/media/rc/rc-main.c | 6 +----- + drivers/media/rc/redrat3.c | 4 +++- + drivers/media/rc/st_rc.c | 2 +- + drivers/media/rc/streamzap.c | 7 ++++--- + drivers/media/rc/sunxi-cir.c | 1 + + drivers/media/rc/ttusbir.c | 2 +- + drivers/media/rc/winbond-cir.c | 2 +- + drivers/media/rc/xbox_remote.c | 5 +++-- + drivers/media/usb/au0828/au0828-input.c | 1 + + drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 1 + + drivers/media/usb/dvb-usb/dvb-usb-remote.c | 6 ++++-- + drivers/media/usb/em28xx/em28xx-input.c | 1 + + drivers/staging/media/av7110/av7110_ir.c | 1 + + include/media/rc-core.h | 2 -- + 41 files changed, 58 insertions(+), 36 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c +index 9e48ad39e1cc99..923e2ed30624b7 100644 +--- a/drivers/gpu/drm/bridge/sil-sii8620.c ++++ b/drivers/gpu/drm/bridge/sil-sii8620.c +@@ -2221,6 +2221,7 @@ static void sii8620_detach(struct drm_bridge *bridge) + return; + + rc_unregister_device(ctx->rc_dev); ++ rc_free_device(ctx->rc_dev); + } + + static int sii8620_is_packing_required(struct sii8620 *ctx, +diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c +index d6faa0e00f95ac..6d4c636e1c9f7e 100644 +--- a/drivers/hid/hid-picolcd_cir.c ++++ b/drivers/hid/hid-picolcd_cir.c +@@ -134,5 +134,6 @@ void picolcd_exit_cir(struct picolcd_data *data) + + data->rc_dev = NULL; + rc_unregister_device(rdev); ++ rc_free_device(rdev); + } + +diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c +index dd6e24a0899bda..1b8a33c05b3c92 100644 +--- a/drivers/media/cec/core/cec-core.c ++++ b/drivers/media/cec/core/cec-core.c +@@ -338,8 +338,8 @@ int cec_register_adapter(struct cec_adapter *adap, + res = cec_devnode_register(&adap->devnode, adap->owner); + if (res) { + #ifdef CONFIG_MEDIA_CEC_RC +- /* Note: rc_unregister also calls rc_free */ + rc_unregister_device(adap->rc); ++ rc_free_device(adap->rc); + adap->rc = NULL; + #endif + return res; +diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c +index d85c78c104b990..5f4c0aa7a0d72a 100644 +--- a/drivers/media/common/siano/smsir.c ++++ b/drivers/media/common/siano/smsir.c +@@ -92,6 +92,7 @@ int sms_ir_init(struct smscore_device_t *coredev) + void sms_ir_exit(struct smscore_device_t *coredev) + { + rc_unregister_device(coredev->ir.dev); ++ rc_free_device(coredev->ir.dev); + + pr_debug("\n"); + } +diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c +index 5588cdd7ec20de..60474531700433 100644 +--- a/drivers/media/i2c/ir-kbd-i2c.c ++++ b/drivers/media/i2c/ir-kbd-i2c.c +@@ -355,6 +355,7 @@ static void ir_work(struct work_struct *work) + mutex_unlock(&ir->lock); + if (rc == -ENODEV) { + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + ir->rc = NULL; + return; + } +@@ -972,6 +973,7 @@ static void ir_remove(struct i2c_client *client) + i2c_unregister_device(ir->tx_c); + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + } + + static const struct i2c_device_id ir_kbd_id[] = { +diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c +index 84aa269248fd36..f84fcf96eca983 100644 +--- a/drivers/media/pci/bt8xx/bttv-input.c ++++ b/drivers/media/pci/bt8xx/bttv-input.c +@@ -572,8 +572,9 @@ void bttv_input_fini(struct bttv *btv) + if (btv->remote == NULL) + return; + +- bttv_ir_stop(btv); + rc_unregister_device(btv->remote->dev); ++ bttv_ir_stop(btv); ++ rc_free_device(btv->remote->dev); + kfree(btv->remote); + btv->remote = NULL; + } +diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c +index d2e84c6457e0ab..722329ef3fd2cc 100644 +--- a/drivers/media/pci/cx23885/cx23885-input.c ++++ b/drivers/media/pci/cx23885/cx23885-input.c +@@ -402,6 +402,7 @@ void cx23885_input_fini(struct cx23885_dev *dev) + if (dev->kernel_ir == NULL) + return; + rc_unregister_device(dev->kernel_ir->rc); ++ rc_free_device(dev->kernel_ir->rc); + kfree(dev->kernel_ir->phys); + kfree(dev->kernel_ir->name); + kfree(dev->kernel_ir); +diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c +index b9f2c14d62b408..4757787c3f5935 100644 +--- a/drivers/media/pci/cx88/cx88-input.c ++++ b/drivers/media/pci/cx88/cx88-input.c +@@ -509,8 +509,9 @@ int cx88_ir_fini(struct cx88_core *core) + if (!ir) + return 0; + +- cx88_ir_stop(core); + rc_unregister_device(ir->dev); ++ cx88_ir_stop(core); ++ rc_free_device(ir->dev); + kfree(ir); + + /* done */ +diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c +index 9e9c7c071accce..e1185aa669f480 100644 +--- a/drivers/media/pci/dm1105/dm1105.c ++++ b/drivers/media/pci/dm1105/dm1105.c +@@ -763,6 +763,7 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105) + static void dm1105_ir_exit(struct dm1105_dev *dm1105) + { + rc_unregister_device(dm1105->ir.dev); ++ rc_free_device(dm1105->ir.dev); + } + + static int dm1105_hw_init(struct dm1105_dev *dev) +diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c +index 34c0d979240fda..edb4cacf55d229 100644 +--- a/drivers/media/pci/mantis/mantis_input.c ++++ b/drivers/media/pci/mantis/mantis_input.c +@@ -72,5 +72,6 @@ EXPORT_SYMBOL_GPL(mantis_input_init); + void mantis_input_exit(struct mantis_pci *mantis) + { + rc_unregister_device(mantis->rc); ++ rc_free_device(mantis->rc); + } + EXPORT_SYMBOL_GPL(mantis_input_exit); +diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c +index 468dbe8d552f82..d39537c95d9d3b 100644 +--- a/drivers/media/pci/saa7134/saa7134-input.c ++++ b/drivers/media/pci/saa7134/saa7134-input.c +@@ -834,6 +834,7 @@ void saa7134_input_fini(struct saa7134_dev *dev) + return; + + rc_unregister_device(dev->remote->dev); ++ rc_free_device(dev->remote->dev); + kfree(dev->remote); + dev->remote = NULL; + } +diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c +index c0604d9c70119a..0bbe4fa2d5a84e 100644 +--- a/drivers/media/pci/smipcie/smipcie-ir.c ++++ b/drivers/media/pci/smipcie/smipcie-ir.c +@@ -181,5 +181,6 @@ void smi_ir_exit(struct smi_dev *dev) + + rc_unregister_device(rc_dev); + smi_ir_stop(ir); ++ rc_free_device(rc_dev); + ir->rc_dev = NULL; + } +diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c +index 33f08adf4feb10..16973ac8e6a920 100644 +--- a/drivers/media/pci/ttpci/budget-ci.c ++++ b/drivers/media/pci/ttpci/budget-ci.c +@@ -249,6 +249,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) + cancel_work_sync(&budget_ci->ir.msp430_irq_bh_work); + + rc_unregister_device(budget_ci->ir.dev); ++ rc_free_device(budget_ci->ir.dev); + } + + static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c +index a733914a257424..f1fd4765651cac 100644 +--- a/drivers/media/rc/ati_remote.c ++++ b/drivers/media/rc/ati_remote.c +@@ -921,7 +921,6 @@ static int ati_remote_probe(struct usb_interface *interface, + input_free_device(input_dev); + exit_unregister_device: + rc_unregister_device(rc_dev); +- rc_dev = NULL; + exit_kill_urbs: + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); +@@ -941,18 +940,19 @@ static void ati_remote_disconnect(struct usb_interface *interface) + struct ati_remote *ati_remote; + + ati_remote = usb_get_intfdata(interface); +- usb_set_intfdata(interface, NULL); + if (!ati_remote) { + dev_warn(&interface->dev, "%s - null device?\n", __func__); + return; + } + ++ rc_unregister_device(ati_remote->rdev); ++ usb_set_intfdata(interface, NULL); + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + if (ati_remote->idev) + input_unregister_device(ati_remote->idev); +- rc_unregister_device(ati_remote->rdev); + ati_remote_free_buffers(ati_remote); ++ rc_free_device(ati_remote->rdev); + kfree(ati_remote); + } + +diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c +index d6c54a3bccc26d..136fc4192265da 100644 +--- a/drivers/media/rc/ene_ir.c ++++ b/drivers/media/rc/ene_ir.c +@@ -1090,7 +1090,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) + release_region(dev->hw_io, ENE_IO_SIZE); + exit_unregister_device: + rc_unregister_device(rdev); +- rdev = NULL; + exit_free_dev_rdev: + rc_free_device(rdev); + kfree(dev); +@@ -1110,6 +1109,7 @@ static void ene_remove(struct pnp_dev *pnp_dev) + ene_rx_restore_hw_buffer(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + ++ rc_free_device(dev->rdev); + free_irq(dev->irq, dev); + release_region(dev->hw_io, ENE_IO_SIZE); + kfree(dev); +diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c +index 3fb0968efd57d3..9b789097cdd4c3 100644 +--- a/drivers/media/rc/fintek-cir.c ++++ b/drivers/media/rc/fintek-cir.c +@@ -568,6 +568,7 @@ static void fintek_remove(struct pnp_dev *pdev) + struct fintek_dev *fintek = pnp_get_drvdata(pdev); + unsigned long flags; + ++ rc_unregister_device(fintek->rdev); + spin_lock_irqsave(&fintek->fintek_lock, flags); + /* disable CIR */ + fintek_disable_cir(fintek); +@@ -580,7 +581,7 @@ static void fintek_remove(struct pnp_dev *pdev) + free_irq(fintek->cir_irq, fintek); + release_region(fintek->cir_addr, fintek->cir_port_len); + +- rc_unregister_device(fintek->rdev); ++ rc_free_device(fintek->rdev); + + kfree(fintek); + } +diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c +index e7e31776453c11..439f95e6879fc4 100644 +--- a/drivers/media/rc/igorplugusb.c ++++ b/drivers/media/rc/igorplugusb.c +@@ -247,6 +247,7 @@ static void igorplugusb_disconnect(struct usb_interface *intf) + usb_set_intfdata(intf, NULL); + usb_unpoison_urb(ir->urb); + usb_free_urb(ir->urb); ++ rc_free_device(ir->rc); + kfree(ir->buf_in); + kfree(ir->request); + } +diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c +index 8af94246e5916e..7bd6dd7254157a 100644 +--- a/drivers/media/rc/iguanair.c ++++ b/drivers/media/rc/iguanair.c +@@ -500,6 +500,7 @@ static void iguanair_disconnect(struct usb_interface *intf) + usb_set_intfdata(intf, NULL); + usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); ++ rc_free_device(ir->rc); + usb_free_urb(ir->urb_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); +diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c +index 63f6f5b36838d0..f30adf4d8444dd 100644 +--- a/drivers/media/rc/img-ir/img-ir-hw.c ++++ b/drivers/media/rc/img-ir/img-ir-hw.c +@@ -1118,9 +1118,10 @@ void img_ir_remove_hw(struct img_ir_priv *priv) + struct rc_dev *rdev = hw->rdev; + if (!rdev) + return; ++ rc_unregister_device(rdev); + img_ir_set_decoder(priv, NULL, 0); + hw->rdev = NULL; +- rc_unregister_device(rdev); ++ rc_free_device(rdev); + #ifdef CONFIG_COMMON_CLK + if (!IS_ERR(priv->clk)) + clk_notifier_unregister(priv->clk, &hw->clk_nb); +diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c +index 92fb7b555a0f65..f1460d4acf3e8a 100644 +--- a/drivers/media/rc/img-ir/img-ir-raw.c ++++ b/drivers/media/rc/img-ir/img-ir-raw.c +@@ -136,6 +136,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv) + if (!rdev) + return; + ++ rc_unregister_device(rdev); + /* switch off and disable raw (edge) interrupts */ + spin_lock_irq(&priv->lock); + raw->rdev = NULL; +@@ -145,7 +146,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv) + img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE); + spin_unlock_irq(&priv->lock); + +- rc_unregister_device(rdev); ++ rc_free_device(rdev); + + timer_delete_sync(&raw->timer); + } +diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c +index 35b9e07003d889..48534bb52e4d04 100644 +--- a/drivers/media/rc/imon.c ++++ b/drivers/media/rc/imon.c +@@ -2541,9 +2541,10 @@ static void imon_disconnect(struct usb_interface *interface) + + if (ifnum == 0) { + ictx->dev_present_intf0 = false; ++ rc_unregister_device(ictx->rdev); + usb_kill_urb(ictx->rx_urb_intf0); + input_unregister_device(ictx->idev); +- rc_unregister_device(ictx->rdev); ++ rc_free_device(ictx->rdev); + if (ictx->display_supported) { + if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) + usb_deregister_dev(interface, &imon_lcd_class); +diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c +index afd80d2350c6d3..bb0f95833df57e 100644 +--- a/drivers/media/rc/ir-hix5hd2.c ++++ b/drivers/media/rc/ir-hix5hd2.c +@@ -331,7 +331,6 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) + + regerr: + rc_unregister_device(rdev); +- rdev = NULL; + clkerr: + clk_disable_unprepare(priv->clock); + err: +@@ -346,6 +345,7 @@ static void hix5hd2_ir_remove(struct platform_device *pdev) + + clk_disable_unprepare(priv->clock); + rc_unregister_device(priv->rdev); ++ rc_free_device(priv->rdev); + } + + #ifdef CONFIG_PM_SLEEP +diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c +index 533faa11751744..e79de56997a426 100644 +--- a/drivers/media/rc/ir_toy.c ++++ b/drivers/media/rc/ir_toy.c +@@ -536,6 +536,7 @@ static void irtoy_disconnect(struct usb_interface *intf) + usb_free_urb(ir->urb_out); + usb_kill_urb(ir->urb_in); + usb_free_urb(ir->urb_in); ++ rc_free_device(ir->rc); + kfree(ir->in); + kfree(ir->out); + kfree(ir); +diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c +index 2bacecb022623e..23afbafb557488 100644 +--- a/drivers/media/rc/ite-cir.c ++++ b/drivers/media/rc/ite-cir.c +@@ -1414,7 +1414,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id + release_region(itdev->cir_addr, itdev->params->io_region_size); + exit_unregister_device: + rc_unregister_device(rdev); +- rdev = NULL; + exit_free_dev_rdev: + rc_free_device(rdev); + kfree(itdev); +@@ -1439,6 +1438,7 @@ static void ite_remove(struct pnp_dev *pdev) + release_region(dev->cir_addr, dev->params->io_region_size); + + rc_unregister_device(dev->rdev); ++ rc_free_device(dev->rdev); + + kfree(dev); + } +diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c +index 044767eb3a38c9..a4c94fdf767ca1 100644 +--- a/drivers/media/rc/mceusb.c ++++ b/drivers/media/rc/mceusb.c +@@ -1850,6 +1850,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf) + usb_free_urb(ir->urb_in); + usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); + usb_put_dev(dev); ++ rc_free_device(ir->rc); + + kfree(ir); + } +diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c +index 5dafe11f61c6b1..76c3d1307f9f1b 100644 +--- a/drivers/media/rc/rc-ir-raw.c ++++ b/drivers/media/rc/rc-ir-raw.c +@@ -648,9 +648,6 @@ int ir_raw_event_register(struct rc_dev *dev) + + void ir_raw_event_free(struct rc_dev *dev) + { +- if (!dev) +- return; +- + kfree(dev->raw); + dev->raw = NULL; + } +@@ -674,8 +671,6 @@ void ir_raw_event_unregister(struct rc_dev *dev) + + lirc_bpf_free(dev); + +- ir_raw_event_free(dev); +- + /* + * A user can be calling bpf(BPF_PROG_{QUERY|ATTACH|DETACH}), so + * ensure that the raw member is null on unlock; this is how +diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c +index 8288366f891fc9..a108b057b5fd56 100644 +--- a/drivers/media/rc/rc-loopback.c ++++ b/drivers/media/rc/rc-loopback.c +@@ -263,6 +263,7 @@ static int __init loop_init(void) + static void __exit loop_exit(void) + { + rc_unregister_device(loopdev.dev); ++ rc_free_device(loopdev.dev); + } + + module_init(loop_init); +diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c +index b9bf5cdcde4ae3..6bdf32cb4a17d8 100644 +--- a/drivers/media/rc/rc-main.c ++++ b/drivers/media/rc/rc-main.c +@@ -1611,6 +1611,7 @@ static void rc_dev_release(struct device *device) + { + struct rc_dev *dev = to_rc_dev(device); + ++ ir_raw_event_free(dev); + kfree(dev); + } + +@@ -1773,7 +1774,6 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev, + } + + rc->dev.parent = dev; +- rc->managed_alloc = true; + *dr = rc; + devres_add(dev, dr); + +@@ -2042,11 +2042,7 @@ void rc_unregister_device(struct rc_dev *dev) + device_del(&dev->dev); + + ida_free(&rc_ida, dev->minor); +- +- if (!dev->managed_alloc) +- rc_free_device(dev); + } +- + EXPORT_SYMBOL_GPL(rc_unregister_device); + + /* +diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c +index a49173f54a4d0e..b8289327f6a206 100644 +--- a/drivers/media/rc/redrat3.c ++++ b/drivers/media/rc/redrat3.c +@@ -1133,11 +1133,13 @@ static void redrat3_dev_disconnect(struct usb_interface *intf) + { + struct usb_device *udev = interface_to_usbdev(intf); + struct redrat3_dev *rr3 = usb_get_intfdata(intf); ++ struct rc_dev *rc = rr3->rc; + + usb_set_intfdata(intf, NULL); +- rc_unregister_device(rr3->rc); ++ rc_unregister_device(rc); + led_classdev_unregister(&rr3->led); + redrat3_delete(rr3, udev); ++ rc_free_device(rc); + } + + static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) +diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c +index 6b70bac5f45d6c..0ba06bfc9e14b6 100644 +--- a/drivers/media/rc/st_rc.c ++++ b/drivers/media/rc/st_rc.c +@@ -203,6 +203,7 @@ static void st_rc_remove(struct platform_device *pdev) + device_init_wakeup(&pdev->dev, false); + clk_disable_unprepare(rc_dev->sys_clock); + rc_unregister_device(rc_dev->rdev); ++ rc_free_device(rc_dev->rdev); + } + + static int st_rc_open(struct rc_dev *rdev) +@@ -334,7 +335,6 @@ static int st_rc_probe(struct platform_device *pdev) + return ret; + rcerr: + rc_unregister_device(rdev); +- rdev = NULL; + clkerr: + clk_disable_unprepare(rc_dev->sys_clock); + err: +diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c +index 8e9b156e430022..8c85b9f30a3a96 100644 +--- a/drivers/media/rc/streamzap.c ++++ b/drivers/media/rc/streamzap.c +@@ -392,15 +392,16 @@ static void streamzap_disconnect(struct usb_interface *interface) + struct streamzap_ir *sz = usb_get_intfdata(interface); + struct usb_device *usbdev = interface_to_usbdev(interface); + +- usb_set_intfdata(interface, NULL); +- + if (!sz) + return; + +- usb_kill_urb(sz->urb_in); + rc_unregister_device(sz->rdev); ++ usb_set_intfdata(interface, NULL); ++ ++ usb_kill_urb(sz->urb_in); + usb_free_urb(sz->urb_in); + usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in); ++ rc_free_device(sz->rdev); + + kfree(sz); + } +diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c +index 92ef4e7c6f69fc..cb4c56bf0752a8 100644 +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -371,6 +371,7 @@ static void sunxi_ir_remove(struct platform_device *pdev) + struct sunxi_ir *ir = platform_get_drvdata(pdev); + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + sunxi_ir_hw_exit(&pdev->dev); + } + +diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c +index dde446a95eaa93..a670d4b008cb0d 100644 +--- a/drivers/media/rc/ttusbir.c ++++ b/drivers/media/rc/ttusbir.c +@@ -336,7 +336,6 @@ static int ttusbir_probe(struct usb_interface *intf, + return 0; + out3: + rc_unregister_device(rc); +- rc = NULL; + out2: + led_classdev_unregister(&tt->led); + out: +@@ -378,6 +377,7 @@ static void ttusbir_disconnect(struct usb_interface *intf) + usb_kill_urb(tt->bulk_urb); + usb_free_urb(tt->bulk_urb); + kfree(tt->bulk_buffer); ++ rc_free_device(tt->rc); + usb_set_intfdata(intf, NULL); + kfree(tt); + } +diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c +index 25884a79985c8a..14d8b58e283980 100644 +--- a/drivers/media/rc/winbond-cir.c ++++ b/drivers/media/rc/winbond-cir.c +@@ -1132,7 +1132,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) + release_region(data->wbase, WAKEUP_IOMEM_LEN); + exit_unregister_device: + rc_unregister_device(data->dev); +- data->dev = NULL; + exit_free_rc: + rc_free_device(data->dev); + exit_unregister_led: +@@ -1163,6 +1162,7 @@ wbcir_remove(struct pnp_dev *device) + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); + + rc_unregister_device(data->dev); ++ rc_free_device(data->dev); + + led_classdev_unregister(&data->led); + +diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c +index 0c9c855ced729c..80b7c247932a8f 100644 +--- a/drivers/media/rc/xbox_remote.c ++++ b/drivers/media/rc/xbox_remote.c +@@ -283,14 +283,15 @@ static void xbox_remote_disconnect(struct usb_interface *interface) + struct xbox_remote *xbox_remote; + + xbox_remote = usb_get_intfdata(interface); +- usb_set_intfdata(interface, NULL); + if (!xbox_remote) { + dev_warn(&interface->dev, "%s - null device?\n", __func__); + return; + } + +- usb_kill_urb(xbox_remote->irq_urb); + rc_unregister_device(xbox_remote->rdev); ++ usb_set_intfdata(interface, NULL); ++ usb_kill_urb(xbox_remote->irq_urb); ++ rc_free_device(xbox_remote->rdev); + usb_free_urb(xbox_remote->irq_urb); + kfree(xbox_remote->inbuf); + kfree(xbox_remote); +diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c +index 3d3368202cd018..283ad2c6288cd5 100644 +--- a/drivers/media/usb/au0828/au0828-input.c ++++ b/drivers/media/usb/au0828/au0828-input.c +@@ -357,6 +357,7 @@ void au0828_rc_unregister(struct au0828_dev *dev) + return; + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + + /* done */ + kfree(ir); +diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +index f1c79f351ec8de..17e8961179d14b 100644 +--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c ++++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +@@ -187,6 +187,7 @@ static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) + if (d->rc_dev) { + cancel_delayed_work_sync(&d->rc_query_work); + rc_unregister_device(d->rc_dev); ++ rc_free_device(d->rc_dev); + d->rc_dev = NULL; + } + +diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c +index 65e2c9e2cdc99f..6dc11718dfb985 100644 +--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c ++++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c +@@ -347,10 +347,12 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d) + { + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_delayed_work_sync(&d->rc_query_work); +- if (d->props.rc.mode == DVB_RC_LEGACY) ++ if (d->props.rc.mode == DVB_RC_LEGACY) { + input_unregister_device(d->input_dev); +- else ++ } else { + rc_unregister_device(d->rc_dev); ++ rc_free_device(d->rc_dev); ++ } + } + d->state &= ~DVB_USB_STATE_REMOTE; + return 0; +diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c +index 5f3b00869bdbc9..26f333b5be7325 100644 +--- a/drivers/media/usb/em28xx/em28xx-input.c ++++ b/drivers/media/usb/em28xx/em28xx-input.c +@@ -853,6 +853,7 @@ static int em28xx_ir_fini(struct em28xx *dev) + goto ref_put; + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + + kfree(ir->i2c_client); + +diff --git a/drivers/staging/media/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c +index 68b3979ba5f20c..fdae467fd7ab81 100644 +--- a/drivers/staging/media/av7110/av7110_ir.c ++++ b/drivers/staging/media/av7110/av7110_ir.c +@@ -151,6 +151,7 @@ int av7110_ir_init(struct av7110 *av7110) + void av7110_ir_exit(struct av7110 *av7110) + { + rc_unregister_device(av7110->ir.rcdev); ++ rc_free_device(av7110->ir.rcdev); + } + + //MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); +diff --git a/include/media/rc-core.h b/include/media/rc-core.h +index 35c7a0546f02ee..7c964b5ad79269 100644 +--- a/include/media/rc-core.h ++++ b/include/media/rc-core.h +@@ -81,7 +81,6 @@ struct lirc_fh { + /** + * struct rc_dev - represents a remote control device + * @dev: driver model's view of this device +- * @managed_alloc: devm_rc_allocate_device was used to create rc_dev + * @registered: set to true by rc_register_device(), false by + * rc_unregister_device + * @idle: used to keep track of RX state +@@ -156,7 +155,6 @@ struct lirc_fh { + */ + struct rc_dev { + struct device dev; +- bool managed_alloc; + bool registered; + bool idle; + bool encode_wakeup; +-- +2.53.0 + diff --git a/queue-6.18/media-rc-ttusbir-fix-inverted-error-logic.patch b/queue-6.18/media-rc-ttusbir-fix-inverted-error-logic.patch new file mode 100644 index 0000000000..fa14c30273 --- /dev/null +++ b/queue-6.18/media-rc-ttusbir-fix-inverted-error-logic.patch @@ -0,0 +1,38 @@ +From e5e5d46bac5151188892f4c7801d3276e3301b34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:03:09 +0200 +Subject: media: rc: ttusbir: fix inverted error logic + +From: Oliver Neukum + +[ Upstream commit 646ebdd3105809d84ed04aa9e92e47e89cc44502 ] + +We have to report ENOMEM if no buffer is allocated. +Typo dropped a "!". Restore it. + +Fixes: 50acaad3d202 ("media: rc: ttusbir: respect DMA coherency rules") +Cc: stable@vger.kernel.org +Signed-off-by: Oliver Neukum +Signed-off-by: Sean Young +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/rc/ttusbir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c +index a670d4b008cb0d..3452b5aefd2848 100644 +--- a/drivers/media/rc/ttusbir.c ++++ b/drivers/media/rc/ttusbir.c +@@ -191,7 +191,7 @@ static int ttusbir_probe(struct usb_interface *intf, + tt = kzalloc(sizeof(*tt), GFP_KERNEL); + buffer = kzalloc(5, GFP_KERNEL); + rc = rc_allocate_device(RC_DRIVER_IR_RAW); +- if (!tt || !rc || buffer) { ++ if (!tt || !rc || !buffer) { + ret = -ENOMEM; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.18/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch b/queue-6.18/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch new file mode 100644 index 0000000000..a0026fc45a --- /dev/null +++ b/queue-6.18/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch @@ -0,0 +1,102 @@ +From bda2bf3f5162bc1c99d8dd439ad2af1a37dcfec2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 14:06:40 +0200 +Subject: net: Avoid checksumming unreadable skb tail on trim +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Björn Töpel + +[ Upstream commit 2e357f002c61fd76fd8f12468744a06a5ec48eaa ] + +pskb_trim_rcsum_slow() keeps CHECKSUM_COMPLETE valid by subtracting +the checksum of the bytes removed from the skb tail. That assumes the +removed bytes can be read. + +io_uring zcrx skbs may contain unreadable net_iov frags. With fbnic +header/data split, small TCP/IPv4 packets can carry Ethernet padding +in such a frag. ip_rcv_core() trims the skb to iph->tot_len before TCP +sees it, and the CHECKSUM_COMPLETE adjustment then calls +skb_checksum() on the padding. + +This is exposed by IPv4 because small TCP/IPv4 frames can be shorter +than the Ethernet minimum payload. TCP/IPv6 frames are large enough in +the normal zcrx path, so they do not hit the same padding trim. + +Keep the existing checksum adjustment for readable skbs. If the +remaining packet is fully linear, drop CHECKSUM_COMPLETE and let the +stack validate the packet after trimming. If unreadable payload would +remain, fail the trim; the checksum cannot be adjusted without reading +the trimmed tail. + +Also clear skb->unreadable when trimming removes all frags. + +Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags") +Signed-off-by: Björn Töpel +Reviewed-by: Breno Leitao +Link: https://patch.msgid.link/20260522120643.242974-1-bjorn@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 31 +++++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index a8911f1b90c15d..6618bfa70ca444 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -2739,6 +2739,8 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) + skb->data_len = 0; + skb_set_tail_pointer(skb, len); + } ++ if (!skb_shinfo(skb)->nr_frags && !skb_has_frag_list(skb)) ++ skb->unreadable = 0; + + if (!skb->sk || skb->destructor == sock_edemux) + skb_condense(skb); +@@ -2746,16 +2748,37 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) + } + EXPORT_SYMBOL(___pskb_trim); + ++static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len) ++{ ++ int delta = skb->len - len; ++ ++ if (skb_frags_readable(skb)) { ++ skb->csum = csum_block_sub(skb->csum, ++ skb_checksum(skb, len, delta, 0), ++ len); ++ return 0; ++ } ++ ++ if (len > skb_headlen(skb)) ++ return -EFAULT; ++ ++ /* The trimmed bytes are unreadable, but the remaining packet can be ++ * checksummed by software after trimming. ++ */ ++ skb->ip_summed = CHECKSUM_NONE; ++ return 0; ++} ++ + /* Note : use pskb_trim_rcsum() instead of calling this directly + */ + int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len) + { + if (skb->ip_summed == CHECKSUM_COMPLETE) { +- int delta = skb->len - len; ++ int err; + +- skb->csum = csum_block_sub(skb->csum, +- skb_checksum(skb, len, delta, 0), +- len); ++ err = pskb_trim_rcsum_complete(skb, len); ++ if (err) ++ return err; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + int hdlen = (len > skb_headlen(skb)) ? skb_headlen(skb) : len; + int offset = skb_checksum_start_offset(skb) + skb->csum_offset; +-- +2.53.0 + diff --git a/queue-6.18/net-handshake-pass-negative-errno-through-handshake_.patch b/queue-6.18/net-handshake-pass-negative-errno-through-handshake_.patch new file mode 100644 index 0000000000..24c1fba77a --- /dev/null +++ b/queue-6.18/net-handshake-pass-negative-errno-through-handshake_.patch @@ -0,0 +1,212 @@ +From 47a42c35e7ae4c6e580abf2c6475186bb80bdaec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:17 -0400 +Subject: net/handshake: Pass negative errno through handshake_complete() + +From: Chuck Lever + +[ Upstream commit 6b22d433aa13f68e3cd9534ca9a5f4277bfa01c2 ] + +handshake_complete() declares status as unsigned int and +tls_handshake_done() negates that value (-status) before handing +it to the TLS consumer. Consumers match on negative errno +constants -- xs_tls_handshake_done() has + + switch (status) { + case 0: + case -EACCES: + case -ETIMEDOUT: + lower_transport->xprt_err = status; + break; + default: + lower_transport->xprt_err = -EACCES; + } + +so the API as designed expects callers to pass positive errno +values that the tlshd shim then negates. + +Three internal callers in handshake_nl_accept_doit(), the +net-exit drain, and a kunit test follow kernel convention and +pass negative errnos -- -EIO, -ETIMEDOUT, -ETIMEDOUT. The +implicit conversion to unsigned int turns -ETIMEDOUT into +0xFFFFFF92; the subsequent -status in tls_handshake_done() +wraps back to 110, the consumer's switch falls through, and +the xprt reports -EACCES on what should be -ETIMEDOUT or -EIO. + +Fix the API rather than the call sites. The natural kernel +convention is negative errno in, negative errno out. Change +handshake_complete() and hp_done to take int status, drop the +negation in tls_handshake_done(), and negate once in +handshake_nl_done_doit() where status arrives from the wire +as an unsigned netlink attribute. The three internal callers +were already correct under that convention and need no change. + +At the same wire boundary, declare MAX_ERRNO as the netlink +policy upper bound for HANDSHAKE_A_DONE_STATUS. Attribute +validation rejects out-of-range values before +handshake_nl_done_doit() runs, and negating a bounded u32 there +stays within int range -- closing the UBSAN-visible signed- +integer overflow that an unconstrained u32 would invoke. + +Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-3-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + Documentation/netlink/specs/handshake.yaml | 8 ++++++++ + net/handshake/genl.c | 3 ++- + net/handshake/genl.h | 1 + + net/handshake/handshake-test.c | 2 +- + net/handshake/handshake.h | 4 ++-- + net/handshake/netlink.c | 2 +- + net/handshake/request.c | 2 +- + net/handshake/tlshd.c | 4 ++-- + 8 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml +index 95c3fade7a8d7b..1024297b38513a 100644 +--- a/Documentation/netlink/specs/handshake.yaml ++++ b/Documentation/netlink/specs/handshake.yaml +@@ -12,6 +12,12 @@ protocol: genetlink + doc: Netlink protocol to request a transport layer security handshake. + + definitions: ++ - ++ type: const ++ name: max-errno ++ value: 4095 ++ header: linux/err.h ++ scope: kernel + - + type: enum + name: handler-class +@@ -80,6 +86,8 @@ attribute-sets: + - + name: status + type: u32 ++ checks: ++ max: max-errno + - + name: sockfd + type: s32 +diff --git a/net/handshake/genl.c b/net/handshake/genl.c +index f55d14d7b7269d..a5fa8b27f22423 100644 +--- a/net/handshake/genl.c ++++ b/net/handshake/genl.c +@@ -9,6 +9,7 @@ + #include "genl.h" + + #include ++#include + + /* HANDSHAKE_CMD_ACCEPT - do */ + static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HANDLER_CLASS + 1] = { +@@ -17,7 +18,7 @@ static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HAN + + /* HANDSHAKE_CMD_DONE - do */ + static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_REMOTE_AUTH + 1] = { +- [HANDSHAKE_A_DONE_STATUS] = { .type = NLA_U32, }, ++ [HANDSHAKE_A_DONE_STATUS] = NLA_POLICY_MAX(NLA_U32, MAX_ERRNO), + [HANDSHAKE_A_DONE_SOCKFD] = { .type = NLA_S32, }, + [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .type = NLA_U32, }, + }; +diff --git a/net/handshake/genl.h b/net/handshake/genl.h +index ae72a596f6cc3e..684e5fd684481b 100644 +--- a/net/handshake/genl.h ++++ b/net/handshake/genl.h +@@ -10,6 +10,7 @@ + #include + + #include ++#include + + int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info); + int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info); +diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c +index 55442b2f518afb..df3948e807a0fd 100644 +--- a/net/handshake/handshake-test.c ++++ b/net/handshake/handshake-test.c +@@ -25,7 +25,7 @@ static int test_accept_func(struct handshake_req *req, struct genl_info *info, + return 0; + } + +-static void test_done_func(struct handshake_req *req, unsigned int status, ++static void test_done_func(struct handshake_req *req, int status, + struct genl_info *info) + { + } +diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h +index a48163765a7a1d..2289b0e274f40a 100644 +--- a/net/handshake/handshake.h ++++ b/net/handshake/handshake.h +@@ -57,7 +57,7 @@ struct handshake_proto { + int (*hp_accept)(struct handshake_req *req, + struct genl_info *info, int fd); + void (*hp_done)(struct handshake_req *req, +- unsigned int status, ++ int status, + struct genl_info *info); + void (*hp_destroy)(struct handshake_req *req); + }; +@@ -86,7 +86,7 @@ struct handshake_req *handshake_req_hash_lookup(struct sock *sk); + struct handshake_req *handshake_req_next(struct handshake_net *hn, int class); + int handshake_req_submit(struct socket *sock, struct handshake_req *req, + gfp_t flags); +-void handshake_complete(struct handshake_req *req, unsigned int status, ++void handshake_complete(struct handshake_req *req, int status, + struct genl_info *info); + bool handshake_req_cancel(struct sock *sk); + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 394e270cc505cb..d8211e0ba75c69 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -161,7 +161,7 @@ int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info) + + status = -EIO; + if (info->attrs[HANDSHAKE_A_DONE_STATUS]) +- status = nla_get_u32(info->attrs[HANDSHAKE_A_DONE_STATUS]); ++ status = -(int)nla_get_u32(info->attrs[HANDSHAKE_A_DONE_STATUS]); + + handshake_complete(req, status, info); + sockfd_put(sock); +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 654e55b141cded..62efb7e32730ea 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -284,7 +284,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + } + EXPORT_SYMBOL(handshake_req_submit); + +-void handshake_complete(struct handshake_req *req, unsigned int status, ++void handshake_complete(struct handshake_req *req, int status, + struct genl_info *info) + { + struct sock *sk = req->hr_sk; +diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c +index af294c6cc71731..7567150c2a4f95 100644 +--- a/net/handshake/tlshd.c ++++ b/net/handshake/tlshd.c +@@ -93,7 +93,7 @@ static void tls_handshake_remote_peerids(struct tls_handshake_req *treq, + * + */ + static void tls_handshake_done(struct handshake_req *req, +- unsigned int status, struct genl_info *info) ++ int status, struct genl_info *info) + { + struct tls_handshake_req *treq = handshake_req_private(req); + +@@ -104,7 +104,7 @@ static void tls_handshake_done(struct handshake_req *req, + if (!status) + set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags); + +- treq->th_consumer_done(treq->th_consumer_data, -status, ++ treq->th_consumer_done(treq->th_consumer_data, status, + treq->th_peerid[0]); + } + +-- +2.53.0 + diff --git a/queue-6.18/net-handshake-use-spin_lock_bh-for-hn_lock.patch b/queue-6.18/net-handshake-use-spin_lock_bh-for-hn_lock.patch new file mode 100644 index 0000000000..1960985647 --- /dev/null +++ b/queue-6.18/net-handshake-use-spin_lock_bh-for-hn_lock.patch @@ -0,0 +1,138 @@ +From a33244e7d99f1609cfe06f3fe1cff7cf9163baaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:15 -0400 +Subject: net/handshake: Use spin_lock_bh for hn_lock + +From: Chuck Lever + +[ Upstream commit cc993e0927ec8bd98ea33377ada03295fcda0f24 ] + +nvmet_tcp_state_change(), a socket callback that runs in BH context, +can reach handshake_req_cancel() via nvmet_tcp_schedule_release_queue() +and tls_handshake_cancel(). handshake_req_cancel() acquires +hn->hn_lock with plain spin_lock(). If a process-context thread on +the same CPU holds hn->hn_lock when a softirq invokes the cancel path, +the lock attempt deadlocks. This is the only caller that invokes +tls_handshake_cancel() from BH context; every other consumer calls it +from process context. + +Deferring the cancel to process context in the NVMe target is not +straightforward: nvmet_tcp_schedule_release_queue() must call +tls_handshake_cancel() atomically with its state transition to +DISCONNECTING. If the cancel were deferred, the handshake completion +callback could fire in the window before the cancel runs, observe the +unexpected state, and return without dropping its kref on the queue. +Reworking that interlock is considerably more invasive than hardening +the handshake lock. Convert all hn->hn_lock acquisitions from +spin_lock/spin_unlock to spin_lock_bh/spin_unlock_bh so the lock is +never taken with softirqs enabled. + +Fixes: 675b453e0241 ("nvmet-tcp: enable TLS handshake upcall") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-1-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/handshake/netlink.c | 4 ++-- + net/handshake/request.c | 14 +++++++------- + net/handshake/tlshd.c | 2 ++ + 3 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 7e46d130dce2cd..394e270cc505cb 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -203,10 +203,10 @@ static void __net_exit handshake_net_exit(struct net *net) + * accepted and are in progress will be destroyed when + * the socket is closed. + */ +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + set_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags); + list_splice_init(&requests, &hn->hn_requests); +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + while (!list_empty(&requests)) { + req = list_first_entry(&requests, struct handshake_req, hr_list); +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 6b7e3e0bf3996e..654e55b141cded 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -167,12 +167,12 @@ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) + { + bool ret = false; + +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + if (!list_empty(&req->hr_list)) { + __remove_pending_locked(hn, req); + ret = true; + } +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + return ret; + } +@@ -182,7 +182,7 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + struct handshake_req *req, *pos; + + req = NULL; +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + list_for_each_entry(pos, &hn->hn_requests, hr_list) { + if (pos->hr_proto->hp_handler_class != class) + continue; +@@ -190,7 +190,7 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + req = pos; + break; + } +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + return req; + } +@@ -249,7 +249,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max) + goto out_err; + +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + ret = -EOPNOTSUPP; + if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags)) + goto out_unlock; +@@ -258,7 +258,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + goto out_unlock; + if (!__add_pending_locked(hn, req)) + goto out_unlock; +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + ret = handshake_genl_notify(net, req->hr_proto, flags); + if (ret) { +@@ -274,7 +274,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + return 0; + + out_unlock: +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + out_err: + /* Restore original destructor so socket teardown still runs on failure */ + req->hr_sk->sk_destruct = req->hr_odestruct; +diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c +index 8f9532a15f43f9..af294c6cc71731 100644 +--- a/net/handshake/tlshd.c ++++ b/net/handshake/tlshd.c +@@ -425,6 +425,8 @@ EXPORT_SYMBOL(tls_server_hello_psk); + * Request cancellation races with request completion. To determine + * who won, callers examine the return value from this function. + * ++ * Context: May be called from process or softirq context. ++ * + * Return values: + * %true - Uncompleted handshake request was canceled + * %false - Handshake request already completed or not found +-- +2.53.0 + diff --git a/queue-6.18/net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch b/queue-6.18/net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch new file mode 100644 index 0000000000..864c6b4296 --- /dev/null +++ b/queue-6.18/net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch @@ -0,0 +1,45 @@ +From 08e4faeb7394f9a82e7ab35363657b40585aa62d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 22:45:24 +0800 +Subject: net: hibmcge: disable Relaxed Ordering to fix RX packet corruption + +From: Jijie Shao + +[ Upstream commit 463a1271aa26eac992851b9d98cc75bc3cd4a1ed ] + +When SMMU is disabled, the hibmcge driver may receive corrupted packets. +The hardware writes packet data and descriptors to the same page, but +with Relaxed Ordering enabled, PCI write transactions may not be +strictly ordered. This can cause the driver to observe a valid +descriptor before the corresponding packet data is fully written. + +Fix this by clearing PCI_EXP_DEVCTL_RELAX_EN in the PCI bridge control +register to ensure strict write ordering between packet data and +descriptors. + +Fixes: f72e25594061 ("net: hibmcge: Implement rx_poll function to receive packets") +Signed-off-by: Jijie Shao +Link: https://patch.msgid.link/20260525144525.94884-2-shaojijie@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c +index 0b92a2e5e98694..cf0f14aa014cf8 100644 +--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c ++++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c +@@ -420,6 +420,9 @@ static int hbg_pci_init(struct pci_dev *pdev) + return -ENOMEM; + + pci_set_master(pdev); ++ pcie_capability_clear_word(pdev, PCI_EXP_DEVCTL, ++ PCI_EXP_DEVCTL_RELAX_EN); ++ pci_save_state(pdev); + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/net-hsr-fix-potential-oob-access-in-supervision-fram.patch b/queue-6.18/net-hsr-fix-potential-oob-access-in-supervision-fram.patch new file mode 100644 index 0000000000..2fbd29013a --- /dev/null +++ b/queue-6.18/net-hsr-fix-potential-oob-access-in-supervision-fram.patch @@ -0,0 +1,48 @@ +From 604a3e9565b3d1f5fa85fa3dc850e3c78eaad2a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 15:03:30 +0200 +Subject: net: hsr: fix potential OOB access in supervision frame handling + +From: Luka Gejak + +[ Upstream commit f229426072fc865654a60978bb7fda790a051ff3 ] + +Ensure the entire TLV header is linearized before access by adding +sizeof(struct hsr_sup_tlv) to the pskb_may_pull() calls. Without this, +a truncated frame could cause an out-of-bounds access. + +Fixes: eafaa88b3eb7 ("net: hsr: Add support for redbox supervision frames") +Signed-off-by: Luka Gejak +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260523130330.61880-1-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_forward.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c +index aefc9b6936ba0c..299de290ddaa5c 100644 +--- a/net/hsr/hsr_forward.c ++++ b/net/hsr/hsr_forward.c +@@ -84,7 +84,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* Get next tlv */ + total_length += hsr_sup_tag->tlv.HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + skb_pull(skb, total_length); + hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data; +@@ -100,7 +100,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* make sure another tlv follows */ + total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tlv->HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + + /* get next tlv */ +-- +2.53.0 + diff --git a/queue-6.18/net-iucv-fix-locking-in-.getsockopt.patch b/queue-6.18/net-iucv-fix-locking-in-.getsockopt.patch new file mode 100644 index 0000000000..118b4a5617 --- /dev/null +++ b/queue-6.18/net-iucv-fix-locking-in-.getsockopt.patch @@ -0,0 +1,87 @@ +From e443cb27cab1aad8c06f8c21ff977251de1d80fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 07:11:45 -0700 +Subject: net/iucv: fix locking in .getsockopt + +From: Breno Leitao + +[ Upstream commit 3589d20a666caf30ad100c960a2de7de390fce88 ] + +Mirror iucv_sock_setsockopt() and wrap the whole switch in +lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock +becomes redundant and is removed. + +Any AF_IUCV HIPER user can potentially crash the kernel by racing +recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences +iucv->hs_dev->mtu after iucv_sock_close() (called from the racing +recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference +oops. + +Suggested-by: Stanislav Fomichev +Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size") +Signed-off-by: Breno Leitao +Reviewed-by: Alexandra Winter +Tested-by: Alexandra Winter +Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/iucv/af_iucv.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index 6c717a7ef29283..c66b90c912e78e 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1538,7 +1538,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + unsigned int val; +- int len; ++ int len, rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; +@@ -1551,26 +1551,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + + len = min_t(unsigned int, len, sizeof(int)); + ++ rc = 0; ++ ++ lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: +- lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ +- release_sock(sk); + break; + case SO_MSGSIZE: +- if (sk->sk_state == IUCV_OPEN) +- return -EBADFD; ++ if (sk->sk_state == IUCV_OPEN) { ++ rc = -EBADFD; ++ break; ++ } + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; + default: +- return -ENOPROTOOPT; ++ rc = -ENOPROTOOPT; ++ break; + } ++ release_sock(sk); ++ ++ if (rc) ++ return rc; + + if (put_user(len, optlen)) + return -EFAULT; +-- +2.53.0 + diff --git a/queue-6.18/net-mana-add-null-guards-in-teardown-path-to-prevent.patch b/queue-6.18/net-mana-add-null-guards-in-teardown-path-to-prevent.patch new file mode 100644 index 0000000000..aef4a553f9 --- /dev/null +++ b/queue-6.18/net-mana-add-null-guards-in-teardown-path-to-prevent.patch @@ -0,0 +1,148 @@ +From e791dc5b86c87f00ea159d61e83c6bf69b468967 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 01:08:24 -0700 +Subject: net: mana: Add NULL guards in teardown path to prevent panic on + attach failure + +From: Dipayaan Roy + +[ Upstream commit 17bfe0a8c014ee1d542ad352cd6a0a505361664a ] + +When queue allocation fails partway through, the error cleanup frees +and NULLs apc->tx_qp and apc->rxqs. Multiple teardown paths such as +mana_remove(), mana_change_mtu() recovery, and internal error handling +in mana_alloc_queues() can subsequently call into functions that +dereference these pointers without NULL checks: + +- mana_chn_setxdp() dereferences apc->rxqs[0], causing a NULL pointer + dereference panic (CR2: 0000000000000000 at mana_chn_setxdp+0x26). +- mana_destroy_vport() iterates apc->rxqs without a NULL check. +- mana_fence_rqs() iterates apc->rxqs without a NULL check. +- mana_dealloc_queues() iterates apc->tx_qp without a NULL check. + +Add NULL guards for apc->rxqs in mana_fence_rqs(), +mana_destroy_vport(), and before the mana_chn_setxdp() call. Add a +NULL guard for apc->tx_qp in mana_dealloc_queues() to skip TX queue +draining when TX queues were never allocated or already freed. + +Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)") +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260525081129.1230035-2-dipayanroy@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 70 +++++++++++-------- + 1 file changed, 41 insertions(+), 29 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index d1eb77d540427d..6ef2a3ee44c6b0 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -1720,6 +1720,9 @@ static void mana_fence_rqs(struct mana_port_context *apc) + struct mana_rxq *rxq; + int err; + ++ if (!apc->rxqs) ++ return; ++ + for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { + rxq = apc->rxqs[rxq_idx]; + err = mana_fence_rq(apc, rxq); +@@ -2830,13 +2833,16 @@ static void mana_destroy_vport(struct mana_port_context *apc) + struct mana_rxq *rxq; + u32 rxq_idx; + +- for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { +- rxq = apc->rxqs[rxq_idx]; +- if (!rxq) +- continue; ++ if (apc->rxqs) { + +- mana_destroy_rxq(apc, rxq, true); +- apc->rxqs[rxq_idx] = NULL; ++ for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { ++ rxq = apc->rxqs[rxq_idx]; ++ if (!rxq) ++ continue; ++ ++ mana_destroy_rxq(apc, rxq, true); ++ apc->rxqs[rxq_idx] = NULL; ++ } + } + + mana_destroy_txq(apc); +@@ -3241,7 +3247,8 @@ static int mana_dealloc_queues(struct net_device *ndev) + if (apc->port_is_up) + return -EINVAL; + +- mana_chn_setxdp(apc, NULL); ++ if (apc->rxqs) ++ mana_chn_setxdp(apc, NULL); + + if (gd->gdma_context->is_pf && !apc->ac->bm_hostmode) + mana_pf_deregister_filter(apc); +@@ -3259,33 +3266,38 @@ static int mana_dealloc_queues(struct net_device *ndev) + * number of queues. + */ + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- tsleep = 1000; +- while (atomic_read(&txq->pending_sends) > 0 && +- time_before(jiffies, timeout)) { +- usleep_range(tsleep, tsleep + 1000); +- tsleep <<= 1; +- } +- if (atomic_read(&txq->pending_sends)) { +- err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); +- if (err) { +- netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", +- err, atomic_read(&txq->pending_sends), +- txq->gdma_txq_id); ++ if (apc->tx_qp) { ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ tsleep = 1000; ++ while (atomic_read(&txq->pending_sends) > 0 && ++ time_before(jiffies, timeout)) { ++ usleep_range(tsleep, tsleep + 1000); ++ tsleep <<= 1; ++ } ++ if (atomic_read(&txq->pending_sends)) { ++ err = ++ pcie_flr(to_pci_dev(gd->gdma_context->dev)); ++ if (err) { ++ netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", ++ err, ++ atomic_read(&txq->pending_sends), ++ txq->gdma_txq_id); ++ } ++ break; + } +- break; + } +- } + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- while ((skb = skb_dequeue(&txq->pending_skbs))) { +- mana_unmap_skb(skb, apc); +- dev_kfree_skb_any(skb); ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ while ((skb = skb_dequeue(&txq->pending_skbs))) { ++ mana_unmap_skb(skb, apc); ++ dev_kfree_skb_any(skb); ++ } ++ atomic_set(&txq->pending_sends, 0); + } +- atomic_set(&txq->pending_sends, 0); + } ++ + /* We're 100% sure the queues can no longer be woken up, because + * we're sure now mana_poll_tx_cq() can't be running. + */ +-- +2.53.0 + diff --git a/queue-6.18/net-mana-skip-redundant-detach-on-already-detached-p.patch b/queue-6.18/net-mana-skip-redundant-detach-on-already-detached-p.patch new file mode 100644 index 0000000000..6077ca7eb4 --- /dev/null +++ b/queue-6.18/net-mana-skip-redundant-detach-on-already-detached-p.patch @@ -0,0 +1,51 @@ +From 2922a922b3d1b6e167b46606ed0b574627f7a7a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 01:08:25 -0700 +Subject: net: mana: Skip redundant detach on already-detached port + +From: Dipayaan Roy + +[ Upstream commit 5b05aa36ee24297d7296ca58dfd8c448d0e4cda3 ] + +When mana_per_port_queue_reset_work_handler() runs after a previous +detach succeeded but attach failed, the port is left in a detached +state with apc->tx_qp and apc->rxqs already freed. Calling +mana_detach() again unconditionally leads to NULL pointer dereferences +during queue teardown. + +Add an early exit in mana_detach() when the port is already in +detached state (!netif_device_present) for non-close callers, making +it safe to call idempotently. This allows the queue reset handler and +other recovery paths to simply retry mana_attach() without redundant +teardown. + +Fixes: 3b194343c250 ("net: mana: Implement ndo_tx_timeout and serialize queue resets per port.") +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260525081129.1230035-3-dipayanroy@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 6ef2a3ee44c6b0..1f723c0ea12837 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3322,6 +3322,12 @@ int mana_detach(struct net_device *ndev, bool from_close) + + ASSERT_RTNL(); + ++ /* If already detached (indicates detach succeeded but attach failed ++ * previously). Now skip mana detach and just retry mana_attach. ++ */ ++ if (!from_close && !netif_device_present(ndev)) ++ return 0; ++ + apc->port_st_save = apc->port_is_up; + apc->port_is_up = false; + +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5-hws-reject-unsupported-remove-header-action.patch b/queue-6.18/net-mlx5-hws-reject-unsupported-remove-header-action.patch new file mode 100644 index 0000000000..c717401013 --- /dev/null +++ b/queue-6.18/net-mlx5-hws-reject-unsupported-remove-header-action.patch @@ -0,0 +1,50 @@ +From 84b76baf8114b699baabfa7199465e44090d70ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:00:31 +0100 +Subject: net/mlx5: HWS: Reject unsupported remove-header action + +From: Prathamesh Deshpande + +[ Upstream commit 86f1d0f063e423a5c1982db1e5e7a8eac511e603 ] + +mlx5_cmd_hws_packet_reformat_alloc() handles +MLX5_REFORMAT_TYPE_REMOVE_HDR by looking up a matching HWS remove-header +action. + +If mlx5_fs_get_action_remove_header_vlan() returns NULL, the code only +logs an error and continues. The function then returns success with a NULL +HWS action stored in the packet-reformat object. + +Return an error when no matching remove-header action is available. + +Fixes: aecd9d1020e3 ("net/mlx5: fs, add HWS packet reformat API function") +Signed-off-by: Prathamesh Deshpande +Reviewed-by: Simon Horman +Reviewed-by: Yevgeny Kliteynik +Acked-by: Tariq Toukan +Link: https://patch.msgid.link/20260506000054.51797-1-prathameshdeshpande7@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c +index 6a4c4cccd64342..c45a7ca66ad8ed 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c +@@ -1323,8 +1323,10 @@ mlx5_cmd_hws_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns, + break; + case MLX5_REFORMAT_TYPE_REMOVE_HDR: + hws_action = mlx5_fs_get_action_remove_header_vlan(fs_ctx, params); +- if (!hws_action) ++ if (!hws_action) { + mlx5_core_err(dev, "Only vlan remove header supported\n"); ++ return -EOPNOTSUPP; ++ } + break; + default: + mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n", +-- +2.53.0 + diff --git a/queue-6.18/net-netlink-don-t-set-nsid-on-local-notifications.patch b/queue-6.18/net-netlink-don-t-set-nsid-on-local-notifications.patch new file mode 100644 index 0000000000..7aa8f0709c --- /dev/null +++ b/queue-6.18/net-netlink-don-t-set-nsid-on-local-notifications.patch @@ -0,0 +1,82 @@ +From 0a31a5650d70f4fccaf4d56e70a49cd2697e221e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:36 +0200 +Subject: net: netlink: don't set nsid on local notifications + +From: Ilya Maximets + +[ Upstream commit 88b126b39f9757e9debc322d4679239e9af089c7 ] + +In most cases, notifications on sockets with NETLINK_LISTEN_ALL_NSID +do not contain NSID in their ancillary data in case the event is local +to the listener. + +However, when a self-referential NSID is allocated for a namespace, +every local notification starts sending this ID to the user space. + +This is problematic, because the listener cannot tell if those +notifications are local or not anymore without making extra requests +to figure out if the provided NSID is local or not. The listener +can also not figure out the local NSID beforehand as it can be +allocated at any point in time by other processes, changing the +structure of the future notifications for everyone. + +The value is practically not useful, since it's the namespace's own +ID that the application has to obtain from other sources in order to +figure out if it's the same or not. So, for the application it's +just an extra busy work with no benefits. Moreover, applications +that do not know about this quirk may be mishandling notifications +with NSID set as notifications from remote namespaces. This is the +case for ovs-vswitchd and the iproute2's 'ip monitor' that stops +printing 'current' and starts printing the nsid number mid-session. + +Lack of clear documentation for this behavior is also not helping. + +A search though open-source projects doesn't reveal any projects +that use NETNSA_NSID_NOT_ASSIGNED and rely on metadata to contain +self-referential NSIDs (expected, since the value is not useful). +Quite the opposite, as already mentioned, there are few applications +that rely on NSID to not be present in local events. + +Since the value is not useful and actively harmful in some cases, +let's not report it for local events, making the notifications more +consistent. + +Also adding some blank lines for readability. + +Fixes: 59324cf35aba ("netlink: allow to listen "all" netns") +Reported-by: Matteo Perin +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-3-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 0e6dfd01d9b419..1d1b3bd54a916b 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1484,10 +1484,14 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ + NETLINK_CB(p->skb2).nsid_is_set = false; +- NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); +- if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) +- NETLINK_CB(p->skb2).nsid_is_set = true; ++ if (!net_eq(sock_net(sk), p->net)) { ++ NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); ++ if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) ++ NETLINK_CB(p->skb2).nsid_is_set = true; ++ } ++ + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { + netlink_overrun(sk); +-- +2.53.0 + diff --git a/queue-6.18/net-netlink-fix-sending-unassigned-nsid-after-assign.patch b/queue-6.18/net-netlink-fix-sending-unassigned-nsid-after-assign.patch new file mode 100644 index 0000000000..868f9b7d17 --- /dev/null +++ b/queue-6.18/net-netlink-fix-sending-unassigned-nsid-after-assign.patch @@ -0,0 +1,45 @@ +From b065309029ea5a81e1836547d84bcb1cc58ebfe1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:35 +0200 +Subject: net: netlink: fix sending unassigned nsid after assigned one + +From: Ilya Maximets + +[ Upstream commit 70f8592ee90585272018a725054b6eb2ab7e99ca ] + +If the current skb is not shared, it is re-used directly for all the +sockets subscribed to the notification. If we have remote all-nsid +socket receiving a message first, then the 'nsid_is_set' will be +set to 'true'. If the nsid is NOT_ASSIGNED for the next socket in +the list, the 'nsid_is_set' will remain 'true' and the negative value +is be delivered to the user space. All subsequent nsid values will be +delivered as well, since there is no code path that sets the flag +back to 'false'. + +Fix that by always dropping the flag to 'false' first. + +Fixes: 7212462fa6fd ("netlink: don't send unknown nsid") +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-2-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 2b46c0cd752a31..0e6dfd01d9b419 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1484,6 +1484,7 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ NETLINK_CB(p->skb2).nsid_is_set = false; + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) + NETLINK_CB(p->skb2).nsid_is_set = true; +-- +2.53.0 + diff --git a/queue-6.18/net-sched-revert-net-sched-restrict-conditions-for-a.patch b/queue-6.18/net-sched-revert-net-sched-restrict-conditions-for-a.patch new file mode 100644 index 0000000000..1d4898147d --- /dev/null +++ b/queue-6.18/net-sched-revert-net-sched-restrict-conditions-for-a.patch @@ -0,0 +1,102 @@ +From 8c1d2e30c6dc44cc920179bd372738ba12172d90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:49 -0400 +Subject: net/sched: Revert "net/sched: Restrict conditions for adding + duplicating netems to qdisc tree" + +From: Jamal Hadi Salim + +[ Upstream commit eda0b7f203bb166c98d1418b204135bd566ac83b ] + +This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. + +The original patch rejects any tree containing two netems when +either has duplication set, even when they sit on unrelated classes +of the same classful parent. That broke configurations that have +worked since netem was introduced. + +The re-entrancy problem the original commit was trying to solve is +handled by later patch using tc_depth flag. + +Doing this revert will (re)expose the original bug with multiple +netem duplication. When this patch is backported make sure +and get the full series. + +Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") +Reported-by: Ji-Soo Chung +Reported-by: Gerlinde +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 +Reported-by: zyc zyc +Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ +Reported-by: Manas Ghandat +Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 40 ---------------------------------------- + 1 file changed, 40 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 47db6da905c585..73b3a8ce2f4350 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1006,41 +1006,6 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, + return 0; + } + +-static const struct Qdisc_class_ops netem_class_ops; +- +-static int check_netem_in_tree(struct Qdisc *sch, bool duplicates, +- struct netlink_ext_ack *extack) +-{ +- struct Qdisc *root, *q; +- unsigned int i; +- +- root = qdisc_root_sleeping(sch); +- +- if (sch != root && root->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(root))->duplicate) +- goto err; +- } +- +- if (!qdisc_dev(root)) +- return 0; +- +- hash_for_each(qdisc_dev(root)->qdisc_hash, i, q, hash) { +- if (sch != q && q->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(q))->duplicate) +- goto err; +- } +- } +- +- return 0; +- +-err: +- NL_SET_ERR_MSG(extack, +- "netem: cannot mix duplicating netems with other netems in tree"); +- return -EINVAL; +-} +- + /* Parse netlink message to set options */ + static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +@@ -1117,11 +1082,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + q->gap = qopt->gap; + q->counter = 0; + q->loss = qopt->loss; +- +- ret = check_netem_in_tree(sch, qopt->duplicate, extack); +- if (ret) +- goto unlock; +- + q->duplicate = qopt->duplicate; + + /* for compatibility with earlier versions. +-- +2.53.0 + diff --git a/queue-6.18/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch b/queue-6.18/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch new file mode 100644 index 0000000000..ffd59e97df --- /dev/null +++ b/queue-6.18/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch @@ -0,0 +1,64 @@ +From ce1b823828a9d42d026f9b1b299a47c1384ab20b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:43:53 +0100 +Subject: net: skbuff: fix pskb_carve leaking zcopy pages + +From: Pavel Begunkov + +[ Upstream commit ff6e798c2eac3ebd0501ad7e796f583fab928de8 ] + +When SKBFL_MANAGED_FRAG_REFS is set, frag pages are not refcounted but +their lifetime is controlled by the attached ubuf_info. To make a copy +of the skb_shared_info, we either should clear the flag and reference +the frags, or keep the flag and have frags unreferenced. + +pskb_carve_inside_header() and pskb_carve_inside_nonlinear() don't +follow the rule and thus can leak page references. Let's clear +SKBFL_MANAGED_FRAG_REFS from the original skb to fix it. It's the +simplest way to address it, but there are more performant ways to do +that if it ever becomes a problem. + +Link: https://lore.kernel.org/all/20260523085809.26331-1-nvminh232@clc.fitus.edu.vn/ +Fixes: 753f1ca4e1e50 ("net: introduce managed frags infrastructure") +Reported-by: Minh Nguyen +Reported-by: Willem de Bruijn +Signed-off-by: Pavel Begunkov +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/1e2086aa69217d7f9c8da3d38f5be7160f1b4cd1.1779993185.git.asml.silence@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 6618bfa70ca444..a52aa79b0fdbaf 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6772,6 +6772,11 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, + skb_copy_from_linear_data_offset(skb, off, data, new_hlen); + skb->len -= off; + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), + offsetof(struct skb_shared_info, +@@ -6883,6 +6888,11 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, + return -ENOMEM; + size = SKB_WITH_OVERHEAD(size); + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0])); + if (skb_orphan_frags(skb, gfp_mask)) { +-- +2.53.0 + diff --git a/queue-6.18/net-smc-do-not-re-initialize-smc-hashtables.patch b/queue-6.18/net-smc-do-not-re-initialize-smc-hashtables.patch new file mode 100644 index 0000000000..557a8065cb --- /dev/null +++ b/queue-6.18/net-smc-do-not-re-initialize-smc-hashtables.patch @@ -0,0 +1,59 @@ +From 2e2cca4092c507b7df463f9706010f2085c47330 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 16:56:39 +0200 +Subject: net/smc: Do not re-initialize smc hashtables + +From: Alexandra Winter + +[ Upstream commit 9e4389b0038781f19f97895186ed941ff8ac1678 ] + +INIT_HLIST_HEAD(&smc_v*_hashinfo.ht) are called after smc_nl_init(), +proto_register() and sock_register(). This can lead to smc_v*_hashinfo.ht +being reset even though hash entries already exist and are being used, +possibly resulting in a corrupted list. + +Remove unnecessary and dangerous re-initialisation of smc_v*_hashinfo.ht in +smc_init(); it is implicitly initialised to zero anyhow. Add +HLIST_HEAD_INIT to the definitions for clarity. + +Fixes: f16a7dd5cf27 ("smc: netlink interface for SMC sockets") +Suggested-by: Halil Pasic +Signed-off-by: Alexandra Winter +Acked-by: Halil Pasic +Reviewed-by: Mahanta Jambigi +Link: https://patch.msgid.link/20260521145639.10317-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 5915fcdef743d2..21d0c62bcf4644 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -188,10 +188,12 @@ static bool smc_hs_congested(const struct sock *sk) + + struct smc_hashinfo smc_v4_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + int smc_hash_sk(struct sock *sk) +@@ -3595,8 +3597,6 @@ static int __init smc_init(void) + pr_err("%s: sock_register fails with %d\n", __func__, rc); + goto out_proto6; + } +- INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); +- INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); + + rc = smc_ib_register_client(); + if (rc) { +-- +2.53.0 + diff --git a/queue-6.18/net-team-fix-null-pointer-dereference-in-team_xmit-d.patch b/queue-6.18/net-team-fix-null-pointer-dereference-in-team_xmit-d.patch new file mode 100644 index 0000000000..0ab97f3860 --- /dev/null +++ b/queue-6.18/net-team-fix-null-pointer-dereference-in-team_xmit-d.patch @@ -0,0 +1,149 @@ +From 1e841a0236db85219d7a6178887759ca393288f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 01:12:01 -0700 +Subject: net: team: fix NULL pointer dereference in team_xmit during mode + change + +From: Weiming Shi + +[ Upstream commit 25fe708bbc59289d3d1ea4b126fbc1b460a072a5 ] + +__team_change_mode() clears team->ops with memset() before restoring +safe dummy handlers via team_adjust_ops(). A concurrent team_xmit() +running under RCU on another CPU can read team->ops.transmit during +this window and call a NULL function pointer, crashing the kernel. + +The race requires a mode change (CAP_NET_ADMIN) concurrent with +transmit on the team device. + + BUG: kernel NULL pointer dereference, address: 0000000000000000 + Oops: 0010 [#1] SMP KASAN NOPTI + RIP: 0010:0x0 + Call Trace: + team_xmit (drivers/net/team/team_core.c:1853) + dev_hard_start_xmit (net/core/dev.c:3904) + __dev_queue_xmit (net/core/dev.c:4871) + packet_sendmsg (net/packet/af_packet.c:3109) + __sys_sendto (net/socket.c:2265) + +The original code assumed that no ports means no traffic, so mode +changes could freely memset()/memcpy() the ops. AF_PACKET with +forced carrier breaks that assumption. + +Prevent the race instead of making it safe: replace memset()/memcpy() +with per-field updates that never touch transmit or receive. Those +two handlers are managed solely by team_adjust_ops(), which already +installs dummies when tx_en_port_count == 0 (always true during mode +change since no ports are present). WRITE_ONCE/READ_ONCE prevent +store/load tearing on the handler pointers. + +synchronize_net() before exit_op() drains in-flight readers that may +still reference old mode state from before port removal switched the +handlers to dummies. + +Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521081159.1491563-3-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/team/team_core.c | 45 +++++++++++++++++++++++++----------- + 1 file changed, 32 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c +index 11c8e6551dd357..ff4dcd6035cd10 100644 +--- a/drivers/net/team/team_core.c ++++ b/drivers/net/team/team_core.c +@@ -535,21 +535,23 @@ static void team_adjust_ops(struct team *team) + + if (!team->en_port_count || !team_is_mode_set(team) || + !team->mode->ops->transmit) +- team->ops.transmit = team_dummy_transmit; ++ WRITE_ONCE(team->ops.transmit, team_dummy_transmit); + else +- team->ops.transmit = team->mode->ops->transmit; ++ WRITE_ONCE(team->ops.transmit, team->mode->ops->transmit); + + if (!team->en_port_count || !team_is_mode_set(team) || + !team->mode->ops->receive) +- team->ops.receive = team_dummy_receive; ++ WRITE_ONCE(team->ops.receive, team_dummy_receive); + else +- team->ops.receive = team->mode->ops->receive; ++ WRITE_ONCE(team->ops.receive, team->mode->ops->receive); + } + + /* +- * We can benefit from the fact that it's ensured no port is present +- * at the time of mode change. Therefore no packets are in fly so there's no +- * need to set mode operations in any special way. ++ * team_change_mode() ensures no ports are present during mode change, ++ * but lockless readers can still reach team_xmit(). Avoid touching ++ * transmit/receive -- they are already set to dummies by ++ * team_adjust_ops() since no ports are enabled. synchronize_net() ++ * drains in-flight readers before destroying old mode state. + */ + static int __team_change_mode(struct team *team, + const struct team_mode *new_mode) +@@ -558,9 +560,21 @@ static int __team_change_mode(struct team *team, + if (team_is_mode_set(team)) { + void (*exit_op)(struct team *team) = team->ops.exit; + +- /* Clear ops area so no callback is called any longer */ +- memset(&team->ops, 0, sizeof(struct team_mode_ops)); +- team_adjust_ops(team); ++ /* Clear cold-path ops used only under RTNL. transmit and ++ * receive are already dummies (no ports) so leave them ++ * alone -- overwriting them is the source of the race. ++ */ ++ team->ops.init = NULL; ++ team->ops.exit = NULL; ++ team->ops.port_enter = NULL; ++ team->ops.port_leave = NULL; ++ team->ops.port_change_dev_addr = NULL; ++ team->ops.port_tx_disabled = NULL; ++ ++ /* Wait for in-flight readers before tearing down mode ++ * state they may reference. ++ */ ++ synchronize_net(); + + if (exit_op) + exit_op(team); +@@ -583,7 +597,12 @@ static int __team_change_mode(struct team *team, + } + + team->mode = new_mode; +- memcpy(&team->ops, new_mode->ops, sizeof(struct team_mode_ops)); ++ team->ops.init = new_mode->ops->init; ++ team->ops.exit = new_mode->ops->exit; ++ team->ops.port_enter = new_mode->ops->port_enter; ++ team->ops.port_leave = new_mode->ops->port_leave; ++ team->ops.port_change_dev_addr = new_mode->ops->port_change_dev_addr; ++ team->ops.port_tx_disabled = new_mode->ops->port_tx_disabled; + team_adjust_ops(team); + + return 0; +@@ -744,7 +763,7 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) + /* allow exact match delivery for disabled ports */ + res = RX_HANDLER_EXACT; + } else { +- res = team->ops.receive(team, port, skb); ++ res = READ_ONCE(team->ops.receive)(team, port, skb); + } + if (res == RX_HANDLER_ANOTHER) { + struct team_pcpu_stats *pcpu_stats; +@@ -1683,7 +1702,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) + + tx_success = team_queue_override_transmit(team, skb); + if (!tx_success) +- tx_success = team->ops.transmit(team, skb); ++ tx_success = READ_ONCE(team->ops.transmit)(team, skb); + if (tx_success) { + struct team_pcpu_stats *pcpu_stats; + +-- +2.53.0 + diff --git a/queue-6.18/net-team-remove-unused-team_mode_op-port_enabled.patch b/queue-6.18/net-team-remove-unused-team_mode_op-port_enabled.patch new file mode 100644 index 0000000000..d75586b7e2 --- /dev/null +++ b/queue-6.18/net-team-remove-unused-team_mode_op-port_enabled.patch @@ -0,0 +1,51 @@ +From 2ed1433987933b7277c9e36cbd38e2150d3ed936 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 02:59:24 +0000 +Subject: net: team: Remove unused team_mode_op, port_enabled + +From: Marc Harvey + +[ Upstream commit 014f249121d73909528df320818fba7693d0ec92 ] + +This team_mode_op wasn't used by any of the team modes, so remove it. + +Reviewed-by: Jiri Pirko +Signed-off-by: Marc Harvey +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260409-teaming-driver-internal-v7-2-f47e7589685d@google.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 25fe708bbc59 ("net: team: fix NULL pointer dereference in team_xmit during mode change") +Signed-off-by: Sasha Levin +--- + drivers/net/team/team_core.c | 2 -- + include/linux/if_team.h | 1 - + 2 files changed, 3 deletions(-) + +diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c +index a98f5e5061544c..712d8043e66e17 100644 +--- a/drivers/net/team/team_core.c ++++ b/drivers/net/team/team_core.c +@@ -945,8 +945,6 @@ static void team_port_enable(struct team *team, + team_port_index_hash(team, port->index)); + team_adjust_ops(team); + team_queue_override_port_add(team, port); +- if (team->ops.port_enabled) +- team->ops.port_enabled(team, port); + team_notify_peers(team); + team_mcast_rejoin(team); + team_lower_state_changed(port); +diff --git a/include/linux/if_team.h b/include/linux/if_team.h +index ce97d891cf720f..0d550d44a1c230 100644 +--- a/include/linux/if_team.h ++++ b/include/linux/if_team.h +@@ -121,7 +121,6 @@ struct team_mode_ops { + int (*port_enter)(struct team *team, struct team_port *port); + void (*port_leave)(struct team *team, struct team_port *port); + void (*port_change_dev_addr)(struct team *team, struct team_port *port); +- void (*port_enabled)(struct team *team, struct team_port *port); + void (*port_disabled)(struct team *team, struct team_port *port); + }; + +-- +2.53.0 + diff --git a/queue-6.18/net-team-rename-port_disabled-team-mode-op-to-port_t.patch b/queue-6.18/net-team-rename-port_disabled-team-mode-op-to-port_t.patch new file mode 100644 index 0000000000..2ca97336f5 --- /dev/null +++ b/queue-6.18/net-team-rename-port_disabled-team-mode-op-to-port_t.patch @@ -0,0 +1,78 @@ +From 203bf220d218b45f7299feb33e96437a90f9e2bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 02:59:25 +0000 +Subject: net: team: Rename port_disabled team mode op to port_tx_disabled + +From: Marc Harvey + +[ Upstream commit cfa477df2cc62ba53cb936669886361152b594a7 ] + +This team mode op is only used by the load balance mode, and it only +uses it in the tx path. + +Reviewed-by: Jiri Pirko +Signed-off-by: Marc Harvey +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260409-teaming-driver-internal-v7-3-f47e7589685d@google.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 25fe708bbc59 ("net: team: fix NULL pointer dereference in team_xmit during mode change") +Signed-off-by: Sasha Levin +--- + drivers/net/team/team_core.c | 4 ++-- + drivers/net/team/team_mode_loadbalance.c | 4 ++-- + include/linux/if_team.h | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c +index 712d8043e66e17..11c8e6551dd357 100644 +--- a/drivers/net/team/team_core.c ++++ b/drivers/net/team/team_core.c +@@ -969,8 +969,8 @@ static void team_port_disable(struct team *team, + { + if (!team_port_enabled(port)) + return; +- if (team->ops.port_disabled) +- team->ops.port_disabled(team, port); ++ if (team->ops.port_tx_disabled) ++ team->ops.port_tx_disabled(team, port); + hlist_del_rcu(&port->hlist); + __reconstruct_port_hlist(team, port->index); + port->index = -1; +diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c +index b14538bde2f824..b27e44a4df5f6e 100644 +--- a/drivers/net/team/team_mode_loadbalance.c ++++ b/drivers/net/team/team_mode_loadbalance.c +@@ -655,7 +655,7 @@ static void lb_port_leave(struct team *team, struct team_port *port) + free_percpu(lb_port_priv->pcpu_stats); + } + +-static void lb_port_disabled(struct team *team, struct team_port *port) ++static void lb_port_tx_disabled(struct team *team, struct team_port *port) + { + lb_tx_hash_to_port_mapping_null_port(team, port); + } +@@ -665,7 +665,7 @@ static const struct team_mode_ops lb_mode_ops = { + .exit = lb_exit, + .port_enter = lb_port_enter, + .port_leave = lb_port_leave, +- .port_disabled = lb_port_disabled, ++ .port_tx_disabled = lb_port_tx_disabled, + .receive = lb_receive, + .transmit = lb_transmit, + }; +diff --git a/include/linux/if_team.h b/include/linux/if_team.h +index 0d550d44a1c230..cd5acf40040d2e 100644 +--- a/include/linux/if_team.h ++++ b/include/linux/if_team.h +@@ -121,7 +121,7 @@ struct team_mode_ops { + int (*port_enter)(struct team *team, struct team_port *port); + void (*port_leave)(struct team *team, struct team_port *port); + void (*port_change_dev_addr)(struct team *team, struct team_port *port); +- void (*port_disabled)(struct team *team, struct team_port *port); ++ void (*port_tx_disabled)(struct team *team, struct team_port *port); + }; + + extern int team_modeop_port_enter(struct team *team, struct team_port *port); +-- +2.53.0 + diff --git a/queue-6.18/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch b/queue-6.18/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch new file mode 100644 index 0000000000..6c3ba9c79d --- /dev/null +++ b/queue-6.18/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch @@ -0,0 +1,107 @@ +From 643e783857c1c0b549731ca97802ad7f8d16d798 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 22:52:07 +0200 +Subject: netfilter: ebtables: fix OOB read in compat_mtw_from_user + +From: Florian Westphal + +[ Upstream commit f438d1786d657d57790c5d138d6db3fc9fdac392 ] + +Luxiao Xu says: + + The function compat_mtw_from_user() converts ebtables extensions from + 32-bit user structures to kernel native structures. However, it lacks + proper validation of the user-supplied match_size/target_size. + + When certain extensions are processed, the kernel-side translation + logic may perform memory accesses based on the extension's expected + size. If the user provides a size smaller than what the extension + requires, it results in an out-of-bounds read as reported by KASAN. + + This fix introduces a check to ensure match_size is at least as large + as the extension's required compatsize. This covers matches, watchers, + and targets, while maintaining compatibility with standard targets. + +AFAIU this is relevant for matches that need to go though +match->compat_from_user() call. Those that use plain memcpy with the +user-provided size are ok because the caller checks that size vs the +start of the next rule entry offset (which itself is checked vs. total +size copied from userspace). + +The ->compat_from_user() callbacks assume they can read compatsize bytes, +so they need this extra check. + +Based on an earlier patch from Luxiao Xu. + +Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 77df9e856c2e73..ecd7baa25d7268 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1956,6 +1956,25 @@ enum compat_mwt { + EBT_COMPAT_TARGET, + }; + ++static bool match_size_ok(const struct xt_match *match, unsigned int match_size) ++{ ++ u16 csize; ++ ++ if (match->matchsize == -1) /* cannot validate ebt_among */ ++ return true; ++ ++ csize = match->compatsize ? : match->matchsize; ++ ++ return match_size >= csize; ++} ++ ++static bool tgt_size_ok(const struct xt_target *tgt, unsigned int tgt_size) ++{ ++ u16 csize = tgt->compatsize ? : tgt->targetsize; ++ ++ return tgt_size >= csize; ++} ++ + static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + enum compat_mwt compat_mwt, + struct ebt_entries_buf_state *state, +@@ -1981,6 +2000,11 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + if (IS_ERR(match)) + return PTR_ERR(match); + ++ if (!match_size_ok(match, match_size)) { ++ module_put(match->me); ++ return -EINVAL; ++ } ++ + off = ebt_compat_match_offset(match, match_size); + if (dst) { + if (match->compat_from_user) +@@ -2000,6 +2024,12 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + mwt->u.revision); + if (IS_ERR(wt)) + return PTR_ERR(wt); ++ ++ if (!tgt_size_ok(wt, match_size)) { ++ module_put(wt->me); ++ return -EINVAL; ++ } ++ + off = xt_compat_target_offset(wt); + + if (dst) { +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch b/queue-6.18/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch new file mode 100644 index 0000000000..f80b54e6e7 --- /dev/null +++ b/queue-6.18/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch @@ -0,0 +1,141 @@ +From bfee6a1b3dab7f70873eed83daae7b12a05dc5f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 16:37:56 +0200 +Subject: netfilter: nf_tables: fix dst corruption in same register operation + +From: Fernando Fernandez Mancera + +[ Upstream commit 18014147d3ee7831dce53fe65d7fc8d428b02552 ] + +For lshift and rshift, the shift operations are performed in a loop over +32-bit words. The loop calculates the shifted value and write it to dst, +and then immediately reads from src to calculate the carry for the next +iteration. Because src and dst could point to the same memory location, +the carry is incorrectly calculated using the newly modified dst value +instead of the original src value. + +Adding a temporary local variable to cache the original value before +writing to dst and using it for the carry calculation solves the +problem. In addition, partial overlap is rejected from control plane for +all kind of operations including byteorder. This was tested with the +following bytecode: + +table test_table ip flags 0 use 1 handle 1 +ip test_table test_chain use 3 type filter hook input prio 0 policy accept packets 0 bytes 0 flags 1 +ip test_table test_chain 2 + [ immediate reg 1 0x44332211 0x88776655 ] + [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ] + [ cmp eq reg 1 0x66443322 0x00887766 ] + [ counter pkts 0 bytes 0 ] +ip test_table test_chain 4 3 + [ immediate reg 1 0x44332211 0x88776655 ] + [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ] + [ cmp eq reg 1 0x55443322 0x00887766 ] + [ counter pkts 21794 bytes 1917798 ] + +Fixes: 567d746b55bc ("netfilter: bitwise: add support for shifts.") +Acked-by: Jeremy Sowden +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 7 +++++++ + net/netfilter/nft_bitwise.c | 18 ++++++++++++++---- + net/netfilter/nft_byteorder.c | 13 ++++++++++--- + 3 files changed, 31 insertions(+), 7 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index 4dc080f7f27c65..b35e8c02fadcd5 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -188,6 +188,13 @@ static inline u64 nft_reg_load64(const u32 *sreg) + return get_unaligned((u64 *)sreg); + } + ++static inline bool nft_reg_overlap(u8 src, u8 dst, u32 len) ++{ ++ unsigned int n = DIV_ROUND_UP(len, sizeof(u32)); ++ ++ return src != dst && src < dst + n && dst < src + n; ++} ++ + static inline void nft_data_copy(u32 *dst, const struct nft_data *src, + unsigned int len) + { +diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c +index af990c600745be..1afb36fb5994db 100644 +--- a/net/netfilter/nft_bitwise.c ++++ b/net/netfilter/nft_bitwise.c +@@ -43,8 +43,10 @@ static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src, + u32 carry = 0; + + for (i = DIV_ROUND_UP(priv->len, sizeof(u32)); i > 0; i--) { +- dst[i - 1] = (src[i - 1] << shift) | carry; +- carry = src[i - 1] >> (BITS_PER_TYPE(u32) - shift); ++ u32 tmp_src = src[i - 1]; ++ ++ dst[i - 1] = (tmp_src << shift) | carry; ++ carry = tmp_src >> (BITS_PER_TYPE(u32) - shift); + } + } + +@@ -56,8 +58,10 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src, + u32 carry = 0; + + for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++) { +- dst[i] = carry | (src[i] >> shift); +- carry = src[i] << (BITS_PER_TYPE(u32) - shift); ++ u32 tmp_src = src[i]; ++ ++ dst[i] = carry | (tmp_src >> shift); ++ carry = tmp_src << (BITS_PER_TYPE(u32) - shift); + } + } + +@@ -235,6 +239,9 @@ static int nft_bitwise_init_bool(const struct nft_ctx *ctx, + &priv->sreg2, priv->len); + if (err < 0) + return err; ++ ++ if (nft_reg_overlap(priv->sreg2, priv->dreg, priv->len)) ++ return -EINVAL; + } + + return 0; +@@ -265,6 +272,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + if (err < 0) + return err; + ++ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len)) ++ return -EINVAL; ++ + if (tb[NFTA_BITWISE_OP]) { + priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])); + switch (priv->op) { +diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c +index af9206a3afd181..5e7a7841b789b0 100644 +--- a/net/netfilter/nft_byteorder.c ++++ b/net/netfilter/nft_byteorder.c +@@ -144,9 +144,16 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, + if (err < 0) + return err; + +- return nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG], +- &priv->dreg, NULL, NFT_DATA_VALUE, +- priv->len); ++ err = nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG], ++ &priv->dreg, NULL, NFT_DATA_VALUE, ++ priv->len); ++ if (err < 0) ++ return err; ++ ++ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len)) ++ return -EINVAL; ++ ++ return 0; + } + + static int nft_byteorder_dump(struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-6.18/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch b/queue-6.18/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch new file mode 100644 index 0000000000..d5eb81a363 --- /dev/null +++ b/queue-6.18/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch @@ -0,0 +1,68 @@ +From 4830d5363650d65456d43a285b1ca3839f7b7d37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 12:36:14 -0700 +Subject: netfilter: synproxy: refresh tcphdr after skb_ensure_writable + +From: Chris Mason + +[ Upstream commit 92170e6afe927ab2792a3f71902845789c8e31b1 ] + +synproxy_tstamp_adjust() rewrites the TCP timestamp option in place +and then patches the TCP checksum via inet_proto_csum_replace4() on +the caller-supplied tcphdr pointer. Both ipv4_synproxy_hook() and +ipv6_synproxy_hook() obtain that pointer with skb_header_pointer() +before calling in, so it may either alias skb->head directly or +point at the caller's on-stack _tcph buffer. + +Between obtaining the pointer and using it, the function calls +skb_ensure_writable(skb, optend), which on a cloned or non-linear +skb invokes pskb_expand_head() and frees the old skb->head. After +that point the cached th is stale: + + caller (ipv[46]_synproxy_hook) + th = skb_header_pointer(skb, ..., &_tcph) + synproxy_tstamp_adjust(skb, protoff, th, ...) + skb_ensure_writable(skb, optend) + pskb_expand_head() /* kfree(old skb->head) */ + ... + inet_proto_csum_replace4(&th->check, ...) + /* writes into freed head, or + into the caller's stack copy + leaving the on-wire checksum + stale */ + +The option bytes are written through skb->data and are fine; only +the checksum update goes through th and so lands in the wrong +place. The result is either a write into freed slab memory or a +packet leaving with a checksum that does not match its payload. + +Fix by re-deriving th from skb->data + protoff immediately after +skb_ensure_writable() succeeds, so the subsequent checksum update +targets the linear, writable header. + +Fixes: 48b1de4c110a ("netfilter: add SYNPROXY core/target") +Assisted-by: kres (claude-opus-4-7) +Signed-off-by: Chris Mason +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 3fa3f5dfb26444..6a851ac4dd048f 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -199,6 +199,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + if (skb_ensure_writable(skb, optend)) + return 0; + ++ th = (struct tcphdr *)(skb->data + protoff); ++ + while (optoff < optend) { + unsigned char *op = skb->data + optoff; + +-- +2.53.0 + diff --git a/queue-6.18/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch b/queue-6.18/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..98b94c751b --- /dev/null +++ b/queue-6.18/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch @@ -0,0 +1,48 @@ +From 38bc8a6c115dc3c07a8ff919578ae71a87058d94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 20:10:08 +0200 +Subject: netfilter: xt_cpu: prefer raw_smp_processor_id + +From: Florian Westphal + +[ Upstream commit c376f07e16c02239ed44cabb97145d03f65b4d15 ] + +With PREEMPT_RCU we get splat: + +BUG: using smp_processor_id() in preemptible [..] +caller is cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 +CPU: 1 .. Comm: syz.3.1377 #0 PREEMPT(full) +Call Trace: + + dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 + check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 + cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 + [..] + +Just use raw version instead. +This is similar to 14d14a5d2957 ("netfilter: nft_meta: use raw_smp_processor_id()"). + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reported-by: syzbot+690d3e3ffa7335ac10eb@syzkaller.appspotmail.com +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c +index 3bdc302a0f9137..9cb259902a586b 100644 +--- a/net/netfilter/xt_cpu.c ++++ b/net/netfilter/xt_cpu.c +@@ -34,7 +34,7 @@ static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_cpu_info *info = par->matchinfo; + +- return (info->cpu == smp_processor_id()) ^ info->invert; ++ return (info->cpu == raw_smp_processor_id()) ^ info->invert; + } + + static struct xt_match cpu_mt_reg __read_mostly = { +-- +2.53.0 + diff --git a/queue-6.18/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch b/queue-6.18/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch new file mode 100644 index 0000000000..f3a6cc42be --- /dev/null +++ b/queue-6.18/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch @@ -0,0 +1,40 @@ +From a94f21950d9c2cbad3089b32f60249705a61f773 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:41 +0000 +Subject: nfc: llcp: Fix use-after-free in llcp_sock_release() + +From: Lee Jones + +[ Upstream commit f4268b466190dae95a7585f69b4f1f8ad097632c ] + +llcp_sock_release() unconditionally unlinks the socket from the local +sockets list. However, if the socket is still in connecting state, it +is on the connecting list. + +Fix this by checking the socket state and unlinking from the correct list. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Signed-off-by: Lee Jones +Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index 57a2f97004e172..915929cd724f90 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -633,6 +633,8 @@ static int llcp_sock_release(struct socket *sock) + + if (sock->type == SOCK_RAW) + nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else if (sk->sk_state == LLCP_CONNECTING) ++ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + else + nfc_llcp_sock_unlink(&local->sockets, sk); + +-- +2.53.0 + diff --git a/queue-6.18/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch b/queue-6.18/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch new file mode 100644 index 0000000000..01a2be8b25 --- /dev/null +++ b/queue-6.18/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch @@ -0,0 +1,67 @@ +From 6cb2942eb336a91362789fc998f38c57e7ed7f58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:42 +0000 +Subject: nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() + +From: Lee Jones + +[ Upstream commit b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 ] + +A race condition exists in the NFC LLCP connection state machine where +the connection acceptance packet (CC) can be processed concurrently with +socket release. This can lead to a use-after-free of the socket object. + +When nfc_llcp_recv_cc() moves the socket from the connecting_sockets +list to the sockets list, it does so without holding the socket lock. +If llcp_sock_release() is executing concurrently, it might have already +unlinked the socket and dropped its references, which can result in +nfc_llcp_recv_cc() linking a freed socket into the live list. + +Fix this by holding lock_sock() during the state transition and list +movement in nfc_llcp_recv_cc(). After acquiring the lock, check if +the socket is still hashed to ensure it hasn't already been unlinked +and marked for destruction by the release path. This aligns the locking +pattern with recv_hdlc() and recv_disc(). + +Fixes: a69f32af86e3 ("NFC: Socket linked list") +Signed-off-by: Lee Jones +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index da8d3add0018f3..c83a00e429852c 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -1218,6 +1218,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + + sk = &llcp_sock->sk; + ++ lock_sock(sk); ++ ++ /* Check if socket was destroyed whilst waiting for the lock */ ++ if (!sk_hashed(sk)) { ++ release_sock(sk); ++ nfc_llcp_sock_put(llcp_sock); ++ return; ++ } ++ + /* Unlink from connecting and link to the client array */ + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + nfc_llcp_sock_link(&local->sockets, sk); +@@ -1229,6 +1238,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + ++ release_sock(sk); ++ + nfc_llcp_sock_put(llcp_sock); + } + +-- +2.53.0 + diff --git a/queue-6.18/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch b/queue-6.18/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch new file mode 100644 index 0000000000..63feabe99c --- /dev/null +++ b/queue-6.18/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch @@ -0,0 +1,83 @@ +From 26612ad39d67ec0a0ce1de4c003ea619ac4e24ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 May 2026 19:55:18 +0800 +Subject: nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems + +From: Carl Lee + +[ Upstream commit f23bf992d65a42007c517b060ca35cebdea3525a ] + +Some ACPI-based platforms report incorrect IRQ trigger types (e.g. +IRQF_TRIGGER_HIGH), which can lead to interrupt storms. + +Use the historically working rising-edge trigger on ACPI systems to +avoid this regression. + +Device Tree-based systems continue to use the firmware-provided +trigger type. + +Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") +Signed-off-by: Carl Lee +Tested-by: Bartosz Golaszewski +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Mark Pearson +Tested-by: Mark Pearson +Tested-by: Luca Stefani +Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index b3d34433bd14a0..a6c08175d9dd93 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -267,6 +268,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + { + struct device *dev = &client->dev; + struct nxp_nci_i2c_phy *phy; ++ unsigned long irqflags; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +@@ -303,9 +305,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + if (r < 0) + return r; + ++ /* ++ * ACPI platforms may report incorrect IRQ trigger types ++ * (e.g. level-high), which can lead to interrupt storms. ++ * ++ * Use the historically stable rising-edge trigger for ACPI devices. ++ * ++ * On non-ACPI systems (e.g. Device Tree), prefer the firmware- ++ * provided trigger type, falling back to rising-edge if not set. ++ */ ++ if (ACPI_COMPANION(dev)) { ++ irqflags = IRQF_TRIGGER_RISING; ++ } else { ++ irqflags = irq_get_trigger_type(client->irq); ++ if (!irqflags) ++ irqflags = IRQF_TRIGGER_RISING; ++ } ++ + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, +- IRQF_ONESHOT, ++ irqflags | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); +-- +2.53.0 + diff --git a/queue-6.18/nvme-tcp-store-negative-errno-in-queue-tls_err.patch b/queue-6.18/nvme-tcp-store-negative-errno-in-queue-tls_err.patch new file mode 100644 index 0000000000..87589be6a8 --- /dev/null +++ b/queue-6.18/nvme-tcp-store-negative-errno-in-queue-tls_err.patch @@ -0,0 +1,52 @@ +From acfb4c09bcdfaa01c1905a2c3d82e0693773f884 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:16 -0400 +Subject: nvme-tcp: store negative errno in queue->tls_err + +From: Chuck Lever + +[ Upstream commit 9015985b5eb1a90eb86caf5bce1dfcf1aa38f8ad ] + +nvme_tcp_tls_done() assigns queue->tls_err in three branches. The +ENOKEY lookup failure and the EOPNOTSUPP initializer both store +negative errnos. The third branch, reached when the handshake +layer reports a non-zero status, stores -status. + +The handshake layer delivers status to the consumer callback as a +negative errno; the other in-tree consumers -- +xs_tls_handshake_done() and the nvmet target callback -- treat +their status argument that way. The extra negation in +nvme_tcp_tls_done() flips the sign, leaving tls_err as a positive +value (for instance, +EIO), which nvme_tcp_start_tls() then +returns to its caller. + +Drop the extra negation so queue->tls_err uniformly carries a +negative errno on failure. + +Fixes: be8e82caa685 ("nvme-tcp: enable TLS handshake upcall") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Reviewed-by: Alistair Francis +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-2-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/tcp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 9a96df1a511c02..afdbcff3d4821e 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1687,7 +1687,7 @@ static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid) + qid, pskid, status); + + if (status) { +- queue->tls_err = -status; ++ queue->tls_err = status; + goto out_complete; + } + +-- +2.53.0 + diff --git a/queue-6.18/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch b/queue-6.18/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch new file mode 100644 index 0000000000..f8ce9764b4 --- /dev/null +++ b/queue-6.18/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch @@ -0,0 +1,80 @@ +From 6bbfc57ed729e96a5c3f1cd80d0ef3d706af24cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 14:09:41 -0400 +Subject: scsi: core: Run queues for all non-SDEV_DEL devices from + scsi_run_host_queues + +From: David Jeffery + +[ Upstream commit 7205b58702273baf21d6ba7992e6ba15852325f7 ] + +While a SCSI host is in a recovery state, scsi_mq_requeue_cmd() will not +set the requeue list for a requeued command to be kicked in the future. +The expectation is a call to scsi_run_host_queues() will kick all SCSI +devices once the recovery state is cleared. + +However, scsi_run_host_queues() uses shost_for_each_device() which uses +scsi_device_get() and so will ignore devices in a partially removed +state like SDEV_CANCEL. But these devices may also have requeued +requests, leaving their requests stuck from not being kicked and causing +the removal process of the device to hang. + +scsi_run_host_queues() needs to run against more devices than the macro +shost_for_each_device() allows. Instead of using the too limiting +scsi_device_get() state checks, only ignore devices in SDEV_DEL state or +when unable to acquire a reference. Attempt to run the queues for all +other devices when scsi_run_host_queues() is called. + +Fixes: 8b566edbdbfb ("scsi: core: Only kick the requeue list if necessary") +Signed-off-by: David Jeffery +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260515180941.9698-1-djeffery@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/scsi_lib.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index 7ddb73cd6d9fe5..3f7ba6d3987f15 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -572,10 +572,33 @@ void scsi_requeue_run_queue(struct work_struct *work) + + void scsi_run_host_queues(struct Scsi_Host *shost) + { +- struct scsi_device *sdev; ++ struct scsi_device *sdev, *prev = NULL; ++ unsigned long flags; + +- shost_for_each_device(sdev, shost) ++ spin_lock_irqsave(shost->host_lock, flags); ++ __shost_for_each_device(sdev, shost) { ++ /* ++ * Only skip devices so deep into removal they will never need ++ * another kick to their queues. Thus scsi_device_get() cannot ++ * be used as it would skip devices in SDEV_CANCEL state which ++ * may need a queue kick. ++ */ ++ if (sdev->sdev_state == SDEV_DEL || ++ !get_device(&sdev->sdev_gendev)) ++ continue; ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ ++ if (prev) ++ put_device(&prev->sdev_gendev); + scsi_run_queue(sdev->request_queue); ++ ++ prev = sdev; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ if (prev) ++ put_device(&prev->sdev_gendev); + } + + static void scsi_uninit_cmd(struct scsi_cmnd *cmd) +-- +2.53.0 + diff --git a/queue-6.18/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch b/queue-6.18/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch new file mode 100644 index 0000000000..9e406f5a24 --- /dev/null +++ b/queue-6.18/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch @@ -0,0 +1,50 @@ +From a9d1c5d40a10e64c351c5154bfa58289e228be8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 11:24:11 +0800 +Subject: sctp: fix race between sctp_wait_for_connect and peeloff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit f14fe6395a8b3d961a61e138ad7b36ba3626dd4e ] + +sctp_wait_for_connect() drops and re-acquires the socket lock while +waiting for the association to reach ESTABLISHED state. During this +window, another thread can peeloff the association to a new socket via +getsockopt(SCTP_SOCKOPT_PEELOFF), changing asoc->base.sk. After +re-acquiring the old socket lock, sctp_wait_for_connect() returns +success without noticing the migration — the caller then accesses +the association under the wrong lock in sctp_datamsg_from_user(). + +Add the same sk != asoc->base.sk check that sctp_wait_for_sndbuf() +already has, returning an error if the association was migrated while +we slept. + +Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") +Signed-off-by: Zhenghang Xiao +Acked-by: Xin Long +Link: https://patch.msgid.link/20260527032411.60959-1-kipreyyy@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 2c5ad53984906c..c763eb3296b3ee 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9350,6 +9350,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) + release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + + *timeo_p = current_timeo; + } +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index 003f0fd2a1..982c70b6f8 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -3,3 +3,93 @@ net-mctp-ensure-our-nlmsg-responses-are-initialised.patch xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch bcache-fix-uninitialized-closure-object.patch +nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch +nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch +xfrm-check-for-underflow-in-xfrm_state_mtu.patch +nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch +tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch +hid-remove-duplicate-hid_warn_ratelimited-definition.patch +kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch +accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch +kernel-fork-validate-exit_signal-in-kernel_clone.patch +netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch +netfilter-xt_cpu-prefer-raw_smp_processor_id.patch +netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch +netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch +tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch +tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch +vsock-keep-poll-shutdown-state-consistent.patch +net-netlink-fix-sending-unassigned-nsid-after-assign.patch +net-netlink-don-t-set-nsid-on-local-notifications.patch +net-smc-do-not-re-initialize-smc-hashtables.patch +net-iucv-fix-locking-in-.getsockopt.patch +scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch +ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch +alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch +asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch +net-mlx5-hws-reject-unsupported-remove-header-action.patch +net-hsr-fix-potential-oob-access-in-supervision-fram.patch +gpio-mxc-fix-irq_high-handling.patch +net-team-remove-unused-team_mode_op-port_enabled.patch +net-team-rename-port_disabled-team-mode-op-to-port_t.patch +net-team-fix-null-pointer-dereference-in-team_xmit-d.patch +net-avoid-checksumming-unreadable-skb-tail-on-trim.patch +ethtool-rss-avoid-modifying-the-rss-context-response.patch +ethtool-rss-add-missing-errno-on-rss-context-delete.patch +ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch +ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch +ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch +ethtool-rss-avoid-device-context-leak-on-reply-build.patch +ethtool-module-call-ethnl_ops_complete-on-module-fla.patch +ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch +ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch +ethtool-module-check-fw_flash_in_progress-under-rtnl.patch +ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch +ethtool-cmis-require-exact-cdb-reply-length.patch +ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch +ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch +ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch +cxl-test-update-mock-dev-array-before-calling-platfo.patch +tunnels-load-network-headers-after-skb_cow-in-iptunn.patch +vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch +tunnels-do-not-assume-transport-header-in-iptunnel_p.patch +ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch +asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch +drm-xe-restore-idledly-regiter-on-engine-reset.patch +bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch +bonding-refuse-to-enslave-can-devices.patch +bridge-fix-sleep-in-atomic-context-in-netlink-path.patch +bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch +ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch +ethtool-tsconfig-fix-reply-error-handling.patch +ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch +ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch +ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch +ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch +ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch +ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch +ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch +ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch +ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch +net-sched-revert-net-sched-restrict-conditions-for-a.patch +net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch +net-handshake-use-spin_lock_bh-for-hn_lock.patch +nvme-tcp-store-negative-errno-in-queue-tls_err.patch +net-handshake-pass-negative-errno-through-handshake_.patch +bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch +bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch +bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch +bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch +gpio-adnp-fix-flow-control-regression-caused-by-scop.patch +gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch +gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch +gpio-rockchip-teardown-bugs-and-resource-leaks.patch +net-mana-add-null-guards-in-teardown-path-to-prevent.patch +net-mana-skip-redundant-detach-on-already-detached-p.patch +sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch +vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch +ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch +ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch +net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch +media-rc-fix-race-between-unregister-and-urb-irq-cal.patch +media-rc-ttusbir-fix-inverted-error-logic.patch diff --git a/queue-6.18/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch b/queue-6.18/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch new file mode 100644 index 0000000000..a3c1badaf6 --- /dev/null +++ b/queue-6.18/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch @@ -0,0 +1,40 @@ +From 695a3801af3a423d02ed4da4025350f397518f68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 11:01:26 +0800 +Subject: tools/bootconfig: Fix buf leaks in apply_xbc + +From: Hongtao Lee + +[ Upstream commit f42d01aadcedd7bbf4f9a466cabe25c1781dedad ] + +If data calloc failed, free the buf before return. + +Link: https://lore.kernel.org/all/20260520030126.147782-1-lihongtao@kylinos.cn/ + +Fixes: 950313ebf79c ("tools: bootconfig: Add bootconfig command") +Signed-off-by: Hongtao Lee +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + tools/bootconfig/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c +index 643f707b8f1da1..ddabde20585f21 100644 +--- a/tools/bootconfig/main.c ++++ b/tools/bootconfig/main.c +@@ -390,8 +390,10 @@ static int apply_xbc(const char *path, const char *xbc_path) + + /* Backup the bootconfig data */ + data = calloc(size + BOOTCONFIG_ALIGN + BOOTCONFIG_FOOTER_SIZE, 1); +- if (!data) ++ if (!data) { ++ free(buf); + return -ENOMEM; ++ } + memcpy(data, buf, size); + + /* Check the data format */ +-- +2.53.0 + diff --git a/queue-6.18/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch b/queue-6.18/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch new file mode 100644 index 0000000000..446e0d96bb --- /dev/null +++ b/queue-6.18/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch @@ -0,0 +1,47 @@ +From 6c5887a6154b0b34ab68ee1f60d28719d1bc7b75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 09:33:13 -0700 +Subject: tun: free page on build_skb failure in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit aa8963fdce667a42fb7f0bdd2909fadcab02f9a8 ] + +When build_skb() fails in tun_xdp_one(), the function sets ret to +-ENOMEM and jumps to the out label, which returns without freeing the +page that vhost_net_build_xdp() allocated for the frame. As with the +short-frame rejection path, tun_sendmsg() discards the per-buffer error +and still returns total_len, so vhost_tx_batch() takes the success path +and never frees the page. Each build_skb() failure in a batch leaks one +page-frag chunk. + +Free the page before taking the error path, matching the put_page() the +other error exits of tun_xdp_one() already perform. + +Fixes: 043d222f93ab ("tuntap: accept an array of XDP buffs through sendmsg()") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260521163312.1479805-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index afba37965ce3b7..9a767da38c71e7 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2437,6 +2437,7 @@ static int tun_xdp_one(struct tun_struct *tun, + build: + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { ++ put_page(virt_to_head_page(xdp->data)); + ret = -ENOMEM; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.18/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch b/queue-6.18/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch new file mode 100644 index 0000000000..24b2865797 --- /dev/null +++ b/queue-6.18/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch @@ -0,0 +1,54 @@ +From 767160ea23e9313076ed069880cfe3c8f799343a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:00:21 -0700 +Subject: tun: free page on short-frame rejection in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit f4feb1e20058e407cb00f45aff47f5b7e19a6bbf ] + +tun_xdp_one() returns -EINVAL on a frame shorter than ETH_HLEN without +freeing the page that vhost_net_build_xdp() allocated for it. +tun_sendmsg() discards that -EINVAL and still returns total_len, so +vhost_tx_batch() takes the success path and never frees the page; each +short frame in a batch leaks one page-frag chunk. + +A local process that can open /dev/net/tun and /dev/vhost-net can hit +this path: it attaches a tun/tap device as the vhost-net backend and +feeds TX descriptors whose length minus the virtio-net header is below +ETH_HLEN. Each kick leaks the page-frag chunks for that batch, and a +tight submission loop exhausts host memory and triggers an OOM panic. +Free the page before returning -EINVAL, matching the XDP-program error +path in the same function. + +Fixes: 049584807f1d ("tun: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260520160020.375349-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 8192740357a09c..afba37965ce3b7 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2392,8 +2392,10 @@ static int tun_xdp_one(struct tun_struct *tun, + bool skb_xdp = false; + struct page *page; + +- if (unlikely(datasize < ETH_HLEN)) ++ if (unlikely(datasize < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + return -EINVAL; ++ } + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { +-- +2.53.0 + diff --git a/queue-6.18/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch b/queue-6.18/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch new file mode 100644 index 0000000000..1002be2292 --- /dev/null +++ b/queue-6.18/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch @@ -0,0 +1,67 @@ +From 56f526ea159163503dce217ec7513fe2eb476aea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 11:55:12 +0000 +Subject: tunnels: do not assume transport header in + iptunnel_pmtud_check_icmp() + +From: Eric Dumazet + +[ Upstream commit 509323077ef79a26ba0c60bb556e45c12c398b2d ] + +In some cases, iptunnel_pmtud_check_icmp() can be called while +skb transport header is not set. + +This triggers an out-of-bound access, because +(typeof(skb->transport_header))~0U is 65535. + +Access the icmp header based on IPv4 network header, +after making sure icmp->type is present in skb linear part. + +Note that iptunnel_pmtud_check_icmpv6()) is fine. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Reported-by: Damiano Melotti +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index d5a63155a05597..4b5fd4b13722ca 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -280,7 +280,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + { +- const struct icmphdr *icmph = icmp_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); + + if (mtu < 576 || iph->frag_off != htons(IP_DF)) +@@ -291,9 +290,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr)) + return 0; + +- if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type)) +- return 0; ++ if (iph->protocol == IPPROTO_ICMP) { ++ const struct icmphdr *icmph; + ++ if (!pskb_network_may_pull(skb, iph->ihl * 4 + ++ offsetofend(struct icmphdr, type))) ++ return 0; ++ iph = ip_hdr(skb); ++ icmph = (void *)iph + iph->ihl * 4; ++ if (icmp_is_err(icmph->type)) ++ return 0; ++ } + return iptunnel_pmtud_build_icmp(skb, mtu); + } + +-- +2.53.0 + diff --git a/queue-6.18/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch b/queue-6.18/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch new file mode 100644 index 0000000000..3c3f78296b --- /dev/null +++ b/queue-6.18/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch @@ -0,0 +1,87 @@ +From b4c2edc7be9365366aba5f0547ab1d733f9f3d71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +From: Eric Dumazet + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 5683c328990f49..d5a63155a05597 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -212,7 +212,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -226,7 +226,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -236,7 +235,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -308,7 +307,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -323,7 +322,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -334,6 +332,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.53.0 + diff --git a/queue-6.18/vsock-keep-poll-shutdown-state-consistent.patch b/queue-6.18/vsock-keep-poll-shutdown-state-consistent.patch new file mode 100644 index 0000000000..8bfeb1dded --- /dev/null +++ b/queue-6.18/vsock-keep-poll-shutdown-state-consistent.patch @@ -0,0 +1,247 @@ +From 86b3cb82627f19ebd8b6921b555385e4dc773e38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 00:56:36 +0800 +Subject: vsock: keep poll shutdown state consistent + +From: Ziyu Zhang + +[ Upstream commit aae9d8a5528b8ee9ff8dc5d3558b8a9f852a724a ] + +vsock_poll() reads vsk->peer_shutdown before taking the socket lock +to set EPOLLHUP and EPOLLRDHUP, then reads it again after taking +the lock to report EOF readability. A shutdown packet can update +peer_shutdown while poll is waiting for the lock, so one poll invocation +can report EOF readability without the corresponding HUP/RDHUP bits. + +For connectible sockets, take one peer_shutdown snapshot after +lock_sock() and use it for all peer-shutdown-derived poll bits. For +datagram sockets, which do not take lock_sock() in poll(), take one +lockless READ_ONCE() snapshot and pair it with WRITE_ONCE() on the +writer side. + +This keeps the peer-shutdown-derived bits internally consistent for each +poll pass. + +Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") +Signed-off-by: Ziyu Zhang +Link: https://patch.msgid.link/20260519165636.62542-1-ziyuzhang201@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/af_vsock.c | 49 ++++++++++++++++--------- + net/vmw_vsock/hyperv_transport.c | 9 +++-- + net/vmw_vsock/virtio_transport_common.c | 14 ++++--- + net/vmw_vsock/vmci_transport.c | 8 ++-- + 4 files changed, 52 insertions(+), 28 deletions(-) + +diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c +index 9d0e1915abbe86..2db48b53e47c77 100644 +--- a/net/vmw_vsock/af_vsock.c ++++ b/net/vmw_vsock/af_vsock.c +@@ -523,7 +523,7 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) + */ + sock_reset_flag(sk, SOCK_DONE); + sk->sk_state = TCP_CLOSE; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + } + + if (sk->sk_type == SOCK_SEQPACKET) { +@@ -814,7 +814,7 @@ static struct sock *__vsock_create(struct net *net, + vsk->rejected = false; + vsk->sent_request = false; + vsk->ignore_connecting_rst = false; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout); + INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work); + +@@ -1122,6 +1122,25 @@ static int vsock_shutdown(struct socket *sock, int mode) + return err; + } + ++static __poll_t vsock_poll_shutdown(struct sock *sk, u32 peer_shutdown) ++{ ++ __poll_t mask = 0; ++ ++ /* INET sockets treat local write shutdown and peer write shutdown as a ++ * case of EPOLLHUP set. ++ */ ++ if (sk->sk_shutdown == SHUTDOWN_MASK || ++ ((sk->sk_shutdown & SEND_SHUTDOWN) && ++ (peer_shutdown & SEND_SHUTDOWN))) ++ mask |= EPOLLHUP; ++ ++ if (sk->sk_shutdown & RCV_SHUTDOWN || ++ peer_shutdown & SEND_SHUTDOWN) ++ mask |= EPOLLRDHUP; ++ ++ return mask; ++} ++ + static __poll_t vsock_poll(struct file *file, struct socket *sock, + poll_table *wait) + { +@@ -1139,24 +1158,17 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + /* Signify that there has been an error on this socket. */ + mask |= EPOLLERR; + +- /* INET sockets treat local write shutdown and peer write shutdown as a +- * case of EPOLLHUP set. +- */ +- if ((sk->sk_shutdown == SHUTDOWN_MASK) || +- ((sk->sk_shutdown & SEND_SHUTDOWN) && +- (vsk->peer_shutdown & SEND_SHUTDOWN))) { +- mask |= EPOLLHUP; +- } +- +- if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { +- mask |= EPOLLRDHUP; +- } +- + if (sk_is_readable(sk)) + mask |= EPOLLIN | EPOLLRDNORM; + + if (sock->type == SOCK_DGRAM) { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ ++ /* DGRAM sockets do not take lock_sock() in poll(), so use one ++ * lockless snapshot for all shutdown-derived mask bits. ++ */ ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); ++ + /* For datagram sockets we can read if there is something in + * the queue and write as long as the socket isn't shutdown for + * sending. +@@ -1171,6 +1183,7 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + + } else if (sock_type_connectible(sk->sk_type)) { + const struct vsock_transport *transport; ++ u32 peer_shutdown; + + lock_sock(sk); + +@@ -1203,8 +1216,10 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + * terminated should also be considered read, and we check the + * shutdown flag for that. + */ ++ peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); + if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { ++ peer_shutdown & SEND_SHUTDOWN) { + mask |= EPOLLIN | EPOLLRDNORM; + } + +diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c +index f9dc9b4d302383..4da752b47b116f 100644 +--- a/net/vmw_vsock/hyperv_transport.c ++++ b/net/vmw_vsock/hyperv_transport.c +@@ -264,7 +264,7 @@ static void hvs_do_close_lock_held(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -593,7 +593,9 @@ static int hvs_update_recv_data(struct hvsock *hvs) + return -EIO; + + if (payload_len == 0) +- hvs->vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(hvs->vsk->peer_shutdown, ++ READ_ONCE(hvs->vsk->peer_shutdown) | ++ SEND_SHUTDOWN); + + hvs->recv_data_len = payload_len; + hvs->recv_data_off = 0; +@@ -736,7 +738,8 @@ static s64 hvs_stream_has_data(struct vsock_sock *vsk) + return ret; + return hvs->recv_data_len; + case 0: +- vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | SEND_SHUTDOWN); + ret = 0; + break; + default: /* -1 */ +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index ed42e08798a967..1e07d3b1a0e800 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -1206,7 +1206,7 @@ static void virtio_transport_do_close(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -1409,12 +1409,15 @@ virtio_transport_recv_connected(struct sock *sk, + case VIRTIO_VSOCK_OP_CREDIT_UPDATE: + sk->sk_write_space(sk); + break; +- case VIRTIO_VSOCK_OP_SHUTDOWN: ++ case VIRTIO_VSOCK_OP_SHUTDOWN: { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_RCV) +- vsk->peer_shutdown |= RCV_SHUTDOWN; ++ peer_shutdown |= RCV_SHUTDOWN; + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_SEND) +- vsk->peer_shutdown |= SEND_SHUTDOWN; +- if (vsk->peer_shutdown == SHUTDOWN_MASK) { ++ peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, peer_shutdown); ++ if (peer_shutdown == SHUTDOWN_MASK) { + if (vsock_stream_has_data(vsk) <= 0 && !sock_flag(sk, SOCK_DONE)) { + (void)virtio_transport_reset(vsk, NULL); + virtio_transport_do_close(vsk, true); +@@ -1429,6 +1432,7 @@ virtio_transport_recv_connected(struct sock *sk, + if (le32_to_cpu(virtio_vsock_hdr(skb)->flags)) + sk->sk_state_change(sk); + break; ++ } + case VIRTIO_VSOCK_OP_RST: + virtio_transport_do_close(vsk, true); + break; +diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c +index 4cd11f355e9d6b..443125e48f2481 100644 +--- a/net/vmw_vsock/vmci_transport.c ++++ b/net/vmw_vsock/vmci_transport.c +@@ -811,7 +811,7 @@ static void vmci_transport_handle_detach(struct sock *sk) + /* On a detach the peer will not be sending or receiving + * anymore. + */ +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + + /* We should not be sending anymore since the peer won't be + * there to receive, but we can still receive if there is data +@@ -1534,7 +1534,9 @@ static int vmci_transport_recv_connected(struct sock *sk, + if (pkt->u.mode) { + vsk = vsock_sk(sk); + +- vsk->peer_shutdown |= pkt->u.mode; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | ++ pkt->u.mode); + sk->sk_state_change(sk); + } + break; +@@ -1551,7 +1553,7 @@ static int vmci_transport_recv_connected(struct sock *sk, + * a clean shutdown. + */ + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + +-- +2.53.0 + diff --git a/queue-6.18/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch b/queue-6.18/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch new file mode 100644 index 0000000000..ad8a4f9ef6 --- /dev/null +++ b/queue-6.18/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch @@ -0,0 +1,89 @@ +From c3c98736e7173eb7601c1bfe46787924caec6364 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 10:33:01 +0800 +Subject: vsock/virtio: bind uarg before filling zerocopy skb + +From: Jingguo Tan + +[ Upstream commit 1e584c304cfb94a759417130b1fc6d30b30c4cce ] + +virtio_transport_send_pkt_info() allocates or reuses the zerocopy uarg +before entering the send loop, but virtio_transport_alloc_skb() still +fills the skb before it inherits that uarg. When fixed-buffer vectored +zerocopy hits MAX_SKB_FRAGS, io_sg_from_iter() may partially attach +managed frags and return -EMSGSIZE. The rollback path call kfree_skb() +to free an skb that carries SKBFL_MANAGED_FRAG_REFS but no uarg, so +skb_release_data() falls through to ordinary frag unref. + +Pass the uarg into virtio_transport_alloc_skb() and bind it immediately +before virtio_transport_fill_skb(). This keeps control or no-payload skbs +untouched while ensuring success and rollback share one lifetime rule. + +Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support") +Signed-off-by: Lin Ma +Signed-off-by: Rongzhen Cui +Signed-off-by: Jingguo Tan +Acked-by: Arseniy Krasnov +Acked-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Link: https://patch.msgid.link/20260527023301.1075581-1-malin89@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/virtio_transport_common.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index 1e07d3b1a0e800..c925b5c5b35a57 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -207,6 +207,7 @@ static u16 virtio_transport_get_type(struct sock *sk) + static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info, + size_t payload_len, + bool zcopy, ++ struct ubuf_info *uarg, + u32 src_cid, + u32 src_port, + u32 dst_cid, +@@ -247,6 +248,12 @@ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info * + if (info->msg && payload_len > 0) { + int err; + ++ /* Bind the zerocopy lifetime before filling frags so error ++ * rollback frees managed fixed-buffer pages through ++ * the uarg-aware path. ++ */ ++ skb_zcopy_set(skb, uarg, NULL); ++ + err = virtio_transport_fill_skb(skb, info, payload_len, zcopy); + if (err) + goto out; +@@ -366,6 +373,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, + skb_len = min(max_skb_len, rest_len); + + skb = virtio_transport_alloc_skb(info, skb_len, can_zcopy, ++ uarg, + src_cid, src_port, + dst_cid, dst_port); + if (!skb) { +@@ -373,8 +381,6 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, + break; + } + +- skb_zcopy_set(skb, uarg, NULL); +- + virtio_transport_inc_tx_pkt(vvs, skb); + + ret = t_ops->send_pkt(skb); +@@ -1161,7 +1167,7 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t, + if (!t) + return -ENOTCONN; + +- reply = virtio_transport_alloc_skb(&info, 0, false, ++ reply = virtio_transport_alloc_skb(&info, 0, false, NULL, + le64_to_cpu(hdr->dst_cid), + le32_to_cpu(hdr->dst_port), + le64_to_cpu(hdr->src_cid), +-- +2.53.0 + diff --git a/queue-6.18/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch b/queue-6.18/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch new file mode 100644 index 0000000000..b922546b5f --- /dev/null +++ b/queue-6.18/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch @@ -0,0 +1,54 @@ +From 3897216ca1fc418d3628857218bb08c04317baac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:36:42 +0000 +Subject: vxlan: do not reuse cached ip_hdr() value after + skb_tunnel_check_pmtu() + +From: Eric Dumazet + +[ Upstream commit 7d9ef0cb271555d8cf39fefe6c981e1493b25ecf ] + +skb_tunnel_check_pmtu() can change skb->head. + +Reusing old_iph afer skb_tunnel_check_pmtu() can cause an UAF. + +Use instead ip_hdr(skb) as done in drivers/net/bareudp.c +and drivers/net/geneve.c. + +Found by Sashiko. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525203642.2389723-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index d2d0e0bd43716c..a4ff66e354f532 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2532,7 +2532,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), + vni, md, flags, udp_sum); +@@ -2606,7 +2606,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip6_dst_hoplimit(ndst); + skb_scrub_packet(skb, xnet); + err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), +-- +2.53.0 + diff --git a/queue-6.18/xfrm-check-for-underflow-in-xfrm_state_mtu.patch b/queue-6.18/xfrm-check-for-underflow-in-xfrm_state_mtu.patch new file mode 100644 index 0000000000..94518e8d01 --- /dev/null +++ b/queue-6.18/xfrm-check-for-underflow-in-xfrm_state_mtu.patch @@ -0,0 +1,85 @@ +From 806f98afcdf628e7f1744c8b16d910975d22c286 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 10:49:14 -0600 +Subject: xfrm: Check for underflow in xfrm_state_mtu + +From: David Ahern + +[ Upstream commit 742b04d0550b0ec89dcbc99537ec88653bd1ad90 ] + +Leo Lin reported OOB write issue in esp component: + + xfrm_state_mtu() returns u32 but performs its arithmetic in unsigned + modulo-2^32 space using an attacker-influenced "header_len + authsize + + net_adj" subtracted from a small "mtu" argument. A nobody user can + install an IPv4 ESP tunnel SA with a large authentication key + (XFRMA_ALG_AUTH_TRUNC, e.g. hmac(sha512), 64-byte key, 64-byte trunc), + configure a small interface MTU (68 bytes), and set XFRMA_TFCPAD to a + large value. When a single UDP datagram is then sent through the + tunnel, xfrm_state_mtu() underflows to a near-2^32 value, and + esp_output() consumes it as a signed int via: + + padto = min(x->tfcpad, xfrm_state_mtu(x, mtu_cached)) + esp.tfclen = padto - skb->len (assigned to int) + + esp.tfclen ends up negative (e.g. -207). It is sign-extended to size_t + when passed to memset() inside esp_output_fill_trailer(), producing a + ~16 EB write of zeroes at skb_tail_pointer(skb). KASAN logs it as + "Write of size 18446744073709551537 at addr ffff888...". + +Check for underflow and return 1. This causes the sendmsg attempt to +fail with ENETUNREACH. + +Fixes: c5c252389374 ("[XFRM]: Optimize MTU calculation") +Reported-by: Leo Lin +Assisted-by: Codex:26.506.31004 +Signed-off-by: David Ahern +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_state.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index f6ba58f18ac18e..1b81e92e3eee78 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -3113,10 +3113,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + const struct xfrm_type *type = READ_ONCE(x->type); + struct crypto_aead *aead; + u32 blksize, net_adj = 0; ++ u32 overhead, payload_mtu; + + if (x->km.state != XFRM_STATE_VALID || +- !type || type->proto != IPPROTO_ESP) ++ !type || type->proto != IPPROTO_ESP) { ++ if (mtu <= x->props.header_len) ++ return 1; + return mtu - x->props.header_len; ++ } + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); +@@ -3139,8 +3143,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + break; + } + +- return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - +- net_adj) & ~(blksize - 1)) + net_adj - 2; ++ overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj; ++ if (mtu <= overhead) ++ return 1; ++ ++ payload_mtu = mtu - overhead; ++ payload_mtu &= ~(blksize - 1); ++ if (payload_mtu <= 2) ++ return 1; ++ ++ return payload_mtu + net_adj - 2; ++ + } + EXPORT_SYMBOL_GPL(xfrm_state_mtu); + +-- +2.53.0 + diff --git a/queue-6.6/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch b/queue-6.6/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch new file mode 100644 index 0000000000..7edcdd0173 --- /dev/null +++ b/queue-6.6/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch @@ -0,0 +1,47 @@ +From c7726f90e5dfa49ae7d153dba4eb96edb5518569 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 09:24:00 -0300 +Subject: ASoC: codecs: simple-mux: Fix enum control bounds check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit f63ad68e18d774a5d15cd7e405ead63f6b322679 ] + +simple_mux_control_put() rejects values greater than e->items, but +enum control values are zero based. For the two-entry mux used by this +driver, valid values are 0 and 1, so value 2 must be rejected as well. + +Accepting e->items can store an invalid mux state, pass it to the GPIO +setter, and pass it on to the DAPM mux update path where it is used as +an index into the enum text array. + +Use the same >= e->items check used by the ASoC enum helpers. + +Fixes: 342fbb7578d1 ("ASoC: add simple-mux") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260527-asoc-simple-mux-enum-bounds-v1-1-3f805b9fc671@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/simple-mux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c +index bf67de12d20b7f..02ccaa4c9a0804 100644 +--- a/sound/soc/codecs/simple-mux.c ++++ b/sound/soc/codecs/simple-mux.c +@@ -40,7 +40,7 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + +- if (ucontrol->value.enumerated.item[0] > e->items) ++ if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + if (priv->mux == ucontrol->value.enumerated.item[0]) +-- +2.53.0 + diff --git a/queue-6.6/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch b/queue-6.6/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch new file mode 100644 index 0000000000..c94234f58e --- /dev/null +++ b/queue-6.6/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch @@ -0,0 +1,112 @@ +From 039fc69523512acd9447a888c2a337e968467e94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 13:51:47 -0300 +Subject: ASoC: Intel: bytcht_es8316: Fix MCLK leak on init errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit afb2a3a9d8369d18122a0d7cd294eba9a98259c6 ] + +byt_cht_es8316_init() enables MCLK before configuring the codec sysclk +and creating the headset jack. If either of those later steps fails, the +function returns without disabling MCLK, leaving the clock enabled after +card registration fails. + +Track whether this driver enabled MCLK and disable it on the init error +paths. Add the matching DAI link exit callback so the same clock enable +is also balanced when ASoC cleans up a successfully initialized link. + +Fixes: a03bdaa565cb ("ASoC: Intel: add machine driver for BYT/CHT + ES8316") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-asoc-bytcht-es8316-mclk-leak-v1-1-b4a11cdc2afd@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_es8316.c | 29 ++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index fbd7e1f0783fd9..d334d748f76fb0 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -39,6 +39,7 @@ struct byt_cht_es8316_private { + struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; + bool speaker_en; ++ bool mclk_enabled; + }; + + enum { +@@ -169,6 +170,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + }, + }; + ++static void byt_cht_es8316_disable_mclk(struct byt_cht_es8316_private *priv) ++{ ++ if (!priv->mclk_enabled) ++ return; ++ ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++} ++ + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + { + struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component; +@@ -225,12 +235,14 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); ++ else ++ priv->mclk_enabled = true; + + ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset", +@@ -239,13 +251,25 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; ++ ++err_disable_mclk: ++ byt_cht_es8316_disable_mclk(priv); ++ return ret; ++} ++ ++static void byt_cht_es8316_exit(struct snd_soc_pcm_runtime *runtime) ++{ ++ struct snd_soc_card *card = runtime->card; ++ struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); ++ ++ byt_cht_es8316_disable_mclk(priv); + } + + static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -355,6 +379,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, ++ .exit = byt_cht_es8316_exit, + SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), + }, + }; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch b/queue-6.6/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch new file mode 100644 index 0000000000..0b96487c72 --- /dev/null +++ b/queue-6.6/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch @@ -0,0 +1,40 @@ +From 1030ebb9fe7fdb4d9a59ec56cd58a2ef59f300b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 11:21:39 +0800 +Subject: Bluetooth: 6lowpan: check skb_clone() return value in + send_mcast_pkt() + +From: Zhao Dongdong + +[ Upstream commit 3c40d381ce04f9575a5d8b542898183c3b4b38dc ] + +The skb_clone() function can return NULL if memory allocation fails. +send_mcast_pkt() calls skb_clone() without checking the return value, which +can lead to a NULL pointer dereference in send_pkt() when it dereferences +skb->data. +Add a NULL check after skb_clone() and skip the peer if the clone fails. + +Fixes: 18722c247023 ("Bluetooth: Enable 6LoWPAN support for BT LE devices") +Signed-off-by: Zhao Dongdong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/6lowpan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index e65d4754c94f4c..b3132079573d4d 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -485,6 +485,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) + int ret; + + local_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!local_skb) ++ continue; + + BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p", + netdev->name, +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch b/queue-6.6/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch new file mode 100644 index 0000000000..8a51833cfc --- /dev/null +++ b/queue-6.6/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch @@ -0,0 +1,62 @@ +From 70d428f6357dc6f750dd9b44a3925956066ea5a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:51:52 +0800 +Subject: Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success + +From: Zhenghang Xiao + +[ Upstream commit 00e1950716c6ed67d74777b2db286b0fa23b4be9 ] + +l2cap_ecred_reconf_rsp() returns early on success without clearing +chan->ident. Every other L2CAP response handler (l2cap_ecred_conn_rsp, +l2cap_le_connect_rsp, l2cap_config_rsp) clears chan->ident after a +successful transaction to prevent the channel from matching subsequent +responses with the recycled ident value. + +A remote attacker that completed a reconfiguration as the peer can +replay a failure response with the stale ident, causing the kernel to +match and destroy the already-established channel via +l2cap_chan_del(chan, ECONNRESET). + +Clear chan->ident for all matching channels on success, and harden the +failure path by using l2cap_chan_hold_unless_zero() consistent with +other L2CAP handlers (l2cap_le_command_rej, __l2cap_get_chan_by_ident). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index bbaf0070ca6176..0295a18a1cb3d7 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5393,14 +5393,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + + BT_DBG("result 0x%4.4x", result); + +- if (!result) ++ if (!result) { ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ if (chan->ident == cmd->ident) ++ chan->ident = 0; ++ } + return 0; ++ } + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + if (chan->ident != cmd->ident) + continue; + +- l2cap_chan_hold(chan); ++ if (!l2cap_chan_hold_unless_zero(chan)) ++ continue; + l2cap_chan_lock(chan); + + l2cap_chan_del(chan, ECONNRESET); +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch b/queue-6.6/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch new file mode 100644 index 0000000000..731b7b5236 --- /dev/null +++ b/queue-6.6/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch @@ -0,0 +1,82 @@ +From 07b8edce9a6ce1d862196700267295326a8ae5e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 12:09:42 -0400 +Subject: Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp + +From: Luiz Augusto von Dentz + +[ Upstream commit 41c2713b204e6cb6a94587bc6bf6935107df5479 ] + +If dcid is received for an already-assigned destination CID the spec +requires that both channels to be discarded, but calling l2cap_chan_del +may invalidate the tmp cursor created by list_for_each_entry_safe and +in fact it is the wrong procedure as the chan->dcid may be assigned +previously it really needs to be disconnected. + +Calling l2cap_chan_clone directly may still lead to l2cap_chan_del so +instead schedule l2cap_chan_timeout with delay 0 to close the channel +asynchronously. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 0295a18a1cb3d7..1f5d5343d380e4 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5195,6 +5195,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct l2cap_chan *orig; + u16 dcid; + + if (chan->ident != cmd->ident || +@@ -5216,8 +5217,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + + BT_DBG("dcid[%d] 0x%4.4x", i, dcid); + ++ orig = __l2cap_get_chan_by_dcid(conn, dcid); ++ + /* Check if dcid is already in use */ +- if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { ++ if (dcid && orig) { + /* If a device receives a + * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an + * already-assigned Destination CID, then both the +@@ -5226,10 +5229,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + */ + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); +- chan = __l2cap_get_chan_by_dcid(conn, dcid); +- l2cap_chan_lock(chan); +- l2cap_chan_del(chan, ECONNRESET); +- l2cap_chan_unlock(chan); ++ ++ /* Check that the dcid channel mode is ++ * L2CAP_MODE_EXT_FLOWCTL since this procedure is only ++ * valid for that mode and shouldn't disconnect a dcid ++ * in other modes. ++ */ ++ if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) { ++ l2cap_chan_lock(orig); ++ /* Disconnect the original channel as it may be ++ * considered connected since dcid has already ++ * been assigned; don't call l2cap_chan_close ++ * directly since that could lead to ++ * l2cap_chan_del and then removing the channel ++ * from the list while we're iterating over it. ++ */ ++ __set_chan_timer(orig, 0); ++ l2cap_chan_unlock(orig); ++ } + continue; + } + +-- +2.53.0 + diff --git a/queue-6.6/bonding-refuse-to-enslave-can-devices.patch b/queue-6.6/bonding-refuse-to-enslave-can-devices.patch new file mode 100644 index 0000000000..71ba947e5d --- /dev/null +++ b/queue-6.6/bonding-refuse-to-enslave-can-devices.patch @@ -0,0 +1,74 @@ +From 3f560f582a0e428c250d53768d4087a68701d8d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:33:19 +0200 +Subject: bonding: refuse to enslave CAN devices + +From: Oliver Hartkopp + +[ Upstream commit 8ba68464e4787b6a7ec938826e16124df20fd23d ] + +syzbot reported a kernel paging request crash in +can_rx_unregister() inside net/can/af_can.c. The crash occurs +because a virtual CAN device (vxcan) is being enslaved to a +bonding master. + +During the enslavement process, the bonding driver mutates +and modifies the network device states to fit an Ethernet-like +aggregation model. However, CAN devices operate on a completely +different Layer 2 architecture, relying on the CAN mid-layer +private data structure (can_ml_priv) instead of standard +Ethernet structures. Since bonding does not initialize or +maintain these CAN structures, subsequent operations on the +half-enslaved interface (such as closing associated sockets +via isotp_release) lead to a null-pointer dereference when +accessing the CAN receiver lists. + +Bonding CAN interfaces is architecturally invalid as CAN lacks +MAC addresses, ARP capabilities, and standard Ethernet +link-layer mechanisms. While generic loopback devices are +blocked globally in net/core/dev.c, virtual CAN devices +bypass this check because they do not carry the IFF_LOOPBACK +flag, despite acting as local software-loopbacks. + +Fix this by explicitly blocking network devices of type +ARPHRD_CAN from being enslaved at the very beginning of +bond_enslave(). This prevents illegal state mutations, +eliminates the resulting KASAN crashes, and avoids potential +memory leaks from incomplete socket cleanups. + +As the CAN support has been added a long time after bonding +the Fixes-tag points to the introduction of ARPHRD_CAN that +would have needed a specific handling in bonding_main.c. + +Fixes: cd05acfe65ed ("[CAN]: Allocate protocol numbers for PF_CAN") +Reported-by: syzbot+8ed98cbd0161632bce95@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8ed98cbd0161632bce95 +Signed-off-by: Oliver Hartkopp +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260526-bonding-candev-v1-1-ba1df400918a@hartkopp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 029a7f001dd8a0..7732f7023033ed 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1889,6 +1889,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, + int link_reporting; + int res = 0, i; + ++ if (slave_dev->type == ARPHRD_CAN) { ++ BOND_NL_ERR(bond_dev, extack, ++ "CAN devices cannot be enslaved"); ++ return -EPERM; ++ } ++ + if (slave_dev->flags & IFF_MASTER && + !netif_is_bond_master(slave_dev)) { + BOND_NL_ERR(bond_dev, extack, +-- +2.53.0 + diff --git a/queue-6.6/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch b/queue-6.6/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch new file mode 100644 index 0000000000..3d031f4ae1 --- /dev/null +++ b/queue-6.6/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch @@ -0,0 +1,48 @@ +From af8f6a69281db87e06a62d37f331b285c893aaaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:32 -0700 +Subject: ethtool: eeprom: add missing ethnl_ops_begin() / _complete() during + fallback + +From: Jakub Kicinski + +[ Upstream commit 2376586f85f972fefe701f095bb37dcfe7405d21 ] + +All ethtool driver op calls should be sandwiched between +ethnl_ops_begin() / ethnl_ops_complete(). In Netlink eeprom code, +if the paged access failed we fall back to old API, but we +first call _complete() and the fallback never does its own +ethnl_ops_begin(). Move the fallback into the _begin() / _complete() +section. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-10-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 6209c3a9c8f723..15546f2a5e4583 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -134,12 +134,11 @@ static int eeprom_prepare_data(const struct ethnl_req_info *req_base, + return 0; + + err_ops: ++ if (ret == -EOPNOTSUPP) ++ ret = eeprom_fallback(request, reply); + ethnl_ops_complete(dev); + err_free: + kfree(page_data.data); +- +- if (ret == -EOPNOTSUPP) +- return eeprom_fallback(request, reply); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.6/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch b/queue-6.6/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch new file mode 100644 index 0000000000..7ecdf45504 --- /dev/null +++ b/queue-6.6/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch @@ -0,0 +1,62 @@ +From 740b8577bd6cfabd23459eb3304cb6feeebeaaa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:33 -0700 +Subject: ethtool: eeprom: add more safeties to EEPROM Netlink fallback + +From: Jakub Kicinski + +[ Upstream commit 67cfdd9210b99f260b3e0afeb9525e0acc7be31e ] + +The Netlink fallback path for reading module EEPROM +(fallback_set_params()) validates that offset < eeprom_len, +but does not check that offset + length stays within eeprom_len. +The ioctl equivalent (ethtool_get_any_eeprom() in ioctl.c) has +always enforced both bounds: + + if (eeprom.offset + eeprom.len > total_len) + return -EINVAL; + +This could lead to surprises in both drivers and device FW. +Add the missing offset + length validation to fallback_set_params(), +mirroring the ioctl. + +Similarly - ethtool core in general, and ethtool_get_any_eeprom() +in particular tries to zero-init all buffers passed to the drivers +to avoid any extra work of zeroing things out. eeprom_fallback() +uses a plain kmalloc(), change it to zalloc. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-11-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 15546f2a5e4583..4e864824b64d28 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -43,6 +43,9 @@ static int fallback_set_params(struct eeprom_req_info *request, + if (offset >= modinfo->eeprom_len) + return -EINVAL; + ++ if (length > modinfo->eeprom_len - offset) ++ return -EINVAL; ++ + eeprom->cmd = ETHTOOL_GMODULEEEPROM; + eeprom->len = length; + eeprom->offset = offset; +@@ -68,7 +71,7 @@ static int eeprom_fallback(struct eeprom_req_info *request, + if (err < 0) + return err; + +- data = kmalloc(eeprom.len, GFP_KERNEL); ++ data = kzalloc(eeprom.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + err = ethtool_get_module_eeprom_call(dev, &eeprom, data); +-- +2.53.0 + diff --git a/queue-6.6/gpio-mxc-fix-irq_high-handling.patch b/queue-6.6/gpio-mxc-fix-irq_high-handling.patch new file mode 100644 index 0000000000..41e6328633 --- /dev/null +++ b/queue-6.6/gpio-mxc-fix-irq_high-handling.patch @@ -0,0 +1,38 @@ +From 189e711347181b3d03c83f45eff0894bb817dbd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:01 +0200 +Subject: gpio: mxc: fix irq_high handling + +From: Alexander Stein + +[ Upstream commit dac917ed5aead741004db8d0d5151dd577802df8 ] + +If port->irq_high is -1 (fsl,imx21-gpio compatible) and gpio_idx is >= 16 +enable_irq_wake() is called with -1 which is wrong. + +Fixes: 5f6d1998adeb ("gpio: mxc: release the parent IRQ in runtime suspend") +Signed-off-by: Alexander Stein +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260526063504.25916-1-alexander.stein@ew.tq-group.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mxc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c +index 3cdc2b218a86af..a8ab78ae7fa30c 100644 +--- a/drivers/gpio/gpio-mxc.c ++++ b/drivers/gpio/gpio-mxc.c +@@ -473,7 +473,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) + * the handler is needed only once, but doing it for every port + * is more robust and easier. + */ +- port->irq_high = -1; ++ port->irq_high = 0; + port->mx_irq_handler = mx2_gpio_irq_handler; + } else + port->mx_irq_handler = mx3_gpio_irq_handler; +-- +2.53.0 + diff --git a/queue-6.6/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch b/queue-6.6/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch new file mode 100644 index 0000000000..8b9abed988 --- /dev/null +++ b/queue-6.6/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch @@ -0,0 +1,78 @@ +From aae89ddf77742bfd1e38c2e3735bce14a2545110 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:45 +0200 +Subject: gpio: rockchip: convert bank->clk to devm_clk_get_enabled() + +From: Marco Scardovi + +[ Upstream commit 3e46c18d5d87f063a93ae0fe7662fbf6660459d5 ] + +The bank->clk was previously obtained via of_clk_get() and manually +prepared/enabled. However, it was missing a corresponding clk_put() in +both the error paths and the remove function, leading to a reference leak. + +Convert the allocation to devm_clk_get_enabled(), which also properly +propagates failures from clk_prepare_enable() that were previously ignored. + +The GPIO bank device uses the same OF node as the previous of_clk_get() +call, so devm_clk_get_enabled(dev, NULL) correctly resolves the same +clock provider entry. + +Fix the reference leak and simplify the code by removing the manual +clk_disable_unprepare() calls in the probe error paths and in the +remove function. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index 752bbc0c3d9db1..ff9a4b8611d7f4 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -647,11 +647,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + if (!bank->irq) + return -EINVAL; + +- bank->clk = of_clk_get(bank->of_node, 0); ++ bank->clk = devm_clk_get_enabled(bank->dev, NULL); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + +- clk_prepare_enable(bank->clk); + id = readl(bank->reg_base + gpio_regs_v2.version_id); + + /* If not gpio v2, that is default to v1. */ +@@ -661,7 +660,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + bank->db_clk = of_clk_get(bank->of_node, 1); + if (IS_ERR(bank->db_clk)) { + dev_err(bank->dev, "cannot find debounce clk\n"); +- clk_disable_unprepare(bank->clk); + return -EINVAL; + } + } else { +@@ -735,7 +733,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev) + + ret = rockchip_gpiolib_register(bank); + if (ret) { +- clk_disable_unprepare(bank->clk); + mutex_unlock(&bank->deferred_lock); + return ret; + } +@@ -776,7 +773,6 @@ static int rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + +- clk_disable_unprepare(bank->clk); + gpiochip_remove(&bank->gpio_chip); + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch b/queue-6.6/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch new file mode 100644 index 0000000000..a4fc69b2be --- /dev/null +++ b/queue-6.6/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch @@ -0,0 +1,48 @@ +From 886d2b8dfd6a7279a446fc799e44f0dbde61aab3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 12:21:47 +0000 +Subject: ipv4: free net->ipv4.sysctl_local_reserved_ports after + unregister_net_sysctl_table() + +From: Eric Dumazet + +[ Upstream commit 87a1e0fe7776da7ab411be332b4be58ac8840d10 ] + +ipv4_sysctl_exit_net() is currently freeing net->ipv4.sysctl_local_reserved_ports +too soon. + +Only after unregister_net_sysctl_table() we can be sure no threads can possibly +use the sysctls, including /proc/sys/net/ipv4/ip_local_reserved_ports. + +Fixes: 122ff243f5f1 ("ipv4: make ip_local_reserved_ports per netns") +Reported-by: Ji'an Zhou +Signed-off-by: Eric Dumazet +Cc: Cong Wang +Reviewed-by: Jason Xing +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521122147.3584624-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/sysctl_net_ipv4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 96f1b8d39fac11..9c827751dad6a7 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -1560,10 +1560,10 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net) + { + struct ctl_table *table; + +- kfree(net->ipv4.sysctl_local_reserved_ports); + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); ++ kfree(net->ipv4.sysctl_local_reserved_ports); + } + + static __net_initdata struct pernet_operations ipv4_sysctl_ops = { +-- +2.53.0 + diff --git a/queue-6.6/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch b/queue-6.6/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch new file mode 100644 index 0000000000..2c8cffb571 --- /dev/null +++ b/queue-6.6/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch @@ -0,0 +1,49 @@ +From 1c232a559021e5a1c16a20cd4ed20ef861acd3c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:31 +0800 +Subject: ipv6: fix possible infinite loop in fib6_select_path() + +From: Jiayuan Chen + +[ Upstream commit 9c7da87c2dc860bb17ca1ece942495d28b1ce3b9 ] + +Found while auditing the same pattern Sashiko reported in +rt6_fill_node() [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&first->fib6_siblings) +without waiting for RCU readers; first->fib6_siblings.next then +still points into the old ring and this softirq-side walker never +reaches &first->fib6_siblings as its terminator. fib6_purge_rt() +always WRITE_ONCE()s first->fib6_nsiblings to 0 before +list_del_rcu(), so an inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 69659f2a6aea96..6d80e17c04c0d8 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -484,6 +484,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res, + const struct fib6_nh *nh = sibling->fib6_nh; + int nh_upper_bound; + ++ if (!READ_ONCE(first->fib6_nsiblings)) ++ break; ++ + nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); + if (hash > nh_upper_bound) + continue; +-- +2.53.0 + diff --git a/queue-6.6/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch b/queue-6.6/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch new file mode 100644 index 0000000000..329c11bd63 --- /dev/null +++ b/queue-6.6/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch @@ -0,0 +1,47 @@ +From 55d1d536cb1a7ca9a1552cd4c9ee3a0d3bcd2dba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:30 +0800 +Subject: ipv6: fix possible infinite loop in rt6_fill_node() + +From: Jiayuan Chen + +[ Upstream commit 9f72412bcf60144f252b0d6205106abf14344abc ] + +Sashiko reported this issue [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&rt->fib6_siblings) +without waiting for RCU readers; rt->fib6_siblings.next then still +points into the old ring and this softirq-side walker never reaches +&rt->fib6_siblings, causing a CPU stall. fib6_del_route() always +WRITE_ONCE()s rt->fib6_nsiblings to 0 before list_del_rcu(), so an +inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index c5b71baf95e7b3..69659f2a6aea96 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -5797,6 +5797,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, + + goto nla_put_failure; + } ++ if (!READ_ONCE(rt->fib6_nsiblings)) ++ break; + } + + rcu_read_unlock(); +-- +2.53.0 + diff --git a/queue-6.6/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch b/queue-6.6/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch new file mode 100644 index 0000000000..37cc7ded98 --- /dev/null +++ b/queue-6.6/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch @@ -0,0 +1,62 @@ +From 9d6d5a9a8501b4999151b8fb7b4f4089edd4aa5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 21:10:31 +0530 +Subject: ipv6: rpl: fix hdrlen overflow in ipv6_rpl_srh_decompress() + +From: Rahul Chandelkar + +[ Upstream commit 9d5e7a46a9f6d8f503b41bfefef70659845f1679 ] + +ipv6_rpl_srh_decompress() computes: + + outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3); + +hdrlen is __u8. For n >= 127 the result exceeds 255 and silently +truncates. With n=127 (cmpri=15, cmpre=15, pad=0, hdrlen=16): + + (128 * 16) >> 3 = 256, truncated to 0 as __u8 + +The caller in ipv6_rpl_srh_rcv() then places the compressed header +at buf + ((ohdr->hdrlen + 1) << 3). With hdrlen=0 this is buf + 8, +but the decompressed region occupies buf[0..2055] (8-byte header +plus 128 full addresses). The compressed header overlaps the +decompressed data, and ipv6_rpl_srh_compress() writes into this +overlap, corrupting the routing header of the forwarded packet. + +The existing guard at exthdrs.c:546 checks (n + 1) > 255, which +prevents n+1 from overflowing unsigned char (the segments_left +field), but does not prevent the computed hdrlen from overflowing +__u8. n=127 passes because 128 <= 255, yet hdrlen=256 does not +fit. + +Tighten the bound to (n + 1) > 127. This caps n at 126, giving +hdrlen = (127 * 16) >> 3 = 254, which fits in __u8. The compressed +header then lands at buf + ((254 + 1) << 3) = buf + 2040, exactly +past the decompressed region (buf[0..2039]). No overlap. 127 +segments is well beyond any realistic RPL deployment. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Signed-off-by: Rahul Chandelkar +Link: https://patch.msgid.link/20260525154031.2290876-1-rc@rexion.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/exthdrs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 54e71623aac9cc..e1d632c12cc46a 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -546,7 +546,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + * unsigned char which is segments_left field. Should not be + * higher than that. + */ +- if (r || (n + 1) > 255) { ++ if (r || (n + 1) > 127) { + kfree_skb(skb); + return -1; + } +-- +2.53.0 + diff --git a/queue-6.6/kernel-fork-validate-exit_signal-in-kernel_clone.patch b/queue-6.6/kernel-fork-validate-exit_signal-in-kernel_clone.patch new file mode 100644 index 0000000000..d542ba6298 --- /dev/null +++ b/queue-6.6/kernel-fork-validate-exit_signal-in-kernel_clone.patch @@ -0,0 +1,116 @@ +From 36851a9ce229b214ca137515fd27a44d87e2f55a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 20:49:56 +0530 +Subject: kernel/fork: validate exit_signal in kernel_clone() + +From: Deepanshu Kartikey + +[ Upstream commit 09e7827e785729f391c8d46dc71becce70d296ab ] + +When a child process exits, it sends exit_signal to its parent via +do_notify_parent(). The clone() syscall constructs exit_signal as: + +(lower_32_bits(clone_flags) & CSIGNAL) + +CSIGNAL is 0xff, so values in the range 65-255 are possible. However, +valid_signal() only accepts signals up to _NSIG (64 on x86_64). A +non-zero non-valid exit_signal acts the same as exit_signal == 0: the +parent process is not signaled when the child terminates. + +The syzkaller reproducer triggers this by calling clone() with flags=0x80, +resulting in exit_signal = (0x80 & CSIGNAL) = 128, which exceeds _NSIG and +is not a valid signal. + +The v1 of this patch added the check only in the clone() syscall handler, +which is incomplete. kernel_clone() has other callers such as +sys_ia32_clone() which would remain unprotected. Move the check to +kernel_clone() to cover all callers. + +Since the valid_signal() check is now in kernel_clone() and covers all +callers including clone3(), the same check in copy_clone_args_from_user() +becomes redundant and is removed. The higher 32bits check for clone3() is +kept as it is clone3() specific. + +Note that this is a user-visible change: previously, passing an invalid +exit_signal to clone() was silently accepted. The man page for clone() +does not document any defined behavior for invalid exit_signal values, so +rejecting them with -EINVAL is the correct behavior. It is unlikely that +any sane application relies on passing an invalid exit_signal. + +[oleg@redhat.com: the comment above kernel_clone() should be updated] + Link: https://lore.kernel.org/abwvgU17W8wuW2-J@redhat.com +Link: https://lore.kernel.org/20260316151956.563558-1-kartikey406@gmail.com +Fixes: 3f2c788a1314 ("fork: prevent accidental access to clone3 features") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Oleg Nesterov +Reported-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=bbe6b99feefc3a0842de +Tested-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20260307064202.353405-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20260316104536.558108-1-kartikey406@gmail.com/T/ [v2] +Acked-by: Oleg Nesterov +Acked-by: Michal Hocko +Cc: Ben Segall +Cc: Christian Brauner +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Cc: Tetsuo Handa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index e280f02b6446ab..d68d40735a082a 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -2870,8 +2870,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node) + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. +- * +- * args->exit_signal is expected to be checked for sanity by the caller. + */ + pid_t kernel_clone(struct kernel_clone_args *args) + { +@@ -2896,6 +2894,9 @@ pid_t kernel_clone(struct kernel_clone_args *args) + (args->pidfd == args->parent_tid)) + return -EINVAL; + ++ if (!valid_signal(args->exit_signal)) ++ return -EINVAL; ++ + /* + * Determine whether and which event to report to ptracer. When + * called from kernel_thread or CLONE_UNTRACED is explicitly +@@ -3098,11 +3099,9 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs, + return -EINVAL; + + /* +- * Verify that higher 32bits of exit_signal are unset and that +- * it is a valid signal ++ * Verify that higher 32bits of exit_signal are unset + */ +- if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) || +- !valid_signal(args.exit_signal))) ++ if (unlikely(args.exit_signal & ~((u64)CSIGNAL))) + return -EINVAL; + + if ((args.flags & CLONE_INTO_CGROUP) && +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch b/queue-6.6/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch new file mode 100644 index 0000000000..17745dbbb5 --- /dev/null +++ b/queue-6.6/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch @@ -0,0 +1,69 @@ +From 8b8b43d74f66682ed56b0d553934ce970cc1f9ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 22:07:16 +0900 +Subject: ksmbd: fix FSCTL permission bypass by adding a permission check for + FSCTL_SET_SPARSE + +From: Sean Shen + +[ Upstream commit cc57232cae23c0df91b4a59d0f519141ce9b5b02 ] + +FSCTL_SET_SPARSE in fsctl_set_sparse() modifies the file's sparse +attribute and saves it through xattr without any permission checks. + +This exposes two issues: + +1) A client on a read-only share can change the sparse attribute + on files it opened, even though the share is read-only. + Other FSCTL write operations already check + test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE), + but FSCTL_SET_SPARSE does not. + +2) Even on writable shares, clients without FILE_WRITE_DATA or + FILE_WRITE_ATTRIBUTES access should not modify the sparse + attribute. Similar handle-level checks exist in other functions + but are missing here. + +Add both share-level writable check and per-handle access check. +Use goto out on error to avoid leaking file references. + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: Namjae Jeon +Cc: Sergey Senozhatsky +Cc: Steve French +Signed-off-by: Sean Shen +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 04d4a784deaf98..97b03f76741ef2 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -8067,9 +8067,20 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id, + int ret = 0; + __le32 old_fattr; + ++ if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { ++ ksmbd_debug(SMB, "User does not have write permission\n"); ++ return -EACCES; ++ } ++ + fp = ksmbd_lookup_fd_fast(work, id); + if (!fp) + return -ENOENT; ++ ++ if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_WRITE_ATTRIBUTES_LE))) { ++ ret = -EACCES; ++ goto out; ++ } ++ + idmap = file_mnt_idmap(fp->filp); + + old_fattr = fp->f_ci->m_fattr; +-- +2.53.0 + diff --git a/queue-6.6/net-hsr-fix-potential-oob-access-in-supervision-fram.patch b/queue-6.6/net-hsr-fix-potential-oob-access-in-supervision-fram.patch new file mode 100644 index 0000000000..5d393491a4 --- /dev/null +++ b/queue-6.6/net-hsr-fix-potential-oob-access-in-supervision-fram.patch @@ -0,0 +1,48 @@ +From fbc479667b40efe1a5a50ad2cb7b73f49fa07a3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 15:03:30 +0200 +Subject: net: hsr: fix potential OOB access in supervision frame handling + +From: Luka Gejak + +[ Upstream commit f229426072fc865654a60978bb7fda790a051ff3 ] + +Ensure the entire TLV header is linearized before access by adding +sizeof(struct hsr_sup_tlv) to the pskb_may_pull() calls. Without this, +a truncated frame could cause an out-of-bounds access. + +Fixes: eafaa88b3eb7 ("net: hsr: Add support for redbox supervision frames") +Signed-off-by: Luka Gejak +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260523130330.61880-1-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_forward.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c +index 3852fd99509f04..7a596c4f603e2d 100644 +--- a/net/hsr/hsr_forward.c ++++ b/net/hsr/hsr_forward.c +@@ -84,7 +84,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* Get next tlv */ + total_length += hsr_sup_tag->tlv.HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + skb_pull(skb, total_length); + hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data; +@@ -100,7 +100,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* make sure another tlv follows */ + total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tlv->HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + + /* get next tlv */ +-- +2.53.0 + diff --git a/queue-6.6/net-iucv-fix-locking-in-.getsockopt.patch b/queue-6.6/net-iucv-fix-locking-in-.getsockopt.patch new file mode 100644 index 0000000000..16163460be --- /dev/null +++ b/queue-6.6/net-iucv-fix-locking-in-.getsockopt.patch @@ -0,0 +1,87 @@ +From fcedd3c64a715fe10a9393ea4bf5db31437f4ea4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 07:11:45 -0700 +Subject: net/iucv: fix locking in .getsockopt + +From: Breno Leitao + +[ Upstream commit 3589d20a666caf30ad100c960a2de7de390fce88 ] + +Mirror iucv_sock_setsockopt() and wrap the whole switch in +lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock +becomes redundant and is removed. + +Any AF_IUCV HIPER user can potentially crash the kernel by racing +recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences +iucv->hs_dev->mtu after iucv_sock_close() (called from the racing +recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference +oops. + +Suggested-by: Stanislav Fomichev +Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size") +Signed-off-by: Breno Leitao +Reviewed-by: Alexandra Winter +Tested-by: Alexandra Winter +Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/iucv/af_iucv.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index 0f660b1d3bd51c..e9a9bb0dee065a 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1539,7 +1539,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + unsigned int val; +- int len; ++ int len, rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; +@@ -1552,26 +1552,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + + len = min_t(unsigned int, len, sizeof(int)); + ++ rc = 0; ++ ++ lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: +- lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ +- release_sock(sk); + break; + case SO_MSGSIZE: +- if (sk->sk_state == IUCV_OPEN) +- return -EBADFD; ++ if (sk->sk_state == IUCV_OPEN) { ++ rc = -EBADFD; ++ break; ++ } + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; + default: +- return -ENOPROTOOPT; ++ rc = -ENOPROTOOPT; ++ break; + } ++ release_sock(sk); ++ ++ if (rc) ++ return rc; + + if (put_user(len, optlen)) + return -EFAULT; +-- +2.53.0 + diff --git a/queue-6.6/net-mana-add-null-guards-in-teardown-path-to-prevent.patch b/queue-6.6/net-mana-add-null-guards-in-teardown-path-to-prevent.patch new file mode 100644 index 0000000000..b9c43f77ab --- /dev/null +++ b/queue-6.6/net-mana-add-null-guards-in-teardown-path-to-prevent.patch @@ -0,0 +1,148 @@ +From bd11f75a6f9ad1296fb4c58e5162b0c43757f5d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 01:08:24 -0700 +Subject: net: mana: Add NULL guards in teardown path to prevent panic on + attach failure + +From: Dipayaan Roy + +[ Upstream commit 17bfe0a8c014ee1d542ad352cd6a0a505361664a ] + +When queue allocation fails partway through, the error cleanup frees +and NULLs apc->tx_qp and apc->rxqs. Multiple teardown paths such as +mana_remove(), mana_change_mtu() recovery, and internal error handling +in mana_alloc_queues() can subsequently call into functions that +dereference these pointers without NULL checks: + +- mana_chn_setxdp() dereferences apc->rxqs[0], causing a NULL pointer + dereference panic (CR2: 0000000000000000 at mana_chn_setxdp+0x26). +- mana_destroy_vport() iterates apc->rxqs without a NULL check. +- mana_fence_rqs() iterates apc->rxqs without a NULL check. +- mana_dealloc_queues() iterates apc->tx_qp without a NULL check. + +Add NULL guards for apc->rxqs in mana_fence_rqs(), +mana_destroy_vport(), and before the mana_chn_setxdp() call. Add a +NULL guard for apc->tx_qp in mana_dealloc_queues() to skip TX queue +draining when TX queues were never allocated or already freed. + +Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)") +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260525081129.1230035-2-dipayanroy@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 70 +++++++++++-------- + 1 file changed, 41 insertions(+), 29 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 343f6e879af39e..3cf4ad1d91f67e 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -1304,6 +1304,9 @@ static void mana_fence_rqs(struct mana_port_context *apc) + struct mana_rxq *rxq; + int err; + ++ if (!apc->rxqs) ++ return; ++ + for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { + rxq = apc->rxqs[rxq_idx]; + err = mana_fence_rq(apc, rxq); +@@ -2334,13 +2337,16 @@ static void mana_destroy_vport(struct mana_port_context *apc) + struct mana_rxq *rxq; + u32 rxq_idx; + +- for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { +- rxq = apc->rxqs[rxq_idx]; +- if (!rxq) +- continue; ++ if (apc->rxqs) { + +- mana_destroy_rxq(apc, rxq, true); +- apc->rxqs[rxq_idx] = NULL; ++ for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { ++ rxq = apc->rxqs[rxq_idx]; ++ if (!rxq) ++ continue; ++ ++ mana_destroy_rxq(apc, rxq, true); ++ apc->rxqs[rxq_idx] = NULL; ++ } + } + + mana_destroy_txq(apc); +@@ -2577,7 +2583,8 @@ static int mana_dealloc_queues(struct net_device *ndev) + if (apc->port_is_up) + return -EINVAL; + +- mana_chn_setxdp(apc, NULL); ++ if (apc->rxqs) ++ mana_chn_setxdp(apc, NULL); + + if (gd->gdma_context->is_pf) + mana_pf_deregister_filter(apc); +@@ -2595,33 +2602,38 @@ static int mana_dealloc_queues(struct net_device *ndev) + * number of queues. + */ + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- tsleep = 1000; +- while (atomic_read(&txq->pending_sends) > 0 && +- time_before(jiffies, timeout)) { +- usleep_range(tsleep, tsleep + 1000); +- tsleep <<= 1; +- } +- if (atomic_read(&txq->pending_sends)) { +- err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); +- if (err) { +- netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", +- err, atomic_read(&txq->pending_sends), +- txq->gdma_txq_id); ++ if (apc->tx_qp) { ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ tsleep = 1000; ++ while (atomic_read(&txq->pending_sends) > 0 && ++ time_before(jiffies, timeout)) { ++ usleep_range(tsleep, tsleep + 1000); ++ tsleep <<= 1; ++ } ++ if (atomic_read(&txq->pending_sends)) { ++ err = ++ pcie_flr(to_pci_dev(gd->gdma_context->dev)); ++ if (err) { ++ netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", ++ err, ++ atomic_read(&txq->pending_sends), ++ txq->gdma_txq_id); ++ } ++ break; + } +- break; + } +- } + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- while ((skb = skb_dequeue(&txq->pending_skbs))) { +- mana_unmap_skb(skb, apc); +- dev_kfree_skb_any(skb); ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ while ((skb = skb_dequeue(&txq->pending_skbs))) { ++ mana_unmap_skb(skb, apc); ++ dev_kfree_skb_any(skb); ++ } ++ atomic_set(&txq->pending_sends, 0); + } +- atomic_set(&txq->pending_sends, 0); + } ++ + /* We're 100% sure the queues can no longer be woken up, because + * we're sure now mana_poll_tx_cq() can't be running. + */ +-- +2.53.0 + diff --git a/queue-6.6/net-netlink-don-t-set-nsid-on-local-notifications.patch b/queue-6.6/net-netlink-don-t-set-nsid-on-local-notifications.patch new file mode 100644 index 0000000000..cca9da792f --- /dev/null +++ b/queue-6.6/net-netlink-don-t-set-nsid-on-local-notifications.patch @@ -0,0 +1,82 @@ +From df346a5056a1641ada9eded25e142c5340a7cfc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:36 +0200 +Subject: net: netlink: don't set nsid on local notifications + +From: Ilya Maximets + +[ Upstream commit 88b126b39f9757e9debc322d4679239e9af089c7 ] + +In most cases, notifications on sockets with NETLINK_LISTEN_ALL_NSID +do not contain NSID in their ancillary data in case the event is local +to the listener. + +However, when a self-referential NSID is allocated for a namespace, +every local notification starts sending this ID to the user space. + +This is problematic, because the listener cannot tell if those +notifications are local or not anymore without making extra requests +to figure out if the provided NSID is local or not. The listener +can also not figure out the local NSID beforehand as it can be +allocated at any point in time by other processes, changing the +structure of the future notifications for everyone. + +The value is practically not useful, since it's the namespace's own +ID that the application has to obtain from other sources in order to +figure out if it's the same or not. So, for the application it's +just an extra busy work with no benefits. Moreover, applications +that do not know about this quirk may be mishandling notifications +with NSID set as notifications from remote namespaces. This is the +case for ovs-vswitchd and the iproute2's 'ip monitor' that stops +printing 'current' and starts printing the nsid number mid-session. + +Lack of clear documentation for this behavior is also not helping. + +A search though open-source projects doesn't reveal any projects +that use NETNSA_NSID_NOT_ASSIGNED and rely on metadata to contain +self-referential NSIDs (expected, since the value is not useful). +Quite the opposite, as already mentioned, there are few applications +that rely on NSID to not be present in local events. + +Since the value is not useful and actively harmful in some cases, +let's not report it for local events, making the notifications more +consistent. + +Also adding some blank lines for readability. + +Fixes: 59324cf35aba ("netlink: allow to listen "all" netns") +Reported-by: Matteo Perin +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-3-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index f8d9a04d5d8b11..f3a8c8338d203f 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1484,10 +1484,14 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ + NETLINK_CB(p->skb2).nsid_is_set = false; +- NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); +- if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) +- NETLINK_CB(p->skb2).nsid_is_set = true; ++ if (!net_eq(sock_net(sk), p->net)) { ++ NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); ++ if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) ++ NETLINK_CB(p->skb2).nsid_is_set = true; ++ } ++ + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { + netlink_overrun(sk); +-- +2.53.0 + diff --git a/queue-6.6/net-netlink-fix-sending-unassigned-nsid-after-assign.patch b/queue-6.6/net-netlink-fix-sending-unassigned-nsid-after-assign.patch new file mode 100644 index 0000000000..b333569bb5 --- /dev/null +++ b/queue-6.6/net-netlink-fix-sending-unassigned-nsid-after-assign.patch @@ -0,0 +1,45 @@ +From db98437ed52e551948572283ee4072486c9c3475 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:35 +0200 +Subject: net: netlink: fix sending unassigned nsid after assigned one + +From: Ilya Maximets + +[ Upstream commit 70f8592ee90585272018a725054b6eb2ab7e99ca ] + +If the current skb is not shared, it is re-used directly for all the +sockets subscribed to the notification. If we have remote all-nsid +socket receiving a message first, then the 'nsid_is_set' will be +set to 'true'. If the nsid is NOT_ASSIGNED for the next socket in +the list, the 'nsid_is_set' will remain 'true' and the negative value +is be delivered to the user space. All subsequent nsid values will be +delivered as well, since there is no code path that sets the flag +back to 'false'. + +Fix that by always dropping the flag to 'false' first. + +Fixes: 7212462fa6fd ("netlink: don't send unknown nsid") +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-2-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index a5ffda87daf63b..f8d9a04d5d8b11 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1484,6 +1484,7 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ NETLINK_CB(p->skb2).nsid_is_set = false; + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) + NETLINK_CB(p->skb2).nsid_is_set = true; +-- +2.53.0 + diff --git a/queue-6.6/net-sched-revert-net-sched-restrict-conditions-for-a.patch b/queue-6.6/net-sched-revert-net-sched-restrict-conditions-for-a.patch new file mode 100644 index 0000000000..a1b944e12a --- /dev/null +++ b/queue-6.6/net-sched-revert-net-sched-restrict-conditions-for-a.patch @@ -0,0 +1,102 @@ +From a932c98b8851c7876d67b1af2e0141a344502b88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:49 -0400 +Subject: net/sched: Revert "net/sched: Restrict conditions for adding + duplicating netems to qdisc tree" + +From: Jamal Hadi Salim + +[ Upstream commit eda0b7f203bb166c98d1418b204135bd566ac83b ] + +This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. + +The original patch rejects any tree containing two netems when +either has duplication set, even when they sit on unrelated classes +of the same classful parent. That broke configurations that have +worked since netem was introduced. + +The re-entrancy problem the original commit was trying to solve is +handled by later patch using tc_depth flag. + +Doing this revert will (re)expose the original bug with multiple +netem duplication. When this patch is backported make sure +and get the full series. + +Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") +Reported-by: Ji-Soo Chung +Reported-by: Gerlinde +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 +Reported-by: zyc zyc +Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ +Reported-by: Manas Ghandat +Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 40 ---------------------------------------- + 1 file changed, 40 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index f8c5c506180858..827489b31626bb 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1005,41 +1005,6 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, + return 0; + } + +-static const struct Qdisc_class_ops netem_class_ops; +- +-static int check_netem_in_tree(struct Qdisc *sch, bool duplicates, +- struct netlink_ext_ack *extack) +-{ +- struct Qdisc *root, *q; +- unsigned int i; +- +- root = qdisc_root_sleeping(sch); +- +- if (sch != root && root->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(root))->duplicate) +- goto err; +- } +- +- if (!qdisc_dev(root)) +- return 0; +- +- hash_for_each(qdisc_dev(root)->qdisc_hash, i, q, hash) { +- if (sch != q && q->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(q))->duplicate) +- goto err; +- } +- } +- +- return 0; +- +-err: +- NL_SET_ERR_MSG(extack, +- "netem: cannot mix duplicating netems with other netems in tree"); +- return -EINVAL; +-} +- + /* Parse netlink message to set options */ + static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +@@ -1116,11 +1081,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + q->gap = qopt->gap; + q->counter = 0; + q->loss = qopt->loss; +- +- ret = check_netem_in_tree(sch, qopt->duplicate, extack); +- if (ret) +- goto unlock; +- + q->duplicate = qopt->duplicate; + + /* for compatibility with earlier versions. +-- +2.53.0 + diff --git a/queue-6.6/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch b/queue-6.6/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch new file mode 100644 index 0000000000..f51c9cf492 --- /dev/null +++ b/queue-6.6/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch @@ -0,0 +1,64 @@ +From 28b57b90365da92cb18898718d1f86b0cf8cd81a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:43:53 +0100 +Subject: net: skbuff: fix pskb_carve leaking zcopy pages + +From: Pavel Begunkov + +[ Upstream commit ff6e798c2eac3ebd0501ad7e796f583fab928de8 ] + +When SKBFL_MANAGED_FRAG_REFS is set, frag pages are not refcounted but +their lifetime is controlled by the attached ubuf_info. To make a copy +of the skb_shared_info, we either should clear the flag and reference +the frags, or keep the flag and have frags unreferenced. + +pskb_carve_inside_header() and pskb_carve_inside_nonlinear() don't +follow the rule and thus can leak page references. Let's clear +SKBFL_MANAGED_FRAG_REFS from the original skb to fix it. It's the +simplest way to address it, but there are more performant ways to do +that if it ever becomes a problem. + +Link: https://lore.kernel.org/all/20260523085809.26331-1-nvminh232@clc.fitus.edu.vn/ +Fixes: 753f1ca4e1e50 ("net: introduce managed frags infrastructure") +Reported-by: Minh Nguyen +Reported-by: Willem de Bruijn +Signed-off-by: Pavel Begunkov +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/1e2086aa69217d7f9c8da3d38f5be7160f1b4cd1.1779993185.git.asml.silence@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 8b05866e93b195..2282b6ad4be21a 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6397,6 +6397,11 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, + skb_copy_from_linear_data_offset(skb, off, data, new_hlen); + skb->len -= off; + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), + offsetof(struct skb_shared_info, +@@ -6509,6 +6514,11 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, + return -ENOMEM; + size = SKB_WITH_OVERHEAD(size); + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0])); + if (skb_orphan_frags(skb, gfp_mask)) { +-- +2.53.0 + diff --git a/queue-6.6/net-smc-do-not-re-initialize-smc-hashtables.patch b/queue-6.6/net-smc-do-not-re-initialize-smc-hashtables.patch new file mode 100644 index 0000000000..a165a777de --- /dev/null +++ b/queue-6.6/net-smc-do-not-re-initialize-smc-hashtables.patch @@ -0,0 +1,59 @@ +From 02743852ff7637214bf2731ea35d49304ab58302 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 16:56:39 +0200 +Subject: net/smc: Do not re-initialize smc hashtables + +From: Alexandra Winter + +[ Upstream commit 9e4389b0038781f19f97895186ed941ff8ac1678 ] + +INIT_HLIST_HEAD(&smc_v*_hashinfo.ht) are called after smc_nl_init(), +proto_register() and sock_register(). This can lead to smc_v*_hashinfo.ht +being reset even though hash entries already exist and are being used, +possibly resulting in a corrupted list. + +Remove unnecessary and dangerous re-initialisation of smc_v*_hashinfo.ht in +smc_init(); it is implicitly initialised to zero anyhow. Add +HLIST_HEAD_INIT to the definitions for clarity. + +Fixes: f16a7dd5cf27 ("smc: netlink interface for SMC sockets") +Suggested-by: Halil Pasic +Signed-off-by: Alexandra Winter +Acked-by: Halil Pasic +Reviewed-by: Mahanta Jambigi +Link: https://patch.msgid.link/20260521145639.10317-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 6629fd61be06a6..7a82e1a8a83f4b 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -181,10 +181,12 @@ static bool smc_hs_congested(const struct sock *sk) + + static struct smc_hashinfo smc_v4_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + static struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + int smc_hash_sk(struct sock *sk) +@@ -3579,8 +3581,6 @@ static int __init smc_init(void) + pr_err("%s: sock_register fails with %d\n", __func__, rc); + goto out_proto6; + } +- INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); +- INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); + + rc = smc_ib_register_client(); + if (rc) { +-- +2.53.0 + diff --git a/queue-6.6/netfilter-bitwise-add-support-for-doing-and-or-and-x.patch b/queue-6.6/netfilter-bitwise-add-support-for-doing-and-or-and-x.patch new file mode 100644 index 0000000000..40c34b0eab --- /dev/null +++ b/queue-6.6/netfilter-bitwise-add-support-for-doing-and-or-and-x.patch @@ -0,0 +1,300 @@ +From 18b5a57676c1eff651be3ff4f29bc73fa2f2e66f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Nov 2024 22:08:13 +0100 +Subject: netfilter: bitwise: add support for doing AND, OR and XOR directly + +From: Jeremy Sowden + +[ Upstream commit b0ccf4f53d968e794a4ea579d5135cc1aaf1a53f ] + +Hitherto, these operations have been converted in user space to +mask-and-xor operations on one register and two immediate values, and it +is the latter which have been evaluated by the kernel. We add support +for evaluating these operations directly in kernel space on one register +and either an immediate value or a second register. + +Pablo made a few changes to the original patch: + +- EINVAL if NFTA_BITWISE_SREG2 is used with fast version. +- Allow _AND,_OR,_XOR with _DATA != sizeof(u32) +- Dump _SREG2 or _DATA with _AND,_OR,_XOR + +Signed-off-by: Jeremy Sowden +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 18014147d3ee ("netfilter: nf_tables: fix dst corruption in same register operation") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/netfilter/nf_tables.h | 8 ++ + net/netfilter/nft_bitwise.c | 134 +++++++++++++++++++++-- + 2 files changed, 131 insertions(+), 11 deletions(-) + +diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h +index cbb1b58e181fca..f8867f198f3104 100644 +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -564,11 +564,17 @@ enum nft_immediate_attributes { + * and XOR boolean operations + * @NFT_BITWISE_LSHIFT: left-shift operation + * @NFT_BITWISE_RSHIFT: right-shift operation ++ * @NFT_BITWISE_AND: and operation ++ * @NFT_BITWISE_OR: or operation ++ * @NFT_BITWISE_XOR: xor operation + */ + enum nft_bitwise_ops { + NFT_BITWISE_MASK_XOR, + NFT_BITWISE_LSHIFT, + NFT_BITWISE_RSHIFT, ++ NFT_BITWISE_AND, ++ NFT_BITWISE_OR, ++ NFT_BITWISE_XOR, + }; + /* + * Old name for NFT_BITWISE_MASK_XOR. Retained for backwards-compatibility. +@@ -586,6 +592,7 @@ enum nft_bitwise_ops { + * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) + * @NFTA_BITWISE_DATA: argument for non-boolean operations + * (NLA_NESTED: nft_data_attributes) ++ * @NFTA_BITWISE_SREG2: second source register (NLA_U32: nft_registers) + * + * The bitwise expression supports boolean and shift operations. It implements + * the boolean operations by performing the following operation: +@@ -609,6 +616,7 @@ enum nft_bitwise_attributes { + NFTA_BITWISE_XOR, + NFTA_BITWISE_OP, + NFTA_BITWISE_DATA, ++ NFTA_BITWISE_SREG2, + __NFTA_BITWISE_MAX + }; + #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) +diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c +index 86abbe4c1308b3..af990c600745be 100644 +--- a/net/netfilter/nft_bitwise.c ++++ b/net/netfilter/nft_bitwise.c +@@ -17,6 +17,7 @@ + + struct nft_bitwise { + u8 sreg; ++ u8 sreg2; + u8 dreg; + enum nft_bitwise_ops op:8; + u8 len; +@@ -60,28 +61,72 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src, + } + } + ++static void nft_bitwise_eval_and(u32 *dst, const u32 *src, const u32 *src2, ++ const struct nft_bitwise *priv) ++{ ++ unsigned int i, n; ++ ++ for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++) ++ dst[i] = src[i] & src2[i]; ++} ++ ++static void nft_bitwise_eval_or(u32 *dst, const u32 *src, const u32 *src2, ++ const struct nft_bitwise *priv) ++{ ++ unsigned int i, n; ++ ++ for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++) ++ dst[i] = src[i] | src2[i]; ++} ++ ++static void nft_bitwise_eval_xor(u32 *dst, const u32 *src, const u32 *src2, ++ const struct nft_bitwise *priv) ++{ ++ unsigned int i, n; ++ ++ for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++) ++ dst[i] = src[i] ^ src2[i]; ++} ++ + void nft_bitwise_eval(const struct nft_expr *expr, + struct nft_regs *regs, const struct nft_pktinfo *pkt) + { + const struct nft_bitwise *priv = nft_expr_priv(expr); +- const u32 *src = ®s->data[priv->sreg]; ++ const u32 *src = ®s->data[priv->sreg], *src2; + u32 *dst = ®s->data[priv->dreg]; + +- switch (priv->op) { +- case NFT_BITWISE_MASK_XOR: ++ if (priv->op == NFT_BITWISE_MASK_XOR) { + nft_bitwise_eval_mask_xor(dst, src, priv); +- break; +- case NFT_BITWISE_LSHIFT: ++ return; ++ } ++ if (priv->op == NFT_BITWISE_LSHIFT) { + nft_bitwise_eval_lshift(dst, src, priv); +- break; +- case NFT_BITWISE_RSHIFT: ++ return; ++ } ++ if (priv->op == NFT_BITWISE_RSHIFT) { + nft_bitwise_eval_rshift(dst, src, priv); +- break; ++ return; ++ } ++ ++ src2 = priv->sreg2 ? ®s->data[priv->sreg2] : priv->data.data; ++ ++ if (priv->op == NFT_BITWISE_AND) { ++ nft_bitwise_eval_and(dst, src, src2, priv); ++ return; ++ } ++ if (priv->op == NFT_BITWISE_OR) { ++ nft_bitwise_eval_or(dst, src, src2, priv); ++ return; ++ } ++ if (priv->op == NFT_BITWISE_XOR) { ++ nft_bitwise_eval_xor(dst, src, src2, priv); ++ return; + } + } + + static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = { + [NFTA_BITWISE_SREG] = { .type = NLA_U32 }, ++ [NFTA_BITWISE_SREG2] = { .type = NLA_U32 }, + [NFTA_BITWISE_DREG] = { .type = NLA_U32 }, + [NFTA_BITWISE_LEN] = { .type = NLA_U32 }, + [NFTA_BITWISE_MASK] = { .type = NLA_NESTED }, +@@ -105,7 +150,8 @@ static int nft_bitwise_init_mask_xor(struct nft_bitwise *priv, + }; + int err; + +- if (tb[NFTA_BITWISE_DATA]) ++ if (tb[NFTA_BITWISE_DATA] || ++ tb[NFTA_BITWISE_SREG2]) + return -EINVAL; + + if (!tb[NFTA_BITWISE_MASK] || +@@ -139,7 +185,8 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv, + int err; + + if (tb[NFTA_BITWISE_MASK] || +- tb[NFTA_BITWISE_XOR]) ++ tb[NFTA_BITWISE_XOR] || ++ tb[NFTA_BITWISE_SREG2]) + return -EINVAL; + + if (!tb[NFTA_BITWISE_DATA]) +@@ -158,6 +205,41 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv, + return 0; + } + ++static int nft_bitwise_init_bool(const struct nft_ctx *ctx, ++ struct nft_bitwise *priv, ++ const struct nlattr *const tb[]) ++{ ++ int err; ++ ++ if (tb[NFTA_BITWISE_MASK] || ++ tb[NFTA_BITWISE_XOR]) ++ return -EINVAL; ++ ++ if ((!tb[NFTA_BITWISE_DATA] && !tb[NFTA_BITWISE_SREG2]) || ++ (tb[NFTA_BITWISE_DATA] && tb[NFTA_BITWISE_SREG2])) ++ return -EINVAL; ++ ++ if (tb[NFTA_BITWISE_DATA]) { ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->data), ++ .len = priv->len, ++ }; ++ ++ err = nft_data_init(NULL, &priv->data, &desc, ++ tb[NFTA_BITWISE_DATA]); ++ if (err < 0) ++ return err; ++ } else { ++ err = nft_parse_register_load(ctx, tb[NFTA_BITWISE_SREG2], ++ &priv->sreg2, priv->len); ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++ + static int nft_bitwise_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]) +@@ -189,6 +271,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + case NFT_BITWISE_MASK_XOR: + case NFT_BITWISE_LSHIFT: + case NFT_BITWISE_RSHIFT: ++ case NFT_BITWISE_AND: ++ case NFT_BITWISE_OR: ++ case NFT_BITWISE_XOR: + break; + default: + return -EOPNOTSUPP; +@@ -205,6 +290,11 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + case NFT_BITWISE_RSHIFT: + err = nft_bitwise_init_shift(priv, tb); + break; ++ case NFT_BITWISE_AND: ++ case NFT_BITWISE_OR: ++ case NFT_BITWISE_XOR: ++ err = nft_bitwise_init_bool(ctx, priv, tb); ++ break; + } + + return err; +@@ -233,6 +323,21 @@ static int nft_bitwise_dump_shift(struct sk_buff *skb, + return 0; + } + ++static int nft_bitwise_dump_bool(struct sk_buff *skb, ++ const struct nft_bitwise *priv) ++{ ++ if (priv->sreg2) { ++ if (nft_dump_register(skb, NFTA_BITWISE_SREG2, priv->sreg2)) ++ return -1; ++ } else { ++ if (nft_data_dump(skb, NFTA_BITWISE_DATA, &priv->data, ++ NFT_DATA_VALUE, sizeof(u32)) < 0) ++ return -1; ++ } ++ ++ return 0; ++} ++ + static int nft_bitwise_dump(struct sk_buff *skb, + const struct nft_expr *expr, bool reset) + { +@@ -256,6 +361,11 @@ static int nft_bitwise_dump(struct sk_buff *skb, + case NFT_BITWISE_RSHIFT: + err = nft_bitwise_dump_shift(skb, priv); + break; ++ case NFT_BITWISE_AND: ++ case NFT_BITWISE_OR: ++ case NFT_BITWISE_XOR: ++ err = nft_bitwise_dump_bool(skb, priv); ++ break; + } + + return err; +@@ -300,6 +410,7 @@ static bool nft_bitwise_reduce(struct nft_regs_track *track, + track->regs[priv->dreg].bitwise && + track->regs[priv->dreg].bitwise->ops == expr->ops && + priv->sreg == bitwise->sreg && ++ priv->sreg2 == bitwise->sreg2 && + priv->dreg == bitwise->dreg && + priv->op == bitwise->op && + priv->len == bitwise->len && +@@ -376,7 +487,8 @@ static int nft_bitwise_fast_init(const struct nft_ctx *ctx, + if (err < 0) + return err; + +- if (tb[NFTA_BITWISE_DATA]) ++ if (tb[NFTA_BITWISE_DATA] || ++ tb[NFTA_BITWISE_SREG2]) + return -EINVAL; + + if (!tb[NFTA_BITWISE_MASK] || +-- +2.53.0 + diff --git a/queue-6.6/netfilter-bitwise-rename-some-boolean-operation-func.patch b/queue-6.6/netfilter-bitwise-rename-some-boolean-operation-func.patch new file mode 100644 index 0000000000..7d7fd489ba --- /dev/null +++ b/queue-6.6/netfilter-bitwise-rename-some-boolean-operation-func.patch @@ -0,0 +1,164 @@ +From 402652d68fff1a19f21133acfdabb8f34c1905e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Nov 2024 22:07:51 +0100 +Subject: netfilter: bitwise: rename some boolean operation functions + +From: Jeremy Sowden + +[ Upstream commit a12143e6084c502fc3cfaa8b717bffc8c14cf806 ] + +In the next patch we add support for doing AND, OR and XOR operations +directly in the kernel, so rename some functions and an enum constant +related to mask-and-xor boolean operations. + +Signed-off-by: Jeremy Sowden +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 18014147d3ee ("netfilter: nf_tables: fix dst corruption in same register operation") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/netfilter/nf_tables.h | 10 ++++--- + net/netfilter/nft_bitwise.c | 34 ++++++++++++------------ + 2 files changed, 24 insertions(+), 20 deletions(-) + +diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h +index 9c29015d09c10f..cbb1b58e181fca 100644 +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -560,16 +560,20 @@ enum nft_immediate_attributes { + /** + * enum nft_bitwise_ops - nf_tables bitwise operations + * +- * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and +- * XOR boolean operations ++ * @NFT_BITWISE_MASK_XOR: mask-and-xor operation used to implement NOT, AND, OR ++ * and XOR boolean operations + * @NFT_BITWISE_LSHIFT: left-shift operation + * @NFT_BITWISE_RSHIFT: right-shift operation + */ + enum nft_bitwise_ops { +- NFT_BITWISE_BOOL, ++ NFT_BITWISE_MASK_XOR, + NFT_BITWISE_LSHIFT, + NFT_BITWISE_RSHIFT, + }; ++/* ++ * Old name for NFT_BITWISE_MASK_XOR. Retained for backwards-compatibility. ++ */ ++#define NFT_BITWISE_BOOL NFT_BITWISE_MASK_XOR + + /** + * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes +diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c +index 2cfb0104680c62..86abbe4c1308b3 100644 +--- a/net/netfilter/nft_bitwise.c ++++ b/net/netfilter/nft_bitwise.c +@@ -25,8 +25,8 @@ struct nft_bitwise { + struct nft_data data; + }; + +-static void nft_bitwise_eval_bool(u32 *dst, const u32 *src, +- const struct nft_bitwise *priv) ++static void nft_bitwise_eval_mask_xor(u32 *dst, const u32 *src, ++ const struct nft_bitwise *priv) + { + unsigned int i; + +@@ -68,8 +68,8 @@ void nft_bitwise_eval(const struct nft_expr *expr, + u32 *dst = ®s->data[priv->dreg]; + + switch (priv->op) { +- case NFT_BITWISE_BOOL: +- nft_bitwise_eval_bool(dst, src, priv); ++ case NFT_BITWISE_MASK_XOR: ++ nft_bitwise_eval_mask_xor(dst, src, priv); + break; + case NFT_BITWISE_LSHIFT: + nft_bitwise_eval_lshift(dst, src, priv); +@@ -90,8 +90,8 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = { + [NFTA_BITWISE_DATA] = { .type = NLA_NESTED }, + }; + +-static int nft_bitwise_init_bool(struct nft_bitwise *priv, +- const struct nlattr *const tb[]) ++static int nft_bitwise_init_mask_xor(struct nft_bitwise *priv, ++ const struct nlattr *const tb[]) + { + struct nft_data_desc mask = { + .type = NFT_DATA_VALUE, +@@ -186,7 +186,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + if (tb[NFTA_BITWISE_OP]) { + priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])); + switch (priv->op) { +- case NFT_BITWISE_BOOL: ++ case NFT_BITWISE_MASK_XOR: + case NFT_BITWISE_LSHIFT: + case NFT_BITWISE_RSHIFT: + break; +@@ -194,12 +194,12 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + return -EOPNOTSUPP; + } + } else { +- priv->op = NFT_BITWISE_BOOL; ++ priv->op = NFT_BITWISE_MASK_XOR; + } + + switch(priv->op) { +- case NFT_BITWISE_BOOL: +- err = nft_bitwise_init_bool(priv, tb); ++ case NFT_BITWISE_MASK_XOR: ++ err = nft_bitwise_init_mask_xor(priv, tb); + break; + case NFT_BITWISE_LSHIFT: + case NFT_BITWISE_RSHIFT: +@@ -210,8 +210,8 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + return err; + } + +-static int nft_bitwise_dump_bool(struct sk_buff *skb, +- const struct nft_bitwise *priv) ++static int nft_bitwise_dump_mask_xor(struct sk_buff *skb, ++ const struct nft_bitwise *priv) + { + if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask, + NFT_DATA_VALUE, priv->len) < 0) +@@ -249,8 +249,8 @@ static int nft_bitwise_dump(struct sk_buff *skb, + return -1; + + switch (priv->op) { +- case NFT_BITWISE_BOOL: +- err = nft_bitwise_dump_bool(skb, priv); ++ case NFT_BITWISE_MASK_XOR: ++ err = nft_bitwise_dump_mask_xor(skb, priv); + break; + case NFT_BITWISE_LSHIFT: + case NFT_BITWISE_RSHIFT: +@@ -270,7 +270,7 @@ static int nft_bitwise_offload(struct nft_offload_ctx *ctx, + const struct nft_bitwise *priv = nft_expr_priv(expr); + struct nft_offload_reg *reg = &ctx->regs[priv->dreg]; + +- if (priv->op != NFT_BITWISE_BOOL) ++ if (priv->op != NFT_BITWISE_MASK_XOR) + return -EOPNOTSUPP; + + if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) || +@@ -407,7 +407,7 @@ nft_bitwise_fast_dump(struct sk_buff *skb, + return -1; + if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(sizeof(u32)))) + return -1; +- if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(NFT_BITWISE_BOOL))) ++ if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(NFT_BITWISE_MASK_XOR))) + return -1; + + data.data[0] = priv->mask; +@@ -502,7 +502,7 @@ nft_bitwise_select_ops(const struct nft_ctx *ctx, + return &nft_bitwise_ops; + + if (tb[NFTA_BITWISE_OP] && +- ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])) != NFT_BITWISE_BOOL) ++ ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])) != NFT_BITWISE_MASK_XOR) + return &nft_bitwise_ops; + + return &nft_bitwise_fast_ops; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch b/queue-6.6/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch new file mode 100644 index 0000000000..1e5308e2bd --- /dev/null +++ b/queue-6.6/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch @@ -0,0 +1,107 @@ +From fc5e49514b4e5606b577a8262de548f245dbd1da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 22:52:07 +0200 +Subject: netfilter: ebtables: fix OOB read in compat_mtw_from_user + +From: Florian Westphal + +[ Upstream commit f438d1786d657d57790c5d138d6db3fc9fdac392 ] + +Luxiao Xu says: + + The function compat_mtw_from_user() converts ebtables extensions from + 32-bit user structures to kernel native structures. However, it lacks + proper validation of the user-supplied match_size/target_size. + + When certain extensions are processed, the kernel-side translation + logic may perform memory accesses based on the extension's expected + size. If the user provides a size smaller than what the extension + requires, it results in an out-of-bounds read as reported by KASAN. + + This fix introduces a check to ensure match_size is at least as large + as the extension's required compatsize. This covers matches, watchers, + and targets, while maintaining compatibility with standard targets. + +AFAIU this is relevant for matches that need to go though +match->compat_from_user() call. Those that use plain memcpy with the +user-provided size are ok because the caller checks that size vs the +start of the next rule entry offset (which itself is checked vs. total +size copied from userspace). + +The ->compat_from_user() callbacks assume they can read compatsize bytes, +so they need this extra check. + +Based on an earlier patch from Luxiao Xu. + +Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index f99e348c8f37fa..bc69406d103df6 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1952,6 +1952,25 @@ enum compat_mwt { + EBT_COMPAT_TARGET, + }; + ++static bool match_size_ok(const struct xt_match *match, unsigned int match_size) ++{ ++ u16 csize; ++ ++ if (match->matchsize == -1) /* cannot validate ebt_among */ ++ return true; ++ ++ csize = match->compatsize ? : match->matchsize; ++ ++ return match_size >= csize; ++} ++ ++static bool tgt_size_ok(const struct xt_target *tgt, unsigned int tgt_size) ++{ ++ u16 csize = tgt->compatsize ? : tgt->targetsize; ++ ++ return tgt_size >= csize; ++} ++ + static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + enum compat_mwt compat_mwt, + struct ebt_entries_buf_state *state, +@@ -1977,6 +1996,11 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + if (IS_ERR(match)) + return PTR_ERR(match); + ++ if (!match_size_ok(match, match_size)) { ++ module_put(match->me); ++ return -EINVAL; ++ } ++ + off = ebt_compat_match_offset(match, match_size); + if (dst) { + if (match->compat_from_user) +@@ -1996,6 +2020,12 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + mwt->u.revision); + if (IS_ERR(wt)) + return PTR_ERR(wt); ++ ++ if (!tgt_size_ok(wt, match_size)) { ++ module_put(wt->me); ++ return -EINVAL; ++ } ++ + off = xt_compat_target_offset(wt); + + if (dst) { +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch b/queue-6.6/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch new file mode 100644 index 0000000000..e321db80eb --- /dev/null +++ b/queue-6.6/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch @@ -0,0 +1,141 @@ +From 18720c912aa30fbd207aa4bb1952a5aea40f0ff5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 16:37:56 +0200 +Subject: netfilter: nf_tables: fix dst corruption in same register operation + +From: Fernando Fernandez Mancera + +[ Upstream commit 18014147d3ee7831dce53fe65d7fc8d428b02552 ] + +For lshift and rshift, the shift operations are performed in a loop over +32-bit words. The loop calculates the shifted value and write it to dst, +and then immediately reads from src to calculate the carry for the next +iteration. Because src and dst could point to the same memory location, +the carry is incorrectly calculated using the newly modified dst value +instead of the original src value. + +Adding a temporary local variable to cache the original value before +writing to dst and using it for the carry calculation solves the +problem. In addition, partial overlap is rejected from control plane for +all kind of operations including byteorder. This was tested with the +following bytecode: + +table test_table ip flags 0 use 1 handle 1 +ip test_table test_chain use 3 type filter hook input prio 0 policy accept packets 0 bytes 0 flags 1 +ip test_table test_chain 2 + [ immediate reg 1 0x44332211 0x88776655 ] + [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ] + [ cmp eq reg 1 0x66443322 0x00887766 ] + [ counter pkts 0 bytes 0 ] +ip test_table test_chain 4 3 + [ immediate reg 1 0x44332211 0x88776655 ] + [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ] + [ cmp eq reg 1 0x55443322 0x00887766 ] + [ counter pkts 21794 bytes 1917798 ] + +Fixes: 567d746b55bc ("netfilter: bitwise: add support for shifts.") +Acked-by: Jeremy Sowden +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 7 +++++++ + net/netfilter/nft_bitwise.c | 18 ++++++++++++++---- + net/netfilter/nft_byteorder.c | 13 ++++++++++--- + 3 files changed, 31 insertions(+), 7 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index ab0567951e3105..a1f828efc9e3de 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -188,6 +188,13 @@ static inline u64 nft_reg_load64(const u32 *sreg) + return get_unaligned((u64 *)sreg); + } + ++static inline bool nft_reg_overlap(u8 src, u8 dst, u32 len) ++{ ++ unsigned int n = DIV_ROUND_UP(len, sizeof(u32)); ++ ++ return src != dst && src < dst + n && dst < src + n; ++} ++ + static inline void nft_data_copy(u32 *dst, const struct nft_data *src, + unsigned int len) + { +diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c +index af990c600745be..1afb36fb5994db 100644 +--- a/net/netfilter/nft_bitwise.c ++++ b/net/netfilter/nft_bitwise.c +@@ -43,8 +43,10 @@ static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src, + u32 carry = 0; + + for (i = DIV_ROUND_UP(priv->len, sizeof(u32)); i > 0; i--) { +- dst[i - 1] = (src[i - 1] << shift) | carry; +- carry = src[i - 1] >> (BITS_PER_TYPE(u32) - shift); ++ u32 tmp_src = src[i - 1]; ++ ++ dst[i - 1] = (tmp_src << shift) | carry; ++ carry = tmp_src >> (BITS_PER_TYPE(u32) - shift); + } + } + +@@ -56,8 +58,10 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src, + u32 carry = 0; + + for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++) { +- dst[i] = carry | (src[i] >> shift); +- carry = src[i] << (BITS_PER_TYPE(u32) - shift); ++ u32 tmp_src = src[i]; ++ ++ dst[i] = carry | (tmp_src >> shift); ++ carry = tmp_src << (BITS_PER_TYPE(u32) - shift); + } + } + +@@ -235,6 +239,9 @@ static int nft_bitwise_init_bool(const struct nft_ctx *ctx, + &priv->sreg2, priv->len); + if (err < 0) + return err; ++ ++ if (nft_reg_overlap(priv->sreg2, priv->dreg, priv->len)) ++ return -EINVAL; + } + + return 0; +@@ -265,6 +272,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + if (err < 0) + return err; + ++ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len)) ++ return -EINVAL; ++ + if (tb[NFTA_BITWISE_OP]) { + priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])); + switch (priv->op) { +diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c +index 2f82a444d21bf3..51f5de5c4ca363 100644 +--- a/net/netfilter/nft_byteorder.c ++++ b/net/netfilter/nft_byteorder.c +@@ -144,9 +144,16 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, + if (err < 0) + return err; + +- return nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG], +- &priv->dreg, NULL, NFT_DATA_VALUE, +- priv->len); ++ err = nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG], ++ &priv->dreg, NULL, NFT_DATA_VALUE, ++ priv->len); ++ if (err < 0) ++ return err; ++ ++ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len)) ++ return -EINVAL; ++ ++ return 0; + } + + static int nft_byteorder_dump(struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-6.6/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch b/queue-6.6/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch new file mode 100644 index 0000000000..c2d0b039da --- /dev/null +++ b/queue-6.6/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch @@ -0,0 +1,68 @@ +From 60f5b7b86f67777d92041c395866c1f3bec484cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 12:36:14 -0700 +Subject: netfilter: synproxy: refresh tcphdr after skb_ensure_writable + +From: Chris Mason + +[ Upstream commit 92170e6afe927ab2792a3f71902845789c8e31b1 ] + +synproxy_tstamp_adjust() rewrites the TCP timestamp option in place +and then patches the TCP checksum via inet_proto_csum_replace4() on +the caller-supplied tcphdr pointer. Both ipv4_synproxy_hook() and +ipv6_synproxy_hook() obtain that pointer with skb_header_pointer() +before calling in, so it may either alias skb->head directly or +point at the caller's on-stack _tcph buffer. + +Between obtaining the pointer and using it, the function calls +skb_ensure_writable(skb, optend), which on a cloned or non-linear +skb invokes pskb_expand_head() and frees the old skb->head. After +that point the cached th is stale: + + caller (ipv[46]_synproxy_hook) + th = skb_header_pointer(skb, ..., &_tcph) + synproxy_tstamp_adjust(skb, protoff, th, ...) + skb_ensure_writable(skb, optend) + pskb_expand_head() /* kfree(old skb->head) */ + ... + inet_proto_csum_replace4(&th->check, ...) + /* writes into freed head, or + into the caller's stack copy + leaving the on-wire checksum + stale */ + +The option bytes are written through skb->data and are fine; only +the checksum update goes through th and so lands in the wrong +place. The result is either a write into freed slab memory or a +packet leaving with a checksum that does not match its payload. + +Fix by re-deriving th from skb->data + protoff immediately after +skb_ensure_writable() succeeds, so the subsequent checksum update +targets the linear, writable header. + +Fixes: 48b1de4c110a ("netfilter: add SYNPROXY core/target") +Assisted-by: kres (claude-opus-4-7) +Signed-off-by: Chris Mason +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 16915f8eef2b16..f5a52075691faa 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -199,6 +199,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + if (skb_ensure_writable(skb, optend)) + return 0; + ++ th = (struct tcphdr *)(skb->data + protoff); ++ + while (optoff < optend) { + unsigned char *op = skb->data + optoff; + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch b/queue-6.6/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..fbd0129590 --- /dev/null +++ b/queue-6.6/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch @@ -0,0 +1,48 @@ +From 4e2a3c94b7263ec961465f8b43e8c84b2ab88f31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 20:10:08 +0200 +Subject: netfilter: xt_cpu: prefer raw_smp_processor_id + +From: Florian Westphal + +[ Upstream commit c376f07e16c02239ed44cabb97145d03f65b4d15 ] + +With PREEMPT_RCU we get splat: + +BUG: using smp_processor_id() in preemptible [..] +caller is cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 +CPU: 1 .. Comm: syz.3.1377 #0 PREEMPT(full) +Call Trace: + + dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 + check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 + cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 + [..] + +Just use raw version instead. +This is similar to 14d14a5d2957 ("netfilter: nft_meta: use raw_smp_processor_id()"). + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reported-by: syzbot+690d3e3ffa7335ac10eb@syzkaller.appspotmail.com +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c +index 3bdc302a0f9137..9cb259902a586b 100644 +--- a/net/netfilter/xt_cpu.c ++++ b/net/netfilter/xt_cpu.c +@@ -34,7 +34,7 @@ static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_cpu_info *info = par->matchinfo; + +- return (info->cpu == smp_processor_id()) ^ info->invert; ++ return (info->cpu == raw_smp_processor_id()) ^ info->invert; + } + + static struct xt_match cpu_mt_reg __read_mostly = { +-- +2.53.0 + diff --git a/queue-6.6/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch b/queue-6.6/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch new file mode 100644 index 0000000000..07f19e2a0d --- /dev/null +++ b/queue-6.6/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch @@ -0,0 +1,40 @@ +From a38f68916d1d39d9a3d46c7e2a44629e1273d820 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:41 +0000 +Subject: nfc: llcp: Fix use-after-free in llcp_sock_release() + +From: Lee Jones + +[ Upstream commit f4268b466190dae95a7585f69b4f1f8ad097632c ] + +llcp_sock_release() unconditionally unlinks the socket from the local +sockets list. However, if the socket is still in connecting state, it +is on the connecting list. + +Fix this by checking the socket state and unlinking from the correct list. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Signed-off-by: Lee Jones +Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index d5344563e525c9..cd1fdf0beefb6b 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -633,6 +633,8 @@ static int llcp_sock_release(struct socket *sock) + + if (sock->type == SOCK_RAW) + nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else if (sk->sk_state == LLCP_CONNECTING) ++ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + else + nfc_llcp_sock_unlink(&local->sockets, sk); + +-- +2.53.0 + diff --git a/queue-6.6/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch b/queue-6.6/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch new file mode 100644 index 0000000000..cb4b99026d --- /dev/null +++ b/queue-6.6/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch @@ -0,0 +1,67 @@ +From 7b3ff0e2277e1abdc4ea650a01408ec636cd9fd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:42 +0000 +Subject: nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() + +From: Lee Jones + +[ Upstream commit b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 ] + +A race condition exists in the NFC LLCP connection state machine where +the connection acceptance packet (CC) can be processed concurrently with +socket release. This can lead to a use-after-free of the socket object. + +When nfc_llcp_recv_cc() moves the socket from the connecting_sockets +list to the sockets list, it does so without holding the socket lock. +If llcp_sock_release() is executing concurrently, it might have already +unlinked the socket and dropped its references, which can result in +nfc_llcp_recv_cc() linking a freed socket into the live list. + +Fix this by holding lock_sock() during the state transition and list +movement in nfc_llcp_recv_cc(). After acquiring the lock, check if +the socket is still hashed to ensure it hasn't already been unlinked +and marked for destruction by the release path. This aligns the locking +pattern with recv_hdlc() and recv_disc(). + +Fixes: a69f32af86e3 ("NFC: Socket linked list") +Signed-off-by: Lee Jones +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index d9562840fa180b..62b0f2d6686eb8 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -1216,6 +1216,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + + sk = &llcp_sock->sk; + ++ lock_sock(sk); ++ ++ /* Check if socket was destroyed whilst waiting for the lock */ ++ if (!sk_hashed(sk)) { ++ release_sock(sk); ++ nfc_llcp_sock_put(llcp_sock); ++ return; ++ } ++ + /* Unlink from connecting and link to the client array */ + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + nfc_llcp_sock_link(&local->sockets, sk); +@@ -1227,6 +1236,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + ++ release_sock(sk); ++ + nfc_llcp_sock_put(llcp_sock); + } + +-- +2.53.0 + diff --git a/queue-6.6/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch b/queue-6.6/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch new file mode 100644 index 0000000000..7daf421b84 --- /dev/null +++ b/queue-6.6/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch @@ -0,0 +1,83 @@ +From 65657174e5b814ac4163e28df16fc74f3f61b22c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 May 2026 19:55:18 +0800 +Subject: nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems + +From: Carl Lee + +[ Upstream commit f23bf992d65a42007c517b060ca35cebdea3525a ] + +Some ACPI-based platforms report incorrect IRQ trigger types (e.g. +IRQF_TRIGGER_HIGH), which can lead to interrupt storms. + +Use the historically working rising-edge trigger on ACPI systems to +avoid this regression. + +Device Tree-based systems continue to use the firmware-provided +trigger type. + +Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") +Signed-off-by: Carl Lee +Tested-by: Bartosz Golaszewski +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Mark Pearson +Tested-by: Mark Pearson +Tested-by: Luca Stefani +Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index 5ecbf3366a1de4..e80ce1b97bccc9 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -267,6 +268,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + { + struct device *dev = &client->dev; + struct nxp_nci_i2c_phy *phy; ++ unsigned long irqflags; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +@@ -303,9 +305,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + if (r < 0) + return r; + ++ /* ++ * ACPI platforms may report incorrect IRQ trigger types ++ * (e.g. level-high), which can lead to interrupt storms. ++ * ++ * Use the historically stable rising-edge trigger for ACPI devices. ++ * ++ * On non-ACPI systems (e.g. Device Tree), prefer the firmware- ++ * provided trigger type, falling back to rising-edge if not set. ++ */ ++ if (ACPI_COMPANION(dev)) { ++ irqflags = IRQF_TRIGGER_RISING; ++ } else { ++ irqflags = irq_get_trigger_type(client->irq); ++ if (!irqflags) ++ irqflags = IRQF_TRIGGER_RISING; ++ } ++ + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, +- IRQF_ONESHOT, ++ irqflags | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); +-- +2.53.0 + diff --git a/queue-6.6/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch b/queue-6.6/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch new file mode 100644 index 0000000000..06cb3ecdc3 --- /dev/null +++ b/queue-6.6/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch @@ -0,0 +1,80 @@ +From b2ff862b5bab1cbbb59bea693b346ba075aa8393 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 14:09:41 -0400 +Subject: scsi: core: Run queues for all non-SDEV_DEL devices from + scsi_run_host_queues + +From: David Jeffery + +[ Upstream commit 7205b58702273baf21d6ba7992e6ba15852325f7 ] + +While a SCSI host is in a recovery state, scsi_mq_requeue_cmd() will not +set the requeue list for a requeued command to be kicked in the future. +The expectation is a call to scsi_run_host_queues() will kick all SCSI +devices once the recovery state is cleared. + +However, scsi_run_host_queues() uses shost_for_each_device() which uses +scsi_device_get() and so will ignore devices in a partially removed +state like SDEV_CANCEL. But these devices may also have requeued +requests, leaving their requests stuck from not being kicked and causing +the removal process of the device to hang. + +scsi_run_host_queues() needs to run against more devices than the macro +shost_for_each_device() allows. Instead of using the too limiting +scsi_device_get() state checks, only ignore devices in SDEV_DEL state or +when unable to acquire a reference. Attempt to run the queues for all +other devices when scsi_run_host_queues() is called. + +Fixes: 8b566edbdbfb ("scsi: core: Only kick the requeue list if necessary") +Signed-off-by: David Jeffery +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260515180941.9698-1-djeffery@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/scsi_lib.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index efd1f1d6e4e9b0..2268e540f28ae6 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -474,10 +474,33 @@ void scsi_requeue_run_queue(struct work_struct *work) + + void scsi_run_host_queues(struct Scsi_Host *shost) + { +- struct scsi_device *sdev; ++ struct scsi_device *sdev, *prev = NULL; ++ unsigned long flags; + +- shost_for_each_device(sdev, shost) ++ spin_lock_irqsave(shost->host_lock, flags); ++ __shost_for_each_device(sdev, shost) { ++ /* ++ * Only skip devices so deep into removal they will never need ++ * another kick to their queues. Thus scsi_device_get() cannot ++ * be used as it would skip devices in SDEV_CANCEL state which ++ * may need a queue kick. ++ */ ++ if (sdev->sdev_state == SDEV_DEL || ++ !get_device(&sdev->sdev_gendev)) ++ continue; ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ ++ if (prev) ++ put_device(&prev->sdev_gendev); + scsi_run_queue(sdev->request_queue); ++ ++ prev = sdev; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ if (prev) ++ put_device(&prev->sdev_gendev); + } + + static void scsi_uninit_cmd(struct scsi_cmnd *cmd) +-- +2.53.0 + diff --git a/queue-6.6/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch b/queue-6.6/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch new file mode 100644 index 0000000000..2a350044e9 --- /dev/null +++ b/queue-6.6/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch @@ -0,0 +1,50 @@ +From e9a67f38739eecd796cab49524a8436f3a8679bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 11:24:11 +0800 +Subject: sctp: fix race between sctp_wait_for_connect and peeloff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit f14fe6395a8b3d961a61e138ad7b36ba3626dd4e ] + +sctp_wait_for_connect() drops and re-acquires the socket lock while +waiting for the association to reach ESTABLISHED state. During this +window, another thread can peeloff the association to a new socket via +getsockopt(SCTP_SOCKOPT_PEELOFF), changing asoc->base.sk. After +re-acquiring the old socket lock, sctp_wait_for_connect() returns +success without noticing the migration — the caller then accesses +the association under the wrong lock in sctp_datamsg_from_user(). + +Add the same sk != asoc->base.sk check that sctp_wait_for_sndbuf() +already has, returning an error if the association was migrated while +we slept. + +Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") +Signed-off-by: Zhenghang Xiao +Acked-by: Xin Long +Link: https://patch.msgid.link/20260527032411.60959-1-kipreyyy@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 98586bcf83cebe..a6a53b0c4ea324 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9371,6 +9371,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) + release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + + *timeo_p = current_timeo; + } +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index 3a056ff01a..f28fade55c 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -4,3 +4,45 @@ net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch drm-remove-plane-hsub-vsub-alignment-requirement-for.patch bcache-fix-uninitialized-closure-object.patch net-cpsw_new-fix-potential-unregister-of-netdev-that.patch +nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch +nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch +xfrm-check-for-underflow-in-xfrm_state_mtu.patch +nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch +kernel-fork-validate-exit_signal-in-kernel_clone.patch +netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch +netfilter-xt_cpu-prefer-raw_smp_processor_id.patch +netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch +netfilter-bitwise-rename-some-boolean-operation-func.patch +netfilter-bitwise-add-support-for-doing-and-or-and-x.patch +netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch +tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch +tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch +vsock-keep-poll-shutdown-state-consistent.patch +net-netlink-fix-sending-unassigned-nsid-after-assign.patch +net-netlink-don-t-set-nsid-on-local-notifications.patch +net-smc-do-not-re-initialize-smc-hashtables.patch +net-iucv-fix-locking-in-.getsockopt.patch +scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch +ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch +asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch +net-hsr-fix-potential-oob-access-in-supervision-fram.patch +gpio-mxc-fix-irq_high-handling.patch +tunnels-load-network-headers-after-skb_cow-in-iptunn.patch +vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch +tunnels-do-not-assume-transport-header-in-iptunnel_p.patch +ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch +asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch +bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch +bonding-refuse-to-enslave-can-devices.patch +ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch +ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch +ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch +net-sched-revert-net-sched-restrict-conditions-for-a.patch +bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch +bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch +gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch +net-mana-add-null-guards-in-teardown-path-to-prevent.patch +sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch +ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch +ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch +net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch diff --git a/queue-6.6/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch b/queue-6.6/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch new file mode 100644 index 0000000000..71d57cc616 --- /dev/null +++ b/queue-6.6/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch @@ -0,0 +1,47 @@ +From d5da23d77f7e9b7ee19a8b1d038f68204ffd9211 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 09:33:13 -0700 +Subject: tun: free page on build_skb failure in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit aa8963fdce667a42fb7f0bdd2909fadcab02f9a8 ] + +When build_skb() fails in tun_xdp_one(), the function sets ret to +-ENOMEM and jumps to the out label, which returns without freeing the +page that vhost_net_build_xdp() allocated for the frame. As with the +short-frame rejection path, tun_sendmsg() discards the per-buffer error +and still returns total_len, so vhost_tx_batch() takes the success path +and never frees the page. Each build_skb() failure in a batch leaks one +page-frag chunk. + +Free the page before taking the error path, matching the put_page() the +other error exits of tun_xdp_one() already perform. + +Fixes: 043d222f93ab ("tuntap: accept an array of XDP buffs through sendmsg()") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260521163312.1479805-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 88b704b5d0b26e..9a4192d6a4cabf 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2505,6 +2505,7 @@ static int tun_xdp_one(struct tun_struct *tun, + build: + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { ++ put_page(virt_to_head_page(xdp->data)); + ret = -ENOMEM; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.6/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch b/queue-6.6/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch new file mode 100644 index 0000000000..3dc4b7aa85 --- /dev/null +++ b/queue-6.6/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch @@ -0,0 +1,54 @@ +From eb77e551673698e972547a5d6b8b5424865bd829 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:00:21 -0700 +Subject: tun: free page on short-frame rejection in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit f4feb1e20058e407cb00f45aff47f5b7e19a6bbf ] + +tun_xdp_one() returns -EINVAL on a frame shorter than ETH_HLEN without +freeing the page that vhost_net_build_xdp() allocated for it. +tun_sendmsg() discards that -EINVAL and still returns total_len, so +vhost_tx_batch() takes the success path and never frees the page; each +short frame in a batch leaks one page-frag chunk. + +A local process that can open /dev/net/tun and /dev/vhost-net can hit +this path: it attaches a tun/tap device as the vhost-net backend and +feeds TX descriptors whose length minus the virtio-net header is below +ETH_HLEN. Each kick leaks the page-frag chunks for that batch, and a +tight submission loop exhausts host memory and triggers an OOM panic. +Free the page before returning -EINVAL, matching the XDP-program error +path in the same function. + +Fixes: 049584807f1d ("tun: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260520160020.375349-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 97dbec8d78077d..88b704b5d0b26e 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2459,8 +2459,10 @@ static int tun_xdp_one(struct tun_struct *tun, + bool skb_xdp = false; + struct page *page; + +- if (unlikely(datasize < ETH_HLEN)) ++ if (unlikely(datasize < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + return -EINVAL; ++ } + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { +-- +2.53.0 + diff --git a/queue-6.6/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch b/queue-6.6/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch new file mode 100644 index 0000000000..10cdb2184e --- /dev/null +++ b/queue-6.6/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch @@ -0,0 +1,67 @@ +From 98d3272a7d817488ae912183d0f8eb90d61d511e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 11:55:12 +0000 +Subject: tunnels: do not assume transport header in + iptunnel_pmtud_check_icmp() + +From: Eric Dumazet + +[ Upstream commit 509323077ef79a26ba0c60bb556e45c12c398b2d ] + +In some cases, iptunnel_pmtud_check_icmp() can be called while +skb transport header is not set. + +This triggers an out-of-bound access, because +(typeof(skb->transport_header))~0U is 65535. + +Access the icmp header based on IPv4 network header, +after making sure icmp->type is present in skb linear part. + +Note that iptunnel_pmtud_check_icmpv6()) is fine. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Reported-by: Damiano Melotti +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 5fb437f040ace7..9f6f1b435d8d72 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -262,7 +262,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + { +- const struct icmphdr *icmph = icmp_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); + + if (mtu < 576 || iph->frag_off != htons(IP_DF)) +@@ -273,9 +272,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr)) + return 0; + +- if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type)) +- return 0; ++ if (iph->protocol == IPPROTO_ICMP) { ++ const struct icmphdr *icmph; + ++ if (!pskb_network_may_pull(skb, iph->ihl * 4 + ++ offsetofend(struct icmphdr, type))) ++ return 0; ++ iph = ip_hdr(skb); ++ icmph = (void *)iph + iph->ihl * 4; ++ if (icmp_is_err(icmph->type)) ++ return 0; ++ } + return iptunnel_pmtud_build_icmp(skb, mtu); + } + +-- +2.53.0 + diff --git a/queue-6.6/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch b/queue-6.6/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch new file mode 100644 index 0000000000..7dd1ba6639 --- /dev/null +++ b/queue-6.6/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch @@ -0,0 +1,87 @@ +From 1025d6fb4e752d1157c1da2f519f180a440a94f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +From: Eric Dumazet + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 75e3d7501752df..5fb437f040ace7 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -208,7 +208,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -218,7 +217,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -290,7 +289,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -305,7 +304,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -316,6 +314,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.53.0 + diff --git a/queue-6.6/vsock-keep-poll-shutdown-state-consistent.patch b/queue-6.6/vsock-keep-poll-shutdown-state-consistent.patch new file mode 100644 index 0000000000..f777d8c1e2 --- /dev/null +++ b/queue-6.6/vsock-keep-poll-shutdown-state-consistent.patch @@ -0,0 +1,247 @@ +From ac849fac58ec871af3d1e59c66b0a5459f5c24b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 00:56:36 +0800 +Subject: vsock: keep poll shutdown state consistent + +From: Ziyu Zhang + +[ Upstream commit aae9d8a5528b8ee9ff8dc5d3558b8a9f852a724a ] + +vsock_poll() reads vsk->peer_shutdown before taking the socket lock +to set EPOLLHUP and EPOLLRDHUP, then reads it again after taking +the lock to report EOF readability. A shutdown packet can update +peer_shutdown while poll is waiting for the lock, so one poll invocation +can report EOF readability without the corresponding HUP/RDHUP bits. + +For connectible sockets, take one peer_shutdown snapshot after +lock_sock() and use it for all peer-shutdown-derived poll bits. For +datagram sockets, which do not take lock_sock() in poll(), take one +lockless READ_ONCE() snapshot and pair it with WRITE_ONCE() on the +writer side. + +This keeps the peer-shutdown-derived bits internally consistent for each +poll pass. + +Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") +Signed-off-by: Ziyu Zhang +Link: https://patch.msgid.link/20260519165636.62542-1-ziyuzhang201@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/af_vsock.c | 49 ++++++++++++++++--------- + net/vmw_vsock/hyperv_transport.c | 9 +++-- + net/vmw_vsock/virtio_transport_common.c | 14 ++++--- + net/vmw_vsock/vmci_transport.c | 8 ++-- + 4 files changed, 52 insertions(+), 28 deletions(-) + +diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c +index 187cc259f820b5..a06f708f300c4a 100644 +--- a/net/vmw_vsock/af_vsock.c ++++ b/net/vmw_vsock/af_vsock.c +@@ -522,7 +522,7 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) + */ + sock_reset_flag(sk, SOCK_DONE); + sk->sk_state = TCP_CLOSE; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + } + + if (sk->sk_type == SOCK_SEQPACKET) { +@@ -813,7 +813,7 @@ static struct sock *__vsock_create(struct net *net, + vsk->rejected = false; + vsk->sent_request = false; + vsk->ignore_connecting_rst = false; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout); + INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work); + +@@ -1095,6 +1095,25 @@ static int vsock_shutdown(struct socket *sock, int mode) + return err; + } + ++static __poll_t vsock_poll_shutdown(struct sock *sk, u32 peer_shutdown) ++{ ++ __poll_t mask = 0; ++ ++ /* INET sockets treat local write shutdown and peer write shutdown as a ++ * case of EPOLLHUP set. ++ */ ++ if (sk->sk_shutdown == SHUTDOWN_MASK || ++ ((sk->sk_shutdown & SEND_SHUTDOWN) && ++ (peer_shutdown & SEND_SHUTDOWN))) ++ mask |= EPOLLHUP; ++ ++ if (sk->sk_shutdown & RCV_SHUTDOWN || ++ peer_shutdown & SEND_SHUTDOWN) ++ mask |= EPOLLRDHUP; ++ ++ return mask; ++} ++ + static __poll_t vsock_poll(struct file *file, struct socket *sock, + poll_table *wait) + { +@@ -1112,24 +1131,17 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + /* Signify that there has been an error on this socket. */ + mask |= EPOLLERR; + +- /* INET sockets treat local write shutdown and peer write shutdown as a +- * case of EPOLLHUP set. +- */ +- if ((sk->sk_shutdown == SHUTDOWN_MASK) || +- ((sk->sk_shutdown & SEND_SHUTDOWN) && +- (vsk->peer_shutdown & SEND_SHUTDOWN))) { +- mask |= EPOLLHUP; +- } +- +- if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { +- mask |= EPOLLRDHUP; +- } +- + if (sk_is_readable(sk)) + mask |= EPOLLIN | EPOLLRDNORM; + + if (sock->type == SOCK_DGRAM) { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ ++ /* DGRAM sockets do not take lock_sock() in poll(), so use one ++ * lockless snapshot for all shutdown-derived mask bits. ++ */ ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); ++ + /* For datagram sockets we can read if there is something in + * the queue and write as long as the socket isn't shutdown for + * sending. +@@ -1144,6 +1156,7 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + + } else if (sock_type_connectible(sk->sk_type)) { + const struct vsock_transport *transport; ++ u32 peer_shutdown; + + lock_sock(sk); + +@@ -1176,8 +1189,10 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + * terminated should also be considered read, and we check the + * shutdown flag for that. + */ ++ peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); + if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { ++ peer_shutdown & SEND_SHUTDOWN) { + mask |= EPOLLIN | EPOLLRDNORM; + } + +diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c +index 34871ed1a099c6..865e004ee286f2 100644 +--- a/net/vmw_vsock/hyperv_transport.c ++++ b/net/vmw_vsock/hyperv_transport.c +@@ -264,7 +264,7 @@ static void hvs_do_close_lock_held(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -593,7 +593,9 @@ static int hvs_update_recv_data(struct hvsock *hvs) + return -EIO; + + if (payload_len == 0) +- hvs->vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(hvs->vsk->peer_shutdown, ++ READ_ONCE(hvs->vsk->peer_shutdown) | ++ SEND_SHUTDOWN); + + hvs->recv_data_len = payload_len; + hvs->recv_data_off = 0; +@@ -704,7 +706,8 @@ static s64 hvs_stream_has_data(struct vsock_sock *vsk) + ret = 1; + break; + case 0: +- vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | SEND_SHUTDOWN); + ret = 0; + break; + default: /* -1 */ +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index d4ff9506eaf6d5..16431ef52799db 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -1043,7 +1043,7 @@ static void virtio_transport_do_close(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -1244,12 +1244,15 @@ virtio_transport_recv_connected(struct sock *sk, + case VIRTIO_VSOCK_OP_CREDIT_UPDATE: + sk->sk_write_space(sk); + break; +- case VIRTIO_VSOCK_OP_SHUTDOWN: ++ case VIRTIO_VSOCK_OP_SHUTDOWN: { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_RCV) +- vsk->peer_shutdown |= RCV_SHUTDOWN; ++ peer_shutdown |= RCV_SHUTDOWN; + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_SEND) +- vsk->peer_shutdown |= SEND_SHUTDOWN; +- if (vsk->peer_shutdown == SHUTDOWN_MASK) { ++ peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, peer_shutdown); ++ if (peer_shutdown == SHUTDOWN_MASK) { + if (vsock_stream_has_data(vsk) <= 0 && !sock_flag(sk, SOCK_DONE)) { + (void)virtio_transport_reset(vsk, NULL); + virtio_transport_do_close(vsk, true); +@@ -1264,6 +1267,7 @@ virtio_transport_recv_connected(struct sock *sk, + if (le32_to_cpu(virtio_vsock_hdr(skb)->flags)) + sk->sk_state_change(sk); + break; ++ } + case VIRTIO_VSOCK_OP_RST: + virtio_transport_do_close(vsk, true); + break; +diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c +index 4cd11f355e9d6b..443125e48f2481 100644 +--- a/net/vmw_vsock/vmci_transport.c ++++ b/net/vmw_vsock/vmci_transport.c +@@ -811,7 +811,7 @@ static void vmci_transport_handle_detach(struct sock *sk) + /* On a detach the peer will not be sending or receiving + * anymore. + */ +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + + /* We should not be sending anymore since the peer won't be + * there to receive, but we can still receive if there is data +@@ -1534,7 +1534,9 @@ static int vmci_transport_recv_connected(struct sock *sk, + if (pkt->u.mode) { + vsk = vsock_sk(sk); + +- vsk->peer_shutdown |= pkt->u.mode; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | ++ pkt->u.mode); + sk->sk_state_change(sk); + } + break; +@@ -1551,7 +1553,7 @@ static int vmci_transport_recv_connected(struct sock *sk, + * a clean shutdown. + */ + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + +-- +2.53.0 + diff --git a/queue-6.6/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch b/queue-6.6/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch new file mode 100644 index 0000000000..4f9733c0d8 --- /dev/null +++ b/queue-6.6/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch @@ -0,0 +1,54 @@ +From 2dd2376124ba04bd65611ef2192912e42c3ca6df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:36:42 +0000 +Subject: vxlan: do not reuse cached ip_hdr() value after + skb_tunnel_check_pmtu() + +From: Eric Dumazet + +[ Upstream commit 7d9ef0cb271555d8cf39fefe6c981e1493b25ecf ] + +skb_tunnel_check_pmtu() can change skb->head. + +Reusing old_iph afer skb_tunnel_check_pmtu() can cause an UAF. + +Use instead ip_hdr(skb) as done in drivers/net/bareudp.c +and drivers/net/geneve.c. + +Found by Sashiko. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525203642.2389723-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index 1a973dcf256127..958d3be4f99086 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2607,7 +2607,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), + vni, md, flags, udp_sum); +@@ -2670,7 +2670,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip6_dst_hoplimit(ndst); + skb_scrub_packet(skb, xnet); + err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), +-- +2.53.0 + diff --git a/queue-6.6/xfrm-check-for-underflow-in-xfrm_state_mtu.patch b/queue-6.6/xfrm-check-for-underflow-in-xfrm_state_mtu.patch new file mode 100644 index 0000000000..bae8be8261 --- /dev/null +++ b/queue-6.6/xfrm-check-for-underflow-in-xfrm_state_mtu.patch @@ -0,0 +1,85 @@ +From cf3c217fc7e297fc037e31a97775ef5f341a6978 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 10:49:14 -0600 +Subject: xfrm: Check for underflow in xfrm_state_mtu + +From: David Ahern + +[ Upstream commit 742b04d0550b0ec89dcbc99537ec88653bd1ad90 ] + +Leo Lin reported OOB write issue in esp component: + + xfrm_state_mtu() returns u32 but performs its arithmetic in unsigned + modulo-2^32 space using an attacker-influenced "header_len + authsize + + net_adj" subtracted from a small "mtu" argument. A nobody user can + install an IPv4 ESP tunnel SA with a large authentication key + (XFRMA_ALG_AUTH_TRUNC, e.g. hmac(sha512), 64-byte key, 64-byte trunc), + configure a small interface MTU (68 bytes), and set XFRMA_TFCPAD to a + large value. When a single UDP datagram is then sent through the + tunnel, xfrm_state_mtu() underflows to a near-2^32 value, and + esp_output() consumes it as a signed int via: + + padto = min(x->tfcpad, xfrm_state_mtu(x, mtu_cached)) + esp.tfclen = padto - skb->len (assigned to int) + + esp.tfclen ends up negative (e.g. -207). It is sign-extended to size_t + when passed to memset() inside esp_output_fill_trailer(), producing a + ~16 EB write of zeroes at skb_tail_pointer(skb). KASAN logs it as + "Write of size 18446744073709551537 at addr ffff888...". + +Check for underflow and return 1. This causes the sendmsg attempt to +fail with ENETUNREACH. + +Fixes: c5c252389374 ("[XFRM]: Optimize MTU calculation") +Reported-by: Leo Lin +Assisted-by: Codex:26.506.31004 +Signed-off-by: David Ahern +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_state.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index 8ba31cf9b31993..6e8860779e2154 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -2860,10 +2860,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + const struct xfrm_type *type = READ_ONCE(x->type); + struct crypto_aead *aead; + u32 blksize, net_adj = 0; ++ u32 overhead, payload_mtu; + + if (x->km.state != XFRM_STATE_VALID || +- !type || type->proto != IPPROTO_ESP) ++ !type || type->proto != IPPROTO_ESP) { ++ if (mtu <= x->props.header_len) ++ return 1; + return mtu - x->props.header_len; ++ } + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); +@@ -2883,8 +2887,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + break; + } + +- return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - +- net_adj) & ~(blksize - 1)) + net_adj - 2; ++ overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj; ++ if (mtu <= overhead) ++ return 1; ++ ++ payload_mtu = mtu - overhead; ++ payload_mtu &= ~(blksize - 1); ++ if (payload_mtu <= 2) ++ return 1; ++ ++ return payload_mtu + net_adj - 2; ++ + } + EXPORT_SYMBOL_GPL(xfrm_state_mtu); + +-- +2.53.0 + diff --git a/queue-7.0/accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch b/queue-7.0/accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch new file mode 100644 index 0000000000..aa8f015b8a --- /dev/null +++ b/queue-7.0/accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch @@ -0,0 +1,40 @@ +From 564b0913fb1d645c6cc17421362708ea1aa98154 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 10:14:42 +0300 +Subject: accel/ivpu: prevent uninitialized data bug in debugfs + +From: Dan Carpenter + +[ Upstream commit 44e151be23deb788d9f6124de93823faf6e04e99 ] + +The simple_write_to_buffer() will only initialize data starting from +the *pos offset so if it's non-zero then the first part of the buffer +uninitialized. Really, if *pos is non-zero then this code won't work +so just check for that at the start of the function. + +Fixes: 320323d2e545 ("accel/ivpu: Add debugfs interface for setting HWS priority bands") +Signed-off-by: Dan Carpenter +Reviewed-by: Karol Wachowski +Signed-off-by: Karol Wachowski +Link: https://patch.msgid.link/ahP24m6Mii9EDL7Q@stanley.mountain +Signed-off-by: Sasha Levin +--- + drivers/accel/ivpu/ivpu_debugfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c +index a09f54fc430206..e93883914bc274 100644 +--- a/drivers/accel/ivpu/ivpu_debugfs.c ++++ b/drivers/accel/ivpu/ivpu_debugfs.c +@@ -440,7 +440,7 @@ priority_bands_fops_write(struct file *file, const char __user *user_buf, size_t + u32 band; + int ret; + +- if (size >= sizeof(buf)) ++ if (*pos != 0 || size >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, pos, user_buf, size); +-- +2.53.0 + diff --git a/queue-7.0/accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch b/queue-7.0/accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch new file mode 100644 index 0000000000..0de20fa19d --- /dev/null +++ b/queue-7.0/accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch @@ -0,0 +1,86 @@ +From 2bb0f440aee93dcf22269b22a0b3361c206510ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 00:00:00 +0530 +Subject: accel/rocket: fix UAF via dangling GEM handle in create_bo + +From: Dhabaleshwar Das + +[ Upstream commit f706e6a4ce75585af979aec3dcbdce68bc76306b ] + +rocket_ioctl_create_bo() inserts a GEM handle into the file's IDR via +drm_gem_handle_create() early on, then performs several operations that +can fail (sgt allocation, drm_mm insert, iommu_map). If any fail after +the handle is live, the error path calls drm_gem_shmem_object_free() +which kfree's the object without removing the handle from the IDR. + +This leaves a dangling handle pointing to freed slab memory. Any +subsequent ioctl using that handle (PREP_BO, FINI_BO, SUBMIT) calls +drm_gem_object_lookup() and dereferences freed memory (UAF). + +Fix by moving drm_gem_handle_create() to after all fallible operations +succeed, matching the pattern used by panfrost, lima, and etnaviv. + +Also fix drm_mm_insert_node_generic() whose return value was silently +overwritten by iommu_map_sgtable() on the next line. Add the missing +error check. + +[tomeu: Move handle creation to the very end] + +Fixes: 658ebeac3351 ("accel/rocket: Add IOCTL for BO creation") +Reported-by: Dhabaleshwar Das +Signed-off-by: Dhabaleshwar Das +Reviewed-by: Tomeu Vizoso +Link: https://patch.msgid.link/20260521165720.2113571-1-tomeu@tomeuvizoso.net +Signed-off-by: Tomeu Vizoso +Signed-off-by: Sasha Levin +--- + drivers/accel/rocket/rocket_gem.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/accel/rocket/rocket_gem.c b/drivers/accel/rocket/rocket_gem.c +index c8084719208a2a..a5fffa51ff3550 100644 +--- a/drivers/accel/rocket/rocket_gem.c ++++ b/drivers/accel/rocket/rocket_gem.c +@@ -79,11 +79,6 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * + rkt_obj->size = args->size; + rkt_obj->offset = 0; + +- ret = drm_gem_handle_create(file, gem_obj, &args->handle); +- drm_gem_object_put(gem_obj); +- if (ret) +- goto err; +- + sgt = drm_gem_shmem_get_pages_sgt(shmem_obj); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); +@@ -95,6 +90,8 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * + rkt_obj->size, PAGE_SIZE, + 0, 0); + mutex_unlock(&rocket_priv->mm_lock); ++ if (ret) ++ goto err; + + ret = iommu_map_sgtable(rocket_priv->domain->domain, + rkt_obj->mm.start, +@@ -112,8 +109,18 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * + args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); + args->dma_address = rkt_obj->mm.start; + ++ ret = drm_gem_handle_create(file, gem_obj, &args->handle); ++ if (ret) ++ goto err_unmap; ++ ++ drm_gem_object_put(gem_obj); ++ + return 0; + ++err_unmap: ++ iommu_unmap(rocket_priv->domain->domain, ++ rkt_obj->mm.start, rkt_obj->size); ++ + err_remove_node: + mutex_lock(&rocket_priv->mm_lock); + drm_mm_remove_node(&rkt_obj->mm); +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-cs35l56-fix-system-name-string-leaks.patch b/queue-7.0/alsa-hda-cs35l56-fix-system-name-string-leaks.patch new file mode 100644 index 0000000000..071478cdec --- /dev/null +++ b/queue-7.0/alsa-hda-cs35l56-fix-system-name-string-leaks.patch @@ -0,0 +1,92 @@ +From ed968acc372b417b96251efb0f17cb4b2fab8177 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 09:49:30 -0300 +Subject: ALSA: hda: cs35l56: Fix system name string leaks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit a0d9e8df2ebca290c2efff70abc05426e5a476b0 ] + +cs35l56_hda_read_acpi() gets an allocated ACPI _SUB string from +acpi_get_subsystem_id(). On success, that string is used to create the +firmware system name. + +Several error paths after the _SUB lookup can return without releasing +the allocated string. This includes speaker ID lookup errors other than +-ENOENT, and errors after a firmware system name has been allocated. + +Use scoped cleanup for the temporary _SUB string and make +cs35l56->system_name device-managed. This releases the temporary _SUB +string on every error path and lets devres release the firmware system +name on probe failure and device removal. + +Fixes: 6f03b446cbae ("ALSA: hda: cs35l56: Add support for speaker id") +Fixes: 40b1c2f9b299 ("ALSA: hda/cs35l56: Workaround bad dev-index on Lenovo Yoga Book 9i GenX") +Signed-off-by: Cássio Gabriel +Reviewed-by: Richard Fitzgerald +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260522-alsa-cs35l56-system-name-leak-v4-1-a6154dd09cd9@gmail.com +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l56_hda.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c +index cdbc576569efee..a0ea08eb96a93f 100644 +--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c ++++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c +@@ -1025,7 +1025,7 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + u32 values[HDA_MAX_COMPONENTS]; + char hid_string[8]; + struct acpi_device *adev; +- const char *property, *sub; ++ const char *property; + int i, ret; + + /* +@@ -1047,7 +1047,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + /* Initialize things that could be overwritten by a fixup */ + cs35l56->index = -1; + +- sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev)); ++ const char *sub __free(kfree) = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev)); ++ + ret = cs35l56_hda_apply_platform_fixups(cs35l56, sub, &id); + if (ret) + return ret; +@@ -1095,15 +1096,16 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, + cs35l56->num_amps, -1); + if (ret == -ENOENT) { +- cs35l56->system_name = sub; ++ cs35l56->system_name = devm_kstrdup(cs35l56->base.dev, sub, GFP_KERNEL); + } else if (ret >= 0) { +- cs35l56->system_name = kasprintf(GFP_KERNEL, "%s-spkid%d", sub, ret); +- kfree(sub); +- if (!cs35l56->system_name) +- return -ENOMEM; ++ cs35l56->system_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, ++ "%s-spkid%d", sub, ret); + } else { + return ret; + } ++ ++ if (!cs35l56->system_name) ++ return -ENOMEM; + } + + cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev, +@@ -1254,7 +1256,6 @@ void cs35l56_hda_remove(struct device *dev) + + cs_dsp_remove(&cs35l56->cs_dsp); + +- kfree(cs35l56->system_name); + pm_runtime_put_noidle(cs35l56->base.dev); + + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); +-- +2.53.0 + diff --git a/queue-7.0/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch b/queue-7.0/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch new file mode 100644 index 0000000000..7be990f732 --- /dev/null +++ b/queue-7.0/alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch @@ -0,0 +1,84 @@ +From 8d1a022b4f8644d835bbec9cf08167ad1bd7bc55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 22:09:40 -0300 +Subject: ALSA: pcm: oss: Fix setup list UAF on proc write error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 4cc54bdd54b337e77115be5b55577d1c58608eae ] + +snd_pcm_oss_proc_write() links a newly allocated setup entry into the +OSS setup list before duplicating the task name. If the task-name +allocation fails, the error path frees the already linked entry and +leaves setup_list pointing at freed memory. + +A later OSS device open can then walk the stale list entry in +snd_pcm_oss_look_for_setup() and dereference freed memory. + +Allocate the task name and initialize the setup entry before publishing +the entry on setup_list. Also fetch the initial proc read iterator only +after taking setup_mutex, so all setup_list traversal follows the same +list lifetime rules. + +Reported-by: syzbot+8e498074a794999eb41c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a1062b7.170a0220.35b2b7.0003.GAE@google.com +Closes: https://syzkaller.appspot.com/bug?extid=8e498074a794999eb41c +Fixes: 060d77b9c04a ("[ALSA] Fix / clean up PCM-OSS setup hooks") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260522-alsa-pcm-oss-setup-uaf-v1-1-40bdcc4d17e8@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/oss/pcm_oss.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index 6af26ec2ecfd59..b1b4c7d017beea 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -2968,8 +2968,10 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) + { + struct snd_pcm_str *pstr = entry->private_data; +- struct snd_pcm_oss_setup *setup = pstr->oss.setup_list; ++ struct snd_pcm_oss_setup *setup; ++ + guard(mutex)(&pstr->oss.setup_mutex); ++ setup = pstr->oss.setup_list; + while (setup) { + snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n", + setup->task_name, +@@ -3054,6 +3056,13 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, + buffer->error = -ENOMEM; + return; + } ++ template.task_name = kstrdup(task_name, GFP_KERNEL); ++ if (!template.task_name) { ++ kfree(setup); ++ buffer->error = -ENOMEM; ++ return; ++ } ++ *setup = template; + if (pstr->oss.setup_list == NULL) + pstr->oss.setup_list = setup; + else { +@@ -3061,12 +3070,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, + setup1->next; setup1 = setup1->next); + setup1->next = setup; + } +- template.task_name = kstrdup(task_name, GFP_KERNEL); +- if (! template.task_name) { +- kfree(setup); +- buffer->error = -ENOMEM; +- return; +- } ++ continue; + } + *setup = template; + } +-- +2.53.0 + diff --git a/queue-7.0/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch b/queue-7.0/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch new file mode 100644 index 0000000000..c8b3bf5f9a --- /dev/null +++ b/queue-7.0/asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch @@ -0,0 +1,47 @@ +From 959828173499d1f14b397934a4dca342be225927 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 09:24:00 -0300 +Subject: ASoC: codecs: simple-mux: Fix enum control bounds check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit f63ad68e18d774a5d15cd7e405ead63f6b322679 ] + +simple_mux_control_put() rejects values greater than e->items, but +enum control values are zero based. For the two-entry mux used by this +driver, valid values are 0 and 1, so value 2 must be rejected as well. + +Accepting e->items can store an invalid mux state, pass it to the GPIO +setter, and pass it on to the DAPM mux update path where it is used as +an index into the enum text array. + +Use the same >= e->items check used by the ASoC enum helpers. + +Fixes: 342fbb7578d1 ("ASoC: add simple-mux") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260527-asoc-simple-mux-enum-bounds-v1-1-3f805b9fc671@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/simple-mux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c +index 069555f35f7359..c2f906a3f074ce 100644 +--- a/sound/soc/codecs/simple-mux.c ++++ b/sound/soc/codecs/simple-mux.c +@@ -51,7 +51,7 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + +- if (ucontrol->value.enumerated.item[0] > e->items) ++ if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + if (priv->mux == ucontrol->value.enumerated.item[0]) +-- +2.53.0 + diff --git a/queue-7.0/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch b/queue-7.0/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch new file mode 100644 index 0000000000..b3a023e685 --- /dev/null +++ b/queue-7.0/asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch @@ -0,0 +1,112 @@ +From 99ceb52e3882357e2d6ce74a52d86a113fb6159a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 13:51:47 -0300 +Subject: ASoC: Intel: bytcht_es8316: Fix MCLK leak on init errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit afb2a3a9d8369d18122a0d7cd294eba9a98259c6 ] + +byt_cht_es8316_init() enables MCLK before configuring the codec sysclk +and creating the headset jack. If either of those later steps fails, the +function returns without disabling MCLK, leaving the clock enabled after +card registration fails. + +Track whether this driver enabled MCLK and disable it on the init error +paths. Add the matching DAI link exit callback so the same clock enable +is also balanced when ASoC cleans up a successfully initialized link. + +Fixes: a03bdaa565cb ("ASoC: Intel: add machine driver for BYT/CHT + ES8316") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-asoc-bytcht-es8316-mclk-leak-v1-1-b4a11cdc2afd@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_es8316.c | 29 ++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index 192e2a394ff3d0..ea387dc7427382 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -40,6 +40,7 @@ struct byt_cht_es8316_private { + struct gpio_desc *speaker_en_gpio; + struct device *codec_dev; + bool speaker_en; ++ bool mclk_enabled; + }; + + enum { +@@ -170,6 +171,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + }, + }; + ++static void byt_cht_es8316_disable_mclk(struct byt_cht_es8316_private *priv) ++{ ++ if (!priv->mclk_enabled) ++ return; ++ ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++} ++ + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + { + struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; +@@ -227,12 +237,14 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); ++ else ++ priv->mclk_enabled = true; + + ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(runtime, 0), 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset", +@@ -241,13 +253,25 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); +- return ret; ++ goto err_disable_mclk; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + + return 0; ++ ++err_disable_mclk: ++ byt_cht_es8316_disable_mclk(priv); ++ return ret; ++} ++ ++static void byt_cht_es8316_exit(struct snd_soc_pcm_runtime *runtime) ++{ ++ struct snd_soc_card *card = runtime->card; ++ struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); ++ ++ byt_cht_es8316_disable_mclk(priv); + } + + static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -353,6 +377,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + | SND_SOC_DAIFMT_CBC_CFC, + .be_hw_params_fixup = byt_cht_es8316_codec_fixup, + .init = byt_cht_es8316_init, ++ .exit = byt_cht_es8316_exit, + SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/blk-mq-reinsert-cached-request-to-the-list.patch b/queue-7.0/blk-mq-reinsert-cached-request-to-the-list.patch new file mode 100644 index 0000000000..cfc7dc3ff1 --- /dev/null +++ b/queue-7.0/blk-mq-reinsert-cached-request-to-the-list.patch @@ -0,0 +1,44 @@ +From a227639fbfd866fd17e126e0ff263df8ff8893fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:31 -0700 +Subject: blk-mq: reinsert cached request to the list + +From: Keith Busch + +[ Upstream commit b051bb6bf0a231117036aa607cadf55be8e63910 ] + +A previous commit removed an optimization out of caution for a scenario +that turns out not to be real: all the "queue_exit" goto's are safe to +reinsert the request into the cached_rq's plug list as they are either +from a non-blocking path, or a successful merge that already holds the +queue reference. This optimization is most needed for small sequential +workloads that successfully merge into larger requests. + +Fixes: dc278e9bf2b9 ("blk-mq: pop cached request if it is usable") +Suggested-by: Ming Lei +Suggested-by: Christoph Hellwig +Signed-off-by: Keith Busch +Reviewed-by: Chaitanya Kulkarni +Link: https://patch.msgid.link/20260526153531.2365935-1-kbusch@meta.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-mq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 39986a742b981a..061c8ef4484a25 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -3244,7 +3244,7 @@ void blk_mq_submit_bio(struct bio *bio) + if (!rq) + blk_queue_exit(q); + else +- blk_mq_free_request(rq); ++ rq_list_add_head(&plug->cached_rqs, rq); + } + + #ifdef CONFIG_BLK_MQ_STACKING +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch b/queue-7.0/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch new file mode 100644 index 0000000000..8375d50720 --- /dev/null +++ b/queue-7.0/bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch @@ -0,0 +1,40 @@ +From c8907a61c18236cd18ddd34f089d2635478d3ab6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 11:21:39 +0800 +Subject: Bluetooth: 6lowpan: check skb_clone() return value in + send_mcast_pkt() + +From: Zhao Dongdong + +[ Upstream commit 3c40d381ce04f9575a5d8b542898183c3b4b38dc ] + +The skb_clone() function can return NULL if memory allocation fails. +send_mcast_pkt() calls skb_clone() without checking the return value, which +can lead to a NULL pointer dereference in send_pkt() when it dereferences +skb->data. +Add a NULL check after skb_clone() and skip the peer if the clone fails. + +Fixes: 18722c247023 ("Bluetooth: Enable 6LoWPAN support for BT LE devices") +Signed-off-by: Zhao Dongdong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/6lowpan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index 2f03b780b40d84..960a19b3e26da1 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -486,6 +486,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) + int ret; + + local_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!local_skb) ++ continue; + + BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p", + netdev->name, +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch b/queue-7.0/bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch new file mode 100644 index 0000000000..c0a4a46d4c --- /dev/null +++ b/queue-7.0/bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch @@ -0,0 +1,38 @@ +From 0b8f63d390a8819be50aa98f2fdcdcf0c1bf635b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 10:50:59 -0300 +Subject: Bluetooth: hci_sync: Reset device counters in hci_dev_close_sync() + +From: Heitor Alves de Siqueira + +[ Upstream commit cdf88b35e06f1b385f7f6228060ae541d44fbb72 ] + +Before resetting or closing the device, protocol counters should also be +zeroed. + +Fixes: d0b137062b2d ("Bluetooth: hci_sync: Rework init stages") +Signed-off-by: Heitor Alves de Siqueira +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sync.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 80b71e39656faf..35988eace9e4f4 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -5393,6 +5393,10 @@ int hci_dev_close_sync(struct hci_dev *hdev) + /* Reset device */ + skb_queue_purge(&hdev->cmd_q); + atomic_set(&hdev->cmd_cnt, 1); ++ hdev->acl_cnt = 0; ++ hdev->sco_cnt = 0; ++ hdev->le_cnt = 0; ++ hdev->iso_cnt = 0; + if (hci_test_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE) && + !auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { + set_bit(HCI_INIT, &hdev->flags); +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch b/queue-7.0/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch new file mode 100644 index 0000000000..d97a10c677 --- /dev/null +++ b/queue-7.0/bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch @@ -0,0 +1,57 @@ +From 35a912c06c6b00ef57e1ae9934c2f76dccd70f43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 10:50:58 -0300 +Subject: Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close + +From: Heitor Alves de Siqueira + +[ Upstream commit 525daaea459fc215f432de1b8debbd9144bf97b0 ] + +Since hci_dev_close_sync() can now be called during the reset path, we +should also set HCI_CMD_DRAIN_WORKQUEUE. This avoids queuing timeouts +while the hdev workqueue is being drained. + +Fixes: 877afadad2dc ("Bluetooth: When HCI work queue is drained, only queue chained work") +Signed-off-by: Heitor Alves de Siqueira +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_sync.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 426f465be35533..80b71e39656faf 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -5301,6 +5301,12 @@ int hci_dev_close_sync(struct hci_dev *hdev) + + bt_dev_dbg(hdev, ""); + ++ /* Set HCI_DRAIN_WORKQUEUE flag to prevent queuing work during ++ * reset/close. See hci_cmd_work() and handle_cmd_cnt_and_timer(). ++ */ ++ hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); ++ synchronize_rcu(); ++ + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + disable_delayed_work(&hdev->power_off); + disable_delayed_work(&hdev->ncmd_timer); +@@ -5324,6 +5330,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) + + if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { + cancel_delayed_work_sync(&hdev->cmd_timer); ++ hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + return err; + } + +@@ -5423,6 +5430,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) + /* Clear flags */ + hdev->flags &= BIT(HCI_RAW); + hci_dev_clear_volatile_flags(hdev); ++ hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch b/queue-7.0/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch new file mode 100644 index 0000000000..be62366f0b --- /dev/null +++ b/queue-7.0/bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch @@ -0,0 +1,62 @@ +From 1471327a723ed39148ab4b7d9408cf2f29fb3a25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:51:52 +0800 +Subject: Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success + +From: Zhenghang Xiao + +[ Upstream commit 00e1950716c6ed67d74777b2db286b0fa23b4be9 ] + +l2cap_ecred_reconf_rsp() returns early on success without clearing +chan->ident. Every other L2CAP response handler (l2cap_ecred_conn_rsp, +l2cap_le_connect_rsp, l2cap_config_rsp) clears chan->ident after a +successful transaction to prevent the channel from matching subsequent +responses with the recycled ident value. + +A remote attacker that completed a reconfiguration as the peer can +replay a failure response with the stale ident, causing the kernel to +match and destroy the already-established channel via +l2cap_chan_del(chan, ECONNRESET). + +Clear chan->ident for all matching channels on success, and harden the +failure path by using l2cap_chan_hold_unless_zero() consistent with +other L2CAP handlers (l2cap_le_command_rej, __l2cap_get_chan_by_ident). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 99297d8f2c1f34..83ea31926bd0f8 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5466,14 +5466,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + + BT_DBG("result 0x%4.4x", result); + +- if (!result) ++ if (!result) { ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ if (chan->ident == cmd->ident) ++ chan->ident = 0; ++ } + return 0; ++ } + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + if (chan->ident != cmd->ident) + continue; + +- l2cap_chan_hold(chan); ++ if (!l2cap_chan_hold_unless_zero(chan)) ++ continue; + l2cap_chan_lock(chan); + + l2cap_chan_del(chan, ECONNRESET); +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch b/queue-7.0/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch new file mode 100644 index 0000000000..60e06c813f --- /dev/null +++ b/queue-7.0/bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch @@ -0,0 +1,82 @@ +From cc27c20a01b88f545defdcdf3fe543d332ec7ffc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 12:09:42 -0400 +Subject: Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp + +From: Luiz Augusto von Dentz + +[ Upstream commit 41c2713b204e6cb6a94587bc6bf6935107df5479 ] + +If dcid is received for an already-assigned destination CID the spec +requires that both channels to be discarded, but calling l2cap_chan_del +may invalidate the tmp cursor created by list_for_each_entry_safe and +in fact it is the wrong procedure as the chan->dcid may be assigned +previously it really needs to be disconnected. + +Calling l2cap_chan_clone directly may still lead to l2cap_chan_del so +instead schedule l2cap_chan_timeout with delay 0 to close the channel +asynchronously. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 83ea31926bd0f8..27b5d459e1217c 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5268,6 +5268,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + cmd_len -= sizeof(*rsp); + + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct l2cap_chan *orig; + u16 dcid; + + if (chan->ident != cmd->ident || +@@ -5289,8 +5290,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + + BT_DBG("dcid[%d] 0x%4.4x", i, dcid); + ++ orig = __l2cap_get_chan_by_dcid(conn, dcid); ++ + /* Check if dcid is already in use */ +- if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { ++ if (dcid && orig) { + /* If a device receives a + * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an + * already-assigned Destination CID, then both the +@@ -5299,10 +5302,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, + */ + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); +- chan = __l2cap_get_chan_by_dcid(conn, dcid); +- l2cap_chan_lock(chan); +- l2cap_chan_del(chan, ECONNRESET); +- l2cap_chan_unlock(chan); ++ ++ /* Check that the dcid channel mode is ++ * L2CAP_MODE_EXT_FLOWCTL since this procedure is only ++ * valid for that mode and shouldn't disconnect a dcid ++ * in other modes. ++ */ ++ if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) { ++ l2cap_chan_lock(orig); ++ /* Disconnect the original channel as it may be ++ * considered connected since dcid has already ++ * been assigned; don't call l2cap_chan_close ++ * directly since that could lead to ++ * l2cap_chan_del and then removing the channel ++ * from the list while we're iterating over it. ++ */ ++ __set_chan_timer(orig, 0); ++ l2cap_chan_unlock(orig); ++ } + continue; + } + +-- +2.53.0 + diff --git a/queue-7.0/bonding-refuse-to-enslave-can-devices.patch b/queue-7.0/bonding-refuse-to-enslave-can-devices.patch new file mode 100644 index 0000000000..48b434a175 --- /dev/null +++ b/queue-7.0/bonding-refuse-to-enslave-can-devices.patch @@ -0,0 +1,74 @@ +From e456d6c0731704887d708fcb72791b742b7f6683 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:33:19 +0200 +Subject: bonding: refuse to enslave CAN devices + +From: Oliver Hartkopp + +[ Upstream commit 8ba68464e4787b6a7ec938826e16124df20fd23d ] + +syzbot reported a kernel paging request crash in +can_rx_unregister() inside net/can/af_can.c. The crash occurs +because a virtual CAN device (vxcan) is being enslaved to a +bonding master. + +During the enslavement process, the bonding driver mutates +and modifies the network device states to fit an Ethernet-like +aggregation model. However, CAN devices operate on a completely +different Layer 2 architecture, relying on the CAN mid-layer +private data structure (can_ml_priv) instead of standard +Ethernet structures. Since bonding does not initialize or +maintain these CAN structures, subsequent operations on the +half-enslaved interface (such as closing associated sockets +via isotp_release) lead to a null-pointer dereference when +accessing the CAN receiver lists. + +Bonding CAN interfaces is architecturally invalid as CAN lacks +MAC addresses, ARP capabilities, and standard Ethernet +link-layer mechanisms. While generic loopback devices are +blocked globally in net/core/dev.c, virtual CAN devices +bypass this check because they do not carry the IFF_LOOPBACK +flag, despite acting as local software-loopbacks. + +Fix this by explicitly blocking network devices of type +ARPHRD_CAN from being enslaved at the very beginning of +bond_enslave(). This prevents illegal state mutations, +eliminates the resulting KASAN crashes, and avoids potential +memory leaks from incomplete socket cleanups. + +As the CAN support has been added a long time after bonding +the Fixes-tag points to the introduction of ARPHRD_CAN that +would have needed a specific handling in bonding_main.c. + +Fixes: cd05acfe65ed ("[CAN]: Allocate protocol numbers for PF_CAN") +Reported-by: syzbot+8ed98cbd0161632bce95@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8ed98cbd0161632bce95 +Signed-off-by: Oliver Hartkopp +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260526-bonding-candev-v1-1-ba1df400918a@hartkopp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index eb49ce486992de..d6a1e814878f28 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1892,6 +1892,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, + struct sockaddr_storage ss; + int res = 0, i; + ++ if (slave_dev->type == ARPHRD_CAN) { ++ BOND_NL_ERR(bond_dev, extack, ++ "CAN devices cannot be enslaved"); ++ return -EPERM; ++ } ++ + if (slave_dev->flags & IFF_MASTER && + !netif_is_bond_master(slave_dev)) { + BOND_NL_ERR(bond_dev, extack, +-- +2.53.0 + diff --git a/queue-7.0/bridge-fix-sleep-in-atomic-context-in-netlink-path.patch b/queue-7.0/bridge-fix-sleep-in-atomic-context-in-netlink-path.patch new file mode 100644 index 0000000000..66db3a4902 --- /dev/null +++ b/queue-7.0/bridge-fix-sleep-in-atomic-context-in-netlink-path.patch @@ -0,0 +1,149 @@ +From 178c953d89bb7ce63cdd15e6f1e3a6bc32f7c5ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 09:48:16 +0300 +Subject: bridge: Fix sleep in atomic context in netlink path + +From: Ido Schimmel + +[ Upstream commit 5eec4427b89c2fb2beac54920101e55a2f1c0c21 ] + +Since the introduction of the netlink configuration path for bridge +ports in commit 25c71c75ac87 ("bridge: bridge port parameters over +netlink"), br_setport() was always called with the bridge lock held +around it. Back then this decision made sense: The bridge lock protects +the STP state of the bridge and its ports and at that time the function +only processed three STP related netlink attributes (cost, priority and +state). + +Nowadays, br_setport() processes a lot more attributes and most of them +do not need the bridge lock: + +* Bridge flags: Only require RTNL. Read locklessly by the data path. + Annotations can be added in net-next. + +* FDB port flushing: Only requires the FDB lock. + +* Multicast attributes: Only require the multicast lock. + +* Group forward mask: Only requires RTNL. Read locklessly by the data + path. Annotations can be added in net-next. + +* Backup port and NHID: Only require RTNL. Read locklessly by the data + path. + +This is a problem as the bridge calls dev_set_promiscuity() when certain +bridge port flags change and this function can sleep since the commit +cited below, resulting in a splat such as [1]. + +Fix this by reducing the scope of the bridge lock and only take it when +processing the three STP related attributes that require it. This is +consistent with the multicast attributes where each attribute acquires +the multicast lock instead of having one critical section for all +relevant attributes. + +[1] +BUG: sleeping function called from invalid context at net/core/dev_addr_lists.c:1262 +in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 356, name: bridge +preempt_count: 201, expected: 0 +RCU nest depth: 0, expected: 0 +2 locks held by bridge/356: +#0: ffffffff919473a0 (rtnl_mutex){+.+.}-{4:4}, at: rtnetlink_rcv_msg (net/core/rtnetlink.c:80 net/core/rtnetlink.c:7002) +#1: ffff888115072d58 (&br->lock){+...}-{3:3}, at: br_setlink (./include/linux/spinlock.h:348 net/bridge/br_netlink.c:1117) +Preemption disabled at: + 0x0 +Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +__might_resched.cold (kernel/sched/core.c:9163) +netif_rx_mode_run (net/core/dev_addr_lists.c:1262) +netif_rx_mode_sync (net/core/dev_addr_lists.c:1428) +dev_set_promiscuity (net/core/dev_api.c:289) +br_manage_promisc (net/bridge/br_if.c:135 net/bridge/br_if.c:172) +br_port_flags_change (net/bridge/br_if.c:242 net/bridge/br_if.c:747) +br_setport (net/bridge/br_netlink.c:1000) +br_setlink (net/bridge/br_netlink.c:1118) +rtnl_bridge_setlink (net/core/rtnetlink.c:5572) +rtnetlink_rcv_msg (net/core/rtnetlink.c:7005) +netlink_rcv_skb (net/netlink/af_netlink.c:2550) +netlink_unicast (net/netlink/af_netlink.c:1318 net/netlink/af_netlink.c:1344) +netlink_sendmsg (net/netlink/af_netlink.c:1894) +__sock_sendmsg (net/socket.c:787 (discriminator 4) net/socket.c:802 (discriminator 4)) +____sys_sendmsg (net/socket.c:2698) +___sys_sendmsg (net/socket.c:2752) +__sys_sendmsg (net/socket.c:2784) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 78cd408356fe ("net: add missing instance lock to dev_set_promiscuity") +Reviewed-by: Nikolay Aleksandrov +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260526064818.272516-2-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/bridge/br_netlink.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c +index 0264730938f4b2..2ad502bfbd55e5 100644 +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -1000,19 +1000,25 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[], + br_port_flags_change(p, changed_mask); + + if (tb[IFLA_BRPORT_COST]) { ++ spin_lock_bh(&p->br->lock); + err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST])); ++ spin_unlock_bh(&p->br->lock); + if (err) + return err; + } + + if (tb[IFLA_BRPORT_PRIORITY]) { ++ spin_lock_bh(&p->br->lock); + err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY])); ++ spin_unlock_bh(&p->br->lock); + if (err) + return err; + } + + if (tb[IFLA_BRPORT_STATE]) { ++ spin_lock_bh(&p->br->lock); + err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE])); ++ spin_unlock_bh(&p->br->lock); + if (err) + return err; + } +@@ -1114,9 +1120,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags, + if (err) + return err; + +- spin_lock_bh(&p->br->lock); + err = br_setport(p, tb, extack); +- spin_unlock_bh(&p->br->lock); + } else { + /* Binary compatibility with old RSTP */ + if (nla_len(protinfo) < sizeof(u8)) +@@ -1203,17 +1207,10 @@ static int br_port_slave_changelink(struct net_device *brdev, + struct nlattr *data[], + struct netlink_ext_ack *extack) + { +- struct net_bridge *br = netdev_priv(brdev); +- int ret; +- + if (!data) + return 0; + +- spin_lock_bh(&br->lock); +- ret = br_setport(br_port_get_rtnl(dev), data, extack); +- spin_unlock_bh(&br->lock); +- +- return ret; ++ return br_setport(br_port_get_rtnl(dev), data, extack); + } + + static int br_port_fill_slave_info(struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-7.0/bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch b/queue-7.0/bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch new file mode 100644 index 0000000000..e1e015c040 --- /dev/null +++ b/queue-7.0/bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch @@ -0,0 +1,158 @@ +From 1c6f20508c064b8161efaa8ba4f9ef3b551f5752 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 09:48:17 +0300 +Subject: bridge: Fix sleep in atomic context in sysfs path + +From: Ido Schimmel + +[ Upstream commit 6d34594cc619d0d4b07d5afcad8b5984f3526dcf ] + +Since the start of the git history, brport_store() always acquired the +bridge lock. Back then this decision made sense: The bridge lock +protects the STP state of the bridge and its ports and at that time the +function was only used by two STP related attributes (cost and +priority). + +Nowadays, brport_store() processes a lot more attributes and most of +them do not need the bridge lock: + +* Bridge flags: Only require RTNL. Read locklessly by the data path. + Annotations can be added in net-next. + +* FDB port flushing: Only requires the FDB lock. + +* Multicast attributes: Only require the multicast lock. + +* Group forward mask: Only requires RTNL. Read locklessly by the data + path. Annotations can be added in net-next. + +* Backup port: Only requires RTNL. Read locklessly by the data path. + +This is a problem as the bridge calls dev_set_promiscuity() when certain +bridge port flags change and this function can sleep since the commit +cited below, resulting in a splat such as [1]. + +Fix this by reducing the scope of the bridge lock and only take it when +processing the two STP related attributes that require it. Remove the +now stale comment from br_switchdev_set_port_flag(). The +SWITCHDEV_F_DEFER flag can be removed in net-next. + +[1] +BUG: sleeping function called from invalid context at net/core/dev_addr_lists.c:1262 +in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 372, name: bash +preempt_count: 201, expected: 0 +RCU nest depth: 0, expected: 0 +5 locks held by bash/372: +#0: ffff88810c51c3f0 (sb_writers#7){.+.+}-{0:0}, at: ksys_write (fs/read_write.c:740) +#1: ffff888115ce9480 (&of->mutex){+.+.}-{4:4}, at: kernfs_fop_write_iter (fs/kernfs/file.c:343) +#2: ffff88810b9fd330 (kn->active#37){.+.+}-{0:0}, at: kernfs_fop_write_iter (fs/kernfs/file.c:80 fs/kernfs/file.c:344) +#3: ffffffffa59473a0 (rtnl_mutex){+.+.}-{4:4}, at: brport_store (net/bridge/br_sysfs_if.c:326) +#4: ffff8881099d2d58 (&br->lock){+...}-{3:3}, at: brport_store (./include/linux/spinlock.h:348 net/bridge/br_sysfs_if.c:345) +Preemption disabled at: + 0x0 +Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +Call Trace: + +dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) +__might_resched.cold (kernel/sched/core.c:9163) +netif_rx_mode_run (net/core/dev_addr_lists.c:1262) +netif_rx_mode_sync (net/core/dev_addr_lists.c:1428) +dev_set_promiscuity (net/core/dev_api.c:289) +br_manage_promisc (net/bridge/br_if.c:135 net/bridge/br_if.c:172) +br_port_flags_change (net/bridge/br_if.c:242 net/bridge/br_if.c:747) +store_learning (net/bridge/br_sysfs_if.c:79 net/bridge/br_sysfs_if.c:235) +brport_store (net/bridge/br_sysfs_if.c:346) +kernfs_fop_write_iter (fs/kernfs/file.c:352) +new_sync_write (fs/read_write.c:595) +vfs_write (fs/read_write.c:688) +ksys_write (fs/read_write.c:740) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 78cd408356fe ("net: add missing instance lock to dev_set_promiscuity") +Reviewed-by: Nikolay Aleksandrov +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260526064818.272516-3-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/bridge/br_switchdev.c | 1 - + net/bridge/br_sysfs_if.c | 30 ++++++++++++++++++++++-------- + 2 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c +index 4fac002922d22a..58257e9e9d30b6 100644 +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -99,7 +99,6 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, + attr.u.brport_flags.val = flags; + attr.u.brport_flags.mask = mask; + +- /* We run from atomic context here */ + err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev, + &info.info, extack); + err = notifier_to_errno(err); +diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c +index 1f57c36a7fc097..d6df81fa0d13fe 100644 +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -86,16 +86,34 @@ static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) + return sysfs_emit(buf, "%d\n", p->path_cost); + } + +-static BRPORT_ATTR(path_cost, 0644, +- show_path_cost, br_stp_set_path_cost); ++static int store_path_cost(struct net_bridge_port *p, unsigned long v) ++{ ++ int ret; ++ ++ spin_lock_bh(&p->br->lock); ++ ret = br_stp_set_path_cost(p, v); ++ spin_unlock_bh(&p->br->lock); ++ return ret; ++} ++ ++static BRPORT_ATTR(path_cost, 0644, show_path_cost, store_path_cost); + + static ssize_t show_priority(struct net_bridge_port *p, char *buf) + { + return sysfs_emit(buf, "%d\n", p->priority); + } + +-static BRPORT_ATTR(priority, 0644, +- show_priority, br_stp_set_port_priority); ++static int store_priority(struct net_bridge_port *p, unsigned long v) ++{ ++ int ret; ++ ++ spin_lock_bh(&p->br->lock); ++ ret = br_stp_set_port_priority(p, v); ++ spin_unlock_bh(&p->br->lock); ++ return ret; ++} ++ ++static BRPORT_ATTR(priority, 0644, show_priority, store_priority); + + static ssize_t show_designated_root(struct net_bridge_port *p, char *buf) + { +@@ -334,17 +352,13 @@ static ssize_t brport_store(struct kobject *kobj, + ret = -ENOMEM; + goto out_unlock; + } +- spin_lock_bh(&p->br->lock); + ret = brport_attr->store_raw(p, buf_copy); +- spin_unlock_bh(&p->br->lock); + kfree(buf_copy); + } else if (brport_attr->store) { + val = simple_strtoul(buf, &endp, 0); + if (endp == buf) + goto out_unlock; +- spin_lock_bh(&p->br->lock); + ret = brport_attr->store(p, val); +- spin_unlock_bh(&p->br->lock); + } + + if (!ret) { +-- +2.53.0 + diff --git a/queue-7.0/cxl-test-update-mock-dev-array-before-calling-platfo.patch b/queue-7.0/cxl-test-update-mock-dev-array-before-calling-platfo.patch new file mode 100644 index 0000000000..2b7a9d6cb2 --- /dev/null +++ b/queue-7.0/cxl-test-update-mock-dev-array-before-calling-platfo.patch @@ -0,0 +1,272 @@ +From 1b8694628317ca2d2a903b454e4aa534458f9c2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 20:14:57 +0800 +Subject: cxl/test: Update mock dev array before calling platform_device_add() + +From: Li Ming + +[ Upstream commit d90f236f8b9e354848bd226f581db27755ab901d ] + +CXL test environment hits the following error sometimes. + + cxl_mem mem9: endpoint7 failed probe + +All mock memdevs are platform firmware devices added by cxl_test module, +and cxl_test module also provides a platform device driver for them to +create a memdev device to CXL subsystem. cxl_test module uses +cxl_rcd/mem_single/mem arrays to store different types of mock memdevs. +CXL drivers calls registered mock functions for a mock memdev by +checking if a given memdev is in these arrays. + +When cxl_test module adds these mock memdevs, it always calls +platform_device_add() before adding them to a suitable mock memdev +array. However, there is a small window where CXL drivers calls mock +function for a added memdev before it added to a mock memdev array. In +above case, cxl endpoint driver considers a added memdev was not a mock +memdev, then calling devm_cxl_endpoint_decoders_setup() for it rather +than mock_endpoint_decoders_setup(). + +An appropriate solution is that adding a new mock device to a mock +device array before calling platform_device_add() for it. It can +guarantee the new mock device is visible to CXL subsystem. + +This patch introduces a new helped called cxl_mock_platform_device_add() +to handle the issue, and uses the function for all mock devices addition. + +Fixes: 3a2b97b3210b ("cxl/test: Improve init-order fidelity relative to real-world systems") +Signed-off-by: Li Ming +Tested-by: Alison Schofield +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260520121457.234404-1-ming.li@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + tools/testing/cxl/test/cxl.c | 105 ++++++++++++++--------------------- + 1 file changed, 43 insertions(+), 62 deletions(-) + +diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c +index 81e2aef3627a44..f4c26441fc41af 100644 +--- a/tools/testing/cxl/test/cxl.c ++++ b/tools/testing/cxl/test/cxl.c +@@ -1144,6 +1144,23 @@ static void mock_companion(struct acpi_device *adev, struct device *dev) + #define SZ_64G (SZ_32G * 2) + #endif + ++static int cxl_mock_platform_device_add(struct platform_device *pdev, ++ struct platform_device **ppdev) ++{ ++ int rc; ++ ++ if (ppdev) ++ *ppdev = pdev; ++ rc = platform_device_add(pdev); ++ if (rc) { ++ platform_device_put(pdev); ++ if (ppdev) ++ *ppdev = NULL; ++ } ++ ++ return rc; ++} ++ + static __init int cxl_rch_topo_init(void) + { + int rc, i; +@@ -1158,13 +1175,10 @@ static __init int cxl_rch_topo_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_rch[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_rch[i] = pdev; + mock_pci_bus[idx].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "firmware_node"); +@@ -1216,13 +1230,10 @@ static __init int cxl_single_topo_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_hb_single[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_hb_single[i] = pdev; + mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "physical_node"); +@@ -1241,12 +1252,9 @@ static __init int cxl_single_topo_init(void) + goto err_port; + pdev->dev.parent = &bridge->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_root_single[i]); ++ if (rc) + goto err_port; +- } +- cxl_root_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++) { +@@ -1259,12 +1267,9 @@ static __init int cxl_single_topo_init(void) + goto err_uport; + pdev->dev.parent = &root_port->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_swu_single[i]); ++ if (rc) + goto err_uport; +- } +- cxl_swu_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++) { +@@ -1278,12 +1283,9 @@ static __init int cxl_single_topo_init(void) + goto err_dport; + pdev->dev.parent = &uport->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_swd_single[i]); ++ if (rc) + goto err_dport; +- } +- cxl_swd_single[i] = pdev; + } + + return 0; +@@ -1356,12 +1358,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &dport->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_mem[i]); ++ if (rc) + goto err_mem; +- } +- cxl_mem[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) { +@@ -1374,12 +1373,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &dport->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_mem_single[i]); ++ if (rc) + goto err_single; +- } +- cxl_mem_single[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) { +@@ -1393,12 +1389,9 @@ static int cxl_mem_init(void) + pdev->dev.parent = &rch->dev; + set_dev_node(&pdev->dev, i % 2); + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_rcd[i]); ++ if (rc) + goto err_rcd; +- } +- cxl_rcd[i] = pdev; + } + + return 0; +@@ -1463,13 +1456,10 @@ static __init int cxl_test_init(void) + goto err_bridge; + + mock_companion(adev, &pdev->dev); +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_host_bridge[i]); ++ if (rc) + goto err_bridge; +- } + +- cxl_host_bridge[i] = pdev; + mock_pci_bus[i].bridge = &pdev->dev; + rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj, + "physical_node"); +@@ -1487,12 +1477,9 @@ static __init int cxl_test_init(void) + goto err_port; + pdev->dev.parent = &bridge->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_root_port[i]); ++ if (rc) + goto err_port; +- } +- cxl_root_port[i] = pdev; + } + + BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port)); +@@ -1505,12 +1492,9 @@ static __init int cxl_test_init(void) + goto err_uport; + pdev->dev.parent = &root_port->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_switch_uport[i]); ++ if (rc) + goto err_uport; +- } +- cxl_switch_uport[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) { +@@ -1523,12 +1507,9 @@ static __init int cxl_test_init(void) + goto err_dport; + pdev->dev.parent = &uport->dev; + +- rc = platform_device_add(pdev); +- if (rc) { +- platform_device_put(pdev); ++ rc = cxl_mock_platform_device_add(pdev, &cxl_switch_dport[i]); ++ if (rc) + goto err_dport; +- } +- cxl_switch_dport[i] = pdev; + } + + rc = cxl_single_topo_init(); +@@ -1546,9 +1527,9 @@ static __init int cxl_test_init(void) + mock_companion(&acpi0017_mock, &cxl_acpi->dev); + acpi0017_mock.dev.bus = &platform_bus_type; + +- rc = platform_device_add(cxl_acpi); ++ rc = cxl_mock_platform_device_add(cxl_acpi, NULL); + if (rc) +- goto err_root; ++ goto err_rch; + + rc = cxl_mem_init(); + if (rc) +-- +2.53.0 + diff --git a/queue-7.0/dpll-export-__dpll_device_change_ntf-for-use-under-d.patch b/queue-7.0/dpll-export-__dpll_device_change_ntf-for-use-under-d.patch new file mode 100644 index 0000000000..0acb948bd2 --- /dev/null +++ b/queue-7.0/dpll-export-__dpll_device_change_ntf-for-use-under-d.patch @@ -0,0 +1,70 @@ +From e1fc70f17d041e2f925e9ce9ac9e1151af5b103b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 09:45:23 +0200 +Subject: dpll: export __dpll_device_change_ntf() for use under dpll_lock + +From: Ivan Vecera + +[ Upstream commit 20040b2a3cb992f84d3db4c086b909eb9b906b31 ] + +Export __dpll_device_change_ntf() so that drivers can send device +change notifications from within device callbacks, which are already +called under dpll_lock. Using dpll_device_change_ntf() in that +context would deadlock. + +Add lockdep_assert_held() to catch misuse without the lock held. + +Signed-off-by: Ivan Vecera +Reviewed-by: Jiri Pirko +Link: https://patch.msgid.link/20260526074525.1451008-2-ivecera@redhat.com +Signed-off-by: Paolo Abeni +Stable-dep-of: d733f519f644 ("dpll: zl3073x: use __dpll_device_change_ntf() and remove change_work") +Signed-off-by: Sasha Levin +--- + drivers/dpll/dpll_netlink.c | 13 +++++++++++-- + include/linux/dpll.h | 1 + + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index 95ae786e98aab3..72aa5f4d5d3114 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -771,12 +771,21 @@ int dpll_device_delete_ntf(struct dpll_device *dpll) + return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll); + } + +-static int +-__dpll_device_change_ntf(struct dpll_device *dpll) ++/** ++ * __dpll_device_change_ntf - notify that the dpll device has been changed ++ * @dpll: registered dpll pointer ++ * ++ * Context: caller must hold dpll_lock. Suitable for use inside device ++ * callbacks which are already invoked under dpll_lock. ++ * Return: 0 if succeeds, error code otherwise. ++ */ ++int __dpll_device_change_ntf(struct dpll_device *dpll) + { ++ lockdep_assert_held(&dpll_lock); + dpll_device_notify(dpll, DPLL_DEVICE_CHANGED); + return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); + } ++EXPORT_SYMBOL_GPL(__dpll_device_change_ntf); + + /** + * dpll_device_change_ntf - notify that the dpll device has been changed +diff --git a/include/linux/dpll.h b/include/linux/dpll.h +index 8f97120ee7b37d..a77d5741dd3932 100644 +--- a/include/linux/dpll.h ++++ b/include/linux/dpll.h +@@ -274,6 +274,7 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, + int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin, + struct dpll_pin *ref_sync_pin); + ++int __dpll_device_change_ntf(struct dpll_device *dpll); + int dpll_device_change_ntf(struct dpll_device *dpll); + + int __dpll_pin_change_ntf(struct dpll_pin *pin); +-- +2.53.0 + diff --git a/queue-7.0/dpll-zl3073x-add-die-temperature-reporting-for-suppo.patch b/queue-7.0/dpll-zl3073x-add-die-temperature-reporting-for-suppo.patch new file mode 100644 index 0000000000..215e923bef --- /dev/null +++ b/queue-7.0/dpll-zl3073x-add-die-temperature-reporting-for-suppo.patch @@ -0,0 +1,183 @@ +From 85afbb582fa268e65be2e196f1179b169301526a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 11:53:00 +0100 +Subject: dpll: zl3073x: add die temperature reporting for supported chips + +From: Ivan Vecera + +[ Upstream commit 3a97e02b3e91e4d40095ad9bb6e466d8d7c1a1bc ] + +Some zl3073x chip variants (0x1Exx, 0x2Exx and 0x3FC4) provide a die +temperature status register with 0.1 C resolution. + +Add a ZL3073X_FLAG_DIE_TEMP chip flag to identify these variants and +implement zl3073x_dpll_temp_get() as the dpll_device_ops.temp_get +callback. The register value is converted from 0.1 C units to +millidegrees as expected by the DPLL subsystem. + +To support per-instance ops selection, copy the base dpll_device_ops +into struct zl3073x_dpll and conditionally set .temp_get during device +registration based on the chip flag. + +Signed-off-by: Ivan Vecera +Link: https://patch.msgid.link/20260227105300.710272-3-ivecera@redhat.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Stable-dep-of: d733f519f644 ("dpll: zl3073x: use __dpll_device_change_ntf() and remove change_work") +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/core.c | 22 +++++++++++----------- + drivers/dpll/zl3073x/core.h | 2 ++ + drivers/dpll/zl3073x/dpll.c | 28 +++++++++++++++++++++++++--- + drivers/dpll/zl3073x/dpll.h | 2 ++ + drivers/dpll/zl3073x/regs.h | 2 ++ + 5 files changed, 42 insertions(+), 14 deletions(-) + +diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c +index c8af3430104505..10e036ccf08f05 100644 +--- a/drivers/dpll/zl3073x/core.c ++++ b/drivers/dpll/zl3073x/core.c +@@ -30,18 +30,18 @@ static const struct zl3073x_chip_info zl3073x_chip_ids[] = { + ZL_CHIP_INFO(0x0E95, 3, ZL3073X_FLAG_REF_PHASE_COMP_32), + ZL_CHIP_INFO(0x0E96, 4, ZL3073X_FLAG_REF_PHASE_COMP_32), + ZL_CHIP_INFO(0x0E97, 5, ZL3073X_FLAG_REF_PHASE_COMP_32), +- ZL_CHIP_INFO(0x1E93, 1, 0), +- ZL_CHIP_INFO(0x1E94, 2, 0), +- ZL_CHIP_INFO(0x1E95, 3, 0), +- ZL_CHIP_INFO(0x1E96, 4, 0), +- ZL_CHIP_INFO(0x1E97, 5, 0), ++ ZL_CHIP_INFO(0x1E93, 1, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E94, 2, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E95, 3, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E96, 4, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E97, 5, ZL3073X_FLAG_DIE_TEMP), + ZL_CHIP_INFO(0x1F60, 2, ZL3073X_FLAG_REF_PHASE_COMP_32), +- ZL_CHIP_INFO(0x2E93, 1, 0), +- ZL_CHIP_INFO(0x2E94, 2, 0), +- ZL_CHIP_INFO(0x2E95, 3, 0), +- ZL_CHIP_INFO(0x2E96, 4, 0), +- ZL_CHIP_INFO(0x2E97, 5, 0), +- ZL_CHIP_INFO(0x3FC4, 2, 0), ++ ZL_CHIP_INFO(0x2E93, 1, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E94, 2, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E95, 3, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E96, 4, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E97, 5, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x3FC4, 2, ZL3073X_FLAG_DIE_TEMP), + }; + + #define ZL_RANGE_OFFSET 0x80 +diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h +index fde5c8371fbd28..b6f22ee1c0bd1b 100644 +--- a/drivers/dpll/zl3073x/core.h ++++ b/drivers/dpll/zl3073x/core.h +@@ -32,11 +32,13 @@ struct zl3073x_dpll; + + enum zl3073x_flags { + ZL3073X_FLAG_REF_PHASE_COMP_32_BIT, ++ ZL3073X_FLAG_DIE_TEMP_BIT, + ZL3073X_FLAGS_NBITS /* must be last */ + }; + + #define __ZL3073X_FLAG(name) BIT(ZL3073X_FLAG_ ## name ## _BIT) + #define ZL3073X_FLAG_REF_PHASE_COMP_32 __ZL3073X_FLAG(REF_PHASE_COMP_32) ++#define ZL3073X_FLAG_DIE_TEMP __ZL3073X_FLAG(DIE_TEMP) + + /** + * struct zl3073x_chip_info - chip variant identification +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index aaa14ea5e670fd..c201c974a7f9a4 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -1065,6 +1065,25 @@ zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, + return 0; + } + ++static int ++zl3073x_dpll_temp_get(const struct dpll_device *dpll, void *dpll_priv, ++ s32 *temp, struct netlink_ext_ack *extack) ++{ ++ struct zl3073x_dpll *zldpll = dpll_priv; ++ struct zl3073x_dev *zldev = zldpll->dev; ++ u16 val; ++ int rc; ++ ++ rc = zl3073x_read_u16(zldev, ZL_REG_DIE_TEMP_STATUS, &val); ++ if (rc) ++ return rc; ++ ++ /* Register value is in units of 0.1 C, convert to millidegrees */ ++ *temp = (s16)val * 100; ++ ++ return 0; ++} ++ + static int + zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_lock_status *status, +@@ -1671,6 +1690,10 @@ zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll) + zldpll->forced_ref = FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, + dpll_mode_refsel); + ++ zldpll->ops = zl3073x_dpll_device_ops; ++ if (zldev->info->flags & ZL3073X_FLAG_DIE_TEMP) ++ zldpll->ops.temp_get = zl3073x_dpll_temp_get; ++ + zldpll->dpll_dev = dpll_device_get(zldev->clock_id, zldpll->id, + THIS_MODULE, &zldpll->tracker); + if (IS_ERR(zldpll->dpll_dev)) { +@@ -1682,7 +1705,7 @@ zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll) + + rc = dpll_device_register(zldpll->dpll_dev, + zl3073x_prop_dpll_type_get(zldev, zldpll->id), +- &zl3073x_dpll_device_ops, zldpll); ++ &zldpll->ops, zldpll); + if (rc) { + dpll_device_put(zldpll->dpll_dev, &zldpll->tracker); + zldpll->dpll_dev = NULL; +@@ -1705,8 +1728,7 @@ zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll) + + cancel_work_sync(&zldpll->change_work); + +- dpll_device_unregister(zldpll->dpll_dev, &zl3073x_dpll_device_ops, +- zldpll); ++ dpll_device_unregister(zldpll->dpll_dev, &zldpll->ops, zldpll); + dpll_device_put(zldpll->dpll_dev, &zldpll->tracker); + zldpll->dpll_dev = NULL; + } +diff --git a/drivers/dpll/zl3073x/dpll.h b/drivers/dpll/zl3073x/dpll.h +index c65c798c37927f..278a24f357c9bd 100644 +--- a/drivers/dpll/zl3073x/dpll.h ++++ b/drivers/dpll/zl3073x/dpll.h +@@ -17,6 +17,7 @@ + * @forced_ref: selected reference in forced reference lock mode + * @check_count: periodic check counter + * @phase_monitor: is phase offset monitor enabled ++ * @ops: DPLL device operations for this instance + * @dpll_dev: pointer to registered DPLL device + * @tracker: tracking object for the acquired reference + * @lock_status: last saved DPLL lock status +@@ -31,6 +32,7 @@ struct zl3073x_dpll { + u8 forced_ref; + u8 check_count; + bool phase_monitor; ++ struct dpll_device_ops ops; + struct dpll_device *dpll_dev; + dpll_tracker tracker; + enum dpll_lock_status lock_status; +diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h +index 5573d7188406bb..19c598daa784ca 100644 +--- a/drivers/dpll/zl3073x/regs.h ++++ b/drivers/dpll/zl3073x/regs.h +@@ -78,6 +78,8 @@ + #define ZL_REG_RESET_STATUS ZL_REG(0, 0x18, 1) + #define ZL_REG_RESET_STATUS_RESET BIT(0) + ++#define ZL_REG_DIE_TEMP_STATUS ZL_REG(0, 0x44, 2) ++ + /************************* + * Register Page 2, Status + *************************/ +-- +2.53.0 + diff --git a/queue-7.0/dpll-zl3073x-detect-dpll-channel-count-from-chip-id-.patch b/queue-7.0/dpll-zl3073x-detect-dpll-channel-count-from-chip-id-.patch new file mode 100644 index 0000000000..73646f5c0c --- /dev/null +++ b/queue-7.0/dpll-zl3073x-detect-dpll-channel-count-from-chip-id-.patch @@ -0,0 +1,425 @@ +From 3dac0b76c78970a25972d9e63870f94dbfed9ba6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 11:52:59 +0100 +Subject: dpll: zl3073x: detect DPLL channel count from chip ID at runtime + +From: Ivan Vecera + +[ Upstream commit 4845f2fff730f0cdf8f7fe6401c8b871891cf1cb ] + +Replace the five per-variant zl3073x_chip_info structures and their +exported symbol definitions with a single consolidated chip ID lookup +table. The chip variant is now detected at runtime by reading the chip +ID register from hardware and looking it up in the table, rather than +being selected at compile time via the bus driver match data. + +Repurpose struct zl3073x_chip_info to hold a single chip ID, its +channel count, and a flags field. Introduce enum zl3073x_flags with +ZL3073X_FLAG_REF_PHASE_COMP_32 to replace the chip_id switch statement +in zl3073x_dev_is_ref_phase_comp_32bit(). Store a pointer to the +detected chip_info entry in struct zl3073x_dev for runtime access. + +This simplifies the bus drivers by removing per-variant .data and +.driver_data references from the I2C/SPI match tables, and makes +adding support for new chip variants a single-line table addition. + +Signed-off-by: Ivan Vecera +Link: https://patch.msgid.link/20260227105300.710272-2-ivecera@redhat.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Stable-dep-of: d733f519f644 ("dpll: zl3073x: use __dpll_device_change_ntf() and remove change_work") +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/core.c | 118 ++++++++++-------------------------- + drivers/dpll/zl3073x/core.h | 57 +++++++++-------- + drivers/dpll/zl3073x/i2c.c | 37 ++++------- + drivers/dpll/zl3073x/spi.c | 37 ++++------- + 4 files changed, 82 insertions(+), 167 deletions(-) + +diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c +index 37f3c33570eef2..c8af3430104505 100644 +--- a/drivers/dpll/zl3073x/core.c ++++ b/drivers/dpll/zl3073x/core.c +@@ -20,79 +20,30 @@ + #include "dpll.h" + #include "regs.h" + +-/* Chip IDs for zl30731 */ +-static const u16 zl30731_ids[] = { +- 0x0E93, +- 0x1E93, +- 0x2E93, ++#define ZL_CHIP_INFO(_id, _nchannels, _flags) \ ++ { .id = (_id), .num_channels = (_nchannels), .flags = (_flags) } ++ ++static const struct zl3073x_chip_info zl3073x_chip_ids[] = { ++ ZL_CHIP_INFO(0x0E30, 2, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E93, 1, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E94, 2, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E95, 3, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E96, 4, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E97, 5, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x1E93, 1, 0), ++ ZL_CHIP_INFO(0x1E94, 2, 0), ++ ZL_CHIP_INFO(0x1E95, 3, 0), ++ ZL_CHIP_INFO(0x1E96, 4, 0), ++ ZL_CHIP_INFO(0x1E97, 5, 0), ++ ZL_CHIP_INFO(0x1F60, 2, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x2E93, 1, 0), ++ ZL_CHIP_INFO(0x2E94, 2, 0), ++ ZL_CHIP_INFO(0x2E95, 3, 0), ++ ZL_CHIP_INFO(0x2E96, 4, 0), ++ ZL_CHIP_INFO(0x2E97, 5, 0), ++ ZL_CHIP_INFO(0x3FC4, 2, 0), + }; + +-const struct zl3073x_chip_info zl30731_chip_info = { +- .ids = zl30731_ids, +- .num_ids = ARRAY_SIZE(zl30731_ids), +- .num_channels = 1, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30731_chip_info, "ZL3073X"); +- +-/* Chip IDs for zl30732 */ +-static const u16 zl30732_ids[] = { +- 0x0E30, +- 0x0E94, +- 0x1E94, +- 0x1F60, +- 0x2E94, +- 0x3FC4, +-}; +- +-const struct zl3073x_chip_info zl30732_chip_info = { +- .ids = zl30732_ids, +- .num_ids = ARRAY_SIZE(zl30732_ids), +- .num_channels = 2, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30732_chip_info, "ZL3073X"); +- +-/* Chip IDs for zl30733 */ +-static const u16 zl30733_ids[] = { +- 0x0E95, +- 0x1E95, +- 0x2E95, +-}; +- +-const struct zl3073x_chip_info zl30733_chip_info = { +- .ids = zl30733_ids, +- .num_ids = ARRAY_SIZE(zl30733_ids), +- .num_channels = 3, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30733_chip_info, "ZL3073X"); +- +-/* Chip IDs for zl30734 */ +-static const u16 zl30734_ids[] = { +- 0x0E96, +- 0x1E96, +- 0x2E96, +-}; +- +-const struct zl3073x_chip_info zl30734_chip_info = { +- .ids = zl30734_ids, +- .num_ids = ARRAY_SIZE(zl30734_ids), +- .num_channels = 4, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30734_chip_info, "ZL3073X"); +- +-/* Chip IDs for zl30735 */ +-static const u16 zl30735_ids[] = { +- 0x0E97, +- 0x1E97, +- 0x2E97, +-}; +- +-const struct zl3073x_chip_info zl30735_chip_info = { +- .ids = zl30735_ids, +- .num_ids = ARRAY_SIZE(zl30735_ids), +- .num_channels = 5, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, "ZL3073X"); +- + #define ZL_RANGE_OFFSET 0x80 + #define ZL_PAGE_SIZE 0x80 + #define ZL_NUM_PAGES 256 +@@ -942,7 +893,7 @@ static void zl3073x_dev_dpll_fini(void *ptr) + } + + static int +-zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) ++zl3073x_devm_dpll_init(struct zl3073x_dev *zldev) + { + struct kthread_worker *kworker; + struct zl3073x_dpll *zldpll; +@@ -952,7 +903,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) + INIT_LIST_HEAD(&zldev->dplls); + + /* Allocate all DPLLs */ +- for (i = 0; i < num_dplls; i++) { ++ for (i = 0; i < zldev->info->num_channels; i++) { + zldpll = zl3073x_dpll_alloc(zldev, i); + if (IS_ERR(zldpll)) { + dev_err_probe(zldev->dev, PTR_ERR(zldpll), +@@ -992,14 +943,12 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) + /** + * zl3073x_dev_probe - initialize zl3073x device + * @zldev: pointer to zl3073x device +- * @chip_info: chip info based on compatible + * + * Common initialization of zl3073x device structure. + * + * Returns: 0 on success, <0 on error + */ +-int zl3073x_dev_probe(struct zl3073x_dev *zldev, +- const struct zl3073x_chip_info *chip_info) ++int zl3073x_dev_probe(struct zl3073x_dev *zldev) + { + u16 id, revision, fw_ver; + unsigned int i; +@@ -1011,18 +960,17 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev, + if (rc) + return rc; + +- /* Check it matches */ +- for (i = 0; i < chip_info->num_ids; i++) { +- if (id == chip_info->ids[i]) ++ /* Detect chip variant */ ++ for (i = 0; i < ARRAY_SIZE(zl3073x_chip_ids); i++) { ++ if (zl3073x_chip_ids[i].id == id) + break; + } + +- if (i == chip_info->num_ids) { ++ if (i == ARRAY_SIZE(zl3073x_chip_ids)) + return dev_err_probe(zldev->dev, -ENODEV, +- "Unknown or non-match chip ID: 0x%0x\n", +- id); +- } +- zldev->chip_id = id; ++ "Unknown chip ID: 0x%04x\n", id); ++ ++ zldev->info = &zl3073x_chip_ids[i]; + + /* Read revision, firmware version and custom config version */ + rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision); +@@ -1061,7 +1009,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev, + "Failed to initialize mutex\n"); + + /* Register DPLL channels */ +- rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels); ++ rc = zl3073x_devm_dpll_init(zldev); + if (rc) + return rc; + +diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h +index fd2af3c62a7d5c..fde5c8371fbd28 100644 +--- a/drivers/dpll/zl3073x/core.h ++++ b/drivers/dpll/zl3073x/core.h +@@ -30,12 +30,32 @@ struct zl3073x_dpll; + #define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \ + ZL3073X_NUM_OUTPUT_PINS) + ++enum zl3073x_flags { ++ ZL3073X_FLAG_REF_PHASE_COMP_32_BIT, ++ ZL3073X_FLAGS_NBITS /* must be last */ ++}; ++ ++#define __ZL3073X_FLAG(name) BIT(ZL3073X_FLAG_ ## name ## _BIT) ++#define ZL3073X_FLAG_REF_PHASE_COMP_32 __ZL3073X_FLAG(REF_PHASE_COMP_32) ++ ++/** ++ * struct zl3073x_chip_info - chip variant identification ++ * @id: chip ID ++ * @num_channels: number of DPLL channels supported by this variant ++ * @flags: chip variant flags ++ */ ++struct zl3073x_chip_info { ++ u16 id; ++ u8 num_channels; ++ unsigned long flags; ++}; ++ + /** + * struct zl3073x_dev - zl3073x device + * @dev: pointer to device + * @regmap: regmap to access device registers ++ * @info: detected chip info + * @multiop_lock: to serialize multiple register operations +- * @chip_id: chip ID read from hardware + * @ref: array of input references' invariants + * @out: array of outs' invariants + * @synth: array of synths' invariants +@@ -46,10 +66,10 @@ struct zl3073x_dpll; + * @phase_avg_factor: phase offset measurement averaging factor + */ + struct zl3073x_dev { +- struct device *dev; +- struct regmap *regmap; +- struct mutex multiop_lock; +- u16 chip_id; ++ struct device *dev; ++ struct regmap *regmap; ++ const struct zl3073x_chip_info *info; ++ struct mutex multiop_lock; + + /* Invariants */ + struct zl3073x_ref ref[ZL3073X_NUM_REFS]; +@@ -68,22 +88,10 @@ struct zl3073x_dev { + u8 phase_avg_factor; + }; + +-struct zl3073x_chip_info { +- const u16 *ids; +- size_t num_ids; +- int num_channels; +-}; +- +-extern const struct zl3073x_chip_info zl30731_chip_info; +-extern const struct zl3073x_chip_info zl30732_chip_info; +-extern const struct zl3073x_chip_info zl30733_chip_info; +-extern const struct zl3073x_chip_info zl30734_chip_info; +-extern const struct zl3073x_chip_info zl30735_chip_info; + extern const struct regmap_config zl3073x_regmap_config; + + struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev); +-int zl3073x_dev_probe(struct zl3073x_dev *zldev, +- const struct zl3073x_chip_info *chip_info); ++int zl3073x_dev_probe(struct zl3073x_dev *zldev); + + int zl3073x_dev_start(struct zl3073x_dev *zldev, bool full); + void zl3073x_dev_stop(struct zl3073x_dev *zldev); +@@ -158,18 +166,7 @@ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel); + static inline bool + zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev) + { +- switch (zldev->chip_id) { +- case 0x0E30: +- case 0x0E93: +- case 0x0E94: +- case 0x0E95: +- case 0x0E96: +- case 0x0E97: +- case 0x1F60: +- return true; +- default: +- return false; +- } ++ return zldev->info->flags & ZL3073X_FLAG_REF_PHASE_COMP_32; + } + + static inline bool +diff --git a/drivers/dpll/zl3073x/i2c.c b/drivers/dpll/zl3073x/i2c.c +index 7bbfdd4ed8671d..979df85826abcc 100644 +--- a/drivers/dpll/zl3073x/i2c.c ++++ b/drivers/dpll/zl3073x/i2c.c +@@ -22,40 +22,25 @@ static int zl3073x_i2c_probe(struct i2c_client *client) + return dev_err_probe(dev, PTR_ERR(zldev->regmap), + "Failed to initialize regmap\n"); + +- return zl3073x_dev_probe(zldev, i2c_get_match_data(client)); ++ return zl3073x_dev_probe(zldev); + } + + static const struct i2c_device_id zl3073x_i2c_id[] = { +- { +- .name = "zl30731", +- .driver_data = (kernel_ulong_t)&zl30731_chip_info, +- }, +- { +- .name = "zl30732", +- .driver_data = (kernel_ulong_t)&zl30732_chip_info, +- }, +- { +- .name = "zl30733", +- .driver_data = (kernel_ulong_t)&zl30733_chip_info, +- }, +- { +- .name = "zl30734", +- .driver_data = (kernel_ulong_t)&zl30734_chip_info, +- }, +- { +- .name = "zl30735", +- .driver_data = (kernel_ulong_t)&zl30735_chip_info, +- }, ++ { "zl30731" }, ++ { "zl30732" }, ++ { "zl30733" }, ++ { "zl30734" }, ++ { "zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(i2c, zl3073x_i2c_id); + + static const struct of_device_id zl3073x_i2c_of_match[] = { +- { .compatible = "microchip,zl30731", .data = &zl30731_chip_info }, +- { .compatible = "microchip,zl30732", .data = &zl30732_chip_info }, +- { .compatible = "microchip,zl30733", .data = &zl30733_chip_info }, +- { .compatible = "microchip,zl30734", .data = &zl30734_chip_info }, +- { .compatible = "microchip,zl30735", .data = &zl30735_chip_info }, ++ { .compatible = "microchip,zl30731" }, ++ { .compatible = "microchip,zl30732" }, ++ { .compatible = "microchip,zl30733" }, ++ { .compatible = "microchip,zl30734" }, ++ { .compatible = "microchip,zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match); +diff --git a/drivers/dpll/zl3073x/spi.c b/drivers/dpll/zl3073x/spi.c +index af901b4d6dda06..f024f42b78d05f 100644 +--- a/drivers/dpll/zl3073x/spi.c ++++ b/drivers/dpll/zl3073x/spi.c +@@ -22,40 +22,25 @@ static int zl3073x_spi_probe(struct spi_device *spi) + return dev_err_probe(dev, PTR_ERR(zldev->regmap), + "Failed to initialize regmap\n"); + +- return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi)); ++ return zl3073x_dev_probe(zldev); + } + + static const struct spi_device_id zl3073x_spi_id[] = { +- { +- .name = "zl30731", +- .driver_data = (kernel_ulong_t)&zl30731_chip_info +- }, +- { +- .name = "zl30732", +- .driver_data = (kernel_ulong_t)&zl30732_chip_info, +- }, +- { +- .name = "zl30733", +- .driver_data = (kernel_ulong_t)&zl30733_chip_info, +- }, +- { +- .name = "zl30734", +- .driver_data = (kernel_ulong_t)&zl30734_chip_info, +- }, +- { +- .name = "zl30735", +- .driver_data = (kernel_ulong_t)&zl30735_chip_info, +- }, ++ { "zl30731" }, ++ { "zl30732" }, ++ { "zl30733" }, ++ { "zl30734" }, ++ { "zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(spi, zl3073x_spi_id); + + static const struct of_device_id zl3073x_spi_of_match[] = { +- { .compatible = "microchip,zl30731", .data = &zl30731_chip_info }, +- { .compatible = "microchip,zl30732", .data = &zl30732_chip_info }, +- { .compatible = "microchip,zl30733", .data = &zl30733_chip_info }, +- { .compatible = "microchip,zl30734", .data = &zl30734_chip_info }, +- { .compatible = "microchip,zl30735", .data = &zl30735_chip_info }, ++ { .compatible = "microchip,zl30731" }, ++ { .compatible = "microchip,zl30732" }, ++ { .compatible = "microchip,zl30733" }, ++ { .compatible = "microchip,zl30734" }, ++ { .compatible = "microchip,zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match); +-- +2.53.0 + diff --git a/queue-7.0/dpll-zl3073x-use-__dpll_device_change_ntf-and-remove.patch b/queue-7.0/dpll-zl3073x-use-__dpll_device_change_ntf-and-remove.patch new file mode 100644 index 0000000000..109001ac71 --- /dev/null +++ b/queue-7.0/dpll-zl3073x-use-__dpll_device_change_ntf-and-remove.patch @@ -0,0 +1,114 @@ +From 9087e846d722a4fba9f263ff9430a9f19be5c7cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 09:45:24 +0200 +Subject: dpll: zl3073x: use __dpll_device_change_ntf() and remove change_work + +From: Ivan Vecera + +[ Upstream commit d733f519f6443540f8359461a34e3b0042099bbe ] + +The change_work was introduced to send device change notifications +from DPLL device callbacks without deadlocking on dpll_lock, since +the callbacks are already invoked under that lock. Now that +__dpll_device_change_ntf() is exported for callers that already +hold dpll_lock, use it directly and remove the change_work +infrastructure entirely. + +This eliminates a race condition where change_work could be +re-scheduled after cancel_work_sync() during device teardown, +potentially causing the handler to dereference a freed or NULL +dpll_dev pointer. + +Fixes: 9363b4837659 ("dpll: zl3073x: Allow to configure phase offset averaging factor") +Signed-off-by: Ivan Vecera +Link: https://patch.msgid.link/20260526074525.1451008-3-ivecera@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/dpll.c | 26 +++++++++----------------- + drivers/dpll/zl3073x/dpll.h | 2 -- + 2 files changed, 9 insertions(+), 19 deletions(-) + +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index c201c974a7f9a4..70c91948c7da8d 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -1193,15 +1193,6 @@ zl3073x_dpll_phase_offset_avg_factor_get(const struct dpll_device *dpll, + return 0; + } + +-static void +-zl3073x_dpll_change_work(struct work_struct *work) +-{ +- struct zl3073x_dpll *zldpll; +- +- zldpll = container_of(work, struct zl3073x_dpll, change_work); +- dpll_device_change_ntf(zldpll->dpll_dev); +-} +- + static int + zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll, + void *dpll_priv, u32 factor, +@@ -1227,8 +1218,10 @@ zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll, + * we have to send a notification for other DPLL devices. + */ + list_for_each_entry(item, &zldpll->dev->dplls, list) { +- if (item != zldpll) +- schedule_work(&item->change_work); ++ struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev); ++ ++ if (item != zldpll && dpll_dev) ++ __dpll_device_change_ntf(dpll_dev); + } + + return 0; +@@ -1724,13 +1717,13 @@ zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll) + static void + zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll) + { +- WARN(!zldpll->dpll_dev, "DPLL device is not registered\n"); ++ struct dpll_device *dpll_dev = READ_ONCE(zldpll->dpll_dev); + +- cancel_work_sync(&zldpll->change_work); ++ WARN(!dpll_dev, "DPLL device is not registered\n"); + +- dpll_device_unregister(zldpll->dpll_dev, &zldpll->ops, zldpll); +- dpll_device_put(zldpll->dpll_dev, &zldpll->tracker); +- zldpll->dpll_dev = NULL; ++ WRITE_ONCE(zldpll->dpll_dev, NULL); ++ dpll_device_unregister(dpll_dev, &zldpll->ops, zldpll); ++ dpll_device_put(dpll_dev, &zldpll->tracker); + } + + /** +@@ -1976,7 +1969,6 @@ zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch) + zldpll->dev = zldev; + zldpll->id = ch; + INIT_LIST_HEAD(&zldpll->pins); +- INIT_WORK(&zldpll->change_work, zl3073x_dpll_change_work); + + return zldpll; + } +diff --git a/drivers/dpll/zl3073x/dpll.h b/drivers/dpll/zl3073x/dpll.h +index 278a24f357c9bd..241253212f7d57 100644 +--- a/drivers/dpll/zl3073x/dpll.h ++++ b/drivers/dpll/zl3073x/dpll.h +@@ -22,7 +22,6 @@ + * @tracker: tracking object for the acquired reference + * @lock_status: last saved DPLL lock status + * @pins: list of pins +- * @change_work: device change notification work + */ + struct zl3073x_dpll { + struct list_head list; +@@ -37,7 +36,6 @@ struct zl3073x_dpll { + dpll_tracker tracker; + enum dpll_lock_status lock_status; + struct list_head pins; +- struct work_struct change_work; + }; + + struct zl3073x_dpll *zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch); +-- +2.53.0 + diff --git a/queue-7.0/drm-i915-aux-use-polling-when-irqs-are-unavailable.patch b/queue-7.0/drm-i915-aux-use-polling-when-irqs-are-unavailable.patch new file mode 100644 index 0000000000..db40a2b833 --- /dev/null +++ b/queue-7.0/drm-i915-aux-use-polling-when-irqs-are-unavailable.patch @@ -0,0 +1,85 @@ +From 1306c5b24b5b65cb690ad7ce8f3be661f2c1b5aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:37:44 +0200 +Subject: drm/i915/aux: use polling when irqs are unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michał Grzelak + +[ Upstream commit 202e77cf2e839e1adc804433322dc5c9ee511c9f ] + +PTL with physically disconnected display was observed to have 40s longer +execution time when testing xe_fault_injection@xe_guc_mmio_send_recv. +The issue has not been seen when reverting commit 40a9f77a28fa ("Revert +"drm/i915/dp: change aux_ctl reg read to polling read""). + +Apparently the configuration suffers from not having AUX enabled when +using interrupts. One probable cause can be xe enabling interrupts too +late: interrupts need memory allocations which currently can't be done +before the display FB takeover is done. + +As for now, use polling for AUX in case interrupts are unavailable. + +Fixes: 40a9f77a28fa ("Revert "drm/i915/dp: change aux_ctl reg read to polling read"") +Suggested-by: Ville Syrjälä +Signed-off-by: Michał Grzelak +Signed-off-by: Ville Syrjälä +Link: https://patch.msgid.link/20260416163744.288107-1-michal.grzelak@intel.com +(cherry picked from commit 05e0550b65cd1604bd515fbc65f522bce4c10a87) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_dp_aux.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c +index b20ec3e589fadc..9c9b6410366d5c 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c +@@ -12,6 +12,7 @@ + #include "intel_dp.h" + #include "intel_dp_aux.h" + #include "intel_dp_aux_regs.h" ++#include "intel_parent.h" + #include "intel_pps.h" + #include "intel_quirks.h" + #include "intel_tc.h" +@@ -60,18 +61,29 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp) + struct intel_display *display = to_intel_display(intel_dp); + i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp); + const unsigned int timeout_ms = 10; ++ bool done = true; + u32 status; +- bool done; ++ int ret; + ++ if (intel_parent_irq_enabled(display)) { + #define C (((status = intel_de_read_notrace(display, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) +- done = wait_event_timeout(display->gmbus.wait_queue, C, +- msecs_to_jiffies_timeout(timeout_ms)); ++ done = wait_event_timeout(display->gmbus.wait_queue, C, ++ msecs_to_jiffies_timeout(timeout_ms)); ++ ++#undef C ++ } else { ++ ret = intel_de_wait_ms(display, ch_ctl, ++ DP_AUX_CH_CTL_SEND_BUSY, 0, ++ timeout_ms, &status); ++ ++ if (ret == -ETIMEDOUT) ++ done = false; ++ } + + if (!done) + drm_err(display->drm, + "%s: did not complete or timeout within %ums (status 0x%08x)\n", + intel_dp->aux.name, timeout_ms, status); +-#undef C + + return status; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-restore-idledly-regiter-on-engine-reset.patch b/queue-7.0/drm-xe-restore-idledly-regiter-on-engine-reset.patch new file mode 100644 index 0000000000..df3f11c7ea --- /dev/null +++ b/queue-7.0/drm-xe-restore-idledly-regiter-on-engine-reset.patch @@ -0,0 +1,43 @@ +From a1a6c6d3e5d15f7e92b8c260bcf13e3cfff779fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 22:05:32 +0530 +Subject: drm/xe: Restore IDLEDLY regiter on engine reset + +From: Balasubramani Vivekanandan + +[ Upstream commit f657a6a3ba4c20bc01f5be3752d53498ee1bfe35 ] + +Wa_16023105232 programs the register IDLEDLY. The register is reset +whenever the engine is reset. Therefore it should be added to the GuC +save-restore register list for it to be restored after reset. + +Fixes: 7c53ff050ba8 ("drm/xe: Apply Wa_16023105232") +Reviewed-by: Matt Roper +Link: https://patch.msgid.link/20260522163531.1365540-2-balasubramani.vivekanandan@intel.com +Signed-off-by: Balasubramani Vivekanandan +(cherry picked from commit df1cfe24743a93b71eab27687e148ab8ae9b69e3) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_guc_ads.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c +index f4cbc030f4c81b..904225cbff0d8a 100644 +--- a/drivers/gpu/drm/xe/xe_guc_ads.c ++++ b/drivers/gpu/drm/xe/xe_guc_ads.c +@@ -770,6 +770,11 @@ static unsigned int guc_mmio_regset_write(struct xe_guc_ads *ads, + } + } + ++ if (XE_GT_WA(hwe->gt, 16023105232)) ++ guc_mmio_regset_write_one(ads, regset_map, ++ RING_IDLEDLY(hwe->mmio_base), ++ count++); ++ + return count; + } + +-- +2.53.0 + diff --git a/queue-7.0/esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch b/queue-7.0/esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch new file mode 100644 index 0000000000..cbb4be9280 --- /dev/null +++ b/queue-7.0/esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch @@ -0,0 +1,152 @@ +From e3d5ae76091ea58f31ca35eee643a7f009d535da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:27:17 +0200 +Subject: esp: fix page frag reference leak on skb_to_sgvec failure + +From: e521588 + +[ Upstream commit 2982e599fff6faa21c8df147d96fc7af6c1a2f24 ] + +In esp_output_tail(), when esp->inplace is false, the old skb page frags +are replaced with a new page from the xfrm page_frag cache. The source +scatterlist (sg) is built from the old frags before the replacement, and +esp_ssg_unref() is responsible for releasing the old page references +after the crypto operation completes. + +However, if the second skb_to_sgvec() call (which builds the destination +scatterlist from the new page) fails, the code jumps to error_free which +only calls kfree(tmp). The old page frag references captured in the +source scatterlist are never released: + + 1. sg[] is built from old frags via skb_to_sgvec() (no extra get_page) + 2. nr_frags is set to 1 and frag[0] is replaced with the new page + 3. Second skb_to_sgvec() fails -> goto error_free + 4. kfree(tmp) frees the sg[] memory but old frags are not unref'd + 5. kfree_skb() only releases frag[0] (the new page), not the old ones + +Fix this by adding a bool parameter to esp_ssg_unref() that, when true, +unconditionally unrefs the source scatterlist frags without checking +req->src and req->dst, since those fields are not yet initialized by +aead_request_set_crypt() at the point of the error. Existing callers +pass false to preserve the original behavior. + +The same issue exists in both esp4 and esp6 as the code is identical. + +Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") +Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") + +Signed-off-by: Alessandro Schino <7991aleschino@gmail.com> +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/ipv4/esp4.c | 12 +++++++----- + net/ipv6/esp6.c | 12 +++++++----- + 2 files changed, 14 insertions(+), 10 deletions(-) + +diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c +index 6a5febbdbee493..8314d7bddcb715 100644 +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -96,7 +96,7 @@ static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead, + __alignof__(struct scatterlist)); + } + +-static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) ++static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb, bool already_unref) + { + struct crypto_aead *aead = x->data; + int extralen = 0; +@@ -113,7 +113,7 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + /* Unref skb_frag_pages in the src scatterlist if necessary. + * Skip the first sg which comes from skb->data. + */ +- if (req->src != req->dst) ++ if (already_unref || req->src != req->dst) + for (sg = sg_next(req->src); sg; sg = sg_next(sg)) + skb_page_unref(page_to_netmem(sg_page(sg)), + skb->pp_recycle); +@@ -220,7 +220,7 @@ static void esp_output_done(void *data, int err) + } + + tmp = ESP_SKB_CB(skb)->tmp; +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + kfree(tmp); + + if (xo && (xo->flags & XFRM_DEV_RESUME)) { +@@ -569,8 +569,10 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * + err = skb_to_sgvec(skb, dsg, + (unsigned char *)esph - skb->data, + assoclen + ivlen + esp->clen + alen); +- if (unlikely(err < 0)) ++ if (unlikely(err < 0)) { ++ esp_ssg_unref(x, tmp, skb, true); + goto error_free; ++ } + } + + if ((x->props.flags & XFRM_STATE_ESN)) +@@ -602,7 +604,7 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * + } + + if (sg != dsg) +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + + if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) + err = esp_output_tail_tcp(x, skb); +diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c +index 9c06c5a1419dc4..9d0c4957ac6276 100644 +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -113,7 +113,7 @@ static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead, + __alignof__(struct scatterlist)); + } + +-static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) ++static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb, bool already_unref) + { + struct crypto_aead *aead = x->data; + int extralen = 0; +@@ -130,7 +130,7 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + /* Unref skb_frag_pages in the src scatterlist if necessary. + * Skip the first sg which comes from skb->data. + */ +- if (req->src != req->dst) ++ if (already_unref || req->src != req->dst) + for (sg = sg_next(req->src); sg; sg = sg_next(sg)) + skb_page_unref(page_to_netmem(sg_page(sg)), + skb->pp_recycle); +@@ -254,7 +254,7 @@ static void esp_output_done(void *data, int err) + } + + tmp = ESP_SKB_CB(skb)->tmp; +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + kfree(tmp); + + esp_output_encap_csum(skb); +@@ -600,8 +600,10 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info + err = skb_to_sgvec(skb, dsg, + (unsigned char *)esph - skb->data, + assoclen + ivlen + esp->clen + alen); +- if (unlikely(err < 0)) ++ if (unlikely(err < 0)) { ++ esp_ssg_unref(x, tmp, skb, true); + goto error_free; ++ } + } + + if ((x->props.flags & XFRM_STATE_ESN)) +@@ -634,7 +636,7 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info + } + + if (sg != dsg) +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + + if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) + err = esp_output_tail_tcp(x, skb); +-- +2.53.0 + diff --git a/queue-7.0/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch b/queue-7.0/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch new file mode 100644 index 0000000000..b584473250 --- /dev/null +++ b/queue-7.0/ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch @@ -0,0 +1,52 @@ +From 2dca642becb9dc2f2f618672bf5b8224075c5055 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:10 -0700 +Subject: ethtool: cmis: fix u16-to-u8 truncation of msleep_pre_rpl + +From: Jakub Kicinski + +[ Upstream commit 3e8c3d464c36bb342fe377b026577c7ec27fdbb4 ] + +ethtool_cmis_cdb_compose_args() accepts msleep_pre_rpl as u16 but stores +it into the u8 field ethtool_cmis_cdb_cmd_args::msleep_pre_rpl, silently +truncating values >= 256. Seven of the nine call sites pass 1000 ms +(it's the third argument from the end). + +Fixes: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-8-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h +index 4a9a946cabf05d..778783a0f23c0b 100644 +--- a/net/ethtool/cmis.h ++++ b/net/ethtool/cmis.h +@@ -63,9 +63,9 @@ struct ethtool_cmis_cdb_request { + * struct ethtool_cmis_cdb_cmd_args - CDB commands execution arguments + * @req: CDB command fields as described in the CMIS standard. + * @max_duration: Maximum duration time for command completion in msec. ++ * @msleep_pre_rpl: Waiting time before checking reply in msec. + * @read_write_len_ext: Allowable additional number of byte octets to the LPL + * in a READ or a WRITE commands. +- * @msleep_pre_rpl: Waiting time before checking reply in msec. + * @rpl_exp_len: Expected reply length in bytes. + * @flags: Validation flags for CDB commands. + * @err_msg: Error message to be sent to user space. +@@ -73,8 +73,8 @@ struct ethtool_cmis_cdb_request { + struct ethtool_cmis_cdb_cmd_args { + struct ethtool_cmis_cdb_request req; + u16 max_duration; ++ u16 msleep_pre_rpl; + u8 read_write_len_ext; +- u8 msleep_pre_rpl; + u8 rpl_exp_len; + u8 flags; + char *err_msg; +-- +2.53.0 + diff --git a/queue-7.0/ethtool-cmis-require-exact-cdb-reply-length.patch b/queue-7.0/ethtool-cmis-require-exact-cdb-reply-length.patch new file mode 100644 index 0000000000..4f8fb6a7ef --- /dev/null +++ b/queue-7.0/ethtool-cmis-require-exact-cdb-reply-length.patch @@ -0,0 +1,70 @@ +From e87c6d88d165888efbf2a4d6902294a2b5646f7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:09 -0700 +Subject: ethtool: cmis: require exact CDB reply length + +From: Jakub Kicinski + +[ Upstream commit 6c3f999a9d1338c6c89a9ff4549eafe72bc2e7b1 ] + +Malicious SFP module could respond with rpl_len longer than +what cmis_cdb_process_reply() expected, leading to OOB writes. +Malicious HW is a bit theoretical but some modules may just +be buggy and/or the reads may occasionally get corrupted, +so let's protect the kernel. + +The existing check protects from short replies. We need to +protect from long ones, too. All callers that pass a non-zero +rpl_exp_len cast the reply payload to a fixed-layout struct +and read fields at fixed offsets, with no version negotiation +or short-reply handling: + + - cmis_cdb_validate_password() + - cmis_cdb_module_features_get() + - cmis_fw_update_fw_mng_features_get() + +so let's assume that responses longer than expected do not +have to be handled gracefully here. Add a warning message +to make the debug easier in case my understanding is wrong... + +Note that page_data->length (argument of kmalloc) comes from +last arg to ethtool_cmis_page_init() which is rpl_exp_len. + +Note2 that AIs also like to point out overflows in args->req.payload +itself (which is a fixed-size 120 B buffer, on the stack), +but callers should be reading structs defined by the standard, +so protecting from requests for more data than max seem like +defensive programming. + +Fixes: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands") +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-7-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_cdb.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c +index 3670ca42dd403e..f3a53a98446099 100644 +--- a/net/ethtool/cmis_cdb.c ++++ b/net/ethtool/cmis_cdb.c +@@ -513,8 +513,13 @@ static int cmis_cdb_process_reply(struct net_device *dev, + } + + rpl = (struct ethtool_cmis_cdb_rpl *)page_data->data; +- if ((args->rpl_exp_len > rpl->hdr.rpl_len + rpl_hdr_len) || +- !rpl->hdr.rpl_chk_code) { ++ if (rpl->hdr.rpl_len != args->rpl_exp_len) { ++ netdev_warn(dev, "CDB reply length mismatch, expected %u got %u\n", ++ args->rpl_exp_len, rpl->hdr.rpl_len); ++ err = -EIO; ++ goto out; ++ } ++ if (!rpl->hdr.rpl_chk_code) { + err = -EIO; + goto out; + } +-- +2.53.0 + diff --git a/queue-7.0/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch b/queue-7.0/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch new file mode 100644 index 0000000000..3330382ad9 --- /dev/null +++ b/queue-7.0/ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch @@ -0,0 +1,48 @@ +From ce13c0943b6b3e93ab040edd59c762a758768d88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:12 -0700 +Subject: ethtool: cmis: validate fw->size against start_cmd_payload_size + +From: Jakub Kicinski + +[ Upstream commit d5551f4c1800dc714cec86647bdd651ae0de923e ] + +cmis_fw_update_start_download() copies start_cmd_payload_size bytes +from the firmware blob into the CDB LPL vendor_data[] payload without +validating that the FW has enough data. + +Since the start_cmd_payload_size can only be ~120B an image too short +is most likely corrupted, so reject it. + +Fixes: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-10-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_fw_update.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index 16190c97e1f78c..291d04d2776a5c 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -130,6 +130,14 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, + u8 lpl_len; + int err; + ++ if (fw_update->fw->size < vendor_data_size) { ++ ethnl_module_fw_flash_ntf_err(fw_update->dev, ++ &fw_update->ntf_params, ++ "Firmware image too small for module's start payload", ++ NULL); ++ return -EINVAL; ++ } ++ + pl.image_size = cpu_to_be32(fw_update->fw->size); + memcpy(pl.vendor_data, fw_update->fw->data, vendor_data_size); + +-- +2.53.0 + diff --git a/queue-7.0/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch b/queue-7.0/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch new file mode 100644 index 0000000000..51741e2f28 --- /dev/null +++ b/queue-7.0/ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch @@ -0,0 +1,96 @@ +From a627e6e43c8d38d63fb877ea6d251fb1e058b668 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:11 -0700 +Subject: ethtool: cmis: validate start_cmd_payload_size from module + +From: Jakub Kicinski + +[ Upstream commit 12c2496a71f82f63617971ca9b730dffa05cf58b ] + +The CMIS firmware update code reads start_cmd_payload_size from +the module's FW Management Features CDB reply and uses it directly +as the byte count for memcpy. The destination buffer is 112 bytes +(ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - 8). So a malicious +module (or corrupted response) can cause a OOB write later on in +cmis_fw_update_start_download(). + +Let's error out. If modules that expect longer LPL writes actually +exist we should revisit. + +struct cmis_cdb_start_fw_download_pl's definition has to move, +no change there. + +Fixes: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-9-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/cmis_fw_update.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c +index df5f344209c47b..16190c97e1f78c 100644 +--- a/net/ethtool/cmis_fw_update.c ++++ b/net/ethtool/cmis_fw_update.c +@@ -44,6 +44,20 @@ enum cmis_cdb_fw_write_mechanism { + CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11, + }; + ++/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard ++ * revision 5.2. ++ * struct cmis_cdb_start_fw_download_pl is a structured layout of the ++ * flat array, ethtool_cmis_cdb_request::payload. ++ */ ++struct cmis_cdb_start_fw_download_pl { ++ __struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */, ++ __be32 image_size; ++ __be32 resv1; ++ ); ++ u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - ++ sizeof(struct cmis_cdb_start_fw_download_pl_h)]; ++}; ++ + static int + cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + struct net_device *dev, +@@ -86,6 +100,14 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + */ + cdb->read_write_len_ext = rpl->read_write_len_ext; + fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size; ++ if (fw_mng->start_cmd_payload_size > ++ sizeof_field(struct cmis_cdb_start_fw_download_pl, vendor_data)) { ++ ethnl_module_fw_flash_ntf_err(dev, ntf_params, ++ "Start cmd payload size exceeds max LPL payload", ++ NULL); ++ return -EINVAL; ++ } ++ + fw_mng->write_mechanism = + rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ? + CMIS_CDB_FW_WRITE_MECHANISM_LPL : +@@ -97,20 +119,6 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, + return 0; + } + +-/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard +- * revision 5.2. +- * struct cmis_cdb_start_fw_download_pl is a structured layout of the +- * flat array, ethtool_cmis_cdb_request::payload. +- */ +-struct cmis_cdb_start_fw_download_pl { +- __struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */, +- __be32 image_size; +- __be32 resv1; +- ); +- u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - +- sizeof(struct cmis_cdb_start_fw_download_pl_h)]; +-}; +- + static int + cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, + struct ethtool_cmis_fw_update_params *fw_update, +-- +2.53.0 + diff --git a/queue-7.0/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch b/queue-7.0/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch new file mode 100644 index 0000000000..21c8cf6854 --- /dev/null +++ b/queue-7.0/ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch @@ -0,0 +1,45 @@ +From bd28fbf9a69ba891490fd79cce95a1d2a0987637 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:24 -0700 +Subject: ethtool: coalesce: cap profile updates at NET_DIM_PARAMS_NUM_PROFILES + +From: Jakub Kicinski + +[ Upstream commit 7281b096b072f6c6e30420e3467d738f2e4c4b57 ] + +ethnl_update_profile() walks the ETHTOOL_A_PROFILE_IRQ_MODERATION +nest list with an index 'i' and writes new_profile[i++] without +bounding i. The destination is kmemdup()'d at NET_DIM_PARAMS_NUM_PROFILES +entries (5), but the Netlink nest count is entirely user-controlled. +Netlink policies do not have support for constraining the number +of nested entries (or number of multi-attr entries). + +Fixes: f750dfe825b9 ("ethtool: provide customized dim profile management") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/coalesce.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ethtool/coalesce.c b/net/ethtool/coalesce.c +index 3e18ca1ccc5ef6..cace02d964cb21 100644 +--- a/net/ethtool/coalesce.c ++++ b/net/ethtool/coalesce.c +@@ -463,6 +463,12 @@ static int ethnl_update_profile(struct net_device *dev, + + nla_for_each_nested_type(nest, ETHTOOL_A_PROFILE_IRQ_MODERATION, + nests, rem) { ++ if (i >= NET_DIM_PARAMS_NUM_PROFILES) { ++ NL_SET_BAD_ATTR(extack, nest); ++ ret = -E2BIG; ++ goto err_out; ++ } ++ + ret = nla_parse_nested(tb, len_irq_moder - 1, nest, + coalesce_irq_moderation_policy, + extack); +-- +2.53.0 + diff --git a/queue-7.0/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch b/queue-7.0/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch new file mode 100644 index 0000000000..896cc7a3cb --- /dev/null +++ b/queue-7.0/ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch @@ -0,0 +1,48 @@ +From ee819def2d239de46f6048a568fe4038f25855b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:32 -0700 +Subject: ethtool: eeprom: add missing ethnl_ops_begin() / _complete() during + fallback + +From: Jakub Kicinski + +[ Upstream commit 2376586f85f972fefe701f095bb37dcfe7405d21 ] + +All ethtool driver op calls should be sandwiched between +ethnl_ops_begin() / ethnl_ops_complete(). In Netlink eeprom code, +if the paged access failed we fall back to old API, but we +first call _complete() and the fallback never does its own +ethnl_ops_begin(). Move the fallback into the _begin() / _complete() +section. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-10-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 3b8209e930fd3a..03cb418a15823b 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -140,12 +140,11 @@ static int eeprom_prepare_data(const struct ethnl_req_info *req_base, + return 0; + + err_ops: ++ if (ret == -EOPNOTSUPP) ++ ret = eeprom_fallback(request, reply); + ethnl_ops_complete(dev); + err_free: + kfree(page_data.data); +- +- if (ret == -EOPNOTSUPP) +- return eeprom_fallback(request, reply); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch b/queue-7.0/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch new file mode 100644 index 0000000000..ebbada34d5 --- /dev/null +++ b/queue-7.0/ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch @@ -0,0 +1,62 @@ +From 037295e26c47f64f130ff17a0f629a7bd1724b2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:33 -0700 +Subject: ethtool: eeprom: add more safeties to EEPROM Netlink fallback + +From: Jakub Kicinski + +[ Upstream commit 67cfdd9210b99f260b3e0afeb9525e0acc7be31e ] + +The Netlink fallback path for reading module EEPROM +(fallback_set_params()) validates that offset < eeprom_len, +but does not check that offset + length stays within eeprom_len. +The ioctl equivalent (ethtool_get_any_eeprom() in ioctl.c) has +always enforced both bounds: + + if (eeprom.offset + eeprom.len > total_len) + return -EINVAL; + +This could lead to surprises in both drivers and device FW. +Add the missing offset + length validation to fallback_set_params(), +mirroring the ioctl. + +Similarly - ethtool core in general, and ethtool_get_any_eeprom() +in particular tries to zero-init all buffers passed to the drivers +to avoid any extra work of zeroing things out. eeprom_fallback() +uses a plain kmalloc(), change it to zalloc. + +Fixes: 96d971e307cc ("ethtool: Add fallback to get_module_eeprom from netlink command") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-11-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/eeprom.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c +index 03cb418a15823b..80af38a6c76acf 100644 +--- a/net/ethtool/eeprom.c ++++ b/net/ethtool/eeprom.c +@@ -43,6 +43,9 @@ static int fallback_set_params(struct eeprom_req_info *request, + if (offset >= modinfo->eeprom_len) + return -EINVAL; + ++ if (length > modinfo->eeprom_len - offset) ++ return -EINVAL; ++ + eeprom->cmd = ETHTOOL_GMODULEEEPROM; + eeprom->len = length; + eeprom->offset = offset; +@@ -68,7 +71,7 @@ static int eeprom_fallback(struct eeprom_req_info *request, + if (err < 0) + return err; + +- data = kmalloc(eeprom.len, GFP_KERNEL); ++ data = kzalloc(eeprom.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + err = ethtool_get_module_eeprom_call(dev, &eeprom, data); +-- +2.53.0 + diff --git a/queue-7.0/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch b/queue-7.0/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch new file mode 100644 index 0000000000..0546f2b7f1 --- /dev/null +++ b/queue-7.0/ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch @@ -0,0 +1,43 @@ +From 38b98152586b77499f2df4274075e6648caa4c24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:26 -0700 +Subject: ethtool: linkstate: fix unbalanced ethnl_ops_complete() on PHY lookup + error + +From: Jakub Kicinski + +[ Upstream commit 596c51ed9e125b12c4d85b4530dfd4c7847634b7 ] + +linkstate_prepare_data() calls ethnl_req_get_phydev() before +ethnl_ops_begin(), but routes its error path through "goto out" +which calls ethnl_ops_complete(). + +Fixes: fe55b1d401c6 ("ethtool: linkstate: migrate linkstate functions to support multi-PHY setups") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-4-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/linkstate.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/linkstate.c b/net/ethtool/linkstate.c +index 05a5f72c99fab1..3dc52a39d34525 100644 +--- a/net/ethtool/linkstate.c ++++ b/net/ethtool/linkstate.c +@@ -105,10 +105,8 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base, + + phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER, + info->extack); +- if (IS_ERR(phydev)) { +- ret = PTR_ERR(phydev); +- goto out; +- } ++ if (IS_ERR(phydev)) ++ return PTR_ERR(phydev); + + ret = ethnl_ops_begin(dev); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-7.0/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch b/queue-7.0/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch new file mode 100644 index 0000000000..f7aab92b37 --- /dev/null +++ b/queue-7.0/ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch @@ -0,0 +1,50 @@ +From 23c8dba54d8c60b29d05026c25a7fc2f1a7ff465 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:05 -0700 +Subject: ethtool: module: avoid leaking a netdev ref on module flash errors + +From: Jakub Kicinski + +[ Upstream commit fb7f511d62692661846c47f199e0afe25c2982db ] + +module_flash_fw_schedule() is missing undo for setting +the "in_progress" flag and taking the netdev reference. +Delay taking these, the device can't disappear while +we are holding rtnl_lock. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-3-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 8047c14f7ee370..594a49fdd7fd06 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -319,8 +319,6 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + if (err < 0) + goto err_release_firmware; + +- dev->ethtool->module_fw_flash_in_progress = true; +- netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL); + fw_update->dev = dev; + fw_update->ntf_params.portid = info->snd_portid; + fw_update->ntf_params.seq = info->snd_seq; +@@ -335,6 +333,9 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + if (err < 0) + goto err_release_firmware; + ++ dev->ethtool->module_fw_flash_in_progress = true; ++ netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL); ++ + schedule_work(&module_fw->work); + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch b/queue-7.0/ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch new file mode 100644 index 0000000000..e6b2050546 --- /dev/null +++ b/queue-7.0/ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch @@ -0,0 +1,64 @@ +From c324e0df6028d324a1c09461e852bf53e0450e7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:06 -0700 +Subject: ethtool: module: avoid racy updates to dev->ethtool bitfield + +From: Jakub Kicinski + +[ Upstream commit 7a84b965ffc12030af63cd10a8f3a1123ff39b7a ] + +When reviewing other changes Gemini points out that we currently +update module_fw_flash_in_progress without holding any locks. +Since module_fw_flash_in_progress is part of a bitfield this +is not great, updates to other fields may be lost. + +We could use a bool and sprinkle some READ_ONCE/WRITE_ONCE here +but seems like the issue is rather than the work is an unusual +writer. The other writers already hold the right locks. So just +very briefly take these locks when the work completes. + +Note that nothing ever cancels the FW update work, so there's +no concern with deadlocks vs cancel. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-4-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 594a49fdd7fd06..ce4ce514edca89 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -221,14 +221,22 @@ static void module_flash_fw_work_list_del(struct list_head *list) + static void module_flash_fw_work(struct work_struct *work) + { + struct ethtool_module_fw_flash *module_fw; ++ struct net_device *dev; + + module_fw = container_of(work, struct ethtool_module_fw_flash, work); ++ dev = module_fw->fw_update.dev; + + ethtool_cmis_fw_update(&module_fw->fw_update); + + module_flash_fw_work_list_del(&module_fw->list); +- module_fw->fw_update.dev->ethtool->module_fw_flash_in_progress = false; +- netdev_put(module_fw->fw_update.dev, &module_fw->dev_tracker); ++ ++ rtnl_lock(); ++ netdev_lock_ops(dev); ++ dev->ethtool->module_fw_flash_in_progress = false; ++ netdev_unlock_ops(dev); ++ rtnl_unlock(); ++ ++ netdev_put(dev, &module_fw->dev_tracker); + release_firmware(module_fw->fw_update.fw); + kfree(module_fw); + } +-- +2.53.0 + diff --git a/queue-7.0/ethtool-module-call-ethnl_ops_complete-on-module-fla.patch b/queue-7.0/ethtool-module-call-ethnl_ops_complete-on-module-fla.patch new file mode 100644 index 0000000000..05aa68b85f --- /dev/null +++ b/queue-7.0/ethtool-module-call-ethnl_ops_complete-on-module-fla.patch @@ -0,0 +1,42 @@ +From 435553a917bdaa1dfc9469d8cdc1e4140d3100b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:04 -0700 +Subject: ethtool: module: call ethnl_ops_complete() on module flash errors + +From: Jakub Kicinski + +[ Upstream commit 84371fb58423f997939aacdcbc02d128d76a54e5 ] + +When validate() fails we are skipping over ethnl_ops_complete() +even tho we already called ethnl_ops_begin(). + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 0a761bf4771e11..8047c14f7ee370 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -427,10 +427,11 @@ int ethnl_act_module_fw_flash(struct sk_buff *skb, struct genl_info *info) + + ret = ethnl_module_fw_flash_validate(dev, info->extack); + if (ret < 0) +- goto out_unlock; ++ goto out_complete; + + ret = module_flash_fw(dev, tb, skb, info); + ++out_complete: + ethnl_ops_complete(dev); + + out_unlock: +-- +2.53.0 + diff --git a/queue-7.0/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch b/queue-7.0/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch new file mode 100644 index 0000000000..7c860187a4 --- /dev/null +++ b/queue-7.0/ethtool-module-check-fw_flash_in_progress-under-rtnl.patch @@ -0,0 +1,56 @@ +From 6fd890d3905671ca0d32603e23f02426807a819f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:07 -0700 +Subject: ethtool: module: check fw_flash_in_progress under rtnl_lock + +From: Jakub Kicinski + +[ Upstream commit 504eaefa44c8dec50f7499edcb36d24f3aefab2a ] + +ethnl_set_module_validate() inspects module_fw_flash_in_progress +but validate is meant for _input_ validation, not state validation. +rtnl_lock is not held, yet. Move the check into ethnl_set_module(). + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Maxime Chevallier +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index ce4ce514edca89..373326e49d150e 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -120,12 +120,6 @@ ethnl_set_module_validate(struct ethnl_req_info *req_info, + if (!tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]) + return 0; + +- if (req_info->dev->ethtool->module_fw_flash_in_progress) { +- NL_SET_ERR_MSG(info->extack, +- "Module firmware flashing is in progress"); +- return -EBUSY; +- } +- + if (!ops->get_module_power_mode || !ops->set_module_power_mode) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY], +@@ -148,6 +142,12 @@ ethnl_set_module(struct ethnl_req_info *req_info, struct genl_info *info) + + ops = dev->ethtool_ops; + ++ if (dev->ethtool->module_fw_flash_in_progress) { ++ NL_SET_ERR_MSG(info->extack, ++ "Module firmware flashing is in progress"); ++ return -EBUSY; ++ } ++ + power_new.policy = nla_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]); + ret = ops->get_module_power_mode(dev, &power, info->extack); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-7.0/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch b/queue-7.0/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch new file mode 100644 index 0000000000..9473de367f --- /dev/null +++ b/queue-7.0/ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch @@ -0,0 +1,105 @@ +From 4277857e3371b603b23d436a698c1fd550a6f91b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:13:08 -0700 +Subject: ethtool: module: fix cleanup if socket used for flashing multiple + devices + +From: Jakub Kicinski + +[ Upstream commit 760d04ebad5c4304f22c0d2251c9623b87a117c8 ] + +When a single Netlink socket issues MODULE_FW_FLASH_ACT against multiple +devices, ethnl_sock_priv_set() overwrites sk_priv->dev on each call, +retaining only the last one. The socket priv is used on socket close, +to walk the global work list and mark the uncompleted flashing work +as "orphaned". Otherwise if another socket reuses the PID it will +unexpectedly receive the flashing notifications. + +Don't record the device, record net pointer instead. The purpose of +the dev is to scope the work to a netns, anyway. If we store netns +the overrides are safe/a nop since all flashed devices must be in +the same netns as the socket. + +Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware") +Reviewed-by: Danielle Ratson +Link: https://patch.msgid.link/20260522231312.1710836-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/module.c | 9 ++++----- + net/ethtool/netlink.c | 4 ++-- + net/ethtool/netlink.h | 4 ++-- + 3 files changed, 8 insertions(+), 9 deletions(-) + +diff --git a/net/ethtool/module.c b/net/ethtool/module.c +index 373326e49d150e..6eb83f6b3d267c 100644 +--- a/net/ethtool/module.c ++++ b/net/ethtool/module.c +@@ -291,11 +291,9 @@ void ethnl_module_fw_flash_sock_destroy(struct ethnl_sock_priv *sk_priv) + + spin_lock(&module_fw_flash_work_list_lock); + list_for_each_entry(work, &module_fw_flash_work_list, list) { +- if (work->fw_update.dev == sk_priv->dev && +- work->fw_update.ntf_params.portid == sk_priv->portid) { ++ if (work->fw_update.ntf_params.portid == sk_priv->portid && ++ dev_net(work->fw_update.dev) == sk_priv->net) + work->fw_update.ntf_params.closed_sock = true; +- break; +- } + } + spin_unlock(&module_fw_flash_work_list_lock); + } +@@ -332,7 +330,8 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name, + fw_update->ntf_params.seq = info->snd_seq; + fw_update->ntf_params.closed_sock = false; + +- err = ethnl_sock_priv_set(skb, dev, fw_update->ntf_params.portid, ++ err = ethnl_sock_priv_set(skb, dev_net(dev), ++ fw_update->ntf_params.portid, + ETHTOOL_SOCK_TYPE_MODULE_FW_FLASH); + if (err < 0) + goto err_release_firmware; +diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c +index 6e5f0f4f815a1a..4cf928da607252 100644 +--- a/net/ethtool/netlink.c ++++ b/net/ethtool/netlink.c +@@ -52,7 +52,7 @@ const struct nla_policy ethnl_header_policy_phy_stats[] = { + [ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1), + }; + +-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, ++int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid, + enum ethnl_sock_type type) + { + struct ethnl_sock_priv *sk_priv; +@@ -61,7 +61,7 @@ int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, + if (IS_ERR(sk_priv)) + return PTR_ERR(sk_priv); + +- sk_priv->dev = dev; ++ sk_priv->net = net; + sk_priv->portid = portid; + sk_priv->type = type; + +diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h +index 89010eaa67dfcd..65c24f627b218f 100644 +--- a/net/ethtool/netlink.h ++++ b/net/ethtool/netlink.h +@@ -318,12 +318,12 @@ enum ethnl_sock_type { + }; + + struct ethnl_sock_priv { +- struct net_device *dev; ++ struct net *net; + u32 portid; + enum ethnl_sock_type type; + }; + +-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid, ++int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid, + enum ethnl_sock_type type); + + /** +-- +2.53.0 + diff --git a/queue-7.0/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch b/queue-7.0/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch new file mode 100644 index 0000000000..268e6002b3 --- /dev/null +++ b/queue-7.0/ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch @@ -0,0 +1,59 @@ +From e789513d907129b0d1859ee78bd50288aa380a53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:27 -0700 +Subject: ethtool: pse-pd: fix missing ethnl_ops_complete() + +From: Jakub Kicinski + +[ Upstream commit ab5bf428fb6bd361163c7247b92750d1d24ca2ed ] + +pse_prepare_data() is missing ethnl_ops_complete() if +ethnl_req_get_phydev() returned an error. Move getting +phydev up so that we don't have to worry about this +(similar order to linkstate_prepare_data()). + +Note that phydev may still be NULL (this is checked in +pse_get_pse_attributes()), the goal isn't really to avoid +the _begin() / _complete() calls, only to simplify the error +handling. + +While at it propagate the original error. Why this code +overrides the error with -ENODEV but !phydev generates +-EOPNOTSUPP is unclear to me... + +Fixes: 31748765bed3 ("net: ethtool: pse-pd: Target the command to the requested PHY") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/pse-pd.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c +index 24def9c9dd54bf..aa4514333d13bd 100644 +--- a/net/ethtool/pse-pd.c ++++ b/net/ethtool/pse-pd.c +@@ -61,14 +61,14 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base, + struct phy_device *phydev; + int ret; + +- ret = ethnl_ops_begin(dev); +- if (ret < 0) +- return ret; +- + phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER, + info->extack); + if (IS_ERR(phydev)) +- return -ENODEV; ++ return PTR_ERR(phydev); ++ ++ ret = ethnl_ops_begin(dev); ++ if (ret < 0) ++ return ret; + + ret = pse_get_pse_attributes(phydev, info->extack, data); + +-- +2.53.0 + diff --git a/queue-7.0/ethtool-rss-add-missing-errno-on-rss-context-delete.patch b/queue-7.0/ethtool-rss-add-missing-errno-on-rss-context-delete.patch new file mode 100644 index 0000000000..caabd3b275 --- /dev/null +++ b/queue-7.0/ethtool-rss-add-missing-errno-on-rss-context-delete.patch @@ -0,0 +1,40 @@ +From 0d6d66ae9eacc703a24f730adde29fbfb418e267 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:43 -0700 +Subject: ethtool: rss: add missing errno on RSS context delete + +From: Jakub Kicinski + +[ Upstream commit 3e6c6e9782ff8a8d8ded774b07ad4590cd61d04c ] + +Remember to set ret before jumping out if someone tries +to delete a context on a device which doesn't support +contexts. + +Fixes: fbe09277fa63 ("ethtool: rss: support removing contexts via Netlink") +Link: https://patch.msgid.link/20260522230647.1705600-3-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 926be5698ba4cc..688c0e4bba69db 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -1160,8 +1160,10 @@ int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info) + dev = req.dev; + ops = dev->ethtool_ops; + +- if (!ops->create_rxfh_context) ++ if (!ops->create_rxfh_context) { ++ ret = -EOPNOTSUPP; + goto exit_free_dev; ++ } + + rtnl_lock(); + netdev_lock_ops(dev); +-- +2.53.0 + diff --git a/queue-7.0/ethtool-rss-avoid-device-context-leak-on-reply-build.patch b/queue-7.0/ethtool-rss-avoid-device-context-leak-on-reply-build.patch new file mode 100644 index 0000000000..70992c7e27 --- /dev/null +++ b/queue-7.0/ethtool-rss-avoid-device-context-leak-on-reply-build.patch @@ -0,0 +1,55 @@ +From fd7cb3983dc035e257226b2029edba581e951a02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:47 -0700 +Subject: ethtool: rss: avoid device context leak on reply-build failure + +From: Jakub Kicinski + +[ Upstream commit 32a9ecde62731c9f7412507709192c84dafc38d1 ] + +We wait with filling the reply for new RSS context creation +until after the driver ->create_rxfh_context call. The driver +needs to fill some of the defaults in the context. The failure +of rss_fill_reply() is somewhat theoretical, but doesn't take +much effort to handle it properly. Call ->remove_rxfh_context(). + +If the driver's remove callback fails (some implementations like sfc +can return real command errors from firmware RPCs) - skip the xa_erase +and kfree, leaving the context in the xarray. This matches how +ethnl_rss_delete_doit() behaves. + +Fixes: a166ab7816c5 ("ethtool: rss: support creating contexts via Netlink") +Link: https://patch.msgid.link/20260522230647.1705600-7-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index f745ddec6fbab8..b122f67dbde1d6 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -1096,7 +1096,7 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) + ntf_fail |= rss_fill_reply(rsp, &req.base, &data.base); + if (WARN_ON(!hdr || ntf_fail)) { + ret = -EMSGSIZE; +- goto exit_unlock; ++ goto err_remove_ctx; + } + + genlmsg_end(rsp, hdr); +@@ -1124,6 +1124,10 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) + nlmsg_free(rsp); + return ret; + ++err_remove_ctx: ++ if (ops->remove_rxfh_context(dev, ctx, req.rss_context, NULL)) ++ /* leave the context on failure, like ethnl_rss_delete_doit() */ ++ goto exit_unlock; + err_ctx_id_free: + xa_erase(&dev->ethtool->rss_ctx, req.rss_context); + err_unlock_free_ctx: +-- +2.53.0 + diff --git a/queue-7.0/ethtool-rss-avoid-modifying-the-rss-context-response.patch b/queue-7.0/ethtool-rss-avoid-modifying-the-rss-context-response.patch new file mode 100644 index 0000000000..f186a33821 --- /dev/null +++ b/queue-7.0/ethtool-rss-avoid-modifying-the-rss-context-response.patch @@ -0,0 +1,73 @@ +From faa3701e72e78b2298ea270b053dac19c6203082 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:42 -0700 +Subject: ethtool: rss: avoid modifying the RSS context response + +From: Jakub Kicinski + +[ Upstream commit c75b6f6eaacd0b74b832414cc3b9289c3686e941 ] + +Gemini says that we're modifying the RSS_CREATE response skb. +I think it's right, the comment says that unicast() should +unshare the skb but I'm not entirely sure what I meant there. +netlink_trim() does a copy but only if skb is not well sized +(it's at least 2x larger than necessary for the payload). + +Fixes: a166ab7816c5 ("ethtool: rss: support creating contexts via Netlink") +Link: https://patch.msgid.link/20260522230647.1705600-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index da5934cceb0757..926be5698ba4cc 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -974,11 +974,17 @@ ethnl_rss_create_validate(struct net_device *dev, struct genl_info *info) + } + + static void +-ethnl_rss_create_send_ntf(struct sk_buff *rsp, struct net_device *dev) ++ethnl_rss_create_send_ntf(const struct sk_buff *rsp, struct net_device *dev) + { +- struct nlmsghdr *nlh = (void *)rsp->data; + struct genlmsghdr *genl_hdr; ++ struct nlmsghdr *nlh; ++ struct sk_buff *ntf; ++ ++ ntf = skb_copy_expand(rsp, 0, 0, GFP_KERNEL); ++ if (!ntf) ++ return; + ++ nlh = nlmsg_hdr(ntf); + /* Convert the reply into a notification */ + nlh->nlmsg_pid = 0; + nlh->nlmsg_seq = ethnl_bcast_seq_next(); +@@ -986,7 +992,7 @@ ethnl_rss_create_send_ntf(struct sk_buff *rsp, struct net_device *dev) + genl_hdr = nlmsg_data(nlh); + genl_hdr->cmd = ETHTOOL_MSG_RSS_CREATE_NTF; + +- ethnl_multicast(rsp, dev); ++ ethnl_multicast(ntf, dev); + } + + int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) +@@ -1094,12 +1100,8 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) + + genlmsg_end(rsp, hdr); + +- /* Use the same skb for the response and the notification, +- * genlmsg_reply() will copy the skb if it has elevated user count. +- */ +- skb_get(rsp); +- ret = genlmsg_reply(rsp, info); + ethnl_rss_create_send_ntf(rsp, dev); ++ ret = genlmsg_reply(rsp, info); + rsp = NULL; + + exit_unlock: +-- +2.53.0 + diff --git a/queue-7.0/ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch b/queue-7.0/ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch new file mode 100644 index 0000000000..698c065a03 --- /dev/null +++ b/queue-7.0/ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch @@ -0,0 +1,38 @@ +From 197579e2f979fa3bfbe5847727d195a1ee8fbcce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:44 -0700 +Subject: ethtool: rss: fix falsely ignoring indir table updates + +From: Jakub Kicinski + +[ Upstream commit 8d60141a32875248ef71d49c9920fa5e2aa40b29 ] + +rss_set_prep_indir() compares the new indirection table against the +current one to determine whether any update is needed. The memcmp +call passes data->indir_size as the length argument, but indir_size +is the number of u32 entries, not the byte count. + +Fixes: c0ae03588bbb ("ethtool: rss: initial RSS_SET (indirection table handling)") +Link: https://patch.msgid.link/20260522230647.1705600-4-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 688c0e4bba69db..4877655f724419 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -684,7 +684,7 @@ rss_set_prep_indir(struct net_device *dev, struct genl_info *info, + ethtool_rxfh_indir_default(i, num_rx_rings); + } + +- *mod |= memcmp(rxfh->indir, data->indir_table, data->indir_size); ++ *mod |= memcmp(rxfh->indir, data->indir_table, alloc_size); + + return 0; + +-- +2.53.0 + diff --git a/queue-7.0/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch b/queue-7.0/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch new file mode 100644 index 0000000000..00a23fd361 --- /dev/null +++ b/queue-7.0/ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch @@ -0,0 +1,47 @@ +From ffe42842b2d707cb7f5e1be7355fc9bfd39a509f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:46 -0700 +Subject: ethtool: rss: fix hkey leak when indir_size is 0 + +From: Jakub Kicinski + +[ Upstream commit 78ccf1a70c6378e1f5073a8c2209b5129067b925 ] + +rss_get_data_alloc() allocates a single buffer that backs both the +indirection table and the hash key, but only assigned data->indir_table +when indir_size was nonzero. The expectation was that no driver +implements RSS without supporting indirection table but apparently +enic does just that (it's the only such in-tree driver). +enic has get_rxfh_key_size but no get_rxfh_indir_size. +data->indir_table stays as NULL, hkey gets set but rss_get_data_free() +kfree(data->indir_table) is a nop and the allocation leaks. + +Always store the allocation base in data->indir_table so the free path +is unambiguous. No caller treats indir_table as a sentinel; everything +keys off indir_size. + +Fixes: 7112a04664bf ("ethtool: add netlink based get rss support") +Link: https://patch.msgid.link/20260522230647.1705600-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 5416aec13b7fe7..f745ddec6fbab8 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -132,8 +132,7 @@ rss_get_data_alloc(struct net_device *dev, struct rss_reply_data *data) + if (!rss_config) + return -ENOMEM; + +- if (data->indir_size) +- data->indir_table = (u32 *)rss_config; ++ data->indir_table = (u32 *)rss_config; + if (data->hkey_size) + data->hkey = rss_config + indir_bytes; + +-- +2.53.0 + diff --git a/queue-7.0/ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch b/queue-7.0/ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch new file mode 100644 index 0000000000..591786f905 --- /dev/null +++ b/queue-7.0/ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch @@ -0,0 +1,41 @@ +From 364ef4eb6b6a58d4d0b4e4a5485b5dc28890262c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 16:06:45 -0700 +Subject: ethtool: rss: fix indir_table and hkey leak on get_rxfh failure + +From: Jakub Kicinski + +[ Upstream commit 266297692f97008ca48bc311775c087c59bd7fe3 ] + +rss_prepare_get() allocates the indirection table and hash key buffer +via rss_get_data_alloc(), then calls ops->get_rxfh() to populate them. +If get_rxfh() fails, the function returns an error without freeing +the allocation. + +Fixes: 4f038a6a02d2 ("net: ethtool: Don't call .cleanup_data when prepare_data fails") +Link: https://patch.msgid.link/20260522230647.1705600-5-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/rss.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c +index 4877655f724419..5416aec13b7fe7 100644 +--- a/net/ethtool/rss.c ++++ b/net/ethtool/rss.c +@@ -168,8 +168,10 @@ rss_prepare_get(const struct rss_req_info *request, struct net_device *dev, + rxfh.key = data->hkey; + + ret = ops->get_rxfh(dev, &rxfh); +- if (ret) ++ if (ret) { ++ rss_get_data_free(data); + goto out_unlock; ++ } + + data->hfunc = rxfh.hfunc; + data->input_xfrm = rxfh.input_xfrm; +-- +2.53.0 + diff --git a/queue-7.0/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch b/queue-7.0/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch new file mode 100644 index 0000000000..e6cb326609 --- /dev/null +++ b/queue-7.0/ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch @@ -0,0 +1,42 @@ +From c9d696dd1160472043a4c815b1e36b10d5e4ff95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:31 -0700 +Subject: ethtool: strset: fix header attribute index in ethnl_req_get_phydev() + +From: Jakub Kicinski + +[ Upstream commit a8d8bef6b45bf7cc0b1f6110c5cd8d0160a9bad7 ] + +strset_prepare_data() passes ETHTOOL_A_HEADER_FLAGS (3) as the header +attribute to ethnl_req_get_phydev(). This is incorrect, in the main +attr space 3 is ETHTOOL_A_STRSET_COUNTS_ONLY, not the request +header attr. The correct constant is ETHTOOL_A_STRSET_HEADER (1). + +ethnl_req_get_phydev() only uses this value for the extack, +so this is not a "functionally visible"(?) bug. + +Fixes: e96c93aa4be9 ("net: ethtool: strset: Allow querying phy stats by index") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-9-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/strset.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c +index f6a67109beda1b..872ca593b97668 100644 +--- a/net/ethtool/strset.c ++++ b/net/ethtool/strset.c +@@ -309,7 +309,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base, + return 0; + } + +- phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS, ++ phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STRSET_HEADER, + info->extack); + + /* phydev can be NULL, check for errors only */ +-- +2.53.0 + diff --git a/queue-7.0/ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch b/queue-7.0/ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch new file mode 100644 index 0000000000..84cd3ac8f9 --- /dev/null +++ b/queue-7.0/ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch @@ -0,0 +1,42 @@ +From fe14dfb0cbc18ca6a70b022e3896c127a0a45bde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:28 -0700 +Subject: ethtool: tsconfig: fix missing ethnl_ops_complete() + +From: Jakub Kicinski + +[ Upstream commit 6386bd772de64e6760306eb91c7e86163af6c22f ] + +tsconfig_prepare_data() calls ethnl_ops_begin(), we need to call +ethnl_ops_complete() before returning the error. + +Fixes: 6e9e2eed4f39 ("net: ethtool: Add support for tsconfig command to get/set hwtstamp config") +Reviewed-by: Vadim Fedorenko +Reviewed-by: Kory Maincent +Link: https://patch.msgid.link/20260526153533.2779187-6-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsconfig.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/tsconfig.c b/net/ethtool/tsconfig.c +index 966c769c72677f..990dca9a3fc564 100644 +--- a/net/ethtool/tsconfig.c ++++ b/net/ethtool/tsconfig.c +@@ -69,8 +69,10 @@ static int tsconfig_prepare_data(const struct ethnl_req_info *req_base, + if (ret) + goto out; + +- if (ts_info.phc_index == -1) +- return -ENODEV; ++ if (ts_info.phc_index == -1) { ++ ret = -ENODEV; ++ goto out; ++ } + + data->hwprov_desc.index = ts_info.phc_index; + data->hwprov_desc.qualifier = ts_info.phc_qualifier; +-- +2.53.0 + diff --git a/queue-7.0/ethtool-tsconfig-fix-reply-error-handling.patch b/queue-7.0/ethtool-tsconfig-fix-reply-error-handling.patch new file mode 100644 index 0000000000..52d830065b --- /dev/null +++ b/queue-7.0/ethtool-tsconfig-fix-reply-error-handling.patch @@ -0,0 +1,55 @@ +From 4819737df5bdc3ca659a57227aa2933bf504fc91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:25 -0700 +Subject: ethtool: tsconfig: fix reply error handling + +From: Jakub Kicinski + +[ Upstream commit a888bbd43940cada72f7686337741ce86d1cf869 ] + +A couple of trivial bugs in error handling in tsconfig_send_reply(). +If we failed to allocate rskb we need to set the error. +If we did allocate it but failed to send it - we need to remember +to free it. + +Fixes: 6e9e2eed4f39 ("net: ethtool: Add support for tsconfig command to get/set hwtstamp config") +Reviewed-by: Vadim Fedorenko +Reviewed-by: Kory Maincent +Link: https://patch.msgid.link/20260526153533.2779187-3-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsconfig.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/tsconfig.c b/net/ethtool/tsconfig.c +index e49e612a68c2c0..966c769c72677f 100644 +--- a/net/ethtool/tsconfig.c ++++ b/net/ethtool/tsconfig.c +@@ -224,16 +224,21 @@ static int tsconfig_send_reply(struct net_device *dev, struct genl_info *info) + reply_len = ret + ethnl_reply_header_size(); + rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_TSCONFIG_SET_REPLY, + ETHTOOL_A_TSCONFIG_HEADER, info, &reply_payload); +- if (!rskb) ++ if (!rskb) { ++ ret = -ENOMEM; + goto err_cleanup; ++ } + + ret = tsconfig_fill_reply(rskb, &req_info->base, &reply_data->base); + if (ret < 0) +- goto err_cleanup; ++ goto err_free_msg; + + genlmsg_end(rskb, reply_payload); + ret = genlmsg_reply(rskb, info); ++ rskb = NULL; + ++err_free_msg: ++ nlmsg_free(rskb); + err_cleanup: + kfree(reply_data); + kfree(req_info); +-- +2.53.0 + diff --git a/queue-7.0/ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch b/queue-7.0/ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch new file mode 100644 index 0000000000..8a9fdb9848 --- /dev/null +++ b/queue-7.0/ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch @@ -0,0 +1,49 @@ +From c3bc87e1fee5346980304db27bf47d63b2ae47af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:30 -0700 +Subject: ethtool: tsinfo: don't pass ERR_PTR to genlmsg_cancel on prepare + failure + +From: Jakub Kicinski + +[ Upstream commit c3fc9976f686f9a95baf87db9d387f218fd65394 ] + +The goto err label leads to: + + genlmsg_cancel(skb, ehdr); + return ret; + +If ethnl_tsinfo_prepare_dump() failed, it has not started a genlmsg. +There's nothing to cancel, and passing an error pointer to +genlmsg_cancel() would cause a crash. + +Fixes: b9e3f7dc9ed9 ("net: ethtool: tsinfo: Enhance tsinfo to support several hwtstamp by net topology") +Reviewed-by: Maxime Chevallier +Reviewed-by: Kory Maincent +Link: https://patch.msgid.link/20260526153533.2779187-8-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsinfo.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/tsinfo.c b/net/ethtool/tsinfo.c +index cb1491e0a28bac..64e6016a7a1772 100644 +--- a/net/ethtool/tsinfo.c ++++ b/net/ethtool/tsinfo.c +@@ -405,10 +405,8 @@ static int ethnl_tsinfo_dump_one_netdev(struct sk_buff *skb, + continue; + + ehdr = ethnl_tsinfo_prepare_dump(skb, dev, reply_data, cb); +- if (IS_ERR(ehdr)) { +- ret = PTR_ERR(ehdr); +- goto err; +- } ++ if (IS_ERR(ehdr)) ++ return PTR_ERR(ehdr); + + reply_data->ts_info.phc_qualifier = ctx->pos_phcqualifier; + ret = ops->get_ts_info(dev, &reply_data->ts_info); +-- +2.53.0 + diff --git a/queue-7.0/ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch b/queue-7.0/ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch new file mode 100644 index 0000000000..008dbf6e1a --- /dev/null +++ b/queue-7.0/ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch @@ -0,0 +1,75 @@ +From 547d8b6755488b890f877b151b8f04890c537bea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:29 -0700 +Subject: ethtool: tsinfo: fix uninitialized stats on the by-PHC path + +From: Jakub Kicinski + +[ Upstream commit 1de405699c62c3a9544bcdcfb9eff8a01cfc7582 ] + +tsinfo_prepare_data() has two code paths: a "by-PHC" path for +user-specified hardware timestamping providers, and the old path. +Commit 89e281ebff72 ("ethtool: init tsinfo stats if requested") added +ethtool_stats_init() to mark stat slots as ETHTOOL_STAT_NOT_SET before +the driver callback populates them, but placed the call inside the +old-path block. + +When commit b9e3f7dc9ed9 ("net: ethtool: tsinfo: Enhance tsinfo to +support several hwtstamp by net topology") added the by-PHC early +return, it landed above the stats initialization. On that path +the stats array retains the zero-fill from ethnl_init_reply_data()'s +zalloc. This leads to the reply including a stats nest with four +zero-valued attributes that should have been absent. + +Reject GET requests for stats with HWTSTAMP_PROVIDER or dump. + +Fixes: b9e3f7dc9ed9 ("net: ethtool: tsinfo: Enhance tsinfo to support several hwtstamp by net topology") +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260526153533.2779187-7-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/tsinfo.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/net/ethtool/tsinfo.c b/net/ethtool/tsinfo.c +index c0145c752d2f8b..cb1491e0a28bac 100644 +--- a/net/ethtool/tsinfo.c ++++ b/net/ethtool/tsinfo.c +@@ -81,6 +81,11 @@ tsinfo_parse_request(struct ethnl_req_info *req_base, struct nlattr **tb, + if (!tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER]) + return 0; + ++ if (req_base->flags & ETHTOOL_FLAG_STATS) { ++ NL_SET_ERR_MSG(extack, "can't query statistics for a provider"); ++ return -EOPNOTSUPP; ++ } ++ + return ts_parse_hwtst_provider(tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER], + &req->hwprov_desc, extack, &mod); + } +@@ -521,6 +526,12 @@ int ethnl_tsinfo_start(struct netlink_callback *cb) + if (ret < 0) + goto free_reply_data; + ++ if (req_info->base.flags & ETHTOOL_FLAG_STATS) { ++ NL_SET_ERR_MSG(cb->extack, "stats not supported in dump"); ++ ret = -EOPNOTSUPP; ++ goto err_dev_put; ++ } ++ + ctx->req_info = req_info; + ctx->reply_data = reply_data; + ctx->pos_ifindex = 0; +@@ -530,6 +541,8 @@ int ethnl_tsinfo_start(struct netlink_callback *cb) + + return 0; + ++err_dev_put: ++ ethnl_parse_header_dev_put(&req_info->base); + free_reply_data: + kfree(reply_data); + free_req_info: +-- +2.53.0 + diff --git a/queue-7.0/gpio-adnp-fix-flow-control-regression-caused-by-scop.patch b/queue-7.0/gpio-adnp-fix-flow-control-regression-caused-by-scop.patch new file mode 100644 index 0000000000..4296edc7e3 --- /dev/null +++ b/queue-7.0/gpio-adnp-fix-flow-control-regression-caused-by-scop.patch @@ -0,0 +1,43 @@ +From e4087ffb82072afe9d635ba50f4bae9e67a6fc05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 09:35:27 +0200 +Subject: gpio: adnp: fix flow control regression caused by scoped_guard() + +From: Bartosz Golaszewski + +[ Upstream commit a5c627d90809b793fc053849b3a00609db305776 ] + +scoped_guard() is implemented as a for loop. Using it to protect code +using the continue statement changes the flow as we now only break out +of the hidden loop inside scoped_guard(), not the original for loop. Use +a regular code block instead. + +Fixes: c7fe19ed3973 ("gpio: adnp: use lock guards for the I2C lock") +Reported-by: David Lechner +Closes: https://lore.kernel.org/all/cde2abb2-4cc8-4fc9-b34a-0c5d2b95779f@baylibre.com/ +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/20260522073527.9812-1-bartosz.golaszewski@oss.qualcomm.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-adnp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c +index e5ac2d2110137f..fe5bcaa90496aa 100644 +--- a/drivers/gpio/gpio-adnp.c ++++ b/drivers/gpio/gpio-adnp.c +@@ -237,7 +237,9 @@ static irqreturn_t adnp_irq(int irq, void *data) + unsigned long pending; + int err; + +- scoped_guard(mutex, &adnp->i2c_lock) { ++ { ++ guard(mutex)(&adnp->i2c_lock); ++ + err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); + if (err < 0) + continue; +-- +2.53.0 + diff --git a/queue-7.0/gpio-mxc-fix-irq_high-handling.patch b/queue-7.0/gpio-mxc-fix-irq_high-handling.patch new file mode 100644 index 0000000000..9aa0277880 --- /dev/null +++ b/queue-7.0/gpio-mxc-fix-irq_high-handling.patch @@ -0,0 +1,38 @@ +From 9aff72d05d5c0f628301257534f677cbd8c5085c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 08:35:01 +0200 +Subject: gpio: mxc: fix irq_high handling + +From: Alexander Stein + +[ Upstream commit dac917ed5aead741004db8d0d5151dd577802df8 ] + +If port->irq_high is -1 (fsl,imx21-gpio compatible) and gpio_idx is >= 16 +enable_irq_wake() is called with -1 which is wrong. + +Fixes: 5f6d1998adeb ("gpio: mxc: release the parent IRQ in runtime suspend") +Signed-off-by: Alexander Stein +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260526063504.25916-1-alexander.stein@ew.tq-group.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mxc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c +index 647b6f4861b744..12f11a6c96653c 100644 +--- a/drivers/gpio/gpio-mxc.c ++++ b/drivers/gpio/gpio-mxc.c +@@ -469,7 +469,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) + * the handler is needed only once, but doing it for every port + * is more robust and easier. + */ +- port->irq_high = -1; ++ port->irq_high = 0; + port->mx_irq_handler = mx2_gpio_irq_handler; + } else + port->mx_irq_handler = mx3_gpio_irq_handler; +-- +2.53.0 + diff --git a/queue-7.0/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch b/queue-7.0/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch new file mode 100644 index 0000000000..ac8b1b35a2 --- /dev/null +++ b/queue-7.0/gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch @@ -0,0 +1,78 @@ +From 5984d5b25d011db16b6c794b47f97aed9636d7ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:45 +0200 +Subject: gpio: rockchip: convert bank->clk to devm_clk_get_enabled() + +From: Marco Scardovi + +[ Upstream commit 3e46c18d5d87f063a93ae0fe7662fbf6660459d5 ] + +The bank->clk was previously obtained via of_clk_get() and manually +prepared/enabled. However, it was missing a corresponding clk_put() in +both the error paths and the remove function, leading to a reference leak. + +Convert the allocation to devm_clk_get_enabled(), which also properly +propagates failures from clk_prepare_enable() that were previously ignored. + +The GPIO bank device uses the same OF node as the previous of_clk_get() +call, so devm_clk_get_enabled(dev, NULL) correctly resolves the same +clock provider entry. + +Fix the reference leak and simplify the code by removing the manual +clk_disable_unprepare() calls in the probe error paths and in the +remove function. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index 0fff4a699f12d1..f910220141f712 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -656,11 +656,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + if (!bank->irq) + return -EINVAL; + +- bank->clk = of_clk_get(bank->of_node, 0); ++ bank->clk = devm_clk_get_enabled(bank->dev, NULL); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + +- clk_prepare_enable(bank->clk); + id = readl(bank->reg_base + gpio_regs_v2.version_id); + + switch (id) { +@@ -672,7 +671,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + bank->db_clk = of_clk_get(bank->of_node, 1); + if (IS_ERR(bank->db_clk)) { + dev_err(bank->dev, "cannot find debounce clk\n"); +- clk_disable_unprepare(bank->clk); + return -EINVAL; + } + break; +@@ -751,7 +749,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev) + + ret = rockchip_gpiolib_register(bank); + if (ret) { +- clk_disable_unprepare(bank->clk); + mutex_unlock(&bank->deferred_lock); + return ret; + } +@@ -792,7 +789,6 @@ static void rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + +- clk_disable_unprepare(bank->clk); + gpiochip_remove(&bank->gpio_chip); + } + +-- +2.53.0 + diff --git a/queue-7.0/gpio-rockchip-teardown-bugs-and-resource-leaks.patch b/queue-7.0/gpio-rockchip-teardown-bugs-and-resource-leaks.patch new file mode 100644 index 0000000000..d6375091ff --- /dev/null +++ b/queue-7.0/gpio-rockchip-teardown-bugs-and-resource-leaks.patch @@ -0,0 +1,88 @@ +From 6b190e68f9aa881bd5f5a82a7c5f19062d079730 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:02:46 +0200 +Subject: gpio: rockchip: teardown bugs and resource leaks + +From: Marco Scardovi + +[ Upstream commit 9500077678230e36d22bf16d2b9539c13e59a801 ] + +Address several teardown issues and resource leaks in the driver's remove +path and error handling: + +1. Debounce clock reference leak: The debounce clock (bank->db_clk) is + obtained using of_clk_get() which increments the clock's reference + count, but clk_put() is never called. Register a devm action to + cleanly release it on unbind. Note that of_clk_get(..., 1) remains + necessary over devm_clk_get() because the DT binding does not define + clock-names, precluding name-based lookup. + +2. Unregistered chained IRQ handler: The chained IRQ handler is not + disconnected in remove(). If a stray interrupt fires after the driver + is removed, the kernel attempts to execute a stale handler, leading + to a panic. Fix this by clearing the handler in remove(). + +3. IRQ domain leak: The linear IRQ domain and its generic chips are + allocated manually during probe but never removed. Remove the IRQ + domain during driver teardown to free the associated generic chips + and mappings. + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260526171050.12785-3-scardracs@disroot.org +[Bartosz: don't emit an error message on devres allocation failure] +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index f910220141f712..1ef0ba956cfd8c 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -638,10 +638,17 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank) + return ret; + } + ++static void rockchip_clk_put(void *data) ++{ ++ struct clk *clk = data; ++ ++ clk_put(clk); ++} ++ + static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + { + struct resource res; +- int id = 0; ++ int id = 0, ret; + + if (of_address_to_resource(bank->of_node, 0, &res)) { + dev_err(bank->dev, "cannot find IO resource for bank\n"); +@@ -673,6 +680,11 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) + dev_err(bank->dev, "cannot find debounce clk\n"); + return -EINVAL; + } ++ ++ ret = devm_add_action_or_reset(bank->dev, rockchip_clk_put, ++ bank->db_clk); ++ if (ret) ++ return ret; + break; + case GPIO_TYPE_V1: + bank->gpio_regs = &gpio_regs_v1; +@@ -789,6 +801,9 @@ static void rockchip_gpio_remove(struct platform_device *pdev) + { + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + ++ irq_set_chained_handler_and_data(bank->irq, NULL, NULL); ++ if (bank->domain) ++ irq_domain_remove(bank->domain); + gpiochip_remove(&bank->gpio_chip); + } + +-- +2.53.0 + diff --git a/queue-7.0/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch b/queue-7.0/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch new file mode 100644 index 0000000000..41d844911d --- /dev/null +++ b/queue-7.0/gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch @@ -0,0 +1,49 @@ +From 15f2fc579a4fb8ff836c58cfc9d011b7828e3add Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 10:15:16 +0300 +Subject: gpio: virtuser: Fix uninitialized data bug in + gpio_virtuser_direction_do_write() + +From: Dan Carpenter + +[ Upstream commit 8a122b5e72cc0043705f0d524bcd15f0c0b3ec15 ] + +If *ppos is non-zero (user-space write split over multiple calls to +write()) then simple_write_to_buffer() won't initialize the start of the +buffer. Really, non-zero values for *ppos aren't going to work at all. +Check for that and return -EINVAL at the start of the function. + +Fixes: 91581c4b3f29 ("gpio: virtuser: new virtual testing driver for the GPIO API") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/ahP3BJWWy-m_qI0X@stanley.mountain +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-virtuser.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c +index 955b5efc283ef5..c6f16cb02bf6b8 100644 +--- a/drivers/gpio/gpio-virtuser.c ++++ b/drivers/gpio/gpio-virtuser.c +@@ -399,7 +399,7 @@ static ssize_t gpio_virtuser_direction_do_write(struct file *file, + char buf[32], *trimmed; + int ret, dir, val = 0; + +- if (count >= sizeof(buf)) ++ if (*ppos != 0 || count >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +@@ -624,7 +624,7 @@ static ssize_t gpio_virtuser_consumer_write(struct file *file, + char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 2]; + int ret; + +- if (count >= sizeof(buf)) ++ if (*ppos != 0 || count >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, GPIO_VIRTUSER_NAME_BUF_LEN, ppos, +-- +2.53.0 + diff --git a/queue-7.0/hid-remove-duplicate-hid_warn_ratelimited-definition.patch b/queue-7.0/hid-remove-duplicate-hid_warn_ratelimited-definition.patch new file mode 100644 index 0000000000..344d5b8cf6 --- /dev/null +++ b/queue-7.0/hid-remove-duplicate-hid_warn_ratelimited-definition.patch @@ -0,0 +1,43 @@ +From c978f9e8dfcc900acff83041b76d773ac13e293a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 16:32:04 +0800 +Subject: HID: remove duplicate hid_warn_ratelimited definition + +From: Liu Kai + +[ Upstream commit dd2147375a8fe7c5bc3f1f1b1d3a9567c26faefa ] + +The hid_warn_ratelimited macro is defined twice in include/linux/hid.h: +- first one added by commit 4051ead99888 ("HID: rate-limit hid_warn to + prevent log flooding") +- second one added by commit 1d64624243af ("HID: core: Add + printk_ratelimited variants to hid_warn() etc")). + +The second definition is correctly grouped with other ratelimited macros. +Remove the duplicate definition. + +Fixes: 1d64624243af ("HID: core: Add printk_ratelimited variants to hid_warn() etc") +Signed-off-by: Liu Kai +[bentiss: edited commit message] +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + include/linux/hid.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/include/linux/hid.h b/include/linux/hid.h +index 101e05acf931a5..c9e0ebe9c75270 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -1284,8 +1284,6 @@ void hid_quirks_exit(__u16 bus); + dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__) + #define hid_warn(hid, fmt, ...) \ + dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__) +-#define hid_warn_ratelimited(hid, fmt, ...) \ +- dev_warn_ratelimited(&(hid)->dev, fmt, ##__VA_ARGS__) + #define hid_info(hid, fmt, ...) \ + dev_info(&(hid)->dev, fmt, ##__VA_ARGS__) + #define hid_dbg(hid, fmt, ...) \ +-- +2.53.0 + diff --git a/queue-7.0/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch b/queue-7.0/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch new file mode 100644 index 0000000000..d8dddc66a7 --- /dev/null +++ b/queue-7.0/ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch @@ -0,0 +1,48 @@ +From 55c128606073a42ce30811703a73053e46d35a53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 12:21:47 +0000 +Subject: ipv4: free net->ipv4.sysctl_local_reserved_ports after + unregister_net_sysctl_table() + +From: Eric Dumazet + +[ Upstream commit 87a1e0fe7776da7ab411be332b4be58ac8840d10 ] + +ipv4_sysctl_exit_net() is currently freeing net->ipv4.sysctl_local_reserved_ports +too soon. + +Only after unregister_net_sysctl_table() we can be sure no threads can possibly +use the sysctls, including /proc/sys/net/ipv4/ip_local_reserved_ports. + +Fixes: 122ff243f5f1 ("ipv4: make ip_local_reserved_ports per netns") +Reported-by: Ji'an Zhou +Signed-off-by: Eric Dumazet +Cc: Cong Wang +Reviewed-by: Jason Xing +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260521122147.3584624-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/sysctl_net_ipv4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 5654cc9c8a0b9e..e47df4d706a9cd 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -1698,10 +1698,10 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net) + { + const struct ctl_table *table; + +- kfree(net->ipv4.sysctl_local_reserved_ports); + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); ++ kfree(net->ipv4.sysctl_local_reserved_ports); + } + + static __net_initdata struct pernet_operations ipv4_sysctl_ops = { +-- +2.53.0 + diff --git a/queue-7.0/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch b/queue-7.0/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch new file mode 100644 index 0000000000..bcdcda4c6a --- /dev/null +++ b/queue-7.0/ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch @@ -0,0 +1,49 @@ +From 0e9f2f0f7b61ab6f16e0d83d28aa893042404627 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:31 +0800 +Subject: ipv6: fix possible infinite loop in fib6_select_path() + +From: Jiayuan Chen + +[ Upstream commit 9c7da87c2dc860bb17ca1ece942495d28b1ce3b9 ] + +Found while auditing the same pattern Sashiko reported in +rt6_fill_node() [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&first->fib6_siblings) +without waiting for RCU readers; first->fib6_siblings.next then +still points into the old ring and this softirq-side walker never +reaches &first->fib6_siblings as its terminator. fib6_purge_rt() +always WRITE_ONCE()s first->fib6_nsiblings to 0 before +list_del_rcu(), so an inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 398e873072bbfb..9a45ecdd7b853c 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -481,6 +481,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res, + const struct fib6_nh *nh = sibling->fib6_nh; + int nh_upper_bound; + ++ if (!READ_ONCE(first->fib6_nsiblings)) ++ break; ++ + nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); + if (hash > nh_upper_bound) + continue; +-- +2.53.0 + diff --git a/queue-7.0/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch b/queue-7.0/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch new file mode 100644 index 0000000000..a7a7700407 --- /dev/null +++ b/queue-7.0/ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch @@ -0,0 +1,47 @@ +From 165f5786a691227b7d6197905485bc0395eab4ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:31:30 +0800 +Subject: ipv6: fix possible infinite loop in rt6_fill_node() + +From: Jiayuan Chen + +[ Upstream commit 9f72412bcf60144f252b0d6205106abf14344abc ] + +Sashiko reported this issue [1]. Apply the same fix as +commit f8d8ce1b515a ("ipv6: fix possible infinite loop in fib6_info_uses_dev()"). + +Writers holding tb6_lock can list_del_rcu(&rt->fib6_siblings) +without waiting for RCU readers; rt->fib6_siblings.next then still +points into the old ring and this softirq-side walker never reaches +&rt->fib6_siblings, causing a CPU stall. fib6_del_route() always +WRITE_ONCE()s rt->fib6_nsiblings to 0 before list_del_rcu(), so an +inside-loop check is a reliable detach signal. + +[1] https://sashiko.dev/#/patchset/20260526020227.4857-1-jiayuan.chen%40linux.dev + +Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn") +Signed-off-by: Jiayuan Chen +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260527053133.180695-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index cb521700cee7ed..398e873072bbfb 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -5891,6 +5891,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, + + goto nla_put_failure; + } ++ if (!READ_ONCE(rt->fib6_nsiblings)) ++ break; + } + + rcu_read_unlock(); +-- +2.53.0 + diff --git a/queue-7.0/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch b/queue-7.0/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch new file mode 100644 index 0000000000..31f76231b2 --- /dev/null +++ b/queue-7.0/ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch @@ -0,0 +1,62 @@ +From 13865a97cf43376e9c365cc3602035cc0d13b553 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 21:10:31 +0530 +Subject: ipv6: rpl: fix hdrlen overflow in ipv6_rpl_srh_decompress() + +From: Rahul Chandelkar + +[ Upstream commit 9d5e7a46a9f6d8f503b41bfefef70659845f1679 ] + +ipv6_rpl_srh_decompress() computes: + + outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3); + +hdrlen is __u8. For n >= 127 the result exceeds 255 and silently +truncates. With n=127 (cmpri=15, cmpre=15, pad=0, hdrlen=16): + + (128 * 16) >> 3 = 256, truncated to 0 as __u8 + +The caller in ipv6_rpl_srh_rcv() then places the compressed header +at buf + ((ohdr->hdrlen + 1) << 3). With hdrlen=0 this is buf + 8, +but the decompressed region occupies buf[0..2055] (8-byte header +plus 128 full addresses). The compressed header overlaps the +decompressed data, and ipv6_rpl_srh_compress() writes into this +overlap, corrupting the routing header of the forwarded packet. + +The existing guard at exthdrs.c:546 checks (n + 1) > 255, which +prevents n+1 from overflowing unsigned char (the segments_left +field), but does not prevent the computed hdrlen from overflowing +__u8. n=127 passes because 128 <= 255, yet hdrlen=256 does not +fit. + +Tighten the bound to (n + 1) > 127. This caps n at 126, giving +hdrlen = (127 * 16) >> 3 = 254, which fits in __u8. The compressed +header then lands at buf + ((254 + 1) << 3) = buf + 2040, exactly +past the decompressed region (buf[0..2039]). No overlap. 127 +segments is well beyond any realistic RPL deployment. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Signed-off-by: Rahul Chandelkar +Link: https://patch.msgid.link/20260525154031.2290876-1-rc@rexion.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/exthdrs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index cf90f933ca1ada..3757317e8151e0 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -544,7 +544,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + * unsigned char which is segments_left field. Should not be + * higher than that. + */ +- if (r || (n + 1) > 255) { ++ if (r || (n + 1) > 127) { + kfree_skb(skb); + return -1; + } +-- +2.53.0 + diff --git a/queue-7.0/kernel-fork-validate-exit_signal-in-kernel_clone.patch b/queue-7.0/kernel-fork-validate-exit_signal-in-kernel_clone.patch new file mode 100644 index 0000000000..0e037b6d42 --- /dev/null +++ b/queue-7.0/kernel-fork-validate-exit_signal-in-kernel_clone.patch @@ -0,0 +1,116 @@ +From 8e2042f9ba5741e337370a16551934b0f431b7b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 20:49:56 +0530 +Subject: kernel/fork: validate exit_signal in kernel_clone() + +From: Deepanshu Kartikey + +[ Upstream commit 09e7827e785729f391c8d46dc71becce70d296ab ] + +When a child process exits, it sends exit_signal to its parent via +do_notify_parent(). The clone() syscall constructs exit_signal as: + +(lower_32_bits(clone_flags) & CSIGNAL) + +CSIGNAL is 0xff, so values in the range 65-255 are possible. However, +valid_signal() only accepts signals up to _NSIG (64 on x86_64). A +non-zero non-valid exit_signal acts the same as exit_signal == 0: the +parent process is not signaled when the child terminates. + +The syzkaller reproducer triggers this by calling clone() with flags=0x80, +resulting in exit_signal = (0x80 & CSIGNAL) = 128, which exceeds _NSIG and +is not a valid signal. + +The v1 of this patch added the check only in the clone() syscall handler, +which is incomplete. kernel_clone() has other callers such as +sys_ia32_clone() which would remain unprotected. Move the check to +kernel_clone() to cover all callers. + +Since the valid_signal() check is now in kernel_clone() and covers all +callers including clone3(), the same check in copy_clone_args_from_user() +becomes redundant and is removed. The higher 32bits check for clone3() is +kept as it is clone3() specific. + +Note that this is a user-visible change: previously, passing an invalid +exit_signal to clone() was silently accepted. The man page for clone() +does not document any defined behavior for invalid exit_signal values, so +rejecting them with -EINVAL is the correct behavior. It is unlikely that +any sane application relies on passing an invalid exit_signal. + +[oleg@redhat.com: the comment above kernel_clone() should be updated] + Link: https://lore.kernel.org/abwvgU17W8wuW2-J@redhat.com +Link: https://lore.kernel.org/20260316151956.563558-1-kartikey406@gmail.com +Fixes: 3f2c788a1314 ("fork: prevent accidental access to clone3 features") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Oleg Nesterov +Reported-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=bbe6b99feefc3a0842de +Tested-by: syzbot+bbe6b99feefc3a0842de@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20260307064202.353405-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20260316104536.558108-1-kartikey406@gmail.com/T/ [v2] +Acked-by: Oleg Nesterov +Acked-by: Michal Hocko +Cc: Ben Segall +Cc: Christian Brauner +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Cc: Tetsuo Handa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 73622ad0665a07..bcde8e2843fb97 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -2606,8 +2606,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node) + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. +- * +- * args->exit_signal is expected to be checked for sanity by the caller. + */ + pid_t kernel_clone(struct kernel_clone_args *args) + { +@@ -2632,6 +2630,9 @@ pid_t kernel_clone(struct kernel_clone_args *args) + (args->pidfd == args->parent_tid)) + return -EINVAL; + ++ if (!valid_signal(args->exit_signal)) ++ return -EINVAL; ++ + /* + * Determine whether and which event to report to ptracer. When + * called from kernel_thread or CLONE_UNTRACED is explicitly +@@ -2830,11 +2831,9 @@ static noinline int copy_clone_args_from_user(struct kernel_clone_args *kargs, + return -EINVAL; + + /* +- * Verify that higher 32bits of exit_signal are unset and that +- * it is a valid signal ++ * Verify that higher 32bits of exit_signal are unset + */ +- if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) || +- !valid_signal(args.exit_signal))) ++ if (unlikely(args.exit_signal & ~((u64)CSIGNAL))) + return -EINVAL; + + if ((args.flags & CLONE_INTO_CGROUP) && +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch b/queue-7.0/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch new file mode 100644 index 0000000000..b78794a596 --- /dev/null +++ b/queue-7.0/ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch @@ -0,0 +1,69 @@ +From 3cf7fd18201f3829d9b400331cd5dd626d1e0142 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 22:07:16 +0900 +Subject: ksmbd: fix FSCTL permission bypass by adding a permission check for + FSCTL_SET_SPARSE + +From: Sean Shen + +[ Upstream commit cc57232cae23c0df91b4a59d0f519141ce9b5b02 ] + +FSCTL_SET_SPARSE in fsctl_set_sparse() modifies the file's sparse +attribute and saves it through xattr without any permission checks. + +This exposes two issues: + +1) A client on a read-only share can change the sparse attribute + on files it opened, even though the share is read-only. + Other FSCTL write operations already check + test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE), + but FSCTL_SET_SPARSE does not. + +2) Even on writable shares, clients without FILE_WRITE_DATA or + FILE_WRITE_ATTRIBUTES access should not modify the sparse + attribute. Similar handle-level checks exist in other functions + but are missing here. + +Add both share-level writable check and per-handle access check. +Use goto out on error to avoid leaking file references. + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: Namjae Jeon +Cc: Sergey Senozhatsky +Cc: Steve French +Signed-off-by: Sean Shen +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 3a8a739c025fb7..64ef1b8b37f8ad 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -8202,9 +8202,20 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id, + int ret = 0; + __le32 old_fattr; + ++ if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { ++ ksmbd_debug(SMB, "User does not have write permission\n"); ++ return -EACCES; ++ } ++ + fp = ksmbd_lookup_fd_fast(work, id); + if (!fp) + return -ENOENT; ++ ++ if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_WRITE_ATTRIBUTES_LE))) { ++ ret = -EACCES; ++ goto out; ++ } ++ + idmap = file_mnt_idmap(fp->filp); + + old_fattr = fp->f_ci->m_fattr; +-- +2.53.0 + diff --git a/queue-7.0/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch b/queue-7.0/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch new file mode 100644 index 0000000000..53067abd82 --- /dev/null +++ b/queue-7.0/kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch @@ -0,0 +1,110 @@ +From 24af084aa70b0ebc3ba5365f20e1b0815dd3fbb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 10:48:54 +0200 +Subject: kunit: fix use-after-free in debugfs when using kunit.filter + +From: Florian Schmaus + +[ Upstream commit fb6988b83b4cafe8db63999c1ddff1b7c66d2ff5 ] + +When the kernel is booted with a kunit filter (e.g., +kunit.filter="speed!=slow"), the kunit executor dynamically allocates +copies of the filtered test suites using kmalloc/kmemdup. + +During the initial boot execution, kunit_debugfs_create_suite() creates +debugfs files (such as /sys/kernel/debug/kunit//run) and +permanently stores a pointer to the dynamically allocated suite in the +inode's i_private field. + +Previously, the executor freed this dynamically allocated suite_set +immediately after executing the boot-time tests. Because the debugfs +nodes were not destroyed, any subsequent interaction with the debugfs +`run` file from userspace triggered a use-after-free (UAF). On systems +with architectural capabilities, like CHERI RISC-V, this resulted in +an immediate fatal hardware exception due to the invalidation of the +capability tags on the reclaimed memory. On other architectures, it +resulted in silent memory corruption. + +Fix this UAF by properly coupling the lifetime of the filtered suite +memory allocation to the lifetime of the kunit subsystem and its +associated VFS nodes. Ownership of the boot-time suite_set is now +transferred to a global tracker ('kunit_boot_suites'), and the memory +is cleanly released in kunit_exit() during module teardown. + +Link: https://lore.kernel.org/r/20260507084854.233984-1-florian.schmaus@codasip.com +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: Florian Schmaus +Reviewed-by: Martin Kaiser +Reviewed-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + include/kunit/test.h | 1 + + lib/kunit/executor.c | 19 ++++++++++++++++--- + lib/kunit/test.c | 1 + + 3 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/include/kunit/test.h b/include/kunit/test.h +index 9cd1594ab697d9..ce0573e196ce75 100644 +--- a/include/kunit/test.h ++++ b/include/kunit/test.h +@@ -613,6 +613,7 @@ unsigned long kunit_vm_mmap(struct kunit *test, struct file *file, + unsigned long offset); + + void kunit_cleanup(struct kunit *test); ++void kunit_free_boot_suites(void); + + void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...); + +diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c +index 1fef217de11db1..b0f8a41d61d367 100644 +--- a/lib/kunit/executor.c ++++ b/lib/kunit/executor.c +@@ -15,6 +15,16 @@ extern struct kunit_suite * const __kunit_suites_end[]; + extern struct kunit_suite * const __kunit_init_suites_start[]; + extern struct kunit_suite * const __kunit_init_suites_end[]; + ++static struct kunit_suite_set kunit_boot_suites; ++ ++void kunit_free_boot_suites(void) ++{ ++ if (kunit_boot_suites.start) { ++ kunit_free_suite_set(kunit_boot_suites); ++ kunit_boot_suites = (struct kunit_suite_set){ NULL, NULL }; ++ } ++} ++ + static char *action_param; + + module_param_named(action, action_param, charp, 0400); +@@ -411,9 +421,12 @@ int kunit_run_all_tests(void) + pr_err("kunit executor: unknown action '%s'\n", action_param); + + free_out: +- if (filter_glob_param || filter_param) +- kunit_free_suite_set(suite_set); +- else if (init_num_suites > 0) ++ if (filter_glob_param || filter_param) { ++ if (err) ++ kunit_free_suite_set(suite_set); ++ else ++ kunit_boot_suites = suite_set; ++ } else if (init_num_suites > 0) + /* Don't use kunit_free_suite_set because suites aren't individually allocated */ + kfree(suite_set.start); + +diff --git a/lib/kunit/test.c b/lib/kunit/test.c +index 41e1c89799b6a7..99773e000e1b77 100644 +--- a/lib/kunit/test.c ++++ b/lib/kunit/test.c +@@ -1075,6 +1075,7 @@ static void __exit kunit_exit(void) + kunit_bus_shutdown(); + + kunit_debugfs_cleanup(); ++ kunit_free_boot_suites(); + } + module_exit(kunit_exit); + +-- +2.53.0 + diff --git a/queue-7.0/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch b/queue-7.0/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch new file mode 100644 index 0000000000..87076cad07 --- /dev/null +++ b/queue-7.0/net-avoid-checksumming-unreadable-skb-tail-on-trim.patch @@ -0,0 +1,102 @@ +From a7143d3ec18f53d308b13cd88e690526a14c8e59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 14:06:40 +0200 +Subject: net: Avoid checksumming unreadable skb tail on trim +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Björn Töpel + +[ Upstream commit 2e357f002c61fd76fd8f12468744a06a5ec48eaa ] + +pskb_trim_rcsum_slow() keeps CHECKSUM_COMPLETE valid by subtracting +the checksum of the bytes removed from the skb tail. That assumes the +removed bytes can be read. + +io_uring zcrx skbs may contain unreadable net_iov frags. With fbnic +header/data split, small TCP/IPv4 packets can carry Ethernet padding +in such a frag. ip_rcv_core() trims the skb to iph->tot_len before TCP +sees it, and the CHECKSUM_COMPLETE adjustment then calls +skb_checksum() on the padding. + +This is exposed by IPv4 because small TCP/IPv4 frames can be shorter +than the Ethernet minimum payload. TCP/IPv6 frames are large enough in +the normal zcrx path, so they do not hit the same padding trim. + +Keep the existing checksum adjustment for readable skbs. If the +remaining packet is fully linear, drop CHECKSUM_COMPLETE and let the +stack validate the packet after trimming. If unreadable payload would +remain, fail the trim; the checksum cannot be adjusted without reading +the trimmed tail. + +Also clear skb->unreadable when trimming removes all frags. + +Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags") +Signed-off-by: Björn Töpel +Reviewed-by: Breno Leitao +Link: https://patch.msgid.link/20260522120643.242974-1-bjorn@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 31 +++++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 28bd8304796d7a..13af6f35428d52 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -2811,6 +2811,8 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) + skb->data_len = 0; + skb_set_tail_pointer(skb, len); + } ++ if (!skb_shinfo(skb)->nr_frags && !skb_has_frag_list(skb)) ++ skb->unreadable = 0; + + if (!skb->sk || skb->destructor == sock_edemux) + skb_condense(skb); +@@ -2818,16 +2820,37 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) + } + EXPORT_SYMBOL(___pskb_trim); + ++static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len) ++{ ++ int delta = skb->len - len; ++ ++ if (skb_frags_readable(skb)) { ++ skb->csum = csum_block_sub(skb->csum, ++ skb_checksum(skb, len, delta, 0), ++ len); ++ return 0; ++ } ++ ++ if (len > skb_headlen(skb)) ++ return -EFAULT; ++ ++ /* The trimmed bytes are unreadable, but the remaining packet can be ++ * checksummed by software after trimming. ++ */ ++ skb->ip_summed = CHECKSUM_NONE; ++ return 0; ++} ++ + /* Note : use pskb_trim_rcsum() instead of calling this directly + */ + int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len) + { + if (skb->ip_summed == CHECKSUM_COMPLETE) { +- int delta = skb->len - len; ++ int err; + +- skb->csum = csum_block_sub(skb->csum, +- skb_checksum(skb, len, delta, 0), +- len); ++ err = pskb_trim_rcsum_complete(skb, len); ++ if (err) ++ return err; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + int hdlen = (len > skb_headlen(skb)) ? skb_headlen(skb) : len; + int offset = skb_checksum_start_offset(skb) + skb->csum_offset; +-- +2.53.0 + diff --git a/queue-7.0/net-handshake-drain-pending-requests-at-net-namespac.patch b/queue-7.0/net-handshake-drain-pending-requests-at-net-namespac.patch new file mode 100644 index 0000000000..93b148c46a --- /dev/null +++ b/queue-7.0/net-handshake-drain-pending-requests-at-net-namespac.patch @@ -0,0 +1,112 @@ +From 0931ecae42ad61cc1eddcb4ad81df6fa680a1311 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:22 -0400 +Subject: net/handshake: Drain pending requests at net namespace exit + +From: Chuck Lever + +[ Upstream commit ea5fe6a73ca57e5150b8a38b341aef2636eb72f0 ] + +The arguments to list_splice_init() in handshake_net_exit() are +reversed. The call moves the local empty "requests" list onto +hn->hn_requests, leaving the local list empty, so the subsequent +drain loop runs zero iterations. Pending handshake requests that +had not yet been accepted are not torn down when the net namespace +is destroyed; each one keeps a reference on a socket file and on +the handshake_req allocation. + +Pass the source and destination in the documented order +(list_splice_init(list, head) moves list onto head) so the pending +list is transferred to the local scratch list and drained through +handshake_complete(). + +Fixing the splice direction exposes a list-corruption race. After +the splice each req->hr_list still has non-empty link pointers, +threading the stack-local scratch list rather than hn_requests. +A concurrent handshake_req_cancel() -- for example, from sunrpc's +TLS timeout on a kernel socket whose netns reference was not +taken -- finds the request through the rhashtable, calls +remove_pending(), and sees !list_empty(&req->hr_list). +__remove_pending_locked() then list_del_init()s an entry off the +scratch list while the drain iterates, corrupting it. The same +call arriving after the drain loop has run list_del() on an +entry hits LIST_POISON instead. + +Have remove_pending() check HANDSHAKE_F_NET_DRAINING under +hn_lock and report not-found when drain is in progress. The +drain has already taken ownership; handshake_complete()'s existing +test_and_set on HANDSHAKE_F_REQ_COMPLETED still arbitrates +between drain and cancel for who calls the consumer's hp_done. Use +list_del_init() rather than list_del() in the drain so req->hr_list +does not carry LIST_POISON after drain releases the entry. + +The DRAINING guard in remove_pending() makes cancel return false, +but cancel still falls through to test_and_set_bit on +HANDSHAKE_F_REQ_COMPLETED and drops the request's hr_file reference. +Without another pin, if that is the last reference, sk_destruct frees +the request while it is still linked on the drain loop's local list. +Pin each request's hr_file under hn_lock before releasing the list, +and drop that drain pin after the loop finishes with the request. + +Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-8-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/handshake/netlink.c | 10 ++++++++-- + net/handshake/request.c | 5 ++++- + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 21d6cbd52fcdb6..3fd4fef9bab1a4 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -201,13 +201,19 @@ static void __net_exit handshake_net_exit(struct net *net) + */ + spin_lock_bh(&hn->hn_lock); + set_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags); +- list_splice_init(&requests, &hn->hn_requests); ++ list_splice_init(&hn->hn_requests, &requests); ++ list_for_each_entry(req, &requests, hr_list) ++ get_file(req->hr_file); + spin_unlock_bh(&hn->hn_lock); + + while (!list_empty(&requests)) { ++ struct file *file; ++ + req = list_first_entry(&requests, struct handshake_req, hr_list); +- list_del(&req->hr_list); ++ file = req->hr_file; ++ list_del_init(&req->hr_list); + handshake_complete(req, -ETIMEDOUT, NULL); ++ fput(file); + } + } + +diff --git a/net/handshake/request.c b/net/handshake/request.c +index e2d7ee7ce6e0e0..2f1ab6eb9538c5 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -163,13 +163,16 @@ static void __remove_pending_locked(struct handshake_net *hn, + * otherwise %false. + * + * If @req was on a pending list, it has not yet been accepted. ++ * Returns %false when the net namespace is draining; the drain ++ * loop has taken ownership of the pending list. + */ + static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) + { + bool ret = false; + + spin_lock_bh(&hn->hn_lock); +- if (!list_empty(&req->hr_list)) { ++ if (!test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags) && ++ !list_empty(&req->hr_list)) { + __remove_pending_locked(hn, req); + ret = true; + } +-- +2.53.0 + diff --git a/queue-7.0/net-handshake-hand-off-the-pinned-file-reference-to-.patch b/queue-7.0/net-handshake-hand-off-the-pinned-file-reference-to-.patch new file mode 100644 index 0000000000..7423d3cb0a --- /dev/null +++ b/queue-7.0/net-handshake-hand-off-the-pinned-file-reference-to-.patch @@ -0,0 +1,151 @@ +From 3ad739a55523fe3e66ddedbf7bf5782ecc3ccb0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:19 -0400 +Subject: net/handshake: hand off the pinned file reference to accept_doit + +From: Chuck Lever + +[ Upstream commit f4251190e58b209999c1ba9e6d2976136a1be055 ] + +handshake_req_next() removes the request from the per-net +pending list and drops hn_lock before handshake_nl_accept_doit() +reads req->hr_sk->sk_socket and dereferences sock->file (once in +FD_PREPARE() and again in get_file()). In that window a +consumer running tls_handshake_cancel() followed by sockfd_put() +(svc_sock_free) or __fput_sync() (xs_reset_transport) releases +sock->file. sock_release() then runs sock_orphan(), zeroing +sk_socket, and frees the struct socket. The accept-side code +either reads NULL through sk_socket or chases freed memory. + +The submit-side sock_hold() does not prevent this. sk_refcnt +protects struct sock, but struct socket and sock->file are +independently refcounted via the file descriptor the consumer +owns. Pinning sk leaves sock and sock->file unprotected. + +Retarget the accept-side dereferences at req->hr_file, which was +pinned at submit time, instead of req->hr_sk->sk_socket->file. +Pinning on its own is not sufficient: a consumer that cancels +between handshake_req_next() returning and accept_doit reaching +FD_PREPARE() takes the !remove_pending() branch in +handshake_req_cancel() and drops hr_file before the accept side +takes its own reference. Hand off an additional file reference +inside handshake_req_next(), under hn_lock, so the accept side +operates on a reference that no concurrent handshake_req_cancel() +can revoke. FD_PREPARE() consumes that handed-off reference, +either by transferring it to the new fd in fd_publish() or by +dropping it in the cleanup destructor on error; the explicit +get_file() that previously balanced FD_PREPARE() is therefore +redundant and goes away. + +Update handshake_req_cancel_test2 and _test3 to simulate the +FD_PREPARE() consumption with an fput() so the kunit file-count +assertions stay balanced. + +Reported-by: Chris Mason +Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-5-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/handshake/handshake-test.c | 8 ++++++++ + net/handshake/netlink.c | 7 ++----- + net/handshake/request.c | 18 ++++++++++++++++++ + 3 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c +index df3948e807a0fd..9cc7a95f41207e 100644 +--- a/net/handshake/handshake-test.c ++++ b/net/handshake/handshake-test.c +@@ -375,6 +375,10 @@ static void handshake_req_cancel_test2(struct kunit *test) + /* Pretend to accept this request */ + next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD); + KUNIT_ASSERT_PTR_EQ(test, req, next); ++ /* Simulate FD_PREPARE() consuming the file reference handed ++ * off by handshake_req_next(); see handshake_nl_accept_doit(). ++ */ ++ fput(filp); + + /* Act */ + result = handshake_req_cancel(sock->sk); +@@ -417,6 +421,10 @@ static void handshake_req_cancel_test3(struct kunit *test) + /* Pretend to accept this request */ + next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD); + KUNIT_ASSERT_PTR_EQ(test, req, next); ++ /* Simulate FD_PREPARE() consuming the file reference handed ++ * off by handshake_req_next(); see handshake_nl_accept_doit(). ++ */ ++ fput(filp); + + /* Pretend to complete this request */ + handshake_complete(next, -ETIMEDOUT, NULL); +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 039344979de934..561dfa6fa7711a 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -92,7 +92,6 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info) + struct net *net = sock_net(skb->sk); + struct handshake_net *hn = handshake_pernet(net); + struct handshake_req *req = NULL; +- struct socket *sock; + int class, err; + + err = -EOPNOTSUPP; +@@ -107,15 +106,13 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info) + err = -EAGAIN; + req = handshake_req_next(hn, class); + if (req) { +- sock = req->hr_sk->sk_socket; +- +- FD_PREPARE(fdf, O_CLOEXEC, sock->file); ++ FD_PREPARE(fdf, O_CLOEXEC, req->hr_file); + if (fdf.err) { ++ fput(req->hr_file); /* drop ref from handshake_req_next() */ + err = fdf.err; + goto out_complete; + } + +- get_file(sock->file); /* FD_PREPARE() consumes a reference. */ + err = req->hr_proto->hp_accept(req, info, fd_prepare_fd(fdf)); + if (err) + goto out_complete; /* Automatic cleanup handles fput */ +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 97f9f823994994..22e4b414ad1d7f 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -177,6 +177,17 @@ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) + return ret; + } + ++/** ++ * handshake_req_next - Return the next queued handshake request ++ * @hn: per-net handshake state ++ * @class: handler class to match ++ * ++ * On a non-NULL return, the caller owns an extra reference ++ * on @req->hr_file. FD_PREPARE() consumes it on success; on ++ * the FD_PREPARE() failure path the caller must fput() it. ++ * ++ * Return: pointer to a removed handshake_req, or NULL. ++ */ + struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + { + struct handshake_req *req, *pos; +@@ -187,6 +198,13 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + if (pos->hr_proto->hp_handler_class != class) + continue; + __remove_pending_locked(hn, pos); ++ /* Hand off a file reference to the accept side under ++ * hn_lock. A concurrent handshake_req_cancel() can drop ++ * hr_file before accept reaches FD_PREPARE(); this extra ++ * reference keeps the file alive until FD_PREPARE() takes ++ * ownership. ++ */ ++ get_file(pos->hr_file); + req = pos; + break; + } +-- +2.53.0 + diff --git a/queue-7.0/net-handshake-pass-negative-errno-through-handshake_.patch b/queue-7.0/net-handshake-pass-negative-errno-through-handshake_.patch new file mode 100644 index 0000000000..f4b3d33cbc --- /dev/null +++ b/queue-7.0/net-handshake-pass-negative-errno-through-handshake_.patch @@ -0,0 +1,212 @@ +From 72d8327f969d3d48e94f6823e951024e4ae84577 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:17 -0400 +Subject: net/handshake: Pass negative errno through handshake_complete() + +From: Chuck Lever + +[ Upstream commit 6b22d433aa13f68e3cd9534ca9a5f4277bfa01c2 ] + +handshake_complete() declares status as unsigned int and +tls_handshake_done() negates that value (-status) before handing +it to the TLS consumer. Consumers match on negative errno +constants -- xs_tls_handshake_done() has + + switch (status) { + case 0: + case -EACCES: + case -ETIMEDOUT: + lower_transport->xprt_err = status; + break; + default: + lower_transport->xprt_err = -EACCES; + } + +so the API as designed expects callers to pass positive errno +values that the tlshd shim then negates. + +Three internal callers in handshake_nl_accept_doit(), the +net-exit drain, and a kunit test follow kernel convention and +pass negative errnos -- -EIO, -ETIMEDOUT, -ETIMEDOUT. The +implicit conversion to unsigned int turns -ETIMEDOUT into +0xFFFFFF92; the subsequent -status in tls_handshake_done() +wraps back to 110, the consumer's switch falls through, and +the xprt reports -EACCES on what should be -ETIMEDOUT or -EIO. + +Fix the API rather than the call sites. The natural kernel +convention is negative errno in, negative errno out. Change +handshake_complete() and hp_done to take int status, drop the +negation in tls_handshake_done(), and negate once in +handshake_nl_done_doit() where status arrives from the wire +as an unsigned netlink attribute. The three internal callers +were already correct under that convention and need no change. + +At the same wire boundary, declare MAX_ERRNO as the netlink +policy upper bound for HANDSHAKE_A_DONE_STATUS. Attribute +validation rejects out-of-range values before +handshake_nl_done_doit() runs, and negating a bounded u32 there +stays within int range -- closing the UBSAN-visible signed- +integer overflow that an unconstrained u32 would invoke. + +Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-3-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + Documentation/netlink/specs/handshake.yaml | 8 ++++++++ + net/handshake/genl.c | 3 ++- + net/handshake/genl.h | 1 + + net/handshake/handshake-test.c | 2 +- + net/handshake/handshake.h | 4 ++-- + net/handshake/netlink.c | 2 +- + net/handshake/request.c | 2 +- + net/handshake/tlshd.c | 4 ++-- + 8 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml +index 95c3fade7a8d7b..1024297b38513a 100644 +--- a/Documentation/netlink/specs/handshake.yaml ++++ b/Documentation/netlink/specs/handshake.yaml +@@ -12,6 +12,12 @@ protocol: genetlink + doc: Netlink protocol to request a transport layer security handshake. + + definitions: ++ - ++ type: const ++ name: max-errno ++ value: 4095 ++ header: linux/err.h ++ scope: kernel + - + type: enum + name: handler-class +@@ -80,6 +86,8 @@ attribute-sets: + - + name: status + type: u32 ++ checks: ++ max: max-errno + - + name: sockfd + type: s32 +diff --git a/net/handshake/genl.c b/net/handshake/genl.c +index 8706126094915d..4b20cd9cdd0e09 100644 +--- a/net/handshake/genl.c ++++ b/net/handshake/genl.c +@@ -10,6 +10,7 @@ + #include "genl.h" + + #include ++#include + + /* HANDSHAKE_CMD_ACCEPT - do */ + static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HANDLER_CLASS + 1] = { +@@ -18,7 +19,7 @@ static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HAN + + /* HANDSHAKE_CMD_DONE - do */ + static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_REMOTE_AUTH + 1] = { +- [HANDSHAKE_A_DONE_STATUS] = { .type = NLA_U32, }, ++ [HANDSHAKE_A_DONE_STATUS] = NLA_POLICY_MAX(NLA_U32, MAX_ERRNO), + [HANDSHAKE_A_DONE_SOCKFD] = { .type = NLA_S32, }, + [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .type = NLA_U32, }, + }; +diff --git a/net/handshake/genl.h b/net/handshake/genl.h +index 8d3e18672dafcf..46b65f131669a6 100644 +--- a/net/handshake/genl.h ++++ b/net/handshake/genl.h +@@ -11,6 +11,7 @@ + #include + + #include ++#include + + int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info); + int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info); +diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c +index 55442b2f518afb..df3948e807a0fd 100644 +--- a/net/handshake/handshake-test.c ++++ b/net/handshake/handshake-test.c +@@ -25,7 +25,7 @@ static int test_accept_func(struct handshake_req *req, struct genl_info *info, + return 0; + } + +-static void test_done_func(struct handshake_req *req, unsigned int status, ++static void test_done_func(struct handshake_req *req, int status, + struct genl_info *info) + { + } +diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h +index a48163765a7a1d..2289b0e274f40a 100644 +--- a/net/handshake/handshake.h ++++ b/net/handshake/handshake.h +@@ -57,7 +57,7 @@ struct handshake_proto { + int (*hp_accept)(struct handshake_req *req, + struct genl_info *info, int fd); + void (*hp_done)(struct handshake_req *req, +- unsigned int status, ++ int status, + struct genl_info *info); + void (*hp_destroy)(struct handshake_req *req); + }; +@@ -86,7 +86,7 @@ struct handshake_req *handshake_req_hash_lookup(struct sock *sk); + struct handshake_req *handshake_req_next(struct handshake_net *hn, int class); + int handshake_req_submit(struct socket *sock, struct handshake_req *req, + gfp_t flags); +-void handshake_complete(struct handshake_req *req, unsigned int status, ++void handshake_complete(struct handshake_req *req, int status, + struct genl_info *info); + bool handshake_req_cancel(struct sock *sk); + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 97114ec8027a5a..039344979de934 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -160,7 +160,7 @@ int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info) + + status = -EIO; + if (info->attrs[HANDSHAKE_A_DONE_STATUS]) +- status = nla_get_u32(info->attrs[HANDSHAKE_A_DONE_STATUS]); ++ status = -(int)nla_get_u32(info->attrs[HANDSHAKE_A_DONE_STATUS]); + + handshake_complete(req, status, info); + sockfd_put(sock); +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 5d4a17f902d201..97f9f823994994 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -284,7 +284,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + } + EXPORT_SYMBOL(handshake_req_submit); + +-void handshake_complete(struct handshake_req *req, unsigned int status, ++void handshake_complete(struct handshake_req *req, int status, + struct genl_info *info) + { + struct sock *sk = req->hr_sk; +diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c +index af294c6cc71731..7567150c2a4f95 100644 +--- a/net/handshake/tlshd.c ++++ b/net/handshake/tlshd.c +@@ -93,7 +93,7 @@ static void tls_handshake_remote_peerids(struct tls_handshake_req *treq, + * + */ + static void tls_handshake_done(struct handshake_req *req, +- unsigned int status, struct genl_info *info) ++ int status, struct genl_info *info) + { + struct tls_handshake_req *treq = handshake_req_private(req); + +@@ -104,7 +104,7 @@ static void tls_handshake_done(struct handshake_req *req, + if (!status) + set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags); + +- treq->th_consumer_done(treq->th_consumer_data, -status, ++ treq->th_consumer_done(treq->th_consumer_data, status, + treq->th_peerid[0]); + } + +-- +2.53.0 + diff --git a/queue-7.0/net-handshake-take-a-long-lived-file-reference-at-su.patch b/queue-7.0/net-handshake-take-a-long-lived-file-reference-at-su.patch new file mode 100644 index 0000000000..e028b3c462 --- /dev/null +++ b/queue-7.0/net-handshake-take-a-long-lived-file-reference-at-su.patch @@ -0,0 +1,187 @@ +From 86969bc5abab447646c757cfd5030956913cbd9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:18 -0400 +Subject: net/handshake: Take a long-lived file reference at submit + +From: Chuck Lever + +[ Upstream commit 09dba37eee70d0596e26645015f1aa95a9848e9d ] + +handshake_nl_accept_doit() needs the file pointer backing +req->hr_sk->sk_socket to survive the window between +handshake_req_next() and the subsequent FD_PREPARE() and get_file(). +The submit-side sock_hold() does not provide that. sk_refcnt keeps +struct sock alive, but struct socket is owned by sock->file: when +the consumer fputs the last file reference, sock_release() tears +the socket down regardless of any sock_hold. + +Add an hr_file pointer to struct handshake_req and acquire an +explicit reference on sock->file during handshake_req_submit(). +handshake_complete() and handshake_req_cancel() release the +reference on the completion-bit-winning path. + +The submit error path must also release the file reference, but +after rhashtable insertion a concurrent handshake_req_cancel() can +discover the request and race the error path. Gate the error-path +cleanup -- sk_destruct restoration, fput, and request destruction +-- with test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED), the same +serialization handshake_complete() and handshake_req_cancel() +already use. When cancel has already claimed ownership, the submit +error path returns without touching the request; socket teardown +handles final destruction. + +The accept-side dereferences are not yet retargeted; that change +comes in the next patch. + +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-4-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Stable-dep-of: ea5fe6a73ca5 ("net/handshake: Drain pending requests at net namespace exit") +Signed-off-by: Sasha Levin +--- + net/handshake/handshake.h | 2 ++ + net/handshake/netlink.c | 6 ------ + net/handshake/request.c | 42 ++++++++++++++++++++++++++++++++------- + 3 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h +index 2289b0e274f40a..da61cadd1ad3e7 100644 +--- a/net/handshake/handshake.h ++++ b/net/handshake/handshake.h +@@ -24,6 +24,7 @@ enum hn_flags_bits { + HANDSHAKE_F_NET_DRAINING, + }; + ++struct file; + struct handshake_proto; + + /* One handshake request */ +@@ -32,6 +33,7 @@ struct handshake_req { + struct rhash_head hr_rhash; + unsigned long hr_flags; + const struct handshake_proto *hr_proto; ++ struct file *hr_file; + struct sock *hr_sk; + void (*hr_odestruct)(struct sock *sk); + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index 561dfa6fa7711a..21d6cbd52fcdb6 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -207,12 +207,6 @@ static void __net_exit handshake_net_exit(struct net *net) + while (!list_empty(&requests)) { + req = list_first_entry(&requests, struct handshake_req, hr_list); + list_del(&req->hr_list); +- +- /* +- * Requests on this list have not yet been +- * accepted, so they do not have an fd to put. +- */ +- + handshake_complete(req, -ETIMEDOUT, NULL); + } + } +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 22e4b414ad1d7f..e2d7ee7ce6e0e0 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -233,9 +234,16 @@ EXPORT_SYMBOL_IF_KUNIT(handshake_req_next); + * A zero return value from handshake_req_submit() means that + * exactly one subsequent completion callback is guaranteed. + * +- * A negative return value from handshake_req_submit() means that +- * no completion callback will be done and that @req has been +- * destroyed. ++ * A negative return value from handshake_req_submit() guarantees that ++ * no completion callback will occur and that @req is no longer owned by ++ * the caller. If cancellation wins the completion race after the request ++ * has been published, final destruction is deferred until socket teardown. ++ * ++ * The caller must hold a reference on @sock->file for the duration ++ * of this call. Once the request is published to the accept side, a ++ * concurrent completion or cancellation may release the request's pin on ++ * @sock->file; the caller's reference is what keeps @sock->sk valid until ++ * handshake_req_submit() returns. + */ + int handshake_req_submit(struct socket *sock, struct handshake_req *req, + gfp_t flags) +@@ -254,6 +262,14 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + kfree(req); + return -EINVAL; + } ++ ++ /* ++ * Pin sock->file for the lifetime of the request so the ++ * accept side does not race a consumer that releases the ++ * socket while a handshake is pending. ++ */ ++ req->hr_file = get_file(sock->file); ++ + req->hr_odestruct = req->hr_sk->sk_destruct; + req->hr_sk->sk_destruct = handshake_sk_destruct; + +@@ -285,7 +301,11 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + goto out_err; + } + +- /* Prevent socket release while a handshake request is pending */ ++ /* ++ * Pin struct sock so sk_destruct does not run until the ++ * handshake completion path releases it; struct socket is ++ * held separately via hr_file above. ++ */ + sock_hold(req->hr_sk); + + trace_handshake_submit(net, req, req->hr_sk); +@@ -294,10 +314,13 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + out_unlock: + spin_unlock_bh(&hn->hn_lock); + out_err: +- /* Restore original destructor so socket teardown still runs on failure */ +- req->hr_sk->sk_destruct = req->hr_odestruct; + trace_handshake_submit_err(net, req, req->hr_sk, ret); +- handshake_req_destroy(req); ++ if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { ++ /* Restore original destructor so socket teardown still runs. */ ++ req->hr_sk->sk_destruct = req->hr_odestruct; ++ fput(req->hr_file); ++ handshake_req_destroy(req); ++ } + return ret; + } + EXPORT_SYMBOL(handshake_req_submit); +@@ -309,11 +332,15 @@ void handshake_complete(struct handshake_req *req, int status, + struct net *net = sock_net(sk); + + if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { ++ struct file *file = req->hr_file; ++ + trace_handshake_complete(net, req, sk, status); + req->hr_proto->hp_done(req, status, info); + + /* Handshake request is no longer pending */ + sock_put(sk); ++ ++ fput(file); + } + } + EXPORT_SYMBOL_IF_KUNIT(handshake_complete); +@@ -362,6 +389,7 @@ bool handshake_req_cancel(struct sock *sk) + + /* Handshake request is no longer pending */ + sock_put(sk); ++ fput(req->hr_file); + return true; + } + EXPORT_SYMBOL(handshake_req_cancel); +-- +2.53.0 + diff --git a/queue-7.0/net-handshake-use-spin_lock_bh-for-hn_lock.patch b/queue-7.0/net-handshake-use-spin_lock_bh-for-hn_lock.patch new file mode 100644 index 0000000000..a2d2ddc4cb --- /dev/null +++ b/queue-7.0/net-handshake-use-spin_lock_bh-for-hn_lock.patch @@ -0,0 +1,138 @@ +From 752b199c12287a17ee46b936125afd25c4f1e549 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:15 -0400 +Subject: net/handshake: Use spin_lock_bh for hn_lock + +From: Chuck Lever + +[ Upstream commit cc993e0927ec8bd98ea33377ada03295fcda0f24 ] + +nvmet_tcp_state_change(), a socket callback that runs in BH context, +can reach handshake_req_cancel() via nvmet_tcp_schedule_release_queue() +and tls_handshake_cancel(). handshake_req_cancel() acquires +hn->hn_lock with plain spin_lock(). If a process-context thread on +the same CPU holds hn->hn_lock when a softirq invokes the cancel path, +the lock attempt deadlocks. This is the only caller that invokes +tls_handshake_cancel() from BH context; every other consumer calls it +from process context. + +Deferring the cancel to process context in the NVMe target is not +straightforward: nvmet_tcp_schedule_release_queue() must call +tls_handshake_cancel() atomically with its state transition to +DISCONNECTING. If the cancel were deferred, the handshake completion +callback could fire in the window before the cancel runs, observe the +unexpected state, and return without dropping its kref on the queue. +Reworking that interlock is considerably more invasive than hardening +the handshake lock. Convert all hn->hn_lock acquisitions from +spin_lock/spin_unlock to spin_lock_bh/spin_unlock_bh so the lock is +never taken with softirqs enabled. + +Fixes: 675b453e0241 ("nvmet-tcp: enable TLS handshake upcall") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-1-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/handshake/netlink.c | 4 ++-- + net/handshake/request.c | 14 +++++++------- + net/handshake/tlshd.c | 2 ++ + 3 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c +index b989456fc4c5ff..97114ec8027a5a 100644 +--- a/net/handshake/netlink.c ++++ b/net/handshake/netlink.c +@@ -202,10 +202,10 @@ static void __net_exit handshake_net_exit(struct net *net) + * accepted and are in progress will be destroyed when + * the socket is closed. + */ +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + set_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags); + list_splice_init(&requests, &hn->hn_requests); +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + while (!list_empty(&requests)) { + req = list_first_entry(&requests, struct handshake_req, hr_list); +diff --git a/net/handshake/request.c b/net/handshake/request.c +index 2829adbeb149b0..5d4a17f902d201 100644 +--- a/net/handshake/request.c ++++ b/net/handshake/request.c +@@ -167,12 +167,12 @@ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) + { + bool ret = false; + +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + if (!list_empty(&req->hr_list)) { + __remove_pending_locked(hn, req); + ret = true; + } +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + return ret; + } +@@ -182,7 +182,7 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + struct handshake_req *req, *pos; + + req = NULL; +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + list_for_each_entry(pos, &hn->hn_requests, hr_list) { + if (pos->hr_proto->hp_handler_class != class) + continue; +@@ -190,7 +190,7 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) + req = pos; + break; + } +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + return req; + } +@@ -249,7 +249,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max) + goto out_err; + +- spin_lock(&hn->hn_lock); ++ spin_lock_bh(&hn->hn_lock); + ret = -EOPNOTSUPP; + if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags)) + goto out_unlock; +@@ -258,7 +258,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + goto out_unlock; + if (!__add_pending_locked(hn, req)) + goto out_unlock; +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + + ret = handshake_genl_notify(net, req->hr_proto, flags); + if (ret) { +@@ -274,7 +274,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, + return 0; + + out_unlock: +- spin_unlock(&hn->hn_lock); ++ spin_unlock_bh(&hn->hn_lock); + out_err: + /* Restore original destructor so socket teardown still runs on failure */ + req->hr_sk->sk_destruct = req->hr_odestruct; +diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c +index 8f9532a15f43f9..af294c6cc71731 100644 +--- a/net/handshake/tlshd.c ++++ b/net/handshake/tlshd.c +@@ -425,6 +425,8 @@ EXPORT_SYMBOL(tls_server_hello_psk); + * Request cancellation races with request completion. To determine + * who won, callers examine the return value from this function. + * ++ * Context: May be called from process or softirq context. ++ * + * Return values: + * %true - Uncompleted handshake request was canceled + * %false - Handshake request already completed or not found +-- +2.53.0 + diff --git a/queue-7.0/net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch b/queue-7.0/net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch new file mode 100644 index 0000000000..1eab6be44d --- /dev/null +++ b/queue-7.0/net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch @@ -0,0 +1,45 @@ +From cfeae8c251efba00e11719a40afda675842367c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 22:45:24 +0800 +Subject: net: hibmcge: disable Relaxed Ordering to fix RX packet corruption + +From: Jijie Shao + +[ Upstream commit 463a1271aa26eac992851b9d98cc75bc3cd4a1ed ] + +When SMMU is disabled, the hibmcge driver may receive corrupted packets. +The hardware writes packet data and descriptors to the same page, but +with Relaxed Ordering enabled, PCI write transactions may not be +strictly ordered. This can cause the driver to observe a valid +descriptor before the corresponding packet data is fully written. + +Fix this by clearing PCI_EXP_DEVCTL_RELAX_EN in the PCI bridge control +register to ensure strict write ordering between packet data and +descriptors. + +Fixes: f72e25594061 ("net: hibmcge: Implement rx_poll function to receive packets") +Signed-off-by: Jijie Shao +Link: https://patch.msgid.link/20260525144525.94884-2-shaojijie@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c +index 068da2fd1fea83..f721e98938049e 100644 +--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c ++++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c +@@ -420,6 +420,9 @@ static int hbg_pci_init(struct pci_dev *pdev) + return -ENOMEM; + + pci_set_master(pdev); ++ pcie_capability_clear_word(pdev, PCI_EXP_DEVCTL, ++ PCI_EXP_DEVCTL_RELAX_EN); ++ pci_save_state(pdev); + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/net-hibmcge-move-dma_rmb-after-dma_sync_single_for_c.patch b/queue-7.0/net-hibmcge-move-dma_rmb-after-dma_sync_single_for_c.patch new file mode 100644 index 0000000000..519c6fe5ec --- /dev/null +++ b/queue-7.0/net-hibmcge-move-dma_rmb-after-dma_sync_single_for_c.patch @@ -0,0 +1,51 @@ +From 1eef5b200c5a704fe170ed657d7149524f46cc1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 22:45:25 +0800 +Subject: net: hibmcge: move dma_rmb() after dma_sync_single_for_cpu() in RX + path + +From: Jijie Shao + +[ Upstream commit b545b6ea1802b32436fa97f1d2918718212cc831 ] + +The dma_rmb() barrier was placed before dma_sync_single_for_cpu(), which +is incorrect. DMA sync must complete first to make the buffer accessible +to the CPU, then the rmb barrier ensures subsequent descriptor reads +observe the latest data written by the hardware. + +Reorder the operations so dma_sync_single_for_cpu() is called before +dma_rmb() to guarantee the driver reads consistent data from the DMA +buffer. + +Fixes: f72e25594061 ("net: hibmcge: Implement rx_poll function to receive packets") +Signed-off-by: Jijie Shao +Link: https://patch.msgid.link/20260525144525.94884-3-shaojijie@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c +index a4ea92c31c2fea..0ae31499467693 100644 +--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c ++++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c +@@ -452,12 +452,12 @@ static bool hbg_sync_data_from_hw(struct hbg_priv *priv, + { + struct hbg_rx_desc *rx_desc; + +- /* make sure HW write desc complete */ +- dma_rmb(); +- + dma_sync_single_for_cpu(&priv->pdev->dev, buffer->page_dma, + buffer->page_size, DMA_FROM_DEVICE); + ++ /* make sure HW write desc complete */ ++ dma_rmb(); ++ + rx_desc = (struct hbg_rx_desc *)buffer->page_addr; + return FIELD_GET(HBG_RX_DESC_W2_PKT_LEN_M, rx_desc->word2) != 0; + } +-- +2.53.0 + diff --git a/queue-7.0/net-hsr-fix-potential-oob-access-in-supervision-fram.patch b/queue-7.0/net-hsr-fix-potential-oob-access-in-supervision-fram.patch new file mode 100644 index 0000000000..8713e5c276 --- /dev/null +++ b/queue-7.0/net-hsr-fix-potential-oob-access-in-supervision-fram.patch @@ -0,0 +1,48 @@ +From 46edc11fffee29f552edb03be622b536bfa94855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 May 2026 15:03:30 +0200 +Subject: net: hsr: fix potential OOB access in supervision frame handling + +From: Luka Gejak + +[ Upstream commit f229426072fc865654a60978bb7fda790a051ff3 ] + +Ensure the entire TLV header is linearized before access by adding +sizeof(struct hsr_sup_tlv) to the pskb_may_pull() calls. Without this, +a truncated frame could cause an out-of-bounds access. + +Fixes: eafaa88b3eb7 ("net: hsr: Add support for redbox supervision frames") +Signed-off-by: Luka Gejak +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260523130330.61880-1-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_forward.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c +index aefc9b6936ba0c..299de290ddaa5c 100644 +--- a/net/hsr/hsr_forward.c ++++ b/net/hsr/hsr_forward.c +@@ -84,7 +84,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* Get next tlv */ + total_length += hsr_sup_tag->tlv.HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + skb_pull(skb, total_length); + hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data; +@@ -100,7 +100,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) + + /* make sure another tlv follows */ + total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tlv->HSR_TLV_length; +- if (!pskb_may_pull(skb, total_length)) ++ if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_tlv))) + return false; + + /* get next tlv */ +-- +2.53.0 + diff --git a/queue-7.0/net-introduce-skb-tc-depth-field-to-track-packet-loo.patch b/queue-7.0/net-introduce-skb-tc-depth-field-to-track-packet-loo.patch new file mode 100644 index 0000000000..e8a632c42f --- /dev/null +++ b/queue-7.0/net-introduce-skb-tc-depth-field-to-track-packet-loo.patch @@ -0,0 +1,95 @@ +From bb7061e5395e889293daffb386f50a6838e46097 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:48 -0400 +Subject: net: Introduce skb tc depth field to track packet loops + +From: Jamal Hadi Salim + +[ Upstream commit 98b34f3e8c3492cfc89ff943c9d92b4d52863d1d ] + +Add a 2-bit per-skb tc depth field to track packet loops across the stack. + +The previous per-CPU loop counters like MIRRED_NEST_LIMIT +assume a single call stack and lose state in two cases: +1) When a packet is queued and reprocessed later (e.g., egress->ingress + via backlog), the per-cpu state is gone by the time it is dequeued. +2) With XPS/RPS a packet may arrive on one CPU and be processed on + another. + +A per-skb field solves both by travelling with the packet itself. + +The field fits in existing padding, using 2 bits that were previously a +hole: + +pahole before(-) and after (+) diff looks like: + __u8 slow_gro:1; /* 132: 3 1 */ + __u8 csum_not_inet:1; /* 132: 4 1 */ + __u8 unreadable:1; /* 132: 5 1 */ + + __u8 tc_depth:2; /* 132: 6 1 */ + + - /* XXX 2 bits hole, try to pack */ + /* XXX 1 byte hole, try to pack */ + + __u16 tc_index; /* 134 2 */ + +There used to be a ttl field which was removed as part of tc_verd in commit +aec745e2c520 ("net-tc: remove unused tc_verd fields"). It was already +unused by that time, due to remove earlier in commit c19ae86a510c ("tc: remove +unused redirect ttl"). + +The first user of this field is netem, which increments tc_depth on +duplicated packets before re-enqueueing them at the root qdisc. On +re-entry, netem skips duplication for any skb with tc_depth already set, +bounding recursion to a single level regardless of tree topology. + +The other user is mirred which increments it on each pass +and limits to depth to MIRRED_DEFER_LIMIT (3). + +The new field was called ttl in earlier versions of this patch +but renamed to tc_depth to avoid confusion with IP ttl. + +Note (looking at you Sashiko! Dont ignore me and continue bringing this up): +1. Since both mirred and netem utilize the same 2-bit tc_depth field it is + possible when netem and mirred are used together that netem qdisc to skip + the duplication step. This is a known trade-off, as a 2-bit field cannot + independently track both features' recursion depths and it is not considered + sane to have a setup that addresses both features on at the same time. + +2. skb_scrub_packet does not clear tc_depth. This means a packet's loop history + is preserved even across namespaces. While this might be restrictive for + some topologies, it is also design intent to provide robustness against loops + across namespaces. + +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-2-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Stable-dep-of: db875221ab08 ("net/sched: Fix ethx:ingress -> ethy:egress -> ethx:ingress mirred loop") +Signed-off-by: Sasha Levin +--- + include/linux/skbuff.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 2f278ce376b7ed..a58ff8903e536e 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -821,6 +821,7 @@ enum skb_tstamp_type { + * @_sk_redir: socket redirection information for skmsg + * @_nfct: Associated connection, if any (with nfctinfo bits) + * @skb_iif: ifindex of device we arrived on ++ * @tc_depth: counter for packet duplication + * @tc_index: Traffic control index + * @hash: the packet hash + * @queue_mapping: Queue mapping for multiqueue devices +@@ -1030,6 +1031,7 @@ struct sk_buff { + __u8 csum_not_inet:1; + #endif + __u8 unreadable:1; ++ __u8 tc_depth:2; + #if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS) + __u16 tc_index; /* traffic control index */ + #endif +-- +2.53.0 + diff --git a/queue-7.0/net-iucv-fix-locking-in-.getsockopt.patch b/queue-7.0/net-iucv-fix-locking-in-.getsockopt.patch new file mode 100644 index 0000000000..1cde028aa9 --- /dev/null +++ b/queue-7.0/net-iucv-fix-locking-in-.getsockopt.patch @@ -0,0 +1,87 @@ +From b2ffd478825809dcaaacb0279519368df3385a11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 07:11:45 -0700 +Subject: net/iucv: fix locking in .getsockopt + +From: Breno Leitao + +[ Upstream commit 3589d20a666caf30ad100c960a2de7de390fce88 ] + +Mirror iucv_sock_setsockopt() and wrap the whole switch in +lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock +becomes redundant and is removed. + +Any AF_IUCV HIPER user can potentially crash the kernel by racing +recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences +iucv->hs_dev->mtu after iucv_sock_close() (called from the racing +recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference +oops. + +Suggested-by: Stanislav Fomichev +Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size") +Signed-off-by: Breno Leitao +Reviewed-by: Alexandra Winter +Tested-by: Alexandra Winter +Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/iucv/af_iucv.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index 6554d2cffc1961..30cbd98f941a98 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1538,7 +1538,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + unsigned int val; +- int len; ++ int len, rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; +@@ -1551,26 +1551,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + + len = min_t(unsigned int, len, sizeof(int)); + ++ rc = 0; ++ ++ lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: +- lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ +- release_sock(sk); + break; + case SO_MSGSIZE: +- if (sk->sk_state == IUCV_OPEN) +- return -EBADFD; ++ if (sk->sk_state == IUCV_OPEN) { ++ rc = -EBADFD; ++ break; ++ } + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; + default: +- return -ENOPROTOOPT; ++ rc = -ENOPROTOOPT; ++ break; + } ++ release_sock(sk); ++ ++ if (rc) ++ return rc; + + if (put_user(len, optlen)) + return -EFAULT; +-- +2.53.0 + diff --git a/queue-7.0/net-mana-add-null-guards-in-teardown-path-to-prevent.patch b/queue-7.0/net-mana-add-null-guards-in-teardown-path-to-prevent.patch new file mode 100644 index 0000000000..59b48bfe9e --- /dev/null +++ b/queue-7.0/net-mana-add-null-guards-in-teardown-path-to-prevent.patch @@ -0,0 +1,148 @@ +From ae0d68b335ffad3e1e24a238363c50cdc850204e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 01:08:24 -0700 +Subject: net: mana: Add NULL guards in teardown path to prevent panic on + attach failure + +From: Dipayaan Roy + +[ Upstream commit 17bfe0a8c014ee1d542ad352cd6a0a505361664a ] + +When queue allocation fails partway through, the error cleanup frees +and NULLs apc->tx_qp and apc->rxqs. Multiple teardown paths such as +mana_remove(), mana_change_mtu() recovery, and internal error handling +in mana_alloc_queues() can subsequently call into functions that +dereference these pointers without NULL checks: + +- mana_chn_setxdp() dereferences apc->rxqs[0], causing a NULL pointer + dereference panic (CR2: 0000000000000000 at mana_chn_setxdp+0x26). +- mana_destroy_vport() iterates apc->rxqs without a NULL check. +- mana_fence_rqs() iterates apc->rxqs without a NULL check. +- mana_dealloc_queues() iterates apc->tx_qp without a NULL check. + +Add NULL guards for apc->rxqs in mana_fence_rqs(), +mana_destroy_vport(), and before the mana_chn_setxdp() call. Add a +NULL guard for apc->tx_qp in mana_dealloc_queues() to skip TX queue +draining when TX queues were never allocated or already freed. + +Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)") +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260525081129.1230035-2-dipayanroy@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 70 +++++++++++-------- + 1 file changed, 41 insertions(+), 29 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 14d6f68eaa6958..3ddbf3b9a76501 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -1713,6 +1713,9 @@ static void mana_fence_rqs(struct mana_port_context *apc) + struct mana_rxq *rxq; + int err; + ++ if (!apc->rxqs) ++ return; ++ + for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { + rxq = apc->rxqs[rxq_idx]; + err = mana_fence_rq(apc, rxq); +@@ -2821,13 +2824,16 @@ static void mana_destroy_vport(struct mana_port_context *apc) + struct mana_rxq *rxq; + u32 rxq_idx; + +- for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { +- rxq = apc->rxqs[rxq_idx]; +- if (!rxq) +- continue; ++ if (apc->rxqs) { + +- mana_destroy_rxq(apc, rxq, true); +- apc->rxqs[rxq_idx] = NULL; ++ for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { ++ rxq = apc->rxqs[rxq_idx]; ++ if (!rxq) ++ continue; ++ ++ mana_destroy_rxq(apc, rxq, true); ++ apc->rxqs[rxq_idx] = NULL; ++ } + } + + mana_destroy_txq(apc); +@@ -3232,7 +3238,8 @@ static int mana_dealloc_queues(struct net_device *ndev) + if (apc->port_is_up) + return -EINVAL; + +- mana_chn_setxdp(apc, NULL); ++ if (apc->rxqs) ++ mana_chn_setxdp(apc, NULL); + + if (gd->gdma_context->is_pf && !apc->ac->bm_hostmode) + mana_pf_deregister_filter(apc); +@@ -3250,33 +3257,38 @@ static int mana_dealloc_queues(struct net_device *ndev) + * number of queues. + */ + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- tsleep = 1000; +- while (atomic_read(&txq->pending_sends) > 0 && +- time_before(jiffies, timeout)) { +- usleep_range(tsleep, tsleep + 1000); +- tsleep <<= 1; +- } +- if (atomic_read(&txq->pending_sends)) { +- err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); +- if (err) { +- netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", +- err, atomic_read(&txq->pending_sends), +- txq->gdma_txq_id); ++ if (apc->tx_qp) { ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ tsleep = 1000; ++ while (atomic_read(&txq->pending_sends) > 0 && ++ time_before(jiffies, timeout)) { ++ usleep_range(tsleep, tsleep + 1000); ++ tsleep <<= 1; ++ } ++ if (atomic_read(&txq->pending_sends)) { ++ err = ++ pcie_flr(to_pci_dev(gd->gdma_context->dev)); ++ if (err) { ++ netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", ++ err, ++ atomic_read(&txq->pending_sends), ++ txq->gdma_txq_id); ++ } ++ break; + } +- break; + } +- } + +- for (i = 0; i < apc->num_queues; i++) { +- txq = &apc->tx_qp[i].txq; +- while ((skb = skb_dequeue(&txq->pending_skbs))) { +- mana_unmap_skb(skb, apc); +- dev_kfree_skb_any(skb); ++ for (i = 0; i < apc->num_queues; i++) { ++ txq = &apc->tx_qp[i].txq; ++ while ((skb = skb_dequeue(&txq->pending_skbs))) { ++ mana_unmap_skb(skb, apc); ++ dev_kfree_skb_any(skb); ++ } ++ atomic_set(&txq->pending_sends, 0); + } +- atomic_set(&txq->pending_sends, 0); + } ++ + /* We're 100% sure the queues can no longer be woken up, because + * we're sure now mana_poll_tx_cq() can't be running. + */ +-- +2.53.0 + diff --git a/queue-7.0/net-mana-skip-redundant-detach-on-already-detached-p.patch b/queue-7.0/net-mana-skip-redundant-detach-on-already-detached-p.patch new file mode 100644 index 0000000000..05c8f81557 --- /dev/null +++ b/queue-7.0/net-mana-skip-redundant-detach-on-already-detached-p.patch @@ -0,0 +1,51 @@ +From 4bdb09f16d22a76ac25db360d5cfbd8dcb341672 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 01:08:25 -0700 +Subject: net: mana: Skip redundant detach on already-detached port + +From: Dipayaan Roy + +[ Upstream commit 5b05aa36ee24297d7296ca58dfd8c448d0e4cda3 ] + +When mana_per_port_queue_reset_work_handler() runs after a previous +detach succeeded but attach failed, the port is left in a detached +state with apc->tx_qp and apc->rxqs already freed. Calling +mana_detach() again unconditionally leads to NULL pointer dereferences +during queue teardown. + +Add an early exit in mana_detach() when the port is already in +detached state (!netif_device_present) for non-close callers, making +it safe to call idempotently. This allows the queue reset handler and +other recovery paths to simply retry mana_attach() without redundant +teardown. + +Fixes: 3b194343c250 ("net: mana: Implement ndo_tx_timeout and serialize queue resets per port.") +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260525081129.1230035-3-dipayanroy@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 3ddbf3b9a76501..13a0af0456c9e3 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3313,6 +3313,12 @@ int mana_detach(struct net_device *ndev, bool from_close) + + ASSERT_RTNL(); + ++ /* If already detached (indicates detach succeeded but attach failed ++ * previously). Now skip mana detach and just retry mana_attach. ++ */ ++ if (!from_close && !netif_device_present(ndev)) ++ return 0; ++ + apc->port_st_save = apc->port_is_up; + apc->port_is_up = false; + +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5-hws-reject-unsupported-remove-header-action.patch b/queue-7.0/net-mlx5-hws-reject-unsupported-remove-header-action.patch new file mode 100644 index 0000000000..8db678a409 --- /dev/null +++ b/queue-7.0/net-mlx5-hws-reject-unsupported-remove-header-action.patch @@ -0,0 +1,50 @@ +From 29a39d1a8e1fa1b8d48f7beacafdc71bb4d79068 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:00:31 +0100 +Subject: net/mlx5: HWS: Reject unsupported remove-header action + +From: Prathamesh Deshpande + +[ Upstream commit 86f1d0f063e423a5c1982db1e5e7a8eac511e603 ] + +mlx5_cmd_hws_packet_reformat_alloc() handles +MLX5_REFORMAT_TYPE_REMOVE_HDR by looking up a matching HWS remove-header +action. + +If mlx5_fs_get_action_remove_header_vlan() returns NULL, the code only +logs an error and continues. The function then returns success with a NULL +HWS action stored in the packet-reformat object. + +Return an error when no matching remove-header action is available. + +Fixes: aecd9d1020e3 ("net/mlx5: fs, add HWS packet reformat API function") +Signed-off-by: Prathamesh Deshpande +Reviewed-by: Simon Horman +Reviewed-by: Yevgeny Kliteynik +Acked-by: Tariq Toukan +Link: https://patch.msgid.link/20260506000054.51797-1-prathameshdeshpande7@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c +index aca77853abb81b..5a172c572a68f5 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c +@@ -1320,8 +1320,10 @@ mlx5_cmd_hws_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns, + break; + case MLX5_REFORMAT_TYPE_REMOVE_HDR: + hws_action = mlx5_fs_get_action_remove_header_vlan(fs_ctx, params); +- if (!hws_action) ++ if (!hws_action) { + mlx5_core_err(dev, "Only vlan remove header supported\n"); ++ return -EOPNOTSUPP; ++ } + break; + default: + mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n", +-- +2.53.0 + diff --git a/queue-7.0/net-netlink-don-t-set-nsid-on-local-notifications.patch b/queue-7.0/net-netlink-don-t-set-nsid-on-local-notifications.patch new file mode 100644 index 0000000000..f995c27ec4 --- /dev/null +++ b/queue-7.0/net-netlink-don-t-set-nsid-on-local-notifications.patch @@ -0,0 +1,82 @@ +From c02be8ca232955dabaaefb486e7a15ee59720851 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:36 +0200 +Subject: net: netlink: don't set nsid on local notifications + +From: Ilya Maximets + +[ Upstream commit 88b126b39f9757e9debc322d4679239e9af089c7 ] + +In most cases, notifications on sockets with NETLINK_LISTEN_ALL_NSID +do not contain NSID in their ancillary data in case the event is local +to the listener. + +However, when a self-referential NSID is allocated for a namespace, +every local notification starts sending this ID to the user space. + +This is problematic, because the listener cannot tell if those +notifications are local or not anymore without making extra requests +to figure out if the provided NSID is local or not. The listener +can also not figure out the local NSID beforehand as it can be +allocated at any point in time by other processes, changing the +structure of the future notifications for everyone. + +The value is practically not useful, since it's the namespace's own +ID that the application has to obtain from other sources in order to +figure out if it's the same or not. So, for the application it's +just an extra busy work with no benefits. Moreover, applications +that do not know about this quirk may be mishandling notifications +with NSID set as notifications from remote namespaces. This is the +case for ovs-vswitchd and the iproute2's 'ip monitor' that stops +printing 'current' and starts printing the nsid number mid-session. + +Lack of clear documentation for this behavior is also not helping. + +A search though open-source projects doesn't reveal any projects +that use NETNSA_NSID_NOT_ASSIGNED and rely on metadata to contain +self-referential NSIDs (expected, since the value is not useful). +Quite the opposite, as already mentioned, there are few applications +that rely on NSID to not be present in local events. + +Since the value is not useful and actively harmful in some cases, +let's not report it for local events, making the notifications more +consistent. + +Also adding some blank lines for readability. + +Fixes: 59324cf35aba ("netlink: allow to listen "all" netns") +Reported-by: Matteo Perin +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-3-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 441c9852b25714..c47f530b9ff7d9 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1482,10 +1482,14 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ + NETLINK_CB(p->skb2).nsid_is_set = false; +- NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); +- if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) +- NETLINK_CB(p->skb2).nsid_is_set = true; ++ if (!net_eq(sock_net(sk), p->net)) { ++ NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); ++ if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) ++ NETLINK_CB(p->skb2).nsid_is_set = true; ++ } ++ + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { + netlink_overrun(sk); +-- +2.53.0 + diff --git a/queue-7.0/net-netlink-fix-sending-unassigned-nsid-after-assign.patch b/queue-7.0/net-netlink-fix-sending-unassigned-nsid-after-assign.patch new file mode 100644 index 0000000000..6dd59536c2 --- /dev/null +++ b/queue-7.0/net-netlink-fix-sending-unassigned-nsid-after-assign.patch @@ -0,0 +1,45 @@ +From d7e12a472a7a13f826bf9f11ea71e8732568776e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 19:22:35 +0200 +Subject: net: netlink: fix sending unassigned nsid after assigned one + +From: Ilya Maximets + +[ Upstream commit 70f8592ee90585272018a725054b6eb2ab7e99ca ] + +If the current skb is not shared, it is re-used directly for all the +sockets subscribed to the notification. If we have remote all-nsid +socket receiving a message first, then the 'nsid_is_set' will be +set to 'true'. If the nsid is NOT_ASSIGNED for the next socket in +the list, the 'nsid_is_set' will remain 'true' and the negative value +is be delivered to the user space. All subsequent nsid values will be +delivered as well, since there is no code path that sets the flag +back to 'false'. + +Fix that by always dropping the flag to 'false' first. + +Fixes: 7212462fa6fd ("netlink: don't send unknown nsid") +Signed-off-by: Ilya Maximets +Acked-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260520172317.175168-2-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlink/af_netlink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 4d609d5cf40653..441c9852b25714 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1482,6 +1482,7 @@ static void do_one_broadcast(struct sock *sk, + p->skb2 = NULL; + goto out; + } ++ NETLINK_CB(p->skb2).nsid_is_set = false; + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) + NETLINK_CB(p->skb2).nsid_is_set = true; +-- +2.53.0 + diff --git a/queue-7.0/net-pcs-pcs-mtk-lynxi-fix-bpi-r3-serdes-configuratio.patch b/queue-7.0/net-pcs-pcs-mtk-lynxi-fix-bpi-r3-serdes-configuratio.patch new file mode 100644 index 0000000000..25d4966514 --- /dev/null +++ b/queue-7.0/net-pcs-pcs-mtk-lynxi-fix-bpi-r3-serdes-configuratio.patch @@ -0,0 +1,63 @@ +From 68d43e79c75d51bed77ed440241f848e044c5ae8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 17:32:38 +0200 +Subject: net: pcs: pcs-mtk-lynxi: fix bpi-r3 serdes configuration + +From: Frank Wunderlich + +[ Upstream commit 422b5233b607476ac7176bfa2a101b9a103d7653 ] + +Commit 8871389da151 introduces common pcs dts properties which writes +rx=normal,tx=normal polarity to register SGMSYS_QPHY_WRAP_CTRL of switch. +This is initialized with tx-bit set and so change inverts polarity +compared to before. + +It looks like mt7531 has tx polarity inverted in hardware and set tx-bit +by default to restore the normal polarity. + +The MT7531 datasheet quite clearly states: +Register 000050EC QPHY_WRAP_CTRL -- QPHY wrapper control +Reset value: 0x00000501 + +BIT 1 RX_BIT_POLARITY -- RX bit polarity control + 1'b0: normal + 1'b1: inverted + +BIT 0 TX_BIT_POLARITY -- TX bit polarity control (TX default inversed +in MT7531) + 1'b0: normal + 1'b1: inverted + +Till this patch the register write was only called when mediatek,pnswap +property was set which cannot be done for switch because the fw-node param +was always NULL from switch driver in the mtk_pcs_lynxi_create call. + +Do not configure switch side like it's done before. + +Fixes: 8871389da151 ("net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"") +Signed-off-by: Frank Wunderlich +Reviewed-by: Vladimir Oltean +Link: https://patch.msgid.link/20260526153239.30194-1-linux@fw-web.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/pcs/pcs-mtk-lynxi.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c +index c12f8087af9be5..a753bd88cbc223 100644 +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -129,6 +129,9 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs, + unsigned int val = 0; + int ret; + ++ if (!fwnode) ++ return 0; ++ + if (fwnode_property_read_bool(fwnode, "mediatek,pnswap")) + default_pol = PHY_POL_INVERT; + +-- +2.53.0 + diff --git a/queue-7.0/net-sched-act_mirred-fix-blockcast-recursion-bypass-.patch b/queue-7.0/net-sched-act_mirred-fix-blockcast-recursion-bypass-.patch new file mode 100644 index 0000000000..6fa82ea912 --- /dev/null +++ b/queue-7.0/net-sched-act_mirred-fix-blockcast-recursion-bypass-.patch @@ -0,0 +1,114 @@ +From 47d74a925129f0f80822a799be3a6404b4bf8be9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:53 -0400 +Subject: net/sched: act_mirred: Fix blockcast recursion bypass leading to + stack overflow + +From: Kito Xu (veritas501) + +[ Upstream commit a005fa5d7502eefec7ee6e1c01adadc06de2f9ad ] + +tcf_mirred_act() checks sched_mirred_nest against MIRRED_NEST_LIMIT (4) +to prevent deep recursion. However, when the action uses blockcast +(tcfm_blockid != 0), the function returns at the tcf_blockcast() call +BEFORE reaching the counter increment. As a result, the recursion +counter never advances and the limit check is entirely bypassed. + +When two devices share a TC egress block with a mirred blockcast rule, +a packet egressing on device A is mirrored to device B via blockcast; +device B's egress TC re-enters tcf_mirred_act() via blockcast and +mirrors back to A, creating an unbounded recursion loop: + + tcf_mirred_act -> tcf_blockcast -> tcf_mirred_to_dev -> dev_queue_xmit + -> sch_handle_egress -> tcf_classify -> tcf_mirred_act -> (repeat) + +This recursion continues until the kernel stack overflows. + +The bug is reachable from an unprivileged user via +unshare(CLONE_NEWUSER | CLONE_NEWNET): user namespaces grant +CAP_NET_ADMIN in the new network namespace, which is sufficient to +create dummy devices, attach clsact qdiscs with shared blocks, and +install mirred blockcast filters. + + BUG: TASK stack guard page was hit at ffffc90000b7fff8 + Oops: stack guard page: 0000 [#1] SMP KASAN NOPTI + CPU: 2 UID: 1000 PID: 169 Comm: poc Not tainted 7.0.0-rc7-next-20260410 + RIP: 0010:xas_find+0x17/0x480 + Call Trace: + xa_find+0x17b/0x1d0 + tcf_mirred_act+0x640/0x1060 + tcf_action_exec+0x400/0x530 + basic_classify+0x128/0x1d0 + tcf_classify+0xd83/0x1150 + tc_run+0x328/0x620 + __dev_queue_xmit+0x797/0x3100 + tcf_mirred_to_dev+0x7b1/0xf70 + tcf_mirred_act+0x68a/0x1060 + [repeating ~30+ times until stack overflow] + Kernel panic - not syncing: Fatal exception in interrupt + +Fix this by incrementing sched_mirred_nest before calling +tcf_blockcast() and decrementing it on return, mirroring the +non-blockcast path. This ensures subsequent recursive entries see the +updated counter and are correctly limited by MIRRED_NEST_LIMIT. + +Fixes: fe946a751d9b ("net/sched: act_mirred: add loop detection") +Signed-off-by: Kito Xu (veritas501) +Link: https://patch.msgid.link/20260525122556.973584-7-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index dd5e7ea7ef2652..dbe4a4ff3e08b8 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -396,14 +396,12 @@ static int tcf_blockcast_mirror(struct sk_buff *skb, struct tcf_mirred *m, + + static int tcf_blockcast(struct sk_buff *skb, struct tcf_mirred *m, + const u32 blockid, struct tcf_result *res, +- int retval) ++ int m_eaction, int retval) + { + const u32 exception_ifindex = skb->dev->ifindex; + struct tcf_block *block; + bool is_redirect; +- int m_eaction; + +- m_eaction = READ_ONCE(m->tcfm_eaction); + is_redirect = tcf_mirred_is_act_redirect(m_eaction); + + /* we are already under rcu protection, so can call block lookup +@@ -453,8 +451,16 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + tcf_action_update_bstats(&m->common, skb); + + blockid = READ_ONCE(m->tcfm_blockid); +- if (blockid) +- return tcf_blockcast(skb, m, blockid, res, retval); ++ m_eaction = READ_ONCE(m->tcfm_eaction); ++ want_ingress = tcf_mirred_act_wants_ingress(m_eaction); ++ if (blockid) { ++ if (!want_ingress) ++ xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = NULL; ++ retval = tcf_blockcast(skb, m, blockid, res, m_eaction, retval); ++ if (!want_ingress) ++ xmit->sched_mirred_nest--; ++ return retval; ++ } + + dev = rcu_dereference_bh(m->tcfm_dev); + if (unlikely(!dev)) { +@@ -463,8 +469,6 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + return retval; + } + +- m_eaction = READ_ONCE(m->tcfm_eaction); +- want_ingress = tcf_mirred_act_wants_ingress(m_eaction); + if (!want_ingress) { + for (i = 0; i < xmit->sched_mirred_nest; i++) { + if (xmit->sched_mirred_dev[i] != dev) +-- +2.53.0 + diff --git a/queue-7.0/net-sched-act_mirred-fix-return-code-in-early-mirred.patch b/queue-7.0/net-sched-act_mirred-fix-return-code-in-early-mirred.patch new file mode 100644 index 0000000000..46dcc790ae --- /dev/null +++ b/queue-7.0/net-sched-act_mirred-fix-return-code-in-early-mirred.patch @@ -0,0 +1,99 @@ +From e2675e84594fb8dfef530667a43734a445885b56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:54 -0400 +Subject: net/sched: act_mirred: Fix return code in early mirred redirect error + paths + +From: Victor Nogueira + +[ Upstream commit e80ad525fc7e8c933ad78478c5dda286cfd55c60 ] + +Since retval is set as TC_ACT_STOLEN in the mirred redirect case, returning +retval in cases where redirect failed will make the callers not register +the skb as being dropped. + +Fix this by returning TC_ACT_SHOT instead in such scenarios. + +Fixes: 16085e48cb48 ("net/sched: act_mirred: Create function tcf_mirred_to_dev and improve readability") +Reported-by: Sashiko +Closes: https://sashiko.dev/#/patchset/20260413082027.2244884-1-hxzene%40gmail.com +Signed-off-by: Victor Nogueira +Link: https://patch.msgid.link/20260525122556.973584-8-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index dbe4a4ff3e08b8..553342c55cf7c6 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -372,7 +372,8 @@ static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m, + dev_is_mac_header_xmit(dev_prev), + m_eaction, retval); + +- return retval; ++ /* If the packet wasn't redirected, we have to register as a drop */ ++ return TC_ACT_SHOT; + } + + static int tcf_blockcast_mirror(struct sk_buff *skb, struct tcf_mirred *m, +@@ -410,7 +411,7 @@ static int tcf_blockcast(struct sk_buff *skb, struct tcf_mirred *m, + block = tcf_block_lookup(dev_net(skb->dev), blockid); + if (!block || xa_empty(&block->ports)) { + tcf_action_inc_overlimit_qstats(&m->common); +- return retval; ++ return is_redirect ? TC_ACT_SHOT : retval; + } + + if (is_redirect) +@@ -428,8 +429,8 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + { + struct tcf_mirred *m = to_mirred(a); + int retval = READ_ONCE(m->tcf_action); ++ bool m_mac_header_xmit, is_redirect; + struct netdev_xmit *xmit; +- bool m_mac_header_xmit; + struct net_device *dev; + bool want_ingress; + int i, m_eaction; +@@ -462,11 +463,13 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + return retval; + } + ++ is_redirect = tcf_mirred_is_act_redirect(m_eaction); ++ + dev = rcu_dereference_bh(m->tcfm_dev); + if (unlikely(!dev)) { + pr_notice_once("tc mirred: target device is gone\n"); + tcf_action_inc_overlimit_qstats(&m->common); +- return retval; ++ goto err_out; + } + + if (!want_ingress) { +@@ -476,7 +479,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + pr_notice_once("tc mirred: loop on device %s\n", + netdev_name(dev)); + tcf_action_inc_overlimit_qstats(&m->common); +- return retval; ++ goto err_out; + } + xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; + } +@@ -489,6 +492,11 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + xmit->sched_mirred_nest--; + + return retval; ++ ++err_out: ++ if (is_redirect) ++ retval = TC_ACT_SHOT; ++ return retval; + } + + static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets, +-- +2.53.0 + diff --git a/queue-7.0/net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch b/queue-7.0/net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch new file mode 100644 index 0000000000..584e3ddce6 --- /dev/null +++ b/queue-7.0/net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch @@ -0,0 +1,135 @@ +From f2941f2de613209607df02d329c266682fa59d59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:52 -0400 +Subject: net/sched: Fix ethx:ingress -> ethy:egress -> ethx:ingress mirred + loop + +From: Jamal Hadi Salim + +[ Upstream commit db875221ab08d213a83bf30196ae8b64d55a3403 ] + +When mirred redirects to ingress (from either ingress or egress) the loop +state from sched_mirred_dev array dev is lost because of 1) the packet +deferral into the backlog and 2) the fact the sched_mirred_dev array is +cleared. In such cases, if there was a loop we won't discover it. + +Here's a simple test to reproduce: +ip a add dev port0 10.10.10.11/24 + +tc qdisc add dev port0 clsact +tc filter add dev port0 egress protocol ip \ + prio 10 matchall action mirred ingress redirect dev port1 + +tc qdisc add dev port1 clsact +tc filter add dev port1 ingress protocol ip \ + prio 10 matchall action mirred egress redirect dev port0 + +ping -c 1 -W0.01 10.10.10.10 + +Fixes: fe946a751d9b ("net/sched: act_mirred: add loop detection") +Tested-by: Victor Nogueira +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-6-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 47 +++++++++++++++++++++++++++--------------- + 1 file changed, 30 insertions(+), 17 deletions(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index 2c5a7a321a9438..dd5e7ea7ef2652 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -26,6 +26,10 @@ + #include + #include + ++#define MIRRED_DEFER_LIMIT 3 ++_Static_assert(MIRRED_DEFER_LIMIT <= 3, ++ "MIRRED_DEFER_LIMIT exceeds tc_depth bitfield width"); ++ + static LIST_HEAD(mirred_list); + static DEFINE_SPINLOCK(mirred_list_lock); + +@@ -234,12 +238,15 @@ tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb) + { + int err; + +- if (!want_ingress) ++ if (!want_ingress) { + err = tcf_dev_queue_xmit(skb, dev_queue_xmit); +- else if (!at_ingress) +- err = netif_rx(skb); +- else +- err = netif_receive_skb(skb); ++ } else { ++ skb->tc_depth++; ++ if (!at_ingress) ++ err = netif_rx(skb); ++ else ++ err = netif_receive_skb(skb); ++ } + + return err; + } +@@ -426,6 +433,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + struct netdev_xmit *xmit; + bool m_mac_header_xmit; + struct net_device *dev; ++ bool want_ingress; + int i, m_eaction; + u32 blockid; + +@@ -434,7 +442,8 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + #else + xmit = this_cpu_ptr(&softnet_data.xmit); + #endif +- if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT)) { ++ if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT || ++ skb->tc_depth >= MIRRED_DEFER_LIMIT)) { + net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n", + netdev_name(skb->dev)); + return TC_ACT_SHOT; +@@ -453,23 +462,27 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, + tcf_action_inc_overlimit_qstats(&m->common); + return retval; + } +- for (i = 0; i < xmit->sched_mirred_nest; i++) { +- if (xmit->sched_mirred_dev[i] != dev) +- continue; +- pr_notice_once("tc mirred: loop on device %s\n", +- netdev_name(dev)); +- tcf_action_inc_overlimit_qstats(&m->common); +- return retval; +- } + +- xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; ++ m_eaction = READ_ONCE(m->tcfm_eaction); ++ want_ingress = tcf_mirred_act_wants_ingress(m_eaction); ++ if (!want_ingress) { ++ for (i = 0; i < xmit->sched_mirred_nest; i++) { ++ if (xmit->sched_mirred_dev[i] != dev) ++ continue; ++ pr_notice_once("tc mirred: loop on device %s\n", ++ netdev_name(dev)); ++ tcf_action_inc_overlimit_qstats(&m->common); ++ return retval; ++ } ++ xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; ++ } + + m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); +- m_eaction = READ_ONCE(m->tcfm_eaction); + + retval = tcf_mirred_to_dev(skb, m, dev, m_mac_header_xmit, m_eaction, + retval); +- xmit->sched_mirred_nest--; ++ if (!want_ingress) ++ xmit->sched_mirred_nest--; + + return retval; + } +-- +2.53.0 + diff --git a/queue-7.0/net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch b/queue-7.0/net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch new file mode 100644 index 0000000000..10180cbc50 --- /dev/null +++ b/queue-7.0/net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch @@ -0,0 +1,71 @@ +From c4011f23f07b6f676e2c8a8786db346fe0baf900 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:51 -0400 +Subject: net/sched: fix packet loop on netem when duplicate is on + +From: Jamal Hadi Salim + +[ Upstream commit 9552b11e3edabc97cfcd9f29103d5afbce7ae183 ] + +When netem duplicates a packet it re-enqueues the copy at the root qdisc. +If another netem sits in the tree the copy can be duplicated +again, recursing until the stack or memory is exhausted. + +The original duplication guard temporarily zeroed q->duplicate around +the re-enqueue, but that does not cover all cases because it is +per-qdisc state shared across all concurrent enqueue paths +and is not safe without additional locking. + +Use the skb tc_depth field introduced in an earlier patch: + - increment it on the duplicate before re-enqueue + - skip duplication for any skb whose tc_depth is already non-zero. + +This marks the packet itself rather than mutating qdisc state, +therefore it is safe regardless of tree topology or concurrency. + +Fixes: 0afb51e72855 ("[PKT_SCHED]: netem: reinsert for duplication") +Reported-by: William Liu +Reported-by: Savino Dicanosa +Closes: https://lore.kernel.org/netdev/8DuRWwfqjoRDLDmBMlIfbrsZg9Gx50DHJc1ilxsEBNe2D6NMoigR_eIRIG0LOjMc3r10nUUZtArXx4oZBIdUfZQrwjcQhdinnMis_0G7VEk=@willsroot.io/ +Co-developed-by: Victor Nogueira +Signed-off-by: Victor Nogueira +Reviewed-by: William Liu +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-5-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index d97acd2f392346..17a79fe2f0911d 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -461,7 +461,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + skb->prev = NULL; + + /* Random duplication */ +- if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor, &q->prng)) ++ if (q->duplicate && skb->tc_depth == 0 && ++ q->duplicate >= get_crandom(&q->dup_cor, &q->prng)) + ++count; + + /* Drop packet? */ +@@ -540,11 +541,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + */ + if (skb2) { + struct Qdisc *rootq = qdisc_root_bh(sch); +- u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ + +- q->duplicate = 0; ++ skb2->tc_depth++; /* prevent duplicating a dup... */ + rootq->enqueue(skb2, rootq, to_free); +- q->duplicate = dupsave; + skb2 = NULL; + } + +-- +2.53.0 + diff --git a/queue-7.0/net-sched-revert-net-sched-restrict-conditions-for-a.patch b/queue-7.0/net-sched-revert-net-sched-restrict-conditions-for-a.patch new file mode 100644 index 0000000000..0b10b146d3 --- /dev/null +++ b/queue-7.0/net-sched-revert-net-sched-restrict-conditions-for-a.patch @@ -0,0 +1,102 @@ +From 9e979a4d13b2b7675c50cff8ecd323d91f115356 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 08:25:49 -0400 +Subject: net/sched: Revert "net/sched: Restrict conditions for adding + duplicating netems to qdisc tree" + +From: Jamal Hadi Salim + +[ Upstream commit eda0b7f203bb166c98d1418b204135bd566ac83b ] + +This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. + +The original patch rejects any tree containing two netems when +either has duplication set, even when they sit on unrelated classes +of the same classful parent. That broke configurations that have +worked since netem was introduced. + +The re-entrancy problem the original commit was trying to solve is +handled by later patch using tc_depth flag. + +Doing this revert will (re)expose the original bug with multiple +netem duplication. When this patch is backported make sure +and get the full series. + +Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") +Reported-by: Ji-Soo Chung +Reported-by: Gerlinde +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 +Reported-by: zyc zyc +Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ +Reported-by: Manas Ghandat +Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ +Reviewed-by: Stephen Hemminger +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 40 ---------------------------------------- + 1 file changed, 40 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index bc18e1976b6e07..d97acd2f392346 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1007,41 +1007,6 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, + return 0; + } + +-static const struct Qdisc_class_ops netem_class_ops; +- +-static int check_netem_in_tree(struct Qdisc *sch, bool duplicates, +- struct netlink_ext_ack *extack) +-{ +- struct Qdisc *root, *q; +- unsigned int i; +- +- root = qdisc_root_sleeping(sch); +- +- if (sch != root && root->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(root))->duplicate) +- goto err; +- } +- +- if (!qdisc_dev(root)) +- return 0; +- +- hash_for_each(qdisc_dev(root)->qdisc_hash, i, q, hash) { +- if (sch != q && q->ops->cl_ops == &netem_class_ops) { +- if (duplicates || +- ((struct netem_sched_data *)qdisc_priv(q))->duplicate) +- goto err; +- } +- } +- +- return 0; +- +-err: +- NL_SET_ERR_MSG(extack, +- "netem: cannot mix duplicating netems with other netems in tree"); +- return -EINVAL; +-} +- + /* Parse netlink message to set options */ + static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +@@ -1118,11 +1083,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + q->gap = qopt->gap; + q->counter = 0; + q->loss = qopt->loss; +- +- ret = check_netem_in_tree(sch, qopt->duplicate, extack); +- if (ret) +- goto unlock; +- + q->duplicate = qopt->duplicate; + + /* for compatibility with earlier versions. +-- +2.53.0 + diff --git a/queue-7.0/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch b/queue-7.0/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch new file mode 100644 index 0000000000..e30c56ebff --- /dev/null +++ b/queue-7.0/net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch @@ -0,0 +1,64 @@ +From 486561b89e9f97c15e8cd6e953d924fd86826871 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2026 19:43:53 +0100 +Subject: net: skbuff: fix pskb_carve leaking zcopy pages + +From: Pavel Begunkov + +[ Upstream commit ff6e798c2eac3ebd0501ad7e796f583fab928de8 ] + +When SKBFL_MANAGED_FRAG_REFS is set, frag pages are not refcounted but +their lifetime is controlled by the attached ubuf_info. To make a copy +of the skb_shared_info, we either should clear the flag and reference +the frags, or keep the flag and have frags unreferenced. + +pskb_carve_inside_header() and pskb_carve_inside_nonlinear() don't +follow the rule and thus can leak page references. Let's clear +SKBFL_MANAGED_FRAG_REFS from the original skb to fix it. It's the +simplest way to address it, but there are more performant ways to do +that if it ever becomes a problem. + +Link: https://lore.kernel.org/all/20260523085809.26331-1-nvminh232@clc.fitus.edu.vn/ +Fixes: 753f1ca4e1e50 ("net: introduce managed frags infrastructure") +Reported-by: Minh Nguyen +Reported-by: Willem de Bruijn +Signed-off-by: Pavel Begunkov +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/1e2086aa69217d7f9c8da3d38f5be7160f1b4cd1.1779993185.git.asml.silence@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 13af6f35428d52..95ef64fad657d3 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6847,6 +6847,11 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, + skb_copy_from_linear_data_offset(skb, off, data, new_hlen); + skb->len -= off; + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), + offsetof(struct skb_shared_info, +@@ -6958,6 +6963,11 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, + return -ENOMEM; + size = SKB_WITH_OVERHEAD(size); + ++ /* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it ++ * while refcounting frags below. ++ */ ++ skb_zcopy_downgrade_managed(skb); ++ + memcpy((struct skb_shared_info *)(data + size), + skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0])); + if (skb_orphan_frags(skb, gfp_mask)) { +-- +2.53.0 + diff --git a/queue-7.0/net-smc-do-not-re-initialize-smc-hashtables.patch b/queue-7.0/net-smc-do-not-re-initialize-smc-hashtables.patch new file mode 100644 index 0000000000..9fd7830569 --- /dev/null +++ b/queue-7.0/net-smc-do-not-re-initialize-smc-hashtables.patch @@ -0,0 +1,59 @@ +From 6137ada3d0ec0ca3637d283839198f46d1936a01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 16:56:39 +0200 +Subject: net/smc: Do not re-initialize smc hashtables + +From: Alexandra Winter + +[ Upstream commit 9e4389b0038781f19f97895186ed941ff8ac1678 ] + +INIT_HLIST_HEAD(&smc_v*_hashinfo.ht) are called after smc_nl_init(), +proto_register() and sock_register(). This can lead to smc_v*_hashinfo.ht +being reset even though hash entries already exist and are being used, +possibly resulting in a corrupted list. + +Remove unnecessary and dangerous re-initialisation of smc_v*_hashinfo.ht in +smc_init(); it is implicitly initialised to zero anyhow. Add +HLIST_HEAD_INIT to the definitions for clarity. + +Fixes: f16a7dd5cf27 ("smc: netlink interface for SMC sockets") +Suggested-by: Halil Pasic +Signed-off-by: Alexandra Winter +Acked-by: Halil Pasic +Reviewed-by: Mahanta Jambigi +Link: https://patch.msgid.link/20260521145639.10317-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index f744f791121776..de034a3e5d801f 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -188,10 +188,12 @@ static bool smc_hs_congested(const struct sock *sk) + + struct smc_hashinfo smc_v4_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + struct smc_hashinfo smc_v6_hashinfo = { + .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), ++ .ht = HLIST_HEAD_INIT, + }; + + int smc_hash_sk(struct sock *sk) +@@ -3522,8 +3524,6 @@ static int __init smc_init(void) + pr_err("%s: sock_register fails with %d\n", __func__, rc); + goto out_proto6; + } +- INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); +- INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); + + rc = smc_ib_register_client(); + if (rc) { +-- +2.53.0 + diff --git a/queue-7.0/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch b/queue-7.0/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch new file mode 100644 index 0000000000..48abe7a89c --- /dev/null +++ b/queue-7.0/netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch @@ -0,0 +1,107 @@ +From 0639455d3782e3bfd34565125f2225b8bfc5f607 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 22:52:07 +0200 +Subject: netfilter: ebtables: fix OOB read in compat_mtw_from_user + +From: Florian Westphal + +[ Upstream commit f438d1786d657d57790c5d138d6db3fc9fdac392 ] + +Luxiao Xu says: + + The function compat_mtw_from_user() converts ebtables extensions from + 32-bit user structures to kernel native structures. However, it lacks + proper validation of the user-supplied match_size/target_size. + + When certain extensions are processed, the kernel-side translation + logic may perform memory accesses based on the extension's expected + size. If the user provides a size smaller than what the extension + requires, it results in an out-of-bounds read as reported by KASAN. + + This fix introduces a check to ensure match_size is at least as large + as the extension's required compatsize. This covers matches, watchers, + and targets, while maintaining compatibility with standard targets. + +AFAIU this is relevant for matches that need to go though +match->compat_from_user() call. Those that use plain memcpy with the +user-provided size are ok because the caller checks that size vs the +start of the next rule entry offset (which itself is checked vs. total +size copied from userspace). + +The ->compat_from_user() callbacks assume they can read compatsize bytes, +so they need this extra check. + +Based on an earlier patch from Luxiao Xu. + +Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index b9f4daac09af36..8a6a069329d21d 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1956,6 +1956,25 @@ enum compat_mwt { + EBT_COMPAT_TARGET, + }; + ++static bool match_size_ok(const struct xt_match *match, unsigned int match_size) ++{ ++ u16 csize; ++ ++ if (match->matchsize == -1) /* cannot validate ebt_among */ ++ return true; ++ ++ csize = match->compatsize ? : match->matchsize; ++ ++ return match_size >= csize; ++} ++ ++static bool tgt_size_ok(const struct xt_target *tgt, unsigned int tgt_size) ++{ ++ u16 csize = tgt->compatsize ? : tgt->targetsize; ++ ++ return tgt_size >= csize; ++} ++ + static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + enum compat_mwt compat_mwt, + struct ebt_entries_buf_state *state, +@@ -1981,6 +2000,11 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + if (IS_ERR(match)) + return PTR_ERR(match); + ++ if (!match_size_ok(match, match_size)) { ++ module_put(match->me); ++ return -EINVAL; ++ } ++ + off = ebt_compat_match_offset(match, match_size); + if (dst) { + if (match->compat_from_user) +@@ -2000,6 +2024,12 @@ static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, + mwt->u.revision); + if (IS_ERR(wt)) + return PTR_ERR(wt); ++ ++ if (!tgt_size_ok(wt, match_size)) { ++ module_put(wt->me); ++ return -EINVAL; ++ } ++ + off = xt_compat_target_offset(wt); + + if (dst) { +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch b/queue-7.0/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch new file mode 100644 index 0000000000..95ab1209ba --- /dev/null +++ b/queue-7.0/netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch @@ -0,0 +1,141 @@ +From b0318bf07d4088b57acb7db0c691bb4f038eeeb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 16:37:56 +0200 +Subject: netfilter: nf_tables: fix dst corruption in same register operation + +From: Fernando Fernandez Mancera + +[ Upstream commit 18014147d3ee7831dce53fe65d7fc8d428b02552 ] + +For lshift and rshift, the shift operations are performed in a loop over +32-bit words. The loop calculates the shifted value and write it to dst, +and then immediately reads from src to calculate the carry for the next +iteration. Because src and dst could point to the same memory location, +the carry is incorrectly calculated using the newly modified dst value +instead of the original src value. + +Adding a temporary local variable to cache the original value before +writing to dst and using it for the carry calculation solves the +problem. In addition, partial overlap is rejected from control plane for +all kind of operations including byteorder. This was tested with the +following bytecode: + +table test_table ip flags 0 use 1 handle 1 +ip test_table test_chain use 3 type filter hook input prio 0 policy accept packets 0 bytes 0 flags 1 +ip test_table test_chain 2 + [ immediate reg 1 0x44332211 0x88776655 ] + [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ] + [ cmp eq reg 1 0x66443322 0x00887766 ] + [ counter pkts 0 bytes 0 ] +ip test_table test_chain 4 3 + [ immediate reg 1 0x44332211 0x88776655 ] + [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ] + [ cmp eq reg 1 0x55443322 0x00887766 ] + [ counter pkts 21794 bytes 1917798 ] + +Fixes: 567d746b55bc ("netfilter: bitwise: add support for shifts.") +Acked-by: Jeremy Sowden +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 7 +++++++ + net/netfilter/nft_bitwise.c | 18 ++++++++++++++---- + net/netfilter/nft_byteorder.c | 13 ++++++++++--- + 3 files changed, 31 insertions(+), 7 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index 3ec41574af776c..668b401f5147b4 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -187,6 +187,13 @@ static inline u64 nft_reg_load64(const u32 *sreg) + return get_unaligned((u64 *)sreg); + } + ++static inline bool nft_reg_overlap(u8 src, u8 dst, u32 len) ++{ ++ unsigned int n = DIV_ROUND_UP(len, sizeof(u32)); ++ ++ return src != dst && src < dst + n && dst < src + n; ++} ++ + static inline void nft_data_copy(u32 *dst, const struct nft_data *src, + unsigned int len) + { +diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c +index af990c600745be..1afb36fb5994db 100644 +--- a/net/netfilter/nft_bitwise.c ++++ b/net/netfilter/nft_bitwise.c +@@ -43,8 +43,10 @@ static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src, + u32 carry = 0; + + for (i = DIV_ROUND_UP(priv->len, sizeof(u32)); i > 0; i--) { +- dst[i - 1] = (src[i - 1] << shift) | carry; +- carry = src[i - 1] >> (BITS_PER_TYPE(u32) - shift); ++ u32 tmp_src = src[i - 1]; ++ ++ dst[i - 1] = (tmp_src << shift) | carry; ++ carry = tmp_src >> (BITS_PER_TYPE(u32) - shift); + } + } + +@@ -56,8 +58,10 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src, + u32 carry = 0; + + for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++) { +- dst[i] = carry | (src[i] >> shift); +- carry = src[i] << (BITS_PER_TYPE(u32) - shift); ++ u32 tmp_src = src[i]; ++ ++ dst[i] = carry | (tmp_src >> shift); ++ carry = tmp_src << (BITS_PER_TYPE(u32) - shift); + } + } + +@@ -235,6 +239,9 @@ static int nft_bitwise_init_bool(const struct nft_ctx *ctx, + &priv->sreg2, priv->len); + if (err < 0) + return err; ++ ++ if (nft_reg_overlap(priv->sreg2, priv->dreg, priv->len)) ++ return -EINVAL; + } + + return 0; +@@ -265,6 +272,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, + if (err < 0) + return err; + ++ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len)) ++ return -EINVAL; ++ + if (tb[NFTA_BITWISE_OP]) { + priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])); + switch (priv->op) { +diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c +index af9206a3afd181..5e7a7841b789b0 100644 +--- a/net/netfilter/nft_byteorder.c ++++ b/net/netfilter/nft_byteorder.c +@@ -144,9 +144,16 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, + if (err < 0) + return err; + +- return nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG], +- &priv->dreg, NULL, NFT_DATA_VALUE, +- priv->len); ++ err = nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG], ++ &priv->dreg, NULL, NFT_DATA_VALUE, ++ priv->len); ++ if (err < 0) ++ return err; ++ ++ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len)) ++ return -EINVAL; ++ ++ return 0; + } + + static int nft_byteorder_dump(struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-7.0/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch b/queue-7.0/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch new file mode 100644 index 0000000000..83279b2f5e --- /dev/null +++ b/queue-7.0/netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch @@ -0,0 +1,68 @@ +From 3785b183ff1f658fab7f65a5e55794ca86ec561a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 12:36:14 -0700 +Subject: netfilter: synproxy: refresh tcphdr after skb_ensure_writable + +From: Chris Mason + +[ Upstream commit 92170e6afe927ab2792a3f71902845789c8e31b1 ] + +synproxy_tstamp_adjust() rewrites the TCP timestamp option in place +and then patches the TCP checksum via inet_proto_csum_replace4() on +the caller-supplied tcphdr pointer. Both ipv4_synproxy_hook() and +ipv6_synproxy_hook() obtain that pointer with skb_header_pointer() +before calling in, so it may either alias skb->head directly or +point at the caller's on-stack _tcph buffer. + +Between obtaining the pointer and using it, the function calls +skb_ensure_writable(skb, optend), which on a cloned or non-linear +skb invokes pskb_expand_head() and frees the old skb->head. After +that point the cached th is stale: + + caller (ipv[46]_synproxy_hook) + th = skb_header_pointer(skb, ..., &_tcph) + synproxy_tstamp_adjust(skb, protoff, th, ...) + skb_ensure_writable(skb, optend) + pskb_expand_head() /* kfree(old skb->head) */ + ... + inet_proto_csum_replace4(&th->check, ...) + /* writes into freed head, or + into the caller's stack copy + leaving the on-wire checksum + stale */ + +The option bytes are written through skb->data and are fine; only +the checksum update goes through th and so lands in the wrong +place. The result is either a write into freed slab memory or a +packet leaving with a checksum that does not match its payload. + +Fix by re-deriving th from skb->data + protoff immediately after +skb_ensure_writable() succeeds, so the subsequent checksum update +targets the linear, writable header. + +Fixes: 48b1de4c110a ("netfilter: add SYNPROXY core/target") +Assisted-by: kres (claude-opus-4-7) +Signed-off-by: Chris Mason +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_synproxy_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c +index 57f57e2fc80a8f..036c8586f49b75 100644 +--- a/net/netfilter/nf_synproxy_core.c ++++ b/net/netfilter/nf_synproxy_core.c +@@ -200,6 +200,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + if (skb_ensure_writable(skb, optend)) + return 0; + ++ th = (struct tcphdr *)(skb->data + protoff); ++ + while (optoff < optend) { + unsigned char *op = skb->data + optoff; + +-- +2.53.0 + diff --git a/queue-7.0/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch b/queue-7.0/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch new file mode 100644 index 0000000000..fb162bbeb5 --- /dev/null +++ b/queue-7.0/netfilter-xt_cpu-prefer-raw_smp_processor_id.patch @@ -0,0 +1,48 @@ +From 64d259f9aff2371b33a3782e01d2a5a6db547288 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 20:10:08 +0200 +Subject: netfilter: xt_cpu: prefer raw_smp_processor_id + +From: Florian Westphal + +[ Upstream commit c376f07e16c02239ed44cabb97145d03f65b4d15 ] + +With PREEMPT_RCU we get splat: + +BUG: using smp_processor_id() in preemptible [..] +caller is cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 +CPU: 1 .. Comm: syz.3.1377 #0 PREEMPT(full) +Call Trace: + + dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 + check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 + cpu_mt+0x53/0xd0 net/netfilter/xt_cpu.c:37 + [..] + +Just use raw version instead. +This is similar to 14d14a5d2957 ("netfilter: nft_meta: use raw_smp_processor_id()"). + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reported-by: syzbot+690d3e3ffa7335ac10eb@syzkaller.appspotmail.com +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c +index 3bdc302a0f9137..9cb259902a586b 100644 +--- a/net/netfilter/xt_cpu.c ++++ b/net/netfilter/xt_cpu.c +@@ -34,7 +34,7 @@ static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_cpu_info *info = par->matchinfo; + +- return (info->cpu == smp_processor_id()) ^ info->invert; ++ return (info->cpu == raw_smp_processor_id()) ^ info->invert; + } + + static struct xt_match cpu_mt_reg __read_mostly = { +-- +2.53.0 + diff --git a/queue-7.0/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch b/queue-7.0/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch new file mode 100644 index 0000000000..a252d90bd5 --- /dev/null +++ b/queue-7.0/nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch @@ -0,0 +1,40 @@ +From 57f7005d37edd17fb90150d2bbe5146cdfc5a0a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:41 +0000 +Subject: nfc: llcp: Fix use-after-free in llcp_sock_release() + +From: Lee Jones + +[ Upstream commit f4268b466190dae95a7585f69b4f1f8ad097632c ] + +llcp_sock_release() unconditionally unlinks the socket from the local +sockets list. However, if the socket is still in connecting state, it +is on the connecting list. + +Fix this by checking the socket state and unlinking from the correct list. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Signed-off-by: Lee Jones +Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index f1be1e84f66537..feab29fc62f44b 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -633,6 +633,8 @@ static int llcp_sock_release(struct socket *sock) + + if (sock->type == SOCK_RAW) + nfc_llcp_sock_unlink(&local->raw_sockets, sk); ++ else if (sk->sk_state == LLCP_CONNECTING) ++ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + else + nfc_llcp_sock_unlink(&local->sockets, sk); + +-- +2.53.0 + diff --git a/queue-7.0/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch b/queue-7.0/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch new file mode 100644 index 0000000000..457c39d3c2 --- /dev/null +++ b/queue-7.0/nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch @@ -0,0 +1,67 @@ +From 6a7ed01eb4ecf4efdae29a44fd4ded9f6176a9dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:40:42 +0000 +Subject: nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() + +From: Lee Jones + +[ Upstream commit b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 ] + +A race condition exists in the NFC LLCP connection state machine where +the connection acceptance packet (CC) can be processed concurrently with +socket release. This can lead to a use-after-free of the socket object. + +When nfc_llcp_recv_cc() moves the socket from the connecting_sockets +list to the sockets list, it does so without holding the socket lock. +If llcp_sock_release() is executing concurrently, it might have already +unlinked the socket and dropped its references, which can result in +nfc_llcp_recv_cc() linking a freed socket into the live list. + +Fix this by holding lock_sock() during the state transition and list +movement in nfc_llcp_recv_cc(). After acquiring the lock, check if +the socket is still hashed to ensure it hasn't already been unlinked +and marked for destruction by the release path. This aligns the locking +pattern with recv_hdlc() and recv_disc(). + +Fixes: a69f32af86e3 ("NFC: Socket linked list") +Signed-off-by: Lee Jones +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + net/nfc/llcp_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index db5bc6a878ddb0..dc65c719f35f2e 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -1218,6 +1218,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + + sk = &llcp_sock->sk; + ++ lock_sock(sk); ++ ++ /* Check if socket was destroyed whilst waiting for the lock */ ++ if (!sk_hashed(sk)) { ++ release_sock(sk); ++ nfc_llcp_sock_put(llcp_sock); ++ return; ++ } ++ + /* Unlink from connecting and link to the client array */ + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + nfc_llcp_sock_link(&local->sockets, sk); +@@ -1229,6 +1238,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + ++ release_sock(sk); ++ + nfc_llcp_sock_put(llcp_sock); + } + +-- +2.53.0 + diff --git a/queue-7.0/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch b/queue-7.0/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch new file mode 100644 index 0000000000..4449a2e534 --- /dev/null +++ b/queue-7.0/nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch @@ -0,0 +1,83 @@ +From 2ebff846067468486d15be8295548ed5de7caaa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 May 2026 19:55:18 +0800 +Subject: nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems + +From: Carl Lee + +[ Upstream commit f23bf992d65a42007c517b060ca35cebdea3525a ] + +Some ACPI-based platforms report incorrect IRQ trigger types (e.g. +IRQF_TRIGGER_HIGH), which can lead to interrupt storms. + +Use the historically working rising-edge trigger on ACPI systems to +avoid this regression. + +Device Tree-based systems continue to use the firmware-provided +trigger type. + +Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") +Signed-off-by: Carl Lee +Tested-by: Bartosz Golaszewski +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Mark Pearson +Tested-by: Mark Pearson +Tested-by: Luca Stefani +Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com +Signed-off-by: David Heidelberg +Signed-off-by: Sasha Levin +--- + drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index b3d34433bd14a0..a6c08175d9dd93 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -267,6 +268,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + { + struct device *dev = &client->dev; + struct nxp_nci_i2c_phy *phy; ++ unsigned long irqflags; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +@@ -303,9 +305,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) + if (r < 0) + return r; + ++ /* ++ * ACPI platforms may report incorrect IRQ trigger types ++ * (e.g. level-high), which can lead to interrupt storms. ++ * ++ * Use the historically stable rising-edge trigger for ACPI devices. ++ * ++ * On non-ACPI systems (e.g. Device Tree), prefer the firmware- ++ * provided trigger type, falling back to rising-edge if not set. ++ */ ++ if (ACPI_COMPANION(dev)) { ++ irqflags = IRQF_TRIGGER_RISING; ++ } else { ++ irqflags = irq_get_trigger_type(client->irq); ++ if (!irqflags) ++ irqflags = IRQF_TRIGGER_RISING; ++ } ++ + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, +- IRQF_ONESHOT, ++ irqflags | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); +-- +2.53.0 + diff --git a/queue-7.0/nvme-tcp-store-negative-errno-in-queue-tls_err.patch b/queue-7.0/nvme-tcp-store-negative-errno-in-queue-tls_err.patch new file mode 100644 index 0000000000..88c0865c8a --- /dev/null +++ b/queue-7.0/nvme-tcp-store-negative-errno-in-queue-tls_err.patch @@ -0,0 +1,52 @@ +From 9ccafa4254a63ef89313fd285189fef0703166dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 12:51:16 -0400 +Subject: nvme-tcp: store negative errno in queue->tls_err + +From: Chuck Lever + +[ Upstream commit 9015985b5eb1a90eb86caf5bce1dfcf1aa38f8ad ] + +nvme_tcp_tls_done() assigns queue->tls_err in three branches. The +ENOKEY lookup failure and the EOPNOTSUPP initializer both store +negative errnos. The third branch, reached when the handshake +layer reports a non-zero status, stores -status. + +The handshake layer delivers status to the consumer callback as a +negative errno; the other in-tree consumers -- +xs_tls_handshake_done() and the nvmet target callback -- treat +their status argument that way. The extra negation in +nvme_tcp_tls_done() flips the sign, leaving tls_err as a positive +value (for instance, +EIO), which nvme_tcp_start_tls() then +returns to its caller. + +Drop the extra negation so queue->tls_err uniformly carries a +negative errno on failure. + +Fixes: be8e82caa685 ("nvme-tcp: enable TLS handshake upcall") +Signed-off-by: Chuck Lever +Reviewed-by: Hannes Reinecke +Reviewed-by: Alistair Francis +Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-2-66c616906ead@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/tcp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 243dab830dc84f..29f9ba0bdd3f1e 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1688,7 +1688,7 @@ static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid) + qid, pskid, status); + + if (status) { +- queue->tls_err = -status; ++ queue->tls_err = status; + goto out_complete; + } + +-- +2.53.0 + diff --git a/queue-7.0/revert-ipv6-preserve-insertion-order-for-same-scope-.patch b/queue-7.0/revert-ipv6-preserve-insertion-order-for-same-scope-.patch new file mode 100644 index 0000000000..9020aff3ed --- /dev/null +++ b/queue-7.0/revert-ipv6-preserve-insertion-order-for-same-scope-.patch @@ -0,0 +1,67 @@ +From 7f947d9ded5a08fd174b0011c86c6f8daa2afba8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 May 2026 13:23:57 +0200 +Subject: Revert "ipv6: preserve insertion order for same-scope addresses" + +From: Fernando Fernandez Mancera + +[ Upstream commit 072aa0f5c3d8f11f3159037418ec45edce7440b8 ] + +Chris Adams reported that preserving insertion order for same-scope +addresses is causing SSH connections to be dropped after stopping a VM +while running NetworkManager. + +NetworkManager caches the IPv6 address configuration, when a RA arrives, +it determines the list of addresses to configure and checks if the +addresses are already in the right order in the kernel. If they aren't, +NetworkManager removes and re-adds them to achieve the desired order. + +As the order changes, NetworkManager is confused and reconfigures the +addresses on every update. In addition, this would also affect to cloud +tooling that relies on IPv6 addresses order to identify primary and +secondaries addresses. + +This reverts commit cb3de96eea66f5e4a580086c6a1be46e765f97f4. + +Fixes: cb3de96eea66 ("ipv6: preserve insertion order for same-scope addresses") +Reported-by: Chris Adams +Closes: https://lore.kernel.org/netdev/20260521135310.GC977@cmadams.net/ +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260529112357.5079-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 2 +- + tools/testing/selftests/net/ioam6.sh | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index dd0b4d80e0f84d..e5276be71062a3 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1012,7 +1012,7 @@ ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) + list_for_each(p, &idev->addr_list) { + struct inet6_ifaddr *ifa + = list_entry(p, struct inet6_ifaddr, if_list); +- if (ifp_scope > ipv6_addr_src_scope(&ifa->addr)) ++ if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr)) + break; + } + +diff --git a/tools/testing/selftests/net/ioam6.sh b/tools/testing/selftests/net/ioam6.sh +index b2b99889942f75..845c26dd01a932 100755 +--- a/tools/testing/selftests/net/ioam6.sh ++++ b/tools/testing/selftests/net/ioam6.sh +@@ -273,8 +273,8 @@ setup() + ip -netns $ioam_node_beta link set ioam-veth-betaR name veth1 &>/dev/null + ip -netns $ioam_node_gamma link set ioam-veth-gamma name veth0 &>/dev/null + +- ip -netns $ioam_node_alpha addr add 2001:db8:1::2/64 dev veth0 &>/dev/null + ip -netns $ioam_node_alpha addr add 2001:db8:1::50/64 dev veth0 &>/dev/null ++ ip -netns $ioam_node_alpha addr add 2001:db8:1::2/64 dev veth0 &>/dev/null + ip -netns $ioam_node_alpha link set veth0 up &>/dev/null + ip -netns $ioam_node_alpha link set lo up &>/dev/null + ip -netns $ioam_node_alpha route add 2001:db8:2::/64 \ +-- +2.53.0 + diff --git a/queue-7.0/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch b/queue-7.0/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch new file mode 100644 index 0000000000..cfccb90f5e --- /dev/null +++ b/queue-7.0/scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch @@ -0,0 +1,80 @@ +From ada4b76d8603ae226ddb79d6f868822cb9969dd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 14:09:41 -0400 +Subject: scsi: core: Run queues for all non-SDEV_DEL devices from + scsi_run_host_queues + +From: David Jeffery + +[ Upstream commit 7205b58702273baf21d6ba7992e6ba15852325f7 ] + +While a SCSI host is in a recovery state, scsi_mq_requeue_cmd() will not +set the requeue list for a requeued command to be kicked in the future. +The expectation is a call to scsi_run_host_queues() will kick all SCSI +devices once the recovery state is cleared. + +However, scsi_run_host_queues() uses shost_for_each_device() which uses +scsi_device_get() and so will ignore devices in a partially removed +state like SDEV_CANCEL. But these devices may also have requeued +requests, leaving their requests stuck from not being kicked and causing +the removal process of the device to hang. + +scsi_run_host_queues() needs to run against more devices than the macro +shost_for_each_device() allows. Instead of using the too limiting +scsi_device_get() state checks, only ignore devices in SDEV_DEL state or +when unable to acquire a reference. Attempt to run the queues for all +other devices when scsi_run_host_queues() is called. + +Fixes: 8b566edbdbfb ("scsi: core: Only kick the requeue list if necessary") +Signed-off-by: David Jeffery +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260515180941.9698-1-djeffery@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/scsi_lib.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index d3a8cd4166f92f..1da52f07d299b5 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -574,10 +574,33 @@ void scsi_requeue_run_queue(struct work_struct *work) + + void scsi_run_host_queues(struct Scsi_Host *shost) + { +- struct scsi_device *sdev; ++ struct scsi_device *sdev, *prev = NULL; ++ unsigned long flags; + +- shost_for_each_device(sdev, shost) ++ spin_lock_irqsave(shost->host_lock, flags); ++ __shost_for_each_device(sdev, shost) { ++ /* ++ * Only skip devices so deep into removal they will never need ++ * another kick to their queues. Thus scsi_device_get() cannot ++ * be used as it would skip devices in SDEV_CANCEL state which ++ * may need a queue kick. ++ */ ++ if (sdev->sdev_state == SDEV_DEL || ++ !get_device(&sdev->sdev_gendev)) ++ continue; ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ ++ if (prev) ++ put_device(&prev->sdev_gendev); + scsi_run_queue(sdev->request_queue); ++ ++ prev = sdev; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ if (prev) ++ put_device(&prev->sdev_gendev); + } + + static void scsi_uninit_cmd(struct scsi_cmnd *cmd) +-- +2.53.0 + diff --git a/queue-7.0/scsi-scsi_debug-add-missing-newline-in-scsi_debug_de.patch b/queue-7.0/scsi-scsi_debug-add-missing-newline-in-scsi_debug_de.patch new file mode 100644 index 0000000000..749b1cccc4 --- /dev/null +++ b/queue-7.0/scsi-scsi_debug-add-missing-newline-in-scsi_debug_de.patch @@ -0,0 +1,40 @@ +From 45613a00a0a2105166c48868e17596aa6ae4edbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 May 2026 16:53:56 -0400 +Subject: scsi: scsi_debug: Add missing newline in scsi_debug_device_reset() + +From: Ewan D. Milne + +[ Upstream commit e4bb73bf3ac11b4a93634660345b9d764a4a80df ] + +A "\n" at the end of the sdev_printk() string appears to have been +inadvertently removed. Add it back for correct log message formatting. + +Fixes: a743b120227a ("scsi: scsi_debug: Stop printing extra function name in debug logs") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Ewan D. Milne +Reviewed-by: Bart Van Assche +Reviewed-by: John Garry +Link: https://patch.msgid.link/20260519205356.1040855-1-emilne@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/scsi_debug.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c +index 1515495fd9ea7e..040c5e1e713a2e 100644 +--- a/drivers/scsi/scsi_debug.c ++++ b/drivers/scsi/scsi_debug.c +@@ -6953,7 +6953,7 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) + ++num_dev_resets; + + if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) +- sdev_printk(KERN_INFO, sdp, "doing device reset"); ++ sdev_printk(KERN_INFO, sdp, "doing device reset\n"); + + scsi_debug_stop_all_queued(sdp); + if (devip) { +-- +2.53.0 + diff --git a/queue-7.0/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch b/queue-7.0/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch new file mode 100644 index 0000000000..b8dbebca8e --- /dev/null +++ b/queue-7.0/sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch @@ -0,0 +1,50 @@ +From 7946fa974b54dec0de9c545a2d82fbcde4b5abe7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 11:24:11 +0800 +Subject: sctp: fix race between sctp_wait_for_connect and peeloff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit f14fe6395a8b3d961a61e138ad7b36ba3626dd4e ] + +sctp_wait_for_connect() drops and re-acquires the socket lock while +waiting for the association to reach ESTABLISHED state. During this +window, another thread can peeloff the association to a new socket via +getsockopt(SCTP_SOCKOPT_PEELOFF), changing asoc->base.sk. After +re-acquiring the old socket lock, sctp_wait_for_connect() returns +success without noticing the migration — the caller then accesses +the association under the wrong lock in sctp_datamsg_from_user(). + +Add the same sk != asoc->base.sk check that sctp_wait_for_sndbuf() +already has, returning an error if the association was migrated while +we slept. + +Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") +Signed-off-by: Zhenghang Xiao +Acked-by: Xin Long +Link: https://patch.msgid.link/20260527032411.60959-1-kipreyyy@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index aeffa10ff2d34a..59e04788e1c760 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9403,6 +9403,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) + release_sock(sk); + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + + *timeo_p = current_timeo; + } +-- +2.53.0 + diff --git a/queue-7.0/series b/queue-7.0/series index 646d508915..00227d5d0b 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -3,3 +3,110 @@ acpi-button-enable-wakeup-gpes-for-acpi-buttons-at-p.patch xfrm-move-policy_bydst-rcu-sync-from-per-netns-.exit.patch net-sched-sch_sfb-replace-direct-dequeue-call-with-p.patch bcache-fix-uninitialized-closure-object.patch +nfc-llcp-fix-use-after-free-in-llcp_sock_release.patch +nfc-llcp-fix-use-after-free-race-in-nfc_llcp_recv_cc.patch +xfrm-check-for-underflow-in-xfrm_state_mtu.patch +nfc-nxp-nci-i2c-use-rising-edge-irq-on-acpi-systems.patch +tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch +hid-remove-duplicate-hid_warn_ratelimited-definition.patch +kunit-fix-use-after-free-in-debugfs-when-using-kunit.patch +accel-rocket-fix-uaf-via-dangling-gem-handle-in-crea.patch +kernel-fork-validate-exit_signal-in-kernel_clone.patch +esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch +netfilter-synproxy-refresh-tcphdr-after-skb_ensure_w.patch +netfilter-xt_cpu-prefer-raw_smp_processor_id.patch +netfilter-ebtables-fix-oob-read-in-compat_mtw_from_u.patch +netfilter-nf_tables-fix-dst-corruption-in-same-regis.patch +tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch +tap-free-page-on-error-paths-in-tap_get_user_xdp.patch +tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch +vsock-keep-poll-shutdown-state-consistent.patch +net-netlink-fix-sending-unassigned-nsid-after-assign.patch +net-netlink-don-t-set-nsid-on-local-notifications.patch +net-smc-do-not-re-initialize-smc-hashtables.patch +net-iucv-fix-locking-in-.getsockopt.patch +scsi-core-run-queues-for-all-non-sdev_del-devices-fr.patch +scsi-scsi_debug-add-missing-newline-in-scsi_debug_de.patch +ipv4-free-net-ipv4.sysctl_local_reserved_ports-after.patch +alsa-hda-cs35l56-fix-system-name-string-leaks.patch +alsa-pcm-oss-fix-setup-list-uaf-on-proc-write-error.patch +asoc-intel-bytcht_es8316-fix-mclk-leak-on-init-error.patch +net-mlx5-hws-reject-unsupported-remove-header-action.patch +net-hsr-fix-potential-oob-access-in-supervision-fram.patch +accel-ivpu-prevent-uninitialized-data-bug-in-debugfs.patch +gpio-mxc-fix-irq_high-handling.patch +drm-i915-aux-use-polling-when-irqs-are-unavailable.patch +net-avoid-checksumming-unreadable-skb-tail-on-trim.patch +ethtool-rss-avoid-modifying-the-rss-context-response.patch +ethtool-rss-add-missing-errno-on-rss-context-delete.patch +ethtool-rss-fix-falsely-ignoring-indir-table-updates.patch +ethtool-rss-fix-indir_table-and-hkey-leak-on-get_rxf.patch +ethtool-rss-fix-hkey-leak-when-indir_size-is-0.patch +ethtool-rss-avoid-device-context-leak-on-reply-build.patch +ethtool-module-call-ethnl_ops_complete-on-module-fla.patch +ethtool-module-avoid-leaking-a-netdev-ref-on-module-.patch +ethtool-module-avoid-racy-updates-to-dev-ethtool-bit.patch +ethtool-module-check-fw_flash_in_progress-under-rtnl.patch +ethtool-module-fix-cleanup-if-socket-used-for-flashi.patch +ethtool-cmis-require-exact-cdb-reply-length.patch +ethtool-cmis-fix-u16-to-u8-truncation-of-msleep_pre_.patch +ethtool-cmis-validate-start_cmd_payload_size-from-mo.patch +ethtool-cmis-validate-fw-size-against-start_cmd_payl.patch +cxl-test-update-mock-dev-array-before-calling-platfo.patch +blk-mq-reinsert-cached-request-to-the-list.patch +tunnels-load-network-headers-after-skb_cow-in-iptunn.patch +vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch +tunnels-do-not-assume-transport-header-in-iptunnel_p.patch +ksmbd-fix-fsctl-permission-bypass-by-adding-a-permis.patch +asoc-codecs-simple-mux-fix-enum-control-bounds-check.patch +drm-xe-restore-idledly-regiter-on-engine-reset.patch +bluetooth-6lowpan-check-skb_clone-return-value-in-se.patch +bonding-refuse-to-enslave-can-devices.patch +bridge-fix-sleep-in-atomic-context-in-netlink-path.patch +bridge-fix-sleep-in-atomic-context-in-sysfs-path.patch +ethtool-coalesce-cap-profile-updates-at-net_dim_para.patch +ethtool-tsconfig-fix-reply-error-handling.patch +ethtool-linkstate-fix-unbalanced-ethnl_ops_complete-.patch +ethtool-pse-pd-fix-missing-ethnl_ops_complete.patch +ethtool-tsconfig-fix-missing-ethnl_ops_complete.patch +ethtool-tsinfo-fix-uninitialized-stats-on-the-by-phc.patch +ethtool-tsinfo-don-t-pass-err_ptr-to-genlmsg_cancel-.patch +ethtool-strset-fix-header-attribute-index-in-ethnl_r.patch +ethtool-eeprom-add-missing-ethnl_ops_begin-_complete.patch +ethtool-eeprom-add-more-safeties-to-eeprom-netlink-f.patch +ipv6-rpl-fix-hdrlen-overflow-in-ipv6_rpl_srh_decompr.patch +net-sched-revert-net-sched-restrict-conditions-for-a.patch +net-sched-fix-packet-loop-on-netem-when-duplicate-is.patch +net-introduce-skb-tc-depth-field-to-track-packet-loo.patch +net-sched-fix-ethx-ingress-ethy-egress-ethx-ingress-.patch +net-sched-act_mirred-fix-blockcast-recursion-bypass-.patch +net-sched-act_mirred-fix-return-code-in-early-mirred.patch +net-hibmcge-disable-relaxed-ordering-to-fix-rx-packe.patch +net-hibmcge-move-dma_rmb-after-dma_sync_single_for_c.patch +net-handshake-use-spin_lock_bh-for-hn_lock.patch +nvme-tcp-store-negative-errno-in-queue-tls_err.patch +net-handshake-pass-negative-errno-through-handshake_.patch +net-handshake-hand-off-the-pinned-file-reference-to-.patch +net-handshake-take-a-long-lived-file-reference-at-su.patch +net-handshake-drain-pending-requests-at-net-namespac.patch +dpll-zl3073x-detect-dpll-channel-count-from-chip-id-.patch +dpll-zl3073x-add-die-temperature-reporting-for-suppo.patch +dpll-export-__dpll_device_change_ntf-for-use-under-d.patch +dpll-zl3073x-use-__dpll_device_change_ntf-and-remove.patch +bluetooth-l2cap-clear-chan-ident-on-ecred-reconfigur.patch +bluetooth-l2cap-fix-possible-crash-on-l2cap_ecred_co.patch +bluetooth-hci_sync-set-hci_cmd_drain_workqueue-durin.patch +bluetooth-hci_sync-reset-device-counters-in-hci_dev_.patch +gpio-adnp-fix-flow-control-regression-caused-by-scop.patch +gpio-virtuser-fix-uninitialized-data-bug-in-gpio_vir.patch +gpio-rockchip-convert-bank-clk-to-devm_clk_get_enabl.patch +gpio-rockchip-teardown-bugs-and-resource-leaks.patch +net-mana-add-null-guards-in-teardown-path-to-prevent.patch +net-mana-skip-redundant-detach-on-already-detached-p.patch +sctp-fix-race-between-sctp_wait_for_connect-and-peel.patch +net-pcs-pcs-mtk-lynxi-fix-bpi-r3-serdes-configuratio.patch +vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch +ipv6-fix-possible-infinite-loop-in-rt6_fill_node.patch +ipv6-fix-possible-infinite-loop-in-fib6_select_path.patch +net-skbuff-fix-pskb_carve-leaking-zcopy-pages.patch +revert-ipv6-preserve-insertion-order-for-same-scope-.patch diff --git a/queue-7.0/tap-free-page-on-error-paths-in-tap_get_user_xdp.patch b/queue-7.0/tap-free-page-on-error-paths-in-tap_get_user_xdp.patch new file mode 100644 index 0000000000..702514d66c --- /dev/null +++ b/queue-7.0/tap-free-page-on-error-paths-in-tap_get_user_xdp.patch @@ -0,0 +1,55 @@ +From 192848b7e150e475aa938b298842ebb047bb1441 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 09:32:31 -0700 +Subject: tap: free page on error paths in tap_get_user_xdp() + +From: Weiming Shi + +[ Upstream commit 3bcf7aec6a9d16438f2cec29f5d7c8d5b8edf9b2 ] + +tap_get_user_xdp() rejects a frame shorter than ETH_HLEN with -EINVAL, +and returns -ENOMEM when build_skb() fails. Both paths jump to the err +label without freeing the page that vhost_net_build_xdp() allocated for +the frame. tap_sendmsg() discards the per-buffer return value and always +returns 0, so vhost_tx_batch() takes the success path and never frees +the page; each rejected frame in a batch leaks one page-frag chunk. + +Free the page on both error paths, before the skb is built. This is the +tap counterpart of the same leak in tun_xdp_one(). + +Fixes: 0efac27791ee ("tap: accept an array of XDP buffs through sendmsg()") +Fixes: ed7f2afdd0e0 ("tap: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260521163230.1478627-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tap.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/tap.c b/drivers/net/tap.c +index a590e07ce0a98c..fae115915c8eff 100644 +--- a/drivers/net/tap.c ++++ b/drivers/net/tap.c +@@ -1052,6 +1052,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) + int err, depth; + + if (unlikely(xdp->data_end - xdp->data < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + err = -EINVAL; + goto err; + } +@@ -1061,6 +1062,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) + + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { ++ put_page(virt_to_head_page(xdp->data)); + err = -ENOMEM; + goto err; + } +-- +2.53.0 + diff --git a/queue-7.0/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch b/queue-7.0/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch new file mode 100644 index 0000000000..18122f1ea2 --- /dev/null +++ b/queue-7.0/tools-bootconfig-fix-buf-leaks-in-apply_xbc.patch @@ -0,0 +1,40 @@ +From ad672bdf9ef924e2b57c79efd27a32e823af81a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 11:01:26 +0800 +Subject: tools/bootconfig: Fix buf leaks in apply_xbc + +From: Hongtao Lee + +[ Upstream commit f42d01aadcedd7bbf4f9a466cabe25c1781dedad ] + +If data calloc failed, free the buf before return. + +Link: https://lore.kernel.org/all/20260520030126.147782-1-lihongtao@kylinos.cn/ + +Fixes: 950313ebf79c ("tools: bootconfig: Add bootconfig command") +Signed-off-by: Hongtao Lee +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + tools/bootconfig/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c +index 643f707b8f1da1..ddabde20585f21 100644 +--- a/tools/bootconfig/main.c ++++ b/tools/bootconfig/main.c +@@ -390,8 +390,10 @@ static int apply_xbc(const char *path, const char *xbc_path) + + /* Backup the bootconfig data */ + data = calloc(size + BOOTCONFIG_ALIGN + BOOTCONFIG_FOOTER_SIZE, 1); +- if (!data) ++ if (!data) { ++ free(buf); + return -ENOMEM; ++ } + memcpy(data, buf, size); + + /* Check the data format */ +-- +2.53.0 + diff --git a/queue-7.0/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch b/queue-7.0/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch new file mode 100644 index 0000000000..eb6da27387 --- /dev/null +++ b/queue-7.0/tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch @@ -0,0 +1,47 @@ +From 460801af0941c4e69c20b9c35fc6cf3780737583 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 May 2026 09:33:13 -0700 +Subject: tun: free page on build_skb failure in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit aa8963fdce667a42fb7f0bdd2909fadcab02f9a8 ] + +When build_skb() fails in tun_xdp_one(), the function sets ret to +-ENOMEM and jumps to the out label, which returns without freeing the +page that vhost_net_build_xdp() allocated for the frame. As with the +short-frame rejection path, tun_sendmsg() discards the per-buffer error +and still returns total_len, so vhost_tx_batch() takes the success path +and never frees the page. Each build_skb() failure in a batch leaks one +page-frag chunk. + +Free the page before taking the error path, matching the put_page() the +other error exits of tun_xdp_one() already perform. + +Fixes: 043d222f93ab ("tuntap: accept an array of XDP buffs through sendmsg()") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260521163312.1479805-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 8154d18a2a235a..ca0ae5df73af78 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2437,6 +2437,7 @@ static int tun_xdp_one(struct tun_struct *tun, + build: + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { ++ put_page(virt_to_head_page(xdp->data)); + ret = -ENOMEM; + goto out; + } +-- +2.53.0 + diff --git a/queue-7.0/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch b/queue-7.0/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch new file mode 100644 index 0000000000..2213f01c25 --- /dev/null +++ b/queue-7.0/tun-free-page-on-short-frame-rejection-in-tun_xdp_on.patch @@ -0,0 +1,54 @@ +From f8ab9d7ffb13bb41e1dfb509ba278090aa062bd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 09:00:21 -0700 +Subject: tun: free page on short-frame rejection in tun_xdp_one() + +From: Weiming Shi + +[ Upstream commit f4feb1e20058e407cb00f45aff47f5b7e19a6bbf ] + +tun_xdp_one() returns -EINVAL on a frame shorter than ETH_HLEN without +freeing the page that vhost_net_build_xdp() allocated for it. +tun_sendmsg() discards that -EINVAL and still returns total_len, so +vhost_tx_batch() takes the success path and never frees the page; each +short frame in a batch leaks one page-frag chunk. + +A local process that can open /dev/net/tun and /dev/vhost-net can hit +this path: it attaches a tun/tap device as the vhost-net backend and +feeds TX descriptors whose length minus the virtio-net header is below +ETH_HLEN. Each kick leaks the page-frag chunks for that batch, and a +tight submission loop exhausts host memory and triggers an OOM panic. +Free the page before returning -EINVAL, matching the XDP-program error +path in the same function. + +Fixes: 049584807f1d ("tun: add missing verification for short frame") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Dongli Zhang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260520160020.375349-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index c492fda6fc15a7..8154d18a2a235a 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2392,8 +2392,10 @@ static int tun_xdp_one(struct tun_struct *tun, + bool skb_xdp = false; + struct page *page; + +- if (unlikely(datasize < ETH_HLEN)) ++ if (unlikely(datasize < ETH_HLEN)) { ++ put_page(virt_to_head_page(xdp->data)); + return -EINVAL; ++ } + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { +-- +2.53.0 + diff --git a/queue-7.0/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch b/queue-7.0/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch new file mode 100644 index 0000000000..f9c5d6e215 --- /dev/null +++ b/queue-7.0/tunnels-do-not-assume-transport-header-in-iptunnel_p.patch @@ -0,0 +1,67 @@ +From 4e29eefbf913240fd13aba9d2b510f5b036e0950 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 May 2026 11:55:12 +0000 +Subject: tunnels: do not assume transport header in + iptunnel_pmtud_check_icmp() + +From: Eric Dumazet + +[ Upstream commit 509323077ef79a26ba0c60bb556e45c12c398b2d ] + +In some cases, iptunnel_pmtud_check_icmp() can be called while +skb transport header is not set. + +This triggers an out-of-bound access, because +(typeof(skb->transport_header))~0U is 65535. + +Access the icmp header based on IPv4 network header, +after making sure icmp->type is present in skb linear part. + +Note that iptunnel_pmtud_check_icmpv6()) is fine. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Reported-by: Damiano Melotti +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index a52ba6f671fedf..fc993c78cbcc5e 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -280,7 +280,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + { +- const struct icmphdr *icmph = icmp_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); + + if (mtu < 576 || iph->frag_off != htons(IP_DF)) +@@ -291,9 +290,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr)) + return 0; + +- if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type)) +- return 0; ++ if (iph->protocol == IPPROTO_ICMP) { ++ const struct icmphdr *icmph; + ++ if (!pskb_network_may_pull(skb, iph->ihl * 4 + ++ offsetofend(struct icmphdr, type))) ++ return 0; ++ iph = ip_hdr(skb); ++ icmph = (void *)iph + iph->ihl * 4; ++ if (icmp_is_err(icmph->type)) ++ return 0; ++ } + return iptunnel_pmtud_build_icmp(skb, mtu); + } + +-- +2.53.0 + diff --git a/queue-7.0/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch b/queue-7.0/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch new file mode 100644 index 0000000000..0f5fc2faa0 --- /dev/null +++ b/queue-7.0/tunnels-load-network-headers-after-skb_cow-in-iptunn.patch @@ -0,0 +1,87 @@ +From e02a263f36925bf91e85998209cad8cc1e2f6841 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:13:35 +0000 +Subject: tunnels: load network headers after skb_cow() in + iptunnel_pmtud_build_icmp[v6]() + +From: Eric Dumazet + +[ Upstream commit b4bc94353050b1fa7b702bd4c6600710dd926cff ] + +Sashiko found that iptunnel_pmtud_build_icmp() and +iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr() +before an skb_cow() call which can reallocate skb->head. + +Fix this possible UAF by initializing the local variables +after the skb_cow() call. + +Remove skb_reset_network_header() calls which were not needed. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_tunnel_core.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index f430d6f0463e7a..a52ba6f671fedf 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -212,7 +212,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + */ + static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + { +- const struct iphdr *iph = ip_hdr(skb); ++ const struct iphdr *iph; + struct icmphdr *icmph; + struct iphdr *niph; + struct ethhdr eh; +@@ -226,7 +226,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph)); + if (err) +@@ -236,7 +235,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) + err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN); + if (err) + return err; +- ++ iph = ip_hdr(skb); + icmph = skb_push(skb, sizeof(*icmph)); + *icmph = (struct icmphdr) { + .type = ICMP_DEST_UNREACH, +@@ -308,7 +307,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu) + */ + static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + { +- const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ const struct ipv6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct ipv6hdr *nip6h; + struct ethhdr eh; +@@ -323,7 +322,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + + skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); + pskb_pull(skb, ETH_HLEN); +- skb_reset_network_header(skb); + + err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h)); + if (err) +@@ -334,6 +332,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu) + if (err) + return err; + ++ ip6h = ipv6_hdr(skb); + icmp6h = skb_push(skb, sizeof(*icmp6h)); + *icmp6h = (struct icmp6hdr) { + .icmp6_type = ICMPV6_PKT_TOOBIG, +-- +2.53.0 + diff --git a/queue-7.0/vsock-keep-poll-shutdown-state-consistent.patch b/queue-7.0/vsock-keep-poll-shutdown-state-consistent.patch new file mode 100644 index 0000000000..07755bde3c --- /dev/null +++ b/queue-7.0/vsock-keep-poll-shutdown-state-consistent.patch @@ -0,0 +1,247 @@ +From 908ca79c324a091b6705fdbb45748d215bcda089 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2026 00:56:36 +0800 +Subject: vsock: keep poll shutdown state consistent + +From: Ziyu Zhang + +[ Upstream commit aae9d8a5528b8ee9ff8dc5d3558b8a9f852a724a ] + +vsock_poll() reads vsk->peer_shutdown before taking the socket lock +to set EPOLLHUP and EPOLLRDHUP, then reads it again after taking +the lock to report EOF readability. A shutdown packet can update +peer_shutdown while poll is waiting for the lock, so one poll invocation +can report EOF readability without the corresponding HUP/RDHUP bits. + +For connectible sockets, take one peer_shutdown snapshot after +lock_sock() and use it for all peer-shutdown-derived poll bits. For +datagram sockets, which do not take lock_sock() in poll(), take one +lockless READ_ONCE() snapshot and pair it with WRITE_ONCE() on the +writer side. + +This keeps the peer-shutdown-derived bits internally consistent for each +poll pass. + +Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") +Signed-off-by: Ziyu Zhang +Link: https://patch.msgid.link/20260519165636.62542-1-ziyuzhang201@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/af_vsock.c | 49 ++++++++++++++++--------- + net/vmw_vsock/hyperv_transport.c | 9 +++-- + net/vmw_vsock/virtio_transport_common.c | 14 ++++--- + net/vmw_vsock/vmci_transport.c | 8 ++-- + 4 files changed, 52 insertions(+), 28 deletions(-) + +diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c +index 08f4dfb9782c28..0a93873eb4672b 100644 +--- a/net/vmw_vsock/af_vsock.c ++++ b/net/vmw_vsock/af_vsock.c +@@ -628,7 +628,7 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) + */ + sock_reset_flag(sk, SOCK_DONE); + sk->sk_state = TCP_CLOSE; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + } + + if (sk->sk_type == SOCK_SEQPACKET) { +@@ -919,7 +919,7 @@ static struct sock *__vsock_create(struct net *net, + vsk->rejected = false; + vsk->sent_request = false; + vsk->ignore_connecting_rst = false; +- vsk->peer_shutdown = 0; ++ WRITE_ONCE(vsk->peer_shutdown, 0); + INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout); + INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work); + +@@ -1227,6 +1227,25 @@ static int vsock_shutdown(struct socket *sock, int mode) + return err; + } + ++static __poll_t vsock_poll_shutdown(struct sock *sk, u32 peer_shutdown) ++{ ++ __poll_t mask = 0; ++ ++ /* INET sockets treat local write shutdown and peer write shutdown as a ++ * case of EPOLLHUP set. ++ */ ++ if (sk->sk_shutdown == SHUTDOWN_MASK || ++ ((sk->sk_shutdown & SEND_SHUTDOWN) && ++ (peer_shutdown & SEND_SHUTDOWN))) ++ mask |= EPOLLHUP; ++ ++ if (sk->sk_shutdown & RCV_SHUTDOWN || ++ peer_shutdown & SEND_SHUTDOWN) ++ mask |= EPOLLRDHUP; ++ ++ return mask; ++} ++ + static __poll_t vsock_poll(struct file *file, struct socket *sock, + poll_table *wait) + { +@@ -1244,24 +1263,17 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + /* Signify that there has been an error on this socket. */ + mask |= EPOLLERR; + +- /* INET sockets treat local write shutdown and peer write shutdown as a +- * case of EPOLLHUP set. +- */ +- if ((sk->sk_shutdown == SHUTDOWN_MASK) || +- ((sk->sk_shutdown & SEND_SHUTDOWN) && +- (vsk->peer_shutdown & SEND_SHUTDOWN))) { +- mask |= EPOLLHUP; +- } +- +- if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { +- mask |= EPOLLRDHUP; +- } +- + if (sk_is_readable(sk)) + mask |= EPOLLIN | EPOLLRDNORM; + + if (sock->type == SOCK_DGRAM) { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ ++ /* DGRAM sockets do not take lock_sock() in poll(), so use one ++ * lockless snapshot for all shutdown-derived mask bits. ++ */ ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); ++ + /* For datagram sockets we can read if there is something in + * the queue and write as long as the socket isn't shutdown for + * sending. +@@ -1276,6 +1288,7 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + + } else if (sock_type_connectible(sk->sk_type)) { + const struct vsock_transport *transport; ++ u32 peer_shutdown; + + lock_sock(sk); + +@@ -1308,8 +1321,10 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock, + * terminated should also be considered read, and we check the + * shutdown flag for that. + */ ++ peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ mask |= vsock_poll_shutdown(sk, peer_shutdown); + if (sk->sk_shutdown & RCV_SHUTDOWN || +- vsk->peer_shutdown & SEND_SHUTDOWN) { ++ peer_shutdown & SEND_SHUTDOWN) { + mask |= EPOLLIN | EPOLLRDNORM; + } + +diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c +index d5b0fd0a889723..842510f7dda2e3 100644 +--- a/net/vmw_vsock/hyperv_transport.c ++++ b/net/vmw_vsock/hyperv_transport.c +@@ -264,7 +264,7 @@ static void hvs_do_close_lock_held(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -593,7 +593,9 @@ static int hvs_update_recv_data(struct hvsock *hvs) + return -EIO; + + if (payload_len == 0) +- hvs->vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(hvs->vsk->peer_shutdown, ++ READ_ONCE(hvs->vsk->peer_shutdown) | ++ SEND_SHUTDOWN); + + hvs->recv_data_len = payload_len; + hvs->recv_data_off = 0; +@@ -736,7 +738,8 @@ static s64 hvs_stream_has_data(struct vsock_sock *vsk) + return ret; + return hvs->recv_data_len; + case 0: +- vsk->peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | SEND_SHUTDOWN); + ret = 0; + break; + default: /* -1 */ +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index e8fb2e20db0f38..1c0f1e5c75dec8 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -1221,7 +1221,7 @@ static void virtio_transport_do_close(struct vsock_sock *vsk, + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + sk->sk_state_change(sk); +@@ -1424,12 +1424,15 @@ virtio_transport_recv_connected(struct sock *sk, + case VIRTIO_VSOCK_OP_CREDIT_UPDATE: + sk->sk_write_space(sk); + break; +- case VIRTIO_VSOCK_OP_SHUTDOWN: ++ case VIRTIO_VSOCK_OP_SHUTDOWN: { ++ u32 peer_shutdown = READ_ONCE(vsk->peer_shutdown); ++ + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_RCV) +- vsk->peer_shutdown |= RCV_SHUTDOWN; ++ peer_shutdown |= RCV_SHUTDOWN; + if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_SEND) +- vsk->peer_shutdown |= SEND_SHUTDOWN; +- if (vsk->peer_shutdown == SHUTDOWN_MASK) { ++ peer_shutdown |= SEND_SHUTDOWN; ++ WRITE_ONCE(vsk->peer_shutdown, peer_shutdown); ++ if (peer_shutdown == SHUTDOWN_MASK) { + if (vsock_stream_has_data(vsk) <= 0 && !sock_flag(sk, SOCK_DONE)) { + (void)virtio_transport_reset(vsk, NULL); + virtio_transport_do_close(vsk, true); +@@ -1444,6 +1447,7 @@ virtio_transport_recv_connected(struct sock *sk, + if (le32_to_cpu(virtio_vsock_hdr(skb)->flags)) + sk->sk_state_change(sk); + break; ++ } + case VIRTIO_VSOCK_OP_RST: + virtio_transport_do_close(vsk, true); + break; +diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c +index d2579380f51e5d..5c1ecd5bfdbc21 100644 +--- a/net/vmw_vsock/vmci_transport.c ++++ b/net/vmw_vsock/vmci_transport.c +@@ -819,7 +819,7 @@ static void vmci_transport_handle_detach(struct sock *sk) + /* On a detach the peer will not be sending or receiving + * anymore. + */ +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + + /* We should not be sending anymore since the peer won't be + * there to receive, but we can still receive if there is data +@@ -1542,7 +1542,9 @@ static int vmci_transport_recv_connected(struct sock *sk, + if (pkt->u.mode) { + vsk = vsock_sk(sk); + +- vsk->peer_shutdown |= pkt->u.mode; ++ WRITE_ONCE(vsk->peer_shutdown, ++ READ_ONCE(vsk->peer_shutdown) | ++ pkt->u.mode); + sk->sk_state_change(sk); + } + break; +@@ -1559,7 +1561,7 @@ static int vmci_transport_recv_connected(struct sock *sk, + * a clean shutdown. + */ + sock_set_flag(sk, SOCK_DONE); +- vsk->peer_shutdown = SHUTDOWN_MASK; ++ WRITE_ONCE(vsk->peer_shutdown, SHUTDOWN_MASK); + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = TCP_CLOSING; + +-- +2.53.0 + diff --git a/queue-7.0/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch b/queue-7.0/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch new file mode 100644 index 0000000000..32d100d0c5 --- /dev/null +++ b/queue-7.0/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch @@ -0,0 +1,89 @@ +From 76f701991ac26a578240a173e7b4ed3688f71c79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 10:33:01 +0800 +Subject: vsock/virtio: bind uarg before filling zerocopy skb + +From: Jingguo Tan + +[ Upstream commit 1e584c304cfb94a759417130b1fc6d30b30c4cce ] + +virtio_transport_send_pkt_info() allocates or reuses the zerocopy uarg +before entering the send loop, but virtio_transport_alloc_skb() still +fills the skb before it inherits that uarg. When fixed-buffer vectored +zerocopy hits MAX_SKB_FRAGS, io_sg_from_iter() may partially attach +managed frags and return -EMSGSIZE. The rollback path call kfree_skb() +to free an skb that carries SKBFL_MANAGED_FRAG_REFS but no uarg, so +skb_release_data() falls through to ordinary frag unref. + +Pass the uarg into virtio_transport_alloc_skb() and bind it immediately +before virtio_transport_fill_skb(). This keeps control or no-payload skbs +untouched while ensuring success and rollback share one lifetime rule. + +Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support") +Signed-off-by: Lin Ma +Signed-off-by: Rongzhen Cui +Signed-off-by: Jingguo Tan +Acked-by: Arseniy Krasnov +Acked-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Link: https://patch.msgid.link/20260527023301.1075581-1-malin89@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/virtio_transport_common.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index 1c0f1e5c75dec8..abe7bfcedc5a6d 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -207,6 +207,7 @@ static u16 virtio_transport_get_type(struct sock *sk) + static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info, + size_t payload_len, + bool zcopy, ++ struct ubuf_info *uarg, + u32 src_cid, + u32 src_port, + u32 dst_cid, +@@ -247,6 +248,12 @@ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info * + if (info->msg && payload_len > 0) { + int err; + ++ /* Bind the zerocopy lifetime before filling frags so error ++ * rollback frees managed fixed-buffer pages through ++ * the uarg-aware path. ++ */ ++ skb_zcopy_set(skb, uarg, NULL); ++ + err = virtio_transport_fill_skb(skb, info, payload_len, zcopy); + if (err) + goto out; +@@ -366,6 +373,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, + skb_len = min(max_skb_len, rest_len); + + skb = virtio_transport_alloc_skb(info, skb_len, can_zcopy, ++ uarg, + src_cid, src_port, + dst_cid, dst_port); + if (!skb) { +@@ -373,8 +381,6 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, + break; + } + +- skb_zcopy_set(skb, uarg, NULL); +- + virtio_transport_inc_tx_pkt(vvs, skb); + + ret = t_ops->send_pkt(skb, info->net); +@@ -1176,7 +1182,7 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t, + if (!t) + return -ENOTCONN; + +- reply = virtio_transport_alloc_skb(&info, 0, false, ++ reply = virtio_transport_alloc_skb(&info, 0, false, NULL, + le64_to_cpu(hdr->dst_cid), + le32_to_cpu(hdr->dst_port), + le64_to_cpu(hdr->src_cid), +-- +2.53.0 + diff --git a/queue-7.0/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch b/queue-7.0/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch new file mode 100644 index 0000000000..7c2cb29ec6 --- /dev/null +++ b/queue-7.0/vxlan-do-not-reuse-cached-ip_hdr-value-after-skb_tun.patch @@ -0,0 +1,54 @@ +From b1f63588e7e767e9b17385d19ab49575780a7475 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 May 2026 20:36:42 +0000 +Subject: vxlan: do not reuse cached ip_hdr() value after + skb_tunnel_check_pmtu() + +From: Eric Dumazet + +[ Upstream commit 7d9ef0cb271555d8cf39fefe6c981e1493b25ecf ] + +skb_tunnel_check_pmtu() can change skb->head. + +Reusing old_iph afer skb_tunnel_check_pmtu() can cause an UAF. + +Use instead ip_hdr(skb) as done in drivers/net/bareudp.c +and drivers/net/geneve.c. + +Found by Sashiko. + +Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20260525203642.2389723-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index a94ac82a613649..0cc3b34add5eb4 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2534,7 +2534,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), + vni, md, flags, udp_sum); +@@ -2608,7 +2608,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto out_unlock; + } + +- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ++ tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb); + ttl = ttl ? : ip6_dst_hoplimit(ndst); + skb_scrub_packet(skb, xnet); + err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), +-- +2.53.0 + diff --git a/queue-7.0/xfrm-check-for-underflow-in-xfrm_state_mtu.patch b/queue-7.0/xfrm-check-for-underflow-in-xfrm_state_mtu.patch new file mode 100644 index 0000000000..96bf46a296 --- /dev/null +++ b/queue-7.0/xfrm-check-for-underflow-in-xfrm_state_mtu.patch @@ -0,0 +1,85 @@ +From 0275e38f18e7e32158919e688382b990eebb4c2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 10:49:14 -0600 +Subject: xfrm: Check for underflow in xfrm_state_mtu + +From: David Ahern + +[ Upstream commit 742b04d0550b0ec89dcbc99537ec88653bd1ad90 ] + +Leo Lin reported OOB write issue in esp component: + + xfrm_state_mtu() returns u32 but performs its arithmetic in unsigned + modulo-2^32 space using an attacker-influenced "header_len + authsize + + net_adj" subtracted from a small "mtu" argument. A nobody user can + install an IPv4 ESP tunnel SA with a large authentication key + (XFRMA_ALG_AUTH_TRUNC, e.g. hmac(sha512), 64-byte key, 64-byte trunc), + configure a small interface MTU (68 bytes), and set XFRMA_TFCPAD to a + large value. When a single UDP datagram is then sent through the + tunnel, xfrm_state_mtu() underflows to a near-2^32 value, and + esp_output() consumes it as a signed int via: + + padto = min(x->tfcpad, xfrm_state_mtu(x, mtu_cached)) + esp.tfclen = padto - skb->len (assigned to int) + + esp.tfclen ends up negative (e.g. -207). It is sign-extended to size_t + when passed to memset() inside esp_output_fill_trailer(), producing a + ~16 EB write of zeroes at skb_tail_pointer(skb). KASAN logs it as + "Write of size 18446744073709551537 at addr ffff888...". + +Check for underflow and return 1. This causes the sendmsg attempt to +fail with ENETUNREACH. + +Fixes: c5c252389374 ("[XFRM]: Optimize MTU calculation") +Reported-by: Leo Lin +Assisted-by: Codex:26.506.31004 +Signed-off-by: David Ahern +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_state.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index 686014d394298c..f597e4996bb28a 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -3114,10 +3114,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + const struct xfrm_type *type = READ_ONCE(x->type); + struct crypto_aead *aead; + u32 blksize, net_adj = 0; ++ u32 overhead, payload_mtu; + + if (x->km.state != XFRM_STATE_VALID || +- !type || type->proto != IPPROTO_ESP) ++ !type || type->proto != IPPROTO_ESP) { ++ if (mtu <= x->props.header_len) ++ return 1; + return mtu - x->props.header_len; ++ } + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); +@@ -3140,8 +3144,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) + break; + } + +- return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - +- net_adj) & ~(blksize - 1)) + net_adj - 2; ++ overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj; ++ if (mtu <= overhead) ++ return 1; ++ ++ payload_mtu = mtu - overhead; ++ payload_mtu &= ~(blksize - 1); ++ if (payload_mtu <= 2) ++ return 1; ++ ++ return payload_mtu + net_adj - 2; ++ + } + EXPORT_SYMBOL_GPL(xfrm_state_mtu); + +-- +2.53.0 +