From: Greg Kroah-Hartman Date: Mon, 4 May 2026 12:49:51 +0000 (+0200) Subject: 7.0-stable patches X-Git-Tag: v6.12.86~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=890736aa9c9271274dc5d93416cf8590eaa81aff;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches added patches: alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch alsa-caiaq-fix-usb_dev-refcount-leak-on-probe-failure.patch drm-amdgpu-fix-zero-size-gds-range-init-on-rdna4.patch drm-imagination-fix-segfault-when-updating-ftrace-mask.patch ipv6-rpl-reserve-mac_len-headroom-when-recompressed-srh-grows.patch mm-page_alloc-return-null-early-from-alloc_frozen_pages_nolock-in-nmi-on-up.patch mm-slab-return-null-early-from-kmalloc_nolock-in-nmi-on-up.patch net-ipv6-fix-noref-dst-use-in-seg6-and-rpl-lwtunnels.patch netfilter-reject-zero-shift-in-nft_bitwise.patch vmalloc-fix-buffer-overflow-in-vrealloc_node_align.patch --- diff --git a/queue-7.0/alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch b/queue-7.0/alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch new file mode 100644 index 0000000000..ba27d20f5a --- /dev/null +++ b/queue-7.0/alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch @@ -0,0 +1,128 @@ +From e5c33cdc6f402eab8abd36ecf436b22c9d3a8aff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= +Date: Fri, 24 Apr 2026 09:48:41 -0300 +Subject: ALSA: aloop: Fix peer runtime UAF during format-change stop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +commit e5c33cdc6f402eab8abd36ecf436b22c9d3a8aff upstream. + +loopback_check_format() may stop the capture side when playback starts +with parameters that no longer match a running capture stream. Commit +826af7fa62e3 ("ALSA: aloop: Fix racy access at PCM trigger") moved +the peer lookup under cable->lock, but the actual snd_pcm_stop() still +runs after dropping that lock. + +A concurrent close can clear the capture entry from cable->streams[] and +detach or free its runtime while the playback trigger path still holds a +stale peer substream pointer. + +Keep a per-cable count of in-flight peer stops before dropping +cable->lock, and make free_cable() wait for those stops before +detaching the runtime. This preserves the existing behavior while +making the peer runtime lifetime explicit. + +Reported-by: syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=8fa95c41eafbc9d2ff6f +Fixes: 597603d615d2 ("ALSA: introduce the snd-aloop module for the PCM loopback") +Cc: stable@vger.kernel.org +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260424-alsa-aloop-peer-stop-uaf-v2-1-94e68101db8a@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/drivers/aloop.c | 43 ++++++++++++++++++++++++++++++------------- + 1 file changed, 30 insertions(+), 13 deletions(-) + +--- a/sound/drivers/aloop.c ++++ b/sound/drivers/aloop.c +@@ -99,6 +99,9 @@ struct loopback_ops { + struct loopback_cable { + spinlock_t lock; + struct loopback_pcm *streams[2]; ++ /* in-flight peer stops running outside cable->lock */ ++ atomic_t stop_count; ++ wait_queue_head_t stop_wait; + struct snd_pcm_hardware hw; + /* flags */ + unsigned int valid; +@@ -366,8 +369,11 @@ static int loopback_check_format(struct + return 0; + if (stream == SNDRV_PCM_STREAM_CAPTURE) + return -EIO; +- else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) ++ else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) { ++ /* close must not free the peer runtime below */ ++ atomic_inc(&cable->stop_count); + stop_capture = true; ++ } + } + + setup = get_setup(dpcm_play); +@@ -396,8 +402,11 @@ static int loopback_check_format(struct + } + } + +- if (stop_capture) ++ if (stop_capture) { + snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING); ++ if (atomic_dec_and_test(&cable->stop_count)) ++ wake_up(&cable->stop_wait); ++ } + + return 0; + } +@@ -1049,23 +1058,29 @@ static void free_cable(struct snd_pcm_su + struct loopback *loopback = substream->private_data; + int dev = get_cable_index(substream); + struct loopback_cable *cable; ++ struct loopback_pcm *dpcm; ++ bool other_alive; + + cable = loopback->cables[substream->number][dev]; + if (!cable) + return; +- if (cable->streams[!substream->stream]) { +- /* other stream is still alive */ +- guard(spinlock_irq)(&cable->lock); +- cable->streams[substream->stream] = NULL; +- } else { +- struct loopback_pcm *dpcm = substream->runtime->private_data; + +- if (cable->ops && cable->ops->close_cable && dpcm) +- cable->ops->close_cable(dpcm); +- /* free the cable */ +- loopback->cables[substream->number][dev] = NULL; +- kfree(cable); ++ scoped_guard(spinlock_irq, &cable->lock) { ++ cable->streams[substream->stream] = NULL; ++ other_alive = cable->streams[!substream->stream]; + } ++ ++ /* Pair with the stop_count increment in loopback_check_format(). */ ++ wait_event(cable->stop_wait, !atomic_read(&cable->stop_count)); ++ if (other_alive) ++ return; ++ ++ dpcm = substream->runtime->private_data; ++ if (cable->ops && cable->ops->close_cable && dpcm) ++ cable->ops->close_cable(dpcm); ++ /* free the cable */ ++ loopback->cables[substream->number][dev] = NULL; ++ kfree(cable); + } + + static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) +@@ -1260,6 +1275,8 @@ static int loopback_open(struct snd_pcm_ + goto unlock; + } + spin_lock_init(&cable->lock); ++ atomic_set(&cable->stop_count, 0); ++ init_waitqueue_head(&cable->stop_wait); + cable->hw = loopback_pcm_hardware; + if (loopback->timer_source) + cable->ops = &loopback_snd_timer_ops; diff --git a/queue-7.0/alsa-caiaq-fix-usb_dev-refcount-leak-on-probe-failure.patch b/queue-7.0/alsa-caiaq-fix-usb_dev-refcount-leak-on-probe-failure.patch new file mode 100644 index 0000000000..3eca6d57fc --- /dev/null +++ b/queue-7.0/alsa-caiaq-fix-usb_dev-refcount-leak-on-probe-failure.patch @@ -0,0 +1,63 @@ +From 7a5f1cd22d47f8ca4b760b6334378ae42c1bd24b Mon Sep 17 00:00:00 2001 +From: Deepanshu Kartikey +Date: Sun, 26 Apr 2026 05:49:34 +0530 +Subject: ALSA: caiaq: fix usb_dev refcount leak on probe failure + +From: Deepanshu Kartikey + +commit 7a5f1cd22d47f8ca4b760b6334378ae42c1bd24b upstream. + +create_card() takes a reference on the USB device with usb_get_dev() +and stores the matching usb_put_dev() in card_free(), which is +installed as the snd_card's ->private_free destructor. + +However, ->private_free is only assigned near the end of init_card(), +after several failure points (usb_set_interface(), EP type checks, +usb_submit_urb(), the EP1_CMD_GET_DEVICE_INFO exchange, and its +timeout). When any of those fail, init_card() returns an error to +snd_probe(), which calls snd_card_free(card). Because ->private_free +is still NULL, card_free() never runs, the usb_get_dev() reference +is not dropped, and the struct usb_device leaks along with its +descriptor allocations and device_private. + +syzbot reproduces this with a malformed UAC3 device whose only valid +altsetting is 0; init_card()'s usb_set_interface(usb_dev, 0, 1) call +fails with -EIO and triggers the leak. + +Move the ->private_free assignment into create_card(), immediately +after usb_get_dev(), so that every error path reaching snd_card_free() +balances the reference. card_free()'s callees (snd_usb_caiaq_input_free, +free_urbs, kfree) already tolerate the partially-initialized state +because the chip private area is zero-initialized by snd_card_new(). + +Fixes: 80bb50e2d459 ("ALSA: caiaq: take a reference on the USB device in create_card()") +Reported-by: syzbot+2afd7e71155c7e241560@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=2afd7e71155c7e241560 +Tested-by: syzbot+2afd7e71155c7e241560@syzkaller.appspotmail.com +Cc: stable@vger.kernel.org +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20260426001934.70813-1-kartikey406@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/caiaq/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/usb/caiaq/device.c ++++ b/sound/usb/caiaq/device.c +@@ -423,6 +423,7 @@ static int create_card(struct usb_device + + cdev = caiaqdev(card); + cdev->chip.dev = usb_get_dev(usb_dev); ++ card->private_free = card_free; + cdev->chip.card = card; + cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct)); +@@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caia + scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)", + cdev->vendor_name, cdev->product_name, usbpath); + +- card->private_free = card_free; + err = setup_card(cdev); + if (err < 0) + goto err_kill_urb; diff --git a/queue-7.0/drm-amdgpu-fix-zero-size-gds-range-init-on-rdna4.patch b/queue-7.0/drm-amdgpu-fix-zero-size-gds-range-init-on-rdna4.patch new file mode 100644 index 0000000000..9cb3623f3b --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-zero-size-gds-range-init-on-rdna4.patch @@ -0,0 +1,64 @@ +From 095a8b0ad3c3b5cdc3850d961adb8a8f735220bb Mon Sep 17 00:00:00 2001 +From: Arjan van de Ven +Date: Mon, 20 Apr 2026 14:57:15 -0700 +Subject: drm/amdgpu: fix zero-size GDS range init on RDNA4 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Arjan van de Ven + +commit 095a8b0ad3c3b5cdc3850d961adb8a8f735220bb upstream. + +RDNA4 (GFX 12) hardware removes the GDS, GWS, and OA on-chip memory +resources. The gfx_v12_0 initialisation code correctly leaves +adev->gds.gds_size, adev->gds.gws_size, and adev->gds.oa_size at +zero to reflect this. + +amdgpu_ttm_init() unconditionally calls amdgpu_ttm_init_on_chip() for +each of these resources regardless of size. When the size is zero, +amdgpu_ttm_init_on_chip() forwards the call to ttm_range_man_init(), +which calls drm_mm_init(mm, 0, 0). drm_mm_init() immediately fires +DRM_MM_BUG_ON(start + size <= start) -- trivially true when size is +zero -- crashing the kernel during modprobe of amdgpu on an RX 9070 XT. + +Guard against this by returning 0 early from +amdgpu_ttm_init_on_chip() when size_in_page is zero. This skips TTM +resource manager registration for hardware resources that are absent, +without affecting any other GPU type. + +DRM_MM_BUG_ON() only asserts if CONFIG_DRM_DEBUG_MM is enabled in +the kernel config. This is apparently rarely enabled as these chips +have been in the market for over a year and this issue was only reported +now. + +Link: https://lore.kernel.org/all/bug-221376-2300@https.bugzilla.kernel.org%2F/ +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221376 +Oops-Analysis: http://oops.fenrus.org/reports/bugzilla.korg/221376/report.html +Assisted-by: GitHub Copilot:Claude Sonnet 4.6 linux-kernel-oops-x86. +Signed-off-by: Arjan van de Ven +Cc: Alex Deucher +Cc: "Christian König" +Cc: amd-gfx@lists.freedesktop.org +Cc: dri-devel@lists.freedesktop.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Alex Deucher +(cherry picked from commit 5719ce5865279cad4fd5f01011fe037168503f2d) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +@@ -75,6 +75,9 @@ static int amdgpu_ttm_init_on_chip(struc + unsigned int type, + uint64_t size_in_page) + { ++ if (!size_in_page) ++ return 0; ++ + return ttm_range_man_init(&adev->mman.bdev, type, + false, size_in_page); + } diff --git a/queue-7.0/drm-imagination-fix-segfault-when-updating-ftrace-mask.patch b/queue-7.0/drm-imagination-fix-segfault-when-updating-ftrace-mask.patch new file mode 100644 index 0000000000..e47b20728b --- /dev/null +++ b/queue-7.0/drm-imagination-fix-segfault-when-updating-ftrace-mask.patch @@ -0,0 +1,86 @@ +From 5dfd429591f8d7185bf63a08b5c30863fb605611 Mon Sep 17 00:00:00 2001 +From: Brajesh Gupta +Date: Mon, 27 Apr 2026 11:01:37 +0530 +Subject: drm/imagination: Fix segfault when updating ftrace mask + +From: Brajesh Gupta + +commit 5dfd429591f8d7185bf63a08b5c30863fb605611 upstream. + +Fix invalid data access by passing right data for debugfs entry. + +[ 171.549793] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 +[ 171.559248] Mem abort info: +[ 171.562173] ESR = 0x0000000096000044 +[ 171.566227] EC = 0x25: DABT (current EL), IL = 32 bits +[ 171.573108] SET = 0, FnV = 0 +[ 171.576448] EA = 0, S1PTW = 0 +[ 171.579745] FSC = 0x04: level 0 translation fault +[ 171.584760] Data abort info: +[ 171.588012] ISV = 0, ISS = 0x00000044, ISS2 = 0x00000000 +[ 171.593734] CM = 0, WnR = 1, TnD = 0, TagAccess = 0 +[ 171.598962] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 171.604471] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000083837000 +[ 171.611358] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000 +[ 171.618500] Internal error: Oops: 0000000096000044 [#1] SMP +[ 171.624222] Modules linked in: powervr drm_shmem_helper drm_gpuvm... +[ 171.656580] CPU: 0 UID: 0 PID: 549 Comm: bash Not tainted 7.0.0-rc2-g730b257ba723-dirty #13 PREEMPT +[ 171.665773] Hardware name: BeagleBoard.org BeaglePlay (DT) +[ 171.671296] pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 171.678306] pc : pvr_fw_trace_mask_set+0x78/0x154 [powervr] +[ 171.683959] lr : pvr_fw_trace_mask_set+0x4c/0x154 [powervr] +[ 171.689593] sp : ffff8000835ebb90 +[ 171.692929] x29: ffff8000835ebc00 x28: ffff000005c60f80 x27: 0000000000000000 +[ 171.700130] x26: 0000000000000000 x25: ffff00000504af28 x24: 0000000000000000 +[ 171.707324] x23: ffff00000504af50 x22: 0000000000000203 x21: 0000000000000000 +[ 171.714518] x20: ffff000005c44a80 x19: ffff000005c457b8 x18: 0000000000000000 +[ 171.721715] x17: 0000000000000000 x16: 0000000000000000 x15: 0000aaaae8887580 +[ 171.728908] x14: 0000000000000000 x13: 0000000000000000 x12: ffff8000835ebc30 +[ 171.736095] x11: ffff00000504af2a x10: ffff00008504af29 x9 : 0fffffffffffffff +[ 171.743286] x8 : ffff8000835ebbf8 x7 : 0000000000000000 x6 : 000000000000002a +[ 171.750479] x5 : ffff00000504af2e x4 : 0000000000000000 x3 : 0000000000000010 +[ 171.757674] x2 : 0000000000000203 x1 : 0000000000000000 x0 : ffff8000835ebba0 +[ 171.764871] Call trace: +[ 171.767342] pvr_fw_trace_mask_set+0x78/0x154 [powervr] (P) +[ 171.772984] simple_attr_write_xsigned.isra.0+0xe0/0x19c +[ 171.778341] simple_attr_write+0x18/0x24 +[ 171.782296] debugfs_attr_write+0x50/0x98 +[ 171.786341] full_proxy_write+0x6c/0xa8 +[ 171.790208] vfs_write+0xd4/0x350 +[ 171.793561] ksys_write+0x70/0x108 +[ 171.796995] __arm64_sys_write+0x1c/0x28 +[ 171.800952] invoke_syscall+0x48/0x10c +[ 171.804740] el0_svc_common.constprop.0+0x40/0xe0 +[ 171.809487] do_el0_svc+0x1c/0x28 +[ 171.812834] el0_svc+0x34/0x108 +[ 171.816013] el0t_64_sync_handler+0xa0/0xe4 +[ 171.820237] el0t_64_sync+0x198/0x19c +[ 171.823939] Code: 32000262 b90ac293 1a931056 9134e293 (b9000036) +[ 171.830073] ---[ end trace 0000000000000000 ]--- + +Fixes: a331631496a0 ("drm/imagination: Simplify module parameters") +Signed-off-by: Brajesh Gupta +Reviewed-by: Alessio Belle +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260427-ftrace_fix-v3-1-e081530759a8@imgtec.com +Signed-off-by: Matt Coster +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/imagination/pvr_fw_trace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c +index e154cb35f604..6193811ef7be 100644 +--- a/drivers/gpu/drm/imagination/pvr_fw_trace.c ++++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c +@@ -558,6 +558,6 @@ pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir) + &pvr_fw_trace_fops); + } + +- debugfs_create_file("trace_mask", 0600, dir, fw_trace, ++ debugfs_create_file("trace_mask", 0600, dir, pvr_dev, + &pvr_fw_trace_mask_fops); + } +-- +2.54.0 + diff --git a/queue-7.0/ipv6-rpl-reserve-mac_len-headroom-when-recompressed-srh-grows.patch b/queue-7.0/ipv6-rpl-reserve-mac_len-headroom-when-recompressed-srh-grows.patch new file mode 100644 index 0000000000..f05ce88ada --- /dev/null +++ b/queue-7.0/ipv6-rpl-reserve-mac_len-headroom-when-recompressed-srh-grows.patch @@ -0,0 +1,78 @@ +From 9e6bf146b55999a095bb14f73a843942456d1adc Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Tue, 21 Apr 2026 15:16:33 +0200 +Subject: ipv6: rpl: reserve mac_len headroom when recompressed SRH grows + +From: Greg Kroah-Hartman + +commit 9e6bf146b55999a095bb14f73a843942456d1adc upstream. + +ipv6_rpl_srh_rcv() decompresses an RFC 6554 Source Routing Header, swaps +the next segment into ipv6_hdr->daddr, recompresses, then pulls the old +header and pushes the new one plus the IPv6 header back. The +recompressed header can be larger than the received one when the swap +reduces the common-prefix length the segments share with daddr (CmprI=0, +CmprE>0, seg[0][0] != daddr[0] gives the maximum +8 bytes). + +pskb_expand_head() was gated on segments_left == 0, so on earlier +segments the push consumed unchecked headroom. Once skb_push() leaves +fewer than skb->mac_len bytes in front of data, +skb_mac_header_rebuild()'s call to: + + skb_set_mac_header(skb, -skb->mac_len); + +will store (data - head) - mac_len into the u16 mac_header field, which +wraps to ~65530, and the following memmove() writes mac_len bytes ~64KiB +past skb->head. + +A single AF_INET6/SOCK_RAW/IPV6_HDRINCL packet over lo with a two +segment type-3 SRH (CmprI=0, CmprE=15) reaches headroom 8 after one +pass; KASAN reports a 14-byte OOB write in ipv6_rthdr_rcv. + +Fix this by expanding the head whenever the remaining room is less than +the push size plus mac_len, and request that much extra so the rebuilt +MAC header fits afterwards. + +Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr") +Cc: stable +Reported-by: Anthropic +Signed-off-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/2026042133-gout-unvented-1bd9@gregkh +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/exthdrs.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -491,6 +491,7 @@ static int ipv6_rpl_srh_rcv(struct sk_bu + struct net *net = dev_net(skb->dev); + struct inet6_dev *idev; + struct ipv6hdr *oldhdr; ++ unsigned int chdr_len; + unsigned char *buf; + int accept_rpl_seg; + int i, err; +@@ -592,8 +593,10 @@ looped_back: + skb_pull(skb, ((hdr->hdrlen + 1) << 3)); + skb_postpull_rcsum(skb, oldhdr, + sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); +- if (unlikely(!hdr->segments_left)) { +- if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0, ++ chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3); ++ if (unlikely(!hdr->segments_left || ++ skb_headroom(skb) < chdr_len + skb->mac_len)) { ++ if (pskb_expand_head(skb, chdr_len + skb->mac_len, 0, + GFP_ATOMIC)) { + __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); + kfree_skb(skb); +@@ -603,7 +606,7 @@ looped_back: + + oldhdr = ipv6_hdr(skb); + } +- skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr)); ++ skb_push(skb, chdr_len); + skb_reset_network_header(skb); + skb_mac_header_rebuild(skb); + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); diff --git a/queue-7.0/mm-page_alloc-return-null-early-from-alloc_frozen_pages_nolock-in-nmi-on-up.patch b/queue-7.0/mm-page_alloc-return-null-early-from-alloc_frozen_pages_nolock-in-nmi-on-up.patch new file mode 100644 index 0000000000..18130147c2 --- /dev/null +++ b/queue-7.0/mm-page_alloc-return-null-early-from-alloc_frozen_pages_nolock-in-nmi-on-up.patch @@ -0,0 +1,61 @@ +From 620b46ed6ae17c8438d889c8c0cfddab36a1476c Mon Sep 17 00:00:00 2001 +From: "Harry Yoo (Oracle)" +Date: Mon, 27 Apr 2026 16:09:52 +0900 +Subject: mm/page_alloc: return NULL early from alloc_frozen_pages_nolock() in NMI on UP + +From: Harry Yoo (Oracle) + +commit 620b46ed6ae17c8438d889c8c0cfddab36a1476c upstream. + +On UP kernels (!CONFIG_SMP), spin_trylock() is a no-op that +unconditionally succeeds even when the lock is already held. As a +result, alloc_frozen_pages_nolock() called from NMI context can +re-enter rmqueue() and acquire the zone lock that the interrupted +context is already holding, corrupting the freelists. + +With CONFIG_DEBUG_SPINLOCK on UP, the following BUG is triggered with +the slub_kunit test module: + + BUG: spinlock trylock failure on UP on CPU#0, kunit_try_catch/243 + [...] + Call Trace: + + dump_stack_lvl+0x3f/0x60 + do_raw_spin_trylock+0x41/0x50 + _raw_spin_trylock+0x24/0x50 + rmqueue.isra.0+0x2a9/0xa70 + get_page_from_freelist+0xeb/0x450 + alloc_frozen_pages_nolock_noprof+0x111/0x1e0 + allocate_slab+0x42a/0x500 + ___slab_alloc+0xa7/0x4c0 + kmalloc_nolock_noprof+0x164/0x310 + [...] + + +Fix this by returning NULL early when invoked from NMI on a UP kernel. + +Link: https://lore.kernel.org/linux-mm/ad_cqe51pvr1WaDg@hyeyoo +Cc: stable@vger.kernel.org +Fixes: d7242af86434 ("mm: Introduce alloc_frozen_pages_nolock()") +Signed-off-by: Harry Yoo (Oracle) +Link: https://patch.msgid.link/20260427-nolock-api-fix-v2-1-a6b83a92d9a4@kernel.org +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Greg Kroah-Hartman +--- + mm/page_alloc.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -7806,6 +7806,11 @@ struct page *alloc_frozen_pages_nolock_n + */ + if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) + return NULL; ++ ++ /* On UP, spin_trylock() always succeeds even when it is locked */ ++ if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) ++ return NULL; ++ + if (!pcp_allowed_order(order)) + return NULL; + diff --git a/queue-7.0/mm-slab-return-null-early-from-kmalloc_nolock-in-nmi-on-up.patch b/queue-7.0/mm-slab-return-null-early-from-kmalloc_nolock-in-nmi-on-up.patch new file mode 100644 index 0000000000..252cdd6fb5 --- /dev/null +++ b/queue-7.0/mm-slab-return-null-early-from-kmalloc_nolock-in-nmi-on-up.patch @@ -0,0 +1,57 @@ +From 5b31044e649e3e54c2caef135c09b371c2fbcd08 Mon Sep 17 00:00:00 2001 +From: "Harry Yoo (Oracle)" +Date: Mon, 27 Apr 2026 16:09:53 +0900 +Subject: mm/slab: return NULL early from kmalloc_nolock() in NMI on UP + +From: Harry Yoo (Oracle) + +commit 5b31044e649e3e54c2caef135c09b371c2fbcd08 upstream. + +On UP kernels (!CONFIG_SMP), spin_trylock() is a no-op that +unconditionally succeeds even when the lock is already held. As a +result, kmalloc_nolock() called from NMI context can re-enter the slab +allocator and acquire n->list_lock that the interrupted context is +already holding, corrupting slab state. + +With CONFIG_DEBUG_SPINLOCK on UP, the following BUG is triggered with +the slub_kunit test module: + + BUG: spinlock trylock failure on UP on CPU#0, kunit_try_catch/243 + [...] + Call Trace: + + dump_stack_lvl+0x3f/0x60 + do_raw_spin_trylock+0x41/0x50 + _raw_spin_trylock+0x24/0x50 + get_from_partial_node+0x120/0x4d0 + ___slab_alloc+0x8a/0x4c0 + kmalloc_nolock_noprof+0x164/0x310 + [...] + + +Fix this by returning NULL early when invoked from NMI on a UP kernel. + +Link: https://lore.kernel.org/linux-mm/ad_cqe51pvr1WaDg@hyeyoo +Cc: stable@vger.kernel.org +Fixes: af92793e52c3 ("slab: Introduce kmalloc_nolock() and kfree_nolock().") +Signed-off-by: Harry Yoo (Oracle) +Link: https://patch.msgid.link/20260427-nolock-api-fix-v2-2-a6b83a92d9a4@kernel.org +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Greg Kroah-Hartman +--- + mm/slub.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -5304,6 +5304,10 @@ void *kmalloc_nolock_noprof(size_t size, + if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) + return NULL; + ++ /* On UP, spin_trylock() always succeeds even when it is locked */ ++ if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) ++ return NULL; ++ + retry: + if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) + return NULL; diff --git a/queue-7.0/net-ipv6-fix-noref-dst-use-in-seg6-and-rpl-lwtunnels.patch b/queue-7.0/net-ipv6-fix-noref-dst-use-in-seg6-and-rpl-lwtunnels.patch new file mode 100644 index 0000000000..79845708d6 --- /dev/null +++ b/queue-7.0/net-ipv6-fix-noref-dst-use-in-seg6-and-rpl-lwtunnels.patch @@ -0,0 +1,122 @@ +From f9c52a6ba9780bd27e0bf4c044fd91c13c778b6e Mon Sep 17 00:00:00 2001 +From: Andrea Mayer +Date: Tue, 21 Apr 2026 11:47:35 +0200 +Subject: net: ipv6: fix NOREF dst use in seg6 and rpl lwtunnels + +From: Andrea Mayer + +commit f9c52a6ba9780bd27e0bf4c044fd91c13c778b6e upstream. + +seg6_input_core() and rpl_input() call ip6_route_input() which sets a +NOREF dst on the skb, then pass it to dst_cache_set_ip6() invoking +dst_hold() unconditionally. +On PREEMPT_RT, ksoftirqd is preemptible and a higher-priority task can +release the underlying pcpu_rt between the lookup and the caching +through a concurrent FIB lookup on a shared nexthop. +Simplified race sequence: + + ksoftirqd/X higher-prio task (same CPU X) + ----------- -------------------------------- + seg6_input_core(,skb)/rpl_input(skb) + dst_cache_get() + -> miss + ip6_route_input(skb) + -> ip6_pol_route(,skb,flags) + [RT6_LOOKUP_F_DST_NOREF in flags] + -> FIB lookup resolves fib6_nh + [nhid=N route] + -> rt6_make_pcpu_route() + [creates pcpu_rt, refcount=1] + pcpu_rt->sernum = fib6_sernum + [fib6_sernum=W] + -> cmpxchg(fib6_nh.rt6i_pcpu, + NULL, pcpu_rt) + [slot was empty, store succeeds] + -> skb_dst_set_noref(skb, dst) + [dst is pcpu_rt, refcount still 1] + + rt_genid_bump_ipv6() + -> bumps fib6_sernum + [fib6_sernum from W to Z] + ip6_route_output() + -> ip6_pol_route() + -> FIB lookup resolves fib6_nh + [nhid=N] + -> rt6_get_pcpu_route() + pcpu_rt->sernum != fib6_sernum + [W <> Z, stale] + -> prev = xchg(rt6i_pcpu, NULL) + -> dst_release(prev) + [prev is pcpu_rt, + refcount 1->0, dead] + + dst = skb_dst(skb) + [dst is the dead pcpu_rt] + dst_cache_set_ip6(dst) + -> dst_hold() on dead dst + -> WARN / use-after-free + +For the race to occur, ksoftirqd must be preemptible (PREEMPT_RT without +PREEMPT_RT_NEEDS_BH_LOCK) and a concurrent task must be able to release +the pcpu_rt. Shared nexthop objects provide such a path, as two routes +pointing to the same nhid share the same fib6_nh and its rt6i_pcpu +entry. + +Fix seg6_input_core() and rpl_input() by calling skb_dst_force() after +ip6_route_input() to force the NOREF dst into a refcounted one before +caching. +The output path is not affected as ip6_route_output() already returns a +refcounted dst. + +Fixes: af4a2209b134 ("ipv6: sr: use dst_cache in seg6_input") +Fixes: a7a29f9c361f ("net: ipv6: add rpl sr tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Andrea Mayer +Reviewed-by: Simon Horman +Reviewed-by: Justin Iurman +Link: https://patch.msgid.link/20260421094735.20997-1-andrea.mayer@uniroma2.it +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/rpl_iptunnel.c | 9 +++++++++ + net/ipv6/seg6_iptunnel.c | 9 +++++++++ + 2 files changed, 18 insertions(+) + +--- a/net/ipv6/rpl_iptunnel.c ++++ b/net/ipv6/rpl_iptunnel.c +@@ -287,7 +287,16 @@ static int rpl_input(struct sk_buff *skb + + if (!dst) { + ip6_route_input(skb); ++ ++ /* ip6_route_input() sets a NOREF dst; force a refcount on it ++ * before caching or further use. ++ */ ++ skb_dst_force(skb); + dst = skb_dst(skb); ++ if (unlikely(!dst)) { ++ err = -ENETUNREACH; ++ goto drop; ++ } + + /* cache only if we don't create a dst reference loop */ + if (!dst->error && lwtst != dst->lwtstate) { +--- a/net/ipv6/seg6_iptunnel.c ++++ b/net/ipv6/seg6_iptunnel.c +@@ -500,7 +500,16 @@ static int seg6_input_core(struct net *n + + if (!dst) { + ip6_route_input(skb); ++ ++ /* ip6_route_input() sets a NOREF dst; force a refcount on it ++ * before caching or further use. ++ */ ++ skb_dst_force(skb); + dst = skb_dst(skb); ++ if (unlikely(!dst)) { ++ err = -ENETUNREACH; ++ goto drop; ++ } + + /* cache only if we don't create a dst reference loop */ + if (!dst->error && lwtst != dst->lwtstate) { diff --git a/queue-7.0/netfilter-reject-zero-shift-in-nft_bitwise.patch b/queue-7.0/netfilter-reject-zero-shift-in-nft_bitwise.patch new file mode 100644 index 0000000000..eb9429a7cd --- /dev/null +++ b/queue-7.0/netfilter-reject-zero-shift-in-nft_bitwise.patch @@ -0,0 +1,47 @@ +From fe11e5c40817b84abaa5d83bfb6586d8412bfd07 Mon Sep 17 00:00:00 2001 +From: Kai Ma +Date: Wed, 22 Apr 2026 22:54:18 +0800 +Subject: netfilter: reject zero shift in nft_bitwise + +From: Kai Ma + +commit fe11e5c40817b84abaa5d83bfb6586d8412bfd07 upstream. + +Reject zero shift operands for nft_bitwise left and right shift +expressions during initialization. + +The carry propagation logic computes the carry from the adjacent 32-bit +word using BITS_PER_TYPE(u32) - shift. A zero shift operand turns this +into a 32-bit shift, which is undefined behaviour. + +Reject zero shift operands in the control plane, alongside the existing +check for values greater than or equal to 32, so malformed rules never +reach the packet path. + +Fixes: 567d746b55bc ("netfilter: bitwise: add support for shifts.") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Kai Ma +Signed-off-by: Ren Wei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nft_bitwise.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/netfilter/nft_bitwise.c ++++ b/net/netfilter/nft_bitwise.c +@@ -196,7 +196,8 @@ static int nft_bitwise_init_shift(struct + if (err < 0) + return err; + +- if (priv->data.data[0] >= BITS_PER_TYPE(u32)) { ++ if (!priv->data.data[0] || ++ priv->data.data[0] >= BITS_PER_TYPE(u32)) { + nft_data_release(&priv->data, desc.type); + return -EINVAL; + } diff --git a/queue-7.0/series b/queue-7.0/series index 28e6acb927..32da0682fa 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -295,4 +295,14 @@ crypto-authencesn-reject-short-ahash-digests-during-instance-creation.patch driver-core-add-kernel-doc-for-dev_flag_count-enum-value.patch alsa-caiaq-fix-potentially-leftover-ep1_in_urb-at-error-path.patch alsa-caiaq-don-t-abort-when-no-input-device-is-available.patch +ipv6-rpl-reserve-mac_len-headroom-when-recompressed-srh-grows.patch +drm-amdgpu-fix-zero-size-gds-range-init-on-rdna4.patch +drm-imagination-fix-segfault-when-updating-ftrace-mask.patch +alsa-caiaq-fix-usb_dev-refcount-leak-on-probe-failure.patch +alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch +vmalloc-fix-buffer-overflow-in-vrealloc_node_align.patch +mm-page_alloc-return-null-early-from-alloc_frozen_pages_nolock-in-nmi-on-up.patch +mm-slab-return-null-early-from-kmalloc_nolock-in-nmi-on-up.patch +net-ipv6-fix-noref-dst-use-in-seg6-and-rpl-lwtunnels.patch +netfilter-reject-zero-shift-in-nft_bitwise.patch selftests-landlock-fix-socket-file-descriptor-leaks-in-audit-helpers.patch diff --git a/queue-7.0/vmalloc-fix-buffer-overflow-in-vrealloc_node_align.patch b/queue-7.0/vmalloc-fix-buffer-overflow-in-vrealloc_node_align.patch new file mode 100644 index 0000000000..408c74f1e8 --- /dev/null +++ b/queue-7.0/vmalloc-fix-buffer-overflow-in-vrealloc_node_align.patch @@ -0,0 +1,46 @@ +From 82d1f01292d3f09bf063f829f8ab8de12b4280a1 Mon Sep 17 00:00:00 2001 +From: Marco Elver +Date: Mon, 20 Apr 2026 13:47:26 +0200 +Subject: vmalloc: fix buffer overflow in vrealloc_node_align() + +From: Marco Elver + +commit 82d1f01292d3f09bf063f829f8ab8de12b4280a1 upstream. + +Commit 4c5d3365882d ("mm/vmalloc: allow to set node and align in +vrealloc") added the ability to force a new allocation if the current +pointer is on the wrong NUMA node, or if an alignment constraint is not +met, even if the user is shrinking the allocation. + +On this path (need_realloc), the code allocates a new object of 'size' +bytes and then memcpy()s 'old_size' bytes into it. If the request is to +shrink the object (size < old_size), this results in an out-of-bounds +write on the new buffer. + +Fix this by bounding the copy length by the new allocation size. + +Link: https://lore.kernel.org/20260420114805.3572606-2-elver@google.com +Fixes: 4c5d3365882d ("mm/vmalloc: allow to set node and align in vrealloc") +Signed-off-by: Marco Elver +Reported-by: Harry Yoo (Oracle) +Reviewed-by: Uladzislau Rezki (Sony) +Acked-by: Vlastimil Babka (SUSE) +Reviewed-by: Harry Yoo (Oracle) +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/vmalloc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -4361,7 +4361,7 @@ need_realloc: + return NULL; + + if (p) { +- memcpy(n, p, old_size); ++ memcpy(n, p, min(size, old_size)); + vfree(p); + } +