From: Greg Kroah-Hartman Date: Thu, 4 Jun 2026 10:37:26 +0000 (+0200) Subject: 7.0-stable patches X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=95245bb033bf885d22a033eb585f9ef3c559e6ae;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches added patches: alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch alsa-hda-realtek-fix-speaker-output-on-asus-rog-strix-g615lp.patch alsa-scarlett2-fix-2i2-gen-4-direct-monitor-gain-on-firmware-2417.patch asoc-qcom-q6asm-dai-close-stream-only-when-running.patch asoc-qcom-q6asm-dai-do-not-set-stream-state-in-event-and-trigger-callbacks.patch asoc-qcom-q6asm-dai-fix-error-handling-in-prepare-and-set_params.patch bpf-sockmap-fix-tail-fragment-offset-in-bpf_msg_push_data.patch dma-buf-fix-uaf-in-dma_buf_fd-tracepoint.patch hid-wacom-fix-oob-write-in-wacom_hid_set_device_mode.patch iommu-debugobjects-avoid-gcc-16.1-section-mismatch-warnings.patch ip6-vti-use-ip6_tnl.net-in-vti6_changelink.patch ip6-vti-use-ip6_tnl.net-in-vti6_siocdevprivate.patch ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch ipv6-exthdrs-refresh-nh-pointer-after-ipv6_hop_jumbo.patch ipv6-validate-extension-header-length-before-copying-to-cmsg.patch l2tp-use-refcount_inc_not_zero-in-l2tp_session_get_by_ifname.patch macsec-fix-replay-protection-at-xpn-lower-pn-wrap.patch net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch netfilter-conntrack-tcp-do-not-force-close-on-invalid-seq-rst-without-direction-check.patch nfc-hci-fix-out-of-bounds-read-in-hcp-header-parsing.patch octeontx2-af-validate-body-pcifunc-in-rvu_mbox_handler_rep_event_notify.patch spi-spi-mem-avoid-mutating-op-template-in-spi_mem_supports_op.patch wireguard-send-append-trailer-after-expanding-head.patch xfrm-ah-use-skb_to_full_sk-in-async-output-callbacks.patch xfrm-esp-restore-combined-single-frag-length-gate.patch xfrm-input-hold-netns-during-deferred-transport-reinjection.patch xfrm-ipcomp-free-destination-pages-on-acomp-errors.patch xfrm-iptfs-reset-runtime-state-when-cloning-sas.patch xfrm-route-migrate-notifications-to-caller-s-netns.patch --- diff --git a/queue-7.0/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch b/queue-7.0/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch new file mode 100644 index 0000000000..7cc53e5427 --- /dev/null +++ b/queue-7.0/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch @@ -0,0 +1,63 @@ +From 98fb1c1bb11e29eb609b7200a25e136e05aa4498 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= +Date: Thu, 21 May 2026 08:01:23 -0300 +Subject: ALSA: firewire-motu: Protect register DSP event queue positions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +commit 98fb1c1bb11e29eb609b7200a25e136e05aa4498 upstream. + +The register DSP event queue is updated under parser->lock, but +snd_motu_register_dsp_message_parser_count_event() reads pull_pos and +push_pos without the lock. +snd_motu_register_dsp_message_parser_copy_event() also reads both queue +positions before taking the lock. + +Protect these accesses with parser->lock as well. This keeps the hwdep +poll/read path consistent with the producer side and with the cached +meter/parameter accessors. + +Fixes: 634ec0b2906e ("ALSA: firewire-motu: notify event for parameter change in register DSP model") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Reviewed-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260521-alsa-firewire-motu-event-locking-v1-1-708e1c2b5e56@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + sound/firewire/motu/motu-register-dsp-message-parser.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/sound/firewire/motu/motu-register-dsp-message-parser.c ++++ b/sound/firewire/motu/motu-register-dsp-message-parser.c +@@ -386,6 +386,8 @@ unsigned int snd_motu_register_dsp_messa + { + struct msg_parser *parser = motu->message_parser; + ++ guard(spinlock_irqsave)(&parser->lock); ++ + if (parser->pull_pos > parser->push_pos) + return EVENT_QUEUE_SIZE - parser->pull_pos + parser->push_pos; + else +@@ -395,13 +397,14 @@ unsigned int snd_motu_register_dsp_messa + bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event) + { + struct msg_parser *parser = motu->message_parser; +- unsigned int pos = parser->pull_pos; +- +- if (pos == parser->push_pos) +- return false; ++ unsigned int pos; + + guard(spinlock_irqsave)(&parser->lock); + ++ if (parser->pull_pos == parser->push_pos) ++ return false; ++ ++ pos = parser->pull_pos; + *event = parser->event_queue[pos]; + + ++pos; diff --git a/queue-7.0/alsa-hda-realtek-fix-speaker-output-on-asus-rog-strix-g615lp.patch b/queue-7.0/alsa-hda-realtek-fix-speaker-output-on-asus-rog-strix-g615lp.patch new file mode 100644 index 0000000000..96c218a34e --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-fix-speaker-output-on-asus-rog-strix-g615lp.patch @@ -0,0 +1,33 @@ +From 20587302f8d700f26ee2c8a60ffb0a69ae0edf16 Mon Sep 17 00:00:00 2001 +From: Zhang Heng +Date: Tue, 26 May 2026 09:36:11 +0800 +Subject: ALSA: hda/realtek: Fix speaker output on ASUS ROG Strix G615LP + +From: Zhang Heng + +commit 20587302f8d700f26ee2c8a60ffb0a69ae0edf16 upstream. + +Add quirk for ALC294 codec on ASUS ROG Strix G615LP +(SSID 1043:1214) using ALC287_FIXUP_TXNW2781_I2C_ASUS to +fix speaker output. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221173 +Cc: +Signed-off-by: Zhang Heng +Link: https://patch.msgid.link/20260526013611.1954949-1-zhangheng@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/hda/codecs/realtek/alc269.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -7260,6 +7260,7 @@ static const struct hda_quirk alc269_fix + SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), + HDA_CODEC_QUIRK(0x1043, 0x1204, "ASUS Strix G16 G615JMR", ALC287_FIXUP_TXNW2781_I2C_ASUS), + SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C), ++ HDA_CODEC_QUIRK(0x1043, 0x1214, "ASUS ROG Strix G615LP", ALC287_FIXUP_TXNW2781_I2C_ASUS), + SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), diff --git a/queue-7.0/alsa-scarlett2-fix-2i2-gen-4-direct-monitor-gain-on-firmware-2417.patch b/queue-7.0/alsa-scarlett2-fix-2i2-gen-4-direct-monitor-gain-on-firmware-2417.patch new file mode 100644 index 0000000000..405d21106d --- /dev/null +++ b/queue-7.0/alsa-scarlett2-fix-2i2-gen-4-direct-monitor-gain-on-firmware-2417.patch @@ -0,0 +1,109 @@ +From db37cf47b67e38ade40de5cd74a4d4d772ff1416 Mon Sep 17 00:00:00 2001 +From: "Geoffrey D. Bennett" +Date: Sun, 24 May 2026 06:34:14 +0930 +Subject: ALSA: scarlett2: Fix 2i2 Gen 4 direct monitor gain on firmware 2417 + +From: Geoffrey D. Bennett + +commit db37cf47b67e38ade40de5cd74a4d4d772ff1416 upstream. + +Firmware 2417 for the Scarlett 4th Gen 2i2 moved the direct monitor +gain parameter by 4 bytes, from offset 0x2a0 to 0x2a4, breaking the +"Direct Monitor X Mix Y" controls. + +Special-case the offset in the get/set config helpers when the +running firmware is 2417 or later. + +Fixes: 4e809a299677 ("ALSA: scarlett2: Add support for Solo, 2i2, and 4i4 Gen 4") +Cc: +Signed-off-by: Geoffrey D. Bennett +Link: https://patch.msgid.link/ahIWTueUlWA5xiV+@m.b4.vu +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/mixer_scarlett2.c | 33 +++++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -2504,6 +2504,27 @@ static int scarlett2_has_config_item( + return !!private->config_set->items[config_item_num].offset; + } + ++/* Return the configuration item's offset, applying any per-firmware ++ * overrides. ++ * ++ * Firmware 2417 for the 2i2 Gen 4 moved DIRECT_MONITOR_GAIN by 4 ++ * bytes. Apply that shift here so that the rest of the driver can ++ * keep using the single config set. This override can be removed ++ * once the multi-config-set framework lands. ++ */ ++static int scarlett2_config_item_offset( ++ struct scarlett2_data *private, int config_item_num) ++{ ++ int offset = private->config_set->items[config_item_num].offset; ++ ++ if (config_item_num == SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN && ++ private->info == &s2i2_gen4_info && ++ private->firmware_version >= 2417) ++ offset = 0x2a4; ++ ++ return offset; ++} ++ + /* Send a USB message to get configuration parameters; result placed in *buf */ + static int scarlett2_usb_get_config( + struct usb_mixer_interface *mixer, +@@ -2513,6 +2534,7 @@ static int scarlett2_usb_get_config( + const struct scarlett2_config *config_item = + &private->config_set->items[config_item_num]; + int size, err, i; ++ int item_offset; + u8 *buf_8; + u8 value; + +@@ -2522,13 +2544,15 @@ static int scarlett2_usb_get_config( + if (!config_item->offset) + return -EFAULT; + ++ item_offset = scarlett2_config_item_offset(private, config_item_num); ++ + /* Writes to the parameter buffer are always 1 byte */ + size = config_item->size ? config_item->size : 8; + + /* For byte-sized parameters, retrieve directly into buf */ + if (size >= 8) { + size = size / 8 * count; +- err = scarlett2_usb_get(mixer, config_item->offset, buf, size); ++ err = scarlett2_usb_get(mixer, item_offset, buf, size); + if (err < 0) + return err; + if (config_item->size == 16) { +@@ -2546,7 +2570,7 @@ static int scarlett2_usb_get_config( + } + + /* For bit-sized parameters, retrieve into value */ +- err = scarlett2_usb_get(mixer, config_item->offset, &value, 1); ++ err = scarlett2_usb_get(mixer, item_offset, &value, 1); + if (err < 0) + return err; + +@@ -2696,7 +2720,8 @@ static int scarlett2_usb_set_config( + */ + if (config_item->size >= 8) { + size = config_item->size / 8; +- offset = config_item->offset + index * size; ++ offset = scarlett2_config_item_offset(private, config_item_num) + ++ index * size; + + /* If updating a bit, retrieve the old value, set/clear the + * bit as needed, and update value +@@ -2705,7 +2730,7 @@ static int scarlett2_usb_set_config( + u8 tmp; + + size = 1; +- offset = config_item->offset; ++ offset = scarlett2_config_item_offset(private, config_item_num); + + err = scarlett2_usb_get(mixer, offset, &tmp, 1); + if (err < 0) diff --git a/queue-7.0/asoc-qcom-q6asm-dai-close-stream-only-when-running.patch b/queue-7.0/asoc-qcom-q6asm-dai-close-stream-only-when-running.patch new file mode 100644 index 0000000000..12e58b3b1e --- /dev/null +++ b/queue-7.0/asoc-qcom-q6asm-dai-close-stream-only-when-running.patch @@ -0,0 +1,72 @@ +From 048c540ee76ded666bda74f9dae1ca3254e0633c Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Mon, 18 May 2026 09:23:44 +0000 +Subject: ASoC: qcom: q6asm-dai: close stream only when running + +From: Srinivas Kandagatla + +commit 048c540ee76ded666bda74f9dae1ca3254e0633c upstream. + +q6asm_dai_close() and q6asm_dai_compr_free() currently issue CMD_CLOSE +whenever prtd->state is non-zero. + +After prepare() closes an existing stream, the state is updated to +Q6ASM_STREAM_STOPPED. Since this state is also non-zero, the close and +free paths can send CMD_CLOSE again for a stream that has already been +closed. + +Restrict CMD_CLOSE to the Q6ASM_STREAM_RUNNING state so the command is +sent only when the ASM stream is still active. + +Fixes: 2a9e92d371db ("ASoC: qdsp6: q6asm: Add q6asm dai driver") +Cc: Stable@vger.kernel.org +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260518092347.3446946-3-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/qcom/qdsp6/q6asm-dai.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/sound/soc/qcom/qdsp6/q6asm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6asm-dai.c +@@ -465,12 +465,12 @@ static int q6asm_dai_close(struct snd_so + struct q6asm_dai_rtd *prtd = runtime->private_data; + + if (prtd->audio_client) { +- if (prtd->state) ++ if (prtd->state == Q6ASM_STREAM_RUNNING) { + q6asm_cmd(prtd->audio_client, prtd->stream_id, + CMD_CLOSE); +- +- q6asm_unmap_memory_regions(substream->stream, ++ q6asm_unmap_memory_regions(substream->stream, + prtd->audio_client); ++ } + q6asm_audio_client_free(prtd->audio_client); + prtd->audio_client = NULL; + } +@@ -682,7 +682,7 @@ static int q6asm_dai_compr_free(struct s + struct snd_soc_pcm_runtime *rtd = stream->private_data; + + if (prtd->audio_client) { +- if (prtd->state) { ++ if (prtd->state == Q6ASM_STREAM_RUNNING) { + q6asm_cmd(prtd->audio_client, prtd->stream_id, + CMD_CLOSE); + if (prtd->next_track_stream_id) { +@@ -690,11 +690,11 @@ static int q6asm_dai_compr_free(struct s + prtd->next_track_stream_id, + CMD_CLOSE); + } +- } + +- snd_dma_free_pages(&prtd->dma_buffer); +- q6asm_unmap_memory_regions(stream->direction, ++ q6asm_unmap_memory_regions(stream->direction, + prtd->audio_client); ++ } ++ snd_dma_free_pages(&prtd->dma_buffer); + q6asm_audio_client_free(prtd->audio_client); + prtd->audio_client = NULL; + } diff --git a/queue-7.0/asoc-qcom-q6asm-dai-do-not-set-stream-state-in-event-and-trigger-callbacks.patch b/queue-7.0/asoc-qcom-q6asm-dai-do-not-set-stream-state-in-event-and-trigger-callbacks.patch new file mode 100644 index 0000000000..0c4dbc95c2 --- /dev/null +++ b/queue-7.0/asoc-qcom-q6asm-dai-do-not-set-stream-state-in-event-and-trigger-callbacks.patch @@ -0,0 +1,67 @@ +From cee3e63e7106c3c81b2053371fdf14240bfba2fc Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Mon, 18 May 2026 09:23:43 +0000 +Subject: ASoC: qcom: q6asm-dai: do not set stream state in event and trigger callbacks + +From: Srinivas Kandagatla + +commit cee3e63e7106c3c81b2053371fdf14240bfba2fc upstream. + +The q6asm-dai stream state is used by prepare() to decide whether an +existing stream setup needs to be closed before opening/configuring a new +one. Updating the state from trigger or asynchronous DSP callbacks can make +that state stale or incorrect relative to the actual setup lifetime. + +In particular, setting Q6ASM_STREAM_STOPPED on STOP or EOS completion can +make prepare() believe there is no active setup to close, which can result +in opening/configuring the same stream more than once. + +Keep stream state updates tied to prepare(), where the stream is actually +closed and reopened, and stop changing it from trigger and EOS callbacks. + +Fixes: bfbb12dfa144 ("ASoC: qcom: q6asm-dai: perform correct state check before closing") +Cc: Stable@vger.kernel.org +Closes: https://lore.kernel.org/all/afS7rTHdc9TyIeLx@rdacayan/ +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260518092347.3446946-2-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/qcom/qdsp6/q6asm-dai.c | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/sound/soc/qcom/qdsp6/q6asm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6asm-dai.c +@@ -186,7 +186,6 @@ static void event_handler(uint32_t opcod + case ASM_CLIENT_EVENT_CMD_RUN_DONE: + break; + case ASM_CLIENT_EVENT_CMD_EOS_DONE: +- prtd->state = Q6ASM_STREAM_STOPPED; + break; + case ASM_CLIENT_EVENT_DATA_WRITE_DONE: { + snd_pcm_period_elapsed(substream); +@@ -349,7 +348,6 @@ static int q6asm_dai_trigger(struct snd_ + 0, 0, 0); + break; + case SNDRV_PCM_TRIGGER_STOP: +- prtd->state = Q6ASM_STREAM_STOPPED; + ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, + CMD_EOS); + break; +@@ -563,8 +561,6 @@ static void compress_event_handler(uint3 + snd_compr_drain_notify(prtd->cstream); + prtd->notify_on_drain = false; + +- } else { +- prtd->state = Q6ASM_STREAM_STOPPED; + } + break; + +@@ -1022,7 +1018,6 @@ static int q6asm_dai_compr_trigger(struc + 0, 0, 0); + break; + case SNDRV_PCM_TRIGGER_STOP: +- prtd->state = Q6ASM_STREAM_STOPPED; + ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, + CMD_EOS); + break; diff --git a/queue-7.0/asoc-qcom-q6asm-dai-fix-error-handling-in-prepare-and-set_params.patch b/queue-7.0/asoc-qcom-q6asm-dai-fix-error-handling-in-prepare-and-set_params.patch new file mode 100644 index 0000000000..100c78e819 --- /dev/null +++ b/queue-7.0/asoc-qcom-q6asm-dai-fix-error-handling-in-prepare-and-set_params.patch @@ -0,0 +1,83 @@ +From 4b4db09f283df65d780bc7cee66cb4a7e9bf4770 Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Mon, 18 May 2026 09:23:45 +0000 +Subject: ASoC: qcom: q6asm-dai: fix error handling in prepare and set_params + +From: Srinivas Kandagatla + +commit 4b4db09f283df65d780bc7cee66cb4a7e9bf4770 upstream. + +Fix error handling in q6asm_dai_compr_set_params() and q6asm_dai_prepare() +for both CMD_CLOSE and q6asm_unmap_memory_regions(). + +In both the functions, we are doing q6asm_audio_client_free in failure +cases, which means if prepare or set_params fail, we can never recover. +Now open and close are done in respective dai_open/close functions. + +Fixes: 2a9e92d371db ("ASoC: qdsp6: q6asm: Add q6asm dai driver") +Cc: Stable@vger.kernel.org +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260518092347.3446946-4-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/qcom/qdsp6/q6asm-dai.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +--- a/sound/soc/qcom/qdsp6/q6asm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6asm-dai.c +@@ -227,9 +227,19 @@ static int q6asm_dai_prepare(struct snd_ + /* rate and channels are sent to audio driver */ + if (prtd->state == Q6ASM_STREAM_RUNNING) { + /* clear the previous setup if any */ +- q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); +- q6asm_unmap_memory_regions(substream->stream, +- prtd->audio_client); ++ ret = q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); ++ if (ret < 0) { ++ dev_err(dev, "Failed to close q6asm stream %d\n", prtd->stream_id); ++ return ret; ++ } ++ ++ ret = q6asm_unmap_memory_regions(substream->stream, prtd->audio_client); ++ if (ret < 0) { ++ dev_err(dev, "Failed to unmap memory regions for q6asm stream %d\n", ++ prtd->stream_id); ++ return ret; ++ } ++ + q6routing_stream_close(soc_prtd->dai_link->id, + substream->stream); + prtd->state = Q6ASM_STREAM_STOPPED; +@@ -297,8 +307,6 @@ routing_err: + q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); + open_err: + q6asm_unmap_memory_regions(substream->stream, prtd->audio_client); +- q6asm_audio_client_free(prtd->audio_client); +- prtd->audio_client = NULL; + + return ret; + } +@@ -916,7 +924,7 @@ static int q6asm_dai_compr_set_params(st + prtd->session_id, dir); + if (ret) { + dev_err(dev, "Stream reg failed ret:%d\n", ret); +- goto q6_err; ++ goto routing_err; + } + + ret = __q6asm_dai_compr_set_codec_params(component, stream, +@@ -942,11 +950,11 @@ static int q6asm_dai_compr_set_params(st + return 0; + + q6_err: ++ q6routing_stream_close(rtd->dai_link->id, dir); ++routing_err: + q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); + + open_err: +- q6asm_audio_client_free(prtd->audio_client); +- prtd->audio_client = NULL; + return ret; + } + diff --git a/queue-7.0/bpf-sockmap-fix-tail-fragment-offset-in-bpf_msg_push_data.patch b/queue-7.0/bpf-sockmap-fix-tail-fragment-offset-in-bpf_msg_push_data.patch new file mode 100644 index 0000000000..292069ff92 --- /dev/null +++ b/queue-7.0/bpf-sockmap-fix-tail-fragment-offset-in-bpf_msg_push_data.patch @@ -0,0 +1,47 @@ +From f72eed9b84fb771019a955908132410a9ba9ea3f Mon Sep 17 00:00:00 2001 +From: Yuqi Xu +Date: Wed, 27 May 2026 11:48:15 +0800 +Subject: bpf: sockmap: fix tail fragment offset in bpf_msg_push_data + +From: Yuqi Xu + +commit f72eed9b84fb771019a955908132410a9ba9ea3f upstream. + +When bpf_msg_push_data() inserts data in the middle of a scatterlist +entry, it splits the original entry into a left fragment and a right +fragment. + +The right fragment offset is page-local, but the code advances it with +`start`, which is the message-global insertion point. For inserts into a +non-first SG entry, this over-advances the offset and leaves the split +layout inconsistent. + +Advance the right fragment offset by the fragment-local delta, +`start - offset`, which matches the length removed from the front of the +original entry. + +Fixes: 6fff607e2f14 ("bpf: sk_msg program helper bpf_msg_push_data") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Signed-off-by: Yuqi Xu +Signed-off-by: Ren Wei +Link: https://patch.msgid.link/8b129d10566aa3eb43f61a8f9757bcf51707d324.1779636774.git.xuyq21@lenovo.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -2865,7 +2865,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_ + + psge->length = start - offset; + rsge.length -= psge->length; +- rsge.offset += start; ++ rsge.offset += start - offset; + + sk_msg_iter_var_next(i); + sg_unmark_end(psge); diff --git a/queue-7.0/dma-buf-fix-uaf-in-dma_buf_fd-tracepoint.patch b/queue-7.0/dma-buf-fix-uaf-in-dma_buf_fd-tracepoint.patch new file mode 100644 index 0000000000..d4e5aab651 --- /dev/null +++ b/queue-7.0/dma-buf-fix-uaf-in-dma_buf_fd-tracepoint.patch @@ -0,0 +1,59 @@ +From ead6680f354f83966c796fc7f9463a3171789616 Mon Sep 17 00:00:00 2001 +From: David Carlier +Date: Sat, 23 May 2026 19:14:46 +0100 +Subject: dma-buf: fix UAF in dma_buf_fd() tracepoint +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: David Carlier + +commit ead6680f354f83966c796fc7f9463a3171789616 upstream. + +Once FD_ADD() returns, the fd is live in the file descriptor table +and a thread sharing that table can close() it before DMA_BUF_TRACE() +runs. The close drops the last reference, __fput() frees the dma_buf, +and the tracepoint then dereferences dmabuf to take dmabuf->name_lock +-- slab-use-after-free. + +Split FD_ADD() back into get_unused_fd_flags() + fd_install() and +emit the tracepoint between them. While the fdtable slot is reserved +with a NULL file pointer, a racing close() returns -EBADF without +entering __fput(), so the dma_buf stays alive across the trace. Same +approach as commit 2d76319c4cbb ("dma-buf: fix UAF in dma_buf_put() +tracepoint"). + +This undoes the FD_ADD() conversion done in commit 34dfce523c90 +("dma: convert dma_buf_fd() to FD_ADD()"); FD_ADD() has no place to +hook the tracepoint safely. + +Reported-by: syzbot+7f4987d0afb97dd090cb@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7f4987d0afb97dd090cb +Fixes: 281a22631423 ("dma-buf: add some tracepoints to debug.") +Cc: stable@vger.kernel.org # 7.0.x +Signed-off-by: David Carlier +Reviewed-by: Christian König +Signed-off-by: Sumit Semwal +Link: https://patch.msgid.link/20260523181446.69525-1-devnexen@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/dma-buf/dma-buf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/dma-buf/dma-buf.c ++++ b/drivers/dma-buf/dma-buf.c +@@ -792,9 +792,13 @@ int dma_buf_fd(struct dma_buf *dmabuf, i + if (!dmabuf || !dmabuf->file) + return -EINVAL; + +- fd = FD_ADD(flags, dmabuf->file); ++ fd = get_unused_fd_flags(flags); ++ if (fd < 0) ++ return fd; ++ + DMA_BUF_TRACE(trace_dma_buf_fd, dmabuf, fd); + ++ fd_install(fd, dmabuf->file); + return fd; + } + EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF"); diff --git a/queue-7.0/hid-wacom-fix-oob-write-in-wacom_hid_set_device_mode.patch b/queue-7.0/hid-wacom-fix-oob-write-in-wacom_hid_set_device_mode.patch new file mode 100644 index 0000000000..fb6a7b7e61 --- /dev/null +++ b/queue-7.0/hid-wacom-fix-oob-write-in-wacom_hid_set_device_mode.patch @@ -0,0 +1,81 @@ +From c0a8899e02ddebd51e2589835182c239c2e224ae Mon Sep 17 00:00:00 2001 +From: Lee Jones +Date: Wed, 27 May 2026 17:05:26 +0100 +Subject: HID: wacom: Fix OOB write in wacom_hid_set_device_mode() + +From: Lee Jones + +commit c0a8899e02ddebd51e2589835182c239c2e224ae upstream. + +wacom_hid_set_device_mode() currently assumes that the HID_DG_INPUTMODE +usage is always located in the first field (field[0]) of the feature report. +However, a device can specify HID_DG_INPUTMODE in a different field. + +If HID_DG_INPUTMODE is in a field other than the first one and the first +field has a report_count smaller than the usage_index of HID_DG_INPUTMODE, +this leads to an out-of-bounds write to r->field[0]->value. + +Fix this by storing the field index of HID_DG_INPUTMODE in 'struct +hid_data' during feature mapping. In wacom_hid_set_device_mode(), use +this stored field index to access the correct field and add bounds +checks to ensure both the field index and the value index are within +valid ranges before writing. + +Cc: stable@vger.kernel.org +Fixes: 5ae6e89f7409 ("HID: wacom: implement the finger part of the HID generic handling") +Tested-by: Ping Cheng +Reviewed-by: Ping Cheng +Signed-off-by: Lee Jones +Signed-off-by: Benjamin Tissoires +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/wacom_sys.c | 13 ++++++++++--- + drivers/hid/wacom_wac.h | 1 + + 2 files changed, 11 insertions(+), 3 deletions(-) + +--- a/drivers/hid/wacom_sys.c ++++ b/drivers/hid/wacom_sys.c +@@ -356,6 +356,7 @@ static void wacom_feature_mapping(struct + + hid_data->inputmode = field->report->id; + hid_data->inputmode_index = usage->usage_index; ++ hid_data->inputmode_field_index = field->index; + break; + + case HID_UP_DIGITIZER: +@@ -571,9 +572,14 @@ static int wacom_hid_set_device_mode(str + + re = &(hdev->report_enum[HID_FEATURE_REPORT]); + r = re->report_id_hash[hid_data->inputmode]; +- if (r) { +- r->field[0]->value[hid_data->inputmode_index] = 2; +- hid_hw_request(hdev, r, HID_REQ_SET_REPORT); ++ if (r && hid_data->inputmode_field_index >= 0 && ++ hid_data->inputmode_field_index < r->maxfield) { ++ struct hid_field *field = r->field[hid_data->inputmode_field_index]; ++ ++ if (field && hid_data->inputmode_index < field->report_count) { ++ field->value[hid_data->inputmode_index] = 2; ++ hid_hw_request(hdev, r, HID_REQ_SET_REPORT); ++ } + } + return 0; + } +@@ -2846,6 +2852,7 @@ static int wacom_probe(struct hid_device + return -ENODEV; + + wacom_wac->hid_data.inputmode = -1; ++ wacom_wac->hid_data.inputmode_field_index = -1; + wacom_wac->mode_report = -1; + + if (hid_is_usb(hdev)) { +--- a/drivers/hid/wacom_wac.h ++++ b/drivers/hid/wacom_wac.h +@@ -295,6 +295,7 @@ struct wacom_shared { + struct hid_data { + __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ + __s16 inputmode_index; /* InputMode HID feature index in the report */ ++ __s16 inputmode_field_index; /* InputMode HID feature field index in the report */ + bool sense_state; + bool inrange_state; + bool eraser; diff --git a/queue-7.0/iommu-debugobjects-avoid-gcc-16.1-section-mismatch-warnings.patch b/queue-7.0/iommu-debugobjects-avoid-gcc-16.1-section-mismatch-warnings.patch new file mode 100644 index 0000000000..7a17765bf5 --- /dev/null +++ b/queue-7.0/iommu-debugobjects-avoid-gcc-16.1-section-mismatch-warnings.patch @@ -0,0 +1,126 @@ +From 4c9ad387aa2d6785299722e54224d34764edaeb3 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Wed, 13 May 2026 16:53:54 +0200 +Subject: iommu, debugobjects: avoid gcc-16.1 section mismatch warnings + +From: Arnd Bergmann + +commit 4c9ad387aa2d6785299722e54224d34764edaeb3 upstream. + +gcc-16 has gained some more advanced inter-procedual optimization +techniques that enable it to inline the dummy_tlb_add_page() and +dummy_tlb_flush() function pointers into a specialized version of +__arm_v7s_unmap: + +WARNING: modpost: vmlinux: section mismatch in reference: __arm_v7s_unmap+0x2cc (section: .text) -> dummy_tlb_add_page (section: .init.text) +ERROR: modpost: Section mismatches detected. + +>From what I can tell, the transformation is correct, as this is only +called when __arm_v7s_unmap() is called from arm_v7s_do_selftests(), +which is also __init. Since __arm_v7s_unmap() however is not __init, +gcc cannot inline the inner function calls directly. + +In debug_objects_selftest(), the same thing happens. Both the +caller and the leaf function are __init, but the IPA pulls +it into a non-init one: + +WARNING: modpost: vmlinux: section mismatch in reference: lookup_object_or_alloc+0x7c (section: .text.lookup_object_or_alloc) -> is_static_object (section: .init.text) + +Marking the affected functions as not "__init" would reliably avoid this +issue but is not a good solution because it removes an otherwise correct +annotation. I tried marking the functions as 'noinline', but that ended +up not covering all the affected configurations. + +With some more experimenting, I found that marking these functions as +__attribute__((noipa)) is both logical and reliable. + +In order to keep the syntax readable, add a custom macro for this in +include/linux/compiler_attributes.h next to other related macros and +use it to annotate both files. + +Link: https://lore.kernel.org/all/abRB6g-48ZX6Yl2r@willie-the-truck/ +Cc: Will Deacon +Cc: Thomas Gleixner +Cc: Andrew Morton +Cc: Miguel Ojeda +Cc: linux-kbuild@vger.kernel.org +Cc: stable@vger.kernel.org +Signed-off-by: Arnd Bergmann +Acked-by: Will Deacon +Acked-by: Thomas Gleixner +Acked-by: Miguel Ojeda +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/io-pgtable-arm-v7s.c | 18 ++++++++++++------ + include/linux/compiler_attributes.h | 11 +++++++++++ + lib/debugobjects.c | 2 +- + 3 files changed, 24 insertions(+), 7 deletions(-) + +--- a/drivers/iommu/io-pgtable-arm-v7s.c ++++ b/drivers/iommu/io-pgtable-arm-v7s.c +@@ -777,21 +777,27 @@ struct io_pgtable_init_fns io_pgtable_ar + + static struct io_pgtable_cfg *cfg_cookie __initdata; + +-static void __init dummy_tlb_flush_all(void *cookie) ++/* ++ * __noipa prevents gcc from turning indirect iommu_flush_ops calls ++ * into direct calls from a specialized __arm_v7s_unmap() that triggers ++ * a build time section mismatch assertion. ++ */ ++static __noipa void __init dummy_tlb_flush_all(void *cookie) + { + WARN_ON(cookie != cfg_cookie); + } + +-static void __init dummy_tlb_flush(unsigned long iova, size_t size, +- size_t granule, void *cookie) ++static __noipa void __init dummy_tlb_flush(unsigned long iova, size_t size, ++ size_t granule, void *cookie) + { + WARN_ON(cookie != cfg_cookie); + WARN_ON(!(size & cfg_cookie->pgsize_bitmap)); + } + +-static void __init dummy_tlb_add_page(struct iommu_iotlb_gather *gather, +- unsigned long iova, size_t granule, +- void *cookie) ++static __noipa void __init dummy_tlb_add_page(struct iommu_iotlb_gather *gather, ++ unsigned long iova, ++ size_t granule, ++ void *cookie) + { + dummy_tlb_flush(iova, granule, granule, cookie); + } +--- a/include/linux/compiler_attributes.h ++++ b/include/linux/compiler_attributes.h +@@ -397,6 +397,17 @@ + #endif + + /* ++ * Optional: not supported by clang ++ * ++ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-noipa ++ */ ++#if __has_attribute(noipa) ++# define __noipa __attribute__((noipa)) ++#else ++# define __noipa ++#endif ++ ++/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-weak-function-attribute + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-weak-variable-attribute + */ +--- a/lib/debugobjects.c ++++ b/lib/debugobjects.c +@@ -1212,7 +1212,7 @@ struct self_test { + + static __initconst const struct debug_obj_descr descr_type_test; + +-static bool __init is_static_object(void *addr) ++static __noipa bool __init is_static_object(void *addr) + { + struct self_test *obj = addr; + diff --git a/queue-7.0/ip6-vti-use-ip6_tnl.net-in-vti6_changelink.patch b/queue-7.0/ip6-vti-use-ip6_tnl.net-in-vti6_changelink.patch new file mode 100644 index 0000000000..14e3b90e50 --- /dev/null +++ b/queue-7.0/ip6-vti-use-ip6_tnl.net-in-vti6_changelink.patch @@ -0,0 +1,76 @@ +From 11b326fb0a374f4654f9be22d0f0f7abd9f7d3fe Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Thu, 21 May 2026 21:05:54 +0800 +Subject: ip6: vti: Use ip6_tnl.net in vti6_changelink(). + +From: Kuniyuki Iwashima + +commit 11b326fb0a374f4654f9be22d0f0f7abd9f7d3fe upstream. + +ip netns add ns1 +ip netns add ns2 +ip -n ns1 link add vti6_test type vti6 remote ::1 local ::2 key 7 +ip -n ns1 link set vti6_test netns ns2 +ip -n ns2 link set vti6_test type vti6 remote ::3 local ::4 key 9 +ip netns del ns2 +ip netns del ns1 +[ 132.495484] ------------[ cut here ]------------ +[ 132.497609] kernel BUG at net/core/dev.c:12376! + +Commit 61220ab34948 ("vti6: Enable namespace changing") dropped +NETIF_F_NETNS_LOCAL from vti6 devices. A vti6 tunnel can then +move through IFLA_NET_NS_FD. After the move dev_net(dev) points +at the new netns while t->net stays at the creation netns. + +vti6_changelink() and vti6_update() still use dev_net(dev) and +dev_net(t->dev). They unlink from one per netns hash and relink +into another. The creation netns is left with a stale entry. +cleanup_net() of that netns later walks freed memory. + +Reachable from an unprivileged user namespace (unshare --user +--map-root-user --net). Cross tenant scope on container hosts. + +Fixes: 61220ab34948 ("vti6: Enable namespace changing") +Reported-by: Maoyi Xie +Reviewed-by: Eric Dumazet +Cc: stable@vger.kernel.org # v5.15+ +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260521130555.3421684-2-maoyixie.tju@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_vti.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -722,10 +722,11 @@ vti6_tnl_change(struct ip6_tnl *t, const + static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p, + bool keep_mtu) + { +- struct net *net = dev_net(t->dev); +- struct vti6_net *ip6n = net_generic(net, vti6_net_id); ++ struct net *net = t->net; ++ struct vti6_net *ip6n; + int err; + ++ ip6n = net_generic(net, vti6_net_id); + vti6_tnl_unlink(ip6n, t); + synchronize_net(); + err = vti6_tnl_change(t, p, keep_mtu); +@@ -1038,11 +1039,12 @@ static int vti6_changelink(struct net_de + struct nlattr *data[], + struct netlink_ext_ack *extack) + { +- struct ip6_tnl *t; ++ struct ip6_tnl *t = netdev_priv(dev); ++ struct net *net = t->net; + struct __ip6_tnl_parm p; +- struct net *net = dev_net(dev); +- struct vti6_net *ip6n = net_generic(net, vti6_net_id); ++ struct vti6_net *ip6n; + ++ ip6n = net_generic(net, vti6_net_id); + if (dev == ip6n->fb_tnl_dev) + return -EINVAL; + diff --git a/queue-7.0/ip6-vti-use-ip6_tnl.net-in-vti6_siocdevprivate.patch b/queue-7.0/ip6-vti-use-ip6_tnl.net-in-vti6_siocdevprivate.patch new file mode 100644 index 0000000000..f10ca6a467 --- /dev/null +++ b/queue-7.0/ip6-vti-use-ip6_tnl.net-in-vti6_siocdevprivate.patch @@ -0,0 +1,88 @@ +From 8b484efd5cb4eeef9021a661e198edc5349dacf6 Mon Sep 17 00:00:00 2001 +From: Maoyi Xie +Date: Thu, 21 May 2026 21:05:55 +0800 +Subject: ip6: vti: Use ip6_tnl.net in vti6_siocdevprivate(). + +From: Maoyi Xie + +commit 8b484efd5cb4eeef9021a661e198edc5349dacf6 upstream. + +After patch 1/2 in this series, vti6_update() unlinks and relinks +the tunnel through t->net. vti6_siocdevprivate() still uses +dev_net(dev) for the collision lookup. For a tunnel moved through +IFLA_NET_NS_FD, dev_net(dev) is the new netns, not t->net. + +SIOCCHGTUNNEL on a migrated tunnel then runs: + + net = dev_net(dev) /* migrated netns */ + t = vti6_locate(net, &p1, false) /* misses target in t->net */ + ... + t = netdev_priv(dev) + vti6_update(t, &p1, false) /* mutates t->net's hash */ + +A caller in the migrated netns picks params that match a tunnel +in the creation netns. The lookup in dev_net(dev) finds nothing. +vti6_update() prepends the migrated tunnel at the head of the +creation netns hash bucket for those params. Later lookups in +the creation netns resolve to the migrated device. xfrm receive +delivers the matched packets through a device the caller controls. + +Reachable from an unprivileged user namespace (unshare --user +--map-root-user --net). Cross tenant scope on container hosts. + +Switch the SIOCCHGTUNNEL path on a non fallback device to use +t->net for the lookup. The lookup now matches the netns +vti6_update() operates on. + +Also add ns_capable(self->net->user_ns, CAP_NET_ADMIN) before +the lookup. The check at the top of the case is against +dev_net(dev)->user_ns, which after migration is the attacker's +netns. A caller there can pick params absent from self->net, +the lookup returns NULL, t becomes self, and vti6_update() +inserts the device into the creation netns hash. The new check +requires CAP_NET_ADMIN in the creation netns user_ns too. + +SIOCADDTUNNEL and SIOCCHGTUNNEL on the fallback device keep +dev_net(dev), which equals init_net there. + +Fixes: 61220ab34948 ("vti6: Enable namespace changing") +Suggested-by: Jakub Kicinski +Suggested-by: Xiao Liang +Cc: stable@vger.kernel.org # v5.15+ +Signed-off-by: Maoyi Xie +Link: https://patch.msgid.link/20260521130555.3421684-3-maoyixie.tju@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_vti.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -834,17 +834,24 @@ vti6_siocdevprivate(struct net_device *d + if (p.proto != IPPROTO_IPV6 && p.proto != 0) + break; + vti6_parm_from_user(&p1, &p); +- t = vti6_locate(net, &p1, cmd == SIOCADDTUNNEL); + if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { ++ struct ip6_tnl *self = netdev_priv(dev); ++ ++ err = -EPERM; ++ if (!ns_capable(self->net->user_ns, CAP_NET_ADMIN)) ++ break; ++ t = vti6_locate(self->net, &p1, false); + if (t) { + if (t->dev != dev) { + err = -EEXIST; + break; + } + } else +- t = netdev_priv(dev); ++ t = self; + + err = vti6_update(t, &p1, false); ++ } else { ++ t = vti6_locate(net, &p1, cmd == SIOCADDTUNNEL); + } + if (t) { + err = 0; diff --git a/queue-7.0/ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch b/queue-7.0/ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch new file mode 100644 index 0000000000..8729b2713f --- /dev/null +++ b/queue-7.0/ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch @@ -0,0 +1,48 @@ +From f7b52afe3592eae66e160586b45a3f2242972c63 Mon Sep 17 00:00:00 2001 +From: Zhengchuan Liang +Date: Fri, 22 May 2026 17:42:26 +0800 +Subject: ipv6: exthdrs: refresh nh after handling HAO option + +From: Zhengchuan Liang + +commit f7b52afe3592eae66e160586b45a3f2242972c63 upstream. + +ip6_parse_tlv() caches skb_network_header(skb) in nh while walking +IPv6 TLVs. + +ipv6_dest_hao() may call pskb_expand_head() for a cloned skb, which can +move the skb head and invalidate the cached network header pointer. +Refresh nh after ipv6_dest_hao() returns so any trailing padding or TLVs +are parsed from the current skb head. + +This matches the existing pattern used in ip6_parse_tlv() after helpers +that can modify skb header storage. + +Fixes: a831f5bbc89a ("[IPV6] MIP6: Add inbound interface of home address option.") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Xin Liu +Co-developed-by: Luxing Yin +Signed-off-by: Luxing Yin +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Justin Iurman +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/7aba1debc2196189172499e5769802b026f8caf8.1779247873.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/exthdrs.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -203,6 +203,8 @@ static bool ip6_parse_tlv(bool hopbyhop, + case IPV6_TLV_HAO: + if (!ipv6_dest_hao(skb, off)) + return false; ++ ++ nh = skb_network_header(skb); + break; + #endif + default: diff --git a/queue-7.0/ipv6-exthdrs-refresh-nh-pointer-after-ipv6_hop_jumbo.patch b/queue-7.0/ipv6-exthdrs-refresh-nh-pointer-after-ipv6_hop_jumbo.patch new file mode 100644 index 0000000000..7c73288bb2 --- /dev/null +++ b/queue-7.0/ipv6-exthdrs-refresh-nh-pointer-after-ipv6_hop_jumbo.patch @@ -0,0 +1,34 @@ +From d47548a36639095939f4747d4c43f2271366f565 Mon Sep 17 00:00:00 2001 +From: Justin Iurman +Date: Fri, 22 May 2026 13:20:13 +0200 +Subject: ipv6: exthdrs: refresh nh pointer after ipv6_hop_jumbo() + +From: Justin Iurman + +commit d47548a36639095939f4747d4c43f2271366f565 upstream. + +ipv6_hop_jumbo() calls pskb_trim_rcsum(), which can change skb pointers. +Let's recompute nh pointer to make sure any change won't mess things up. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Justin Iurman +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260522112013.12342-1-justin.iurman@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/exthdrs.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -184,6 +184,8 @@ static bool ip6_parse_tlv(bool hopbyhop, + case IPV6_TLV_JUMBO: + if (!ipv6_hop_jumbo(skb, off)) + return false; ++ ++ nh = skb_network_header(skb); + break; + case IPV6_TLV_CALIPSO: + if (!ipv6_hop_calipso(skb, off)) diff --git a/queue-7.0/ipv6-validate-extension-header-length-before-copying-to-cmsg.patch b/queue-7.0/ipv6-validate-extension-header-length-before-copying-to-cmsg.patch new file mode 100644 index 0000000000..78caabecca --- /dev/null +++ b/queue-7.0/ipv6-validate-extension-header-length-before-copying-to-cmsg.patch @@ -0,0 +1,166 @@ +From dd433671fef381fdaf7b530c631e6b782d66e224 Mon Sep 17 00:00:00 2001 +From: Qi Tang +Date: Sat, 23 May 2026 22:32:45 +0800 +Subject: ipv6: validate extension header length before copying to cmsg + +From: Qi Tang + +commit dd433671fef381fdaf7b530c631e6b782d66e224 upstream. + +ip6_datagram_recv_specific_ctl() builds IPV6_{HOPOPTS,DSTOPTS,RTHDR} +cmsgs (and their IPV6_2292* legacy counterparts) by trusting the +on-wire hdrlen byte (ptr[1]) when computing the put_cmsg() length. +The length was validated only at parse time (ipv6_parse_hopopts(), +etc.). An nftables payload-write expression can rewrite hdrlen after +parsing and before the skb reaches recvmsg; the write itself is +in-bounds but put_cmsg() then reads up to ((hdrlen+1) << 3) = 2040 +bytes from an 8-byte header. nftables is reachable from an +unprivileged user namespace, so this is an unprivileged +slab-out-of-bounds read: + + BUG: KASAN: slab-out-of-bounds in put_cmsg+0x3ac/0x540 + put_cmsg+0x3ac/0x540 + udpv6_recvmsg+0xca0/0x1250 + sock_recvmsg+0xdf/0x190 + ____sys_recvmsg+0x1b1/0x620 + +Add ipv6_get_exthdr_len() which validates that at least two bytes +are accessible before reading the hdrlen field, then checks the +computed length against skb_tail_pointer(skb), returning 0 on +failure. Extension headers are kept in the linear skb area by +pskb_may_pull() during input, so skb_tail_pointer() is the correct +bound. + +Use ipv6_get_exthdr_len() at all non-AH call sites: the five +standalone cmsg blocks (HbH, 2292HbH, 2292DSTOPTS x2, 2292RTHDR) +and the three standard cases in the extension-header walk loop +(DSTOPTS, ROUTING, default). AH retains an inline bounds check +because its length formula differs ((ptr[1]+2)<<2). + +The walk loop also gets a pre-read bounds check at the top to +validate ptr before any case accesses ptr[0] or ptr[1]. + +When the walk loop detects a corrupted header, return from the +function instead of continuing to process later socket options. + +Cc: stable@vger.kernel.org +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Qi Tang +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260523143245.2281415-1-tpluszz77@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/datagram.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 46 insertions(+), 8 deletions(-) + +--- a/net/ipv6/datagram.c ++++ b/net/ipv6/datagram.c +@@ -618,6 +618,18 @@ void ip6_datagram_recv_common_ctl(struct + } + } + ++static u16 ipv6_get_exthdr_len(const struct sk_buff *skb, const u8 *ptr) ++{ ++ u16 len; ++ ++ if (ptr + 2 > skb_tail_pointer(skb)) ++ return 0; ++ ++ len = (ptr[1] + 1) << 3; ++ ++ return (len <= skb_tail_pointer(skb) - ptr) ? len : 0; ++} ++ + void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, + struct sk_buff *skb) + { +@@ -644,7 +656,10 @@ void ip6_datagram_recv_specific_ctl(stru + /* HbH is allowed only once */ + if (np->rxopt.bits.hopopts && (opt->flags & IP6SKB_HOPBYHOP)) { + u8 *ptr = nh + sizeof(struct ipv6hdr); +- put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr); ++ u16 len = ipv6_get_exthdr_len(skb, ptr); ++ ++ if (len) ++ put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, len, ptr); + } + + if (opt->lastopt && +@@ -665,26 +680,37 @@ void ip6_datagram_recv_specific_ctl(stru + unsigned int len; + u8 *ptr = nh + off; + ++ if (ptr + 2 > skb_tail_pointer(skb)) ++ return; ++ + switch (nexthdr) { + case IPPROTO_DSTOPTS: + nexthdr = ptr[0]; +- len = (ptr[1] + 1) << 3; ++ len = ipv6_get_exthdr_len(skb, ptr); ++ if (!len) ++ return; + if (np->rxopt.bits.dstopts) + put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, len, ptr); + break; + case IPPROTO_ROUTING: + nexthdr = ptr[0]; +- len = (ptr[1] + 1) << 3; ++ len = ipv6_get_exthdr_len(skb, ptr); ++ if (!len) ++ return; + if (np->rxopt.bits.srcrt) + put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, len, ptr); + break; + case IPPROTO_AH: + nexthdr = ptr[0]; + len = (ptr[1] + 2) << 2; ++ if (ptr + len > skb_tail_pointer(skb)) ++ return; + break; + default: + nexthdr = ptr[0]; +- len = (ptr[1] + 1) << 3; ++ len = ipv6_get_exthdr_len(skb, ptr); ++ if (!len) ++ return; + break; + } + +@@ -706,19 +732,31 @@ void ip6_datagram_recv_specific_ctl(stru + } + if (np->rxopt.bits.ohopopts && (opt->flags & IP6SKB_HOPBYHOP)) { + u8 *ptr = nh + sizeof(struct ipv6hdr); +- put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr); ++ u16 len = ipv6_get_exthdr_len(skb, ptr); ++ ++ if (len) ++ put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, len, ptr); + } + if (np->rxopt.bits.odstopts && opt->dst0) { + u8 *ptr = nh + opt->dst0; +- put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); ++ u16 len = ipv6_get_exthdr_len(skb, ptr); ++ ++ if (len) ++ put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, len, ptr); + } + if (np->rxopt.bits.osrcrt && opt->srcrt) { + struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(nh + opt->srcrt); +- put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr); ++ u16 len = ipv6_get_exthdr_len(skb, (u8 *)rthdr); ++ ++ if (len) ++ put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, len, rthdr); + } + if (np->rxopt.bits.odstopts && opt->dst1) { + u8 *ptr = nh + opt->dst1; +- put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); ++ u16 len = ipv6_get_exthdr_len(skb, ptr); ++ ++ if (len) ++ put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, len, ptr); + } + if (np->rxopt.bits.rxorigdstaddr) { + struct sockaddr_in6 sin6; diff --git a/queue-7.0/l2tp-use-refcount_inc_not_zero-in-l2tp_session_get_by_ifname.patch b/queue-7.0/l2tp-use-refcount_inc_not_zero-in-l2tp_session_get_by_ifname.patch new file mode 100644 index 0000000000..446da3c195 --- /dev/null +++ b/queue-7.0/l2tp-use-refcount_inc_not_zero-in-l2tp_session_get_by_ifname.patch @@ -0,0 +1,73 @@ +From 05f95729ca844704d15e49ce14868af4b403b32b Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Fri, 22 May 2026 22:34:23 -0400 +Subject: l2tp: use refcount_inc_not_zero in l2tp_session_get_by_ifname + +From: Michael Bommarito + +commit 05f95729ca844704d15e49ce14868af4b403b32b upstream. + +A reader in l2tp_session_get_by_ifname() can return a pointer to a +session whose refcount has reached zero. The getter takes its +reference with plain refcount_inc(), but every other session getter +in the same file (l2tp_v2_session_get, l2tp_v3_session_get, and the +corresponding _get_next variants) uses refcount_inc_not_zero() +because the IDR/RCU lookup can race with refcount_dec_and_test() -> +l2tp_session_free() -> kfree_rcu(). The ifname getter is the only +outlier; the inconsistency was raised on-list after 979c017803c4 +("l2tp: use list_del_rcu in l2tp_session_unhash"). + +A reader inside rcu_read_lock_bh() that matches session->ifname can +be preempted between the strcmp() and the refcount_inc(). If the +last reference drops on another CPU in that window, the reader's +refcount_inc() runs on a counter that has reached zero. refcount_t +catches the addition-on-zero, prints "refcount_t: addition on 0; +use-after-free", saturates the counter, and returns the saturated +pointer to the caller. Session memory is held live by the in-flight +RCU read section, but the kfree_rcu() callback queued from +l2tp_session_free() will free it once the grace period closes; a +caller that dereferences the returned session past that point hits +a slab-use-after-free. On PREEMPT_RT local_bh_disable() is a per-CPU +sleeping lock and the preemption window is real; on stock PREEMPT +kernels local_bh_disable() is a preempt_count increment that closes +the cross-CPU race in practice (see below). + +Use refcount_inc_not_zero() and continue the list walk on failure, +matching the other session getters in the file. The ifname getter +is the only session getter in net/l2tp/ that still uses the bare +refcount_inc() pattern; this change restores file-internal +consistency. The success path is unchanged. + +Fixes: abe7a1a7d0b6 ("l2tp: improve tunnel/session refcount helpers") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Reviewed-by: James Chapman +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260523023423.2568972-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/l2tp/l2tp_core.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -441,12 +441,13 @@ struct l2tp_session *l2tp_session_get_by + idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) { + if (tunnel) { + list_for_each_entry_rcu(session, &tunnel->session_list, list) { +- if (!strcmp(session->ifname, ifname)) { +- refcount_inc(&session->ref_count); +- rcu_read_unlock_bh(); ++ if (strcmp(session->ifname, ifname)) ++ continue; ++ if (!refcount_inc_not_zero(&session->ref_count)) ++ continue; ++ rcu_read_unlock_bh(); + +- return session; +- } ++ return session; + } + } + } diff --git a/queue-7.0/macsec-fix-replay-protection-at-xpn-lower-pn-wrap.patch b/queue-7.0/macsec-fix-replay-protection-at-xpn-lower-pn-wrap.patch new file mode 100644 index 0000000000..53bbd666fb --- /dev/null +++ b/queue-7.0/macsec-fix-replay-protection-at-xpn-lower-pn-wrap.patch @@ -0,0 +1,43 @@ +From e68842b3356471ba56c882209f324613dac47f64 Mon Sep 17 00:00:00 2001 +From: Junrui Luo +Date: Wed, 20 May 2026 11:47:55 +0800 +Subject: macsec: fix replay protection at XPN lower-PN wrap + +From: Junrui Luo + +commit e68842b3356471ba56c882209f324613dac47f64 upstream. + +In macsec_post_decrypt(), when pn is U32_MAX, pn + 1 overflows u32 to 0 +and the first branch never fires. If next_pn_halves.lower is also in the +upper half, pn_same_half(pn, lower) is true and the XPN else-if does not +fire either, leaving next_pn_halves unchanged. An attacker that captures +the legitimate frame carrying pn == 0xFFFFFFFF on an XPN association +can then replay it indefinitely, since lowest_pn never rises above +the captured pn and macsec_decrypt() reconstructs the same IV. + +Extend the XPN else-if to also fire when pn + 1 wraps to 0, so receipt +of pn == U32_MAX advances next_pn_halves to (upper + 1, 0). + +Fixes: a21ecf0e0338 ("macsec: Support XPN frame handling - IEEE 802.1AEbw") +Reported-by: Yuhao Jiang +Cc: stable@vger.kernel.org +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB78813FD49E58F253B989F197AF012@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/macsec.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -804,7 +804,8 @@ static bool macsec_post_decrypt(struct s + if (pn + 1 > rx_sa->next_pn_halves.lower) { + rx_sa->next_pn_halves.lower = pn + 1; + } else if (secy->xpn && +- !pn_same_half(pn, rx_sa->next_pn_halves.lower)) { ++ (pn + 1 == 0 || ++ !pn_same_half(pn, rx_sa->next_pn_halves.lower))) { + rx_sa->next_pn_halves.upper++; + rx_sa->next_pn_halves.lower = pn + 1; + } diff --git a/queue-7.0/net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch b/queue-7.0/net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch new file mode 100644 index 0000000000..5d53746b17 --- /dev/null +++ b/queue-7.0/net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch @@ -0,0 +1,88 @@ +From 98d0912e9f841e5529a5b89a972805f34cb1c69d Mon Sep 17 00:00:00 2001 +From: Minh Nguyen +Date: Tue, 26 May 2026 11:12:39 +0700 +Subject: net: skbuff: fix missing zerocopy reference in pskb_carve helpers + +From: Minh Nguyen + +commit 98d0912e9f841e5529a5b89a972805f34cb1c69d upstream. + +pskb_carve_inside_header() and pskb_carve_inside_nonlinear() both copy +the old skb_shared_info header into a new buffer via memcpy(), which +includes the destructor_arg pointer (uarg) for MSG_ZEROCOPY skbs. +Neither function calls net_zcopy_get() for the new shinfo, creating an +unaccounted holder: every skb_shared_info with destructor_arg set will +call skb_zcopy_clear() once when freed, but the corresponding +net_zcopy_get() was never called for the new copy. Repeated calls +drive uarg->refcnt to zero prematurely, freeing ubuf_info_msgzc while +TX skbs still hold live destructor_arg pointers. + +KASAN reports use-after-free on a freed ubuf_info_msgzc: + + BUG: KASAN: slab-use-after-free in skb_release_data+0x77b/0x810 + Read of size 8 at addr ffff88801574d3e8 by task poc/220 + + Call Trace: + skb_release_data+0x77b/0x810 + kfree_skb_list_reason+0x13e/0x610 + skb_release_data+0x4cd/0x810 + sk_skb_reason_drop+0xf3/0x340 + skb_queue_purge_reason+0x282/0x440 + rds_tcp_inc_free+0x1e/0x30 + rds_recvmsg+0x354/0x1780 + __sys_recvmsg+0xdf/0x180 + + Allocated by task 219: + msg_zerocopy_realloc+0x157/0x7b0 + tcp_sendmsg_locked+0x2892/0x3ba0 + + Freed by task 219: + ip_recv_error+0x74a/0xb10 + tcp_recvmsg+0x475/0x530 + +The skb consuming the late access still referenced the same uarg via +shinfo->destructor_arg copied by pskb_carve_inside_nonlinear() without +a refcount bump. This has been verified to be reliably exploitable: a +working proof-of-concept achieves full root privilege escalation from +an unprivileged local user on a default kernel configuration. + +The fix follows the pattern of pskb_expand_head() which has the same +memcpy/cloned structure. For pskb_carve_inside_header(), net_zcopy_get() +is placed after skb_orphan_frags() succeeds, so the orphan error path +needs no cleanup. For pskb_carve_inside_nonlinear(), net_zcopy_get() is +placed after all failure points and just before skb_release_data(), so +no error path needs cleanup at all -- matching pskb_expand_head() more +closely and avoiding the need for a balancing net_zcopy_put(). + +Fixes: 6fa01ccd8830 ("skbuff: Add pskb_extract() helper function") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-sonnet-4-6 +Signed-off-by: Minh Nguyen +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260526041240.329462-1-minhnguyen.080505@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/core/skbuff.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6862,6 +6862,8 @@ static int pskb_carve_inside_header(stru + skb_kfree_head(data, size); + return -ENOMEM; + } ++ if (skb_zcopy(skb)) ++ net_zcopy_get(skb_zcopy(skb)); + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + skb_frag_ref(skb, i); + if (skb_has_frag_list(skb)) +@@ -7010,6 +7012,8 @@ static int pskb_carve_inside_nonlinear(s + skb_kfree_head(data, size); + return -ENOMEM; + } ++ if (skb_zcopy(skb)) ++ net_zcopy_get(skb_zcopy(skb)); + skb_release_data(skb, SKB_CONSUMED); + + skb->head = data; diff --git a/queue-7.0/netfilter-conntrack-tcp-do-not-force-close-on-invalid-seq-rst-without-direction-check.patch b/queue-7.0/netfilter-conntrack-tcp-do-not-force-close-on-invalid-seq-rst-without-direction-check.patch new file mode 100644 index 0000000000..ae3557d707 --- /dev/null +++ b/queue-7.0/netfilter-conntrack-tcp-do-not-force-close-on-invalid-seq-rst-without-direction-check.patch @@ -0,0 +1,49 @@ +From bed6e04be8e6b9133d8b16d5a42d0e0ce674fa9a Mon Sep 17 00:00:00 2001 +From: Hamza Mahfooz +Date: Mon, 11 May 2026 10:43:14 -0400 +Subject: netfilter: conntrack: tcp: do not force CLOSE on invalid-seq RST without direction check + +From: Hamza Mahfooz + +commit bed6e04be8e6b9133d8b16d5a42d0e0ce674fa9a upstream. + +An unintended behavior in the TCP conntrack state machine allows a +connection to be forced into the CLOSE state using an RST packet with an +invalid sequence number. + +Specifically, after a SYN packet is observed, an RST with an invalid SEQ +can transition the conntrack entry to TCP_CONNTRACK_CLOSE, regardless of +whether the RST corresponds to the expected reply direction. The relevant +code path assumes the RST is a response to an outgoing SYN, but does not +validate packet direction or ensure that a matching SYN was actually sent +in the opposite direction. + +As a result, a crafted packet sequence consisting of a SYN followed by an +invalid-sequence RST can prematurely terminate an active NAT entry. This +makes connection teardown easier than intended. + +So, tighten the state transition logic to ensure that RST-triggered +CLOSE transitions only occur when the RST is a valid response to a +previously observed SYN in the correct direction. + +Cc: stable@vger.kernel.org +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Hamza Mahfooz +Signed-off-by: Florian Westphal +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_conntrack_proto_tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -1221,7 +1221,8 @@ int nf_conntrack_tcp_packet(struct nf_co + new_state = old_state; + } + if (((test_bit(IPS_SEEN_REPLY_BIT, &ct->status) +- && ct->proto.tcp.last_index == TCP_SYN_SET) ++ && ct->proto.tcp.last_index == TCP_SYN_SET ++ && ct->proto.tcp.last_dir != dir) + || (!test_bit(IPS_ASSURED_BIT, &ct->status) + && ct->proto.tcp.last_index == TCP_ACK_SET)) + && ntohl(th->ack_seq) == ct->proto.tcp.last_end) { diff --git a/queue-7.0/nfc-hci-fix-out-of-bounds-read-in-hcp-header-parsing.patch b/queue-7.0/nfc-hci-fix-out-of-bounds-read-in-hcp-header-parsing.patch new file mode 100644 index 0000000000..1f81e0e7f5 --- /dev/null +++ b/queue-7.0/nfc-hci-fix-out-of-bounds-read-in-hcp-header-parsing.patch @@ -0,0 +1,89 @@ +From f040e590c035bfd9553fe79ee9585caf1b14d67b Mon Sep 17 00:00:00 2001 +From: Ashutosh Desai +Date: Tue, 5 May 2026 17:07:12 +0000 +Subject: nfc: hci: fix out-of-bounds read in HCP header parsing + +From: Ashutosh Desai + +commit f040e590c035bfd9553fe79ee9585caf1b14d67b upstream. + +Both nfc_hci_recv_from_llc() and nci_hci_data_received_cb() read +packet->header from skb->data at function entry without first checking +that the buffer holds at least one byte. A malicious NFC peer can send +a 0-byte HCP frame that passes through the SHDLC layer and reaches +these functions, causing an out-of-bounds heap read of packet->header. +The same 0-byte frame, if queued as a non-final fragment, also causes +the reassembly loop to underflow msg_len to UINT_MAX, triggering +skb_over_panic() when the reassembled skb is written. + +Fix this by adding a pskb_may_pull() check at the entry of each +function before packet->header is first accessed. The existing +pskb_may_pull() checks before the reassembled hcp_skb is cast to +struct hcp_packet remain in place to guard the 2-byte HCP message +header. + +Fixes: 8b8d2e08bf0d ("NFC: HCI support") +Fixes: 11f54f228643 ("NFC: nci: Add HCI over NCI protocol support") +Cc: stable@vger.kernel.org +Reviewed-by: Simon Horman +Signed-off-by: Ashutosh Desai +Link: https://patch.msgid.link/20260505170712.96560-1-ashutoshdesai993@gmail.com +Signed-off-by: David Heidelberg +Signed-off-by: Greg Kroah-Hartman +--- + net/nfc/hci/core.c | 10 ++++++++++ + net/nfc/nci/hci.c | 10 ++++++++++ + 2 files changed, 20 insertions(+) + +--- a/net/nfc/hci/core.c ++++ b/net/nfc/hci/core.c +@@ -861,6 +861,11 @@ static void nfc_hci_recv_from_llc(struct + struct sk_buff *frag_skb; + int msg_len; + ++ if (!pskb_may_pull(skb, NFC_HCI_HCP_PACKET_HEADER_LEN)) { ++ kfree_skb(skb); ++ return; ++ } ++ + packet = (struct hcp_packet *)skb->data; + if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { + skb_queue_tail(&hdev->rx_hcp_frags, skb); +@@ -904,6 +909,11 @@ static void nfc_hci_recv_from_llc(struct + * unblock waiting cmd context. Otherwise, enqueue to dispatch + * in separate context where handler can also execute command. + */ ++ if (!pskb_may_pull(hcp_skb, NFC_HCI_HCP_HEADER_LEN)) { ++ kfree_skb(hcp_skb); ++ return; ++ } ++ + packet = (struct hcp_packet *)hcp_skb->data; + type = HCP_MSG_GET_TYPE(packet->message.header); + if (type == NFC_HCI_HCP_RESPONSE) { +--- a/net/nfc/nci/hci.c ++++ b/net/nfc/nci/hci.c +@@ -439,6 +439,11 @@ void nci_hci_data_received_cb(void *cont + return; + } + ++ if (!pskb_may_pull(skb, NCI_HCI_HCP_PACKET_HEADER_LEN)) { ++ kfree_skb(skb); ++ return; ++ } ++ + packet = (struct nci_hcp_packet *)skb->data; + if ((packet->header & ~NCI_HCI_FRAGMENT) == 0) { + skb_queue_tail(&ndev->hci_dev->rx_hcp_frags, skb); +@@ -482,6 +487,11 @@ void nci_hci_data_received_cb(void *cont + * unblock waiting cmd context. Otherwise, enqueue to dispatch + * in separate context where handler can also execute command. + */ ++ if (!pskb_may_pull(hcp_skb, NCI_HCI_HCP_HEADER_LEN)) { ++ kfree_skb(hcp_skb); ++ return; ++ } ++ + packet = (struct nci_hcp_packet *)hcp_skb->data; + type = NCI_HCP_MSG_GET_TYPE(packet->message.header); + if (type == NCI_HCI_HCP_RESPONSE) { diff --git a/queue-7.0/octeontx2-af-validate-body-pcifunc-in-rvu_mbox_handler_rep_event_notify.patch b/queue-7.0/octeontx2-af-validate-body-pcifunc-in-rvu_mbox_handler_rep_event_notify.patch new file mode 100644 index 0000000000..8fe4997fb7 --- /dev/null +++ b/queue-7.0/octeontx2-af-validate-body-pcifunc-in-rvu_mbox_handler_rep_event_notify.patch @@ -0,0 +1,86 @@ +From 2156a29aecfffa2eb7c558255690084efbe9f3b0 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Wed, 20 May 2026 11:41:57 -0400 +Subject: octeontx2-af: validate body pcifunc in rvu_mbox_handler_rep_event_notify + +From: Michael Bommarito + +commit 2156a29aecfffa2eb7c558255690084efbe9f3b0 upstream. + +rvu_mbox_handler_rep_event_notify() in drivers/net/ethernet/marvell/ +octeontx2/af/rvu_rep.c queues a sender-controlled REP_EVENT_NOTIFY +request body verbatim, and rvu_rep_up_notify() then forwards +event->pcifunc (the nested body field, distinct from the +AF-normalised header pcifunc) into rvu_get_pfvf(), rvu_get_pf() and +the AF->PF mailbox device index without any bounds check. + +A VF attached to a PF that has been put into switchdev +representor mode reaches this path: the VF mailbox handler +otx2_pfvf_mbox_handler() forwards every message id including +MBOX_MSG_REP_EVENT_NOTIFY to AF without an allowlist, and the AF +dispatcher rewrites only msg->pcifunc, leaving struct +rep_event::pcifunc attacker-controlled. The sibling +rvu_mbox_handler_esw_cfg() refuses requests whose header pcifunc +is not rvu->rep_pcifunc; this handler has no equivalent gate. + +An out-of-range body pcifunc selects an &rvu->pf[]/&rvu->hwvf[] +element past the allocated array and, for RVU_EVENT_MAC_ADDR_CHANGE, +turns into a six-byte attacker-chosen OOB ether_addr_copy() target +inside the queued worker; KASAN reports a slab-out-of-bounds write +in rvu_rep_wq_handler. + +Reject malformed requests at the handler entry by gating on +is_pf_func_valid(), which is already the canonical PF/VF range check +in this driver; expose it via rvu.h so callers in rvu_rep.c can use +it instead of open-coding the same range arithmetic. + +Fixes: b8fea84a0468 ("octeontx2-pf: Add support to sync link state between representor and VFs") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260520154157.1439319-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 2 +- + drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 1 + + drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c | 8 ++++++++ + 3 files changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -435,7 +435,7 @@ struct rvu_pfvf *rvu_get_pfvf(struct rvu + return &rvu->pf[rvu_get_pf(rvu->pdev, pcifunc)]; + } + +-static bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc) ++bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc) + { + int pf, vf, nvfs; + u64 cfg; +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -910,6 +910,7 @@ u16 rvu_get_rsrc_mapcount(struct rvu_pfv + struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc); + void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf); + bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr); ++bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc); + bool is_pffunc_map_valid(struct rvu *rvu, u16 pcifunc, int blktype); + int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot); + int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf); +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c +@@ -97,6 +97,14 @@ int rvu_mbox_handler_rep_event_notify(st + { + struct rep_evtq_ent *qentry; + ++ /* The mailbox dispatcher normalises only the header pcifunc; the ++ * nested struct rep_event::pcifunc body field is sender-controlled ++ * and is later used by rvu_rep_up_notify() to index rvu->pf[] / ++ * rvu->hwvf[]. Reject out-of-range body selectors before queueing. ++ */ ++ if (!is_pf_func_valid(rvu, req->pcifunc)) ++ return -EINVAL; ++ + qentry = kmalloc_obj(*qentry, GFP_ATOMIC); + if (!qentry) + return -ENOMEM; diff --git a/queue-7.0/series b/queue-7.0/series index 7c14905f34..d702f3cbeb 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -205,3 +205,32 @@ usb-dwc2-fix-use-after-free-in-debug-code.patch input-elan_i2c-validate-firmware-size-before-use.patch i2c-davinci-fix-division-by-zero-on-missing-clock-frequency.patch x86-ftrace-relocate-rip-relative-percpu-refs-in-dynamic-trampolines.patch +wireguard-send-append-trailer-after-expanding-head.patch +bpf-sockmap-fix-tail-fragment-offset-in-bpf_msg_push_data.patch +macsec-fix-replay-protection-at-xpn-lower-pn-wrap.patch +ipv6-exthdrs-refresh-nh-pointer-after-ipv6_hop_jumbo.patch +asoc-qcom-q6asm-dai-fix-error-handling-in-prepare-and-set_params.patch +octeontx2-af-validate-body-pcifunc-in-rvu_mbox_handler_rep_event_notify.patch +ipv6-exthdrs-refresh-nh-after-handling-hao-option.patch +ip6-vti-use-ip6_tnl.net-in-vti6_siocdevprivate.patch +ipv6-validate-extension-header-length-before-copying-to-cmsg.patch +xfrm-input-hold-netns-during-deferred-transport-reinjection.patch +l2tp-use-refcount_inc_not_zero-in-l2tp_session_get_by_ifname.patch +ip6-vti-use-ip6_tnl.net-in-vti6_changelink.patch +net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch +spi-spi-mem-avoid-mutating-op-template-in-spi_mem_supports_op.patch +hid-wacom-fix-oob-write-in-wacom_hid_set_device_mode.patch +iommu-debugobjects-avoid-gcc-16.1-section-mismatch-warnings.patch +nfc-hci-fix-out-of-bounds-read-in-hcp-header-parsing.patch +xfrm-route-migrate-notifications-to-caller-s-netns.patch +xfrm-ipcomp-free-destination-pages-on-acomp-errors.patch +xfrm-ah-use-skb_to_full_sk-in-async-output-callbacks.patch +alsa-scarlett2-fix-2i2-gen-4-direct-monitor-gain-on-firmware-2417.patch +alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch +netfilter-conntrack-tcp-do-not-force-close-on-invalid-seq-rst-without-direction-check.patch +asoc-qcom-q6asm-dai-close-stream-only-when-running.patch +asoc-qcom-q6asm-dai-do-not-set-stream-state-in-event-and-trigger-callbacks.patch +xfrm-esp-restore-combined-single-frag-length-gate.patch +alsa-hda-realtek-fix-speaker-output-on-asus-rog-strix-g615lp.patch +xfrm-iptfs-reset-runtime-state-when-cloning-sas.patch +dma-buf-fix-uaf-in-dma_buf_fd-tracepoint.patch diff --git a/queue-7.0/spi-spi-mem-avoid-mutating-op-template-in-spi_mem_supports_op.patch b/queue-7.0/spi-spi-mem-avoid-mutating-op-template-in-spi_mem_supports_op.patch new file mode 100644 index 0000000000..aef54bdacb --- /dev/null +++ b/queue-7.0/spi-spi-mem-avoid-mutating-op-template-in-spi_mem_supports_op.patch @@ -0,0 +1,57 @@ +From 79378db6a86c7014cce40b65252e6c18f5b8bcc2 Mon Sep 17 00:00:00 2001 +From: Santhosh Kumar K +Date: Wed, 27 May 2026 23:07:36 +0530 +Subject: spi: spi-mem: avoid mutating op template in spi_mem_supports_op() + +From: Santhosh Kumar K + +commit 79378db6a86c7014cce40b65252e6c18f5b8bcc2 upstream. + +spi_mem_supports_op() accepts a const struct spi_mem_op pointer but +casts away const internally to call spi_mem_adjust_op_freq(). This +mutates the caller's op template, which causes stale max_freq values +when callers reuse persistent templates - subsequent calls won't +re-apply the device frequency cap since spi_mem_adjust_op_freq() +skips non-zero values. + +Fix by operating on a stack-local copy instead. + +Fixes: a4f8e70d75dd ("spi: spi-mem: add spi_mem_adjust_op_freq() in spi_mem_supports_op()") +Cc: Tianyu Xu +Cc: stable@vger.kernel.org +Signed-off-by: Santhosh Kumar K +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260527173736.2243004-1-s-k6@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-mem.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-mem.c ++++ b/drivers/spi/spi-mem.c +@@ -279,13 +279,20 @@ static bool spi_mem_internal_supports_op + */ + bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) + { +- /* Make sure the operation frequency is correct before going futher */ +- spi_mem_adjust_op_freq(mem, (struct spi_mem_op *)op); ++ struct spi_mem_op eval_op = *op; + +- if (spi_mem_check_op(op)) ++ /* ++ * Work on a local copy; this is a pure capability check and must ++ * not modify the caller's op. Stored templates with max_freq == 0 ++ * must remain unset so their frequency is always re-capped to the ++ * current device maximum at execution time. ++ */ ++ spi_mem_adjust_op_freq(mem, &eval_op); ++ ++ if (spi_mem_check_op(&eval_op)) + return false; + +- return spi_mem_internal_supports_op(mem, op); ++ return spi_mem_internal_supports_op(mem, &eval_op); + } + EXPORT_SYMBOL_GPL(spi_mem_supports_op); + diff --git a/queue-7.0/wireguard-send-append-trailer-after-expanding-head.patch b/queue-7.0/wireguard-send-append-trailer-after-expanding-head.patch new file mode 100644 index 0000000000..703c1fb9fa --- /dev/null +++ b/queue-7.0/wireguard-send-append-trailer-after-expanding-head.patch @@ -0,0 +1,61 @@ +From f75e3eb08fe31d30a9af6ed80cdd22e6772837e2 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 29 May 2026 19:31:34 +0200 +Subject: wireguard: send: append trailer after expanding head + +From: Jason A. Donenfeld + +commit f75e3eb08fe31d30a9af6ed80cdd22e6772837e2 upstream. + +With how this is currently written, we add the trailer, zero it out, and +then add the header space on. If that header space requires a +reallocation + copy, the zeros in the trailer aren't copied, because the +skb len hasn't actually been yet expanded to cover that. Instead add the +padding at the end of the process rather than at the beginning. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Link: https://patch.msgid.link/20260529173134.3080773-2-Jason@zx2c4.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireguard/send.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -177,16 +177,6 @@ static bool encrypt_packet(struct sk_buf + trailer_len = padding_len + noise_encrypted_len(0); + plaintext_len = skb->len + padding_len; + +- /* Expand data section to have room for padding and auth tag. */ +- num_frags = skb_cow_data(skb, trailer_len, &trailer); +- if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg))) +- return false; +- +- /* Set the padding to zeros, and make sure it and the auth tag are part +- * of the skb. +- */ +- memset(skb_tail_pointer(trailer), 0, padding_len); +- + /* Expand head section to have room for our header and the network + * stack's headers. + */ +@@ -198,6 +188,16 @@ static bool encrypt_packet(struct sk_buf + skb_checksum_help(skb))) + return false; + ++ /* Expand data section to have room for padding and auth tag. */ ++ num_frags = skb_cow_data(skb, trailer_len, &trailer); ++ if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg))) ++ return false; ++ ++ /* Set the padding to zeros, and make sure it and the auth tag are part ++ * of the skb. ++ */ ++ memset(skb_tail_pointer(trailer), 0, padding_len); ++ + /* Only after checksumming can we safely add on the padding at the end + * and the header. + */ diff --git a/queue-7.0/xfrm-ah-use-skb_to_full_sk-in-async-output-callbacks.patch b/queue-7.0/xfrm-ah-use-skb_to_full_sk-in-async-output-callbacks.patch new file mode 100644 index 0000000000..a15cfb11aa --- /dev/null +++ b/queue-7.0/xfrm-ah-use-skb_to_full_sk-in-async-output-callbacks.patch @@ -0,0 +1,86 @@ +From 79d8be262377f7112cfa3088dfc4142d5a2533f3 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Fri, 15 May 2026 11:45:31 -0400 +Subject: xfrm: ah: use skb_to_full_sk in async output callbacks + +From: Michael Bommarito + +commit 79d8be262377f7112cfa3088dfc4142d5a2533f3 upstream. + +When AH output is offloaded to an asynchronous crypto provider +(hardware accelerators such as AMD CCP, or a forced-async software +shim used for testing), the digest completion fires +ah_output_done() / ah6_output_done() on a workqueue. The egress +skb at that point may have been originated by a TCP listener +sending a SYN-ACK, which sets skb->sk to a request_sock via +skb_set_owner_edemux(); it may also have been originated by an +inet_timewait_sock retransmit. Neither is a full struct sock, and +passing the raw skb->sk to xfrm_output_resume() then forwards a +non-full socket through the rest of the xfrm output chain. + +xfrm_output_resume() and its downstream consumers expect a full +sk where they dereference at all. The natural egress path +through ah_output_done() does not crash today because the +consumers that read past sock_common are either gated by +sk_fullsock() or short-circuit on flags that are clear on a fresh +request_sock; an exhaustive walk of the 50 most plausible +consumers under sch_fq, dev_queue_xmit, netfilter, tc-egress and +cgroup-egress BPF found no current unguarded deref. The bug is +still a real type confusion that future consumer changes could +turn into a memory-corruption primitive. + +This is the same bug class fixed for ESP in commit 1620c88887b1 +("xfrm: Fix the usage of skb->sk"). Apply the analogous fix to +AH: convert skb->sk to a full socket pointer (or NULL) via +skb_to_full_sk() before handing it to xfrm_output_resume(). + +The same async AH callbacks were touched recently for an +independent ESN-related ICV layout bug in commit ec54093e6a8f +("xfrm: ah: account for ESN high bits in async callbacks"); the +sk type-confusion addressed here is orthogonal. This patch is +part of an ongoing audit of the AH callback paths; an ah_output +ihl-validation hardening series is also currently under review on +netdev. + +Reproduced under UML + KASAN + lockdep with a forced-async +hmac(sha1) shim that registers at priority 9999 and wraps the +sync in-tree hmac-sha1-lib. With the shim loaded, ah_output_done +runs on every SYN-ACK egress through a transport-mode AH SA and +skb->sk arrives as a request_sock (TCP_NEW_SYN_RECV); after this +patch, xfrm_output_resume() receives the listener (the result of +sk_to_full_sk()) and consumer derefs land on full-sock fields as +intended. + +Fixes: 9ab1265d5231 ("xfrm: Use actual socket sk instead of skb socket for xfrm_output_resume") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ah4.c | 2 +- + net/ipv6/ah6.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ipv4/ah4.c ++++ b/net/ipv4/ah4.c +@@ -143,7 +143,7 @@ static void ah_output_done(void *data, i + } + + kfree(AH_SKB_CB(skb)->tmp); +- xfrm_output_resume(skb->sk, skb, err); ++ xfrm_output_resume(skb_to_full_sk(skb), skb, err); + } + + static int ah_output(struct xfrm_state *x, struct sk_buff *skb) +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -337,7 +337,7 @@ static void ah6_output_done(void *data, + ah6_restore_hdrs(top_iph, iph_ext, extlen); + + kfree(AH_SKB_CB(skb)->tmp); +- xfrm_output_resume(skb->sk, skb, err); ++ xfrm_output_resume(skb_to_full_sk(skb), skb, err); + } + + static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) diff --git a/queue-7.0/xfrm-esp-restore-combined-single-frag-length-gate.patch b/queue-7.0/xfrm-esp-restore-combined-single-frag-length-gate.patch new file mode 100644 index 0000000000..13af0299b3 --- /dev/null +++ b/queue-7.0/xfrm-esp-restore-combined-single-frag-length-gate.patch @@ -0,0 +1,60 @@ +From dfa0d7b0ff1eb6b2c416b8fdb9b4f2cefba57a40 Mon Sep 17 00:00:00 2001 +From: Jingguo Tan +Date: Mon, 18 May 2026 17:06:48 +0800 +Subject: xfrm: esp: restore combined single-frag length gate + +From: Jingguo Tan + +commit dfa0d7b0ff1eb6b2c416b8fdb9b4f2cefba57a40 upstream. + +The ESP out-of-place fast path appends the trailer in esp_output_head() +before esp_output_tail() allocates the destination page frag. The +head-side gate currently checks skb->data_len and tailen separately, but +the tail code allocates a single destination frag from the combined +post-trailer skb->data_len. + +Reject the page-frag fast path when the combined aligned length exceeds a +page. Otherwise skb_page_frag_refill() may fall back to a single page while +the destination sg still spans the combined skb->data_len. + +Restore this combined-length page gate for both IPv4 and IPv6. + +Fixes: 5bd8baab087d ("esp: limit skb_page_frag_refill use to a single page") +Cc: stable@vger.kernel.org +Signed-off-by: Lin Ma +Signed-off-by: Chenyuan Mi +Signed-off-by: Jingguo Tan +Reviewed-by: Sabrina Dubroca +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/esp4.c | 4 ++-- + net/ipv6/esp6.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -419,8 +419,8 @@ int esp_output_head(struct xfrm_state *x + return err; + } + +- if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE || +- ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE) ++ if (ALIGN(skb->data_len + tailen, L1_CACHE_BYTES) > ++ PAGE_SIZE) + goto cow; + + if (!skb_cloned(skb)) { +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -448,8 +448,8 @@ int esp6_output_head(struct xfrm_state * + return err; + } + +- if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE || +- ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE) ++ if (ALIGN(skb->data_len + tailen, L1_CACHE_BYTES) > ++ PAGE_SIZE) + goto cow; + + if (!skb_cloned(skb)) { diff --git a/queue-7.0/xfrm-input-hold-netns-during-deferred-transport-reinjection.patch b/queue-7.0/xfrm-input-hold-netns-during-deferred-transport-reinjection.patch new file mode 100644 index 0000000000..84012b09c1 --- /dev/null +++ b/queue-7.0/xfrm-input-hold-netns-during-deferred-transport-reinjection.patch @@ -0,0 +1,75 @@ +From c16f74dc1d75d0e2e7670076d5375deda110ebeb Mon Sep 17 00:00:00 2001 +From: Zhengchuan Liang +Date: Fri, 22 May 2026 17:31:55 +0800 +Subject: xfrm: input: hold netns during deferred transport reinjection + +From: Zhengchuan Liang + +commit c16f74dc1d75d0e2e7670076d5375deda110ebeb upstream. + +Transport-mode reinjection stores a struct net pointer in skb->cb and +uses it later from xfrm_trans_reinject(). That pointer must stay valid +until the deferred callback runs. + +Take a netns reference when queueing deferred reinjection work and drop +it after the callback completes. Use maybe_get_net() so the queueing +path does not revive a namespace that is already being torn down. + +This keeps the existing workqueue design and fixes the netns lifetime +handling in one place for all users of xfrm_trans_queue_net(). + +Fixes: 7b3801927e52 ("xfrm: introduce xfrm_trans_queue_net") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Xin Liu +Co-developed-by: Luxing Yin +Signed-off-by: Luxing Yin +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Assisted-by: Codex:gpt-5.4 +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_input.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +--- a/net/xfrm/xfrm_input.c ++++ b/net/xfrm/xfrm_input.c +@@ -797,9 +797,12 @@ static void xfrm_trans_reinject(struct w + spin_unlock_bh(&trans->queue_lock); + + local_bh_disable(); +- while ((skb = __skb_dequeue(&queue))) +- XFRM_TRANS_SKB_CB(skb)->finish(XFRM_TRANS_SKB_CB(skb)->net, +- NULL, skb); ++ while ((skb = __skb_dequeue(&queue))) { ++ struct net *net = XFRM_TRANS_SKB_CB(skb)->net; ++ ++ XFRM_TRANS_SKB_CB(skb)->finish(net, NULL, skb); ++ put_net(net); ++ } + local_bh_enable(); + } + +@@ -808,6 +811,7 @@ int xfrm_trans_queue_net(struct net *net + struct sk_buff *)) + { + struct xfrm_trans_tasklet *trans; ++ struct net *hold_net; + + trans = this_cpu_ptr(&xfrm_trans_tasklet); + +@@ -816,8 +820,12 @@ int xfrm_trans_queue_net(struct net *net + + BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb)); + ++ hold_net = maybe_get_net(net); ++ if (!hold_net) ++ return -ENODEV; ++ + XFRM_TRANS_SKB_CB(skb)->finish = finish; +- XFRM_TRANS_SKB_CB(skb)->net = net; ++ XFRM_TRANS_SKB_CB(skb)->net = hold_net; + spin_lock_bh(&trans->queue_lock); + __skb_queue_tail(&trans->queue, skb); + spin_unlock_bh(&trans->queue_lock); diff --git a/queue-7.0/xfrm-ipcomp-free-destination-pages-on-acomp-errors.patch b/queue-7.0/xfrm-ipcomp-free-destination-pages-on-acomp-errors.patch new file mode 100644 index 0000000000..022f07e3f5 --- /dev/null +++ b/queue-7.0/xfrm-ipcomp-free-destination-pages-on-acomp-errors.patch @@ -0,0 +1,59 @@ +From 7dbac7680eb629b3b4dc7e98c34f943b8814c0c8 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 6 May 2026 21:23:28 +0800 +Subject: xfrm: ipcomp: Free destination pages on acomp errors + +From: Herbert Xu + +commit 7dbac7680eb629b3b4dc7e98c34f943b8814c0c8 upstream. + +Move the out_free_req label up by a couple of lines so that the +allocated dst SG list gets freed on error as well as success. + +Fixes: eb2953d26971 ("xfrm: ipcomp: Use crypto_acomp interface") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Reported-by: Yilin Zhu +Signed-off-by: Herbert Xu +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_ipcomp.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/net/xfrm/xfrm_ipcomp.c ++++ b/net/xfrm/xfrm_ipcomp.c +@@ -51,11 +51,15 @@ static int ipcomp_post_acomp(struct sk_b + struct scatterlist *dsg; + int len, dlen; + +- if (unlikely(err)) +- goto out_free_req; ++ if (unlikely(!req)) ++ return err; + + extra = acomp_request_extra(req); + dsg = extra->sg; ++ ++ if (unlikely(err)) ++ goto out_free_req; ++ + dlen = req->dlen; + + pskb_trim_unique(skb, 0); +@@ -84,10 +88,10 @@ static int ipcomp_post_acomp(struct sk_b + skb_shinfo(skb)->nr_frags++; + } while ((dlen -= len)); + +- for (; dsg; dsg = sg_next(dsg)) ++out_free_req: ++ for (; dsg && sg_page(dsg); dsg = sg_next(dsg)) + __free_page(sg_page(dsg)); + +-out_free_req: + acomp_request_free(req); + return err; + } diff --git a/queue-7.0/xfrm-iptfs-reset-runtime-state-when-cloning-sas.patch b/queue-7.0/xfrm-iptfs-reset-runtime-state-when-cloning-sas.patch new file mode 100644 index 0000000000..a2bb07e27d --- /dev/null +++ b/queue-7.0/xfrm-iptfs-reset-runtime-state-when-cloning-sas.patch @@ -0,0 +1,91 @@ +From 7f83d174073234839aea176f265e517e0d50a1d2 Mon Sep 17 00:00:00 2001 +From: Shaomin Chen +Date: Thu, 21 May 2026 02:07:23 +0800 +Subject: xfrm: iptfs: reset runtime state when cloning SAs + +From: Shaomin Chen + +commit 7f83d174073234839aea176f265e517e0d50a1d2 upstream. + +iptfs_clone_state() clones the IPTFS mode data with kmemdup(). This +copies runtime objects which must not be shared with the original SA, +including the embedded sk_buff_head, hrtimers, spinlock, and in-flight +reassembly/reorder state. + +If xfrm_state_migrate() fails after clone_state() but before the later +init_state() call has reinitialized those fields, the cloned state can be +destroyed by xfrm_state_gc_task() with list and timer state copied from the +original SA. With queued packets this lets the clone splice and free skbs +owned by the original IPTFS queue, leading to use-after-free and +double-free reports in iptfs_destroy_state() and skb release paths. + +Reinitialize the clone's runtime state before publishing it through +x->mode_data. Because clone_state() now publishes a destroyable mode_data +object before init_state(), take the mode callback module reference there. +Avoid taking it again from __iptfs_init_state() for the same object. + +Fixes: 0e4fbf013fa5 ("xfrm: iptfs: add user packet (tunnel ingress) handling") +Cc: stable@vger.kernel.org +Signed-off-by: Shaomin Chen +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_iptfs.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +--- a/net/xfrm/xfrm_iptfs.c ++++ b/net/xfrm/xfrm_iptfs.c +@@ -2650,7 +2650,8 @@ static void __iptfs_init_state(struct xf + x->props.enc_hdr_len = sizeof(struct ip_iptfs_hdr); + + /* Always keep a module reference when x->mode_data is set */ +- __module_get(x->mode_cbs->owner); ++ if (x->mode_data != xtfs) ++ __module_get(x->mode_cbs->owner); + + x->mode_data = xtfs; + xtfs->x = x; +@@ -2658,22 +2659,39 @@ static void __iptfs_init_state(struct xf + + static int iptfs_clone_state(struct xfrm_state *x, struct xfrm_state *orig) + { ++ struct skb_wseq *w_saved = NULL; + struct xfrm_iptfs_data *xtfs; + + xtfs = kmemdup(orig->mode_data, sizeof(*xtfs), GFP_KERNEL); + if (!xtfs) + return -ENOMEM; + +- xtfs->ra_newskb = NULL; + if (xtfs->cfg.reorder_win_size) { +- xtfs->w_saved = kzalloc_objs(*xtfs->w_saved, +- xtfs->cfg.reorder_win_size); +- if (!xtfs->w_saved) { ++ w_saved = kzalloc_objs(*w_saved, xtfs->cfg.reorder_win_size); ++ if (!w_saved) { + kfree_sensitive(xtfs); + return -ENOMEM; + } + } ++ xtfs->w_saved = w_saved; + ++ __skb_queue_head_init(&xtfs->queue); ++ xtfs->queue_size = 0; ++ hrtimer_setup(&xtfs->iptfs_timer, iptfs_delay_timer, CLOCK_MONOTONIC, ++ IPTFS_HRTIMER_MODE); ++ ++ spin_lock_init(&xtfs->drop_lock); ++ hrtimer_setup(&xtfs->drop_timer, iptfs_drop_timer, CLOCK_MONOTONIC, ++ IPTFS_HRTIMER_MODE); ++ ++ xtfs->w_seq_set = false; ++ xtfs->w_wantseq = 0; ++ xtfs->w_savedlen = 0; ++ xtfs->ra_newskb = NULL; ++ xtfs->ra_wantseq = 0; ++ xtfs->ra_runtlen = 0; ++ ++ __module_get(x->mode_cbs->owner); + x->mode_data = xtfs; + xtfs->x = x; + diff --git a/queue-7.0/xfrm-route-migrate-notifications-to-caller-s-netns.patch b/queue-7.0/xfrm-route-migrate-notifications-to-caller-s-netns.patch new file mode 100644 index 0000000000..4945ec8243 --- /dev/null +++ b/queue-7.0/xfrm-route-migrate-notifications-to-caller-s-netns.patch @@ -0,0 +1,161 @@ +From 7e2a4f7ca0952820731ef7bdadfc9a9e9d3571b4 Mon Sep 17 00:00:00 2001 +From: Maoyi Xie +Date: Mon, 4 May 2026 22:27:36 +0800 +Subject: xfrm: route MIGRATE notifications to caller's netns + +From: Maoyi Xie + +commit 7e2a4f7ca0952820731ef7bdadfc9a9e9d3571b4 upstream. + +xfrm_send_migrate() in net/xfrm/xfrm_user.c and pfkey_send_migrate() +in net/key/af_key.c both hardcode &init_net for the multicast that +announces a successful XFRM_MSG_MIGRATE / SADB_X_MIGRATE. + +XFRM_MSG_MIGRATE arrives on a per-netns NETLINK_XFRM socket, and the +rest of the xfrm/af_key netlink path was made netns-aware in 2008. +The other 14 multicast paths in xfrm_user.c route their event using +xs_net(x), xp_net(xp) or sock_net(skb->sk); only the migrate path +was missed. + +Two consequences of the init_net hardcoding: + + 1. The notification (selector, old/new endpoint addresses, and the + km_address) is delivered to listeners on init_net's + XFRMNLGRP_MIGRATE / pfkey BROADCAST_ALL groups rather than on + the issuing netns. An IKE daemon running in init_net therefore + receives migration notifications originating from any other + netns on the host. + + 2. An IKE daemon running inside a non-init netns and subscribed + to its own XFRMNLGRP_MIGRATE / pfkey groups never receives the + notification of its own migration. IKEv2 MOBIKE / address-update + handling inside a netns is silently broken. + +Thread struct net through km_migrate() and the xfrm_mgr.migrate +function pointer, drop the &init_net override in xfrm_send_migrate() +and pfkey_send_migrate(), and pass the caller's net (already in +scope in xfrm_migrate() via sock_net(skb->sk)) all the way down. +struct xfrm_mgr is in-tree only and not exported as a stable API, +so the function-pointer signature change is internal. + +pfkey_broadcast() is already netns-aware via net_generic(net, +pfkey_net_id) since the pernet conversion. The five other +pfkey_broadcast() callers in af_key.c already pass xs_net(x), +sock_net(sk) or a per-netns net, so this only removes the +&init_net outlier. + +Fixes: 5c79de6e79cd ("[XFRM]: User interface for handling XFRM_MSG_MIGRATE") +Cc: stable@vger.kernel.org # v5.15+ +Signed-off-by: Maoyi Xie +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + include/net/xfrm.h | 3 ++- + net/key/af_key.c | 6 +++--- + net/xfrm/xfrm_policy.c | 2 +- + net/xfrm/xfrm_state.c | 4 ++-- + net/xfrm/xfrm_user.c | 5 ++--- + 5 files changed, 10 insertions(+), 10 deletions(-) + +--- a/include/net/xfrm.h ++++ b/include/net/xfrm.h +@@ -715,6 +715,7 @@ struct xfrm_mgr { + const struct xfrm_migrate *m, + int num_bundles, + const struct xfrm_kmaddress *k, ++ struct net *net, + const struct xfrm_encap_tmpl *encap); + bool (*is_alive)(const struct km_event *c); + }; +@@ -1891,7 +1892,7 @@ int xfrm_sk_policy_insert(struct sock *s + #ifdef CONFIG_XFRM_MIGRATE + int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + const struct xfrm_migrate *m, int num_bundles, +- const struct xfrm_kmaddress *k, ++ const struct xfrm_kmaddress *k, struct net *net, + const struct xfrm_encap_tmpl *encap); + struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net, + u32 if_id); +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -3564,7 +3564,7 @@ static int set_ipsecrequest(struct sk_bu + #ifdef CONFIG_NET_KEY_MIGRATE + static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + const struct xfrm_migrate *m, int num_bundles, +- const struct xfrm_kmaddress *k, ++ const struct xfrm_kmaddress *k, struct net *net, + const struct xfrm_encap_tmpl *encap) + { + int i; +@@ -3669,7 +3669,7 @@ static int pfkey_send_migrate(const stru + } + + /* broadcast migrate message to sockets */ +- pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net); ++ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, net); + + return 0; + +@@ -3680,7 +3680,7 @@ err: + #else + static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + const struct xfrm_migrate *m, int num_bundles, +- const struct xfrm_kmaddress *k, ++ const struct xfrm_kmaddress *k, struct net *net, + const struct xfrm_encap_tmpl *encap) + { + return -ENOPROTOOPT; +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -4704,7 +4704,7 @@ int xfrm_migrate(const struct xfrm_selec + } + + /* Stage 5 - announce */ +- km_migrate(sel, dir, type, m, num_migrate, k, encap); ++ km_migrate(sel, dir, type, m, num_migrate, k, net, encap); + + xfrm_pol_put(pol); + +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -2837,7 +2837,7 @@ EXPORT_SYMBOL(km_policy_expired); + #ifdef CONFIG_XFRM_MIGRATE + int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + const struct xfrm_migrate *m, int num_migrate, +- const struct xfrm_kmaddress *k, ++ const struct xfrm_kmaddress *k, struct net *net, + const struct xfrm_encap_tmpl *encap) + { + int err = -EINVAL; +@@ -2848,7 +2848,7 @@ int km_migrate(const struct xfrm_selecto + list_for_each_entry_rcu(km, &xfrm_km_list, list) { + if (km->migrate) { + ret = km->migrate(sel, dir, type, m, num_migrate, k, +- encap); ++ net, encap); + if (!ret) + err = ret; + } +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -3271,10 +3271,9 @@ out_cancel: + + static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + const struct xfrm_migrate *m, int num_migrate, +- const struct xfrm_kmaddress *k, ++ const struct xfrm_kmaddress *k, struct net *net, + const struct xfrm_encap_tmpl *encap) + { +- struct net *net = &init_net; + struct sk_buff *skb; + int err; + +@@ -3292,7 +3291,7 @@ static int xfrm_send_migrate(const struc + #else + static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + const struct xfrm_migrate *m, int num_migrate, +- const struct xfrm_kmaddress *k, ++ const struct xfrm_kmaddress *k, struct net *net, + const struct xfrm_encap_tmpl *encap) + { + return -ENOPROTOOPT;