From: Greg Kroah-Hartman Date: Fri, 24 Apr 2026 12:30:26 +0000 (+0200) Subject: 7.0-stable patches X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=07cf5757aa40b9d09534a817565f406b2fc1014c;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches added patches: alsa-caiaq-take-a-reference-on-the-usb-device-in-create_card.patch alsa-hda-realtek-add-quirk-for-legion-s7-15imh.patch alsa-usb-audio-apply-quirk-for-moondrop-ju-jiu.patch crypto-ccp-don-t-attempt-to-copy-csr-to-userspace-if-psp-command-failed.patch crypto-ccp-don-t-attempt-to-copy-id-to-userspace-if-psp-command-failed.patch crypto-ccp-don-t-attempt-to-copy-pdh-cert-to-userspace-if-psp-command-failed.patch f2fs-fix-to-avoid-memory-leak-in-f2fs_rename.patch f2fs-fix-to-avoid-uninit-value-access-in-f2fs_sanity_check_node_footer.patch f2fs-fix-to-do-sanity-check-on-dcc-discard_cmd_cnt-conditionally.patch f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch f2fs-fix-use-after-free-of-sbi-in-f2fs_compress_write_end_io.patch fs-ntfs3-validate-rec-used-in-journal-replay-file-record-check.patch fuse-abort-on-fatal-signal-during-sync-init.patch fuse-check-for-large-folio-with-splice_f_move.patch fuse-fuse_dev_ioctl_clone-should-wait-for-device-file-to-be-initialized.patch fuse-quiet-down-complaints-in-fuse_conn_limit_write.patch fuse-reject-oversized-dirents-in-page-cache.patch ksmbd-fix-out-of-bounds-write-in-smb2_get_ea-ea-alignment.patch ksmbd-require-minimum-ace-size-in-smb_check_perm_dacl.patch ksmbd-reset-rcount-per-connection-in-ksmbd_conn_wait_idle_sess_id.patch ksmbd-use-check_add_overflow-to-prevent-u16-dacl-size-overflow.patch ksmbd-validate-num_aces-and-harden-ace-walk-in-smb_inherit_dacl.patch ksmbd-validate-response-sizes-in-ipc_validate_msg.patch mshv_vtl-fix-vmemmap_shift-exceeding-max_folio_order.patch net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch rxrpc-fix-missing-validation-of-ticket-length-in-non-xdr-key-preparsing.patch smb-client-fix-dir-separator-in-smb1-unix-mounts.patch smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch smb-server-fix-active_num_conn-leak-on-transport-allocation-failure.patch smb-server-fix-max_connections-off-by-one-in-tcp-accept-path.patch writeback-fix-use-after-free-in-inode_switch_wbs_work_fn.patch --- diff --git a/queue-7.0/alsa-caiaq-take-a-reference-on-the-usb-device-in-create_card.patch b/queue-7.0/alsa-caiaq-take-a-reference-on-the-usb-device-in-create_card.patch new file mode 100644 index 0000000000..7c245509c6 --- /dev/null +++ b/queue-7.0/alsa-caiaq-take-a-reference-on-the-usb-device-in-create_card.patch @@ -0,0 +1,57 @@ +From 80bb50e2d459213cccff3111d5ef98ed4238c0d5 Mon Sep 17 00:00:00 2001 +From: Berk Cem Goksel +Date: Mon, 13 Apr 2026 06:49:41 +0300 +Subject: ALSA: caiaq: take a reference on the USB device in create_card() + +From: Berk Cem Goksel + +commit 80bb50e2d459213cccff3111d5ef98ed4238c0d5 upstream. + +The caiaq driver stores a pointer to the parent USB device in +cdev->chip.dev but never takes a reference on it. The card's +private_free callback, snd_usb_caiaq_card_free(), can run +asynchronously via snd_card_free_when_closed() after the USB +device has already been disconnected and freed, so any access to +cdev->chip.dev in that path dereferences a freed usb_device. + +On top of the refcounting issue, the current card_free implementation +calls usb_reset_device(cdev->chip.dev). A reset in a free callback +is inappropriate: the device is going away, the call takes the +device lock in a teardown context, and the reset races with the +disconnect path that the callback is already cleaning up after. + +Take a reference on the USB device in create_card() with +usb_get_dev(), drop it with usb_put_dev() in the free callback, +and remove the usb_reset_device() call. + +Fixes: b04dcbb7f7b1 ("ALSA: caiaq: Use snd_card_free_when_closed() at disconnection") +Cc: stable@vger.kernel.org +Cc: Andrey Konovalov +Signed-off-by: Berk Cem Goksel +Link: https://patch.msgid.link/20260413034941.1131465-3-berkcgoksel@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/caiaq/device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/usb/caiaq/device.c ++++ b/sound/usb/caiaq/device.c +@@ -384,7 +384,7 @@ static void card_free(struct snd_card *c + snd_usb_caiaq_input_free(cdev); + #endif + snd_usb_caiaq_audio_free(cdev); +- usb_reset_device(cdev->chip.dev); ++ usb_put_dev(cdev->chip.dev); + } + + static int create_card(struct usb_device *usb_dev, +@@ -410,7 +410,7 @@ static int create_card(struct usb_device + return err; + + cdev = caiaqdev(card); +- cdev->chip.dev = usb_dev; ++ cdev->chip.dev = usb_get_dev(usb_dev); + cdev->chip.card = card; + cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct)); diff --git a/queue-7.0/alsa-hda-realtek-add-quirk-for-legion-s7-15imh.patch b/queue-7.0/alsa-hda-realtek-add-quirk-for-legion-s7-15imh.patch new file mode 100644 index 0000000000..833821c953 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-quirk-for-legion-s7-15imh.patch @@ -0,0 +1,30 @@ +From 67f4c61a73e9b17dc9593bf27badc6785ecadd78 Mon Sep 17 00:00:00 2001 +From: Eric Naim +Date: Mon, 13 Apr 2026 23:48:17 +0800 +Subject: ALSA: hda/realtek: Add quirk for Legion S7 15IMH + +From: Eric Naim + +commit 67f4c61a73e9b17dc9593bf27badc6785ecadd78 upstream. + +Fix speaker output on the Lenovo Legion S7 15IMH05. + +Cc: stable@vger.kernel.org +Signed-off-by: Eric Naim +Link: https://patch.msgid.link/20260413154818.351597-1-dnaim@cachyos.org +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 +@@ -7605,6 +7605,7 @@ static const struct hda_quirk alc269_fix + SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), + SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C), ++ SND_PCI_QUIRK(0x17aa, 0x3811, "Legion S7 15IMH05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), + SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), + SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7), + SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS), diff --git a/queue-7.0/alsa-usb-audio-apply-quirk-for-moondrop-ju-jiu.patch b/queue-7.0/alsa-usb-audio-apply-quirk-for-moondrop-ju-jiu.patch new file mode 100644 index 0000000000..e4ed00cce9 --- /dev/null +++ b/queue-7.0/alsa-usb-audio-apply-quirk-for-moondrop-ju-jiu.patch @@ -0,0 +1,40 @@ +From 4513d3e0bbc0585b86ccf2631902593ff97e88f5 Mon Sep 17 00:00:00 2001 +From: Cryolitia PukNgae +Date: Thu, 2 Apr 2026 13:36:57 +0800 +Subject: ALSA: usb-audio: apply quirk for MOONDROP JU Jiu + +From: Cryolitia PukNgae + +commit 4513d3e0bbc0585b86ccf2631902593ff97e88f5 upstream. + +It(ID 31b2:0111 JU Jiu) reports a MIN value -12800 for volume control, but +will mute when setting it less than -10880. + +Thanks to my girlfriend Kagura for reporting this issue. + +Cc: Kagura +Cc: stable@vger.kernel.org +Signed-off-by: Cryolitia PukNgae +Link: https://patch.msgid.link/20260402-syy-v1-1-068d3bc30ddc@linux.dev +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/mixer.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1204,6 +1204,13 @@ static void volume_control_quirks(struct + cval->min = -11264; /* Mute under it */ + } + break; ++ case USB_ID(0x31b2, 0x0111): /* MOONDROP JU Jiu */ ++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) { ++ usb_audio_info(chip, ++ "set volume quirk for MOONDROP JU Jiu\n"); ++ cval->min = -10880; /* Mute under it */ ++ } ++ break; + } + } + diff --git a/queue-7.0/crypto-ccp-don-t-attempt-to-copy-csr-to-userspace-if-psp-command-failed.patch b/queue-7.0/crypto-ccp-don-t-attempt-to-copy-csr-to-userspace-if-psp-command-failed.patch new file mode 100644 index 0000000000..f14b6a671a --- /dev/null +++ b/queue-7.0/crypto-ccp-don-t-attempt-to-copy-csr-to-userspace-if-psp-command-failed.patch @@ -0,0 +1,84 @@ +From abe4a6d6f606113251868c2c4a06ba904bb41eed Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Fri, 13 Mar 2026 10:43:16 -0700 +Subject: crypto: ccp: Don't attempt to copy CSR to userspace if PSP command failed + +From: Sean Christopherson + +commit abe4a6d6f606113251868c2c4a06ba904bb41eed upstream. + +When retrieving the PEK CSR, don't attempt to copy the blob to userspace +if the firmware command failed. If the failure was due to an invalid +length, i.e. the userspace buffer+length was too small, copying the number +of bytes _firmware_ requires will overflow the kernel-allocated buffer and +leak data to userspace. + + BUG: KASAN: slab-out-of-bounds in instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] + BUG: KASAN: slab-out-of-bounds in _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] + BUG: KASAN: slab-out-of-bounds in _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 + Read of size 2084 at addr ffff898144612e20 by task syz.9.219/21405 + + CPU: 14 UID: 0 PID: 21405 Comm: syz.9.219 Tainted: G U O 7.0.0-smp-DEV #28 PREEMPTLAZY + Tainted: [U]=USER, [O]=OOT_MODULE + Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.62.0-0 11/19/2025 + Call Trace: + + dump_stack_lvl+0xc5/0x110 ../lib/dump_stack.c:120 + print_address_description ../mm/kasan/report.c:378 [inline] + print_report+0xbc/0x260 ../mm/kasan/report.c:482 + kasan_report+0xa2/0xe0 ../mm/kasan/report.c:595 + check_region_inline ../mm/kasan/generic.c:-1 [inline] + kasan_check_range+0x264/0x2c0 ../mm/kasan/generic.c:200 + instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] + _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] + _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 + copy_to_user ../include/linux/uaccess.h:236 [inline] + sev_ioctl_do_pek_csr+0x31f/0x590 ../drivers/crypto/ccp/sev-dev.c:1872 + sev_ioctl+0x3a4/0x490 ../drivers/crypto/ccp/sev-dev.c:2562 + vfs_ioctl ../fs/ioctl.c:51 [inline] + __do_sys_ioctl ../fs/ioctl.c:597 [inline] + __se_sys_ioctl+0x11d/0x1b0 ../fs/ioctl.c:583 + do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xe0/0x800 ../arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + +WARN if the driver says the command succeeded, but the firmware error code +says otherwise, as __sev_do_cmd_locked() is expected to return -EIO on any +firwmware error. + +Reported-by: Alexander Potapenko +Reported-by: Sebastian Alba Vives +Fixes: e799035609e1 ("crypto: ccp: Implement SEV_PEK_CSR ioctl command") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/ccp/sev-dev.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -1860,7 +1860,10 @@ cmd: + + ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, &data, &argp->error); + +- /* If we query the CSR length, FW responded with expected data. */ ++ /* ++ * Firmware will returns the length of the CSR blob (either the minimum ++ * required length or the actual length written), return it to the user. ++ */ + input.length = data.len; + + if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { +@@ -1868,6 +1871,9 @@ cmd: + goto e_free_blob; + } + ++ if (ret || WARN_ON_ONCE(argp->error)) ++ goto e_free_blob; ++ + if (blob) { + if (copy_to_user(input_address, blob, input.length)) + ret = -EFAULT; diff --git a/queue-7.0/crypto-ccp-don-t-attempt-to-copy-id-to-userspace-if-psp-command-failed.patch b/queue-7.0/crypto-ccp-don-t-attempt-to-copy-id-to-userspace-if-psp-command-failed.patch new file mode 100644 index 0000000000..8eec2a7639 --- /dev/null +++ b/queue-7.0/crypto-ccp-don-t-attempt-to-copy-id-to-userspace-if-psp-command-failed.patch @@ -0,0 +1,72 @@ +From 4f685dbfa87c546e51d9dc6cab379d20f275e114 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Fri, 13 Mar 2026 10:57:31 -0700 +Subject: crypto: ccp: Don't attempt to copy ID to userspace if PSP command failed + +From: Sean Christopherson + +commit 4f685dbfa87c546e51d9dc6cab379d20f275e114 upstream. + +When retrieving the ID for the CPU, don't attempt to copy the ID blob to +userspace if the firmware command failed. If the failure was due to an +invalid length, i.e. the userspace buffer+length was too small, copying +the number of bytes _firmware_ requires will overflow the kernel-allocated +buffer and leak data to userspace. + + BUG: KASAN: slab-out-of-bounds in instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] + BUG: KASAN: slab-out-of-bounds in _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] + BUG: KASAN: slab-out-of-bounds in _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 + Read of size 64 at addr ffff8881867f5960 by task syz.0.906/24388 + + CPU: 130 UID: 0 PID: 24388 Comm: syz.0.906 Tainted: G U O 7.0.0-smp-DEV #28 PREEMPTLAZY + Tainted: [U]=USER, [O]=OOT_MODULE + Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.62.0-0 11/19/2025 + Call Trace: + + dump_stack_lvl+0xc5/0x110 ../lib/dump_stack.c:120 + print_address_description ../mm/kasan/report.c:378 [inline] + print_report+0xbc/0x260 ../mm/kasan/report.c:482 + kasan_report+0xa2/0xe0 ../mm/kasan/report.c:595 + check_region_inline ../mm/kasan/generic.c:-1 [inline] + kasan_check_range+0x264/0x2c0 ../mm/kasan/generic.c:200 + instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] + _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] + _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 + copy_to_user ../include/linux/uaccess.h:236 [inline] + sev_ioctl_do_get_id2+0x361/0x490 ../drivers/crypto/ccp/sev-dev.c:2222 + sev_ioctl+0x25f/0x490 ../drivers/crypto/ccp/sev-dev.c:2575 + vfs_ioctl ../fs/ioctl.c:51 [inline] + __do_sys_ioctl ../fs/ioctl.c:597 [inline] + __se_sys_ioctl+0x11d/0x1b0 ../fs/ioctl.c:583 + do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xe0/0x800 ../arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + +WARN if the driver says the command succeeded, but the firmware error code +says otherwise, as __sev_do_cmd_locked() is expected to return -EIO on any +firwmware error. + +Reported-by: Alexander Potapenko +Reported-by: Sebastian Alba Vives +Fixes: d6112ea0cb34 ("crypto: ccp - introduce SEV_GET_ID2 command") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/ccp/sev-dev.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -2224,6 +2224,9 @@ static int sev_ioctl_do_get_id2(struct s + goto e_free; + } + ++ if (ret || WARN_ON_ONCE(argp->error)) ++ goto e_free; ++ + if (id_blob) { + if (copy_to_user(input_address, id_blob, data.len)) { + ret = -EFAULT; diff --git a/queue-7.0/crypto-ccp-don-t-attempt-to-copy-pdh-cert-to-userspace-if-psp-command-failed.patch b/queue-7.0/crypto-ccp-don-t-attempt-to-copy-pdh-cert-to-userspace-if-psp-command-failed.patch new file mode 100644 index 0000000000..8313966b7a --- /dev/null +++ b/queue-7.0/crypto-ccp-don-t-attempt-to-copy-pdh-cert-to-userspace-if-psp-command-failed.patch @@ -0,0 +1,84 @@ +From e76239fed3cffd6d304d8ca3ce23984fd24f57d3 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Fri, 13 Mar 2026 10:48:53 -0700 +Subject: crypto: ccp: Don't attempt to copy PDH cert to userspace if PSP command failed + +From: Sean Christopherson + +commit e76239fed3cffd6d304d8ca3ce23984fd24f57d3 upstream. + +When retrieving the PDH cert, don't attempt to copy the blobs to userspace +if the firmware command failed. If the failure was due to an invalid +length, i.e. the userspace buffer+length was too small, copying the number +of bytes _firmware_ requires will overflow the kernel-allocated buffer and +leak data to userspace. + + BUG: KASAN: slab-out-of-bounds in instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] + BUG: KASAN: slab-out-of-bounds in _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] + BUG: KASAN: slab-out-of-bounds in _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 + Read of size 2084 at addr ffff8885c4ab8aa0 by task syz.0.186/21033 + + CPU: 51 UID: 0 PID: 21033 Comm: syz.0.186 Tainted: G U O 7.0.0-smp-DEV #28 PREEMPTLAZY + Tainted: [U]=USER, [O]=OOT_MODULE + Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 34.84.12-0 11/17/2025 + Call Trace: + + dump_stack_lvl+0xc5/0x110 ../lib/dump_stack.c:120 + print_address_description ../mm/kasan/report.c:378 [inline] + print_report+0xbc/0x260 ../mm/kasan/report.c:482 + kasan_report+0xa2/0xe0 ../mm/kasan/report.c:595 + check_region_inline ../mm/kasan/generic.c:-1 [inline] + kasan_check_range+0x264/0x2c0 ../mm/kasan/generic.c:200 + instrument_copy_to_user ../include/linux/instrumented.h:129 [inline] + _inline_copy_to_user ../include/linux/uaccess.h:205 [inline] + _copy_to_user+0x66/0xa0 ../lib/usercopy.c:26 + copy_to_user ../include/linux/uaccess.h:236 [inline] + sev_ioctl_do_pdh_export+0x3d3/0x7c0 ../drivers/crypto/ccp/sev-dev.c:2347 + sev_ioctl+0x2a2/0x490 ../drivers/crypto/ccp/sev-dev.c:2568 + vfs_ioctl ../fs/ioctl.c:51 [inline] + __do_sys_ioctl ../fs/ioctl.c:597 [inline] + __se_sys_ioctl+0x11d/0x1b0 ../fs/ioctl.c:583 + do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xe0/0x800 ../arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + +WARN if the driver says the command succeeded, but the firmware error code +says otherwise, as __sev_do_cmd_locked() is expected to return -EIO on any +firwmware error. + +Reported-by: Alexander Potapenko +Reported-by: Sebastian Alba Vives +Fixes: 76a2b524a4b1 ("crypto: ccp: Implement SEV_PDH_CERT_EXPORT ioctl command") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/ccp/sev-dev.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -2340,7 +2340,10 @@ cmd: + + ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, &data, &argp->error); + +- /* If we query the length, FW responded with expected data. */ ++ /* ++ * Firmware will return the length of the blobs (either the minimum ++ * required length or the actual length written), return 'em to the user. ++ */ + input.cert_chain_len = data.cert_chain_len; + input.pdh_cert_len = data.pdh_cert_len; + +@@ -2349,6 +2352,9 @@ cmd: + goto e_free_cert; + } + ++ if (ret || WARN_ON_ONCE(argp->error)) ++ goto e_free_cert; ++ + if (pdh_blob) { + if (copy_to_user(input_pdh_cert_address, + pdh_blob, input.pdh_cert_len)) { diff --git a/queue-7.0/f2fs-fix-to-avoid-memory-leak-in-f2fs_rename.patch b/queue-7.0/f2fs-fix-to-avoid-memory-leak-in-f2fs_rename.patch new file mode 100644 index 0000000000..439f731f07 --- /dev/null +++ b/queue-7.0/f2fs-fix-to-avoid-memory-leak-in-f2fs_rename.patch @@ -0,0 +1,63 @@ +From 3cf11e6f36c170050c12171dd6fd3142711478fc Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Wed, 4 Mar 2026 16:22:31 +0800 +Subject: f2fs: fix to avoid memory leak in f2fs_rename() + +From: Chao Yu + +commit 3cf11e6f36c170050c12171dd6fd3142711478fc upstream. + +syzbot reported a f2fs bug as below: + +BUG: memory leak +unreferenced object 0xffff888127f70830 (size 16): + comm "syz.0.23", pid 6144, jiffies 4294943712 + hex dump (first 16 bytes): + 3c af 57 72 5b e6 8f ad 6e 8e fd 33 42 39 03 ff <.Wr[...n..3B9.. + backtrace (crc 925f8a80): + kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline] + slab_post_alloc_hook mm/slub.c:4520 [inline] + slab_alloc_node mm/slub.c:4844 [inline] + __do_kmalloc_node mm/slub.c:5237 [inline] + __kmalloc_noprof+0x3bd/0x560 mm/slub.c:5250 + kmalloc_noprof include/linux/slab.h:954 [inline] + fscrypt_setup_filename+0x15e/0x3b0 fs/crypto/fname.c:364 + f2fs_setup_filename+0x52/0xb0 fs/f2fs/dir.c:143 + f2fs_rename+0x159/0xca0 fs/f2fs/namei.c:961 + f2fs_rename2+0xd5/0xf20 fs/f2fs/namei.c:1308 + vfs_rename+0x7ff/0x1250 fs/namei.c:6026 + filename_renameat2+0x4f4/0x660 fs/namei.c:6144 + __do_sys_renameat2 fs/namei.c:6173 [inline] + __se_sys_renameat2 fs/namei.c:6168 [inline] + __x64_sys_renameat2+0x59/0x80 fs/namei.c:6168 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +The root cause is in commit 40b2d55e0452 ("f2fs: fix to create selinux +label during whiteout initialization"), we added a call to +f2fs_setup_filename() without a matching call to f2fs_free_filename(), +fix it. + +Fixes: 40b2d55e0452 ("f2fs: fix to create selinux label during whiteout initialization") +Cc: stable@kernel.org +Reported-by: syzbot+cf7946ab25b21abc4b66@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/linux-f2fs-devel/69a75fe1.a70a0220.b118c.0014.GAE@google.com +Suggested-by: Eric Biggers +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/namei.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/f2fs/namei.c ++++ b/fs/f2fs/namei.c +@@ -964,6 +964,7 @@ static int f2fs_rename(struct mnt_idmap + return err; + + err = f2fs_create_whiteout(idmap, old_dir, &whiteout, &fname); ++ f2fs_free_filename(&fname); + if (err) + return err; + } diff --git a/queue-7.0/f2fs-fix-to-avoid-uninit-value-access-in-f2fs_sanity_check_node_footer.patch b/queue-7.0/f2fs-fix-to-avoid-uninit-value-access-in-f2fs_sanity_check_node_footer.patch new file mode 100644 index 0000000000..8659fc2b2b --- /dev/null +++ b/queue-7.0/f2fs-fix-to-avoid-uninit-value-access-in-f2fs_sanity_check_node_footer.patch @@ -0,0 +1,71 @@ +From 7b9161a605e91d0987e2596a245dc1f21621b23f Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Mon, 9 Mar 2026 02:22:37 +0000 +Subject: f2fs: fix to avoid uninit-value access in f2fs_sanity_check_node_footer + +From: Chao Yu + +commit 7b9161a605e91d0987e2596a245dc1f21621b23f upstream. + +syzbot reported a f2fs bug as below: + +BUG: KMSAN: uninit-value in f2fs_sanity_check_node_footer+0x374/0xa20 fs/f2fs/node.c:1520 + f2fs_sanity_check_node_footer+0x374/0xa20 fs/f2fs/node.c:1520 + f2fs_finish_read_bio+0xe1e/0x1d60 fs/f2fs/data.c:177 + f2fs_read_end_io+0x6ab/0x2220 fs/f2fs/data.c:-1 + bio_endio+0x1006/0x1160 block/bio.c:1792 + submit_bio_noacct+0x533/0x2960 block/blk-core.c:891 + submit_bio+0x57a/0x620 block/blk-core.c:926 + blk_crypto_submit_bio include/linux/blk-crypto.h:203 [inline] + f2fs_submit_read_bio+0x12c/0x360 fs/f2fs/data.c:557 + f2fs_submit_page_bio+0xee2/0x1450 fs/f2fs/data.c:775 + read_node_folio+0x384/0x4b0 fs/f2fs/node.c:1481 + __get_node_folio+0x5db/0x15d0 fs/f2fs/node.c:1576 + f2fs_get_inode_folio+0x40/0x50 fs/f2fs/node.c:1623 + do_read_inode fs/f2fs/inode.c:425 [inline] + f2fs_iget+0x1209/0x9380 fs/f2fs/inode.c:596 + f2fs_fill_super+0x8f5a/0xb2e0 fs/f2fs/super.c:5184 + get_tree_bdev_flags+0x6e6/0x920 fs/super.c:1694 + get_tree_bdev+0x38/0x50 fs/super.c:1717 + f2fs_get_tree+0x35/0x40 fs/f2fs/super.c:5436 + vfs_get_tree+0xb3/0x5d0 fs/super.c:1754 + fc_mount fs/namespace.c:1193 [inline] + do_new_mount_fc fs/namespace.c:3763 [inline] + do_new_mount+0x885/0x1dd0 fs/namespace.c:3839 + path_mount+0x7a2/0x20b0 fs/namespace.c:4159 + do_mount fs/namespace.c:4172 [inline] + __do_sys_mount fs/namespace.c:4361 [inline] + __se_sys_mount+0x704/0x7f0 fs/namespace.c:4338 + __x64_sys_mount+0xe4/0x150 fs/namespace.c:4338 + x64_sys_call+0x39f0/0x3ea0 arch/x86/include/generated/asm/syscalls_64.h:166 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x134/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +The root cause is: in f2fs_finish_read_bio(), we may access uninit data +in folio if we failed to read the data from device into folio, let's add +a check condition to avoid such issue. + +Cc: stable@kernel.org +Fixes: 50ac3ecd8e05 ("f2fs: fix to do sanity check on node footer in {read,write}_end_io") +Reported-by: syzbot+9aac813cdc456cdd49f8@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/linux-f2fs-devel/69a9ca26.a70a0220.305d9a.0000.GAE@google.com +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -173,7 +173,8 @@ static void f2fs_finish_read_bio(struct + while (nr_pages--) + dec_page_count(F2FS_F_SB(folio), __read_io_type(folio)); + +- if (F2FS_F_SB(folio)->node_inode && is_node_folio(folio) && ++ if (bio->bi_status == BLK_STS_OK && ++ F2FS_F_SB(folio)->node_inode && is_node_folio(folio) && + f2fs_sanity_check_node_footer(F2FS_F_SB(folio), + folio, folio->index, NODE_TYPE_REGULAR, true)) + bio->bi_status = BLK_STS_IOERR; diff --git a/queue-7.0/f2fs-fix-to-do-sanity-check-on-dcc-discard_cmd_cnt-conditionally.patch b/queue-7.0/f2fs-fix-to-do-sanity-check-on-dcc-discard_cmd_cnt-conditionally.patch new file mode 100644 index 0000000000..a5affa3899 --- /dev/null +++ b/queue-7.0/f2fs-fix-to-do-sanity-check-on-dcc-discard_cmd_cnt-conditionally.patch @@ -0,0 +1,153 @@ +From 6af249c996f7d73a3435f9e577956fa259347d18 Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Wed, 11 Mar 2026 21:35:42 +0800 +Subject: f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally + +From: Chao Yu + +commit 6af249c996f7d73a3435f9e577956fa259347d18 upstream. + +Syzbot reported a f2fs bug as below: + +------------[ cut here ]------------ +kernel BUG at fs/f2fs/segment.c:1900! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 6527 Comm: syz.5.110 Not tainted syzkaller #0 PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026 +RIP: 0010:f2fs_issue_discard_timeout+0x59b/0x5a0 fs/f2fs/segment.c:1900 +Code: d9 80 e1 07 80 c1 03 38 c1 0f 8c d6 fe ff ff 48 89 df e8 a8 5e fa fd e9 c9 fe ff ff e8 4e 46 94 fd 90 0f 0b e8 46 46 94 fd 90 <0f> 0b 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 +RSP: 0018:ffffc9000494f940 EFLAGS: 00010283 +RAX: ffffffff843009ca RBX: 0000000000000001 RCX: 0000000000080000 +RDX: ffffc9001ca78000 RSI: 00000000000029f3 RDI: 00000000000029f4 +RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: ffffed100893a431 R12: 1ffff1100893a430 +R13: 1ffff1100c2b702c R14: dffffc0000000000 R15: ffff8880449d2160 +FS: 00007ffa35fed6c0(0000) GS:ffff88812643d000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f2b68634000 CR3: 0000000039f62000 CR4: 00000000003526f0 +Call Trace: + + __f2fs_remount fs/f2fs/super.c:2960 [inline] + f2fs_reconfigure+0x108a/0x1710 fs/f2fs/super.c:5443 + reconfigure_super+0x227/0x8a0 fs/super.c:1080 + do_remount fs/namespace.c:3391 [inline] + path_mount+0xdc5/0x10e0 fs/namespace.c:4151 + do_mount fs/namespace.c:4172 [inline] + __do_sys_mount fs/namespace.c:4361 [inline] + __se_sys_mount+0x31d/0x420 fs/namespace.c:4338 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7ffa37dbda0a + +The root cause is there will be race condition in between f2fs_ioc_fitrim() +and f2fs_remount(): + +- f2fs_remount - f2fs_ioc_fitrim + - f2fs_issue_discard_timeout + - __issue_discard_cmd + - __drop_discard_cmd + - __wait_all_discard_cmd + - f2fs_trim_fs + - f2fs_write_checkpoint + - f2fs_clear_prefree_segments + - f2fs_issue_discard + - __issue_discard_async + - __queue_discard_cmd + - __update_discard_tree_range + - __insert_discard_cmd + - __create_discard_cmd + : atomic_inc(&dcc->discard_cmd_cnt); + - sanity check on dcc->discard_cmd_cnt (expect discard_cmd_cnt to be zero) + +This will only happen when fitrim races w/ remount rw, if we remount to +readonly filesystem, remount will wait until mnt_pcp.mnt_writers to zero, +that means fitrim is not in process at that time. + +Cc: stable@kernel.org +Fixes: 2482c4325dfe ("f2fs: detect bug_on in f2fs_wait_discard_bios") +Reported-by: syzbot+62538b67389ee582837a@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/linux-f2fs-devel/69b07d7c.050a0220.8df7.09a1.GAE@google.com +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 2 +- + fs/f2fs/segment.c | 6 +++--- + fs/f2fs/super.c | 11 ++++++++--- + 3 files changed, 12 insertions(+), 7 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -3989,7 +3989,7 @@ bool f2fs_is_checkpointed_data(struct f2 + int f2fs_start_discard_thread(struct f2fs_sb_info *sbi); + void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi); + void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi); +-bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi); ++bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi, bool need_check); + void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, + struct cp_control *cpc); + void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi); +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -1880,7 +1880,7 @@ void f2fs_stop_discard_thread(struct f2f + * + * Return true if issued all discard cmd or no discard cmd need issue, otherwise return false. + */ +-bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) ++bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi, bool need_check) + { + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; + struct discard_policy dpolicy; +@@ -1897,7 +1897,7 @@ bool f2fs_issue_discard_timeout(struct f + /* just to make sure there is no pending discard commands */ + __wait_all_discard_cmd(sbi, NULL); + +- f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt)); ++ f2fs_bug_on(sbi, need_check && atomic_read(&dcc->discard_cmd_cnt)); + return !dropped; + } + +@@ -2367,7 +2367,7 @@ static void destroy_discard_cmd_control( + * Recovery can cache discard commands, so in error path of + * fill_super(), it needs to give a chance to handle them. + */ +- f2fs_issue_discard_timeout(sbi); ++ f2fs_issue_discard_timeout(sbi, true); + + kfree(dcc); + SM_I(sbi)->dcc_info = NULL; +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -2009,7 +2009,7 @@ static void f2fs_put_super(struct super_ + } + + /* be sure to wait for any on-going discard commands */ +- done = f2fs_issue_discard_timeout(sbi); ++ done = f2fs_issue_discard_timeout(sbi, true); + if (f2fs_realtime_discard_enable(sbi) && !sbi->discard_blks && done) { + struct cp_control cpc = { + .reason = CP_UMOUNT | CP_TRIMMED, +@@ -2152,7 +2152,7 @@ static int f2fs_unfreeze(struct super_bl + * will recover after removal of snapshot. + */ + if (test_opt(sbi, DISCARD) && !f2fs_hw_support_discard(sbi)) +- f2fs_issue_discard_timeout(sbi); ++ f2fs_issue_discard_timeout(sbi, true); + + clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); + return 0; +@@ -2957,7 +2957,12 @@ static int __f2fs_remount(struct fs_cont + need_stop_discard = true; + } else { + f2fs_stop_discard_thread(sbi); +- f2fs_issue_discard_timeout(sbi); ++ /* ++ * f2fs_ioc_fitrim() won't race w/ "remount ro" ++ * so it's safe to check discard_cmd_cnt in ++ * f2fs_issue_discard_timeout(). ++ */ ++ f2fs_issue_discard_timeout(sbi, flags & SB_RDONLY); + need_restart_discard = true; + } + } diff --git a/queue-7.0/f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch b/queue-7.0/f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch new file mode 100644 index 0000000000..d599beff82 --- /dev/null +++ b/queue-7.0/f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch @@ -0,0 +1,71 @@ +From 2d9c4a4ed4eef1f82c5b16b037aee8bad819fd53 Mon Sep 17 00:00:00 2001 +From: Yongpeng Yang +Date: Fri, 27 Feb 2026 15:30:52 +0800 +Subject: f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io() + +From: Yongpeng Yang + +commit 2d9c4a4ed4eef1f82c5b16b037aee8bad819fd53 upstream. + +The xfstests case "generic/107" and syzbot have both reported a NULL +pointer dereference. + +The concurrent scenario that triggers the panic is as follows: + +F2FS_WB_CP_DATA write callback umount + - f2fs_write_checkpoint + - f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA) +- blk_mq_end_request + - bio_endio + - f2fs_write_end_io + : dec_page_count(sbi, F2FS_WB_CP_DATA) + : wake_up(&sbi->cp_wait) + - kill_f2fs_super + - kill_block_super + - f2fs_put_super + : iput(sbi->node_inode) + : sbi->node_inode = NULL + : f2fs_in_warm_node_list + - is_node_folio // sbi->node_inode is NULL and panic + +The root cause is that f2fs_put_super() calls iput(sbi->node_inode) and +sets sbi->node_inode to NULL after sbi->nr_pages[F2FS_WB_CP_DATA] is +decremented to zero. As a result, f2fs_in_warm_node_list() may +dereference a NULL node_inode when checking whether a folio belongs to +the node inode, leading to a panic. + +This patch fixes the issue by calling f2fs_in_warm_node_list() before +decrementing sbi->nr_pages[F2FS_WB_CP_DATA], thus preventing the +use-after-free condition. + +Cc: stable@kernel.org +Fixes: 50fa53eccf9f ("f2fs: fix to avoid broken of dnode block list") +Reported-by: syzbot+6e4cb1cac5efc96ea0ca@syzkaller.appspotmail.com +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -386,6 +386,8 @@ static void f2fs_write_end_io(struct bio + folio->index, NODE_TYPE_REGULAR, true); + f2fs_bug_on(sbi, folio->index != nid_of_node(folio)); + } ++ if (f2fs_in_warm_node_list(sbi, folio)) ++ f2fs_del_fsync_node_entry(sbi, folio); + + dec_page_count(sbi, type); + +@@ -397,8 +399,6 @@ static void f2fs_write_end_io(struct bio + wq_has_sleeper(&sbi->cp_wait)) + wake_up(&sbi->cp_wait); + +- if (f2fs_in_warm_node_list(sbi, folio)) +- f2fs_del_fsync_node_entry(sbi, folio); + folio_clear_f2fs_gcing(folio); + folio_end_writeback(folio); + } diff --git a/queue-7.0/f2fs-fix-use-after-free-of-sbi-in-f2fs_compress_write_end_io.patch b/queue-7.0/f2fs-fix-use-after-free-of-sbi-in-f2fs_compress_write_end_io.patch new file mode 100644 index 0000000000..a7fe2b4b26 --- /dev/null +++ b/queue-7.0/f2fs-fix-use-after-free-of-sbi-in-f2fs_compress_write_end_io.patch @@ -0,0 +1,78 @@ +From 39d4ee19c1e7d753dd655aebee632271b171f43a Mon Sep 17 00:00:00 2001 +From: George Saad +Date: Mon, 23 Mar 2026 11:21:23 +0000 +Subject: f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: George Saad + +commit 39d4ee19c1e7d753dd655aebee632271b171f43a upstream. + +In f2fs_compress_write_end_io(), dec_page_count(sbi, type) can bring +the F2FS_WB_CP_DATA counter to zero, unblocking +f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount +CPU. The unmount path then proceeds to call +f2fs_destroy_page_array_cache(sbi), which destroys +sbi->page_array_slab via kmem_cache_destroy(), and eventually +kfree(sbi). Meanwhile, the bio completion callback is still executing: +when it reaches page_array_free(sbi, ...), it dereferences +sbi->page_array_slab — a destroyed slab cache — to call +kmem_cache_free(), causing a use-after-free. + +This is the same class of bug as CVE-2026-23234 (which fixed the +equivalent race in f2fs_write_end_io() in data.c), but in the +compressed writeback completion path that was not covered by that fix. + +Fix this by moving dec_page_count() to after page_array_free(), so +that all sbi accesses complete before the counter decrement that can +unblock unmount. For non-last folios (where atomic_dec_return on +cic->pending_pages is nonzero), dec_page_count is called immediately +before returning — page_array_free is not reached on this path, so +there is no post-decrement sbi access. For the last folio, +page_array_free runs while the F2FS_WB_CP_DATA counter is still +nonzero (this folio has not yet decremented it), keeping sbi alive, +and dec_page_count runs as the final operation. + +Fixes: 4c8ff7095bef ("f2fs: support data compression") +Cc: stable@vger.kernel.org +Signed-off-by: George Saad +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/compress.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/fs/f2fs/compress.c ++++ b/fs/f2fs/compress.c +@@ -1491,10 +1491,10 @@ void f2fs_compress_write_end_io(struct b + + f2fs_compress_free_page(page); + +- dec_page_count(sbi, type); +- +- if (atomic_dec_return(&cic->pending_pages)) ++ if (atomic_dec_return(&cic->pending_pages)) { ++ dec_page_count(sbi, type); + return; ++ } + + for (i = 0; i < cic->nr_rpages; i++) { + WARN_ON(!cic->rpages[i]); +@@ -1504,6 +1504,14 @@ void f2fs_compress_write_end_io(struct b + + page_array_free(sbi, cic->rpages, cic->nr_rpages); + kmem_cache_free(cic_entry_slab, cic); ++ ++ /* ++ * Make sure dec_page_count() is the last access to sbi. ++ * Once it drops the F2FS_WB_CP_DATA counter to zero, the ++ * unmount thread can proceed to destroy sbi and ++ * sbi->page_array_slab. ++ */ ++ dec_page_count(sbi, type); + } + + static int f2fs_write_raw_pages(struct compress_ctx *cc, diff --git a/queue-7.0/fs-ntfs3-validate-rec-used-in-journal-replay-file-record-check.patch b/queue-7.0/fs-ntfs3-validate-rec-used-in-journal-replay-file-record-check.patch new file mode 100644 index 0000000000..4ebad4c757 --- /dev/null +++ b/queue-7.0/fs-ntfs3-validate-rec-used-in-journal-replay-file-record-check.patch @@ -0,0 +1,78 @@ +From 0ca0485e4b2e837ebb6cbd4f2451aba665a03e4b Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 9 Apr 2026 16:37:15 +0200 +Subject: fs/ntfs3: validate rec->used in journal-replay file record check + +From: Greg Kroah-Hartman + +commit 0ca0485e4b2e837ebb6cbd4f2451aba665a03e4b upstream. + +check_file_record() validates rec->total against the record size but +never validates rec->used. The do_action() journal-replay handlers read +rec->used from disk and use it to compute memmove lengths: + + DeleteAttribute: memmove(attr, ..., used - asize - roff) + CreateAttribute: memmove(..., attr, used - roff) + change_attr_size: memmove(..., used - PtrOffset(rec, next)) + +When rec->used is smaller than the offset of a validated attribute, or +larger than the record size, these subtractions can underflow allowing +us to copy huge amounts of memory in to a 4kb buffer, generally +considered a bad idea overall. + +This requires a corrupted filesystem, which isn't a threat model the +kernel really needs to worry about, but checking for such an obvious +out-of-bounds value is good to keep things robust, especially on journal +replay + +Fix this up by bounding rec->used correctly. + +This is much like commit b2bc7c44ed17 ("fs/ntfs3: Fix slab-out-of-bounds +read in DeleteIndexEntryRoot") which checked different values in this +same switch statement. + +Cc: Konstantin Komarov +Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal") +Cc: stable +Assisted-by: gregkh_clanker_t1000 +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Konstantin Komarov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ntfs3/fslog.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -2791,13 +2791,14 @@ static inline bool check_file_record(con + u16 fn = le16_to_cpu(rec->rhdr.fix_num); + u16 ao = le16_to_cpu(rec->attr_off); + u32 rs = sbi->record_size; ++ u32 used = le32_to_cpu(rec->used); + + /* Check the file record header for consistency. */ + if (rec->rhdr.sign != NTFS_FILE_SIGNATURE || + fo > (SECTOR_SIZE - ((rs >> SECTOR_SHIFT) + 1) * sizeof(short)) || + (fn - 1) * SECTOR_SIZE != rs || ao < MFTRECORD_FIXUP_OFFSET_1 || + ao > sbi->record_size - SIZEOF_RESIDENT || !is_rec_inuse(rec) || +- le32_to_cpu(rec->total) != rs) { ++ le32_to_cpu(rec->total) != rs || used > rs || used < ao) { + return false; + } + +@@ -2809,6 +2810,15 @@ static inline bool check_file_record(con + return false; + } + ++ /* ++ * The do_action() handlers compute memmove lengths as ++ * "rec->used - ", which underflows when ++ * rec->used is smaller than the attribute walk reached. At this ++ * point attr is the ATTR_END marker; rec->used must cover it. ++ */ ++ if (used < PtrOffset(rec, attr) + sizeof(attr->type)) ++ return false; ++ + return true; + } + diff --git a/queue-7.0/fuse-abort-on-fatal-signal-during-sync-init.patch b/queue-7.0/fuse-abort-on-fatal-signal-during-sync-init.patch new file mode 100644 index 0000000000..3ac8b3ccf4 --- /dev/null +++ b/queue-7.0/fuse-abort-on-fatal-signal-during-sync-init.patch @@ -0,0 +1,75 @@ +From 204aa22a686bfee48daca7db620c1e017615f2ff Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Mon, 16 Mar 2026 14:10:00 +0100 +Subject: fuse: abort on fatal signal during sync init + +From: Miklos Szeredi + +commit 204aa22a686bfee48daca7db620c1e017615f2ff upstream. + +When sync init is used and the server exits for some reason (error, crash) +while processing FUSE_INIT, the filesystem creation will hang. The reason +is that while all other threads will exit, the mounting thread (or process) +will keep the device fd open, which will prevent an abort from happening. + +This is a regression from the async mount case, where the mount was done +first, and the FUSE_INIT processing afterwards, in which case there's no +such recursive syscall keeping the fd open. + +Fixes: dfb84c330794 ("fuse: allow synchronous FUSE_INIT") +Cc: stable@vger.kernel.org # v6.18 +Reviewed-by: Joanne Koong +Reviewed-by: Bernd Schubert +Reviewed-by: "Darrick J. Wong" +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/dev.c | 8 +++++++- + fs/fuse/fuse_i.h | 1 + + fs/fuse/inode.c | 1 + + 3 files changed, 9 insertions(+), 1 deletion(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -570,6 +570,11 @@ static void request_wait_answer(struct f + if (!err) + return; + ++ if (req->args->abort_on_kill) { ++ fuse_abort_conn(fc); ++ return; ++ } ++ + if (test_bit(FR_URING, &req->flags)) + removed = fuse_uring_remove_pending_req(req); + else +@@ -676,7 +681,8 @@ ssize_t __fuse_simple_request(struct mnt + fuse_force_creds(req); + + __set_bit(FR_WAITING, &req->flags); +- __set_bit(FR_FORCE, &req->flags); ++ if (!args->abort_on_kill) ++ __set_bit(FR_FORCE, &req->flags); + } else { + WARN_ON(args->nocreds); + req = fuse_get_req(idmap, fm, false); +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -345,6 +345,7 @@ struct fuse_args { + bool is_ext:1; + bool is_pinned:1; + bool invalidate_vmap:1; ++ bool abort_on_kill:1; + struct fuse_in_arg in_args[4]; + struct fuse_arg out_args[2]; + void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -1551,6 +1551,7 @@ int fuse_send_init(struct fuse_mount *fm + int err; + + if (fm->fc->sync_init) { ++ ia->args.abort_on_kill = true; + err = fuse_simple_request(fm, &ia->args); + /* Ignore size of init reply */ + if (err > 0) diff --git a/queue-7.0/fuse-check-for-large-folio-with-splice_f_move.patch b/queue-7.0/fuse-check-for-large-folio-with-splice_f_move.patch new file mode 100644 index 0000000000..8426ed5d3c --- /dev/null +++ b/queue-7.0/fuse-check-for-large-folio-with-splice_f_move.patch @@ -0,0 +1,40 @@ +From 59ba47b6be9cd0146ef9a55c6e32e337e11e7625 Mon Sep 17 00:00:00 2001 +From: Bernd Schubert +Date: Sun, 11 Jan 2026 12:48:07 +0100 +Subject: fuse: Check for large folio with SPLICE_F_MOVE + +From: Bernd Schubert + +commit 59ba47b6be9cd0146ef9a55c6e32e337e11e7625 upstream. + +xfstest generic/074 and generic/075 complain result in kernel +warning messages / page dumps. +This is easily reproducible (on 6.19) with +CONFIG_TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ALWAYS=y +CONFIG_TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ALWAYS=y + +This just adds a test for large folios fuse_try_move_folio +with the same page copy fallback, but to avoid the warnings +from fuse_check_folio(). + +Cc: stable@vger.kernel.org +Signed-off-by: Bernd Schubert +Signed-off-by: Horst Birthelmer +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/dev.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1017,6 +1017,9 @@ static int fuse_try_move_folio(struct fu + folio_clear_uptodate(newfolio); + folio_clear_mappedtodisk(newfolio); + ++ if (folio_test_large(newfolio)) ++ goto out_fallback_unlock; ++ + if (fuse_check_folio(newfolio) != 0) + goto out_fallback_unlock; + diff --git a/queue-7.0/fuse-fuse_dev_ioctl_clone-should-wait-for-device-file-to-be-initialized.patch b/queue-7.0/fuse-fuse_dev_ioctl_clone-should-wait-for-device-file-to-be-initialized.patch new file mode 100644 index 0000000000..3ca93918cc --- /dev/null +++ b/queue-7.0/fuse-fuse_dev_ioctl_clone-should-wait-for-device-file-to-be-initialized.patch @@ -0,0 +1,60 @@ +From da6fcc6dbddbef80e603d2f0c1554a9f2ac03742 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Thu, 2 Apr 2026 20:19:55 +0200 +Subject: fuse: fuse_dev_ioctl_clone() should wait for device file to be initialized + +From: Miklos Szeredi + +commit da6fcc6dbddbef80e603d2f0c1554a9f2ac03742 upstream. + +Use fuse_get_dev() not __fuse_get_dev() on the old fd, since in the case of +synchronous INIT the caller will want to wait for the device file to be +available for cloning, just like I/O wants to wait instead of returning an +error. + +Fixes: dfb84c330794 ("fuse: allow synchronous FUSE_INIT") +Cc: stable@vger.kernel.org # v6.18 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/dev.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -2599,9 +2599,8 @@ static int fuse_device_clone(struct fuse + + static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp) + { +- int res; + int oldfd; +- struct fuse_dev *fud = NULL; ++ struct fuse_dev *fud; + + if (get_user(oldfd, argp)) + return -EFAULT; +@@ -2614,17 +2613,15 @@ static long fuse_dev_ioctl_clone(struct + * Check against file->f_op because CUSE + * uses the same ioctl handler. + */ +- if (fd_file(f)->f_op == file->f_op) +- fud = __fuse_get_dev(fd_file(f)); ++ if (fd_file(f)->f_op != file->f_op) ++ return -EINVAL; + +- res = -EINVAL; +- if (fud) { +- mutex_lock(&fuse_mutex); +- res = fuse_device_clone(fud->fc, file); +- mutex_unlock(&fuse_mutex); +- } ++ fud = fuse_get_dev(fd_file(f)); ++ if (IS_ERR(fud)) ++ return PTR_ERR(fud); + +- return res; ++ guard(mutex)(&fuse_mutex); ++ return fuse_device_clone(fud->fc, file); + } + + static long fuse_dev_ioctl_backing_open(struct file *file, diff --git a/queue-7.0/fuse-quiet-down-complaints-in-fuse_conn_limit_write.patch b/queue-7.0/fuse-quiet-down-complaints-in-fuse_conn_limit_write.patch new file mode 100644 index 0000000000..cd67b78782 --- /dev/null +++ b/queue-7.0/fuse-quiet-down-complaints-in-fuse_conn_limit_write.patch @@ -0,0 +1,67 @@ +From 129a45f9755a89f573c6a513a6b9e3d234ce89b0 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Mon, 23 Feb 2026 15:06:50 -0800 +Subject: fuse: quiet down complaints in fuse_conn_limit_write +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Darrick J. Wong + +commit 129a45f9755a89f573c6a513a6b9e3d234ce89b0 upstream. + +gcc 15 complains about an uninitialized variable val that is passed by +reference into fuse_conn_limit_write: + + control.c: In function ‘fuse_conn_congestion_threshold_write’: + include/asm-generic/rwonce.h:55:37: warning: ‘val’ may be used uninitialized [-Wmaybe-uninitialized] + 55 | *(volatile typeof(x) *)&(x) = (val); \ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ + include/asm-generic/rwonce.h:61:9: note: in expansion of macro ‘__WRITE_ONCE’ + 61 | __WRITE_ONCE(x, val); \ + | ^~~~~~~~~~~~ + control.c:178:9: note: in expansion of macro ‘WRITE_ONCE’ + 178 | WRITE_ONCE(fc->congestion_threshold, val); + | ^~~~~~~~~~ + control.c:166:18: note: ‘val’ was declared here + 166 | unsigned val; + | ^~~ + +Unfortunately there's enough macro spew involved in kstrtoul_from_user +that I think gcc gives up on its analysis and sprays the above warning. +AFAICT it's not actually a bug, but we could just zero-initialize the +variable to enable using -Wmaybe-uninitialized to find real problems. + +Previously we would use some weird uninitialized_var annotation to quiet +down the warnings, so clearly this code has been like this for quite +some time. + +Cc: stable@vger.kernel.org # v5.9 +Fixes: 3f649ab728cda8 ("treewide: Remove uninitialized_var() usage") +Signed-off-by: Darrick J. Wong +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/control.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/fuse/control.c ++++ b/fs/fuse/control.c +@@ -121,7 +121,7 @@ static ssize_t fuse_conn_max_background_ + const char __user *buf, + size_t count, loff_t *ppos) + { +- unsigned val; ++ unsigned int val = 0; + ssize_t ret; + + ret = fuse_conn_limit_write(file, buf, count, ppos, &val, +@@ -163,7 +163,7 @@ static ssize_t fuse_conn_congestion_thre + const char __user *buf, + size_t count, loff_t *ppos) + { +- unsigned val; ++ unsigned int val = 0; + struct fuse_conn *fc; + ssize_t ret; + diff --git a/queue-7.0/fuse-reject-oversized-dirents-in-page-cache.patch b/queue-7.0/fuse-reject-oversized-dirents-in-page-cache.patch new file mode 100644 index 0000000000..0999686ca0 --- /dev/null +++ b/queue-7.0/fuse-reject-oversized-dirents-in-page-cache.patch @@ -0,0 +1,50 @@ +From 51a8de6c50bf947c8f534cd73da4c8f0a13e7bed Mon Sep 17 00:00:00 2001 +From: Samuel Page +Date: Mon, 20 Apr 2026 11:01:37 +0200 +Subject: fuse: reject oversized dirents in page cache + +From: Samuel Page + +commit 51a8de6c50bf947c8f534cd73da4c8f0a13e7bed upstream. + +fuse_add_dirent_to_cache() computes a serialized dirent size from the +server-controlled namelen field and copies the dirent into a single +page-cache page. The existing logic only checks whether the dirent fits +in the remaining space of the current page and advances to a fresh page +if not. It never checks whether the dirent itself exceeds PAGE_SIZE. + +As a result, a malicious FUSE server can return a dirent with +namelen=4095, producing a serialized record size of 4120 bytes. On 4 KiB +page systems this causes memcpy() to overflow the cache page by 24 bytes +into the following kernel page. + +Reject dirents that cannot fit in a single page before copying them into +the readdir cache. + +Fixes: 69e34551152a ("fuse: allow caching readdir") +Cc: stable@vger.kernel.org # v6.16+ +Assisted-by: Bynario AI +Signed-off-by: Samuel Page +Reported-by: Qi Tang +Reported-by: Zijun Hu +Signed-off-by: Miklos Szeredi +Link: https://patch.msgid.link/20260420090139.662772-1-mszeredi@redhat.com +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/readdir.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/fuse/readdir.c ++++ b/fs/fuse/readdir.c +@@ -41,6 +41,10 @@ static void fuse_add_dirent_to_cache(str + unsigned int offset; + void *addr; + ++ /* Dirent doesn't fit in readdir cache page? Skip caching. */ ++ if (reclen > PAGE_SIZE) ++ return; ++ + spin_lock(&fi->rdc.lock); + /* + * Is cache already completed? Or this entry does not go at the end of diff --git a/queue-7.0/ksmbd-fix-out-of-bounds-write-in-smb2_get_ea-ea-alignment.patch b/queue-7.0/ksmbd-fix-out-of-bounds-write-in-smb2_get_ea-ea-alignment.patch new file mode 100644 index 0000000000..1cd5d45c11 --- /dev/null +++ b/queue-7.0/ksmbd-fix-out-of-bounds-write-in-smb2_get_ea-ea-alignment.patch @@ -0,0 +1,52 @@ +From 30010c952077a1c89ecdd71fc4d574c75a8f5617 Mon Sep 17 00:00:00 2001 +From: Tristan Madani +Date: Fri, 17 Apr 2026 19:33:17 +0000 +Subject: ksmbd: fix out-of-bounds write in smb2_get_ea() EA alignment + +From: Tristan Madani + +commit 30010c952077a1c89ecdd71fc4d574c75a8f5617 upstream. + +smb2_get_ea() applies 4-byte alignment padding via memset() after +writing each EA entry. The bounds check on buf_free_len is performed +before the value memcpy, but the alignment memset fires unconditionally +afterward with no check on remaining space. + +When the EA value exactly fills the remaining buffer (buf_free_len == 0 +after value subtraction), the alignment memset writes 1-3 NUL bytes +past the buf_free_len boundary. In compound requests where the response +buffer is shared across commands, the first command (e.g., READ) can +consume most of the buffer, leaving a tight remainder for the QUERY_INFO +EA response. The alignment memset then overwrites past the physical +kvmalloc allocation into adjacent kernel heap memory. + +Add a bounds check before the alignment memset to ensure buf_free_len +can accommodate the padding bytes. + +This is the same bug pattern fixed by commit beef2634f81f ("ksmbd: fix +potencial OOB in get_file_all_info() for compound requests") and +commit fda9522ed6af ("ksmbd: fix OOB write in QUERY_INFO for compound +requests"), both of which added bounds checks before unconditional +writes in QUERY_INFO response handlers. + +Cc: stable@vger.kernel.org +Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound") +Signed-off-by: Tristan Madani +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smb2pdu.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -4822,6 +4822,8 @@ static int smb2_get_ea(struct ksmbd_work + /* align next xattr entry at 4 byte bundary */ + alignment_bytes = ((next_offset + 3) & ~3) - next_offset; + if (alignment_bytes) { ++ if (buf_free_len < alignment_bytes) ++ break; + memset(ptr, '\0', alignment_bytes); + ptr += alignment_bytes; + next_offset += alignment_bytes; diff --git a/queue-7.0/ksmbd-require-minimum-ace-size-in-smb_check_perm_dacl.patch b/queue-7.0/ksmbd-require-minimum-ace-size-in-smb_check_perm_dacl.patch new file mode 100644 index 0000000000..e0adfa8b35 --- /dev/null +++ b/queue-7.0/ksmbd-require-minimum-ace-size-in-smb_check_perm_dacl.patch @@ -0,0 +1,102 @@ +From d07b26f39246a82399661936dd0c853983cfade7 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Tue, 14 Apr 2026 15:15:33 -0400 +Subject: ksmbd: require minimum ACE size in smb_check_perm_dacl() + +From: Michael Bommarito + +commit d07b26f39246a82399661936dd0c853983cfade7 upstream. + +Both ACE-walk loops in smb_check_perm_dacl() only guard against an +under-sized remaining buffer, not against an ACE whose declared +`ace->size` is smaller than the struct it claims to describe: + + if (offsetof(struct smb_ace, access_req) > aces_size) + break; + ace_size = le16_to_cpu(ace->size); + if (ace_size > aces_size) + break; + +The first check only requires the 4-byte ACE header to be in bounds; +it does not require access_req (4 bytes at offset 4) to be readable. +An attacker who has set a crafted DACL on a file they own can declare +ace->size == 4 with aces_size == 4, pass both checks, and then + + granted |= le32_to_cpu(ace->access_req); /* upper loop */ + compare_sids(&sid, &ace->sid); /* lower loop */ + +reads access_req at offset 4 (OOB by up to 4 bytes) and ace->sid at +offset 8 (OOB by up to CIFS_SID_BASE_SIZE + SID_MAX_SUB_AUTHORITIES +* 4 bytes). + +Tighten both loops to require + + ace_size >= offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE + +which is the smallest valid on-wire ACE layout (4-byte header + +4-byte access_req + 8-byte sid base with zero sub-auths). Also +reject ACEs whose sid.num_subauth exceeds SID_MAX_SUB_AUTHORITIES +before letting compare_sids() dereference sub_auth[] entries. + +parse_sec_desc() already enforces an equivalent check (lines 441-448); +smb_check_perm_dacl() simply grew weaker validation over time. + +Reachability: authenticated SMB client with permission to set an ACL +on a file. On a subsequent CREATE against that file, the kernel +walks the stored DACL via smb_check_perm_dacl() and triggers the +OOB read. Not pre-auth, and the OOB read is not reflected to the +attacker, but KASAN reports and kernel state corruption are +possible. + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Michael Bommarito +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smbacl.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -1342,10 +1342,13 @@ int smb_check_perm_dacl(struct ksmbd_con + ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); + aces_size = acl_size - sizeof(struct smb_acl); + for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) { +- if (offsetof(struct smb_ace, access_req) > aces_size) ++ if (offsetof(struct smb_ace, sid) + ++ aces_size < CIFS_SID_BASE_SIZE) + break; + ace_size = le16_to_cpu(ace->size); +- if (ace_size > aces_size) ++ if (ace_size > aces_size || ++ ace_size < offsetof(struct smb_ace, sid) + ++ CIFS_SID_BASE_SIZE) + break; + aces_size -= ace_size; + granted |= le32_to_cpu(ace->access_req); +@@ -1360,13 +1363,19 @@ int smb_check_perm_dacl(struct ksmbd_con + ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); + aces_size = acl_size - sizeof(struct smb_acl); + for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) { +- if (offsetof(struct smb_ace, access_req) > aces_size) ++ if (offsetof(struct smb_ace, sid) + ++ aces_size < CIFS_SID_BASE_SIZE) + break; + ace_size = le16_to_cpu(ace->size); +- if (ace_size > aces_size) ++ if (ace_size > aces_size || ++ ace_size < offsetof(struct smb_ace, sid) + ++ CIFS_SID_BASE_SIZE) + break; + aces_size -= ace_size; + ++ if (ace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) ++ break; ++ + if (!compare_sids(&sid, &ace->sid) || + !compare_sids(&sid_unix_NFS_mode, &ace->sid)) { + found = 1; diff --git a/queue-7.0/ksmbd-reset-rcount-per-connection-in-ksmbd_conn_wait_idle_sess_id.patch b/queue-7.0/ksmbd-reset-rcount-per-connection-in-ksmbd_conn_wait_idle_sess_id.patch new file mode 100644 index 0000000000..1fce1e1c40 --- /dev/null +++ b/queue-7.0/ksmbd-reset-rcount-per-connection-in-ksmbd_conn_wait_idle_sess_id.patch @@ -0,0 +1,66 @@ +From def036ef87f8641c1c525d5ae17438d7a1006491 Mon Sep 17 00:00:00 2001 +From: DaeMyung Kang +Date: Sun, 19 Apr 2026 02:28:44 +0900 +Subject: ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id() + +From: DaeMyung Kang + +commit def036ef87f8641c1c525d5ae17438d7a1006491 upstream. + +rcount is intended to be connection-specific: 2 for curr_conn, 1 for +every other connection sharing the same session. However, it is +initialised only once before the hash iteration and is never reset. +After the loop visits curr_conn, later sibling connections are also +checked against rcount == 2, so a sibling with req_running == 1 is +incorrectly treated as idle. This makes the outcome depend on the +hash iteration order: whether a given sibling is checked against the +loose (< 2) or the strict (< 1) threshold is decided by whether it +happens to be visited before or after curr_conn. + +The function's contract is "wait until every connection sharing this +session is idle" so that destroy_previous_session() can safely tear +the session down. The latched rcount violates that contract and +reopens the teardown race window the wait logic was meant to close: +destroy_previous_session() may proceed before sibling channels have +actually quiesced, overlapping session teardown with in-flight work +on those connections. + +Recompute rcount inside the loop so each connection is compared +against its own threshold regardless of iteration order. + +This is a code-inspection fix for an iteration-order-dependent logic +error; a targeted reproducer would require SMB3 multichannel with +in-flight work on a sibling channel landing after curr_conn in hash +order, which is not something that can be triggered reliably. + +Fixes: 76e98a158b20 ("ksmbd: fix race condition between destroy_previous_session() and smb2 operations()") +Cc: stable@vger.kernel.org +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/connection.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/fs/smb/server/connection.c ++++ b/fs/smb/server/connection.c +@@ -237,7 +237,7 @@ int ksmbd_conn_wait_idle_sess_id(struct + { + struct ksmbd_conn *conn; + int rc, retry_count = 0, max_timeout = 120; +- int rcount = 1, bkt; ++ int rcount, bkt; + + retry_idle: + if (retry_count >= max_timeout) +@@ -246,8 +246,7 @@ retry_idle: + down_read(&conn_list_lock); + hash_for_each(conn_list, bkt, conn, hlist) { + if (conn->binding || xa_load(&conn->sessions, sess_id)) { +- if (conn == curr_conn) +- rcount = 2; ++ rcount = (conn == curr_conn) ? 2 : 1; + if (atomic_read(&conn->req_running) >= rcount) { + rc = wait_event_timeout(conn->req_running_q, + atomic_read(&conn->req_running) < rcount, diff --git a/queue-7.0/ksmbd-use-check_add_overflow-to-prevent-u16-dacl-size-overflow.patch b/queue-7.0/ksmbd-use-check_add_overflow-to-prevent-u16-dacl-size-overflow.patch new file mode 100644 index 0000000000..4cd3d4ec28 --- /dev/null +++ b/queue-7.0/ksmbd-use-check_add_overflow-to-prevent-u16-dacl-size-overflow.patch @@ -0,0 +1,86 @@ +From 299f962c0b02d048fb45d248b4da493d03f3175d Mon Sep 17 00:00:00 2001 +From: Tristan Madani +Date: Fri, 17 Apr 2026 19:54:57 +0000 +Subject: ksmbd: use check_add_overflow() to prevent u16 DACL size overflow + +From: Tristan Madani + +commit 299f962c0b02d048fb45d248b4da493d03f3175d upstream. + +set_posix_acl_entries_dacl() and set_ntacl_dacl() accumulate ACE sizes +in u16 variables. When a file has many POSIX ACL entries, the +accumulated size can wrap past 65535, causing the pointer arithmetic +(char *)pndace + *size to land within already-written ACEs. Subsequent +writes then overwrite earlier entries, and pndacl->size gets a +truncated value. + +Use check_add_overflow() at each accumulation point to detect the +wrap before it corrupts the buffer, consistent with existing +check_mul_overflow() usage elsewhere in smbacl.c. + +Cc: stable@vger.kernel.org +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Signed-off-by: Tristan Madani +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smbacl.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -596,6 +596,7 @@ static void set_posix_acl_entries_dacl(s + struct smb_sid *sid; + struct smb_ace *ntace; + int i, j; ++ u16 ace_sz; + + if (!fattr->cf_acls) + goto posix_default_acl; +@@ -640,8 +641,10 @@ static void set_posix_acl_entries_dacl(s + flags = 0x03; + + ntace = (struct smb_ace *)((char *)pndace + *size); +- *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, ++ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, + pace->e_perm, 0777); ++ if (check_add_overflow(*size, ace_sz, size)) ++ break; + (*num_aces)++; + if (pace->e_tag == ACL_USER) + ntace->access_req |= +@@ -650,8 +653,10 @@ static void set_posix_acl_entries_dacl(s + if (S_ISDIR(fattr->cf_mode) && + (pace->e_tag == ACL_USER || pace->e_tag == ACL_GROUP)) { + ntace = (struct smb_ace *)((char *)pndace + *size); +- *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, ++ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, + 0x03, pace->e_perm, 0777); ++ if (check_add_overflow(*size, ace_sz, size)) ++ break; + (*num_aces)++; + if (pace->e_tag == ACL_USER) + ntace->access_req |= +@@ -691,8 +696,10 @@ posix_default_acl: + } + + ntace = (struct smb_ace *)((char *)pndace + *size); +- *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, ++ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, + pace->e_perm, 0777); ++ if (check_add_overflow(*size, ace_sz, size)) ++ break; + (*num_aces)++; + if (pace->e_tag == ACL_USER) + ntace->access_req |= +@@ -728,7 +735,8 @@ static void set_ntacl_dacl(struct mnt_id + break; + + memcpy((char *)pndace + size, ntace, nt_ace_size); +- size += nt_ace_size; ++ if (check_add_overflow(size, nt_ace_size, &size)) ++ break; + aces_size -= nt_ace_size; + ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); + num_aces++; diff --git a/queue-7.0/ksmbd-validate-num_aces-and-harden-ace-walk-in-smb_inherit_dacl.patch b/queue-7.0/ksmbd-validate-num_aces-and-harden-ace-walk-in-smb_inherit_dacl.patch new file mode 100644 index 0000000000..f5b8fa7a51 --- /dev/null +++ b/queue-7.0/ksmbd-validate-num_aces-and-harden-ace-walk-in-smb_inherit_dacl.patch @@ -0,0 +1,139 @@ +From 3e4e2ea2a781018ed5d75f969e3e5606beb66e48 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Fri, 17 Apr 2026 14:45:57 -0400 +Subject: ksmbd: validate num_aces and harden ACE walk in smb_inherit_dacl() + +From: Michael Bommarito + +commit 3e4e2ea2a781018ed5d75f969e3e5606beb66e48 upstream. + +smb_inherit_dacl() trusts the on-disk num_aces value from the parent +directory's DACL xattr and uses it to size a heap allocation: + + aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, ...); + +num_aces is a u16 read from le16_to_cpu(parent_pdacl->num_aces) +without checking that it is consistent with the declared pdacl_size. +An authenticated client whose parent directory's security.NTACL is +tampered (e.g. via offline xattr corruption or a concurrent path that +bypasses parse_dacl()) can present num_aces = 65535 with minimal +actual ACE data. This causes a ~8 MB allocation (not kzalloc, so +uninitialized) that the subsequent loop only partially populates, and +may also overflow the three-way size_t multiply on 32-bit kernels. + +Additionally, the ACE walk loop uses the weaker +offsetof(struct smb_ace, access_req) minimum size check rather than +the minimum valid on-wire ACE size, and does not reject ACEs whose +declared size is below the minimum. + +Reproduced on UML + KASAN + LOCKDEP against the real ksmbd code path. +A legitimate mount.cifs client creates a parent directory over SMB +(ksmbd writes a valid security.NTACL xattr), then the NTACL blob on +the backing filesystem is rewritten to set num_aces = 0xFFFF while +keeping the posix_acl_hash bytes intact so ksmbd_vfs_get_sd_xattr()'s +hash check still passes. A subsequent SMB2 CREATE of a child under +that parent drives smb2_open() into smb_inherit_dacl() (share has +"vfs objects = acl_xattr" set), which fails the page allocator: + + WARNING: mm/page_alloc.c:5226 at __alloc_frozen_pages_noprof+0x46c/0x9c0 + Workqueue: ksmbd-io handle_ksmbd_work + __alloc_frozen_pages_noprof+0x46c/0x9c0 + ___kmalloc_large_node+0x68/0x130 + __kmalloc_large_node_noprof+0x24/0x70 + __kmalloc_noprof+0x4c9/0x690 + smb_inherit_dacl+0x394/0x2430 + smb2_open+0x595d/0xabe0 + handle_ksmbd_work+0x3d3/0x1140 + +With the patch applied the added guard rejects the tampered value +with -EINVAL before any large allocation runs, smb2_open() falls back +to smb2_create_sd_buffer(), and the child is created with a default +SD. No warning, no splat. + +Fix by: + + 1. Validating num_aces against pdacl_size using the same formula + applied in parse_dacl(). + + 2. Replacing the raw kmalloc(sizeof * num_aces * 2) with + kmalloc_array(num_aces * 2, sizeof(...)) for overflow-safe + allocation. + + 3. Tightening the per-ACE loop guard to require the minimum valid + ACE size (offsetof(smb_ace, sid) + CIFS_SID_BASE_SIZE) and + rejecting under-sized ACEs, matching the hardening in + smb_check_perm_dacl() and parse_dacl(). + +v1 -> v2: + - Replace the synthetic test-module splat in the changelog with a + real-path UML + KASAN reproduction driven through mount.cifs and + SMB2 CREATE; Namjae flagged the kcifs3_test_inherit_dacl_old name + in v1 since it does not exist in ksmbd. + - Drop the commit-hash citation from the code comment per Namjae's + review; keep the parse_dacl() pointer. + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smbacl.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -1106,8 +1106,24 @@ int smb_inherit_dacl(struct ksmbd_conn * + goto free_parent_pntsd; + } + +- aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, +- KSMBD_DEFAULT_GFP); ++ aces_size = pdacl_size - sizeof(struct smb_acl); ++ ++ /* ++ * Validate num_aces against the DACL payload before allocating. ++ * Each ACE must be at least as large as its fixed-size header ++ * (up to the SID base), so num_aces cannot exceed the payload ++ * divided by the minimum ACE size. This mirrors the existing ++ * check in parse_dacl(). ++ */ ++ if (num_aces > aces_size / (offsetof(struct smb_ace, sid) + ++ offsetof(struct smb_sid, sub_auth) + ++ sizeof(__le16))) { ++ rc = -EINVAL; ++ goto free_parent_pntsd; ++ } ++ ++ aces_base = kmalloc_array(num_aces * 2, sizeof(struct smb_ace), ++ KSMBD_DEFAULT_GFP); + if (!aces_base) { + rc = -ENOMEM; + goto free_parent_pntsd; +@@ -1116,7 +1132,6 @@ int smb_inherit_dacl(struct ksmbd_conn * + aces = (struct smb_ace *)aces_base; + parent_aces = (struct smb_ace *)((char *)parent_pdacl + + sizeof(struct smb_acl)); +- aces_size = acl_len - sizeof(struct smb_acl); + + if (pntsd_type & DACL_AUTO_INHERITED) + inherited_flags = INHERITED_ACE; +@@ -1124,11 +1139,14 @@ int smb_inherit_dacl(struct ksmbd_conn * + for (i = 0; i < num_aces; i++) { + int pace_size; + +- if (offsetof(struct smb_ace, access_req) > aces_size) ++ if (aces_size < offsetof(struct smb_ace, sid) + ++ CIFS_SID_BASE_SIZE) + break; + + pace_size = le16_to_cpu(parent_aces->size); +- if (pace_size > aces_size) ++ if (pace_size > aces_size || ++ pace_size < offsetof(struct smb_ace, sid) + ++ CIFS_SID_BASE_SIZE) + break; + + aces_size -= pace_size; diff --git a/queue-7.0/ksmbd-validate-response-sizes-in-ipc_validate_msg.patch b/queue-7.0/ksmbd-validate-response-sizes-in-ipc_validate_msg.patch new file mode 100644 index 0000000000..eea7523f7f --- /dev/null +++ b/queue-7.0/ksmbd-validate-response-sizes-in-ipc_validate_msg.patch @@ -0,0 +1,122 @@ +From d6a6aa81eac2c9bff66dc6e191179cb69a14426b Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Wed, 15 Apr 2026 07:25:00 -0400 +Subject: ksmbd: validate response sizes in ipc_validate_msg() + +From: Michael Bommarito + +commit d6a6aa81eac2c9bff66dc6e191179cb69a14426b upstream. + +ipc_validate_msg() computes the expected message size for each +response type by adding (or multiplying) attacker-controlled fields +from the daemon response to a fixed struct size in unsigned int +arithmetic. Three cases can overflow: + + KSMBD_EVENT_RPC_REQUEST: + msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; + KSMBD_EVENT_SHARE_CONFIG_REQUEST: + msg_sz = sizeof(struct ksmbd_share_config_response) + + resp->payload_sz; + KSMBD_EVENT_LOGIN_REQUEST_EXT: + msg_sz = sizeof(struct ksmbd_login_response_ext) + + resp->ngroups * sizeof(gid_t); + +resp->payload_sz is __u32 and resp->ngroups is __s32. Each addition +can wrap in unsigned int; the multiplication by sizeof(gid_t) mixes +signed and size_t, so a negative ngroups is converted to SIZE_MAX +before the multiply. A wrapped value of msg_sz that happens to +equal entry->msg_sz bypasses the size check on the next line, and +downstream consumers (smb2pdu.c:6742 memcpy using rpc_resp->payload_sz, +kmemdup in ksmbd_alloc_user using resp_ext->ngroups) then trust the +unverified length. + +Use check_add_overflow() on the RPC_REQUEST and SHARE_CONFIG_REQUEST +paths to detect integer overflow without constraining functional +payload size; userspace ksmbd-tools grows NDR responses in 4096-byte +chunks for calls like NetShareEnumAll, so a hard transport cap is +unworkable on the response side. For LOGIN_REQUEST_EXT, reject +resp->ngroups outside the signed [0, NGROUPS_MAX] range up front and +report the error from ipc_validate_msg() so it fires at the IPC +boundary; with that bound the subsequent multiplication and addition +stay well below UINT_MAX. The now-redundant ngroups check and +pr_err in ksmbd_alloc_user() are removed. + +This is the response-side analogue of aab98e2dbd64 ("ksmbd: fix +integer overflows on 32 bit systems"), which hardened the request +side. + +Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers") +Fixes: a77e0e02af1c ("ksmbd: add support for supplementary groups") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Michael Bommarito +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/mgmt/user_config.c | 6 ------ + fs/smb/server/transport_ipc.c | 16 +++++++++++++--- + 2 files changed, 13 insertions(+), 9 deletions(-) + +--- a/fs/smb/server/mgmt/user_config.c ++++ b/fs/smb/server/mgmt/user_config.c +@@ -56,12 +56,6 @@ struct ksmbd_user *ksmbd_alloc_user(stru + goto err_free; + + if (resp_ext) { +- if (resp_ext->ngroups > NGROUPS_MAX) { +- pr_err("ngroups(%u) from login response exceeds max groups(%d)\n", +- resp_ext->ngroups, NGROUPS_MAX); +- goto err_free; +- } +- + user->sgid = kmemdup(resp_ext->____payload, + resp_ext->ngroups * sizeof(gid_t), + KSMBD_DEFAULT_GFP); +--- a/fs/smb/server/transport_ipc.c ++++ b/fs/smb/server/transport_ipc.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "vfs_cache.h" + #include "transport_ipc.h" +@@ -497,7 +498,9 @@ static int ipc_validate_msg(struct ipc_m + { + struct ksmbd_rpc_command *resp = entry->response; + +- msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; ++ if (check_add_overflow(sizeof(struct ksmbd_rpc_command), ++ resp->payload_sz, &msg_sz)) ++ return -EINVAL; + break; + } + case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST: +@@ -516,8 +519,9 @@ static int ipc_validate_msg(struct ipc_m + if (resp->payload_sz < resp->veto_list_sz) + return -EINVAL; + +- msg_sz = sizeof(struct ksmbd_share_config_response) + +- resp->payload_sz; ++ if (check_add_overflow(sizeof(struct ksmbd_share_config_response), ++ resp->payload_sz, &msg_sz)) ++ return -EINVAL; + } + break; + } +@@ -526,6 +530,12 @@ static int ipc_validate_msg(struct ipc_m + struct ksmbd_login_response_ext *resp = entry->response; + + if (resp->ngroups) { ++ if (resp->ngroups < 0 || ++ resp->ngroups > NGROUPS_MAX) { ++ pr_err("ngroups(%d) from login response exceeds max groups(%d)\n", ++ resp->ngroups, NGROUPS_MAX); ++ return -EINVAL; ++ } + msg_sz = sizeof(struct ksmbd_login_response_ext) + + resp->ngroups * sizeof(gid_t); + } diff --git a/queue-7.0/mshv_vtl-fix-vmemmap_shift-exceeding-max_folio_order.patch b/queue-7.0/mshv_vtl-fix-vmemmap_shift-exceeding-max_folio_order.patch new file mode 100644 index 0000000000..4541e122db --- /dev/null +++ b/queue-7.0/mshv_vtl-fix-vmemmap_shift-exceeding-max_folio_order.patch @@ -0,0 +1,100 @@ +From 404cd6bffe17e25e0f94ed2775ffdd6cd10ac3fd Mon Sep 17 00:00:00 2001 +From: Naman Jain +Date: Mon, 6 Apr 2026 09:24:59 +0000 +Subject: mshv_vtl: Fix vmemmap_shift exceeding MAX_FOLIO_ORDER + +From: Naman Jain + +commit 404cd6bffe17e25e0f94ed2775ffdd6cd10ac3fd upstream. + +When registering VTL0 memory via MSHV_ADD_VTL0_MEMORY, the kernel +computes pgmap->vmemmap_shift as the number of trailing zeros in the +OR of start_pfn and last_pfn, intending to use the largest compound +page order both endpoints are aligned to. + +However, this value is not clamped to MAX_FOLIO_ORDER, so a +sufficiently aligned range (e.g. physical range +[0x800000000000, 0x800080000000), corresponding to start_pfn=0x800000000 +with 35 trailing zeros) can produce a shift larger than what +memremap_pages() accepts, triggering a WARN and returning -EINVAL: + + WARNING: ... memremap_pages+0x512/0x650 + requested folio size unsupported + +The MAX_FOLIO_ORDER check was added by +commit 646b67d57589 ("mm/memremap: reject unreasonable folio/compound +page sizes in memremap_pages()"). + +Fix this by clamping vmemmap_shift to MAX_FOLIO_ORDER so we always +request the largest order the kernel supports, in those cases, rather +than an out-of-range value. + +Also fix the error path to propagate the actual error code from +devm_memremap_pages() instead of hard-coding -EFAULT, which was +masking the real -EINVAL return. + +Fixes: 7bfe3b8ea6e3 ("Drivers: hv: Introduce mshv_vtl driver") +Cc: stable@vger.kernel.org +Signed-off-by: Naman Jain +Reviewed-by: Michael Kelley +Signed-off-by: Wei Liu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hv/mshv_vtl_main.c | 12 +++++++++--- + include/uapi/linux/mshv.h | 2 +- + 2 files changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/hv/mshv_vtl_main.c ++++ b/drivers/hv/mshv_vtl_main.c +@@ -386,7 +386,6 @@ static int mshv_vtl_ioctl_add_vtl0_mem(s + + if (copy_from_user(&vtl0_mem, arg, sizeof(vtl0_mem))) + return -EFAULT; +- /* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design */ + if (vtl0_mem.last_pfn <= vtl0_mem.start_pfn) { + dev_err(vtl->module_dev, "range start pfn (%llx) > end pfn (%llx)\n", + vtl0_mem.start_pfn, vtl0_mem.last_pfn); +@@ -397,6 +396,10 @@ static int mshv_vtl_ioctl_add_vtl0_mem(s + if (!pgmap) + return -ENOMEM; + ++ /* ++ * vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design. ++ * last_pfn is not reserved or wasted, and reflects 'start_pfn + size' of pagemap range. ++ */ + pgmap->ranges[0].start = PFN_PHYS(vtl0_mem.start_pfn); + pgmap->ranges[0].end = PFN_PHYS(vtl0_mem.last_pfn) - 1; + pgmap->nr_range = 1; +@@ -405,8 +408,11 @@ static int mshv_vtl_ioctl_add_vtl0_mem(s + /* + * Determine the highest page order that can be used for the given memory range. + * This works best when the range is aligned; i.e. both the start and the length. ++ * Clamp to MAX_FOLIO_ORDER to avoid a WARN in memremap_pages() when the range ++ * alignment exceeds the maximum supported folio order for this kernel config. + */ +- pgmap->vmemmap_shift = count_trailing_zeros(vtl0_mem.start_pfn | vtl0_mem.last_pfn); ++ pgmap->vmemmap_shift = min(count_trailing_zeros(vtl0_mem.start_pfn | vtl0_mem.last_pfn), ++ MAX_FOLIO_ORDER); + dev_dbg(vtl->module_dev, + "Add VTL0 memory: start: 0x%llx, end_pfn: 0x%llx, page order: %lu\n", + vtl0_mem.start_pfn, vtl0_mem.last_pfn, pgmap->vmemmap_shift); +@@ -415,7 +421,7 @@ static int mshv_vtl_ioctl_add_vtl0_mem(s + if (IS_ERR(addr)) { + dev_err(vtl->module_dev, "devm_memremap_pages error: %ld\n", PTR_ERR(addr)); + kfree(pgmap); +- return -EFAULT; ++ return PTR_ERR(addr); + } + + /* Don't free pgmap, since it has to stick around until the memory +--- a/include/uapi/linux/mshv.h ++++ b/include/uapi/linux/mshv.h +@@ -357,7 +357,7 @@ struct mshv_vtl_sint_post_msg { + + struct mshv_vtl_ram_disposition { + __u64 start_pfn; +- __u64 last_pfn; ++ __u64 last_pfn; /* last_pfn is excluded from the range [start_pfn, last_pfn) */ + }; + + struct mshv_vtl_set_poll_file { diff --git a/queue-7.0/net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch b/queue-7.0/net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch new file mode 100644 index 0000000000..3f4908fc32 --- /dev/null +++ b/queue-7.0/net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch @@ -0,0 +1,89 @@ +From 2c054e17d9d41f1020376806c7f750834ced4dc5 Mon Sep 17 00:00:00 2001 +From: Bingquan Chen +Date: Sat, 18 Apr 2026 19:20:06 +0800 +Subject: net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd() + +From: Bingquan Chen + +commit 2c054e17d9d41f1020376806c7f750834ced4dc5 upstream. + +In tpacket_snd(), when PACKET_VNET_HDR is enabled, vnet_hdr points +directly into the mmap'd TX ring buffer shared with userspace. The +kernel validates the header via __packet_snd_vnet_parse() but then +re-reads all fields later in virtio_net_hdr_to_skb(). A concurrent +userspace thread can modify the vnet_hdr fields between validation +and use, bypassing all safety checks. + +The non-TPACKET path (packet_snd()) already correctly copies vnet_hdr +to a stack-local variable. All other vnet_hdr consumers in the kernel +(tun.c, tap.c, virtio_net.c) also use stack copies. The TPACKET TX +path is the only caller of virtio_net_hdr_to_skb() that reads directly +from user-controlled shared memory. + +Fix this by copying vnet_hdr from the mmap'd ring buffer to a +stack-local variable before validation and use, consistent with the +approach used in packet_snd() and all other callers. + +Fixes: 1d036d25e560 ("packet: tpacket_snd gso and checksum offload") +Signed-off-by: Bingquan Chen +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260418112006.78823-1-patzilla007@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/packet/af_packet.c | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -2717,7 +2717,8 @@ static int tpacket_snd(struct packet_soc + { + struct sk_buff *skb = NULL; + struct net_device *dev; +- struct virtio_net_hdr *vnet_hdr = NULL; ++ struct virtio_net_hdr vnet_hdr; ++ bool has_vnet_hdr = false; + struct sockcm_cookie sockc; + __be16 proto; + int err, reserve = 0; +@@ -2818,16 +2819,20 @@ static int tpacket_snd(struct packet_soc + hlen = LL_RESERVED_SPACE(dev); + tlen = dev->needed_tailroom; + if (vnet_hdr_sz) { +- vnet_hdr = data; + data += vnet_hdr_sz; + tp_len -= vnet_hdr_sz; +- if (tp_len < 0 || +- __packet_snd_vnet_parse(vnet_hdr, tp_len)) { ++ if (tp_len < 0) { ++ tp_len = -EINVAL; ++ goto tpacket_error; ++ } ++ memcpy(&vnet_hdr, data - vnet_hdr_sz, sizeof(vnet_hdr)); ++ if (__packet_snd_vnet_parse(&vnet_hdr, tp_len)) { + tp_len = -EINVAL; + goto tpacket_error; + } + copylen = __virtio16_to_cpu(vio_le(), +- vnet_hdr->hdr_len); ++ vnet_hdr.hdr_len); ++ has_vnet_hdr = true; + } + copylen = max_t(int, copylen, dev->hard_header_len); + skb = sock_alloc_send_skb(&po->sk, +@@ -2864,12 +2869,12 @@ tpacket_error: + } + } + +- if (vnet_hdr_sz) { +- if (virtio_net_hdr_to_skb(skb, vnet_hdr, vio_le())) { ++ if (has_vnet_hdr) { ++ if (virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le())) { + tp_len = -EINVAL; + goto tpacket_error; + } +- virtio_net_hdr_set_proto(skb, vnet_hdr); ++ virtio_net_hdr_set_proto(skb, &vnet_hdr); + } + + skb->destructor = tpacket_destruct_skb; diff --git a/queue-7.0/rxrpc-fix-missing-validation-of-ticket-length-in-non-xdr-key-preparsing.patch b/queue-7.0/rxrpc-fix-missing-validation-of-ticket-length-in-non-xdr-key-preparsing.patch new file mode 100644 index 0000000000..2e9b0b7f86 --- /dev/null +++ b/queue-7.0/rxrpc-fix-missing-validation-of-ticket-length-in-non-xdr-key-preparsing.patch @@ -0,0 +1,56 @@ +From ac33733b10b484d666f97688561670afd5861383 Mon Sep 17 00:00:00 2001 +From: Anderson Nascimento +Date: Wed, 22 Apr 2026 17:14:35 +0100 +Subject: rxrpc: Fix missing validation of ticket length in non-XDR key preparsing + +From: Anderson Nascimento + +commit ac33733b10b484d666f97688561670afd5861383 upstream. + +In rxrpc_preparse(), there are two paths for parsing key payloads: the +XDR path (for large payloads) and the non-XDR path (for payloads <= 28 +bytes). While the XDR path (rxrpc_preparse_xdr_rxkad()) correctly +validates the ticket length against AFSTOKEN_RK_TIX_MAX, the non-XDR +path fails to do so. + +This allows an unprivileged user to provide a very large ticket length. +When this key is later read via rxrpc_read(), the total +token size (toksize) calculation results in a value that exceeds +AFSTOKEN_LENGTH_MAX, triggering a WARN_ON(). + +[ 2001.302904] WARNING: CPU: 2 PID: 2108 at net/rxrpc/key.c:778 rxrpc_read+0x109/0x5c0 [rxrpc] + +Fix this by adding a check in the non-XDR parsing path of rxrpc_preparse() +to ensure the ticket length does not exceed AFSTOKEN_RK_TIX_MAX, +bringing it into parity with the XDR parsing logic. + +Fixes: 8a7a3eb4ddbe ("KEYS: RxRPC: Use key preparsing") +Fixes: 84924aac08a4 ("rxrpc: Fix checker warning") +Reported-by: Anderson Nascimento +Signed-off-by: Anderson Nascimento +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260422161438.2593376-7-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/key.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/net/rxrpc/key.c ++++ b/net/rxrpc/key.c +@@ -502,6 +502,10 @@ static int rxrpc_preparse(struct key_pre + if (v1->security_index != RXRPC_SECURITY_RXKAD) + goto error; + ++ ret = -EKEYREJECTED; ++ if (v1->ticket_length > AFSTOKEN_RK_TIX_MAX) ++ goto error; ++ + plen = sizeof(*token->kad) + v1->ticket_length; + prep->quotalen += plen + sizeof(*token); + diff --git a/queue-7.0/series b/queue-7.0/series index 59e09276fe..6286349c34 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -7,3 +7,36 @@ ksmbd-fix-use-after-free-in-__ksmbd_close_fd-via-durable-scavenger.patch ksmbd-validate-owner-of-durable-handle-on-reconnect.patch scripts-generate_rust_analyzer.py-define-scripts.patch scripts-dtc-remove-unused-dts_version-in-dtc-lexer.l.patch +fs-ntfs3-validate-rec-used-in-journal-replay-file-record-check.patch +f2fs-fix-to-do-sanity-check-on-dcc-discard_cmd_cnt-conditionally.patch +f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch +f2fs-fix-to-avoid-memory-leak-in-f2fs_rename.patch +f2fs-fix-to-avoid-uninit-value-access-in-f2fs_sanity_check_node_footer.patch +fuse-reject-oversized-dirents-in-page-cache.patch +fuse-abort-on-fatal-signal-during-sync-init.patch +fuse-check-for-large-folio-with-splice_f_move.patch +fuse-quiet-down-complaints-in-fuse_conn_limit_write.patch +fuse-fuse_dev_ioctl_clone-should-wait-for-device-file-to-be-initialized.patch +ksmbd-require-minimum-ace-size-in-smb_check_perm_dacl.patch +smb-server-fix-active_num_conn-leak-on-transport-allocation-failure.patch +smb-client-fix-dir-separator-in-smb1-unix-mounts.patch +smb-server-fix-max_connections-off-by-one-in-tcp-accept-path.patch +smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch +smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch +smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch +ksmbd-validate-response-sizes-in-ipc_validate_msg.patch +ksmbd-validate-num_aces-and-harden-ace-walk-in-smb_inherit_dacl.patch +ksmbd-fix-out-of-bounds-write-in-smb2_get_ea-ea-alignment.patch +ksmbd-use-check_add_overflow-to-prevent-u16-dacl-size-overflow.patch +ksmbd-reset-rcount-per-connection-in-ksmbd_conn_wait_idle_sess_id.patch +writeback-fix-use-after-free-in-inode_switch_wbs_work_fn.patch +f2fs-fix-use-after-free-of-sbi-in-f2fs_compress_write_end_io.patch +alsa-usb-audio-apply-quirk-for-moondrop-ju-jiu.patch +alsa-hda-realtek-add-quirk-for-legion-s7-15imh.patch +alsa-caiaq-take-a-reference-on-the-usb-device-in-create_card.patch +net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch +crypto-ccp-don-t-attempt-to-copy-csr-to-userspace-if-psp-command-failed.patch +crypto-ccp-don-t-attempt-to-copy-pdh-cert-to-userspace-if-psp-command-failed.patch +crypto-ccp-don-t-attempt-to-copy-id-to-userspace-if-psp-command-failed.patch +rxrpc-fix-missing-validation-of-ticket-length-in-non-xdr-key-preparsing.patch +mshv_vtl-fix-vmemmap_shift-exceeding-max_folio_order.patch diff --git a/queue-7.0/smb-client-fix-dir-separator-in-smb1-unix-mounts.patch b/queue-7.0/smb-client-fix-dir-separator-in-smb1-unix-mounts.patch new file mode 100644 index 0000000000..628c9b0394 --- /dev/null +++ b/queue-7.0/smb-client-fix-dir-separator-in-smb1-unix-mounts.patch @@ -0,0 +1,119 @@ +From c4d3fc5844d685441befd0caaab648321013cdfd Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Thu, 16 Apr 2026 21:15:50 -0300 +Subject: smb: client: fix dir separator in SMB1 UNIX mounts + +From: Paulo Alcantara + +commit c4d3fc5844d685441befd0caaab648321013cdfd upstream. + +When calling cifs_mount_get_tcon() with SMB1 UNIX mounts, +@cifs_sb->mnt_cifs_flags needs to be read or updated only after +calling reset_cifs_unix_caps(), otherwise it might end up with missing +CIFS_MOUNT_POSIXACL and CIFS_MOUNT_POSIX_PATHS bits. + +This fixes the wrong dir separator used in paths caused by the missing +CIFS_MOUNT_POSIX_PATHS bit in cifs_sb_info::mnt_cifs_flags. + +Reported-by: "Kris Karas (Bug Reporting)" +Closes: https://lore.kernel.org/r/f758f4ff-4d54-4244-931d-38f469c3ff14@moonlit-rail.com +Fixes: 4fc3a433c139 ("smb: client: use atomic_t for mnt_cifs_flags") +Signed-off-by: Paulo Alcantara (Red Hat) +Cc: David Howells +Cc: linux-cifs@vger.kernel.org +Cc: stable@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/connect.c | 10 +++++----- + fs/smb/client/smb1ops.c | 19 ++++++++----------- + 2 files changed, 13 insertions(+), 16 deletions(-) + +--- a/fs/smb/client/connect.c ++++ b/fs/smb/client/connect.c +@@ -3610,7 +3610,6 @@ int cifs_mount_get_tcon(struct cifs_moun + server = mnt_ctx->server; + ctx = mnt_ctx->fs_ctx; + cifs_sb = mnt_ctx->cifs_sb; +- sbflags = cifs_sb_flags(cifs_sb); + + /* search for existing tcon to this server share */ + tcon = cifs_get_tcon(mnt_ctx->ses, ctx); +@@ -3625,9 +3624,10 @@ int cifs_mount_get_tcon(struct cifs_moun + * path (i.e., do not remap / and \ and do not map any special characters) + */ + if (tcon->posix_extensions) { +- sbflags |= CIFS_MOUNT_POSIX_PATHS; +- sbflags &= ~(CIFS_MOUNT_MAP_SFM_CHR | +- CIFS_MOUNT_MAP_SPECIAL_CHR); ++ atomic_or(CIFS_MOUNT_POSIX_PATHS, &cifs_sb->mnt_cifs_flags); ++ atomic_andnot(CIFS_MOUNT_MAP_SFM_CHR | ++ CIFS_MOUNT_MAP_SPECIAL_CHR, ++ &cifs_sb->mnt_cifs_flags); + } + + #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY +@@ -3651,6 +3651,7 @@ int cifs_mount_get_tcon(struct cifs_moun + #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ + tcon->unix_ext = 0; /* server does not support them */ + ++ sbflags = cifs_sb_flags(cifs_sb); + /* do not care if a following call succeed - informational */ + if (!tcon->pipe && server->ops->qfs_tcon) { + server->ops->qfs_tcon(mnt_ctx->xid, tcon, cifs_sb); +@@ -3675,7 +3676,6 @@ int cifs_mount_get_tcon(struct cifs_moun + + out: + mnt_ctx->tcon = tcon; +- atomic_set(&cifs_sb->mnt_cifs_flags, sbflags); + return rc; + } + +--- a/fs/smb/client/smb1ops.c ++++ b/fs/smb/client/smb1ops.c +@@ -49,7 +49,6 @@ void reset_cifs_unix_caps(unsigned int x + + if (!CIFSSMBQFSUnixInfo(xid, tcon)) { + __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); +- unsigned int sbflags; + + cifs_dbg(FYI, "unix caps which server supports %lld\n", cap); + /* +@@ -76,29 +75,27 @@ void reset_cifs_unix_caps(unsigned int x + if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) + cifs_dbg(VFS, "per-share encryption not supported yet\n"); + +- if (cifs_sb) +- sbflags = cifs_sb_flags(cifs_sb); +- + cap &= CIFS_UNIX_CAP_MASK; + if (ctx && ctx->no_psx_acl) + cap &= ~CIFS_UNIX_POSIX_ACL_CAP; + else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { + cifs_dbg(FYI, "negotiated posix acl support\n"); +- if (cifs_sb) +- sbflags |= CIFS_MOUNT_POSIXACL; ++ if (cifs_sb) { ++ atomic_or(CIFS_MOUNT_POSIXACL, ++ &cifs_sb->mnt_cifs_flags); ++ } + } + + if (ctx && ctx->posix_paths == 0) + cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; + else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { + cifs_dbg(FYI, "negotiate posix pathnames\n"); +- if (cifs_sb) +- sbflags |= CIFS_MOUNT_POSIX_PATHS; ++ if (cifs_sb) { ++ atomic_or(CIFS_MOUNT_POSIX_PATHS, ++ &cifs_sb->mnt_cifs_flags); ++ } + } + +- if (cifs_sb) +- atomic_set(&cifs_sb->mnt_cifs_flags, sbflags); +- + cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap); + #ifdef CONFIG_CIFS_DEBUG2 + if (cap & CIFS_UNIX_FCNTL_CAP) diff --git a/queue-7.0/smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch b/queue-7.0/smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch new file mode 100644 index 0000000000..f3efa38b95 --- /dev/null +++ b/queue-7.0/smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch @@ -0,0 +1,51 @@ +From a58c5af19ff0d6f44f6e9fe31e33a2c92223f77e Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 19 Apr 2026 19:35:19 -0400 +Subject: smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path + +From: Michael Bommarito + +commit a58c5af19ff0d6f44f6e9fe31e33a2c92223f77e upstream. + +smb2_ioctl_query_info() has two response-copy branches: PASSTHRU_FSCTL +and the default QUERY_INFO path. The QUERY_INFO branch clamps +qi.input_buffer_length to the server-reported OutputBufferLength and then +copies qi.input_buffer_length bytes from qi_rsp->Buffer to userspace, but +it never verifies that the flexible-array payload actually fits within +rsp_iov[1].iov_len. + +A malicious server can return OutputBufferLength larger than the actual +QUERY_INFO response, causing copy_to_user() to walk past the response +buffer and expose adjacent kernel heap to userspace. + +Guard the QUERY_INFO copy with a bounds check on the actual Buffer +payload. Use struct_size(qi_rsp, Buffer, qi.input_buffer_length) +rather than an open-coded addition so the guard cannot overflow on +32-bit builds. + +Fixes: f5778c398713 ("SMB3: Allow SMB3 FSCTL queries to be sent to server from tools") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/smb2ops.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -1783,6 +1783,12 @@ replay_again: + qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; + if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length) + qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength); ++ if (qi.input_buffer_length > 0 && ++ struct_size(qi_rsp, Buffer, qi.input_buffer_length) > ++ rsp_iov[1].iov_len) { ++ rc = -EFAULT; ++ goto out; ++ } + if (copy_to_user(&pqi->input_buffer_length, + &qi.input_buffer_length, + sizeof(qi.input_buffer_length))) { diff --git a/queue-7.0/smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch b/queue-7.0/smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch new file mode 100644 index 0000000000..7ebcb16c85 --- /dev/null +++ b/queue-7.0/smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch @@ -0,0 +1,42 @@ +From 2757ad3e4b6f9e0fed4c7739594e702abc5cab21 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Mon, 20 Apr 2026 09:50:58 -0400 +Subject: smb: client: require a full NFS mode SID before reading mode bits + +From: Michael Bommarito + +commit 2757ad3e4b6f9e0fed4c7739594e702abc5cab21 upstream. + +parse_dacl() treats an ACE SID matching sid_unix_NFS_mode as an NFS +mode SID and reads sid.sub_auth[2] to recover the mode bits. + +That assumes the ACE carries three subauthorities, but compare_sids() +only compares min(a, b) subauthorities. A malicious server can return +an ACE with num_subauth = 2 and sub_auth[] = {88, 3}, which still +matches sid_unix_NFS_mode and then drives the sub_auth[2] read four +bytes past the end of the ACE. + +Require num_subauth >= 3 before treating the ACE as an NFS mode SID. +This keeps the fix local to the special-SID mode path without changing +compare_sids() semantics for the rest of cifsacl. + +Fixes: e2f8fbfb8d09 ("cifs: get mode bits from special sid on stat") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/cifsacl.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/smb/client/cifsacl.c ++++ b/fs/smb/client/cifsacl.c +@@ -831,6 +831,7 @@ static void parse_dacl(struct smb_acl *p + dump_ace(ppace[i], end_of_acl); + #endif + if (mode_from_special_sid && ++ ppace[i]->sid.num_subauth >= 3 && + (compare_sids(&(ppace[i]->sid), + &sid_unix_NFS_mode) == 0)) { + /* diff --git a/queue-7.0/smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch b/queue-7.0/smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch new file mode 100644 index 0000000000..68fa2710eb --- /dev/null +++ b/queue-7.0/smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch @@ -0,0 +1,223 @@ +From 0a8cf165566ba55a39fd0f4de172119dd646d39a Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 19 Apr 2026 20:11:31 -0400 +Subject: smb: client: validate the whole DACL before rewriting it in cifsacl + +From: Michael Bommarito + +commit 0a8cf165566ba55a39fd0f4de172119dd646d39a upstream. + +build_sec_desc() and id_mode_to_cifs_acl() derive a DACL pointer from a +server-supplied dacloffset and then use the incoming ACL to rebuild the +chmod/chown security descriptor. + +The original fix only checked that the struct smb_acl header fits before +reading dacl_ptr->size or dacl_ptr->num_aces. That avoids the immediate +header-field OOB read, but the rewrite helpers still walk ACEs based on +pdacl->num_aces with no structural validation of the incoming DACL body. + +A malicious server can return a truncated DACL that still contains a +header, claims one or more ACEs, and then drive +replace_sids_and_copy_aces() or set_chmod_dacl() past the validated +extent while they compare or copy attacker-controlled ACEs. + +Factor the DACL structural checks into validate_dacl(), extend them to +validate each ACE against the DACL bounds, and use the shared validator +before the chmod/chown rebuild paths. parse_dacl() reuses the same +validator so the read-side parser and write-side rewrite paths agree on +what constitutes a well-formed incoming DACL. + +Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Michael Bommarito +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/cifsacl.c | 116 +++++++++++++++++++++++++++++++++++------------- + 1 file changed, 85 insertions(+), 31 deletions(-) + +--- a/fs/smb/client/cifsacl.c ++++ b/fs/smb/client/cifsacl.c +@@ -758,6 +758,77 @@ static void dump_ace(struct smb_ace *pac + } + #endif + ++static int validate_dacl(struct smb_acl *pdacl, char *end_of_acl) ++{ ++ int i, ace_hdr_size, ace_size, min_ace_size; ++ u16 dacl_size, num_aces; ++ char *acl_base, *end_of_dacl; ++ struct smb_ace *pace; ++ ++ if (!pdacl) ++ return 0; ++ ++ if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl)) { ++ cifs_dbg(VFS, "ACL too small to parse DACL\n"); ++ return -EINVAL; ++ } ++ ++ dacl_size = le16_to_cpu(pdacl->size); ++ if (dacl_size < sizeof(struct smb_acl) || ++ end_of_acl < (char *)pdacl + dacl_size) { ++ cifs_dbg(VFS, "ACL too small to parse DACL\n"); ++ return -EINVAL; ++ } ++ ++ num_aces = le16_to_cpu(pdacl->num_aces); ++ if (!num_aces) ++ return 0; ++ ++ ace_hdr_size = offsetof(struct smb_ace, sid) + ++ offsetof(struct smb_sid, sub_auth); ++ min_ace_size = ace_hdr_size + sizeof(__le32); ++ if (num_aces > (dacl_size - sizeof(struct smb_acl)) / min_ace_size) { ++ cifs_dbg(VFS, "ACL too small to parse DACL\n"); ++ return -EINVAL; ++ } ++ ++ end_of_dacl = (char *)pdacl + dacl_size; ++ acl_base = (char *)pdacl; ++ ace_size = sizeof(struct smb_acl); ++ ++ for (i = 0; i < num_aces; ++i) { ++ if (end_of_dacl - acl_base < ace_size) { ++ cifs_dbg(VFS, "ACL too small to parse ACE\n"); ++ return -EINVAL; ++ } ++ ++ pace = (struct smb_ace *)(acl_base + ace_size); ++ acl_base = (char *)pace; ++ ++ if (end_of_dacl - acl_base < ace_hdr_size || ++ pace->sid.num_subauth == 0 || ++ pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) { ++ cifs_dbg(VFS, "ACL too small to parse ACE\n"); ++ return -EINVAL; ++ } ++ ++ ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth; ++ if (end_of_dacl - acl_base < ace_size || ++ le16_to_cpu(pace->size) < ace_size) { ++ cifs_dbg(VFS, "ACL too small to parse ACE\n"); ++ return -EINVAL; ++ } ++ ++ ace_size = le16_to_cpu(pace->size); ++ if (end_of_dacl - acl_base < ace_size) { ++ cifs_dbg(VFS, "ACL too small to parse ACE\n"); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ + static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, + struct smb_sid *pownersid, struct smb_sid *pgrpsid, + struct cifs_fattr *fattr, bool mode_from_special_sid) +@@ -765,7 +836,7 @@ static void parse_dacl(struct smb_acl *p + int i; + u16 num_aces = 0; + int acl_size; +- char *acl_base; ++ char *acl_base, *end_of_dacl; + struct smb_ace **ppace; + + /* BB need to add parm so we can store the SID BB */ +@@ -777,12 +848,8 @@ static void parse_dacl(struct smb_acl *p + return; + } + +- /* validate that we do not go past end of acl */ +- if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) || +- end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { +- cifs_dbg(VFS, "ACL too small to parse DACL\n"); ++ if (validate_dacl(pdacl, end_of_acl)) + return; +- } + + cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n", + le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), +@@ -793,6 +860,7 @@ static void parse_dacl(struct smb_acl *p + user/group/other have no permissions */ + fattr->cf_mode &= ~(0777); + ++ end_of_dacl = (char *)pdacl + le16_to_cpu(pdacl->size); + acl_base = (char *)pdacl; + acl_size = sizeof(struct smb_acl); + +@@ -800,35 +868,15 @@ static void parse_dacl(struct smb_acl *p + if (num_aces > 0) { + umode_t denied_mode = 0; + +- if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) / +- (offsetof(struct smb_ace, sid) + +- offsetof(struct smb_sid, sub_auth) + sizeof(__le16))) +- return; +- + ppace = kmalloc_objs(struct smb_ace *, num_aces); + if (!ppace) + return; + + for (i = 0; i < num_aces; ++i) { +- if (end_of_acl - acl_base < acl_size) +- break; +- + ppace[i] = (struct smb_ace *) (acl_base + acl_size); +- acl_base = (char *)ppace[i]; +- acl_size = offsetof(struct smb_ace, sid) + +- offsetof(struct smb_sid, sub_auth); +- +- if (end_of_acl - acl_base < acl_size || +- ppace[i]->sid.num_subauth == 0 || +- ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || +- (end_of_acl - acl_base < +- acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || +- (le16_to_cpu(ppace[i]->size) < +- acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) +- break; + + #ifdef CONFIG_CIFS_DEBUG2 +- dump_ace(ppace[i], end_of_acl); ++ dump_ace(ppace[i], end_of_dacl); + #endif + if (mode_from_special_sid && + ppace[i]->sid.num_subauth >= 3 && +@@ -871,6 +919,7 @@ static void parse_dacl(struct smb_acl *p + (void *)ppace[i], + sizeof(struct smb_ace)); */ + ++ acl_base = (char *)ppace[i]; + acl_size = le16_to_cpu(ppace[i]->size); + } + +@@ -1294,10 +1343,9 @@ static int build_sec_desc(struct smb_nts + dacloffset = le32_to_cpu(pntsd->dacloffset); + if (dacloffset) { + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); +- if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) { +- cifs_dbg(VFS, "Server returned illegal ACL size\n"); +- return -EINVAL; +- } ++ rc = validate_dacl(dacl_ptr, end_of_acl); ++ if (rc) ++ return rc; + } + + owner_sid_ptr = (struct smb_sid *)((char *)pntsd + +@@ -1663,6 +1711,12 @@ id_mode_to_cifs_acl(struct inode *inode, + dacloffset = le32_to_cpu(pntsd->dacloffset); + if (dacloffset) { + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); ++ rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen); ++ if (rc) { ++ kfree(pntsd); ++ cifs_put_tlink(tlink); ++ return rc; ++ } + if (mode_from_sid) + nsecdesclen += + le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace); diff --git a/queue-7.0/smb-server-fix-active_num_conn-leak-on-transport-allocation-failure.patch b/queue-7.0/smb-server-fix-active_num_conn-leak-on-transport-allocation-failure.patch new file mode 100644 index 0000000000..599477b3d8 --- /dev/null +++ b/queue-7.0/smb-server-fix-active_num_conn-leak-on-transport-allocation-failure.patch @@ -0,0 +1,68 @@ +From 6551300dc452ac16a855a83dbd1e74899542d3b3 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Tue, 14 Apr 2026 18:54:38 -0400 +Subject: smb: server: fix active_num_conn leak on transport allocation failure + +From: Michael Bommarito + +commit 6551300dc452ac16a855a83dbd1e74899542d3b3 upstream. + +Commit 77ffbcac4e56 ("smb: server: fix leak of active_num_conn in +ksmbd_tcp_new_connection()") addressed the kthread_run() failure +path. The earlier alloc_transport() == NULL path in the same +function has the same leak, is reachable pre-authentication via any +TCP connect to port 445, and was empirically reproduced on UML +(ARCH=um, v7.0-rc7): a small number of forced allocation failures +were sufficient to put ksmbd into a state where every subsequent +connection attempt was rejected for the remainder of the boot. + +ksmbd_kthread_fn() increments active_num_conn before calling +ksmbd_tcp_new_connection() and discards the return value, so when +alloc_transport() returns NULL the socket is released and -ENOMEM +returned without decrementing the counter. Each such failure +permanently consumes one slot from the max_connections pool; once +cumulative failures reach the cap, atomic_inc_return() hits the +threshold on every subsequent accept and every new connection is +rejected. The counter is only reset by module reload. + +An unauthenticated remote attacker can drive the server toward the +memory pressure that makes alloc_transport() fail by holding open +connections with large RFC1002 lengths up to MAX_STREAM_PROT_LEN +(0x00FFFFFF); natural transient allocation failures on a loaded +host produce the same drift more slowly. + +Mirror the existing rollback pattern in ksmbd_kthread_fn(): on the +alloc_transport() failure path, decrement active_num_conn gated on +server_conf.max_connections. + +Repro details: with the patch reverted, forced alloc_transport() +NULL returns leaked counter slots and subsequent connection +attempts -- including legitimate connects issued after the +forced-fail window had closed -- were all rejected with "Limit the +maximum number of connections". With this patch applied, the same +connect sequence produces no rejections and the counter cycles +cleanly between zero and one on every accept. + +Fixes: 0d0d4680db22 ("ksmbd: add max connections parameter") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Michael Bommarito +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/transport_tcp.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/smb/server/transport_tcp.c ++++ b/fs/smb/server/transport_tcp.c +@@ -183,6 +183,8 @@ static int ksmbd_tcp_new_connection(stru + t = alloc_transport(client_sk); + if (!t) { + sock_release(client_sk); ++ if (server_conf.max_connections) ++ atomic_dec(&active_num_conn); + return -ENOMEM; + } + diff --git a/queue-7.0/smb-server-fix-max_connections-off-by-one-in-tcp-accept-path.patch b/queue-7.0/smb-server-fix-max_connections-off-by-one-in-tcp-accept-path.patch new file mode 100644 index 0000000000..ff9ca8bda3 --- /dev/null +++ b/queue-7.0/smb-server-fix-max_connections-off-by-one-in-tcp-accept-path.patch @@ -0,0 +1,52 @@ +From ce23158bfe584bd90d1918f279fdf9de57802012 Mon Sep 17 00:00:00 2001 +From: DaeMyung Kang +Date: Fri, 17 Apr 2026 06:17:35 +0900 +Subject: smb: server: fix max_connections off-by-one in tcp accept path + +From: DaeMyung Kang + +commit ce23158bfe584bd90d1918f279fdf9de57802012 upstream. + +The global max_connections check in ksmbd's TCP accept path counts +the newly accepted connection with atomic_inc_return(), but then +rejects the connection when the result is greater than or equal to +server_conf.max_connections. + +That makes the effective limit one smaller than configured. For +example: + +- max_connections=1 rejects the first connection +- max_connections=2 allows only one connection + +The per-IP limit in the same function uses <= correctly because it +counts only pre-existing connections. The global limit instead checks +the post-increment total, so it should reject only when that total +exceeds the configured maximum. + +Fix this by changing the comparison from >= to >, so exactly +max_connections simultaneous connections are allowed and the next one +is rejected. This matches the documented meaning of max_connections +in fs/smb/server/ksmbd_netlink.h as the "Number of maximum simultaneous +connections". + +Fixes: 0d0d4680db22 ("ksmbd: add max connections parameter") +Cc: stable@vger.kernel.org +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/transport_tcp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/smb/server/transport_tcp.c ++++ b/fs/smb/server/transport_tcp.c +@@ -281,7 +281,7 @@ static int ksmbd_kthread_fn(void *p) + + skip_max_ip_conns_limit: + if (server_conf.max_connections && +- atomic_inc_return(&active_num_conn) >= server_conf.max_connections) { ++ atomic_inc_return(&active_num_conn) > server_conf.max_connections) { + pr_info_ratelimited("Limit the maximum number of connections(%u)\n", + atomic_read(&active_num_conn)); + atomic_dec(&active_num_conn); diff --git a/queue-7.0/writeback-fix-use-after-free-in-inode_switch_wbs_work_fn.patch b/queue-7.0/writeback-fix-use-after-free-in-inode_switch_wbs_work_fn.patch new file mode 100644 index 0000000000..6955974b98 --- /dev/null +++ b/queue-7.0/writeback-fix-use-after-free-in-inode_switch_wbs_work_fn.patch @@ -0,0 +1,104 @@ +From 6689f01d6740cf358932b3e97ee968c6099800d9 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 13 Apr 2026 11:36:19 +0200 +Subject: writeback: Fix use after free in inode_switch_wbs_work_fn() + +From: Jan Kara + +commit 6689f01d6740cf358932b3e97ee968c6099800d9 upstream. + +inode_switch_wbs_work_fn() has a loop like: + + wb_get(new_wb); + while (1) { + list = llist_del_all(&new_wb->switch_wbs_ctxs); + /* Nothing to do? */ + if (!list) + break; + ... process the items ... + } + +Now adding of items to the list looks like: + +wb_queue_isw() + if (llist_add(&isw->list, &wb->switch_wbs_ctxs)) + queue_work(isw_wq, &wb->switch_work); + +Because inode_switch_wbs_work_fn() loops when processing isw items, it +can happen that wb->switch_work is pending while wb->switch_wbs_ctxs is +empty. This is a problem because in that case wb can get freed (no isw +items -> no wb reference) while the work is still pending causing +use-after-free issues. + +We cannot just fix this by cancelling work when freeing wb because that +could still trigger problematic 0 -> 1 transitions on wb refcount due to +wb_get() in inode_switch_wbs_work_fn(). It could be all handled with +more careful code but that seems unnecessarily complex so let's avoid +that until it is proven that the looping actually brings practical +benefit. Just remove the loop from inode_switch_wbs_work_fn() instead. +That way when wb_queue_isw() queues work, we are guaranteed we have +added the first item to wb->switch_wbs_ctxs and nobody is going to +remove it (and drop the wb reference it holds) until the queued work +runs. + +Fixes: e1b849cfa6b6 ("writeback: Avoid contention on wb->list_lock when switching inodes") +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +Link: https://patch.msgid.link/20260413093618.17244-2-jack@suse.cz +Acked-by: Tejun Heo +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/fs-writeback.c | 36 +++++++++++++++++++----------------- + 1 file changed, 19 insertions(+), 17 deletions(-) + +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -570,28 +570,30 @@ void inode_switch_wbs_work_fn(struct wor + struct inode_switch_wbs_context *isw, *next_isw; + struct llist_node *list; + ++ list = llist_del_all(&new_wb->switch_wbs_ctxs); + /* +- * Grab out reference to wb so that it cannot get freed under us ++ * Nothing to do? That would be a problem as references held by isw ++ * items protect wb from freeing... ++ */ ++ if (WARN_ON_ONCE(!list)) ++ return; ++ ++ /* ++ * Grab our reference to wb so that it cannot get freed under us + * after we process all the isw items. + */ + wb_get(new_wb); +- while (1) { +- list = llist_del_all(&new_wb->switch_wbs_ctxs); +- /* Nothing to do? */ +- if (!list) +- break; +- /* +- * In addition to synchronizing among switchers, I_WB_SWITCH +- * tells the RCU protected stat update paths to grab the i_page +- * lock so that stat transfer can synchronize against them. +- * Let's continue after I_WB_SWITCH is guaranteed to be +- * visible. +- */ +- synchronize_rcu(); ++ /* ++ * In addition to synchronizing among switchers, I_WB_SWITCH ++ * tells the RCU protected stat update paths to grab the i_page ++ * lock so that stat transfer can synchronize against them. ++ * Let's continue after I_WB_SWITCH is guaranteed to be ++ * visible. ++ */ ++ synchronize_rcu(); + +- llist_for_each_entry_safe(isw, next_isw, list, list) +- process_inode_switch_wbs(new_wb, isw); +- } ++ llist_for_each_entry_safe(isw, next_isw, list, list) ++ process_inode_switch_wbs(new_wb, isw); + wb_put(new_wb); + } +