From: Greg Kroah-Hartman Date: Wed, 29 Jul 2026 13:57:09 +0000 (+0200) Subject: 7.1-stable patches X-Git-Tag: v6.1.179~19 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=08156ad38affaa56e51ce1c239b4178519bc653f;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: amt-fix-use-after-free-in-amt-delayed-works.patch asoc-fsl-imx-card-skip-sysclk-reset-for-active-dais-in-shutdown.patch asoc-fsl_sai-fix-spurious-bclk-on-resume-by-clearing-byp.patch binfmt_elf_fdpic-only-honour-the-first-pt_interp.patch ceph-add-owner-capability-checks-for-ceph_ioc_set_layout.patch ceph-fix-pre-auth-out-of-bounds-read-on-snaptrace-in-ceph_handle_caps.patch ceph-fix-refcount-leak-in-ceph_readdir.patch ceph-fix-writeback_count-leak-in-write_folio_nounlock.patch fs-preserve-acl_dont_cache-state-in-forget_cached_acl.patch fs-super-fix-emergency-thaw-double-unlock-of-s_umount.patch fscrypt-add-missing-superblock-check-in-find_or_insert_direct_key.patch fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devices.patch ftrace-add-global-mutex-to-serialize-trace_parser-access.patch geneve-require-cap_net_admin-in-the-device-netns-for-changelink.patch ice-fix-ptp-call-trace-during-ptp-release.patch io_uring-rw-fix-missing-erestartsys-conversion-in-read-paths.patch iomap-fix-out-of-bounds-bitmap_set-with-zero-length-range.patch iommu-vt-d-disallow-sva-if-page-walk-is-not-coherent.patch ksmbd-defer-destroy_previous_session-until-after-ntlm-authentication.patch ksmbd-validate-minimum-pdu-size-for-transform-requests.patch libceph-bound-get_version-reply-decode-to-front-len.patch libceph-bound-pg_-temp-upmap-upmap_items-length-to-ceph_pg_max_size.patch libceph-fix-multiplication-overflow-in-decode_new_up_state_weight.patch libceph-fix-two-unsafe-bare-decodes-in-decode_lockers.patch libceph-guard-missing-crush-type-name-lookup.patch libceph-refresh-auth-authorizer_buf-_len-after-authorizer-update.patch libceph-reject-monmaps-advertising-zero-monitors.patch libceph-reject-zero-bucket-types-in-crush_decode.patch libceph-remove-debugfs-files-before-client-teardown.patch m68k-avoid-wunused-but-set-parameter-in-clear_user_page.patch mm-damon-core-disallow-overlapping-input-ranges-for-damon_set_regions.patch mm-damon-core-validate-ranges-in-damon_set_regions.patch mm-huge_memory-set-pg_has_hwpoisoned-only-after-new-folio-head-is-established.patch mm-kmemleak-fix-checksum-computation-for-per-cpu-objects.patch mm-memory-failure-trace-change-memory_failure_event-to-ras-subsystem.patch mm-page_vma_mapped-fix-device-private-pmd-handling.patch mm-slab-fix-a-memory-leak-due-to-bootstrapping-sheaves-twice.patch mm-slab-prevent-unbounded-recursion-in-free-path-with-new-kmalloc-type.patch mm-slub-fix-lost-local-objects-when-bulk-remote-free-batch-fills.patch net-af_iucv-fix-null-deref-in-afiucv_hs_callback_syn.patch net-gro-fix-double-aggregation-of-flush-marked-skbs.patch net-hip04-fix-rx-buffer-leak-on-build_skb-failure.patch net-iucv-fix-use-after-free-of-a-severed-iucv_path.patch net-mlx5e-use-sender-devcom-for-mpv-master-up.patch net-pcs-xpcs-fix-sgmii-state-reading.patch net-qrtr-ns-raise-node-count-limit-to-512.patch net-sched-serialize-qdisc_rtab_list-against-concurrent-get-put.patch net-slip-serialize-receive-against-buffer-reallocation.patch net-stmmac-intel-skip-serdes-reconfig-when-rate-is-unchanged.patch net-x25-fix-use-after-free-in-x25_kill_by_neigh.patch phonet-pep-fix-use-after-free-in-pep_get_sb.patch proc-fix-broken-error-paths-for-namespace-links.patch ptp-ptp_s390-add-missing-facility-check.patch rbd-reset-positive-result-codes-to-zero-in-object-map-update-path.patch sctp-avoid-auth_enable-sysctl-uaf-during-netns-teardown.patch sctp-close-udp-tunnel-sockets-during-netns-teardown.patch sctp-don-t-free-the-asconf-s-own-transport-in-del-ip-processing.patch selftests-ftrace-reset-triggers-at-top-level-before-instance-loop.patch smb-client-handle-status_stopped_on_symlink-responses-without-a-symlink-target.patch super-fix-emergency-thaw-deadlock-on-frozen-block-devices.patch userfaultfd-prevent-registration-of-special-vmas.patch vxlan-require-cap_net_admin-in-the-device-netns-for-changelink.patch --- diff --git a/queue-7.1/amt-fix-use-after-free-in-amt-delayed-works.patch b/queue-7.1/amt-fix-use-after-free-in-amt-delayed-works.patch new file mode 100644 index 0000000000..777954c896 --- /dev/null +++ b/queue-7.1/amt-fix-use-after-free-in-amt-delayed-works.patch @@ -0,0 +1,89 @@ +From ea20c44935d6142daecfa9b39d635033a7553e1b Mon Sep 17 00:00:00 2001 +From: Shihuang Liu +Date: Wed, 22 Jul 2026 19:39:19 +0800 +Subject: amt: fix use-after-free in AMT delayed works + +From: Shihuang Liu + +commit ea20c44935d6142daecfa9b39d635033a7553e1b upstream. + +When an AMT device is removed, pending delayed works can still access +the freed amt_dev structure, which may result in kernel crashes or +memory corruption. + +amt_dev_stop() cancels req_wq and discovery_wq with +cancel_delayed_work_sync(), but these works can be scheduled again +from event_wq after the cancellation. This allows delayed works to +access the freed amt_dev structure after the netdev has been released. + +The following is a simple race scenario: + +CPU0 CPU1 + +amt_dev_stop() +cancel_delayed_work_sync() + amt_event_work() + mod_delayed_work(req_wq) +free netdev + req_wq accesses freed amt_dev + +Use disable_delayed_work_sync() in amt_dev_stop() to prevent req_wq and +discovery_wq from being queued again and wait for running work items +to complete. + +The delayed works are disabled after initialization in +amt_newlink() and enabled only when the device is successfully opened. +This keeps the delayed work lifecycle synchronized with the lifetime +of the AMT device. + +Fixes: cbc21dc1cfe9 ("amt: add data plane of amt interface") +Cc: stable@vger.kernel.org +Signed-off-by: Shihuang Liu +Reviewed-by: Simon Horman +Reviewed-by: Taehee Yoo +Link: https://patch.msgid.link/20260722113919.7723-1-shlomojune6@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/amt.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/drivers/net/amt.c ++++ b/drivers/net/amt.c +@@ -3034,9 +3034,15 @@ static int amt_dev_open(struct net_devic + amt->event_idx = 0; + amt->nr_events = 0; + ++ enable_delayed_work(&amt->discovery_wq); ++ enable_delayed_work(&amt->req_wq); ++ + err = amt_socket_create(amt); +- if (err) ++ if (err) { ++ disable_delayed_work(&amt->req_wq); ++ disable_delayed_work(&amt->discovery_wq); + return err; ++ } + + amt->req_cnt = 0; + amt->remote_ip = 0; +@@ -3062,8 +3068,8 @@ static int amt_dev_stop(struct net_devic + struct sk_buff *skb; + int i; + +- cancel_delayed_work_sync(&amt->req_wq); +- cancel_delayed_work_sync(&amt->discovery_wq); ++ disable_delayed_work_sync(&amt->req_wq); ++ disable_delayed_work_sync(&amt->discovery_wq); + cancel_delayed_work_sync(&amt->secret_wq); + + /* shutdown */ +@@ -3317,6 +3323,8 @@ static int amt_newlink(struct net_device + INIT_DELAYED_WORK(&amt->req_wq, amt_req_work); + INIT_DELAYED_WORK(&amt->secret_wq, amt_secret_work); + INIT_WORK(&amt->event_wq, amt_event_work); ++ disable_delayed_work(&amt->req_wq); ++ disable_delayed_work(&amt->discovery_wq); + INIT_LIST_HEAD(&amt->tunnel_list); + return 0; + err: diff --git a/queue-7.1/asoc-fsl-imx-card-skip-sysclk-reset-for-active-dais-in-shutdown.patch b/queue-7.1/asoc-fsl-imx-card-skip-sysclk-reset-for-active-dais-in-shutdown.patch new file mode 100644 index 0000000000..b99ddf811e --- /dev/null +++ b/queue-7.1/asoc-fsl-imx-card-skip-sysclk-reset-for-active-dais-in-shutdown.patch @@ -0,0 +1,50 @@ +From 9f86aea992568c2b4db78c80ff9508af9e050ff7 Mon Sep 17 00:00:00 2001 +From: Chancel Liu +Date: Fri, 10 Jul 2026 12:13:33 +0900 +Subject: ASoC: fsl: imx-card: Skip sysclk reset for active DAIs in shutdown + +From: Chancel Liu + +commit 9f86aea992568c2b4db78c80ff9508af9e050ff7 upstream. + +In a full-duplex setup, when one direction (playback or capture) is +closed while the other is still running, imx_aif_shutdown() was +unconditionally calling snd_soc_dai_set_sysclk() with rate=0 for all +cpu/codec DAIs, which would disable the clock still needed by the +active stream. + +Add snd_soc_dai_active() checks before clearing sysclk so that only +truly inactive DAIs have their clocks reset. + +Fixes: 2260bc6ea8bd ("ASoC: imx-card: Add WM8524 support") +Cc: stable@vger.kernel.org +Signed-off-by: Chancel Liu +Link: https://patch.msgid.link/20260710031333.3491445-1-chancel.liu@oss.nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/fsl/imx-card.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/sound/soc/fsl/imx-card.c ++++ b/sound/soc/fsl/imx-card.c +@@ -496,11 +496,15 @@ static void imx_aif_shutdown(struct snd_ + struct snd_soc_dai *codec_dai; + int i; + +- for_each_rtd_cpu_dais(rtd, i, cpu_dai) +- snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); ++ for_each_rtd_cpu_dais(rtd, i, cpu_dai) { ++ if (!snd_soc_dai_active(cpu_dai)) ++ snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); ++ } + +- for_each_rtd_codec_dais(rtd, i, codec_dai) +- snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN); ++ for_each_rtd_codec_dais(rtd, i, codec_dai) { ++ if (!snd_soc_dai_active(codec_dai)) ++ snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN); ++ } + } + + static const struct snd_soc_ops imx_aif_ops = { diff --git a/queue-7.1/asoc-fsl_sai-fix-spurious-bclk-on-resume-by-clearing-byp.patch b/queue-7.1/asoc-fsl_sai-fix-spurious-bclk-on-resume-by-clearing-byp.patch new file mode 100644 index 0000000000..c42623d3f0 --- /dev/null +++ b/queue-7.1/asoc-fsl_sai-fix-spurious-bclk-on-resume-by-clearing-byp.patch @@ -0,0 +1,80 @@ +From d091132889c1378dd0944a72f86eae3e4da1e4fa Mon Sep 17 00:00:00 2001 +From: Chancel Liu +Date: Fri, 10 Jul 2026 16:08:35 +0900 +Subject: ASoC: fsl_sai: Fix spurious BCLK on resume by clearing BYP + +From: Chancel Liu + +commit d091132889c1378dd0944a72f86eae3e4da1e4fa upstream. + +When the BCLK divider ratio is 1:1, fsl_sai_set_bclk() enables bypass +mode by setting BYP, but never clears the bit. The BYP=1 value remains +in the regcache, and is restored by regcache_sync() on the next runtime +resume. + +Since BYP=1 combined with BCD=1 immediately outputs the ungated MCLK +as BCLK without waiting for BCE/TE/RE to be enabled, the clock is +driven prematurely before the stream is fully configured, causing +noise on some codecs. + +Fix this by clearing BYP and BCI in fsl_sai_hw_free() taking into +account sync mode and the opposite stream's state, so that the regcache +holds BYP=0 before runtime suspend and regcache_sync() on resume will +not restore bypass mode prematurely. + +Fixes: a50b7926d015 ("ASoC: fsl_sai: implement 1:1 bclk:mclk ratio support") +Cc: stable@vger.kernel.org +Signed-off-by: Chancel Liu +Reviewed-by: Shengjiu Wang +Link: https://patch.msgid.link/20260710070835.3749817-1-chancel.liu@oss.nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/fsl/fsl_sai.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +--- a/sound/soc/fsl/fsl_sai.c ++++ b/sound/soc/fsl/fsl_sai.c +@@ -804,6 +804,8 @@ static int fsl_sai_hw_free(struct snd_pc + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int ofs = sai->soc_data->reg_offset; ++ int adir = tx ? RX : TX; ++ int dir = tx ? TX : RX; + + /* Clear xMR to avoid channel swap with mclk_with_tere enabled case */ + regmap_write(sai->regmap, FSL_SAI_xMR(tx), 0); +@@ -811,10 +813,29 @@ static int fsl_sai_hw_free(struct snd_pc + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), + FSL_SAI_CR3_TRCE_MASK, 0); + +- if (!sai->is_consumer_mode[tx] && +- sai->mclk_streams & BIT(substream->stream)) { +- clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); +- sai->mclk_streams &= ~BIT(substream->stream); ++ if (!sai->is_consumer_mode[tx]) { ++ bool adir_active = !!(sai->mclk_streams & BIT(!substream->stream)); ++ /* ++ * If opposite stream provides clocks for synchronous mode and ++ * it is inactive, Clear BYP and BCI ++ */ ++ if (fsl_sai_dir_is_synced(sai, adir) && !adir_active) ++ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs), ++ FSL_SAI_CR2_BCI | FSL_SAI_CR2_BYP, 0); ++ /* ++ * Clear BYP and BCI of current stream if either of: ++ * 1. current stream doesn't provide clocks for synchronous mode ++ * 2. current stream provides clocks for synchronous mode but no ++ * more stream is active. ++ */ ++ if (!fsl_sai_dir_is_synced(sai, dir) || !adir_active) ++ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), ++ FSL_SAI_CR2_BCI | FSL_SAI_CR2_BYP, 0); ++ ++ if (sai->mclk_streams & BIT(substream->stream)) { ++ clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); ++ sai->mclk_streams &= ~BIT(substream->stream); ++ } + } + + return 0; diff --git a/queue-7.1/binfmt_elf_fdpic-only-honour-the-first-pt_interp.patch b/queue-7.1/binfmt_elf_fdpic-only-honour-the-first-pt_interp.patch new file mode 100644 index 0000000000..24b5359996 --- /dev/null +++ b/queue-7.1/binfmt_elf_fdpic-only-honour-the-first-pt_interp.patch @@ -0,0 +1,47 @@ +From 3349ef6a366a61d631f6a263d12cea240957719d Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Tue, 21 Jul 2026 13:20:45 +0200 +Subject: binfmt_elf_fdpic: only honour the first PT_INTERP + +From: Christian Brauner + +commit 3349ef6a366a61d631f6a263d12cea240957719d upstream. + +The program header scan handles PT_INTERP from a switch nested in the +scan loop, so its break leaves the switch and not the loop. A binary +carrying more than one PT_INTERP runs the case again and overwrites both +interpreter_name and interpreter. The previous name allocation leaks and +so does the previous interpreter reference, along with the write denial +open_exec() took on it. The denial is never released, so the file stays +unwritable for as long as the system runs. + +An unprivileged caller reaches this with a crafted binary and repeats it +at will. binfmt_elf stops at the first PT_INTERP. Do the same here. + +The flaw dates back to the driver's introduction in the pre-git history +tree introduced in v2.6.11 by 91808d6ebe39 ("[PATCH] FRV: Add FDPIC ELF +binary format driver"). + +Link: https://patch.msgid.link/20260721-gezittert-medium-kreide-b41fc1f0277e@brauner +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Reviewed-by: Jori Koolstra +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_elf_fdpic.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/binfmt_elf_fdpic.c ++++ b/fs/binfmt_elf_fdpic.c +@@ -231,6 +231,10 @@ static int load_elf_fdpic_binary(struct + for (i = 0; i < exec_params.hdr.e_phnum; i++, phdr++) { + switch (phdr->p_type) { + case PT_INTERP: ++ /* elf ABI allows only one interpreter */ ++ if (interpreter_name) ++ continue; ++ + retval = -ENOMEM; + if (phdr->p_filesz > PATH_MAX) + goto error; diff --git a/queue-7.1/ceph-add-owner-capability-checks-for-ceph_ioc_set_layout.patch b/queue-7.1/ceph-add-owner-capability-checks-for-ceph_ioc_set_layout.patch new file mode 100644 index 0000000000..d5495018dc --- /dev/null +++ b/queue-7.1/ceph-add-owner-capability-checks-for-ceph_ioc_set_layout.patch @@ -0,0 +1,52 @@ +From cee38bbf5556a8e0a232ccae41649580827d7806 Mon Sep 17 00:00:00 2001 +From: Max Kellermann +Date: Tue, 21 Jul 2026 08:20:46 +0200 +Subject: ceph: add owner/capability checks for CEPH_IOC_SET_LAYOUT* + +From: Max Kellermann + +commit cee38bbf5556a8e0a232ccae41649580827d7806 upstream. + +These permission checks were already missing in the initial +impementation of these ioctls. This Ceph allows any user who owns a +file descriptor to manipulate the layout of any file, even if they +don't have write permissions. + +It might be a good idea to guard other ioctls with permission checks +as well or even disallow regular users (even if they own the file) to +manipulate layout settings completely, as this may be abused to DoS +the Ceph servers, but right now, I find it most urgent to have setter +checks at all. + +Cc: stable@vger.kernel.org +Fixes: 8f4e91dee2a2 ("ceph: ioctls") +Signed-off-by: Max Kellermann +Reviewed-by: Xiubo Li +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/fs/ceph/ioctl.c ++++ b/fs/ceph/ioctl.c +@@ -72,6 +72,9 @@ static long ceph_ioctl_set_layout(struct + struct ceph_ioctl_layout nl; + int err; + ++ if (!inode_owner_or_capable(&nop_mnt_idmap, inode)) ++ return -EACCES; ++ + if (copy_from_user(&l, arg, sizeof(l))) + return -EFAULT; + +@@ -142,6 +145,9 @@ static long ceph_ioctl_set_layout_policy + int err; + struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(inode->i_sb)->mdsc; + ++ if (!inode_owner_or_capable(&nop_mnt_idmap, inode)) ++ return -EACCES; ++ + /* copy and validate */ + if (copy_from_user(&l, arg, sizeof(l))) + return -EFAULT; diff --git a/queue-7.1/ceph-fix-pre-auth-out-of-bounds-read-on-snaptrace-in-ceph_handle_caps.patch b/queue-7.1/ceph-fix-pre-auth-out-of-bounds-read-on-snaptrace-in-ceph_handle_caps.patch new file mode 100644 index 0000000000..fde531d439 --- /dev/null +++ b/queue-7.1/ceph-fix-pre-auth-out-of-bounds-read-on-snaptrace-in-ceph_handle_caps.patch @@ -0,0 +1,72 @@ +From 4dbc71bcaf9a30abf3920a4e2cc4ed33bba78c02 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Fri, 29 May 2026 00:37:24 +0000 +Subject: ceph: fix pre-auth out-of-bounds read on snaptrace in ceph_handle_caps() + +From: Bryam Vargas + +commit 4dbc71bcaf9a30abf3920a4e2cc4ed33bba78c02 upstream. + +ceph_handle_caps() reads snap_trace_len from the wire-format +ceph_mds_caps header and uses it unconditionally to build a fake +end pointer (snaptrace + snaptrace_len) that is later handed to +ceph_update_snap_trace() in the CEPH_CAP_OP_IMPORT case: + + snaptrace = h + 1; + snaptrace_len = le32_to_cpu(h->snap_trace_len); + p = snaptrace + snaptrace_len; + ... + case CEPH_CAP_OP_IMPORT: + if (snaptrace_len) { + ... + if (ceph_update_snap_trace(mdsc, snaptrace, + snaptrace + snaptrace_len, + false, &realm)) { ... } + +ceph_update_snap_trace() then decodes a struct ceph_mds_snap_realm +from snaptrace using ceph_decode_need(&p, e, sizeof(*ri), bad) +with the attacker-supplied fake end e == snaptrace + snaptrace_len. +With snaptrace_len == 0xFFFFFFFF the bound check is trivially +satisfied, ri = p reads sizeof(struct ceph_mds_snap_realm) past +the legitimate msg->front buffer, and ri->num_snaps / +ri->num_prior_parent_snaps then drive further out-of-bounds +reads of the encoded snap arrays. + +The eleven msg_version >= 2 .. msg_version >= 12 decoder blocks +above the op switch each catch this OOB through their +ceph_decode_*_safe() / ceph_decode_need() helpers, but they sit +behind a hdr.version-gated if, so a malicious or compromised +MDS that sets msg->hdr.version = 1 reaches the IMPORT path with +no version-gated decoder having validated snap_trace_len. The +shape has been present since ceph_handle_caps() was introduced. + +Validate snap_trace_len against the message front buffer before +consuming it, using the canonical ceph_decode_need() / ceph_has_room() +helper. The helper bounds the length with subtraction (n <= end - p, +guarded by end >= p) rather than pointer addition, so it is wrap-safe +for the attacker-controlled u32 length on 32-bit builds where +p + snap_trace_len could overflow the address space. This matches the +rest of the ceph decode path (e.g. the pool_ns_len check a few lines +below), and the existing goto bad cleanup already covers this exit +path. + +Cc: stable@vger.kernel.org +Fixes: a8599bd821d0 ("ceph: capability management") +Signed-off-by: Bryam Vargas +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/caps.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -4365,6 +4365,7 @@ void ceph_handle_caps(struct ceph_mds_se + + snaptrace = h + 1; + snaptrace_len = le32_to_cpu(h->snap_trace_len); ++ ceph_decode_need(&snaptrace, end, snaptrace_len, bad); + p = snaptrace + snaptrace_len; + + if (msg_version >= 2) { diff --git a/queue-7.1/ceph-fix-refcount-leak-in-ceph_readdir.patch b/queue-7.1/ceph-fix-refcount-leak-in-ceph_readdir.patch new file mode 100644 index 0000000000..c2ba7c157f --- /dev/null +++ b/queue-7.1/ceph-fix-refcount-leak-in-ceph_readdir.patch @@ -0,0 +1,51 @@ +From c3e64079d8b9663e3998d0caac9aba915b6b93ae Mon Sep 17 00:00:00 2001 +From: WenTao Liang +Date: Thu, 11 Jun 2026 22:40:07 +0800 +Subject: ceph: fix refcount leak in ceph_readdir() + +From: WenTao Liang + +commit c3e64079d8b9663e3998d0caac9aba915b6b93ae upstream. + +The ceph_readdir() function allocates a ceph_mds_request via +ceph_mdsc_create_request() and stores it in dfi->last_readdir. In +the directory entry processing loop, if the entry's offset is less +than ctx->pos or if the inode pointer is unexpectedly NULL, the +function returns -EIO without releasing the reference held by +dfi->last_readdir, causing a refcount leak. + +Fix this by adding ceph_mdsc_put_request(dfi->last_readdir) before +returning on these error paths. Also set dfi->last_readdir to NULL +for safety, matching the cleanup done at the normal exit. + +Cc: stable@vger.kernel.org +Fixes: af9ffa6df7e3 ("ceph: add support to readdir for encrypted names") +Signed-off-by: WenTao Liang +Reviewed-by: Viacheslav Dubeyko +Reviewed-by: Alex Markuze +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/dir.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/fs/ceph/dir.c ++++ b/fs/ceph/dir.c +@@ -546,11 +546,16 @@ more: + pr_warn_client(cl, + "%p %llx.%llx rde->offset 0x%llx ctx->pos 0x%llx\n", + inode, ceph_vinop(inode), rde->offset, ctx->pos); ++ ceph_mdsc_put_request(dfi->last_readdir); ++ dfi->last_readdir = NULL; + return -EIO; + } + +- if (WARN_ON_ONCE(!rde->inode.in)) ++ if (WARN_ON_ONCE(!rde->inode.in)) { ++ ceph_mdsc_put_request(dfi->last_readdir); ++ dfi->last_readdir = NULL; + return -EIO; ++ } + + ctx->pos = rde->offset; + doutc(cl, "%p %llx.%llx (%d/%d) -> %llx '%.*s' %p\n", inode, diff --git a/queue-7.1/ceph-fix-writeback_count-leak-in-write_folio_nounlock.patch b/queue-7.1/ceph-fix-writeback_count-leak-in-write_folio_nounlock.patch new file mode 100644 index 0000000000..47a696ab58 --- /dev/null +++ b/queue-7.1/ceph-fix-writeback_count-leak-in-write_folio_nounlock.patch @@ -0,0 +1,64 @@ +From cbf59617cd715219e84c50d106a3d0e1e8ba054e Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Thu, 4 Jun 2026 02:19:51 +0000 +Subject: ceph: fix writeback_count leak in write_folio_nounlock() + +From: Wentao Liang + +commit cbf59617cd715219e84c50d106a3d0e1e8ba054e upstream. + +write_folio_nounlock() increments fsc->writeback_count to track +in-flight writeback operations. On several error paths where the +function returns early (folio lookup failure, snapshot context +allocation failure, and writepages submission failure), the function +returns without calling atomic_long_dec_return() to decrement the +counter. + +Each leaked increment keeps the counter above zero, which can prevent +the filesystem from cleanly unmounting or suspending writes. + +Add atomic_long_dec_return() calls on all error paths that currently +return without decrementing the counter. + +Cc: stable@vger.kernel.org +Fixes: d55207717ded ("ceph: add encryption support to writepage and writepages") +Signed-off-by: Wentao Liang +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/addr.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/fs/ceph/addr.c ++++ b/fs/ceph/addr.c +@@ -790,6 +790,9 @@ static int write_folio_nounlock(struct f + ceph_wbc.truncate_size, true); + if (IS_ERR(req)) { + folio_redirty_for_writepage(wbc, folio); ++ if (atomic_long_dec_return(&fsc->writeback_count) < ++ CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb)) ++ fsc->write_congested = false; + return PTR_ERR(req); + } + +@@ -809,6 +812,9 @@ static int write_folio_nounlock(struct f + folio_redirty_for_writepage(wbc, folio); + folio_end_writeback(folio); + ceph_osdc_put_request(req); ++ if (atomic_long_dec_return(&fsc->writeback_count) < ++ CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb)) ++ fsc->write_congested = false; + return PTR_ERR(bounce_page); + } + } +@@ -847,6 +853,9 @@ static int write_folio_nounlock(struct f + ceph_vinop(inode), folio); + folio_redirty_for_writepage(wbc, folio); + folio_end_writeback(folio); ++ if (atomic_long_dec_return(&fsc->writeback_count) < ++ CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb)) ++ fsc->write_congested = false; + return err; + } + if (err == -EBLOCKLISTED) diff --git a/queue-7.1/fs-preserve-acl_dont_cache-state-in-forget_cached_acl.patch b/queue-7.1/fs-preserve-acl_dont_cache-state-in-forget_cached_acl.patch new file mode 100644 index 0000000000..3d38e6a89a --- /dev/null +++ b/queue-7.1/fs-preserve-acl_dont_cache-state-in-forget_cached_acl.patch @@ -0,0 +1,57 @@ +From 4b9a5458d02e214ef2b384124ca626e3e381d778 Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Tue, 14 Jul 2026 00:09:31 +0200 +Subject: fs: preserve ACL_DONT_CACHE state in forget_cached_acl() + +From: Amir Goldstein + +commit 4b9a5458d02e214ef2b384124ca626e3e381d778 upstream. + +The ACL_DONT_CACHE state is meant to be a constant state for the inode +for filesystems that want to opt out of posix acl caching. + +Commit facd61053cff1 ("fuse: fixes after adapting to new posix acl api") +used this facility to opt out of posix acl caching for fuse inodes with +fuse server that does not negotiate FUSE_POSIX_ACL (fc->posix_acl). + +The commit also takes care to gate the forget_all_cached_acls() call in +fuse_set_acl() on fc->posix_acl because there is no need for it, but +there are other placed in fuse code which call forget_all_cached_acls() +unconditional to fc->posix_acl and those cause the loss of the +ACL_DONT_CACHE state. + +This is not only a functional bug. Properly timed, a get_acl() from this +fuse filesystem can return a stale cached value, as was observed in tests, +because set_acl() does not invalidate the unintentional acl cache. + +We could fix this in fuse, but it actually makes no sense for the vfs +helper forget_cached_acl() to invalidate the ACL_DONT_CACHE state, so +let it not do that to fix fuse and future users of ACL_DONT_CACHE. + +Fixes: facd61053cff1 ("fuse: fixes after adapting to new posix acl api") +Cc: stable@vger.kernel.org +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260713220932.413004-2-amir73il@gmail.com +Reviewed-by: Luis Henriques +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/posix_acl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/fs/posix_acl.c ++++ b/fs/posix_acl.c +@@ -93,6 +93,13 @@ static void __forget_cached_acl(struct p + { + struct posix_acl *old; + ++ /* ++ * ACL_DONT_CACHE is expected to be a "const" value and xchg it with ++ * ACL_NOT_CACHED would enable acl caching for the inode - ++ * clearly not what the caller has intended. ++ */ ++ if (READ_ONCE(*p) == ACL_DONT_CACHE) ++ return; + old = xchg(p, ACL_NOT_CACHED); + if (!is_uncached_acl(old)) + posix_acl_release(old); diff --git a/queue-7.1/fs-super-fix-emergency-thaw-double-unlock-of-s_umount.patch b/queue-7.1/fs-super-fix-emergency-thaw-double-unlock-of-s_umount.patch new file mode 100644 index 0000000000..a1c83a808c --- /dev/null +++ b/queue-7.1/fs-super-fix-emergency-thaw-double-unlock-of-s_umount.patch @@ -0,0 +1,95 @@ +From 503d67fbaec6fdeaba391cb497675071db9d16ea Mon Sep 17 00:00:00 2001 +From: Chen Changcheng +Date: Tue, 21 Jul 2026 14:41:40 +0800 +Subject: fs/super: fix emergency thaw double-unlock of s_umount + +From: Chen Changcheng + +commit 503d67fbaec6fdeaba391cb497675071db9d16ea upstream. + +do_thaw_all() iterates over all superblocks via __iterate_supers() +with SUPER_ITER_EXCL, which acquires s_umount exclusively before +calling the callback and releases it afterwards. However, the +callback do_thaw_all_callback() calls thaw_super_locked() which +unconditionally releases s_umount on every code path. This results +in a second unlock attempt in __iterate_supers() that corrupts the +rwsem state, triggering a DEBUG_RWSEMS warning: + +[ 182.601148] sysrq: Emergency Thaw of all frozen filesystems +[ 182.601865] ------------[ cut here ]------------ +[ 182.602375] DEBUG_RWSEMS_WARN_ON((rwsem_owner(sem) != current) && !rwsem_test_oflags(sem, RWSEM_NONSPINNABLE)): count = 0x0, magic = 0xffff99b1011e5870, owner = 0x0, curr 0xffff99b101b06c80, list not empty +[ 182.603817] WARNING: kernel/locking/rwsem.c:1412 at up_write+0xa3/0x170, CPU#2: kworker/2:1/53 +[ 182.604578] Modules linked in: +[ 182.604864] CPU: 2 UID: 0 PID: 53 Comm: kworker/2:1 Not tainted 7.2.0-rc4-00001-gbd3bd93ea98a-dirty #4 PREEMPT(lazy) +[ 182.605711] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1kylin1 04/01/2014 +[ 182.606417] Workqueue: events do_thaw_all +[ 182.606750] RIP: 0010:up_write+0xaf/0x170 +[ 182.607076] Code: 19 3a 92 48 0f 44 c2 48 8b 55 08 48 8b 55 00 4c 8b 45 08 48 8b 55 00 48 8d 3d ad 91 e0 01 48 8b 4d 20 50 48 c7 c6 f0 8c 26 92 <67> 48 0f b9 3a e8 d7 93 4e 00 58 eb 81 48 83 7f 18 00 48 c7 c2 8d +[ 182.608563] RSP: 0018:ffffb670001d7e08 EFLAGS: 00010246 +[ 182.609007] RAX: ffffffff92349e8d RBX: 0000000000000000 RCX: ffff99b1011e5870 +[ 182.609595] RDX: 0000000000000000 RSI: ffffffff92268cf0 RDI: ffffffff92914d10 +[ 182.610283] RBP: ffff99b1011e5870 R08: 0000000000000000 R09: ffff99b101b06c80 +[ 182.610847] R10: ffff99b10139a808 R11: fefefefefefefeff R12: 0000000000000000 +[ 182.611414] R13: ffffffff90cf74d0 R14: 0000000000000000 R15: ffff99b1011e5800 +[ 182.612009] FS: 0000000000000000(0000) GS:ffff99b1eaaee000(0000) knlGS:0000000000000000 +[ 182.612670] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 182.613146] CR2: 00000000005c631c CR3: 00000000013ee000 CR4: 00000000000006f0 +[ 182.613722] Call Trace: +[ 182.613946] +[ 182.614130] __iterate_supers+0x128/0x150 +[ 182.614463] do_thaw_all+0x1b/0x30 +[ 182.614759] process_scheduled_works+0xbb/0x3f0 +[ 182.615150] ? __pfx_worker_thread+0x10/0x10 +[ 182.615499] worker_thread+0x129/0x270 +[ 182.615816] ? __pfx_worker_thread+0x10/0x10 +[ 182.616201] kthread+0xe2/0x120 +[ 182.616469] ? __pfx_kthread+0x10/0x10 +[ 182.616792] ret_from_fork+0x15b/0x240 +[ 182.617115] ? __pfx_kthread+0x10/0x10 +[ 182.617426] ret_from_fork_asm+0x1a/0x30 +[ 182.617761] +[ 182.617968] ---[ end trace 0000000000000000 ]--- +[ 182.618412] Emergency Thaw complete + +Fix this by switching to SUPER_ITER_UNLOCKED and acquiring s_umount +in the callback via super_lock_excl() before calling +thaw_super_locked(). This matches the locking pattern expected by +thaw_super_locked() and eliminates the double unlock. + +While at it, remove the dead 'return;' at the end of +do_thaw_all_callback(). + +Fixes: 2992476528ae ("super: use a common iterator (Part 1)") +Cc: stable@vger.kernel.org +Signed-off-by: Chen Changcheng +Link: https://patch.msgid.link/20260721064140.152305-1-chenchangcheng@kylinos.cn +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/super.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/super.c ++++ b/fs/super.c +@@ -1145,16 +1145,19 @@ void emergency_remount(void) + + static void do_thaw_all_callback(struct super_block *sb, void *unused) + { ++ if (!super_lock_excl(sb)) ++ return; ++ + if (IS_ENABLED(CONFIG_BLOCK)) + while (sb->s_bdev && !bdev_thaw(sb->s_bdev)) + pr_warn("Emergency Thaw on %pg\n", sb->s_bdev); ++ + thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE, NULL); +- return; + } + + static void do_thaw_all(struct work_struct *work) + { +- __iterate_supers(do_thaw_all_callback, NULL, SUPER_ITER_EXCL); ++ __iterate_supers(do_thaw_all_callback, NULL, SUPER_ITER_UNLOCKED); + kfree(work); + printk(KERN_WARNING "Emergency Thaw complete\n"); + } diff --git a/queue-7.1/fscrypt-add-missing-superblock-check-in-find_or_insert_direct_key.patch b/queue-7.1/fscrypt-add-missing-superblock-check-in-find_or_insert_direct_key.patch new file mode 100644 index 0000000000..e83afbc7d7 --- /dev/null +++ b/queue-7.1/fscrypt-add-missing-superblock-check-in-find_or_insert_direct_key.patch @@ -0,0 +1,66 @@ +From b5fa40226e71c17847b9ff2816c6ca4133d0d994 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sat, 18 Jul 2026 20:31:20 -0700 +Subject: fscrypt: Add missing superblock check in find_or_insert_direct_key() + +From: Eric Biggers + +commit b5fa40226e71c17847b9ff2816c6ca4133d0d994 upstream. + +The legacy 'fscrypt_direct_keys' table caches master keys that are used +by v1 encryption policies that have FSCRYPT_POLICY_FLAG_DIRECT_KEY. +It's just a global table for all filesystems (since the keys can be +provided by the legacy process-subscribed keyrings mechanism, which +makes it difficult to reuse super_block::s_master_keys). + +The entries in it ('struct fscrypt_direct_key') do contain a super_block +pointer, though, for passing to fscrypt_destroy_inline_crypt_key() when +the last inode that references the key is evicted. + +However, when finding the fscrypt_direct_key for an inode, we weren't +actually comparing the super_block pointer. As a result, inodes with +different super_blocks could point to the same fscrypt_direct_key. That +could extend the lifetime of a fscrypt_direct_key beyond the +super_block it points to, causing a use-after-free later. + +Fix this by creating distinct fscrypt_direct_key structs for distinct +super_block structs. + +Note that this problem doesn't exist in the v2 policy equivalent +("per-mode keys"), since the data structures there are per super_block. + +Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references") +Cc: stable@vger.kernel.org +Reported-by: Sashiko +Closes: https://sashiko.dev/#/patchset/20260717044303.425265-1-ebiggers%40kernel.org +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260719033120.122120-1-ebiggers@kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + fs/crypto/keysetup_v1.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/fs/crypto/keysetup_v1.c ++++ b/fs/crypto/keysetup_v1.c +@@ -147,13 +147,19 @@ find_or_insert_direct_key(struct fscrypt + if (memcmp(ci->ci_policy.v1.master_key_descriptor, + dk->dk_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE) != 0) + continue; ++ /* The sb is used at eviction time, so it must be the same. */ ++ if (ci->ci_inode->i_sb != dk->dk_sb) ++ continue; + if (ci->ci_mode != dk->dk_mode) + continue; + if (!fscrypt_is_key_prepared(&dk->dk_key, ci)) + continue; + if (crypto_memneq(raw_key, dk->dk_raw, ci->ci_mode->keysize)) + continue; +- /* using existing tfm with same (descriptor, mode, raw_key) */ ++ /* ++ * Use an existing prepared key with the same (descriptor, sb, ++ * mode, inlinecrypt, raw_key) combination. ++ */ + refcount_inc(&dk->dk_refcount); + spin_unlock(&fscrypt_direct_keys_lock); + free_direct_key(to_insert); diff --git a/queue-7.1/fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devices.patch b/queue-7.1/fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devices.patch new file mode 100644 index 0000000000..9a8ff1b094 --- /dev/null +++ b/queue-7.1/fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devices.patch @@ -0,0 +1,253 @@ +From 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sat, 18 Jul 2026 22:56:02 -0700 +Subject: fscrypt: Avoid dynamic allocation in fscrypt_get_devices() + +From: Eric Biggers + +commit 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 upstream. + +When a blk_crypto_key starts being used or is evicted, fs/crypto/ calls +fscrypt_get_devices() to get the filesystem's list of block devices, +then iterates over them and calls blk_crypto_config_supported(), +blk_crypto_start_using_key(), or blk_crypto_evict_key() on each one. + +Currently, the block device pointers are placed in a dynamically +allocated array. This dynamic allocation is problematic because: + +- It can fail, especially at the fscrypt_destroy_inline_crypt_key() call + site when it's invoked for inode eviction under direct reclaim. + +- fscrypt_destroy_inline_crypt_key() doesn't handle the failure. It + just zeroizes and frees the blk_crypto_key without calling + blk_crypto_evict_key(). That causes a use-after-free. + +For now, let's fix this in the straightforward and easily-backportable +way by switching to an on-stack array. Currently the fscrypt +multi-device functionality is used only by f2fs, which has a hardcoded +limit of 8 block devices. An on-stack array works fine for that. + +(Of course, this solution won't scale up to large number of block +devices. For that we'd need a different solution, like moving the block +device iteration into the filesystem. Or in the case of btrfs, which +will only support blk-crypto-fallback, we should make it just call +blk-crypto-fallback directly, so the block devices won't be needed.) + +Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references") +Cc: stable@vger.kernel.org +Reported-by: Sashiko +Closes: https://sashiko.dev/#/patchset/20260713023708.9245-1-ebiggers%40kernel.org +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260719055602.78828-1-ebiggers@kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + fs/crypto/inline_crypt.c | 57 ++++++++++++++++------------------------------- + fs/f2fs/super.c | 25 +++++++++++--------- + include/linux/fscrypt.h | 20 +++++++++------- + 3 files changed, 45 insertions(+), 57 deletions(-) + +--- a/fs/crypto/inline_crypt.c ++++ b/fs/crypto/inline_crypt.c +@@ -22,22 +22,14 @@ + + #include "fscrypt_private.h" + +-static struct block_device **fscrypt_get_devices(struct super_block *sb, +- unsigned int *num_devs) ++static unsigned int ++fscrypt_get_devices(struct super_block *sb, ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]) + { +- struct block_device **devs; +- +- if (sb->s_cop->get_devices) { +- devs = sb->s_cop->get_devices(sb, num_devs); +- if (devs) +- return devs; +- } +- devs = kmalloc_obj(*devs); +- if (!devs) +- return ERR_PTR(-ENOMEM); ++ if (sb->s_cop->get_devices) ++ return sb->s_cop->get_devices(sb, devs); + devs[0] = sb->s_bdev; +- *num_devs = 1; +- return devs; ++ return 1; + } + + static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_inode_info *ci) +@@ -96,7 +88,7 @@ int fscrypt_select_encryption_impl(struc + const struct inode *inode = ci->ci_inode; + struct super_block *sb = inode->i_sb; + struct blk_crypto_config crypto_cfg; +- struct block_device **devs; ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]; + unsigned int num_devs; + unsigned int i; + +@@ -135,20 +127,15 @@ int fscrypt_select_encryption_impl(struc + crypto_cfg.key_type = is_hw_wrapped_key ? + BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW; + +- devs = fscrypt_get_devices(sb, &num_devs); +- if (IS_ERR(devs)) +- return PTR_ERR(devs); +- ++ num_devs = fscrypt_get_devices(sb, devs); + for (i = 0; i < num_devs; i++) { + if (!blk_crypto_config_supported(devs[i], &crypto_cfg)) +- goto out_free_devs; ++ return 0; + } + + fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg); + + ci->ci_inlinecrypt = true; +-out_free_devs: +- kfree(devs); + + return 0; + } +@@ -164,7 +151,7 @@ int fscrypt_prepare_inline_crypt_key(str + enum blk_crypto_key_type key_type = is_hw_wrapped ? + BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW; + struct blk_crypto_key *blk_key; +- struct block_device **devs; ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]; + unsigned int num_devs; + unsigned int i; + int err; +@@ -182,17 +169,12 @@ int fscrypt_prepare_inline_crypt_key(str + } + + /* Start using blk-crypto on all the filesystem's block devices. */ +- devs = fscrypt_get_devices(sb, &num_devs); +- if (IS_ERR(devs)) { +- err = PTR_ERR(devs); +- goto fail; +- } ++ num_devs = fscrypt_get_devices(sb, devs); + for (i = 0; i < num_devs; i++) { + err = blk_crypto_start_using_key(devs[i], blk_key); + if (err) + break; + } +- kfree(devs); + if (err) { + fscrypt_err(inode, "error %d starting to use blk-crypto", err); + goto fail; +@@ -210,20 +192,21 @@ void fscrypt_destroy_inline_crypt_key(st + struct fscrypt_prepared_key *prep_key) + { + struct blk_crypto_key *blk_key = prep_key->blk_key; +- struct block_device **devs; ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]; + unsigned int num_devs; + unsigned int i; + + if (!blk_key) + return; + +- /* Evict the key from all the filesystem's block devices. */ +- devs = fscrypt_get_devices(sb, &num_devs); +- if (!IS_ERR(devs)) { +- for (i = 0; i < num_devs; i++) +- blk_crypto_evict_key(devs[i], blk_key); +- kfree(devs); +- } ++ /* ++ * Evict the key from all the filesystem's block devices. ++ * This *must* be done before the key is freed. ++ */ ++ num_devs = fscrypt_get_devices(sb, devs); ++ for (i = 0; i < num_devs; i++) ++ blk_crypto_evict_key(devs[i], blk_key); ++ + kfree_sensitive(blk_key); + } + +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -3731,24 +3731,27 @@ static bool f2fs_has_stable_inodes(struc + return true; + } + +-static struct block_device **f2fs_get_devices(struct super_block *sb, +- unsigned int *num_devs) ++static unsigned int ++f2fs_get_devices(struct super_block *sb, ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]) + { + struct f2fs_sb_info *sbi = F2FS_SB(sb); +- struct block_device **devs; ++ int ndevs; + int i; + +- if (!f2fs_is_multi_device(sbi)) +- return NULL; ++ static_assert(MAX_DEVICES <= FSCRYPT_MAX_DEVICES); + +- devs = kmalloc_objs(*devs, sbi->s_ndevs); +- if (!devs) +- return ERR_PTR(-ENOMEM); ++ if (!f2fs_is_multi_device(sbi)) { ++ devs[0] = sb->s_bdev; ++ return 1; ++ } ++ ndevs = sbi->s_ndevs; ++ if (WARN_ON_ONCE(ndevs > FSCRYPT_MAX_DEVICES)) ++ ndevs = FSCRYPT_MAX_DEVICES; + +- for (i = 0; i < sbi->s_ndevs; i++) ++ for (i = 0; i < ndevs; i++) + devs[i] = FDEV(i).bdev; +- *num_devs = sbi->s_ndevs; +- return devs; ++ return ndevs; + } + + static const struct fscrypt_operations f2fs_cryptops = { +--- a/include/linux/fscrypt.h ++++ b/include/linux/fscrypt.h +@@ -57,6 +57,9 @@ struct fscrypt_name { + /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ + #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40 + ++/* Maximum supported number of block devices per filesystem */ ++#define FSCRYPT_MAX_DEVICES 8 ++ + #ifdef CONFIG_FS_ENCRYPTION + + /* Crypto operations for filesystems */ +@@ -181,21 +184,20 @@ struct fscrypt_operations { + bool (*has_stable_inodes)(struct super_block *sb); + + /* +- * Return an array of pointers to the block devices to which the +- * filesystem may write encrypted file contents, NULL if the filesystem +- * only has a single such block device, or an ERR_PTR() on error. +- * +- * On successful non-NULL return, *num_devs is set to the number of +- * devices in the returned array. The caller must free the returned +- * array using kfree(). ++ * Retrieve the list of block devices to which the filesystem may write ++ * encrypted file contents. ++ * ++ * This writes the block_device pointers to @devs and returns the count ++ * (between 1 and FSCRYPT_MAX_DEVICES inclusively). + * + * If the filesystem can use multiple block devices (other than block + * devices that aren't used for encrypted file contents, such as + * external journal devices), and wants to support inline encryption, + * then it must implement this function. Otherwise it's not needed. + */ +- struct block_device **(*get_devices)(struct super_block *sb, +- unsigned int *num_devs); ++ unsigned int (*get_devices)( ++ struct super_block *sb, ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]); + }; + + int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name, diff --git a/queue-7.1/ftrace-add-global-mutex-to-serialize-trace_parser-access.patch b/queue-7.1/ftrace-add-global-mutex-to-serialize-trace_parser-access.patch new file mode 100644 index 0000000000..58c2c52ab8 --- /dev/null +++ b/queue-7.1/ftrace-add-global-mutex-to-serialize-trace_parser-access.patch @@ -0,0 +1,98 @@ +From 7720b63bcef3f54c7fe288774b720a227d54a306 Mon Sep 17 00:00:00 2001 +From: Tengda Wu +Date: Sat, 25 Jul 2026 02:47:21 +0000 +Subject: ftrace: Add global mutex to serialize trace_parser access + +From: Tengda Wu + +commit 7720b63bcef3f54c7fe288774b720a227d54a306 upstream. + +In ftrace, the trace_parser structure is allocated and initialized when +a trace file is opened, and is subsequently used across write and release +handlers to parse user input. + +The affected handler paths and their specific functions are: + - Open paths: ftrace_regex_open(), ftrace_graph_open() + - Write paths: ftrace_regex_write(), ftrace_graph_write() + - Release paths: ftrace_regex_release(), ftrace_graph_release() + +If userspace opens a trace file descriptor and shares it across multiple +threads, concurrent write calls will race on the parser's internal state, +specifically the 'idx', 'cont', and 'buffer' fields, leading to corrupted +input or undefined behavior. + +Fix this by adding a global mutex, parser_lock, to serialize all access +to trace_parser across write and release paths, preventing concurrent +corruption of parser state. + +Fixes: e704eff3ff51 ("ftrace: Have set_graph_function handle multiple functions in one write") +Fixes: 689fd8b65d66 ("tracing: trace parser support for function and graph") +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260725024721.1983675-1-wutengda@huaweicloud.com +Signed-off-by: Tengda Wu +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/ftrace.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -1098,6 +1098,12 @@ struct ftrace_ops global_ops = { + }; + + /* ++ * parser_lock - Protects trace_parser state against concurrent operations. ++ * Held across trace_get_user() and subsequent buffer parsing to prevent races. ++ */ ++static DEFINE_MUTEX(parser_lock); ++ ++/* + * Used by the stack unwinder to know about dynamic ftrace trampolines. + */ + struct ftrace_ops *ftrace_ops_trampoline(unsigned long addr) +@@ -5824,6 +5830,8 @@ ftrace_regex_write(struct file *file, co + /* iter->hash is a local copy, so we don't need regex_lock */ + + parser = &iter->parser; ++ ++ guard(mutex)(&parser_lock); + read = trace_get_user(parser, ubuf, cnt, ppos); + + if (read >= 0 && trace_parser_loaded(parser) && +@@ -6961,12 +6969,14 @@ int ftrace_regex_release(struct inode *i + iter = file->private_data; + + parser = &iter->parser; ++ mutex_lock(&parser_lock); + if (trace_parser_loaded(parser)) { + int enable = !(iter->flags & FTRACE_ITER_NOTRACE); + + ftrace_process_regex(iter, parser->buffer, + parser->idx, enable); + } ++ mutex_unlock(&parser_lock); + + trace_parser_put(parser); + +@@ -7298,10 +7308,12 @@ ftrace_graph_release(struct inode *inode + + parser = &fgd->parser; + ++ mutex_lock(&parser_lock); + if (trace_parser_loaded((parser))) { + ret = ftrace_graph_set_hash(fgd->new_hash, + parser->buffer); + } ++ mutex_unlock(&parser_lock); + + trace_parser_put(parser); + +@@ -7414,6 +7426,7 @@ ftrace_graph_write(struct file *file, co + + parser = &fgd->parser; + ++ guard(mutex)(&parser_lock); + read = trace_get_user(parser, ubuf, cnt, ppos); + + if (read >= 0 && trace_parser_loaded(parser) && diff --git a/queue-7.1/geneve-require-cap_net_admin-in-the-device-netns-for-changelink.patch b/queue-7.1/geneve-require-cap_net_admin-in-the-device-netns-for-changelink.patch new file mode 100644 index 0000000000..d0367ade97 --- /dev/null +++ b/queue-7.1/geneve-require-cap_net_admin-in-the-device-netns-for-changelink.patch @@ -0,0 +1,52 @@ +From 8efb8f8bbb353b8f2fdf4f37534c6d96c9f69e01 Mon Sep 17 00:00:00 2001 +From: Doruk Tan Ozturk +Date: Thu, 16 Jul 2026 22:35:00 +0200 +Subject: geneve: require CAP_NET_ADMIN in the device netns for changelink + +From: Doruk Tan Ozturk + +commit 8efb8f8bbb353b8f2fdf4f37534c6d96c9f69e01 upstream. + +A tunnel changelink() operates on at most two netns, dev_net(dev) and +the sticky underlay netns geneve->net. They differ once the device is +created in or moved to a netns other than the one the request runs in. +The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), +so a caller privileged there but not in geneve->net can rewrite a geneve +device whose underlay lives in geneve->net. + +geneve_changelink() applies the new configuration against geneve->net: +geneve_link_config() and the geneve_quiesce()/geneve_unquiesce() pair +reopen the underlay sockets in that netns (geneve_sock_add() uses +geneve->net), so the same reasoning as the tunnel changelink series +applies here. + +Gate geneve_changelink() with rtnl_dev_link_net_capable(), at the top of +the op before any attribute is parsed, matching ipgre_changelink() and +the rest of the "require CAP_NET_ADMIN in the device netns for +changelink" series. + +Found by 0sec automated security-research tooling (https://0sec.ai). + +Fixes: 5b861f6baa3a ("geneve: add rtnl changelink support") +Cc: stable@vger.kernel.org +Signed-off-by: Doruk Tan Ozturk +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260716203500.70573-3-doruk@0sec.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/geneve.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/geneve.c ++++ b/drivers/net/geneve.c +@@ -2251,6 +2251,9 @@ static int geneve_changelink(struct net_ + struct geneve_config cfg; + int err; + ++ if (!rtnl_dev_link_net_capable(dev, geneve->net)) ++ return -EPERM; ++ + /* If the geneve device is configured for metadata (or externally + * controlled, for example, OVS), then nothing can be changed. + */ diff --git a/queue-7.1/ice-fix-ptp-call-trace-during-ptp-release.patch b/queue-7.1/ice-fix-ptp-call-trace-during-ptp-release.patch new file mode 100644 index 0000000000..52bb8701db --- /dev/null +++ b/queue-7.1/ice-fix-ptp-call-trace-during-ptp-release.patch @@ -0,0 +1,54 @@ +From f6a7e00b81e35ef1325234925f2fe1e53b466f92 Mon Sep 17 00:00:00 2001 +From: Paul Greenwalt +Date: Fri, 17 Jul 2026 11:53:31 -0700 +Subject: ice: fix PTP Call Trace during PTP release + +From: Paul Greenwalt + +commit f6a7e00b81e35ef1325234925f2fe1e53b466f92 upstream. + +If a PF reset occurs when the PTP state is ICE_PTP_UNINIT, then +ice_ptp_rebuild() will update the state to ICE_PTP_ERROR. This will +result in the following PTP release call trace during driver unload: + + kernel BUG at lib/list_debug.c:52! + ice_ptp_release+0x332/0x3c0 [ice] + ice_deinit_features.part.0+0x10e/0x120 [ice] + ice_remove+0x100/0x220 [ice] + +This was observed when passing PF1 through to a VM. ice_ptp_init() +fails because ctrl_pf is NULL and sets the state to ICE_PTP_UNINIT. + +Fix by detecting the ICE_PTP_UNINIT state in ice_ptp_rebuild() and +returning without error, preventing the invalid state transition to +ICE_PTP_ERROR. The only valid path to ICE_PTP_ERROR is from +ICE_PTP_RESETTING after a failed rebuild. + +Fixes: 8293e4cb2ff5 ("ice: introduce PTP state machine") +Cc: stable@vger.kernel.org +Signed-off-by: Paul Greenwalt +Signed-off-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Rinitha S (A Contingent worker at Intel) +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260717185340.3595286-10-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/intel/ice/ice_ptp.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/net/ethernet/intel/ice/ice_ptp.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp.c +@@ -3035,6 +3035,11 @@ void ice_ptp_rebuild(struct ice_pf *pf, + struct ice_ptp *ptp = &pf->ptp; + int err; + ++ if (ptp->state == ICE_PTP_UNINIT) { ++ dev_dbg(ice_pf_to_dev(pf), "PTP was not initialized, skipping rebuild\n"); ++ return; ++ } ++ + if (ptp->state == ICE_PTP_READY) { + ice_ptp_prepare_for_reset(pf, reset_type); + } else if (ptp->state != ICE_PTP_RESETTING) { diff --git a/queue-7.1/io_uring-rw-fix-missing-erestartsys-conversion-in-read-paths.patch b/queue-7.1/io_uring-rw-fix-missing-erestartsys-conversion-in-read-paths.patch new file mode 100644 index 0000000000..8323df645a --- /dev/null +++ b/queue-7.1/io_uring-rw-fix-missing-erestartsys-conversion-in-read-paths.patch @@ -0,0 +1,100 @@ +From ab05caca123c6d0b41850b7c05b246e4dca4a770 Mon Sep 17 00:00:00 2001 +From: Yitang Yang +Date: Wed, 22 Jul 2026 20:45:51 +0800 +Subject: io_uring/rw: fix missing ERESTARTSYS conversion in read paths + +From: Yitang Yang + +commit ab05caca123c6d0b41850b7c05b246e4dca4a770 upstream. + +Both read and write may receive internal restart error codes from +the filesystem layer and should be converted to -EINTR. However, +when multishot read support was added, the error code normalization +was lost for both io_read() and io_read_mshot(). + +Extract the conversion into io_fixup_restart_res() and apply it +in all three locations: io_rw_done(), io_read(), and io_read_mshot(). + +Fixes: a08d195b586a ("io_uring/rw: split io_read() into a helper") +Cc: stable@vger.kernel.org +Signed-off-by: Yitang Yang +Link: https://patch.msgid.link/20260722124551.130563-1-yi1tang.yang@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + io_uring/rw.c | 42 +++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 17 deletions(-) + +--- a/io_uring/rw.c ++++ b/io_uring/rw.c +@@ -615,6 +615,24 @@ static void io_complete_rw_iopoll(struct + smp_store_release(&req->iopoll_completed, 1); + } + ++static inline ssize_t io_fixup_restart_res(ssize_t ret) ++{ ++ switch (ret) { ++ case -ERESTARTSYS: ++ case -ERESTARTNOINTR: ++ case -ERESTARTNOHAND: ++ case -ERESTART_RESTARTBLOCK: ++ /* ++ * We can't just restart the syscall, since previously ++ * submitted sqes may already be in progress. Just fail ++ * this IO with EINTR. ++ */ ++ return -EINTR; ++ default: ++ return ret; ++ } ++} ++ + static inline void io_rw_done(struct io_kiocb *req, ssize_t ret) + { + struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw); +@@ -624,21 +642,8 @@ static inline void io_rw_done(struct io_ + return; + + /* transform internal restart error codes */ +- if (unlikely(ret < 0)) { +- switch (ret) { +- case -ERESTARTSYS: +- case -ERESTARTNOINTR: +- case -ERESTARTNOHAND: +- case -ERESTART_RESTARTBLOCK: +- /* +- * We can't just restart the syscall, since previously +- * submitted sqes may already be in progress. Just fail +- * this IO with EINTR. +- */ +- ret = -EINTR; +- break; +- } +- } ++ if (unlikely(ret < 0)) ++ ret = io_fixup_restart_res(ret); + + if (req->flags & REQ_F_IOPOLL) + io_complete_rw_iopoll(&rw->kiocb, ret); +@@ -1034,7 +1039,8 @@ int io_read(struct io_kiocb *req, unsign + + if (req->flags & REQ_F_BUFFERS_COMMIT) + io_kbuf_recycle(req, sel.buf_list, issue_flags); +- return ret; ++ ++ return io_fixup_restart_res(ret); + } + + int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags) +@@ -1068,8 +1074,10 @@ int io_read_mshot(struct io_kiocb *req, + return IOU_RETRY; + } else if (ret <= 0) { + io_kbuf_recycle(req, sel.buf_list, issue_flags); +- if (ret < 0) ++ if (ret < 0) { ++ ret = io_fixup_restart_res(ret); + req_set_fail(req); ++ } + } else if (!(req->flags & REQ_F_APOLL_MULTISHOT)) { + cflags = io_put_kbuf(req, ret, sel.buf_list); + } else { diff --git a/queue-7.1/iomap-fix-out-of-bounds-bitmap_set-with-zero-length-range.patch b/queue-7.1/iomap-fix-out-of-bounds-bitmap_set-with-zero-length-range.patch new file mode 100644 index 0000000000..02047bf133 --- /dev/null +++ b/queue-7.1/iomap-fix-out-of-bounds-bitmap_set-with-zero-length-range.patch @@ -0,0 +1,81 @@ +From 9c7d8f7c8994c790fca501dc45ce66e7356cbe05 Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Tue, 14 Jul 2026 16:23:24 +0800 +Subject: iomap: fix out-of-bounds bitmap_set() with zero-length range + +From: Zhang Yi + +commit 9c7d8f7c8994c790fca501dc45ce66e7356cbe05 upstream. + +ifs_set_range_dirty() and ifs_set_range_uptodate() compute last_blk +as (off + len - 1) >> i_blkbits. When off is 0 and len is 0, the +unsigned subtraction underflows to SIZE_MAX, producing a huge +last_blk and nr_blks value that causes bitmap_set() to write far +beyond the ifs->state allocation. + +Regarding ifs_set_range_uptodate(), it is temporarily safe because len +cannot be passed in as 0. However, for ifs_set_range_dirty() this is +reachable from __iomap_write_end(): when copy_folio_from_iter_atomic() +returns 0 (e.g. user buffer fault) and the folio is already uptodate, +the guard at the top of __iomap_write_end() does not trigger because +!folio_test_uptodate() is false, and iomap_set_range_dirty() is called +with copied == 0. + +Add a !len guard to both functions before the computation, so that a +zero-length range is a no-op. + +Fixes: 4ce02c679722 ("iomap: Add per-block dirty state tracking to improve performance") +Cc: stable@vger.kernel.org # v6.6 +Signed-off-by: Zhang Yi +Link: https://patch.msgid.link/20260714082325.325163-5-yi.zhang@huaweicloud.com +Reviewed-by: Joanne Koong +Reviewed-by: "Darrick J. Wong" +Reviewed-by: Christoph Hellwig +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/iomap/buffered-io.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -67,11 +67,13 @@ static bool ifs_set_range_uptodate(struc + struct iomap_folio_state *ifs, size_t off, size_t len) + { + struct inode *inode = folio->mapping->host; +- unsigned int first_blk = off >> inode->i_blkbits; +- unsigned int last_blk = (off + len - 1) >> inode->i_blkbits; +- unsigned int nr_blks = last_blk - first_blk + 1; ++ unsigned int first_blk, last_blk; + +- bitmap_set(ifs->state, first_blk, nr_blks); ++ if (len) { ++ first_blk = off >> inode->i_blkbits; ++ last_blk = (off + len - 1) >> inode->i_blkbits; ++ bitmap_set(ifs->state, first_blk, last_blk - first_blk + 1); ++ } + return ifs_is_fully_uptodate(folio, ifs); + } + +@@ -203,13 +205,17 @@ static void ifs_set_range_dirty(struct f + { + struct inode *inode = folio->mapping->host; + unsigned int blks_per_folio = i_blocks_per_folio(inode, folio); +- unsigned int first_blk = (off >> inode->i_blkbits); +- unsigned int last_blk = (off + len - 1) >> inode->i_blkbits; +- unsigned int nr_blks = last_blk - first_blk + 1; ++ unsigned int first_blk, last_blk; + unsigned long flags; + ++ if (!len) ++ return; ++ ++ first_blk = off >> inode->i_blkbits; ++ last_blk = (off + len - 1) >> inode->i_blkbits; + spin_lock_irqsave(&ifs->state_lock, flags); +- bitmap_set(ifs->state, first_blk + blks_per_folio, nr_blks); ++ bitmap_set(ifs->state, first_blk + blks_per_folio, ++ last_blk - first_blk + 1); + spin_unlock_irqrestore(&ifs->state_lock, flags); + } + diff --git a/queue-7.1/iommu-vt-d-disallow-sva-if-page-walk-is-not-coherent.patch b/queue-7.1/iommu-vt-d-disallow-sva-if-page-walk-is-not-coherent.patch new file mode 100644 index 0000000000..32f525386c --- /dev/null +++ b/queue-7.1/iommu-vt-d-disallow-sva-if-page-walk-is-not-coherent.patch @@ -0,0 +1,43 @@ +From 780dfed688622ea01be3c9c2c55eec2207f05e04 Mon Sep 17 00:00:00 2001 +From: Lu Baolu +Date: Thu, 16 Jul 2026 13:35:53 +0800 +Subject: iommu/vt-d: Disallow SVA if page walk is not coherent + +From: Lu Baolu + +commit 780dfed688622ea01be3c9c2c55eec2207f05e04 upstream. + +Hardware implementations report Scalable-Mode Page-walk Coherency Support +via the SMPWCS field in the extended capability register. If the hardware +does not support page-walk coherency, a clflush is required every time +the page table entries (which are walked by the IOMMU hardware) are +updated. + +In the SVA case, page tables are managed by the CPU mm core, not by the +IOMMU driver. Because the IOMMU driver has no way of knowing whether the +CPU page table management code has ensured coherency via clflush, the +driver must deny SVA if the hardware does not support coherent paging. + +Fixes: ff3dc6521f78 ("iommu/vt-d: Fix CPU and IOMMU SVM feature matching checks") +Cc: stable@vger.kernel.org +Signed-off-by: Lu Baolu +Reviewed-by: Kevin Tian +Reviewed-by: Samiullah Khawaja +Reviewed-by: Jason Gunthorpe +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/intel/svm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/iommu/intel/svm.c ++++ b/drivers/iommu/intel/svm.c +@@ -27,7 +27,7 @@ + + void intel_svm_check(struct intel_iommu *iommu) + { +- if (!pasid_supported(iommu)) ++ if (!pasid_supported(iommu) || !ecap_smpwc(iommu->ecap)) + return; + + if (cpu_feature_enabled(X86_FEATURE_GBPAGES) && diff --git a/queue-7.1/ksmbd-defer-destroy_previous_session-until-after-ntlm-authentication.patch b/queue-7.1/ksmbd-defer-destroy_previous_session-until-after-ntlm-authentication.patch new file mode 100644 index 0000000000..6b2d0e3855 --- /dev/null +++ b/queue-7.1/ksmbd-defer-destroy_previous_session-until-after-ntlm-authentication.patch @@ -0,0 +1,60 @@ +From c74801ee524f477c174a1899782b6c3b6918d407 Mon Sep 17 00:00:00 2001 +From: James Montgomery +Date: Fri, 3 Jul 2026 15:26:41 -0400 +Subject: ksmbd: defer destroy_previous_session() until after NTLM authentication + +From: James Montgomery + +commit c74801ee524f477c174a1899782b6c3b6918d407 upstream. + +In ntlm_authenticate(), destroy_previous_session() is called using a +user pointer resolved from the client-supplied NTLM blob username field +before the NTLMv2 response is validated. An authenticated attacker can +set the NTLM blob username to match a victim account and set +PreviousSessionId to the victim's session ID; destroy_previous_session() +destroys the victim's session while ksmbd_decode_ntlmssp_auth_blob() +subsequently rejects the request with -EPERM. + +Move destroy_previous_session() and the prev_id assignment to after +ksmbd_decode_ntlmssp_auth_blob() returns success and use sess->user +rather than the pre-authentication lookup result. This matches the +ordering already used by krb5_authenticate(), where +destroy_previous_session() is called only after +ksmbd_krb5_authenticate() returns success. + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/linux-cifs/20260702155449.3639773-1-james_montgomery@disroot.org/ +Signed-off-by: James Montgomery +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smb2pdu.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -1535,11 +1535,6 @@ static int ntlm_authenticate(struct ksmb + return -EPERM; + } + +- /* Check for previous session */ +- prev_id = le64_to_cpu(req->PreviousSessionId); +- if (prev_id && prev_id != sess->id) +- destroy_previous_session(conn, user, prev_id); +- + if (sess->state == SMB2_SESSION_VALID) { + /* + * Reuse session if anonymous try to connect +@@ -1579,6 +1574,10 @@ static int ntlm_authenticate(struct ksmb + } + } + ++ prev_id = le64_to_cpu(req->PreviousSessionId); ++ if (prev_id && prev_id != sess->id) ++ destroy_previous_session(conn, sess->user, prev_id); ++ + /* + * If session state is SMB2_SESSION_VALID, We can assume + * that it is reauthentication. And the user/password diff --git a/queue-7.1/ksmbd-validate-minimum-pdu-size-for-transform-requests.patch b/queue-7.1/ksmbd-validate-minimum-pdu-size-for-transform-requests.patch new file mode 100644 index 0000000000..d41d4b84dd --- /dev/null +++ b/queue-7.1/ksmbd-validate-minimum-pdu-size-for-transform-requests.patch @@ -0,0 +1,74 @@ +From cfc0b8e5080aec87700774e8568765eaa4b7b92b Mon Sep 17 00:00:00 2001 +From: Namjae Jeon +Date: Sat, 4 Jul 2026 11:30:27 +0900 +Subject: ksmbd: validate minimum PDU size for transform requests + +From: Namjae Jeon + +commit cfc0b8e5080aec87700774e8568765eaa4b7b92b upstream. + +The receive path applies the minimum SMB2 PDU size check only when +ProtocolId is SMB2_PROTO_NUMBER. A packet carrying +SMB2_TRANSFORM_PROTO_NUM bypasses the check even when the negotiated +dialect does not provide transform handling. + +On an SMB 2.1 connection, a short transform packet therefore reaches +init_smb2_rsp_hdr(), which interprets the request as a full SMB2 header +and reads beyond the request allocation. The copied fields can then be +returned to the unauthenticated client. + +Compression transforms are converted to ordinary SMB2 messages before +protocol validation. After that conversion, validate ordinary SMB2 +requests against SMB2_MIN_SUPPORTED_PDU_SIZE and require encryption +transform requests to contain both a transform header and an SMB2 +header. This rejects truncated requests before work allocation. + +Fixes: 368ba06881c3 ("ksmbd: check the validation of pdu_size in ksmbd_conn_handler_loop") +Cc: stable@vger.kernel.org +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-31063 +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/connection.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/fs/smb/server/connection.c ++++ b/fs/smb/server/connection.c +@@ -440,6 +440,8 @@ bool ksmbd_conn_alive(struct ksmbd_conn + /* "+2" for BCC field (ByteCount, 2 bytes) */ + #define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2) + #define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu)) ++#define SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE \ ++ (sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_hdr)) + + /** + * ksmbd_conn_handler_loop() - session thread to listen on new smb requests +@@ -454,6 +456,7 @@ int ksmbd_conn_handler_loop(void *p) + struct ksmbd_conn *conn = (struct ksmbd_conn *)p; + struct ksmbd_transport *t = conn->transport; + unsigned int pdu_size, max_allowed_pdu_size, max_req; ++ __le32 proto; + char hdr_buf[4] = {0,}; + int size; + +@@ -534,11 +537,14 @@ recheck: + if (!ksmbd_smb_request(conn)) + break; + +- if (((struct smb2_hdr *)smb_get_msg(conn->request_buf))->ProtocolId == +- SMB2_PROTO_NUMBER) { +- if (pdu_size < SMB2_MIN_SUPPORTED_PDU_SIZE) +- break; +- } ++ proto = *(__le32 *)smb_get_msg(conn->request_buf); ++ if (proto == SMB2_PROTO_NUMBER && ++ pdu_size < SMB2_MIN_SUPPORTED_PDU_SIZE) ++ break; ++ ++ if (proto == SMB2_TRANSFORM_PROTO_NUM && ++ pdu_size < SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE) ++ break; + + if (!default_conn_ops.process_fn) { + pr_err("No connection request callback\n"); diff --git a/queue-7.1/libceph-bound-get_version-reply-decode-to-front-len.patch b/queue-7.1/libceph-bound-get_version-reply-decode-to-front-len.patch new file mode 100644 index 0000000000..9be426fa7c --- /dev/null +++ b/queue-7.1/libceph-bound-get_version-reply-decode-to-front-len.patch @@ -0,0 +1,47 @@ +From d3c32939fa0e3ee9b883b9a0fd1972c5c444e3d0 Mon Sep 17 00:00:00 2001 +From: Douya Le +Date: Sun, 7 Jun 2026 17:35:49 +0800 +Subject: libceph: bound get_version reply decode to front len + +From: Douya Le + +commit d3c32939fa0e3ee9b883b9a0fd1972c5c444e3d0 upstream. + +handle_get_version_reply() uses msg->front_alloc_len as the decode +boundary for MON_GET_VERSION_REPLY. That is the size of the reused +reply buffer, not the number of bytes actually received. + +A truncated reply can therefore pass ceph_decode_need() and decode the +second u64 from stale tail bytes left in the buffer by an earlier +message, causing an uninitialized memory read. + +Use msg->front.iov_len as the receive-side decode boundary, matching +other libceph reply handlers and limiting decoding to the bytes that +were actually read from the wire. + +Cc: stable@vger.kernel.org +Fixes: 513a8243d67f ("libceph: mon_get_version request infrastructure") +Reported-by: Yuan Tan +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Assisted-by: Codex:GPT-5.4 +Signed-off-by: Douya Le +Signed-off-by: Ren Wei +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/mon_client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ceph/mon_client.c ++++ b/net/ceph/mon_client.c +@@ -821,7 +821,7 @@ static void handle_get_version_reply(str + struct ceph_mon_generic_request *req; + u64 tid = le64_to_cpu(msg->hdr.tid); + void *p = msg->front.iov_base; +- void *end = p + msg->front_alloc_len; ++ void *const end = p + msg->front.iov_len; + u64 handle; + + dout("%s msg %p tid %llu\n", __func__, msg, tid); diff --git a/queue-7.1/libceph-bound-pg_-temp-upmap-upmap_items-length-to-ceph_pg_max_size.patch b/queue-7.1/libceph-bound-pg_-temp-upmap-upmap_items-length-to-ceph_pg_max_size.patch new file mode 100644 index 0000000000..9c1502b6c6 --- /dev/null +++ b/queue-7.1/libceph-bound-pg_-temp-upmap-upmap_items-length-to-ceph_pg_max_size.patch @@ -0,0 +1,68 @@ +From 9f00f9cf2be293efe899db67dc5272e3a9c62717 Mon Sep 17 00:00:00 2001 +From: Xiang Mei +Date: Mon, 8 Jun 2026 21:40:09 -0700 +Subject: libceph: bound pg_{temp,upmap,upmap_items} length to CEPH_PG_MAX_SIZE + +From: Xiang Mei + +commit 9f00f9cf2be293efe899db67dc5272e3a9c62717 upstream. + +__decode_pg_temp() decodes an user-controlled length but only rejects +values large enough to overflow the allocation; it does not bound it to +CEPH_PG_MAX_SIZE. The helper backs both pg_temp and pg_upmap decoding, and +apply_upmap()/get_temp_osds() later copy the decoded list into the fixed-size +on-stack array struct ceph_osds.osds[CEPH_PG_MAX_SIZE]. A monitor that sends +an OSDMap with a pg_temp/pg_upmap entry longer than 32 thus causes a stack +out-of-bounds write. + +An OSD set for a single PG can never exceed CEPH_PG_MAX_SIZE, so reject longer +entries at decode time. The bound is well below the old overflow threshold, so +it also covers the allocation-size overflow the previous check guarded against. + + BUG: KASAN: stack-out-of-bounds in ceph_pg_to_up_acting_osds + Write of size 4 ... by task exploit + kasan_report (mm/kasan/report.c:595) + ceph_pg_to_up_acting_osds (net/ceph/osdmap.c:2617 net/ceph/osdmap.c:2833) + calc_target (net/ceph/osd_client.c:1638) + __submit_request (net/ceph/osd_client.c:2394) + ceph_osdc_start_request (net/ceph/osd_client.c:2490) + ceph_osdc_call (net/ceph/osd_client.c:5164) + rbd_dev_image_probe (drivers/block/rbd.c:6899) + do_rbd_add (drivers/block/rbd.c:7138) + ... + kernel BUG at net/ceph/osdmap.c:2670! + +[ idryomov: do the same in __decode_pg_upmap_items() ] + +Cc: stable@vger.kernel.org +Fixes: a303bb0e5834 ("libceph: introduce and switch to decode_pg_mapping()") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Xiang Mei +Reviewed-by: Alex Markuze +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -1436,7 +1436,7 @@ static struct ceph_pg_mapping *__decode_ + ceph_decode_32_safe(p, end, len, e_inval); + if (len == 0 && incremental) + return NULL; /* new_pg_temp: [] to remove */ +- if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / sizeof(u32)) ++ if (len > CEPH_PG_MAX_SIZE) + return ERR_PTR(-EINVAL); + + ceph_decode_need(p, end, len * sizeof(u32), e_inval); +@@ -1617,7 +1617,7 @@ static struct ceph_pg_mapping *__decode_ + u32 len, i; + + ceph_decode_32_safe(p, end, len, e_inval); +- if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32))) ++ if (len > CEPH_PG_MAX_SIZE) + return ERR_PTR(-EINVAL); + + ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval); diff --git a/queue-7.1/libceph-fix-multiplication-overflow-in-decode_new_up_state_weight.patch b/queue-7.1/libceph-fix-multiplication-overflow-in-decode_new_up_state_weight.patch new file mode 100644 index 0000000000..6df62aa2d2 --- /dev/null +++ b/queue-7.1/libceph-fix-multiplication-overflow-in-decode_new_up_state_weight.patch @@ -0,0 +1,55 @@ +From 98917a499ec7064c14fc56d180a4fd636fc2784c Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Wed, 27 May 2026 16:06:17 +0200 +Subject: libceph: Fix multiplication overflow in decode_new_up_state_weight() + +From: Raphael Zimmer + +commit 98917a499ec7064c14fc56d180a4fd636fc2784c upstream. + +If a message of type CEPH_MSG_OSD_MAP contains a (maliciously) corrupted +osdmap, out-of-bounds memory accesses may occur in +decode_new_up_state_weight(). This happens because the bounds check for +the new_state part is based on calculating its length depending on a len +value read from the incoming message. This calculation may overflow +leading to an incorrect bounds check. Subsequently, out-of-bounds reads +may occur when decoding this part. + +This patch switches the multiplication to use check_mul_overflow() to +abort processing the osdmap if an overflow occurred. Therefore, +osdmaps/messages containing large values for len that result in a +multiplication overflow are treated as invalid. + +[ idryomov: rename new_state_len -> new_state_item_size, formatting ] + +Cc: stable@vger.kernel.org +Fixes: 930c53286977 ("libceph: apply new_state before new_up_client on incrementals") +Signed-off-by: Raphael Zimmer +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -1842,6 +1842,8 @@ static int decode_new_up_state_weight(vo + void *new_up_client; + void *new_state; + void *new_weight_end; ++ const u32 new_state_item_size = ++ sizeof(u32) + (struct_v >= 5 ? sizeof(u32) : sizeof(u8)); + u32 len; + int ret; + int i; +@@ -1862,7 +1864,8 @@ static int decode_new_up_state_weight(vo + + new_state = *p; + ceph_decode_32_safe(p, end, len, e_inval); +- len *= sizeof(u32) + (struct_v >= 5 ? sizeof(u32) : sizeof(u8)); ++ if (check_mul_overflow(len, new_state_item_size, &len)) ++ goto e_inval; + ceph_decode_need(p, end, len, e_inval); + *p += len; + diff --git a/queue-7.1/libceph-fix-two-unsafe-bare-decodes-in-decode_lockers.patch b/queue-7.1/libceph-fix-two-unsafe-bare-decodes-in-decode_lockers.patch new file mode 100644 index 0000000000..6af4b8bd18 --- /dev/null +++ b/queue-7.1/libceph-fix-two-unsafe-bare-decodes-in-decode_lockers.patch @@ -0,0 +1,104 @@ +From a109a556115271ca7896dcda7b4b7e45e156c227 Mon Sep 17 00:00:00 2001 +From: Pavitra Jha +Date: Tue, 2 Jun 2026 00:17:35 -0400 +Subject: libceph: fix two unsafe bare decodes in decode_lockers() + +From: Pavitra Jha + +commit a109a556115271ca7896dcda7b4b7e45e156c227 upstream. + +decode_lockers() in cls_lock_client.c contains two bare decode operations +that allow a malicious or compromised OSD to trigger slab-out-of-bounds +reads: + +1. ceph_decode_32(p) at the num_lockers field has no preceding bounds + check. ceph_start_decoding() accepts struct_len=0 as valid -- the + internal ceph_decode_need(p, end, 0, bad) always passes -- so when an + OSD sends struct_len=0, ceph_start_decoding() returns success with + p == end. The immediately following bare ceph_decode_32(p) then reads + 4 bytes past the validated buffer boundary. The garbage value is + passed directly to kzalloc_objs() as the locker count. + + The sibling function decode_watchers() in osd_client.c already uses + ceph_decode_32_safe() after its own ceph_start_decoding() call. + decode_lockers() was the only site using the bare variant. + +2. ceph_decode_8(p) after the decode_locker() loop has no preceding + bounds check. If an OSD crafts num_lockers such that the loop + advances p exactly to end, the subsequent bare ceph_decode_8(p) reads + one byte past the validated buffer boundary. The result is passed + directly into *type, which is used as a lock type discriminator by + callers, giving an OSD-controlled one-byte OOB read with direct + influence over the lock type field. + +Fix both by replacing bare operations with their safe variants: + ceph_decode_32(p) -> ceph_decode_32_safe(p, end, *num_lockers, + err_inval) + ceph_decode_8(p) -> ceph_decode_8_safe(p, end, *type, + err_free_lockers) + +The goto targets differ intentionally: + err_inval: is a new label returning -EINVAL directly. It is used for + the pre-allocation failure path where *lockers is not yet allocated + and must not be passed to ceph_free_lockers(). + + err_free_lockers: is the existing label. It is used for the + post-allocation failure path where *lockers is allocated and must + be freed. + +ret is set to -EINVAL before ceph_decode_8_safe() so that +err_free_lockers returns the correct error code on bounds violation. +Without this, err_free_lockers would return a stale ret value (0 from +the successful decode_locker() loop), silently swallowing the error. + +-EINVAL is correct for both failure paths. The data received from the +OSD is structurally malformed. -ENOMEM would misrepresent the failure +class to callers and to stable@ backporters triaging error paths. + +Attacker model: a malicious or compromised OSD in a multi-tenant Ceph +deployment can trigger this against any kernel client that issues the +lock.get_info class method (e.g. during RBD exclusive lock acquisition). + +[ idryomov: trim changelog, formatting ] + +Cc: stable@vger.kernel.org +Fixes: d4ed4a530562 ("libceph: support for lock.lock_info") +Signed-off-by: Pavitra Jha +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/cls_lock_client.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/net/ceph/cls_lock_client.c ++++ b/net/ceph/cls_lock_client.c +@@ -299,7 +299,7 @@ static int decode_lockers(void **p, void + if (ret) + return ret; + +- *num_lockers = ceph_decode_32(p); ++ ceph_decode_32_safe(p, end, *num_lockers, err_inval); + *lockers = kzalloc_objs(**lockers, *num_lockers, GFP_NOIO); + if (!*lockers) + return -ENOMEM; +@@ -310,7 +310,8 @@ static int decode_lockers(void **p, void + goto err_free_lockers; + } + +- *type = ceph_decode_8(p); ++ ret = -EINVAL; ++ ceph_decode_8_safe(p, end, *type, err_free_lockers); + s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO); + if (IS_ERR(s)) { + ret = PTR_ERR(s); +@@ -320,6 +321,9 @@ static int decode_lockers(void **p, void + *tag = s; + return 0; + ++err_inval: ++ return -EINVAL; ++ + err_free_lockers: + ceph_free_lockers(*lockers, *num_lockers); + return ret; diff --git a/queue-7.1/libceph-guard-missing-crush-type-name-lookup.patch b/queue-7.1/libceph-guard-missing-crush-type-name-lookup.patch new file mode 100644 index 0000000000..eb39aa2e66 --- /dev/null +++ b/queue-7.1/libceph-guard-missing-crush-type-name-lookup.patch @@ -0,0 +1,50 @@ +From bbeae12fda3384a90fbebc8a19ba9d33f85b5361 Mon Sep 17 00:00:00 2001 +From: Zhao Zhang +Date: Fri, 19 Jun 2026 15:40:03 +0800 +Subject: libceph: guard missing CRUSH type name lookup + +From: Zhao Zhang + +commit bbeae12fda3384a90fbebc8a19ba9d33f85b5361 upstream. + +Localized read selection can walk a parent bucket whose name exists in +the CRUSH map while its type has no matching entry in type_names. +get_immediate_parent() then dereferences a NULL type_cn and passes an +invalid pointer into strcmp(), causing a null-ptr-deref. + +Skip such malformed parent buckets unless both the bucket name and type +name metadata are present. This keeps malformed hierarchy data from +crashing locality lookup and safely falls back to "not local". + +[ idryomov: add WARN_ON_ONCE ] + +Cc: stable@vger.kernel.org +Fixes: 117d96a04f00 ("libceph: support for balanced and localized reads") +Reported-by: Yuan Tan +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Assisted-by: Codex:GPT-5.4 +Signed-off-by: Zhao Zhang +Signed-off-by: Ren Wei +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -3058,8 +3058,11 @@ static int get_immediate_parent(struct c + if (b->items[j] != id) + continue; + +- *parent_type_id = b->type; + type_cn = lookup_crush_name(&c->type_names, b->type); ++ if (WARN_ON_ONCE(!type_cn)) ++ continue; ++ ++ *parent_type_id = b->type; + parent_loc->cl_type_name = type_cn->cn_name; + parent_loc->cl_name = cn->cn_name; + return b->id; diff --git a/queue-7.1/libceph-refresh-auth-authorizer_buf-_len-after-authorizer-update.patch b/queue-7.1/libceph-refresh-auth-authorizer_buf-_len-after-authorizer-update.patch new file mode 100644 index 0000000000..bda96e22db --- /dev/null +++ b/queue-7.1/libceph-refresh-auth-authorizer_buf-_len-after-authorizer-update.patch @@ -0,0 +1,61 @@ +From 937d61f86d377a3aa578adae7a3dfcecdddf9d89 Mon Sep 17 00:00:00 2001 +From: Shuangpeng Bai +Date: Mon, 29 Jun 2026 13:14:22 -0400 +Subject: libceph: refresh auth->authorizer_buf{,_len} after authorizer update + +From: Shuangpeng Bai + +commit 937d61f86d377a3aa578adae7a3dfcecdddf9d89 upstream. + +ceph_x_create_authorizer() caches au->buf->vec.iov_base and +au->buf->vec.iov_len in struct ceph_auth_handshake. These +cached values are then used by the messenger connect code when +sending the authorizer. + +ceph_x_update_authorizer() can rebuild the authorizer when a newer +service ticket is available. If the rebuilt authorizer no longer +fits in the existing buffer, ceph_x_build_authorizer() drops its +reference to au->buf and allocates a new one. If this is the final +reference, ceph_buffer_put() frees the old ceph_buffer and its +vec.iov_base, but auth->authorizer_buf still points at that freed +memory. + +A subsequent msgr1 reconnect can therefore queue the stale pointer +and trigger a KASAN slab-use-after-free in _copy_from_iter() while +tcp_sendmsg() copies the authorizer. + +Refresh auth->authorizer_buf and auth->authorizer_buf_len after a +successful authorizer rebuild so the messenger sends the current +buffer. + +Cc: stable@vger.kernel.org +Fixes: 0bed9b5c523d ("libceph: add update_authorizer auth method") +Closes: https://lore.kernel.org/all/E378850E-106C-427B-A241-970EB2D054D7@gmail.com/ +Signed-off-by: Shuangpeng Bai +Reviewed-by: Alex Markuze +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/auth_x.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/net/ceph/auth_x.c ++++ b/net/ceph/auth_x.c +@@ -849,9 +849,16 @@ static int ceph_x_update_authorizer( + + au = (struct ceph_x_authorizer *)auth->authorizer; + if (au->secret_id < th->secret_id) { ++ int ret; ++ + dout("ceph_x_update_authorizer service %u secret %llu < %llu\n", + au->service, au->secret_id, th->secret_id); +- return ceph_x_build_authorizer(ac, th, au); ++ ret = ceph_x_build_authorizer(ac, th, au); ++ if (ret) ++ return ret; ++ ++ auth->authorizer_buf = au->buf->vec.iov_base; ++ auth->authorizer_buf_len = au->buf->vec.iov_len; + } + return 0; + } diff --git a/queue-7.1/libceph-reject-monmaps-advertising-zero-monitors.patch b/queue-7.1/libceph-reject-monmaps-advertising-zero-monitors.patch new file mode 100644 index 0000000000..670cbe84c3 --- /dev/null +++ b/queue-7.1/libceph-reject-monmaps-advertising-zero-monitors.patch @@ -0,0 +1,47 @@ +From 40480eee361ed9676b3f844d532ac28b47251634 Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Fri, 29 May 2026 09:42:57 +0200 +Subject: libceph: Reject monmaps advertising zero monitors + +From: Raphael Zimmer + +commit 40480eee361ed9676b3f844d532ac28b47251634 upstream. + +A message of type CEPH_MSG_MON_MAP contains a monmap that is sent from a +monitor to the client. This monmap contains information about the +existing monitors in the cluster. Currently, a monmap indicating that +there are zero monitors in the cluster is treated as valid. However, it +is impossible to have zero monitors in the cluster and still receive a +valid monmap from a monitor. Therefore, such a monmap must be corrupted +and should be treated as invalid. Furthermore, a monmap with a monitor +count of zero can subsequently crash the client when attempting to open +a session with a monitor in __open_session(). This happens because the +"BUG_ON(monc->monmap->num_mon < 1)" assertion in pick_new_mon() is +triggered. + +This patch extends a check in ceph_monmap_decode() to also reject +arriving mon_maps with num_mon == 0 rather than only with +num_mon > CEPH_MAX_MON. + +[ idryomov: drop "log output for unusual values of num_mon" part ] + +Cc: stable@vger.kernel.org +Signed-off-by: Raphael Zimmer +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/mon_client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ceph/mon_client.c ++++ b/net/ceph/mon_client.c +@@ -114,7 +114,7 @@ static struct ceph_monmap *ceph_monmap_d + + dout("%s fsid %pU epoch %u num_mon %u\n", __func__, &fsid, epoch, + num_mon); +- if (num_mon > CEPH_MAX_MON) ++ if (num_mon == 0 || num_mon > CEPH_MAX_MON) + goto e_inval; + + monmap = kmalloc_flex(*monmap, mon_inst, num_mon, GFP_NOIO); diff --git a/queue-7.1/libceph-reject-zero-bucket-types-in-crush_decode.patch b/queue-7.1/libceph-reject-zero-bucket-types-in-crush_decode.patch new file mode 100644 index 0000000000..fc7cdab804 --- /dev/null +++ b/queue-7.1/libceph-reject-zero-bucket-types-in-crush_decode.patch @@ -0,0 +1,46 @@ +From 05f90284223381005d6bcddab3fda4a97f9c3401 Mon Sep 17 00:00:00 2001 +From: Douya Le +Date: Fri, 29 May 2026 16:11:44 +0800 +Subject: libceph: reject zero bucket types in crush_decode + +From: Douya Le + +commit 05f90284223381005d6bcddab3fda4a97f9c3401 upstream. + +CRUSH bucket type 0 is reserved for devices. The mapper relies on +that invariant and uses type 0 to identify leaf devices. + +If crush_decode() accepts a bucket with type 0, a malformed CRUSH map +can make the mapper treat a negative bucket ID as a device and pass it +to is_out(), which then indexes the OSD weight array with a negative +value. + +Reject zero bucket types while decoding the CRUSH map so the invalid +state never reaches the mapper. + +Cc: stable@vger.kernel.org +Fixes: f24e9980eb86 ("ceph: OSD client") +Reported-by: Yuan Tan +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Assisted-by: Codex:GPT-5.4 +Signed-off-by: Douya Le +Signed-off-by: Ren Wei +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -518,6 +518,8 @@ static struct crush_map *crush_decode(vo + ceph_decode_need(p, end, 4*sizeof(u32), bad); + b->id = ceph_decode_32(p); + b->type = ceph_decode_16(p); ++ if (b->type == 0) ++ goto bad; + b->alg = ceph_decode_8(p); + if (b->alg != alg) { + b->alg = 0; diff --git a/queue-7.1/libceph-remove-debugfs-files-before-client-teardown.patch b/queue-7.1/libceph-remove-debugfs-files-before-client-teardown.patch new file mode 100644 index 0000000000..d4ddc1ffa4 --- /dev/null +++ b/queue-7.1/libceph-remove-debugfs-files-before-client-teardown.patch @@ -0,0 +1,51 @@ +From e4c804726c4afce3ba648b982d564f6af2cfa328 Mon Sep 17 00:00:00 2001 +From: Douya Le +Date: Mon, 15 Jun 2026 14:31:06 +0800 +Subject: libceph: remove debugfs files before client teardown + +From: Douya Le + +commit e4c804726c4afce3ba648b982d564f6af2cfa328 upstream. + +ceph_destroy_client() tears down the monitor client before removing +the per-client debugfs files. A concurrent read of the monmap debugfs +file can enter monmap_show() after ceph_monc_stop() has freed +monc->monmap, triggering a use-after-free. + +Remove the debugfs files before stopping the OSD and monitor clients. +debugfs_remove() drains active handlers and prevents new accesses, so +the debugfs callbacks can no longer race the rest of client teardown. + +Cc: stable@vger.kernel.org +Fixes: 76aa844d5b2f ("ceph: debugfs") +Reported-by: Yuan Tan +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Assisted-by: Codex:GPT-5.4 +Signed-off-by: Douya Le +Signed-off-by: Ren Wei +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/ceph_common.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ceph/ceph_common.c ++++ b/net/ceph/ceph_common.c +@@ -762,13 +762,13 @@ void ceph_destroy_client(struct ceph_cli + + atomic_set(&client->msgr.stopping, 1); + ++ ceph_debugfs_client_cleanup(client); ++ + /* unmount */ + ceph_osdc_stop(&client->osdc); + ceph_monc_stop(&client->monc); + ceph_messenger_fini(&client->msgr); + +- ceph_debugfs_client_cleanup(client); +- + ceph_destroy_options(client->options); + + kfree(client); diff --git a/queue-7.1/m68k-avoid-wunused-but-set-parameter-in-clear_user_page.patch b/queue-7.1/m68k-avoid-wunused-but-set-parameter-in-clear_user_page.patch new file mode 100644 index 0000000000..78b3101ef5 --- /dev/null +++ b/queue-7.1/m68k-avoid-wunused-but-set-parameter-in-clear_user_page.patch @@ -0,0 +1,61 @@ +From 955b67c3ddf9912a670ed80eae7769745b4f405e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= +Date: Mon, 25 May 2026 10:33:52 +0200 +Subject: m68k: avoid -Wunused-but-set-parameter in clear_user_page() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +commit 955b67c3ddf9912a670ed80eae7769745b4f405e upstream. + +The loop in clear_user_pages() iterates over all pages and calls +clear_user_page() for each of them. During the loop "vaddr" is modified. +However on m68k clear_user() is a macro which does not use "vaddr". The +compiler sees a variable which is modified but never used and emits a +warning for that: + +include/linux/highmem.h: In function 'clear_user_pages': +include/linux/highmem.h:234:63: warning: parameter 'vaddr' set but not used [-Wunused-but-set-parameter=] + static inline void clear_user_pages(void *addr, unsigned long vaddr, + +Other architectures use an inline function for clear_user_page() which +avoids the warning. This is not possible on m68k, as dlush_dcache_page() +is another macro which is not yet defined where clear_user_page() is +defined. Including cacheflush_mm.h will trigger recursive and lots of +other issues. + +So hide the warning with a cast to (void) instead. + +While we are here, do the same for copy_user_page(). + +Link: https://lore.kernel.org/20260525-m68k-clear_user_page-v2-1-0c8981c6eca1@weissschuh.net +Fixes: 62a9f5a85b98 ("mm: introduce clear_pages() and clear_user_pages()") +Signed-off-by: Thomas Weißschuh +Acked-by: Geert Uytterhoeven +Cc: Andreas Schwab +Cc: Ankur Arora +Cc: David Hildenbrand +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + arch/m68k/include/asm/page_mm.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/m68k/include/asm/page_mm.h ++++ b/arch/m68k/include/asm/page_mm.h +@@ -55,10 +55,12 @@ static inline void clear_page(void *page + #define clear_user_page(addr, vaddr, page) \ + do { clear_page(addr); \ + flush_dcache_page(page); \ ++ (void)(vaddr); \ + } while (0) + #define copy_user_page(to, from, vaddr, page) \ + do { copy_page(to, from); \ + flush_dcache_page(page); \ ++ (void)(vaddr); \ + } while (0) + + extern unsigned long m68k_memoffset; diff --git a/queue-7.1/mm-damon-core-disallow-overlapping-input-ranges-for-damon_set_regions.patch b/queue-7.1/mm-damon-core-disallow-overlapping-input-ranges-for-damon_set_regions.patch new file mode 100644 index 0000000000..37cb7a161d --- /dev/null +++ b/queue-7.1/mm-damon-core-disallow-overlapping-input-ranges-for-damon_set_regions.patch @@ -0,0 +1,70 @@ +From 954157679ec34661c2e87e7eb796104a797c32db Mon Sep 17 00:00:00 2001 +From: SJ Park +Date: Fri, 3 Jul 2026 09:56:08 -0700 +Subject: mm/damon/core: disallow overlapping input ranges for damon_set_regions() + +From: SJ Park + +commit 954157679ec34661c2e87e7eb796104a797c32db upstream. + +damon_set_regions() assumes the input ranges are sorted by the address and +don't overlap each other. Hence the assumption was initially to be +explicitly validated. But commit 97d482f4592f ("mm/damon/sysfs: reuse +damon_set_regions() for regions setting") has mistakenly removed the +validation. + +This can make DAMON behave in unexpected ways. At the best, the +monitoring results snapshot will just look weird since there will be +overlapping regions. DAMOS will also work weirdly, applying the same +action multiple times for overlapping regions, and make DAMOS quota weird. +More seriously, depending on the setup and regions updates sequence, +negative size regions can be made. It will trigger WARN_ONCE() if the +kernel is built with CONFIG_DAMON_DEBUG_SANITY=y. Depending on the +monitoring results, the negative size region can further trigger division +by zero in damon_merge_two_regions(). + +Note that some of the consequences including the WARN_ONCE() and the +divide by zero depend on commits that were introduced after the root cause +commit 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for +regions setting"). + +Fix the problems by checking the assumption and returning an error if +the input ranges don't meet the assumption. + +The issue was discovered [1] by Sashiko. + +Link: https://lore.kernel.org/20260703165610.92894-1-sj@kernel.org +Link: https://lore.kernel.org/20260630041806.151124-1-sj@kernel.org [1] +Fixes: 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for regions setting") +Signed-off-by: SJ Park +Cc: # 5.19.x +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/damon/core.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -240,12 +240,19 @@ int damon_set_regions(struct damon_targe + { + struct damon_region *r, *next; + unsigned int i; ++ unsigned long last_end; + int err; + + for (i = 0; i < nr_ranges; i++) { +- if (ALIGN_DOWN(ranges[i].start, min_region_sz) >= +- ALIGN(ranges[i].end, min_region_sz)) ++ unsigned long start, end; ++ ++ start = ALIGN_DOWN(ranges[i].start, min_region_sz); ++ end = ALIGN(ranges[i].end, min_region_sz); ++ if (start >= end) ++ return -EINVAL; ++ if (i > 0 && last_end > start) + return -EINVAL; ++ last_end = end; + } + + /* Remove regions which are not in the new ranges */ diff --git a/queue-7.1/mm-damon-core-validate-ranges-in-damon_set_regions.patch b/queue-7.1/mm-damon-core-validate-ranges-in-damon_set_regions.patch new file mode 100644 index 0000000000..4efbd3e9c0 --- /dev/null +++ b/queue-7.1/mm-damon-core-validate-ranges-in-damon_set_regions.patch @@ -0,0 +1,60 @@ +From 1292c0ecb1caefb8ca064a3639d5673991e8810c Mon Sep 17 00:00:00 2001 +From: SJ Park +Date: Mon, 29 Jun 2026 20:52:19 -0700 +Subject: mm/damon/core: validate ranges in damon_set_regions() + +From: SJ Park + +commit 1292c0ecb1caefb8ca064a3639d5673991e8810c upstream. + +DAMON core logic assumes zero length regions don't exist. However, a few +DAMON API callers including DAMON_SYSFS, DAMON_RECLAIM and DAMON_LRU_SORT +allow users to set empty monitoring target regions. This could result in +WARN_ONCE() on CONFIG_DAMON_DEBUG_SANITY enabled kernel, and +divide-by-zero from damon_merge_two_regions(). + +For example, the WANR_ONCE() can be triggered like below. + + # grep DAMON_DEBUG_SANITY /boot/config-$(uname -r) + # CONFIG_DAMON_DEBUG_SANITY=y + # damo start + # cd /sys/kernel/mm/damon/admin/kdamonds/0 + # echo 0 > contexts/0/targets/0/regions/0/start + # echo 0 > contexts/0/targets/0/regions/0/end + # echo commit > state + # dmesg + [....] + [ 73.705780] ------------[ cut here ]------------ + [ 73.707552] start 0 >= end 0 + [ 73.708452] WARNING: mm/damon/core.c:359 at damon_new_region+0x6e/0x80, CPU#1: kdamond.0/758 + [...] + +All DAMON API callers eventually use damon_set_regions() to setup the +regions. Add the validation logic in the function. + +Link: https://lore.kernel.org/20260630035221.146458-1-sj@kernel.org +Fixes: 43b0536cb471 ("mm/damon: introduce DAMON-based Reclamation (DAMON_RECLAIM)") +Signed-off-by: SJ Park +Cc: Yang yingliang +Cc: # 5.16.x +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/damon/core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -242,6 +242,12 @@ int damon_set_regions(struct damon_targe + unsigned int i; + int err; + ++ for (i = 0; i < nr_ranges; i++) { ++ if (ALIGN_DOWN(ranges[i].start, min_region_sz) >= ++ ALIGN(ranges[i].end, min_region_sz)) ++ return -EINVAL; ++ } ++ + /* Remove regions which are not in the new ranges */ + damon_for_each_region_safe(r, next, t) { + for (i = 0; i < nr_ranges; i++) { diff --git a/queue-7.1/mm-huge_memory-set-pg_has_hwpoisoned-only-after-new-folio-head-is-established.patch b/queue-7.1/mm-huge_memory-set-pg_has_hwpoisoned-only-after-new-folio-head-is-established.patch new file mode 100644 index 0000000000..0a9134fd78 --- /dev/null +++ b/queue-7.1/mm-huge_memory-set-pg_has_hwpoisoned-only-after-new-folio-head-is-established.patch @@ -0,0 +1,105 @@ +From e1cd30eceb6908fc13bebce41283b885d71ee8d6 Mon Sep 17 00:00:00 2001 +From: Rik van Riel +Date: Wed, 1 Jul 2026 13:42:34 -0400 +Subject: mm/huge_memory: set PG_has_hwpoisoned only after new folio head is established + +From: Rik van Riel + +commit e1cd30eceb6908fc13bebce41283b885d71ee8d6 upstream. + +__split_folio_to_order() copies the hwpoison state onto each new sub-folio +while splitting a folio to a non-zero order. It does so via + + if (handle_hwpoison && page_range_has_hwpoisoned(new_head, new_nr_pages)) + folio_set_has_hwpoisoned(new_folio); + +*before* clear_compound_head(new_head)/prep_compound_page(new_head, ...) +turns @new_head from a tail page into a proper folio head. + +PG_has_hwpoisoned is a FOLIO_SECOND_PAGE flag, so +folio_set_has_hwpoisoned() resolves to folio_flags(folio, 1). With the +new compound_info-based page-flags layout, folio_flags() asserts the page +is not a tail: + + VM_BUG_ON_PGFLAGS(page->compound_info & 1, page); + VM_BUG_ON_PGFLAGS(n > 0 && !test_bit(PG_head, &page->flags.f), page); + +At the current call site @new_head still has the tail marker +(compound_info bit 0 set, PG_head clear), so on CONFIG_DEBUG_VM kernels +this hits: + + kernel BUG at include/linux/page-flags.h:354 + folio_flags+0x82 + folio_set_has_hwpoisoned + __split_folio_to_order + __split_unmapped_folio + __folio_split + truncate_inode_partial_folio (shmem hole-punch / MADV_REMOVE) + +Reproduced by syzkaller: hwpoison-inject a few subpages of a large shmem +folio, then MADV_REMOVE (fallocate punch hole) on the same range, which +splits the partial folio to a non-zero order. + +memory_failure() tries to split the poisoned folio to order 0 first, but +that split is best-effort; when it fails the folio is left large with +PG_has_hwpoisoned set, the case fa5a06170036 added this hwpoison copying +for. + +Move the folio_set_has_hwpoisoned() call to after +clear_compound_head()/prep_compound_page(), where @new_folio is a real +order-new_order head folio (handle_hwpoison implies new_order != 0, so a +second page always exists). The flag still lands on the same struct page +(page[1] of the new folio); only the ordering relative to compound-head +setup changes, satisfying the FOLIO_SECOND_PAGE precondition. + +Link: https://lore.kernel.org/20260701174235.3173401-1-riel@surriel.com +Fixes: fa5a06170036 ("mm/huge_memory: preserve PG_has_hwpoisoned if a folio is split to >0 order") +Signed-off-by: Rik van Riel +Assisted-by: Claude:claude-opus-4-8 +Reviewed-by: Zi Yan +Acked-by: David Hildenbrand (Arm) +Tested-by: Lance Yang +Reviewed-by: Lorenzo Stoakes +Reviewed-by: Baolin Wang +Cc: Barry Song +Cc: Dev Jain +Cc: Lance Yang +Cc: Liam R. Howlett +Cc: Nico Pache +Cc: Ryan Roberts +Cc: Yang Shi +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/huge_memory.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -3649,10 +3649,6 @@ static void __split_folio_to_order(struc + (1L << PG_dropbehind) | + LRU_GEN_MASK | LRU_REFS_MASK)); + +- if (handle_hwpoison && +- page_range_has_hwpoisoned(new_head, new_nr_pages)) +- folio_set_has_hwpoisoned(new_folio); +- + new_folio->mapping = folio->mapping; + new_folio->index = folio->index + i; + +@@ -3674,6 +3670,14 @@ static void __split_folio_to_order(struc + folio_set_large_rmappable(new_folio); + } + ++ /* ++ * PG_has_hwpoisoned is on the 2nd page, so set it after ++ * the compound head is prepped. ++ */ ++ if (handle_hwpoison && ++ page_range_has_hwpoisoned(new_head, new_nr_pages)) ++ folio_set_has_hwpoisoned(new_folio); ++ + if (folio_test_young(folio)) + folio_set_young(new_folio); + if (folio_test_idle(folio)) diff --git a/queue-7.1/mm-kmemleak-fix-checksum-computation-for-per-cpu-objects.patch b/queue-7.1/mm-kmemleak-fix-checksum-computation-for-per-cpu-objects.patch new file mode 100644 index 0000000000..9fe470e3ce --- /dev/null +++ b/queue-7.1/mm-kmemleak-fix-checksum-computation-for-per-cpu-objects.patch @@ -0,0 +1,74 @@ +From 79c37ae3733e93d9d8ea12ecb44f717e61439024 Mon Sep 17 00:00:00 2001 +From: Breno Leitao +Date: Fri, 3 Jul 2026 09:17:24 -0700 +Subject: mm/kmemleak: fix checksum computation for per-cpu objects + +From: Breno Leitao + +commit 79c37ae3733e93d9d8ea12ecb44f717e61439024 upstream. + +The per-cpu object checksum folds each CPU's CRC together with XOR and +seeds every CRC with 0. Both choices make update_checksum() miss content +changes: + + - XOR is self-cancelling, so equal contents on two CPUs cancel out and + simultaneous identical changes leave the checksum unchanged. + - crc32(0, ...) over all-zero content is 0, so a freshly allocated, + zeroed per-cpu area checksums to 0, matching the initial value, and + the object is never seen to change. + +See discussions at [0]. + +When update_checksum() wrongly reports an actively modified object as +unchanged, kmemleak stops greying it for an extra scan and can report a +live per-cpu object as a leak. + +Fold the per-cpu CRC as a single rolling checksum across all CPUs and +initialise the object checksum to ~0 so the first computed value always +registers as a change, even for content that hashes to 0. +reset_checksum() is seeded the same way. + +Link: https://lore.kernel.org/all/akfYImSNDh3OjIfR@gmail.com [0] +Link: https://lore.kernel.org/20260703-kmemleak_checksum-v1-1-5e0ab7d6966f@debian.org +Fixes: 6c99d4eb7c5e ("kmemleak: enable tracking for percpu pointers") +Signed-off-by: Breno Leitao +Co-developed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +Reviewed-by: Pavel Tikhomirov +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/kmemleak.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/mm/kmemleak.c ++++ b/mm/kmemleak.c +@@ -676,7 +676,7 @@ static struct kmemleak_object *__alloc_o + atomic_set(&object->use_count, 1); + object->excess_ref = 0; + object->count = 0; /* white color initially */ +- object->checksum = 0; ++ object->checksum = ~0; + object->del_state = 0; + + /* task information */ +@@ -970,7 +970,7 @@ static void reset_checksum(unsigned long + } + + raw_spin_lock_irqsave(&object->lock, flags); +- object->checksum = 0; ++ object->checksum = ~0; + raw_spin_unlock_irqrestore(&object->lock, flags); + put_object(object); + } +@@ -1399,7 +1399,8 @@ static bool update_checksum(struct kmeml + for_each_possible_cpu(cpu) { + void *ptr = per_cpu_ptr((void __percpu *)object->pointer, cpu); + +- object->checksum ^= crc32(0, kasan_reset_tag((void *)ptr), object->size); ++ object->checksum = crc32(object->checksum, ++ kasan_reset_tag((void *)ptr), object->size); + } + } else { + object->checksum = crc32(0, kasan_reset_tag((void *)object->pointer), object->size); diff --git a/queue-7.1/mm-memory-failure-trace-change-memory_failure_event-to-ras-subsystem.patch b/queue-7.1/mm-memory-failure-trace-change-memory_failure_event-to-ras-subsystem.patch new file mode 100644 index 0000000000..ccec2e43c2 --- /dev/null +++ b/queue-7.1/mm-memory-failure-trace-change-memory_failure_event-to-ras-subsystem.patch @@ -0,0 +1,53 @@ +From e57d6e9e20b551e4910d7a6331a81775c3ad6693 Mon Sep 17 00:00:00 2001 +From: Xie Yuanbin +Date: Fri, 5 Jun 2026 16:12:13 +0800 +Subject: mm/memory-failure: trace: change memory_failure_event to ras subsystem + +From: Xie Yuanbin + +commit e57d6e9e20b551e4910d7a6331a81775c3ad6693 upstream. + +Commit 97f0b1345219 ("tracing: add trace event for memory-failure") +introduced memory_failure_event in ras subsystem. commit 31807483d395 +("mm/memory-failure: remove the selection of RAS") changed +memory_failure_event to memory_failure subsystem. This breaks the +backward compatibility, some user programs rely on it. + +Change memory_failure_event to ras subsystem to keep backward +compatibility. + +Link: https://lore.kernel.org/20260605081213.154660-1-xieyuanbin1@huawei.com +Fixes: 31807483d395 ("mm/memory-failure: remove the selection of RAS") +Signed-off-by: Xie Yuanbin +Reported-by: Yi Lai +Reported-by: Qiuxu Zhuo +Closes: https://lore.kernel.org/linux-mm/CY8PR11MB7134346A3E4BB28ECA28D6E989132@CY8PR11MB7134.namprd11.prod.outlook.com +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Qiuxu Zhuo +Reviewed-by: Lance Yang +Reviewed-by: Miaohe Lin +Tested-by: Qiuxu Zhuo +Reviewed-by: Lance Yang +Cc: Steven Rostedt +Cc: Borislav Petkov +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + include/trace/events/memory-failure.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/include/trace/events/memory-failure.h ++++ b/include/trace/events/memory-failure.h +@@ -1,6 +1,10 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + #undef TRACE_SYSTEM +-#define TRACE_SYSTEM memory_failure ++/* ++ * For historical versions, memory_failure_event is in ras subsystem, ++ * some user programs depend on it. ++ */ ++#define TRACE_SYSTEM ras + #define TRACE_INCLUDE_FILE memory-failure + + #if !defined(_TRACE_MEMORY_FAILURE_H) || defined(TRACE_HEADER_MULTI_READ) diff --git a/queue-7.1/mm-page_vma_mapped-fix-device-private-pmd-handling.patch b/queue-7.1/mm-page_vma_mapped-fix-device-private-pmd-handling.patch new file mode 100644 index 0000000000..c988f4fa97 --- /dev/null +++ b/queue-7.1/mm-page_vma_mapped-fix-device-private-pmd-handling.patch @@ -0,0 +1,118 @@ +From f84ca9b1888d8fce7dfefe0e750fa971f8797486 Mon Sep 17 00:00:00 2001 +From: Wei Yang +Date: Tue, 30 Jun 2026 02:15:40 +0000 +Subject: mm/page_vma_mapped: fix device-private PMD handling + +From: Wei Yang + +commit f84ca9b1888d8fce7dfefe0e750fa971f8797486 upstream. + +Commit 65edfda6f3f2 ("mm/rmap: extend rmap and migration support +device-private entries") introduced the concept of device-private PMD +entries, but did not correctly update the rmap walk code to account for +them. + +As a result, when page_vma_mapped_walk() encounters device-private PMD +entries, it takes no action other than to acquire the PMD lock and exit. + +However this is highly problematic for two reasons - firstly, device +private entries possess a PFN so check_pmd() needs to be called to ensure +an overlapping PFN range. + +Secondly, and more importantly, if PVMW_MIGRATION is set the caller +assumes the returned entry is a migration entry, resulting in memory +corruption when the caller tries to interpret the device private entry as +such. + +In addition, commit 146287290023 ("mm/huge_memory: implement +device-private THP splitting") allowed device private PMDs to be split +like THP mappings, but again did not update this code path. + +As a result, we might race a PMD split prior to acquiring the PMD lock. + +This patch addresses all of these issues by invoking check_pmd(), ensuring +PMVW_MIGRATION is not set and checks whether a split raced us we do for +PMD THP and migration entries. + +Instead of checking for a subset of the cases after taking the pmd_lock(), +put device-private along with pmd_trans_huge() and +pmd_is_migration_entry(). Also remove thp_migration_supported() as it is +already guarded by pmd_is_migration_entry(). + +[akpm@linux-foundation.org: fix Raspberry Pi 1 build, per David] +Link: https://lore.kernel.org/20260630021540.17297-1-richard.weiyang@gmail.com +Fixes: 65edfda6f3f2 ("mm/rmap: extend rmap and migration support device-private entries") +Signed-off-by: Wei Yang +Suggested-by: David Hildenbrand +Reviewed-by: Lance Yang +Acked-by: Balbir Singh +Tested-by: Klara Modin +Cc: SeongJae Park +Cc: Zi Yan +Cc: Lorenzo Stoakes +Cc: q +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/page_vma_mapped.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +--- a/mm/page_vma_mapped.c ++++ b/mm/page_vma_mapped.c +@@ -242,21 +242,31 @@ restart: + */ + pmde = pmdp_get_lockless(pvmw->pmd); + +- if (pmd_trans_huge(pmde) || pmd_is_migration_entry(pmde)) { ++ if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && ++ (pmd_trans_huge(pmde) || pmd_is_migration_entry(pmde) || ++ pmd_is_device_private_entry(pmde))) { + pvmw->ptl = pmd_lock(mm, pvmw->pmd); + pmde = *pvmw->pmd; +- if (!pmd_present(pmde)) { ++ if (pmd_is_migration_entry(pmde)) { + softleaf_t entry; + +- if (!thp_migration_supported() || +- !(pvmw->flags & PVMW_MIGRATION)) ++ if (!(pvmw->flags & PVMW_MIGRATION)) + return not_found(pvmw); + entry = softleaf_from_pmd(pmde); ++ if (!check_pmd(softleaf_to_pfn(entry), pvmw)) ++ return not_found(pvmw); ++ return true; ++ } else if (pmd_is_device_private_entry(pmde)) { ++ softleaf_t entry; + +- if (!softleaf_is_migration(entry) || +- !check_pmd(softleaf_to_pfn(entry), pvmw)) ++ if (pvmw->flags & PVMW_MIGRATION) ++ return not_found(pvmw); ++ entry = softleaf_from_pmd(pmde); ++ if (!check_pmd(softleaf_to_pfn(entry), pvmw)) + return not_found(pvmw); + return true; ++ } else if (!pmd_present(pmde)) { ++ return not_found(pvmw); + } + if (likely(pmd_trans_huge(pmde))) { + if (pvmw->flags & PVMW_MIGRATION) +@@ -265,17 +275,10 @@ restart: + return not_found(pvmw); + return true; + } +- /* THP pmd was split under us: handle on pte level */ ++ /* THP/device-private pmd was split under us: handle on pte level */ + spin_unlock(pvmw->ptl); + pvmw->ptl = NULL; + } else if (!pmd_present(pmde)) { +- const softleaf_t entry = softleaf_from_pmd(pmde); +- +- if (softleaf_is_device_private(entry)) { +- pvmw->ptl = pmd_lock(mm, pvmw->pmd); +- return true; +- } +- + if ((pvmw->flags & PVMW_SYNC) && + thp_vma_suitable_order(vma, pvmw->address, + PMD_ORDER) && diff --git a/queue-7.1/mm-slab-fix-a-memory-leak-due-to-bootstrapping-sheaves-twice.patch b/queue-7.1/mm-slab-fix-a-memory-leak-due-to-bootstrapping-sheaves-twice.patch new file mode 100644 index 0000000000..e32589c3f5 --- /dev/null +++ b/queue-7.1/mm-slab-fix-a-memory-leak-due-to-bootstrapping-sheaves-twice.patch @@ -0,0 +1,58 @@ +From 1dba91a0493b7ffe9cbbcf7a8df1b361ddcac515 Mon Sep 17 00:00:00 2001 +From: "Harry Yoo (Oracle)" +Date: Mon, 13 Jul 2026 23:28:49 +0900 +Subject: mm/slab: fix a memory leak due to bootstrapping sheaves twice + +From: Harry Yoo (Oracle) + +commit 1dba91a0493b7ffe9cbbcf7a8df1b361ddcac515 upstream. + +When kmalloc caches are aliased, multiple cache pointers reference +the same kmem_cache. As a result, iterating over kmalloc indices and +bootstrapping sheaves can bootstrap the same cache more than once and +leak memory. + +Currently, this could happen when the architecture specifies +minimum alignment for slab caches that is larger than +ARCH_KMALLOC_MINALIGN. + +Bootstrap sheaves only when the cache does not have them already. +Add a warning when bootstrap_cache_sheaves() is called for a cache +that already has sheaves enabled. + +Fixes: 913ffd3a1bf5 ("slab: handle kmalloc sheaves bootstrap") +Cc: stable@vger.kernel.org +Signed-off-by: Harry Yoo (Oracle) +Reviewed-by: Suren Baghdasaryan +Link: https://patch.msgid.link/20260713-kmalloc-no-objext-v3-1-47c7bd138de7@kernel.org +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Greg Kroah-Hartman +--- + mm/slub.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -8423,6 +8423,8 @@ static void __init bootstrap_cache_sheav + bool failed = false; + int node, cpu; + ++ VM_WARN_ON_ONCE(cache_has_sheaves(s)); ++ + capacity = calculate_sheaf_capacity(s, &empty_args); + + /* capacity can be 0 due to debugging or SLUB_TINY */ +@@ -8473,8 +8475,11 @@ static void __init bootstrap_kmalloc_she + + for (type = KMALLOC_NORMAL; type <= KMALLOC_RANDOM_END; type++) { + for (int idx = 0; idx < KMALLOC_SHIFT_HIGH + 1; idx++) { +- if (kmalloc_caches[type][idx]) +- bootstrap_cache_sheaves(kmalloc_caches[type][idx]); ++ struct kmem_cache *s = kmalloc_caches[type][idx]; ++ ++ /* Do not bootstrap twice when caches are aliased */ ++ if (s && !cache_has_sheaves(s)) ++ bootstrap_cache_sheaves(s); + } + } + } diff --git a/queue-7.1/mm-slab-prevent-unbounded-recursion-in-free-path-with-new-kmalloc-type.patch b/queue-7.1/mm-slab-prevent-unbounded-recursion-in-free-path-with-new-kmalloc-type.patch new file mode 100644 index 0000000000..fa64e206da --- /dev/null +++ b/queue-7.1/mm-slab-prevent-unbounded-recursion-in-free-path-with-new-kmalloc-type.patch @@ -0,0 +1,425 @@ +From d9e6a7623938968e3752b67e37eaff097e559a54 Mon Sep 17 00:00:00 2001 +From: "Harry Yoo (Oracle)" +Date: Mon, 13 Jul 2026 23:28:52 +0900 +Subject: mm/slab: prevent unbounded recursion in free path with new kmalloc type + +From: Harry Yoo (Oracle) + +commit d9e6a7623938968e3752b67e37eaff097e559a54 upstream. + +Commit 280ea9c3154b ("mm/slab: avoid allocating slabobj_ext array from +its own slab") avoided recursive allocation of obj_exts from kmalloc +caches of the same size, by bumping the obj_exts array's allocation +size whenever the array size equals the size of the object being +allocated. + +However, as reported by Danielle Costantino and Shakeel Butt, +even slabs from kmalloc caches of different sizes can form a cycle +by allocating obj_exts arrays from each other [1]: + + What happened: a KMALLOC_NORMAL slab's obj_exts array (used by + allocation profiling / memcg accounting) is itself kmalloc()'d from a + KMALLOC_NORMAL cache, so the "slab holds another slab's obj_exts array" + relation can form cycles. With sizeof(struct slabobj_ext) == 16 and + the host's geometry: + + - kmalloc-512 has 64 objects/slab -> array is 64*16 == 1024 bytes, + served from kmalloc-1k; + - kmalloc-1k has 32 objects/slab -> array is 32*16 == 512 bytes, + served from kmalloc-512. + + A kmalloc-512 slab and a kmalloc-1k slab therefore hold each other's + obj_exts array. Discarding one frees the other's array, which empties + and discards that slab, which frees the first's array, and so on: + __free_slab() -> free_slab_obj_exts() -> kfree() -> discard_slab() -> + __free_slab() recurses along the cycle until the stack is exhausted. + +With memory allocation profiling, this allows unbounded recursion +in the free path and led to a stack overflow on a production host in +the Meta fleet [1]: + + BUG: TASK stack guard page was hit + Oops: stack guard page + RIP: 0010:kfree+0x8/0x5d0 + Call Trace: + __free_slab+0x66/0xc0 + kfree+0x3f0/0x5d0 + ... ( ~125x __free_slab <-> kfree ) ... + + do_syscall_64 + +It is proposed [1] to resolve this issue by always serving the obj_exts +array allocation from kmalloc caches (or large kmalloc) of sizes larger +than the object size. However, as pointed out by Vlastimil Babka [2], +this can waste an excessive amount of memory as slabs from large +kmalloc sizes (e.g. kmalloc-8k) generally need obj_exts arrays much +smaller than the object size. + +Therefore, rather than bumping the size, let us take a different +approach; disallow formation of cycles between kmalloc types when +allocating obj_exts arrays. Currently, all obj_exts arrays are served +from normal kmalloc caches. Cycles cannot be created if obj_exts arrays +of normal kmalloc caches are served from a special kmalloc type that can +never have obj_exts arrays. + +To achieve this, create a new kmalloc type called KMALLOC_NO_OBJ_EXT. +KMALLOC_NO_OBJ_EXT caches are created with SLAB_NO_OBJ_EXT flag when +either 1) memory allocation profiling is not permanently disabled, +or 2) kmalloc types with a priority higher than KMALLOC_CGROUP are +aliased with KMALLOC_NORMAL. + +Sheaf bootstrapping for KMALLOC_NO_OBJ_EXT caches now must be deferred +because allocation of a barn can trigger obj_exts array allocation of +normal kmalloc caches when the KMALLOC_NO_OBJ_EXT cache for that size +is not ready yet. For simplicity, perform bootstrapping of sheaves for +all kmalloc caches later. + +Introduce a new slab alloc flag, SLAB_ALLOC_NO_OBJ_EXT, to prevent +allocation of obj_exts arrays, and let kmalloc_slab() override the type +to KMALLOC_NO_OBJ_EXT when specified. Note that kmalloc_type() remains +unchanged because kmalloc_flags() bypasses the kmalloc fastpath. + +Do not pass SLAB_ALLOC_NO_RECURSE to kmalloc_flags() in +alloc_slab_obj_exts() and instead use SLAB_ALLOC_NO_OBJ_EXT only when +the objects are allocated from normal kmalloc caches. While this +prevents unbounded recursive allocation of obj_exts, it allows +KMALLOC_NO_OBJ_EXT caches to have sheaves. + +Since sheaf allocations specify SLAB_ALLOC_NO_RECURSE that prevents +allocation of both sheaves and obj_exts arrays, the recursion depth +is bounded. + +obj_exts arrays for non-kmalloc-normal caches can now have a valid tag. +Do not call mark_obj_codetag_empty() when freeing an obj_exts array to +avoid false warnings. KMALLOC_NO_OBJ_EXT don't need this as they never +allocate those arrays. + +Reported-by: Danielle Costantino +Reported-by: Shakeel Butt +Closes: https://lore.kernel.org/linux-mm/20260625230029.703750-1-shakeel.butt@linux.dev [1] +Fixes: 4b8736964640 ("mm/slab: add allocation accounting into slab allocation and free paths") +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/linux-mm/c5c4208d-a6f0-413e-bad9-49be12f12d55@kernel.org [2] +Signed-off-by: Harry Yoo (Oracle) +Reviewed-by: Suren Baghdasaryan +Link: https://patch.msgid.link/20260713-kmalloc-no-objext-v3-4-47c7bd138de7@kernel.org +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/slab.h | 6 +++ + mm/slab.h | 32 ++++++++++++++-- + mm/slab_common.c | 19 +++++++++- + mm/slub.c | 90 ++++++++++++++++---------------------------- + 4 files changed, 85 insertions(+), 62 deletions(-) + +diff --git a/include/linux/slab.h b/include/linux/slab.h +index 08d7b6c9c4d6..3a14df50766a 100644 +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -708,6 +708,9 @@ enum kmalloc_cache_type { + #endif + #ifndef CONFIG_MEMCG + KMALLOC_CGROUP = KMALLOC_NORMAL, ++#endif ++#ifndef CONFIG_SLAB_OBJ_EXT ++ KMALLOC_NO_OBJ_EXT = KMALLOC_NORMAL, + #endif + KMALLOC_PARTITION_START = KMALLOC_NORMAL, + KMALLOC_PARTITION_END = KMALLOC_PARTITION_START + KMALLOC_PARTITION_CACHES_NR, +@@ -721,6 +724,9 @@ enum kmalloc_cache_type { + #endif + #ifdef CONFIG_MEMCG + KMALLOC_CGROUP, ++#endif ++#ifdef CONFIG_SLAB_OBJ_EXT ++ KMALLOC_NO_OBJ_EXT, + #endif + NR_KMALLOC_TYPES + }; +diff --git a/mm/slab.h b/mm/slab.h +index 281a65233795..f5e336b6b6b0 100644 +--- a/mm/slab.h ++++ b/mm/slab.h +@@ -22,6 +22,7 @@ + #define SLAB_ALLOC_NOLOCK 0x01 /* a kmalloc_nolock() allocation */ + #define SLAB_ALLOC_NEW_SLAB 0x02 /* a flag for alloc_slab_obj_exts() */ + #define SLAB_ALLOC_NO_RECURSE 0x04 /* prevent kmalloc() recursion */ ++#define SLAB_ALLOC_NO_OBJ_EXT 0x08 /* prevent obj_exts array allocation */ + + static inline bool alloc_flags_allow_spinning(const unsigned int alloc_flags) + { +@@ -386,12 +387,17 @@ static inline unsigned int size_index_elem(unsigned int bytes) + * KMALLOC_MAX_CACHE_SIZE and the caller must check that. + */ + static inline struct kmem_cache * +-kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, kmalloc_token_t token) ++kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, kmalloc_token_t token, ++ unsigned int alloc_flags) + { + unsigned int index; ++ enum kmalloc_cache_type type = kmalloc_type(flags, token); ++ ++ if (alloc_flags & SLAB_ALLOC_NO_OBJ_EXT) ++ type = KMALLOC_NO_OBJ_EXT; + + if (!b) +- b = &kmalloc_caches[kmalloc_type(flags, token)]; ++ b = &kmalloc_caches[type]; + if (size <= 192) + index = kmalloc_size_index[size_index_elem(size)]; + else +@@ -426,7 +432,8 @@ static inline bool is_kmalloc_normal(struct kmem_cache *s) + { + if (!is_kmalloc_cache(s)) + return false; +- return !(s->flags & (SLAB_CACHE_DMA|SLAB_ACCOUNT|SLAB_RECLAIM_ACCOUNT)); ++ ++ return !(s->flags & (SLAB_CACHE_DMA|SLAB_ACCOUNT|SLAB_RECLAIM_ACCOUNT|SLAB_NO_OBJ_EXT)); + } + + bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj); +@@ -529,6 +536,25 @@ static inline void metadata_access_disable(void) + kasan_enable_current(); + } + ++/* ++ * Return true if KMALLOC_NORMAL caches may need obj_exts arrays. ++ * ++ * Memory allocation profiling requires obj_exts for all caches. ++ * Memcg usually doesn't need them for normal kmalloc caches, but kmalloc types ++ * with a priority higher than KMALLOC_CGROUP can be aliased with KMALLOC_NORMAL. ++ */ ++static inline bool need_kmalloc_no_objext(void) ++{ ++ if (!mem_alloc_profiling_permanently_disabled()) ++ return true; ++ ++ if (!mem_cgroup_kmem_disabled() && ++ (KMALLOC_NORMAL == KMALLOC_RECLAIM)) ++ return true; ++ ++ return false; ++} ++ + #ifdef CONFIG_SLAB_OBJ_EXT + + /* +diff --git a/mm/slab_common.c b/mm/slab_common.c +index b6426d7ceec9..03ecac12cd86 100644 +--- a/mm/slab_common.c ++++ b/mm/slab_common.c +@@ -783,11 +783,15 @@ u8 kmalloc_size_index[24] __ro_after_init = { + size_t kmalloc_size_roundup(size_t size) + { + if (size && size <= KMALLOC_MAX_CACHE_SIZE) { ++ struct kmem_cache *s; ++ + /* + * The flags don't matter since size_index is common to all. + * Neither does the caller for just getting ->object_size. + */ +- return kmalloc_slab(size, NULL, GFP_KERNEL, __kmalloc_token(0))->object_size; ++ s = kmalloc_slab(size, NULL, GFP_KERNEL, __kmalloc_token(0), ++ SLAB_ALLOC_DEFAULT); ++ return s->object_size; + } + + /* Above the smaller buckets, size is a multiple of page size. */ +@@ -843,6 +847,12 @@ EXPORT_SYMBOL(kmalloc_size_roundup); + #define KMALLOC_PARTITION_NAME(N, sz) + #endif + ++#ifdef CONFIG_SLAB_OBJ_EXT ++#define KMALLOC_NO_OBJ_EXT_NAME(sz) .name[KMALLOC_NO_OBJ_EXT] = "kmalloc-no-objext-" #sz, ++#else ++#define KMALLOC_NO_OBJ_EXT_NAME(sz) ++#endif ++ + #define INIT_KMALLOC_INFO(__size, __short_size) \ + { \ + .name[KMALLOC_NORMAL] = "kmalloc-" #__short_size, \ +@@ -850,6 +860,7 @@ EXPORT_SYMBOL(kmalloc_size_roundup); + KMALLOC_CGROUP_NAME(__short_size) \ + KMALLOC_DMA_NAME(__short_size) \ + KMALLOC_PARTITION_NAME(KMALLOC_PARTITION_CACHES_NR, __short_size) \ ++ KMALLOC_NO_OBJ_EXT_NAME(__short_size) \ + .size = __size, \ + } + +@@ -957,6 +968,12 @@ new_kmalloc_cache(int idx, enum kmalloc_cache_type type) + return; + } + flags |= SLAB_ACCOUNT; ++ } else if (IS_ENABLED(CONFIG_SLAB_OBJ_EXT) && type == KMALLOC_NO_OBJ_EXT) { ++ if (!need_kmalloc_no_objext()) { ++ kmalloc_caches[type][idx] = kmalloc_caches[KMALLOC_NORMAL][idx]; ++ return; ++ } ++ flags |= SLAB_NO_OBJ_EXT | SLAB_NO_MERGE; + } else if (IS_ENABLED(CONFIG_ZONE_DMA) && (type == KMALLOC_DMA)) { + flags |= SLAB_CACHE_DMA; + } +diff --git a/mm/slub.c b/mm/slub.c +index abe748b7dddb..0337e60db5ac 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2123,42 +2123,6 @@ static inline void init_slab_obj_exts(struct slab *slab) + slab->obj_exts = 0; + } + +-/* +- * Calculate the allocation size for slabobj_ext array. +- * +- * When memory allocation profiling is enabled, the obj_exts array +- * could be allocated from the same slab cache it's being allocated for. +- * This would prevent the slab from ever being freed because it would +- * always contain at least one allocated object (its own obj_exts array). +- * +- * To avoid this, increase the allocation size when we detect the array +- * may come from the same cache, forcing it to use a different cache. +- */ +-static inline size_t obj_exts_alloc_size(struct kmem_cache *s, +- struct slab *slab, gfp_t gfp) +-{ +- size_t sz = sizeof(struct slabobj_ext) * slab->objects; +- struct kmem_cache *obj_exts_cache; +- +- if (sz > KMALLOC_MAX_CACHE_SIZE) +- return sz; +- +- if (!is_kmalloc_normal(s)) +- return sz; +- +- obj_exts_cache = kmalloc_slab(sz, NULL, gfp, __kmalloc_token(0)); +- /* +- * We can't simply compare s with obj_exts_cache, because partitioned kmalloc +- * caches have multiple caches per size, selected by caller address or type. +- * Since caller address or type may differ between kmalloc_slab() and actual +- * allocation, bump size when sizes are equal. +- */ +- if (s->object_size == obj_exts_cache->object_size) +- return obj_exts_cache->object_size + 1; +- +- return sz; +-} +- + int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s, + gfp_t gfp, unsigned int alloc_flags) + { +@@ -2168,14 +2132,18 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s, + unsigned long new_exts; + unsigned long old_exts; + struct slabobj_ext *vec; +- size_t sz; ++ size_t sz = sizeof(struct slabobj_ext) * slab->objects; + + gfp &= ~OBJCGS_CLEAR_MASK; +- /* Prevent recursive extension vector allocation */ +- alloc_flags |= SLAB_ALLOC_NO_RECURSE; +- alloc_flags &= ~SLAB_ALLOC_NEW_SLAB; ++ /* ++ * In most cases, obj_exts arrays are allocated from normal kmalloc. ++ * However, normal kmalloc caches must allocate them from ++ * KMALLOC_NO_OBJ_EXT caches to prevent recursion. ++ */ ++ if (is_kmalloc_normal(s)) ++ alloc_flags |= SLAB_ALLOC_NO_OBJ_EXT; + +- sz = obj_exts_alloc_size(s, slab, gfp); ++ alloc_flags &= ~SLAB_ALLOC_NEW_SLAB; + + /* This will use kmalloc_nolock() if alloc_flags say so */ + vec = kmalloc_flags(sz, gfp | __GFP_ZERO, alloc_flags, slab_nid(slab)); +@@ -2193,8 +2161,21 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s, + return -ENOMEM; + } + +- VM_WARN_ON_ONCE(virt_to_slab(vec) != NULL && +- virt_to_slab(vec)->slab_cache == s); ++ if (IS_ENABLED(CONFIG_DEBUG_VM)) { ++ struct kmem_cache *exts_cache; ++ struct slab *exts_slab; ++ ++ exts_slab = virt_to_slab(vec); ++ if (exts_slab) { ++ /* ++ * The vector must be allocated from either normal or ++ * KMALLOC_NO_OBJ_EXT kmalloc caches to avoid cycles. ++ */ ++ exts_cache = exts_slab->slab_cache; ++ WARN_ON_ONCE(!is_kmalloc_normal(exts_cache) && ++ !(exts_cache->flags & SLAB_NO_OBJ_EXT)); ++ } ++ } + + new_exts = (unsigned long)vec; + #ifdef CONFIG_MEMCG +@@ -2217,7 +2198,6 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s, + * assign slabobj_exts in parallel. In this case the existing + * objcg vector should be reused. + */ +- mark_obj_codetag_empty(vec); + if (unlikely(!allow_spin)) + kfree_nolock(vec); + else +@@ -2253,14 +2233,6 @@ static inline void free_slab_obj_exts(struct slab *slab, bool allow_spin) + return; + } + +- /* +- * obj_exts was created with SLAB_ALLOC_NO_RECURSE flag, therefore its +- * corresponding extension will be NULL. alloc_tag_sub() will throw a +- * warning if slab has extensions but the extension of an object is +- * NULL, therefore replace NULL with CODETAG_EMPTY to indicate that +- * the extension for obj_exts is expected to be NULL. +- */ +- mark_obj_codetag_empty(obj_exts); + if (allow_spin) + kfree(obj_exts); + else +@@ -5356,7 +5328,7 @@ void *__do_kmalloc_node(kmem_buckets *b, gfp_t flags, int node, + if (unlikely(!size)) + return ZERO_SIZE_PTR; + +- s = kmalloc_slab(size, b, flags, token); ++ s = kmalloc_slab(size, b, flags, token, ac->alloc_flags); + + ret = slab_alloc_node(s, flags, node, ac); + ret = kasan_kmalloc(s, ret, size, flags); +@@ -5419,7 +5391,9 @@ static void *__kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_f + retry: + if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) + return NULL; +- s = kmalloc_slab(size, NULL, gfp_flags, PASS_TOKEN_PARAM(token)); ++ ++ s = kmalloc_slab(size, NULL, gfp_flags, PASS_TOKEN_PARAM(token), ++ ac->alloc_flags); + + if (!(s->flags & __CMPXCHG_DOUBLE) && !kmem_cache_debug(s)) + /* +@@ -7979,10 +7953,10 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s) + s->allocflags |= __GFP_RECLAIMABLE; + + /* +- * For KMALLOC_NORMAL caches we enable sheaves later by +- * bootstrap_kmalloc_sheaves() to avoid recursion ++ * For kmalloc caches we enable sheaves later by ++ * bootstrap_kmalloc_sheaves() to avoid recursion. + */ +- if (!is_kmalloc_normal(s)) ++ if (!is_kmalloc_cache(s)) + s->sheaf_capacity = calculate_sheaf_capacity(s, args); + + /* +@@ -8548,7 +8522,7 @@ static void __init bootstrap_kmalloc_sheaves(void) + { + enum kmalloc_cache_type type; + +- for (type = KMALLOC_NORMAL; type <= KMALLOC_PARTITION_END; type++) { ++ for (type = KMALLOC_NORMAL; type < NR_KMALLOC_TYPES; type++) { + for (int idx = 0; idx < KMALLOC_SHIFT_HIGH + 1; idx++) { + struct kmem_cache *s = kmalloc_caches[type][idx]; + +-- +2.55.0 + diff --git a/queue-7.1/mm-slub-fix-lost-local-objects-when-bulk-remote-free-batch-fills.patch b/queue-7.1/mm-slub-fix-lost-local-objects-when-bulk-remote-free-batch-fills.patch new file mode 100644 index 0000000000..78c63359cc --- /dev/null +++ b/queue-7.1/mm-slub-fix-lost-local-objects-when-bulk-remote-free-batch-fills.patch @@ -0,0 +1,95 @@ +From af9ea231c0b4530edc389a3126a69e0699b7699d Mon Sep 17 00:00:00 2001 +From: Shengming Hu +Date: Mon, 6 Jul 2026 21:39:09 +0800 +Subject: mm/slub: fix lost local objects when bulk remote free batch fills + +From: Shengming Hu + +commit af9ea231c0b4530edc389a3126a69e0699b7699d upstream. + +In free_to_pcs_bulk(), when remote_objects[] fills to PCS_BATCH_MAX, +the code jumps to flush_remote to free the batch. If all remote entries +have already been compacted out of p[] via tail swaps while local objects +remain, the flush_remote path returns early since `i < size` no longer +holds. The leftover local objects are then neither cached in the sheaf +nor returned to the slab freelist, causing a memory leak. + +For illustration: + size = 64, local objects at p[0..31], remote objects at p[32..63] + After scanning all remotes: i = 32, size = 32 + p[0..31] local objects are dropped. + +Harry pointed out that, although the logic contains a real leak, it does +not appear to be triggerable with the current in-tree users. To hit this +path, at least PCS_BATCH_MAX objects, currently hardcoded to 32, need to +be collected in remote_objects[]. Looking at current kmem_cache_free_bulk() +users: + +* maple_node has sheaf_capacity = 32 +* skbuff_head_cache has sheaf_capacity = 28 +* panthor and msm drivers have sheaf_capacity = 4 + +The sheaf capacity is, at least for now, derived purely from the object +size, with the user-requested capacity used as a minimum. Therefore, among +the current users, only maple_node has a sheaf_capacity large enough to +reach PCS_BATCH_MAX. + +However, for the bug to trigger in maple_node, all objects in the sheaf +would have to be from remote nodes. In that case, there would be no local +objects left to leak. So this issue was found by code review rather than +from a runtime report, and it does not seem to be triggerable by current +users. + +Still, the bug could become reachable with future users, a different sheaf +capacity, or a change to PCS_BATCH_MAX. Fix the logic by freeing a full +remote batch in place during the scan and then continuing to process the +compacted array. This keeps all local objects on the normal fast path, +while the tail path only handles any leftover partial remote batch. The +redundant next_remote_batch jump label is removed as well. + +Fixes: 989b09b73978 ("slab: skip percpu sheaves for remote object freeing") +Signed-off-by: Shengming Hu +Link: https://patch.msgid.link/202607062139095043SOsLi6TIf403tcjPf8fm@zte.com.cn +Cc: stable@vger.kernel.org +Reviewed-by: Harry Yoo (Oracle) +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Greg Kroah-Hartman +--- + mm/slub.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -6066,7 +6066,6 @@ static void free_to_pcs_bulk(struct kmem + void *remote_objects[PCS_BATCH_MAX]; + unsigned int remote_nr = 0; + +-next_remote_batch: + while (i < size) { + struct slab *slab = virt_to_slab(p[i]); + +@@ -6081,8 +6080,11 @@ next_remote_batch: + if (unlikely(!can_free_to_pcs(slab))) { + remote_objects[remote_nr] = p[i]; + p[i] = p[--size]; +- if (++remote_nr >= PCS_BATCH_MAX) +- goto flush_remote; ++ if (++remote_nr >= PCS_BATCH_MAX) { ++ __kmem_cache_free_bulk(s, remote_nr, &remote_objects[0]); ++ stat_add(s, FREE_SLOWPATH, remote_nr); ++ remote_nr = 0; ++ } + continue; + } + +@@ -6166,10 +6168,6 @@ flush_remote: + if (remote_nr) { + __kmem_cache_free_bulk(s, remote_nr, &remote_objects[0]); + stat_add(s, FREE_SLOWPATH, remote_nr); +- if (i < size) { +- remote_nr = 0; +- goto next_remote_batch; +- } + } + } + diff --git a/queue-7.1/net-af_iucv-fix-null-deref-in-afiucv_hs_callback_syn.patch b/queue-7.1/net-af_iucv-fix-null-deref-in-afiucv_hs_callback_syn.patch new file mode 100644 index 0000000000..fa431f2295 --- /dev/null +++ b/queue-7.1/net-af_iucv-fix-null-deref-in-afiucv_hs_callback_syn.patch @@ -0,0 +1,46 @@ +From 47a5116e56a6b6fe1e909f244e39cd0fc26ceee4 Mon Sep 17 00:00:00 2001 +From: Hidayath Khan +Date: Thu, 9 Jul 2026 21:17:32 +0200 +Subject: net/af_iucv: fix NULL deref in afiucv_hs_callback_syn() + +From: Hidayath Khan + +commit 47a5116e56a6b6fe1e909f244e39cd0fc26ceee4 upstream. + +afiucv_hs_callback_syn() allocates the child socket with GFP_ATOMIC. +If the allocation fails, nsk is NULL. + +The connection-refused path is entered when the listen state check +fails, the accept backlog is full, or nsk is NULL. The code +unconditionally calls iucv_sock_kill(nsk) in that path. + +iucv_sock_kill() does not accept a NULL socket pointer and immediately +dereferences sk via sock_flag(sk, SOCK_ZAPPED). When nsk is NULL, +calling iucv_sock_kill(nsk) results in a NULL pointer dereference. + +Only call iucv_sock_kill() when a child socket was successfully +allocated. + +Fixes: 3881ac441f64 ("af_iucv: add HiperSockets transport") +Cc: stable@vger.kernel.org +Reviewed-by: Alexandra Winter +Signed-off-by: Hidayath Khan +Link: https://patch.msgid.link/20260709191732.124092-1-hidayath@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/iucv/af_iucv.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1874,7 +1874,8 @@ static int afiucv_hs_callback_syn(struct + afiucv_swap_src_dest(skb); + trans_hdr->flags = AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_FIN; + err = dev_queue_xmit(skb); +- iucv_sock_kill(nsk); ++ if (nsk) ++ iucv_sock_kill(nsk); + bh_unlock_sock(sk); + goto out; + } diff --git a/queue-7.1/net-gro-fix-double-aggregation-of-flush-marked-skbs.patch b/queue-7.1/net-gro-fix-double-aggregation-of-flush-marked-skbs.patch new file mode 100644 index 0000000000..4072337be7 --- /dev/null +++ b/queue-7.1/net-gro-fix-double-aggregation-of-flush-marked-skbs.patch @@ -0,0 +1,83 @@ +From e751256486d0ded20f5a9f9863467f1dce65142f Mon Sep 17 00:00:00 2001 +From: Shiming Cheng +Date: Thu, 9 Jul 2026 09:46:39 +0800 +Subject: net: gro: fix double aggregation of flush-marked skbs + +From: Shiming Cheng + +commit e751256486d0ded20f5a9f9863467f1dce65142f upstream. + +Commit 0ab03f353d36 ("net-gro: Fix GRO flush when receiving a GSO +packet.") added a flush check to skb_gro_receive(), but +skb_gro_receive_list() lacks the same validation. + +As a result, packets marked with NAPI_GRO_CB(skb)->flush may still be +re-aggregated. + +This allows already-GRO'd packets with existing frag_list to be +re-aggregated into a new GRO session, corrupting the frag_list chain +structure. When skb_segment() attempts to unpack these malformed packets, +it encounters invalid state and triggers a kernel panic. + +Scenario (Tethering/Device forwarding): + 1. Driver: Generated aggregated packet P1 via LRO with frag_list + 2. Dev A: Receives aggregated fraglist packet and flush flag set + 3. Dev A: Re-enters GRO, skb_gro_receive_list() is called + 4. Missing flush check allows re-aggregation despite flush flag + 5. Frag_list chain becomes corrupted (loops or dangling refs) + 6. Dev B: TX path calls skb_segment(), crashes on corrupted frag_list + +Root cause in skb_segment(): + The check at line ~4891: + if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) && + (skb_headlen(list_skb) == len || sg)) { + + When frag_list is corrupted by double aggregation, when list_skb is + a NULL pointer from skb->next, skb_headlen(list_skb) dereference + NULL/corrupted pointers occurs. + +Call Trace: + skb_headlen(NULL skb) + skb_segment + tcp_gso_segment + tcp4_gso_segment + inet_gso_segment + skb_mac_gso_segment + __skb_gso_segment + skb_gso_segment + validate_xmit_skb + validate_xmit_skb_list + sch_direct_xmit + qdisc_restart + __qdisc_run + qdisc_run + net_tx_action + +Fix: Add NAPI_GRO_CB(skb)->flush validation to the early-return check in +skb_gro_receive_list(), matching the defensive programming pattern of +skb_gro_receive(). + +Fixes: 3a1296a38d0c ("net: Support GRO/GSO fraglist chaining.") +Cc: stable@vger.kernel.org +Signed-off-by: Shiming Cheng +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260709014704.3625-1-shiming.cheng@mediatek.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/core/gro.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/net/core/gro.c ++++ b/net/core/gro.c +@@ -229,7 +229,9 @@ done: + + int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) + { +- if (unlikely(p->len + skb->len >= 65536)) ++ /* make sure to check flush flag and to not merge */ ++ if (unlikely(p->len + skb->len >= 65536 || ++ NAPI_GRO_CB(skb)->flush)) + return -E2BIG; + + if (!pskb_may_pull(skb, skb_gro_offset(skb))) { diff --git a/queue-7.1/net-hip04-fix-rx-buffer-leak-on-build_skb-failure.patch b/queue-7.1/net-hip04-fix-rx-buffer-leak-on-build_skb-failure.patch new file mode 100644 index 0000000000..60ef3a03c8 --- /dev/null +++ b/queue-7.1/net-hip04-fix-rx-buffer-leak-on-build_skb-failure.patch @@ -0,0 +1,64 @@ +From 14fa65d10f5696b063a7d8d26e8291ea84a2c6ed Mon Sep 17 00:00:00 2001 +From: Fan Wu +Date: Sun, 12 Jul 2026 14:27:29 +0000 +Subject: net: hip04: fix RX buffer leak on build_skb failure + +From: Fan Wu + +commit 14fa65d10f5696b063a7d8d26e8291ea84a2c6ed upstream. + +When build_skb() fails in hip04_rx_poll(), the driver jumps to the +refill path without releasing the current RX buffer and its DMA mapping. +Installing a replacement buffer then overwrites the slot references and +leaks both resources. + +Keep the current slot intact and return budget so NAPI retries the same +buffer. Also free a newly allocated RX fragment when dma_map_single() +fails. + +This issue was found by an in-house static analysis tool. + +Fixes: 701a0fd52318 ("hip04_eth: fix missing error handle for build_skb failed") +Cc: stable@vger.kernel.org +Signed-off-by: Fan Wu +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260712142729.2057636-1-fanwu01@zju.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/hisilicon/hip04_eth.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/hisilicon/hip04_eth.c ++++ b/drivers/net/ethernet/hisilicon/hip04_eth.c +@@ -594,7 +594,11 @@ static int hip04_rx_poll(struct napi_str + skb = build_skb(buf, priv->rx_buf_size); + if (unlikely(!skb)) { + net_dbg_ratelimited("build_skb failed\n"); +- goto refill; ++ /* Retain the slot; return budget so NAPI retries this ++ * buffer. Refill would overwrite rx_buf[]/rx_phys[] ++ * and leak them. ++ */ ++ return budget; + } + + dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head], +@@ -622,14 +626,15 @@ static int hip04_rx_poll(struct napi_str + rx++; + } + +-refill: + buf = netdev_alloc_frag(priv->rx_buf_size); + if (!buf) + goto done; + phys = dma_map_single(priv->dev, buf, + RX_BUF_SIZE, DMA_FROM_DEVICE); +- if (dma_mapping_error(priv->dev, phys)) ++ if (dma_mapping_error(priv->dev, phys)) { ++ skb_free_frag(buf); + goto done; ++ } + priv->rx_buf[priv->rx_head] = buf; + priv->rx_phys[priv->rx_head] = phys; + hip04_set_recv_desc(priv, phys); diff --git a/queue-7.1/net-iucv-fix-use-after-free-of-a-severed-iucv_path.patch b/queue-7.1/net-iucv-fix-use-after-free-of-a-severed-iucv_path.patch new file mode 100644 index 0000000000..a672db88e3 --- /dev/null +++ b/queue-7.1/net-iucv-fix-use-after-free-of-a-severed-iucv_path.patch @@ -0,0 +1,61 @@ +From be7cc4656eb1f54029610e82d1f0fdd3f9b5ec0a Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Tue, 7 Jul 2026 02:00:54 -0500 +Subject: net/iucv: fix use-after-free of a severed iucv_path + +From: Bryam Vargas + +commit be7cc4656eb1f54029610e82d1f0fdd3f9b5ec0a upstream. + +af_iucv queues not-yet-received message notifications on iucv->message_q, +each holding a raw pointer to the connection's iucv_path. When the peer +severs the connection, iucv_sever_path() frees that path with +iucv_path_free() but leaves the notifications queued. A later recvmsg() +drains message_q via iucv_process_message_q() and hands the stale path to +message_receive() -- a use-after-free of the freed iucv_path. + +Drop the queued notifications when the path is severed; once the path is +gone they can no longer be received. This also frees the notifications +leaked when a socket is closed with messages still queued. + +Fixes: f0703c80e515 ("[AF_IUCV]: postpone receival of iucv-packets") +Closes: https://sashiko.dev/#/patchset/20260705-b4-disp-fc79c0dc-v1-1-d2cdcb57afa9@proton.me?part=1 +Cc: stable@vger.kernel.org +Signed-off-by: Bryam Vargas +Link: https://patch.msgid.link/20260707-b4-disp-783fedbb-v1-1-463b9dbda2ea@proton.me +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/iucv/af_iucv.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -336,6 +336,7 @@ static void iucv_sever_path(struct sock + unsigned char user_data[16]; + struct iucv_sock *iucv = iucv_sk(sk); + struct iucv_path *path = iucv->path; ++ struct sock_msg_q *p, *n; + + /* Whoever resets the path pointer, must sever and free it. */ + if (xchg(&iucv->path, NULL)) { +@@ -347,6 +348,19 @@ static void iucv_sever_path(struct sock + } else + pr_iucv->path_sever(path, NULL); + iucv_path_free(path); ++ ++ /* ++ * Message notifications queued on message_q still reference ++ * the now freed path; drop them, otherwise a later recvmsg() ++ * would pass the freed iucv_path to message_receive() via ++ * iucv_process_message_q(). ++ */ ++ spin_lock_bh(&iucv->message_q.lock); ++ list_for_each_entry_safe(p, n, &iucv->message_q.list, list) { ++ list_del(&p->list); ++ kfree(p); ++ } ++ spin_unlock_bh(&iucv->message_q.lock); + } + } + diff --git a/queue-7.1/net-mlx5e-use-sender-devcom-for-mpv-master-up.patch b/queue-7.1/net-mlx5e-use-sender-devcom-for-mpv-master-up.patch new file mode 100644 index 0000000000..b07564416e --- /dev/null +++ b/queue-7.1/net-mlx5e-use-sender-devcom-for-mpv-master-up.patch @@ -0,0 +1,78 @@ +From e32649b4bad90a6216d8e93cd7dd050af8ac9740 Mon Sep 17 00:00:00 2001 +From: Manjunath Patil +Date: Tue, 7 Jul 2026 16:39:11 -0700 +Subject: net/mlx5e: Use sender devcom for MPV master-up + +From: Manjunath Patil + +commit e32649b4bad90a6216d8e93cd7dd050af8ac9740 upstream. + +After PCIe DPC recovery, mlx5 reloads the affected functions and +replays multiport affiliation events. In the reported failure, the +first relevant device error was: + + pcieport 0000:10:01.1: DPC: containment event + pcieport 0000:10:01.1: PCIe Bus Error: severity=Uncorrected (Fatal) + pcieport 0000:10:01.1: [ 5] SDES (First) + +mlx5 recovered the PCI functions and resumed 0000:11:00.1. During +that resume, RDMA multiport binding replayed +MLX5_DRIVER_EVENT_AFFILIATION_DONE and mlx5e sent +MPV_DEVCOM_MASTER_UP. The host then panicked with: + + BUG: kernel NULL pointer dereference, address: 0000000000000010 + RIP: mlx5_devcom_comp_set_ready+0x5/0x40 [mlx5_core] + RDI: 0000000000000000 + +Call trace included: + + mlx5_devcom_comp_set_ready + mlx5e_devcom_event_mpv + mlx5_devcom_send_event + mlx5_ib_bind_slave_port + mlx5r_mp_probe + mlx5_pci_resume + +MPV devcom registration publishes mlx5e private data to the component +peer list before mlx5e_devcom_init_mpv() stores the returned component +device in priv->devcom. A concurrent master-up event can therefore +reach a peer whose private data is visible but whose priv->devcom +backpointer is still NULL. + +MPV_DEVCOM_MASTER_UP already carries the sender/master mlx5e private +data as event_data. The ready bit is stored on the shared devcom +component, not on an individual peer. Use the sender devcom when +marking the MPV component ready. + +This preserves the readiness transition while avoiding a NULL +dereference of the peer devcom pointer during affiliation replay after +PCI error recovery. + +Fixes: bf11485f8419 ("net/mlx5: Register mlx5e priv to devcom in MPV mode") +Assisted-by: Codex:gpt-5 +Signed-off-by: Manjunath Patil +Cc: stable@vger.kernel.org # 6.7+ +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260707233911.3651139-1-manjunath.b.patil@oracle.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -211,11 +211,11 @@ static void mlx5e_disable_async_events(s + + static int mlx5e_devcom_event_mpv(int event, void *my_data, void *event_data) + { +- struct mlx5e_priv *slave_priv = my_data; ++ struct mlx5e_priv *master_priv = event_data; + + switch (event) { + case MPV_DEVCOM_MASTER_UP: +- mlx5_devcom_comp_set_ready(slave_priv->devcom, true); ++ mlx5_devcom_comp_set_ready(master_priv->devcom, true); + break; + case MPV_DEVCOM_MASTER_DOWN: + /* no need for comp set ready false since we unregister after diff --git a/queue-7.1/net-pcs-xpcs-fix-sgmii-state-reading.patch b/queue-7.1/net-pcs-xpcs-fix-sgmii-state-reading.patch new file mode 100644 index 0000000000..46916f01af --- /dev/null +++ b/queue-7.1/net-pcs-xpcs-fix-sgmii-state-reading.patch @@ -0,0 +1,114 @@ +From def9a4745e105145133e442dd8a1c126caf0f553 Mon Sep 17 00:00:00 2001 +From: Coia Prant +Date: Fri, 17 Jul 2026 15:43:25 +0800 +Subject: net: pcs: xpcs: fix SGMII state reading + +From: Coia Prant + +commit def9a4745e105145133e442dd8a1c126caf0f553 upstream. + +Commit 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode") +added a path in xpcs_get_state_c37_sgmii() that reads speed/duplex from +BMCR after AN completes. However, BMCR does not reflect the negotiated +result on the hardware where this has been tested: + +- On RK3568 (MAC side SGMII), BMCR returns a fixed hardware reset value +- Wangxun engineer Jiawen Wu confirmed that on their side, "BMCR looks + like it only wants to be return as 0" [0] + +The correct information is available in CL37_ANSGM_STS, which contains +the actual link status and negotiated speed/duplex. + +This bug was previously masked by phylink core, which overrides the PCS +link state with the PHY state when a PHY is present: + + /* If we have a phy, the "up" state is the union of both the + * PHY and the MAC + */ + if (phy) + link_state.link &= pl->phy_state.link; + +Thus, when the link is down, the PHY's link_down state is applied on top +of whatever the PCS reports, hiding the broken PCS state reading path. + +Modify xpcs_get_state_c37_sgmii() to: +1. Read link state from CL37_ANSGM_STS +2. If link is up, report speed/duplex from CL37_ANSGM_STS +3. Remove the broken BMCR reading path entirely + +Also properly set state->an_complete to reflect the AN completion status, +and clear CL37_ANCMPLT_INTR when link is down to avoid stale state. + +[0] https://lore.kernel.org/all/000c01dd1593$2ac0b0f0$804212d0$@trustnetic.com/ + +Fixes: 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode") +Cc: stable@vger.kernel.org +Tested-by: Jiawen Wu +Signed-off-by: Coia Prant +Tested-by: Maxime Chevallier +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260717074324.3250043-2-coiaprant@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/pcs/pcs-xpcs.c | 32 +++++++------------------------- + 1 file changed, 7 insertions(+), 25 deletions(-) + +--- a/drivers/net/pcs/pcs-xpcs.c ++++ b/drivers/net/pcs/pcs-xpcs.c +@@ -1058,6 +1058,7 @@ static int xpcs_get_state_c37_sgmii(stru + + /* Reset link_state */ + state->link = false; ++ state->an_complete = false; + state->speed = SPEED_UNKNOWN; + state->duplex = DUPLEX_UNKNOWN; + state->pause = 0; +@@ -1069,6 +1070,8 @@ static int xpcs_get_state_c37_sgmii(stru + if (ret < 0) + return ret; + ++ state->an_complete = ret & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR; ++ + if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) { + int speed_value; + +@@ -1086,34 +1089,13 @@ static int xpcs_get_state_c37_sgmii(stru + state->duplex = DUPLEX_FULL; + else + state->duplex = DUPLEX_HALF; +- } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) { +- int speed, duplex; +- +- state->link = true; +- +- speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR); +- if (speed < 0) +- return speed; + +- speed &= BMCR_SPEED100 | BMCR_SPEED1000; +- if (speed == BMCR_SPEED1000) +- state->speed = SPEED_1000; +- else if (speed == BMCR_SPEED100) +- state->speed = SPEED_100; +- else if (speed == 0) +- state->speed = SPEED_10; +- +- duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE); +- if (duplex < 0) +- return duplex; +- +- if (duplex & ADVERTISE_1000XFULL) +- state->duplex = DUPLEX_FULL; +- else if (duplex & ADVERTISE_1000XHALF) +- state->duplex = DUPLEX_HALF; ++ return 0; ++ } + ++ /* Clear AN complete status or interrupt */ ++ if (state->an_complete) + xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0); +- } + + return 0; + } diff --git a/queue-7.1/net-qrtr-ns-raise-node-count-limit-to-512.patch b/queue-7.1/net-qrtr-ns-raise-node-count-limit-to-512.patch new file mode 100644 index 0000000000..2b0f3bc5f9 --- /dev/null +++ b/queue-7.1/net-qrtr-ns-raise-node-count-limit-to-512.patch @@ -0,0 +1,38 @@ +From ff194cffd586cbd4cc49eccb002c65f2a902a277 Mon Sep 17 00:00:00 2001 +From: Youssef Samir +Date: Mon, 13 Jul 2026 16:59:01 +0200 +Subject: net: qrtr: ns: Raise node count limit to 512 + +From: Youssef Samir + +commit ff194cffd586cbd4cc49eccb002c65f2a902a277 upstream. + +The current node limit of 64 breaks the functionality for a number of AI200 +deployments that have up to 384 nodes. Raise the limit to 512. + +Fixes: 27d5e84e810b ("net: qrtr: ns: Limit the total number of nodes") +Cc: stable@vger.kernel.org +Signed-off-by: Youssef Samir +Link: https://patch.msgid.link/20260713145901.212396-1-youssef.abdulrahman@oss.qualcomm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/qrtr/ns.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/qrtr/ns.c ++++ b/net/qrtr/ns.c +@@ -76,11 +76,11 @@ struct qrtr_node { + * requirements. If the requirement changes in the future, these values can be + * increased. + */ +-#define QRTR_NS_MAX_NODES 64 ++#define QRTR_NS_MAX_NODES 512 + #define QRTR_NS_MAX_SERVERS 256 + #define QRTR_NS_MAX_LOOKUPS 64 + +-static u8 node_count; ++static u16 node_count; + + static struct qrtr_node *node_get(unsigned int node_id) + { diff --git a/queue-7.1/net-sched-serialize-qdisc_rtab_list-against-concurrent-get-put.patch b/queue-7.1/net-sched-serialize-qdisc_rtab_list-against-concurrent-get-put.patch new file mode 100644 index 0000000000..731397d195 --- /dev/null +++ b/queue-7.1/net-sched-serialize-qdisc_rtab_list-against-concurrent-get-put.patch @@ -0,0 +1,133 @@ +From f43ee0c0730d6191629b5ee1ceae27b1ebfdc047 Mon Sep 17 00:00:00 2001 +From: Aldo Ariel Panzardo +Date: Wed, 15 Jul 2026 08:41:14 -0300 +Subject: net/sched: serialize qdisc_rtab_list against concurrent get/put + +From: Aldo Ariel Panzardo + +commit f43ee0c0730d6191629b5ee1ceae27b1ebfdc047 upstream. + +qdisc_get_rtab() and qdisc_put_rtab() mutate the process-global singly +linked list qdisc_rtab_list and a plain non-atomic 'int refcnt' with no +lock. This was only safe because every caller historically held the RTNL +mutex, which serialized all rate-table lookups, inserts and frees. + +That invariant no longer holds. cls_flower sets +TCF_PROTO_OPS_DOIT_UNLOCKED, so tc_new_tfilter() keeps rtnl_held == false +for it and sets TCA_ACT_FLAGS_NO_RTNL. That flag propagates through +tcf_exts_validate_ex() -> tcf_action_init() -> tcf_action_init_1() -> +tcf_police_init(), which calls qdisc_get_rtab()/qdisc_put_rtab() with the +RTNL mutex NOT held. Two RTM_NEWTFILTER requests on different CPUs, each +adding a flower filter with a police action carrying the same rate, then +race on qdisc_rtab_list and on the non-atomic refcnt, leading to a +use-after-free / double-free of the kmalloc-2k struct qdisc_rate_table. +qdisc_rtab_list is a single global (not per-netns), so the corrupted +object is shared system-wide. + + BUG: KASAN: slab-use-after-free in qdisc_put_rtab+0x12f/0x160 + qdisc_put_rtab+0x12f/0x160 + tcf_police_init+0xda9/0x1590 + tcf_action_init_1+0x460/0x6b0 + tcf_action_init+0x439/0xa40 + tcf_exts_validate_ex+0x42d/0x550 + fl_change+0xddd/0x7da0 + tc_new_tfilter+0xaa7/0x2420 + rtnetlink_rcv_msg+0x95e/0xe90 + which belongs to the cache kmalloc-2k of size 2048 + +Protect qdisc_rtab_list and the refcount with a dedicated spinlock. The +(sleeping, GFP_KERNEL) allocation in qdisc_get_rtab() is performed before +taking the lock; if a concurrent inserter added an identical table in the +meantime the freshly allocated one is freed under the lock, so no +duplicate is leaked. qdisc_put_rtab() now decrements the refcount and +unlinks under the same lock. + +Fixes: 470502de5bdb ("net: sched: unlock rules update API") +Suggested-by: Eric Dumazet +Signed-off-by: Aldo Ariel Panzardo +Cc: stable@vger.kernel.org +Acked-by: Jamal Hadi Salim +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260715114114.446841-1-qwe.aldo@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sched/sch_api.c | 24 +++++++++++++++++++----- + 1 file changed, 19 insertions(+), 5 deletions(-) + +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -415,12 +415,13 @@ static __u8 __detect_linklayer(struct tc + } + + static struct qdisc_rate_table *qdisc_rtab_list; ++static DEFINE_SPINLOCK(qdisc_rtab_lock); + + struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, + struct nlattr *tab, + struct netlink_ext_ack *extack) + { +- struct qdisc_rate_table *rtab; ++ struct qdisc_rate_table *rtab, *new_rtab; + + if (tab == NULL || r->rate == 0 || + r->cell_log == 0 || r->cell_log >= 32 || +@@ -429,15 +430,20 @@ struct qdisc_rate_table *qdisc_get_rtab( + return NULL; + } + ++ new_rtab = kmalloc_obj(*new_rtab); ++ ++ spin_lock(&qdisc_rtab_lock); + for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) { + if (!memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) && + !memcmp(&rtab->data, nla_data(tab), TC_RTAB_SIZE)) { + rtab->refcnt++; ++ spin_unlock(&qdisc_rtab_lock); ++ kfree(new_rtab); + return rtab; + } + } + +- rtab = kmalloc_obj(*rtab); ++ rtab = new_rtab; + if (rtab) { + rtab->rate = *r; + rtab->refcnt = 1; +@@ -449,6 +455,7 @@ struct qdisc_rate_table *qdisc_get_rtab( + } else { + NL_SET_ERR_MSG(extack, "Failed to allocate new qdisc rate table"); + } ++ spin_unlock(&qdisc_rtab_lock); + return rtab; + } + EXPORT_SYMBOL(qdisc_get_rtab); +@@ -457,18 +464,25 @@ void qdisc_put_rtab(struct qdisc_rate_ta + { + struct qdisc_rate_table *rtab, **rtabp; + +- if (!tab || --tab->refcnt) ++ if (!tab) ++ return; ++ ++ spin_lock(&qdisc_rtab_lock); ++ if (--tab->refcnt) { ++ spin_unlock(&qdisc_rtab_lock); + return; ++ } + + for (rtabp = &qdisc_rtab_list; + (rtab = *rtabp) != NULL; + rtabp = &rtab->next) { + if (rtab == tab) { + *rtabp = rtab->next; +- kfree(rtab); +- return; ++ break; + } + } ++ spin_unlock(&qdisc_rtab_lock); ++ kfree(tab); + } + EXPORT_SYMBOL(qdisc_put_rtab); + diff --git a/queue-7.1/net-slip-serialize-receive-against-buffer-reallocation.patch b/queue-7.1/net-slip-serialize-receive-against-buffer-reallocation.patch new file mode 100644 index 0000000000..65040783ca --- /dev/null +++ b/queue-7.1/net-slip-serialize-receive-against-buffer-reallocation.patch @@ -0,0 +1,51 @@ +From ee7f9bb9320add61f7b367d7e6cd55e3a3a4d65d Mon Sep 17 00:00:00 2001 +From: Sungmin Kang <726ksm@gmail.com> +Date: Sat, 18 Jul 2026 16:36:30 +0900 +Subject: net: slip: serialize receive against buffer reallocation + +From: Sungmin Kang <726ksm@gmail.com> + +commit ee7f9bb9320add61f7b367d7e6cd55e3a3a4d65d upstream. + +sl_realloc_bufs() replaces rbuff and updates buffsize while holding +sl->lock. slip_receive_buf() reads those fields and writes through rbuff +without holding the lock. + +An MTU change can therefore race with receive processing. An MTU shrink +can expose the new smaller rbuff with the old larger bound, causing an +out-of-bounds write. A receive callback which already loaded the old +rbuff can instead continue writing after that buffer has been freed. + +Serialize receive processing with sl_realloc_bufs() by holding sl->lock +while consuming each receive batch. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Sungmin Kang <726ksm@gmail.com> +Link: https://patch.msgid.link/20260718073631.1674-1-726ksm@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/slip/slip.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/slip/slip.c ++++ b/drivers/net/slip/slip.c +@@ -693,6 +693,8 @@ static void slip_receive_buf(struct tty_ + if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) + return; + ++ spin_lock_bh(&sl->lock); ++ + /* Read the characters out of the buffer */ + while (count--) { + if (fp && *fp++) { +@@ -708,6 +710,8 @@ static void slip_receive_buf(struct tty_ + #endif + slip_unesc(sl, *cp++); + } ++ ++ spin_unlock_bh(&sl->lock); + } + + /************************************ diff --git a/queue-7.1/net-stmmac-intel-skip-serdes-reconfig-when-rate-is-unchanged.patch b/queue-7.1/net-stmmac-intel-skip-serdes-reconfig-when-rate-is-unchanged.patch new file mode 100644 index 0000000000..ca9bdad20e --- /dev/null +++ b/queue-7.1/net-stmmac-intel-skip-serdes-reconfig-when-rate-is-unchanged.patch @@ -0,0 +1,98 @@ +From 0ab78ead2481adb52f9eb5b403865c529f6f2348 Mon Sep 17 00:00:00 2001 +From: Markus Breitenberger +Date: Mon, 13 Jul 2026 19:16:19 +0200 +Subject: net: stmmac: intel: skip SerDes reconfig when rate is unchanged + +From: Markus Breitenberger + +commit 0ab78ead2481adb52f9eb5b403865c529f6f2348 upstream. + +intel_mac_finish() is registered as the phylink mac_finish() +callback for the Elkhart Lake SGMII ports. phylink calls it at +the end of every major link reconfiguration, including the +initial one during probe. + +The callback selects the PMC ModPHY LCPLL programming for the +requested MAC-side interface and then power-cycles the SerDes. +On Elkhart Lake that ModPHY is also used by the on-die AHCI +SATA PHY. Reapplying the programming during the initial +boot-time link-up disturbs the shared analog block while it is +still driving SATA, so the SATA link fails to train: + + ata1: SATA link down (SStatus 1 SControl 300) + +The disk carrying the root filesystem is never detected and the +system hangs at rootwait. Ethernet itself comes up normally, +which makes the failure look unrelated to the network driver. + +Before mac_finish() runs, the legacy SerDes power-up path has +already programmed SERDES_GCR0 for the current interface. The +1G and 2.5G ModPHY tables selected by mac_finish() correspond +to the SerDes lane rate, so read that rate back from SERDES_GCR0 +and skip the PMC reprogramming and SerDes power-cycle when it +already matches the selected interface. + +This keeps the disruptive reprogramming out of the boot path +when the SerDes is configured correctly, while preserving the +previous behavior when a real SGMII/1000BASE-X to 2500BASE-X +rate change is needed. If the register read fails, reconfigure +as before. + +Fixes: a42f6b3f1cc1 ("net: stmmac: configure SerDes according to the interface mode") +Cc: stable@vger.kernel.org +Signed-off-by: Markus Breitenberger +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260713171619.192452-1-bre@breiti.cc +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 31 ++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +@@ -524,6 +524,32 @@ static int intel_set_reg_access(const st + return ret; + } + ++/* ++ * Return true if the SerDes lane rate must change to serve @interface. ++ * If the current rate cannot be determined, reconfigure as before. ++ */ ++static bool intel_serdes_needs_reconfig(struct stmmac_priv *priv, ++ struct intel_priv_data *intel_priv, ++ phy_interface_t interface) ++{ ++ u32 cur_rate, want_rate; ++ int data; ++ ++ if (!intel_priv->mdio_adhoc_addr) ++ return true; ++ ++ data = mdiobus_read(priv->mii, intel_priv->mdio_adhoc_addr, ++ SERDES_GCR0); ++ if (data < 0) ++ return true; ++ ++ cur_rate = (data & SERDES_RATE_MASK) >> SERDES_RATE_PCIE_SHIFT; ++ want_rate = interface == PHY_INTERFACE_MODE_2500BASEX ? ++ SERDES_RATE_PCIE_GEN2 : SERDES_RATE_PCIE_GEN1; ++ ++ return cur_rate != want_rate; ++} ++ + static int intel_mac_finish(struct net_device *ndev, + void *intel_data, + unsigned int mode, +@@ -535,6 +561,11 @@ static int intel_mac_finish(struct net_d + int max_regs = 0; + int ret = 0; + ++ if (!intel_serdes_needs_reconfig(priv, intel_priv, interface)) { ++ priv->plat->phy_interface = interface; ++ return 0; ++ } ++ + ret = intel_tsn_lane_is_available(ndev, intel_priv); + if (ret < 0) { + netdev_info(priv->dev, "No TSN lane available to set the registers.\n"); diff --git a/queue-7.1/net-x25-fix-use-after-free-in-x25_kill_by_neigh.patch b/queue-7.1/net-x25-fix-use-after-free-in-x25_kill_by_neigh.patch new file mode 100644 index 0000000000..d349400ead --- /dev/null +++ b/queue-7.1/net-x25-fix-use-after-free-in-x25_kill_by_neigh.patch @@ -0,0 +1,66 @@ +From 5499e0602d2faafd42c580d25f615903c3fbe11b Mon Sep 17 00:00:00 2001 +From: David Lee +Date: Mon, 13 Jul 2026 10:47:50 +0000 +Subject: net/x25: fix use-after-free in x25_kill_by_neigh() + +From: David Lee + +commit 5499e0602d2faafd42c580d25f615903c3fbe11b upstream. + +x25_kill_by_neigh() walks the global X.25 socket list looking for sockets +attached to a terminating neighbour. x25_list_lock protects list membership +while the lookup is in progress, but it does not pin a socket's lifetime +after the lock is dropped. + +The function currently drops x25_list_lock before calling lock_sock(s). A +concurrent close can run x25_release(), remove the same socket from +x25_list, and drop the last socket reference in that window. The neighbour +teardown path can then lock or inspect a freed struct sock/struct x25_sock. + +Take sock_hold(s) while x25_list_lock still proves that the list entry is +live, then drop the temporary reference after the socket has been locked, +rechecked, and released. Recheck x25_sk(s)->neighbour after lock_sock(), +because another path may have disconnected the socket before this path +acquired the socket lock. Restart the list walk after each disconnect +because the list lock was dropped and the previous iterator state may no +longer be valid. + +A QEMU/KASAN run against origin/master reproduced a slab-use-after-free in +x25_kill_by_neigh(). + +Fixes: 7781607938c8 ("net/x25: Fix null-ptr-deref caused by x25_disconnect") +Cc: stable@vger.kernel.org +Signed-off-by: David Lee +Assisted-by: Codex:gpt-5.5 +Acked-by: Martin Schiller +Link: https://patch.msgid.link/20260713104752.241175-1-david.lee@trailofbits.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/x25/af_x25.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/net/x25/af_x25.c ++++ b/net/x25/af_x25.c +@@ -1772,15 +1772,19 @@ void x25_kill_by_neigh(struct x25_neigh + { + struct sock *s; + ++again: + write_lock_bh(&x25_list_lock); + + sk_for_each(s, &x25_list) { + if (x25_sk(s)->neighbour == nb) { ++ sock_hold(s); + write_unlock_bh(&x25_list_lock); + lock_sock(s); +- x25_disconnect(s, ENETUNREACH, 0, 0); ++ if (x25_sk(s)->neighbour == nb) ++ x25_disconnect(s, ENETUNREACH, 0, 0); + release_sock(s); +- write_lock_bh(&x25_list_lock); ++ sock_put(s); ++ goto again; + } + } + write_unlock_bh(&x25_list_lock); diff --git a/queue-7.1/phonet-pep-fix-use-after-free-in-pep_get_sb.patch b/queue-7.1/phonet-pep-fix-use-after-free-in-pep_get_sb.patch new file mode 100644 index 0000000000..273d200fbe --- /dev/null +++ b/queue-7.1/phonet-pep-fix-use-after-free-in-pep_get_sb.patch @@ -0,0 +1,48 @@ +From 0f71f852a96af9685858ce59fda34ecbf85c283d Mon Sep 17 00:00:00 2001 +From: Breno Leitao +Date: Tue, 21 Jul 2026 01:58:45 -0700 +Subject: phonet: pep: fix use-after-free in pep_get_sb() + +From: Breno Leitao + +commit 0f71f852a96af9685858ce59fda34ecbf85c283d upstream. + +pep_get_sb() doesn't consider that pskb_may_pull() might have relocated +the skb data, and continue to access the older pointer, causing UAF. + +Reproduced under KASAN: + + BUG: KASAN: slab-use-after-free in pep_get_sb+0x234/0x3b0 + Read of size 1 at addr ff11000105510f50 by task repro/157 + pep_get_sb+0x234/0x3b0 + pipe_handler_do_rcv+0x5f7/0xa10 + pep_do_rcv+0x203/0x410 + __sk_receive_skb+0x471/0x4a0 + phonet_rcv+0x5b3/0x6c0 + __netif_receive_skb+0xcc/0x1d0 + +Refetch the header with skb_header_pointer() after pskb_may_pull(), so +the possibly stale pointer is no longer dereferenced. There are better +ways to solve this, but, this is the less instrusive one. + +Fixes: 9641458d3ec4 ("Phonet: Pipe End Point for Phonet Pipes protocol") +Cc: stable@vger.kernel.org +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260721-phonet_get_sb_uaf-v1-1-95fd7881cc4e@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/phonet/pep.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/phonet/pep.c ++++ b/net/phonet/pep.c +@@ -55,6 +55,8 @@ static unsigned char *pep_get_sb(struct + ph = skb_header_pointer(skb, 0, 2, &h); + if (ph == NULL || ph->sb_len < 2 || !pskb_may_pull(skb, ph->sb_len)) + return NULL; ++ /* pskb_may_pull() may have reallocated the head; refetch ph. */ ++ ph = skb_header_pointer(skb, 0, 2, &h); + ph->sb_len -= 2; + *ptype = ph->sb_type; + *plen = ph->sb_len; diff --git a/queue-7.1/proc-fix-broken-error-paths-for-namespace-links.patch b/queue-7.1/proc-fix-broken-error-paths-for-namespace-links.patch new file mode 100644 index 0000000000..ee75b5c9d5 --- /dev/null +++ b/queue-7.1/proc-fix-broken-error-paths-for-namespace-links.patch @@ -0,0 +1,52 @@ +From 425224c2d700391729be7fe6929a88ef4e2d7a4e Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Mon, 6 Jul 2026 20:22:42 +0200 +Subject: proc: Fix broken error paths for namespace links + +From: Jann Horn + +commit 425224c2d700391729be7fe6929a88ef4e2d7a4e upstream. + +Don't return the return value of down_read_killable() (0) when a ptrace +access check fails, return -EACCES as intended. + +Reported-by: Magnus Lindholm +Closes: https://lore.kernel.org/r/20260706170735.2941493-1-linmag7@gmail.com +Fixes: 6650527444da ("proc: protect ptrace_may_access() with exec_update_lock (part 1)") +Cc: stable@vger.kernel.org +Signed-off-by: Jann Horn +Link: https://patch.msgid.link/20260706-procfs-ns-eacces-fix-v1-1-a69ab14c02e6@google.com +Tested-by: Magnus Lindholm +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/proc/namespaces.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/proc/namespaces.c ++++ b/fs/proc/namespaces.c +@@ -46,7 +46,7 @@ static const char *proc_ns_get_link(stru + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; + struct task_struct *task; + struct path ns_path; +- int error = -EACCES; ++ int error; + + if (!dentry) + return ERR_PTR(-ECHILD); +@@ -59,6 +59,7 @@ static const char *proc_ns_get_link(stru + if (error) + goto out_put_task; + ++ error = -EACCES; + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) + goto out; + +@@ -90,6 +91,7 @@ static int proc_ns_readlink(struct dentr + if (res) + goto out_put_task; + ++ res = -EACCES; + if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { + res = ns_get_name(name, sizeof(name), task, ns_ops); + if (res >= 0) diff --git a/queue-7.1/ptp-ptp_s390-add-missing-facility-check.patch b/queue-7.1/ptp-ptp_s390-add-missing-facility-check.patch new file mode 100644 index 0000000000..d94bccc897 --- /dev/null +++ b/queue-7.1/ptp-ptp_s390-add-missing-facility-check.patch @@ -0,0 +1,45 @@ +From e78f1ac37afcb16cb6fef8a2c92591eab6558956 Mon Sep 17 00:00:00 2001 +From: Sven Schnelle +Date: Tue, 14 Jul 2026 15:03:42 +0200 +Subject: ptp: ptp_s390: Add missing facility check + +From: Sven Schnelle + +commit e78f1ac37afcb16cb6fef8a2c92591eab6558956 upstream. + +Only register the physical clock when facility 28 is installed +and PTFF QAF returns that PTFF QPT is available. + +Fixes: 2d7de7a3010d ("s390/time: Add PtP driver") +Signed-off-by: Sven Schnelle +Cc: stable@kernel.org +Reviewed-by: Heiko Carstens +Link: https://patch.msgid.link/20260714130342.1971700-3-svens@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/ptp/ptp_s390.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/ptp/ptp_s390.c ++++ b/drivers/ptp/ptp_s390.c +@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void) + if (IS_ERR(ptp_stcke_clock)) + return PTR_ERR(ptp_stcke_clock); + ++ if (!test_facility(28) || !ptff_query(PTFF_QPT)) ++ return 0; ++ + ptp_qpt_clock = ptp_clock_register(&ptp_s390_qpt_info, NULL); + if (IS_ERR(ptp_qpt_clock)) { + ptp_clock_unregister(ptp_stcke_clock); +@@ -117,7 +120,8 @@ static __init int ptp_s390_init(void) + + static __exit void ptp_s390_exit(void) + { +- ptp_clock_unregister(ptp_qpt_clock); ++ if (ptp_qpt_clock) ++ ptp_clock_unregister(ptp_qpt_clock); + ptp_clock_unregister(ptp_stcke_clock); + } + diff --git a/queue-7.1/rbd-reset-positive-result-codes-to-zero-in-object-map-update-path.patch b/queue-7.1/rbd-reset-positive-result-codes-to-zero-in-object-map-update-path.patch new file mode 100644 index 0000000000..8974f09a00 --- /dev/null +++ b/queue-7.1/rbd-reset-positive-result-codes-to-zero-in-object-map-update-path.patch @@ -0,0 +1,58 @@ +From a6c4250b81bd30beae94e1b7a4b26fa1193ad2e4 Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Thu, 9 Jul 2026 13:26:20 +0200 +Subject: rbd: Reset positive result codes to zero in object map update path + +From: Raphael Zimmer + +commit a6c4250b81bd30beae94e1b7a4b26fa1193ad2e4 upstream. + +In a reply message to an RBD request, a positive result code indicates +a data payload, which is not allowed for writes. While +rbd_osd_req_callback() already resets a positive result code for writes +to zero, rbd_object_map_callback() does not. This allows a corrupted +reply to an object map update to trigger the rbd_assert(*result < 0) in +__rbd_obj_handle_request(). This happens, because +rbd_object_map_callback() calls rbd_obj_handle_request() -> +__rbd_obj_handle_request() and passes this positive result code. From +__rbd_obj_handle_request(), rbd_obj_advance_write() is called, which +leaves the positive result code unchanged and returns true. Therefore, +the if(done && *result) branch is executed in __rbd_obj_handle_request() +and the assertion triggers. + +This patch fixes the issue by adjusting the logic in the +rbd_object_map_callback() path. A positive result code for an object map +update is now reset to zero (similar to rbd_osd_req_callback()), and the +message is subsequently handled the same way as if the result code was +zero from the beginning. Additionally, a WARN_ON_ONCE() is added for +this case. + +Cc: stable@vger.kernel.org +Fixes: 22e8bd51bb04 ("rbd: support for object-map and fast-diff") +Signed-off-by: Raphael Zimmer +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -1957,10 +1957,15 @@ static int rbd_object_map_update_finish( + bool has_current_state; + void *p; + +- if (osd_req->r_result) ++ if (osd_req->r_result < 0) + return osd_req->r_result; + + /* ++ * Writes aren't allowed to return a data payload. ++ */ ++ WARN_ON_ONCE(osd_req->r_result > 0); ++ ++ /* + * Nothing to do for a snapshot object map. + */ + if (osd_req->r_num_ops == 1) diff --git a/queue-7.1/sctp-avoid-auth_enable-sysctl-uaf-during-netns-teardown.patch b/queue-7.1/sctp-avoid-auth_enable-sysctl-uaf-during-netns-teardown.patch new file mode 100644 index 0000000000..5e37d0cebd --- /dev/null +++ b/queue-7.1/sctp-avoid-auth_enable-sysctl-uaf-during-netns-teardown.patch @@ -0,0 +1,130 @@ +From f8d5e7846025f4ab15a461235f8ebae9094a361a Mon Sep 17 00:00:00 2001 +From: Zhiling Zou +Date: Wed, 15 Jul 2026 09:50:10 +0800 +Subject: sctp: avoid auth_enable sysctl UAF during netns teardown + +From: Zhiling Zou + +commit f8d5e7846025f4ab15a461235f8ebae9094a361a upstream. + +proc_sctp_do_auth() updates the SCTP control socket after changing +net.sctp.auth_enable. The handler gets the per-net SCTP state from +ctl->data, so an already opened sysctl file can still target a network +namespace while that namespace is being torn down. + +SCTP previously registered its per-net sysctls from sctp_defaults_init(), +while the control socket is created later from sctp_ctrlsock_init(). This +exposed a window during initialization where auth_enable was writable +before net->sctp.ctl_sock existed, and a teardown window where auth_enable +stayed writable after inet_ctl_sock_destroy() had released the control +socket. + +Move the per-net SCTP sysctl registration into sctp_ctrlsock_init() after +sctp_ctl_sock_init() succeeds, and unregister the sysctl table before +destroying the control socket in sctp_ctrlsock_exit(). If sysctl +registration fails after the control socket was created, destroy the +control socket in the same init path. + +Make sctp_sysctl_net_unregister() tolerate a missing header and clear the +saved pointer so init-error and exit paths can safely share the unregister +helper. + +Fixes: 15649fd5415e ("sctp: sysctl: auth_enable: avoid using current->nsproxy") +Cc: stable@vger.kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Co-developed-by: Qi Tang +Signed-off-by: Qi Tang +Signed-off-by: Zhiling Zou +Signed-off-by: Ren Wei +Acked-by: Xin Long +Link: https://patch.msgid.link/390cd5e91ed60eea27b0b64d0468301a9e73b808.1784033357.git.roxy520tt@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/protocol.c | 20 ++++++++++++-------- + net/sctp/sysctl.c | 9 +++++++-- + 2 files changed, 19 insertions(+), 10 deletions(-) + +--- a/net/sctp/protocol.c ++++ b/net/sctp/protocol.c +@@ -1377,10 +1377,6 @@ static int __net_init sctp_defaults_init + net->sctp.l3mdev_accept = 1; + #endif + +- status = sctp_sysctl_net_register(net); +- if (status) +- goto err_sysctl_register; +- + /* Allocate and initialise sctp mibs. */ + status = init_sctp_mibs(net); + if (status) +@@ -1414,8 +1410,6 @@ err_init_proc: + cleanup_sctp_mibs(net); + #endif + err_init_mibs: +- sctp_sysctl_net_unregister(net); +-err_sysctl_register: + return status; + } + +@@ -1430,7 +1424,6 @@ static void __net_exit sctp_defaults_exi + net->sctp.proc_net_sctp = NULL; + #endif + cleanup_sctp_mibs(net); +- sctp_sysctl_net_unregister(net); + } + + static struct pernet_operations sctp_defaults_ops = { +@@ -1444,16 +1437,27 @@ static int __net_init sctp_ctrlsock_init + + /* Initialize the control inode/socket for handling OOTB packets. */ + status = sctp_ctl_sock_init(net); +- if (status) ++ if (status) { + pr_err("Failed to initialize the SCTP control sock\n"); ++ return status; ++ } ++ ++ status = sctp_sysctl_net_register(net); ++ if (status) { ++ inet_ctl_sock_destroy(net->sctp.ctl_sock); ++ net->sctp.ctl_sock = NULL; ++ } + + return status; + } + + static void __net_exit sctp_ctrlsock_exit(struct net *net) + { ++ sctp_sysctl_net_unregister(net); ++ + /* Free the control endpoint. */ + inet_ctl_sock_destroy(net->sctp.ctl_sock); ++ net->sctp.ctl_sock = NULL; + } + + static struct pernet_operations sctp_ctrlsock_ops = { +--- a/net/sctp/sysctl.c ++++ b/net/sctp/sysctl.c +@@ -615,11 +615,16 @@ int sctp_sysctl_net_register(struct net + + void sctp_sysctl_net_unregister(struct net *net) + { ++ struct ctl_table_header *header = net->sctp.sysctl_header; + const struct ctl_table *table; + +- table = net->sctp.sysctl_header->ctl_table_arg; +- unregister_net_sysctl_table(net->sctp.sysctl_header); ++ if (!header) ++ return; ++ ++ table = header->ctl_table_arg; ++ unregister_net_sysctl_table(header); + kfree(table); ++ net->sctp.sysctl_header = NULL; + } + + static struct ctl_table_header *sctp_sysctl_header; diff --git a/queue-7.1/sctp-close-udp-tunnel-sockets-during-netns-teardown.patch b/queue-7.1/sctp-close-udp-tunnel-sockets-during-netns-teardown.patch new file mode 100644 index 0000000000..a5929e1c1b --- /dev/null +++ b/queue-7.1/sctp-close-udp-tunnel-sockets-during-netns-teardown.patch @@ -0,0 +1,43 @@ +From ffb2bd7ade36ec4da32c46a6eddbf4515316d08c Mon Sep 17 00:00:00 2001 +From: Zhiling Zou +Date: Wed, 15 Jul 2026 09:50:11 +0800 +Subject: sctp: close UDP tunnel sockets during netns teardown + +From: Zhiling Zou + +commit ffb2bd7ade36ec4da32c46a6eddbf4515316d08c upstream. + +proc_sctp_do_udp_port() starts per-net SCTP UDP tunneling sockets when +net.sctp.udp_port is set, and stops/restarts them when the sysctl value +changes. The netns exit path does not stop these sockets, so a namespace +can be torn down while its SCTP UDP tunnel sockets are still installed. + +Close the UDP tunnel sockets from sctp_ctrlsock_exit() after unregistering +the per-net sysctl table. This prevents new sysctl writes from racing in +while the sockets are being released, and closes the sockets before the +control socket is destroyed. + +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Cc: stable@vger.kernel.org +Reported-by: Sashiko +Closes: https://sashiko.dev/#/patchset/b9f1f02b0780ad6a719e2413f5f0bb8eb7702d94.1782585631.git.roxy520tt%40gmail.com +Signed-off-by: Zhiling Zou +Signed-off-by: Ren Wei +Acked-by: Xin Long +Link: https://patch.msgid.link/6dab75f22855cb219e2e30a5497cab03b970ab91.1784033357.git.roxy520tt@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/protocol.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/sctp/protocol.c ++++ b/net/sctp/protocol.c +@@ -1454,6 +1454,7 @@ static int __net_init sctp_ctrlsock_init + static void __net_exit sctp_ctrlsock_exit(struct net *net) + { + sctp_sysctl_net_unregister(net); ++ sctp_udp_sock_stop(net); + + /* Free the control endpoint. */ + inet_ctl_sock_destroy(net->sctp.ctl_sock); diff --git a/queue-7.1/sctp-don-t-free-the-asconf-s-own-transport-in-del-ip-processing.patch b/queue-7.1/sctp-don-t-free-the-asconf-s-own-transport-in-del-ip-processing.patch new file mode 100644 index 0000000000..ac284ce8dd --- /dev/null +++ b/queue-7.1/sctp-don-t-free-the-asconf-s-own-transport-in-del-ip-processing.patch @@ -0,0 +1,62 @@ +From 9b2854f86f0b56e9027d68e7a3fc909d1a9b566f Mon Sep 17 00:00:00 2001 +From: Jun Yang +Date: Tue, 21 Jul 2026 21:14:05 +0800 +Subject: sctp: don't free the ASCONF's own transport in DEL-IP processing + +From: Jun Yang + +commit 9b2854f86f0b56e9027d68e7a3fc909d1a9b566f upstream. + +sctp_process_asconf() caches the transport the ASCONF chunk is processed +against in asconf->transport (== chunk->transport, set once in sctp_rcv()). +For an ASCONF located through its Address Parameter by +__sctp_rcv_asconf_lookup(), that cached transport corresponds to the +Address Parameter, which need not be the packet's source address. + +sctp_process_asconf_param() rejects a DEL-IP for the packet source address +(ADDIP D8, SCTP_ERROR_DEL_SRC_IP), but nothing protects asconf->transport. +A single ASCONF can therefore carry, in order: + + [Address Parameter L] [DEL-IP L] [DEL-IP 0.0.0.0] + +where L differs from the source. The DEL-IP for L passes the D8 check and +calls sctp_assoc_rm_peer() on the transport that asconf->transport still +points at, freeing it (RCU-deferred). The following wildcard DEL-IP then +reuses the now-dangling asconf->transport in sctp_assoc_set_primary() and +sctp_assoc_del_nonprimary_peers(): set_primary() dereferences the freed +transport (->ipaddr, ->state) and plants the dangling pointer into +asoc->peer.primary_path / active_path, and del_nonprimary_peers(), keeping +only the pointer that is no longer on the list, removes every real +transport, leaving the association with a transport_count of 0 and +primary_path/active_path pointing at freed memory. + +Reject a DEL-IP that targets the transport the ASCONF is being processed +against, mirroring the existing source-address guard, so the wildcard +branch can never reuse a freed transport. + +Fixes: 42e30bf3463c ("[SCTP]: Handle the wildcard ADD-IP Address parameter") +Cc: stable@kernel.org +Signed-off-by: Jun Yang +Acked-by: Xin Long +Link: https://patch.msgid.link/tencent_73762ED1DF08CC9D5F5F61954B01350CFE0A@qq.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/sm_make_chunk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -3153,6 +3153,12 @@ static __be16 sctp_process_asconf_param( + if (!peer) + return SCTP_ERROR_DNS_FAILED; + ++ /* Don't free asconf->transport; a later wildcard DEL-IP ++ * parameter reuses it. ++ */ ++ if (peer == asconf->transport) ++ return SCTP_ERROR_REQ_REFUSED; ++ + sctp_assoc_rm_peer(asoc, peer); + break; + case SCTP_PARAM_SET_PRIMARY: diff --git a/queue-7.1/selftests-ftrace-reset-triggers-at-top-level-before-instance-loop.patch b/queue-7.1/selftests-ftrace-reset-triggers-at-top-level-before-instance-loop.patch new file mode 100644 index 0000000000..71a97f78c7 --- /dev/null +++ b/queue-7.1/selftests-ftrace-reset-triggers-at-top-level-before-instance-loop.patch @@ -0,0 +1,45 @@ +From 1a087033a6bad73b4140020b40e819b0933aafc3 Mon Sep 17 00:00:00 2001 +From: "Masami Hiramatsu (Google)" +Date: Fri, 17 Jul 2026 11:51:59 +0900 +Subject: selftests/ftrace: Reset triggers at top level before instance loop + +From: Masami Hiramatsu (Google) + +commit 1a087033a6bad73b4140020b40e819b0933aafc3 upstream. + +When running instance tests, 'ftracetest' creates a new ftrace instance +and runs the tests inside it. Before starting each test, it executes +'initialize_system()' to reset the ftrace state to initial-state. + +However, since 'initialize_system()' is executed in the context of the +instance directory, it only cleans up triggers and filters of that +instance. +Any triggers or dynamic events left behind in the top-level instance by +previous failed top-level tests, are left completely untouched. These +top-level leftovers can cause subsequent instance-based tests to fail +or even crash the kernel. + +Fix this by executing 'initialize_system()' in the top-level tracing +directory once before entering the instance loop. + +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/178425671889.84440.9477850701738666404.stgit@devnote2 +Fixes: b5b77be812de ("selftests: ftrace: Allow some tests to be run in a tracing instance") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman +--- + tools/testing/selftests/ftrace/ftracetest | 1 + + 1 file changed, 1 insertion(+) + +--- a/tools/testing/selftests/ftrace/ftracetest ++++ b/tools/testing/selftests/ftrace/ftracetest +@@ -503,6 +503,7 @@ for t in $TEST_CASES; do + done + + # Test on instance loop ++(cd $TRACING_DIR; initialize_system) + INSTANCE=" (instance) " + for t in $TEST_CASES; do + test_on_instance $t || continue diff --git a/queue-7.1/series b/queue-7.1/series index f417da5e6a..04d98dd14c 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -614,3 +614,65 @@ mptcp-pm-userspace-fix-use-after-free-in-get_local_id.patch selftests-mptcp-userspace_pm-fix-undefined-variable-port.patch afs-fix-afs_edit_dir_remove-to-get-not-find-block-0.patch btrfs-do-not-try-compression-for-data-reloc-inodes.patch +userfaultfd-prevent-registration-of-special-vmas.patch +mm-damon-core-validate-ranges-in-damon_set_regions.patch +m68k-avoid-wunused-but-set-parameter-in-clear_user_page.patch +mm-damon-core-disallow-overlapping-input-ranges-for-damon_set_regions.patch +mm-kmemleak-fix-checksum-computation-for-per-cpu-objects.patch +mm-memory-failure-trace-change-memory_failure_event-to-ras-subsystem.patch +mm-page_vma_mapped-fix-device-private-pmd-handling.patch +mm-huge_memory-set-pg_has_hwpoisoned-only-after-new-folio-head-is-established.patch +sctp-don-t-free-the-asconf-s-own-transport-in-del-ip-processing.patch +sctp-avoid-auth_enable-sysctl-uaf-during-netns-teardown.patch +sctp-close-udp-tunnel-sockets-during-netns-teardown.patch +ceph-add-owner-capability-checks-for-ceph_ioc_set_layout.patch +ceph-fix-pre-auth-out-of-bounds-read-on-snaptrace-in-ceph_handle_caps.patch +ceph-fix-refcount-leak-in-ceph_readdir.patch +ceph-fix-writeback_count-leak-in-write_folio_nounlock.patch +libceph-bound-get_version-reply-decode-to-front-len.patch +libceph-bound-pg_-temp-upmap-upmap_items-length-to-ceph_pg_max_size.patch +libceph-fix-multiplication-overflow-in-decode_new_up_state_weight.patch +libceph-fix-two-unsafe-bare-decodes-in-decode_lockers.patch +libceph-guard-missing-crush-type-name-lookup.patch +libceph-refresh-auth-authorizer_buf-_len-after-authorizer-update.patch +libceph-reject-monmaps-advertising-zero-monitors.patch +libceph-reject-zero-bucket-types-in-crush_decode.patch +libceph-remove-debugfs-files-before-client-teardown.patch +amt-fix-use-after-free-in-amt-delayed-works.patch +asoc-fsl-imx-card-skip-sysclk-reset-for-active-dais-in-shutdown.patch +asoc-fsl_sai-fix-spurious-bclk-on-resume-by-clearing-byp.patch +binfmt_elf_fdpic-only-honour-the-first-pt_interp.patch +fs-super-fix-emergency-thaw-double-unlock-of-s_umount.patch +fs-preserve-acl_dont_cache-state-in-forget_cached_acl.patch +fscrypt-add-missing-superblock-check-in-find_or_insert_direct_key.patch +fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devices.patch +ftrace-add-global-mutex-to-serialize-trace_parser-access.patch +io_uring-rw-fix-missing-erestartsys-conversion-in-read-paths.patch +iomap-fix-out-of-bounds-bitmap_set-with-zero-length-range.patch +iommu-vt-d-disallow-sva-if-page-walk-is-not-coherent.patch +mm-slub-fix-lost-local-objects-when-bulk-remote-free-batch-fills.patch +mm-slab-fix-a-memory-leak-due-to-bootstrapping-sheaves-twice.patch +net-stmmac-intel-skip-serdes-reconfig-when-rate-is-unchanged.patch +phonet-pep-fix-use-after-free-in-pep_get_sb.patch +vxlan-require-cap_net_admin-in-the-device-netns-for-changelink.patch +net-slip-serialize-receive-against-buffer-reallocation.patch +geneve-require-cap_net_admin-in-the-device-netns-for-changelink.patch +net-af_iucv-fix-null-deref-in-afiucv_hs_callback_syn.patch +net-iucv-fix-use-after-free-of-a-severed-iucv_path.patch +net-mlx5e-use-sender-devcom-for-mpv-master-up.patch +net-sched-serialize-qdisc_rtab_list-against-concurrent-get-put.patch +net-x25-fix-use-after-free-in-x25_kill_by_neigh.patch +net-gro-fix-double-aggregation-of-flush-marked-skbs.patch +net-hip04-fix-rx-buffer-leak-on-build_skb-failure.patch +net-pcs-xpcs-fix-sgmii-state-reading.patch +net-qrtr-ns-raise-node-count-limit-to-512.patch +proc-fix-broken-error-paths-for-namespace-links.patch +ptp-ptp_s390-add-missing-facility-check.patch +ice-fix-ptp-call-trace-during-ptp-release.patch +selftests-ftrace-reset-triggers-at-top-level-before-instance-loop.patch +super-fix-emergency-thaw-deadlock-on-frozen-block-devices.patch +rbd-reset-positive-result-codes-to-zero-in-object-map-update-path.patch +smb-client-handle-status_stopped_on_symlink-responses-without-a-symlink-target.patch +ksmbd-defer-destroy_previous_session-until-after-ntlm-authentication.patch +ksmbd-validate-minimum-pdu-size-for-transform-requests.patch +mm-slab-prevent-unbounded-recursion-in-free-path-with-new-kmalloc-type.patch diff --git a/queue-7.1/smb-client-handle-status_stopped_on_symlink-responses-without-a-symlink-target.patch b/queue-7.1/smb-client-handle-status_stopped_on_symlink-responses-without-a-symlink-target.patch new file mode 100644 index 0000000000..418faa982a --- /dev/null +++ b/queue-7.1/smb-client-handle-status_stopped_on_symlink-responses-without-a-symlink-target.patch @@ -0,0 +1,163 @@ +From 2eb74eef4b7eda8df593d22fb48e94ef959ec8a5 Mon Sep 17 00:00:00 2001 +From: Carl Johnson +Date: Tue, 21 Jul 2026 13:27:55 -0400 +Subject: smb: client: handle STATUS_STOPPED_ON_SYMLINK responses without a symlink target +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Carl Johnson + +commit 2eb74eef4b7eda8df593d22fb48e94ef959ec8a5 upstream. + +The macOS built-in SMB server returns STATUS_STOPPED_ON_SYMLINK for a +CREATE on a path whose final component is a symlink, but it does not +include a Symbolic Link Error Response in the error data: both +ErrorContextCount and ByteCount are zero, so the symlink target is not +present in the response at all. Per [MS-SMB2] section 2.2.2 such a +response should carry a valid Symbolic Link Error Response, so this is a +server bug, but the target can still be retrieved with +FSCTL_GET_REPARSE_POINT. + +Frame from a capture against macOS 26.5.2 (build 25F84): + + SMB2 hdr : Status=0x8000002d STATUS_STOPPED_ON_SYMLINK, Cmd=Create + Error Rsp: StructureSize=0x0009 + Error Context Count: 0 + Byte Count: 0 + Error Data: 00 + +symlink_data() cannot find a struct smb2_symlink_err_rsp in such a +response and returns -EINVAL, which parse_create_response() propagates, +so smb2_query_path_info() bails out at + + if (rc || !data->reparse_point) + goto out; + +before it can retry with SMB2_OP_GET_REPARSE. stat(), readlink() and ls +of any server-side symlink then fail with -EINVAL: + + $ ls -la Config + l????????? ? ? ? ? ? Config.json + $ stat Config/Config.json + stat: cannot statx 'Config/Config.json': Invalid argument + +A 5.10 client resolves these symlinks correctly against the same server +and share, so this is a regression for Apple SMB servers. + +Handle it in several places: + + - symlink_data() detects the empty response (ErrorContextCount and + ByteCount both zero) and returns a distinct -ENODATA, so that "server + did not send the target" can be told apart from a genuinely malformed + response and only this case is worked around. + + - parse_create_response() treats -ENODATA like + STATUS_IO_REPARSE_TAG_NOT_HANDLED, which does not carry the target + either: leave the reparse tag unset and clear rc, so the existing + SMB2_OP_GET_REPARSE path retrieves the target. + + - smb2_query_path_info() only fixes up the symlink target type when the + target is already known. SMB2_OP_GET_REPARSE sets data->reparse.tag + but does not parse the target out of the reparse buffer; that happens + later, in reparse_info_to_fattr(). Without this check + smb2_fix_symlink_target_type() is called with a NULL target and + returns -EIO. This could not happen with servers that send the target + inline and therefore skip SMB2_OP_GET_REPARSE. + + - smb2_open_file() maps -ENODATA to -EIO, matching + STATUS_IO_REPARSE_TAG_NOT_HANDLED, so its callers retrieve the target + with SMB2_OP_GET_REPARSE as well. + +Tested on Debian 13, kernel 6.18.38 (armv7), against macOS 26.5.2: +symlinks now resolve, including relative, parent-traversing and directory +symlinks, and reads through symlinks succeed. + +Cc: stable@vger.kernel.org +Co-developed-by: Pali Rohár +Signed-off-by: Pali Rohár +Signed-off-by: Carl Johnson +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/smb2file.c | 21 +++++++++++++++++++++ + fs/smb/client/smb2inode.c | 23 ++++++++++++++++++++--- + 2 files changed, 41 insertions(+), 3 deletions(-) + +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -30,6 +30,19 @@ static struct smb2_symlink_err_rsp *syml + u8 *end = (u8 *)err + iov->iov_len; + u32 len; + ++ /* ++ * Per [MS-SMB2] section 2.2.2, a STATUS_STOPPED_ON_SYMLINK response has to ++ * carry a Symbolic Link Error Response, so ByteCount cannot be zero. Some ++ * servers (e.g. the macOS built-in SMB server) violate this and return an ++ * empty error response, with both ErrorContextCount and ByteCount set to ++ * zero, i.e. without the symlink target. Detect this and return -ENODATA ++ * so that callers can tell "server did not send the target" apart from a ++ * malformed response, and retrieve the target with FSCTL_GET_REPARSE_POINT ++ * instead. ++ */ ++ if (!err->ErrorContextCount && !le32_to_cpu(err->ByteCount)) ++ return ERR_PTR(-ENODATA); ++ + if (err->ErrorContextCount) { + struct smb2_error_context_rsp *p; + +@@ -201,6 +214,14 @@ int smb2_open_file(const unsigned int xi + rc = smb2_parse_symlink_response(oparms->cifs_sb, &err_iov, + oparms->path, + &data->symlink_target); ++ /* ++ * If smb2_parse_symlink_response returned -ENODATA then the ++ * symlink_target was not sent. Treat this as if the SMB2_open() ++ * failed with STATUS_IO_REPARSE_TAG_NOT_HANDLED status, which is ++ * indicated by the -EIO errno. ++ */ ++ if (rc == -ENODATA) ++ rc = -EIO; + if (!rc) { + memset(smb2_data, 0, sizeof(*smb2_data)); + oparms->create_options |= OPEN_REPARSE_POINT; +--- a/fs/smb/client/smb2inode.c ++++ b/fs/smb/client/smb2inode.c +@@ -792,9 +792,19 @@ static int parse_create_response(struct + rc = smb2_parse_symlink_response(cifs_sb, iov, + full_path, + &data->symlink_target); +- if (rc) ++ if (rc != 0 && rc != -ENODATA) + return rc; +- tag = IO_REPARSE_TAG_SYMLINK; ++ /* ++ * -ENODATA means that the response was parsed but did not contain ++ * the symlink target at all (see symlink_data()). Treat it like ++ * STATUS_IO_REPARSE_TAG_NOT_HANDLED, which does not contain it ++ * either: leave the tag unset and clear rc, so that the caller ++ * retrieves the target with SMB2_OP_GET_REPARSE. ++ */ ++ if (rc == -ENODATA) ++ rc = 0; ++ else ++ tag = IO_REPARSE_TAG_SYMLINK; + reparse_point = true; + break; + case STATUS_SUCCESS: +@@ -987,7 +997,14 @@ int smb2_query_path_info(const unsigned + rc = -EOPNOTSUPP; + } + +- if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) { ++ /* ++ * If the symlink was already parsed in create response then it is needed to fix ++ * its type now (after the second call with OPEN_REPARSE_POINT which filled the ++ * data->fi.Attributes). If the symlink was not parsed in create response then ++ * the data->symlink_target was not filled yet and then the type will be fixed ++ * later after data->symlink_target is filled. ++ */ ++ if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc && data->symlink_target) { + bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY; + rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb); + } diff --git a/queue-7.1/super-fix-emergency-thaw-deadlock-on-frozen-block-devices.patch b/queue-7.1/super-fix-emergency-thaw-deadlock-on-frozen-block-devices.patch new file mode 100644 index 0000000000..5fbe67b7d0 --- /dev/null +++ b/queue-7.1/super-fix-emergency-thaw-deadlock-on-frozen-block-devices.patch @@ -0,0 +1,144 @@ +From 749d7aa0377aae32af8c0a4ad43371e7bf830ab5 Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Thu, 23 Jul 2026 11:37:05 +0200 +Subject: super: fix emergency thaw deadlock on frozen block devices + +From: Christian Brauner + +commit 749d7aa0377aae32af8c0a4ad43371e7bf830ab5 upstream. + +do_thaw_all_callback() calls bdev_thaw() while holding sb->s_umount +exclusively. If the block device was frozen via bdev_freeze() dropping +the last block layer freeze reference calls fs_bdev_thaw() which +reacquires s_umount: + + do_thaw_all_callback(sb) + super_lock_excl(sb) # holds sb->s_umount + bdev_thaw(sb->s_bdev) + mutex_lock(&bdev->bd_fsfreeze_mutex) + # bd_fsfreeze_count drops 1 -> 0 + bd_holder_ops->thaw == fs_bdev_thaw + get_bdev_super(bdev) + bdev_super_lock(bdev, true) + super_lock(sb, true) + down_write(&sb->s_umount) # same task: deadlock + +The emergency thaw worker deadlocks against itself holding both +s_umount and bd_fsfreeze_mutex. That fscks any subsequent unmount, +freeze, or thaw of that filesystem and block device. + + [ 81.878470] sysrq: Show Blocked State + [ 81.880140] task:kworker/0:1 state:D stack:0 pid:11 tgid:11 ppid:2 task_flags:0x4208060 flags:0x00080000 + [ 81.884876] Workqueue: events do_thaw_all + [ 81.886656] Call Trace: + [ 81.887759] + [ 81.888763] __schedule+0x579/0x1420 + [ 81.890372] schedule+0x3a/0x100 + [ 81.891794] schedule_preempt_disabled+0x15/0x30 + [ 81.893848] rwsem_down_write_slowpath+0x1ea/0x900 + [ 81.895191] ? __pfx_do_thaw_all_callback+0x10/0x10 + [ 81.896528] down_write+0xbd/0xc0 + [ 81.897505] super_lock+0x91/0x180 + [ 81.898457] ? __mutex_lock+0xa99/0x1140 + [ 81.900748] ? __mutex_unlock_slowpath+0x1f/0x400 + [ 81.902069] bdev_super_lock+0x5b/0x150 + [ 81.903132] get_bdev_super+0x10/0x60 + [ 81.904042] fs_bdev_thaw+0x23/0xf0 + [ 81.904755] bdev_thaw+0x82/0x100 + [ 81.905484] do_thaw_all_callback+0x2c/0x50 + [ 81.906298] __iterate_supers+0x5d/0x130 + [ 81.907067] do_thaw_all+0x20/0x40 + [ 81.907739] process_one_work+0x206/0x5e0 + [ 81.908545] worker_thread+0x1e2/0x3c0 + [ 81.909339] ? __pfx_worker_thread+0x10/0x10 + [ 81.910171] kthread+0xf4/0x130 + [ 81.910799] ? __pfx_kthread+0x10/0x10 + [ 81.911528] ret_from_fork+0x2e2/0x3b0 + [ 81.912259] ? __pfx_kthread+0x10/0x10 + [ 81.913010] ret_from_fork_asm+0x1a/0x30 + [ 81.913806] + +bdev_super_lock() even documents the violated requirement with +lockdep_assert_not_held(&sb->s_umount). + +Acquiring bd_fsfreeze_mutex under s_umount also inverts the +bd_fsfreeze_mutex vs. s_umount ordering established by +bdev_{freeze,thaw}() and can thus ABBA against a concurrent block-layer +freeze even when the recursive path isn't hit. + +Fix this by not holding s_umount around the bdev_thaw() loop at all. Pin +the superblock with an active reference instead as +filesystems_freeze_callback() does. The active reference keeps the +superblock from being shut down and so ->s_bdev stays valid without +holding s_umount. The block-layer-held freeze is dropped by +fs_bdev_thaw() with FREEZE_MAY_NEST | FREEZE_HOLDER_USERSPACE exactly as +a regular unfreeze would and thaw_super_locked() handles +filesystem-level freezes as before. + +The emergency thaw path has deadlocked like this in one form or +another for a long long time but the current exclusively-held +shape dates back to commit [1] where thaw_bdev() already ended in +thaw_super() with s_umount held by do_thaw_all_callback(). + +Fixes: 08fdc8a0138a ("buffer.c: call thaw_super during emergency thaw") [1] +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260723-work-super-emergency_thaw-v1-1-7c315c600245@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/super.c | 29 ++++++++++++++++------------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +--- a/fs/super.c ++++ b/fs/super.c +@@ -1143,16 +1143,30 @@ void emergency_remount(void) + } + } + ++static inline bool get_active_super(struct super_block *sb) ++{ ++ bool active = false; ++ ++ if (super_lock_excl(sb)) { ++ active = atomic_inc_not_zero(&sb->s_active); ++ super_unlock_excl(sb); ++ } ++ return active; ++} ++ + static void do_thaw_all_callback(struct super_block *sb, void *unused) + { +- if (!super_lock_excl(sb)) ++ if (!get_active_super(sb)) + return; + ++ /* fs_bdev_thaw() acquires s_umount so it must not be held here */ + if (IS_ENABLED(CONFIG_BLOCK)) + while (sb->s_bdev && !bdev_thaw(sb->s_bdev)) + pr_warn("Emergency Thaw on %pg\n", sb->s_bdev); + +- thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE, NULL); ++ if (super_lock_excl(sb)) ++ thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE, NULL); ++ deactivate_super(sb); + } + + static void do_thaw_all(struct work_struct *work) +@@ -1178,17 +1192,6 @@ void emergency_thaw_all(void) + } + } + +-static inline bool get_active_super(struct super_block *sb) +-{ +- bool active = false; +- +- if (super_lock_excl(sb)) { +- active = atomic_inc_not_zero(&sb->s_active); +- super_unlock_excl(sb); +- } +- return active; +-} +- + static const char *filesystems_freeze_ptr = "filesystems_freeze"; + + static void filesystems_freeze_callback(struct super_block *sb, void *freeze_all_ptr) diff --git a/queue-7.1/userfaultfd-prevent-registration-of-special-vmas.patch b/queue-7.1/userfaultfd-prevent-registration-of-special-vmas.patch new file mode 100644 index 0000000000..3ec59ef622 --- /dev/null +++ b/queue-7.1/userfaultfd-prevent-registration-of-special-vmas.patch @@ -0,0 +1,58 @@ +From 3c58f641e813c3c71039f8fd4d4e2a3aab713288 Mon Sep 17 00:00:00 2001 +From: "Mike Rapoport (Microsoft)" +Date: Thu, 18 Jun 2026 12:50:17 +0300 +Subject: userfaultfd: prevent registration of special VMAs + +From: Mike Rapoport (Microsoft) + +commit 3c58f641e813c3c71039f8fd4d4e2a3aab713288 upstream. + +Vova Tokarev says: + + userfaultfd allows registration on shadow stack VMAs. With userfaultfd + access, you can register on the shadow stack, discard a page ... and + inject a page with chosen return addresses via UFFDIO_COPY. + +Update vma_can_userfault() to reject VM_SHADOW_STACK. + +While on it, also reject VM_SPECIAL so that if a driver would implement +vm_uffd_ops, it wouldn't be possible to register special VMAs with +userfaultfd. + +Since VM_SPECIAL includes VM_DONTEXPAND which is set but hugetlb, exclude +hugetlb VMAs from the check for VM_SPECIAL. + +Link: https://lore.kernel.org/20260618095017.2553004-1-rppt@kernel.org +Fixes: 54007f818206 ("mm: Introduce VM_SHADOW_STACK for shadow stack memory") +Signed-off-by: Mike Rapoport (Microsoft) +Reported-by: vova tokarev +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Lorenzo Stoakes +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Cc: Linus Torvalds +Cc: Mike Rapoport +Cc: Oleg Nesterov +Cc: Peter Xu +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/userfaultfd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/mm/userfaultfd.c ++++ b/mm/userfaultfd.c +@@ -2095,7 +2095,10 @@ bool vma_can_userfault(struct vm_area_st + { + const struct vm_uffd_ops *ops = vma_uffd_ops(vma); + +- if (vma->vm_flags & VM_DROPPABLE) ++ if (vma->vm_flags & (VM_DROPPABLE | VM_SHADOW_STACK)) ++ return false; ++ ++ if (!is_vm_hugetlb_page(vma) && (vma->vm_flags & VM_SPECIAL)) + return false; + + vm_flags &= __VM_UFFD_FLAGS; diff --git a/queue-7.1/vxlan-require-cap_net_admin-in-the-device-netns-for-changelink.patch b/queue-7.1/vxlan-require-cap_net_admin-in-the-device-netns-for-changelink.patch new file mode 100644 index 0000000000..8bd837bb7e --- /dev/null +++ b/queue-7.1/vxlan-require-cap_net_admin-in-the-device-netns-for-changelink.patch @@ -0,0 +1,51 @@ +From 3a61bd9637f3d929aa846e4eb3d98b48c26fcb0e Mon Sep 17 00:00:00 2001 +From: Doruk Tan Ozturk +Date: Thu, 16 Jul 2026 22:34:59 +0200 +Subject: vxlan: require CAP_NET_ADMIN in the device netns for changelink + +From: Doruk Tan Ozturk + +commit 3a61bd9637f3d929aa846e4eb3d98b48c26fcb0e upstream. + +A tunnel changelink() operates on at most two netns, dev_net(dev) and +the sticky underlay netns vxlan->net. They differ once the device is +created in or moved to a netns other than the one the request runs in. +The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), +so a caller privileged there but not in vxlan->net can rewrite a vxlan +device whose underlay lives in vxlan->net. + +vxlan_changelink() validates and applies the new configuration against +vxlan->net (vxlan_config_validate(vxlan->net, ...)) and can reopen the +underlay socket in that netns, so the same reasoning as the tunnel +changelink series applies here. + +Gate vxlan_changelink() with rtnl_dev_link_net_capable(), at the top of +the op before any attribute is parsed, matching ipgre_changelink() and +the rest of the "require CAP_NET_ADMIN in the device netns for +changelink" series. + +Found by 0sec automated security-research tooling (https://0sec.ai). + +Fixes: 8bcdc4f3a20b ("vxlan: add changelink support") +Cc: stable@vger.kernel.org +Signed-off-by: Doruk Tan Ozturk +Reviewed-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260716203500.70573-2-doruk@0sec.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/vxlan/vxlan_core.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -4422,6 +4422,9 @@ static int vxlan_changelink(struct net_d + struct vxlan_rdst *dst; + int err; + ++ if (!rtnl_dev_link_net_capable(dev, vxlan->net)) ++ return -EPERM; ++ + dst = &vxlan->default_dst; + err = vxlan_nl2conf(tb, data, dev, &conf, true, extack); + if (err)