From: Greg Kroah-Hartman Date: Thu, 23 Apr 2026 11:29:14 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v6.6.136~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45801d06edb56165d98b558e78acb42bd4c47af2;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-to-0.81v.patch arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-up-to-0.85v.patch arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch fs-ocfs2-fix-comments-mentioning-i_mutex.patch mm-blk-cgroup-fix-use-after-free-in-cgwb_release_workfn.patch mptcp-fix-lock-class-name-family-in-pm_nl_create_listen_socket.patch netdevsim-fix-memory-leak-of-nsim_dev-fa_cookie.patch netfilter-nft_set_pipapo-do-not-rely-on-zero_size_ptr.patch ocfs2-add-inline-inode-consistency-check-to-ocfs2_validate_inode_block.patch ocfs2-fix-out-of-bounds-write-in-ocfs2_write_end_inline.patch ocfs2-fix-possible-deadlock-between-unlink-and-dio_end_io_write.patch ocfs2-validate-inline-data-i_size-during-inode-read.patch powerpc64-bpf-do-not-increment-tailcall-count-when-prog-is-null.patch revert-arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch rxrpc-fix-call-removal-to-use-rcu-safe-deletion.patch rxrpc-fix-key-quota-calculation-for-multitoken-keys.patch rxrpc-reject-undecryptable-rxkad-response-tickets.patch tty-n_gsm-fix-deadlock-and-link-starvation-in-outgoing-data-path.patch xen-netfront-handle-null-returned-by-xdp_convert_buff_to_frame.patch xfrm-clear-trailing-padding-in-build_polexpire.patch --- diff --git a/queue-5.15/arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-to-0.81v.patch b/queue-5.15/arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-to-0.81v.patch new file mode 100644 index 0000000000..8d2c8d39d8 --- /dev/null +++ b/queue-5.15/arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-to-0.81v.patch @@ -0,0 +1,36 @@ +From stable+bounces-236109-greg=kroah.com@vger.kernel.org Mon Apr 13 16:22:47 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 10:20:55 -0400 +Subject: arm64: dts: imx8mq-librem5: Bump BUCK1 suspend voltage to 0.81V +To: stable@vger.kernel.org +Cc: Sebastian Krzyszkowiak , Martin Kepplinger , Shawn Guo , Sasha Levin +Message-ID: <20260413142057.2909222-2-sashal@kernel.org> + +From: Sebastian Krzyszkowiak + +[ Upstream commit 94b91e3ca6688fafd6a5dd70bd89fe9d3aee88da ] + +0.8V is outside of the operating voltage specified for imx8mq, see +chapter 3.1.4 "Operating ranges" of the IMX8MDQLQCEC document. + +Signed-off-by: Sebastian Krzyszkowiak +Signed-off-by: Martin Kepplinger +Signed-off-by: Shawn Guo +Stable-dep-of: 511f76bf1dce ("arm64: dts: imx8mq-librem5: Bump BUCK1 suspend voltage up to 0.85V") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi +@@ -706,7 +706,7 @@ + regulator-ramp-delay = <1250>; + rohm,dvs-run-voltage = <880000>; + rohm,dvs-idle-voltage = <820000>; +- rohm,dvs-suspend-voltage = <800000>; ++ rohm,dvs-suspend-voltage = <810000>; + regulator-always-on; + }; + diff --git a/queue-5.15/arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-up-to-0.85v.patch b/queue-5.15/arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-up-to-0.85v.patch new file mode 100644 index 0000000000..cb1a2f3bf2 --- /dev/null +++ b/queue-5.15/arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-up-to-0.85v.patch @@ -0,0 +1,41 @@ +From stable+bounces-236111-greg=kroah.com@vger.kernel.org Mon Apr 13 16:22:52 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 10:20:57 -0400 +Subject: arm64: dts: imx8mq-librem5: Bump BUCK1 suspend voltage up to 0.85V +To: stable@vger.kernel.org +Cc: Sebastian Krzyszkowiak , Frank Li , Sasha Levin +Message-ID: <20260413142057.2909222-4-sashal@kernel.org> + +From: Sebastian Krzyszkowiak + +[ Upstream commit 511f76bf1dce5acf8907b65a7d1bc8f7e7c0d637 ] + +The minimal voltage of VDD_SOC sourced from BUCK1 is 0.81V, which +is the currently set value. However, BD71837 only guarantees accuracy +of ±0.01V, and this still doesn't factor other reasons for actual +voltage to slightly drop in, resulting in the possibility of running +out of the operational range. + +Bump the voltage up to 0.85V, which should give enough headroom. + +Cc: stable@vger.kernel.org +Fixes: 8f0216b006e5 ("arm64: dts: Add a device tree for the Librem 5 phone") +Signed-off-by: Sebastian Krzyszkowiak +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi +@@ -706,7 +706,7 @@ + regulator-ramp-delay = <1250>; + rohm,dvs-run-voltage = <900000>; + rohm,dvs-idle-voltage = <850000>; +- rohm,dvs-suspend-voltage = <810000>; ++ rohm,dvs-suspend-voltage = <850000>; + regulator-always-on; + }; + diff --git a/queue-5.15/arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch b/queue-5.15/arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch new file mode 100644 index 0000000000..eee850ec8a --- /dev/null +++ b/queue-5.15/arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch @@ -0,0 +1,116 @@ +From stable+bounces-236108-greg=kroah.com@vger.kernel.org Mon Apr 13 16:27:58 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 10:20:54 -0400 +Subject: arm64: dts: imx8mq-librem5: Set the DVS voltages lower +To: stable@vger.kernel.org +Cc: Sebastian Krzyszkowiak , Martin Kepplinger , Shawn Guo , Sasha Levin +Message-ID: <20260413142057.2909222-1-sashal@kernel.org> + +From: Sebastian Krzyszkowiak + +[ Upstream commit c24a9b698fb02cd0723fa8375abab07f94b97b10 ] + +They're still in the operating range according to i.MX 8M Quad +datasheet. There's some headroom added over minimal values to +account for voltage drop. + +Operational ranges (min - typ - max [selected]): + - VDD_SOC (BUCK1): 0.81 - 0.9 - 0.99 [0.88] + - VDD_ARM (BUCK2): 0.81 - 0.9 - 1.05 [0.84] (1000MHz) + 0.90 - 1.0 - 1.05 [0.93] (1500MHz) + - VDD_GPU (BUCK3): 0.81 - 0.9 - 1.05 [0.85] (800MHz) + 0.90 - 1.0 - 1.05 [ -- ] (1000MHz) + - VDD_VPU (BUCK4): 0.81 - 0.9 - 1.05 [ -- ] (550/500/588MHz) + 0.90 - 1.0 - 1.05 [0.93] (660/600/800MHz) + +Idle power consumption doesn't appear to be influenced much, +but a simple load test (`cat /dev/urandom | pigz - > /dev/null` +combined with running Animatch) seems to show about 0.3W of +difference. + +Care is advised, as there may be differences between each +units in how low can they be undervolted - in my experience, +reaching that point usually makes the phone fail to boot. +In my case, it appears that my Birch phone can go down the most. + +This is a somewhat conservative set of values that I've seen +working well on all my devices; I haven't tried very hard to +optimize it, so more experiments are welcome. + +Signed-off-by: Sebastian Krzyszkowiak +Signed-off-by: Martin Kepplinger +Signed-off-by: Shawn Guo +Stable-dep-of: 511f76bf1dce ("arm64: dts: imx8mq-librem5: Bump BUCK1 suspend voltage up to 0.85V") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts | 2 - + arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi | 22 ++++++++++++++------ + 2 files changed, 17 insertions(+), 7 deletions(-) + +--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts +@@ -12,7 +12,7 @@ + + &a53_opp_table { + opp-1000000000 { +- opp-microvolt = <1000000>; ++ opp-microvolt = <950000>; + }; + }; + +--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi +@@ -704,8 +704,8 @@ + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; +- rohm,dvs-run-voltage = <900000>; +- rohm,dvs-idle-voltage = <850000>; ++ rohm,dvs-run-voltage = <880000>; ++ rohm,dvs-idle-voltage = <820000>; + rohm,dvs-suspend-voltage = <800000>; + regulator-always-on; + }; +@@ -716,8 +716,8 @@ + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; +- rohm,dvs-run-voltage = <1000000>; +- rohm,dvs-idle-voltage = <900000>; ++ rohm,dvs-run-voltage = <950000>; ++ rohm,dvs-idle-voltage = <850000>; + regulator-always-on; + }; + +@@ -726,14 +726,14 @@ + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; +- rohm,dvs-run-voltage = <900000>; ++ rohm,dvs-run-voltage = <850000>; + }; + + buck4_reg: BUCK4 { + regulator-name = "buck4"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; +- rohm,dvs-run-voltage = <1000000>; ++ rohm,dvs-run-voltage = <930000>; + }; + + buck5_reg: BUCK5 { +@@ -1214,3 +1214,13 @@ + fsl,ext-reset-output; + status = "okay"; + }; ++ ++&a53_opp_table { ++ opp-1000000000 { ++ opp-microvolt = <850000>; ++ }; ++ ++ opp-1500000000 { ++ opp-microvolt = <950000>; ++ }; ++}; diff --git a/queue-5.15/fs-ocfs2-fix-comments-mentioning-i_mutex.patch b/queue-5.15/fs-ocfs2-fix-comments-mentioning-i_mutex.patch new file mode 100644 index 0000000000..f44af4ec84 --- /dev/null +++ b/queue-5.15/fs-ocfs2-fix-comments-mentioning-i_mutex.patch @@ -0,0 +1,209 @@ +From stable+bounces-239239-greg=kroah.com@vger.kernel.org Mon Apr 20 18:53:29 2026 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:41:57 -0400 +Subject: fs/ocfs2: fix comments mentioning i_mutex +To: stable@vger.kernel.org +Cc: hongnanli , Joseph Qi , Mark Fasheh , Joel Becker , Junxiao Bi , Changwei Ge , Gang He , Jun Piao , Andrew Morton , Linus Torvalds , Sasha Levin +Message-ID: <20260420144158.1143438-1-sashal@kernel.org> + +From: hongnanli + +[ Upstream commit 137cebf9432eae024d0334953ed92a2a78619b52 ] + +inode->i_mutex has been replaced with inode->i_rwsem long ago. Fix +comments still mentioning i_mutex. + +Link: https://lkml.kernel.org/r/20220214031314.100094-1-hongnan.li@linux.alibaba.com +Signed-off-by: hongnanli +Acked-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Gang He +Cc: Jun Piao +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Stable-dep-of: b02da26a992d ("ocfs2: fix possible deadlock between unlink and dio_end_io_write") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ocfs2/alloc.c | 2 +- + fs/ocfs2/aops.c | 2 +- + fs/ocfs2/cluster/nodemanager.c | 2 +- + fs/ocfs2/dir.c | 4 ++-- + fs/ocfs2/file.c | 4 ++-- + fs/ocfs2/inode.c | 2 +- + fs/ocfs2/localalloc.c | 6 +++--- + fs/ocfs2/namei.c | 2 +- + fs/ocfs2/ocfs2.h | 4 ++-- + fs/ocfs2/quota_global.c | 2 +- + fs/ocfs2/xattr.c | 2 +- + 11 files changed, 16 insertions(+), 16 deletions(-) + +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -5986,7 +5986,7 @@ bail: + return status; + } + +-/* Expects you to already be holding tl_inode->i_mutex */ ++/* Expects you to already be holding tl_inode->i_rwsem */ + int __ocfs2_flush_truncate_log(struct ocfs2_super *osb) + { + int status; +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -2324,7 +2324,7 @@ static int ocfs2_dio_end_io_write(struct + + down_write(&oi->ip_alloc_sem); + +- /* Delete orphan before acquire i_mutex. */ ++ /* Delete orphan before acquire i_rwsem. */ + if (dwc->dw_orphaned) { + BUG_ON(dwc->dw_writer_pid != task_pid_nr(current)); + +--- a/fs/ocfs2/cluster/nodemanager.c ++++ b/fs/ocfs2/cluster/nodemanager.c +@@ -689,7 +689,7 @@ static struct config_group *o2nm_cluster + struct o2nm_node_group *ns = NULL; + struct config_group *o2hb_group = NULL, *ret = NULL; + +- /* this runs under the parent dir's i_mutex; there can be only ++ /* this runs under the parent dir's i_rwsem; there can be only + * one caller in here at a time */ + if (o2nm_single_cluster) + return ERR_PTR(-ENOSPC); +--- a/fs/ocfs2/dir.c ++++ b/fs/ocfs2/dir.c +@@ -1979,7 +1979,7 @@ bail_nolock: + } + + /* +- * NOTE: this should always be called with parent dir i_mutex taken. ++ * NOTE: this should always be called with parent dir i_rwsem taken. + */ + int ocfs2_find_files_on_disk(const char *name, + int namelen, +@@ -2026,7 +2026,7 @@ int ocfs2_lookup_ino_from_name(struct in + * Return -EEXIST if the directory contains the name + * Return -EFSCORRUPTED if found corruption + * +- * Callers should have i_mutex + a cluster lock on dir ++ * Callers should have i_rwsem + a cluster lock on dir + */ + int ocfs2_check_dir_for_entry(struct inode *dir, + const char *name, +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -270,7 +270,7 @@ int ocfs2_update_inode_atime(struct inod + + /* + * Don't use ocfs2_mark_inode_dirty() here as we don't always +- * have i_mutex to guard against concurrent changes to other ++ * have i_rwsem to guard against concurrent changes to other + * inode fields. + */ + inode->i_atime = current_time(inode); +@@ -1068,7 +1068,7 @@ static int ocfs2_extend_file(struct inod + /* + * The alloc sem blocks people in read/write from reading our + * allocation until we're done changing it. We depend on +- * i_mutex to block other extend/truncate calls while we're ++ * i_rwsem to block other extend/truncate calls while we're + * here. We even have to hold it for sparse files because there + * might be some tail zeroing. + */ +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -713,7 +713,7 @@ bail: + /* + * Serialize with orphan dir recovery. If the process doing + * recovery on this orphan dir does an iget() with the dir +- * i_mutex held, we'll deadlock here. Instead we detect this ++ * i_rwsem held, we'll deadlock here. Instead we detect this + * and exit early - recovery will wipe this inode for us. + */ + static int ocfs2_check_orphan_recovery_state(struct ocfs2_super *osb, +--- a/fs/ocfs2/localalloc.c ++++ b/fs/ocfs2/localalloc.c +@@ -606,7 +606,7 @@ out: + + /* + * make sure we've got at least bits_wanted contiguous bits in the +- * local alloc. You lose them when you drop i_mutex. ++ * local alloc. You lose them when you drop i_rwsem. + * + * We will add ourselves to the transaction passed in, but may start + * our own in order to shift windows. +@@ -636,7 +636,7 @@ int ocfs2_reserve_local_alloc_bits(struc + + /* + * We must double check state and allocator bits because +- * another process may have changed them while holding i_mutex. ++ * another process may have changed them while holding i_rwsem. + */ + spin_lock(&osb->osb_lock); + if (!ocfs2_la_state_enabled(osb) || +@@ -1029,7 +1029,7 @@ enum ocfs2_la_event { + /* + * Given an event, calculate the size of our next local alloc window. + * +- * This should always be called under i_mutex of the local alloc inode ++ * This should always be called under i_rwsem of the local alloc inode + * so that local alloc disabling doesn't race with processes trying to + * use the allocator. + * +--- a/fs/ocfs2/namei.c ++++ b/fs/ocfs2/namei.c +@@ -485,7 +485,7 @@ leave: + ocfs2_free_alloc_context(meta_ac); + + /* +- * We should call iput after the i_mutex of the bitmap been ++ * We should call iput after the i_rwsem of the bitmap been + * unlocked in ocfs2_free_alloc_context, or the + * ocfs2_delete_inode will mutex_lock again. + */ +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -369,7 +369,7 @@ struct ocfs2_super + struct delayed_work la_enable_wq; + + /* +- * Must hold local alloc i_mutex and osb->osb_lock to change ++ * Must hold local alloc i_rwsem and osb->osb_lock to change + * local_alloc_bits. Reads can be done under either lock. + */ + unsigned int local_alloc_bits; +@@ -444,7 +444,7 @@ struct ocfs2_super + atomic_t osb_tl_disable; + /* + * How many clusters in our truncate log. +- * It must be protected by osb_tl_inode->i_mutex. ++ * It must be protected by osb_tl_inode->i_rwsem. + */ + unsigned int truncated_clusters; + +--- a/fs/ocfs2/quota_global.c ++++ b/fs/ocfs2/quota_global.c +@@ -36,7 +36,7 @@ + * should be obeyed by all the functions: + * - any write of quota structure (either to local or global file) is protected + * by dqio_sem or dquot->dq_lock. +- * - any modification of global quota file holds inode cluster lock, i_mutex, ++ * - any modification of global quota file holds inode cluster lock, i_rwsem, + * and ip_alloc_sem of the global quota file (achieved by + * ocfs2_lock_global_qf). It also has to hold qinfo_lock. + * - an allocation of new blocks for local quota file is protected by +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -7208,7 +7208,7 @@ out: + * Used for reflink a non-preserve-security file. + * + * It uses common api like ocfs2_xattr_set, so the caller +- * must not hold any lock expect i_mutex. ++ * must not hold any lock expect i_rwsem. + */ + int ocfs2_init_security_and_acl(struct inode *dir, + struct inode *inode, diff --git a/queue-5.15/mm-blk-cgroup-fix-use-after-free-in-cgwb_release_workfn.patch b/queue-5.15/mm-blk-cgroup-fix-use-after-free-in-cgwb_release_workfn.patch new file mode 100644 index 0000000000..fdd5a3d639 --- /dev/null +++ b/queue-5.15/mm-blk-cgroup-fix-use-after-free-in-cgwb_release_workfn.patch @@ -0,0 +1,91 @@ +From stable+bounces-239966-greg=kroah.com@vger.kernel.org Mon Apr 20 20:27:29 2026 +From: Sasha Levin +Date: Mon, 20 Apr 2026 13:29:31 -0400 +Subject: mm: blk-cgroup: fix use-after-free in cgwb_release_workfn() +To: stable@vger.kernel.org +Cc: Breno Leitao , Dennis Zhou , Shakeel Butt , David Hildenbrand , Jens Axboe , Johannes Weiner , Josef Bacik , JP Kobryn , Liam Howlett , "Lorenzo Stoakes (Oracle)" , Martin KaFai Lau , Michal Hocko , Mike Rapoport , Suren Baghdasaryan , Tejun Heo , Andrew Morton , Sasha Levin +Message-ID: <20260420172931.1421876-1-sashal@kernel.org> + +From: Breno Leitao + +[ Upstream commit 8f5857be99f1ed1fa80991c72449541f634626ee ] + +cgwb_release_workfn() calls css_put(wb->blkcg_css) and then later accesses +wb->blkcg_css again via blkcg_unpin_online(). If css_put() drops the last +reference, the blkcg can be freed asynchronously (css_free_rwork_fn -> +blkcg_css_free -> kfree) before blkcg_unpin_online() dereferences the +pointer to access blkcg->online_pin, resulting in a use-after-free: + + BUG: KASAN: slab-use-after-free in blkcg_unpin_online (./include/linux/instrumented.h:112 ./include/linux/atomic/atomic-instrumented.h:400 ./include/linux/refcount.h:389 ./include/linux/refcount.h:432 ./include/linux/refcount.h:450 block/blk-cgroup.c:1367) + Write of size 4 at addr ff11000117aa6160 by task kworker/71:1/531 + Workqueue: cgwb_release cgwb_release_workfn + Call Trace: + + blkcg_unpin_online (./include/linux/instrumented.h:112 ./include/linux/atomic/atomic-instrumented.h:400 ./include/linux/refcount.h:389 ./include/linux/refcount.h:432 ./include/linux/refcount.h:450 block/blk-cgroup.c:1367) + cgwb_release_workfn (mm/backing-dev.c:629) + process_scheduled_works (kernel/workqueue.c:3278 kernel/workqueue.c:3385) + + Freed by task 1016: + kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6246 mm/slub.c:6561) + css_free_rwork_fn (kernel/cgroup/cgroup.c:5542) + process_scheduled_works (kernel/workqueue.c:3302 kernel/workqueue.c:3385) + +** Stack based on commit 66672af7a095 ("Add linux-next specific files +for 20260410") + +I am seeing this crash sporadically in Meta fleet across multiple kernel +versions. A full reproducer is available at: +https://github.com/leitao/debug/blob/main/reproducers/repro_blkcg_uaf.sh + +(The race window is narrow. To make it easily reproducible, inject a +msleep(100) between css_put() and blkcg_unpin_online() in +cgwb_release_workfn(). With that delay and a KASAN-enabled kernel, the +reproducer triggers the splat reliably in less than a second.) + +Fix this by moving blkcg_unpin_online() before css_put(), so the +cgwb's CSS reference keeps the blkcg alive while blkcg_unpin_online() +accesses it. + +Link: https://lore.kernel.org/20260413-blkcg-v1-1-35b72622d16c@debian.org +Fixes: 59b57717fff8 ("blkcg: delay blkg destruction until after writeback has finished") +Signed-off-by: Breno Leitao +Reviewed-by: Dennis Zhou +Reviewed-by: Shakeel Butt +Cc: David Hildenbrand +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Josef Bacik +Cc: JP Kobryn +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Martin KaFai Lau +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Suren Baghdasaryan +Cc: Tejun Heo +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/backing-dev.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/mm/backing-dev.c ++++ b/mm/backing-dev.c +@@ -404,12 +404,13 @@ static void cgwb_release_workfn(struct w + wb_shutdown(wb); + + css_put(wb->memcg_css); +- css_put(wb->blkcg_css); +- mutex_unlock(&wb->bdi->cgwb_release_mutex); + + /* triggers blkg destruction if no online users left */ + blkcg_unpin_online(blkcg); + ++ css_put(wb->blkcg_css); ++ mutex_unlock(&wb->bdi->cgwb_release_mutex); ++ + fprop_local_destroy_percpu(&wb->memcg_completions); + + spin_lock_irq(&cgwb_lock); diff --git a/queue-5.15/mptcp-fix-lock-class-name-family-in-pm_nl_create_listen_socket.patch b/queue-5.15/mptcp-fix-lock-class-name-family-in-pm_nl_create_listen_socket.patch new file mode 100644 index 0000000000..7adc952850 --- /dev/null +++ b/queue-5.15/mptcp-fix-lock-class-name-family-in-pm_nl_create_listen_socket.patch @@ -0,0 +1,41 @@ +From stable+bounces-233086-greg=kroah.com@vger.kernel.org Thu Apr 2 19:42:24 2026 +From: "Matthieu Baerts (NGI0)" +Date: Thu, 2 Apr 2026 19:42:01 +0200 +Subject: MPTCP: fix lock class name family in pm_nl_create_listen_socket +To: stable@vger.kernel.org, gregkh@linuxfoundation.org +Cc: MPTCP Upstream , Li Xiasong , "Matthieu Baerts (NGI0)" , Jakub Kicinski +Message-ID: <20260402174200.3474039-2-matttbe@kernel.org> + +From: Li Xiasong + +commit 7ab4a7c5d969642782b8a5b608da0dd02aa9f229 upstream. + +In mptcp_pm_nl_create_listen_socket(), use entry->addr.family +instead of sk->sk_family for lock class setup. The 'sk' parameter +is a netlink socket, not the MPTCP subflow socket being created. + +Fixes: cee4034a3db1 ("mptcp: fix lockdep false positive in mptcp_pm_nl_create_listen_socket()") +Signed-off-by: Li Xiasong +Reviewed-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260319112159.3118874-1-lixiasong1@huawei.com +Signed-off-by: Jakub Kicinski +[ Conflict in pm_kernel.c, because commit 8617e85e04bd ("mptcp: pm: + split in-kernel PM specific code") is not in this version, and moves + code from pm_netlink.c to pm_kernel.c. ] +Signed-off-by: Matthieu Baerts (NGI0) +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm_netlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -1041,7 +1041,7 @@ static struct lock_class_key mptcp_keys[ + static int mptcp_pm_nl_create_listen_socket(struct sock *sk, + struct mptcp_pm_addr_entry *entry) + { +- bool is_ipv6 = sk->sk_family == AF_INET6; ++ bool is_ipv6 = entry->addr.family == AF_INET6; + int addrlen = sizeof(struct sockaddr_in); + struct sockaddr_storage addr; + struct socket *ssock; diff --git a/queue-5.15/netdevsim-fix-memory-leak-of-nsim_dev-fa_cookie.patch b/queue-5.15/netdevsim-fix-memory-leak-of-nsim_dev-fa_cookie.patch new file mode 100644 index 0000000000..021fe760a1 --- /dev/null +++ b/queue-5.15/netdevsim-fix-memory-leak-of-nsim_dev-fa_cookie.patch @@ -0,0 +1,62 @@ +From stable+bounces-230415-greg=kroah.com@vger.kernel.org Thu Mar 26 04:18:23 2026 +From: Johnny Hao +Date: Thu, 26 Mar 2026 11:18:02 +0800 +Subject: netdevsim: Fix memory leak of nsim_dev->fa_cookie +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: linux-kernel@vger.kernel.org, Wang Yufen , Jiri Pirko , Jakub Kicinski , Johnny Hao +Message-ID: <20260326031802.2410719-1-johnny_haocn@sina.com> + +From: Wang Yufen + +[ Upstream commit 064bc7312bd09a48798418663090be0c776183db ] + +kmemleak reports this issue: + +unreferenced object 0xffff8881bac872d0 (size 8): + comm "sh", pid 58603, jiffies 4481524462 (age 68.065s) + hex dump (first 8 bytes): + 04 00 00 00 de ad be ef ........ + backtrace: + [<00000000c80b8577>] __kmalloc+0x49/0x150 + [<000000005292b8c6>] nsim_dev_trap_fa_cookie_write+0xc1/0x210 [netdevsim] + [<0000000093d78e77>] full_proxy_write+0xf3/0x180 + [<000000005a662c16>] vfs_write+0x1c5/0xaf0 + [<000000007aabf84a>] ksys_write+0xed/0x1c0 + [<000000005f1d2e47>] do_syscall_64+0x3b/0x90 + [<000000006001c6ec>] entry_SYSCALL_64_after_hwframe+0x63/0xcd + +The issue occurs in the following scenarios: + +nsim_dev_trap_fa_cookie_write() + kmalloc() fa_cookie + nsim_dev->fa_cookie = fa_cookie +.. +nsim_drv_remove() + +The fa_cookie allocked in nsim_dev_trap_fa_cookie_write() is not freed. To +fix, add kfree(nsim_dev->fa_cookie) to nsim_drv_remove(). + +Fixes: d3cbb907ae57 ("netdevsim: add ACL trap reporting cookie as a metadata") +Signed-off-by: Wang Yufen +Cc: Jiri Pirko +Link: https://lore.kernel.org/r/1668504625-14698-1-git-send-email-wangyufen@huawei.com +Signed-off-by: Jakub Kicinski +[ The context change is due to the commit 5e388f3dc38c +("netdevsim: move vfconfig to nsim_dev") in v5.16 +which is irrelevant to the logic of this patch. ] +Signed-off-by: Johnny Hao +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/netdevsim/dev.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -1582,6 +1582,7 @@ void nsim_dev_remove(struct nsim_bus_dev + ARRAY_SIZE(nsim_devlink_params)); + devlink_unregister(devlink); + devlink_resources_unregister(devlink, NULL); ++ kfree(nsim_dev->fa_cookie); + devlink_free(devlink); + } + diff --git a/queue-5.15/netfilter-nft_set_pipapo-do-not-rely-on-zero_size_ptr.patch b/queue-5.15/netfilter-nft_set_pipapo-do-not-rely-on-zero_size_ptr.patch new file mode 100644 index 0000000000..af3ff3e17f --- /dev/null +++ b/queue-5.15/netfilter-nft_set_pipapo-do-not-rely-on-zero_size_ptr.patch @@ -0,0 +1,67 @@ +From 07ace0bbe03b3d8e85869af1dec5e4087b1d57b8 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 13 Feb 2024 16:23:38 +0100 +Subject: netfilter: nft_set_pipapo: do not rely on ZERO_SIZE_PTR + +From: Florian Westphal + +commit 07ace0bbe03b3d8e85869af1dec5e4087b1d57b8 upstream. + +pipapo relies on kmalloc(0) returning ZERO_SIZE_PTR (i.e., not NULL +but pointer is invalid). + +Rework this to not call slab allocator when we'd request a 0-byte +allocation. + +Reviewed-by: Stefano Brivio +Signed-off-by: Florian Westphal +[Keerthana: In older stable branches (v6.6 and earlier), the allocation logic in +pipapo_clone() still relies on `src->rules` rather than `src->rules_alloc` +(introduced in v6.9 via 9f439bd6ef4f). Consequently, the previously +backported INT_MAX clamping check uses `src->rules`. This patch correctly +moves that `src->rules > (INT_MAX / ...)` check inside the new +`if (src->rules > 0)` block] +Signed-off-by: Keerthana K +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nft_set_pipapo.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +--- a/net/netfilter/nft_set_pipapo.c ++++ b/net/netfilter/nft_set_pipapo.c +@@ -525,6 +525,8 @@ static struct nft_pipapo_elem *pipapo_ge + int i; + + m = priv->clone; ++ if (m->bsize_max == 0) ++ return ret; + + res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC); + if (!res_map) { +@@ -1365,14 +1367,20 @@ static struct nft_pipapo_match *pipapo_c + src->bsize * sizeof(*dst->lt) * + src->groups * NFT_PIPAPO_BUCKETS(src->bb)); + +- if (src->rules > (INT_MAX / sizeof(*src->mt))) +- goto out_mt; ++ if (src->rules > 0) { ++ if (src->rules > (INT_MAX / sizeof(*src->mt))) ++ goto out_mt; ++ ++ dst->mt = kvmalloc_array(src->rules, sizeof(*src->mt), ++ GFP_KERNEL); ++ if (!dst->mt) ++ goto out_mt; + +- dst->mt = kvmalloc(src->rules * sizeof(*src->mt), GFP_KERNEL); +- if (!dst->mt) +- goto out_mt; ++ memcpy(dst->mt, src->mt, src->rules * sizeof(*src->mt)); ++ } else { ++ dst->mt = NULL; ++ } + +- memcpy(dst->mt, src->mt, src->rules * sizeof(*src->mt)); + src++; + dst++; + } diff --git a/queue-5.15/ocfs2-add-inline-inode-consistency-check-to-ocfs2_validate_inode_block.patch b/queue-5.15/ocfs2-add-inline-inode-consistency-check-to-ocfs2_validate_inode_block.patch new file mode 100644 index 0000000000..015d8a2bdd --- /dev/null +++ b/queue-5.15/ocfs2-add-inline-inode-consistency-check-to-ocfs2_validate_inode_block.patch @@ -0,0 +1,53 @@ +From stable+bounces-236156-greg=kroah.com@vger.kernel.org Mon Apr 13 17:56:30 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 11:50:23 -0400 +Subject: ocfs2: add inline inode consistency check to ocfs2_validate_inode_block() +To: stable@vger.kernel.org +Cc: Dmitry Antipov , syzbot+c16daba279a1161acfb0@syzkaller.appspotmail.com, Joseph Qi , Joseph Qi , Mark Fasheh , Joel Becker , Junxiao Bi , Changwei Ge , Jun Piao , Heming Zhao , Andrew Morton , Sasha Levin +Message-ID: <20260413155025.3145781-1-sashal@kernel.org> + +From: Dmitry Antipov + +[ Upstream commit a2b1c419ff72ec62ff5831684e30cd1d4f0b09ee ] + +In 'ocfs2_validate_inode_block()', add an extra check whether an inode +with inline data (i.e. self-contained) has no clusters, thus preventing +an invalid inode from being passed to 'ocfs2_evict_inode()' and below. + +Link: https://lkml.kernel.org/r/20251023141650.417129-1-dmantipov@yandex.ru +Signed-off-by: Dmitry Antipov +Reported-by: syzbot+c16daba279a1161acfb0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=c16daba279a1161acfb0 +Reviewed-by: Joseph Qi +Cc: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Stable-dep-of: 7bc5da4842be ("ocfs2: fix out-of-bounds write in ocfs2_write_end_inline") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ocfs2/inode.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -1416,6 +1416,14 @@ int ocfs2_validate_inode_block(struct su + goto bail; + } + ++ if ((le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) && ++ le32_to_cpu(di->i_clusters)) { ++ rc = ocfs2_error(sb, "Invalid dinode %llu: %u clusters\n", ++ (unsigned long long)bh->b_blocknr, ++ le32_to_cpu(di->i_clusters)); ++ goto bail; ++ } ++ + rc = 0; + + bail: diff --git a/queue-5.15/ocfs2-fix-out-of-bounds-write-in-ocfs2_write_end_inline.patch b/queue-5.15/ocfs2-fix-out-of-bounds-write-in-ocfs2_write_end_inline.patch new file mode 100644 index 0000000000..1366ca6885 --- /dev/null +++ b/queue-5.15/ocfs2-fix-out-of-bounds-write-in-ocfs2_write_end_inline.patch @@ -0,0 +1,77 @@ +From stable+bounces-236158-greg=kroah.com@vger.kernel.org Mon Apr 13 17:50:34 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 11:50:25 -0400 +Subject: ocfs2: fix out-of-bounds write in ocfs2_write_end_inline +To: stable@vger.kernel.org +Cc: Joseph Qi , syzbot+62c1793956716ea8b28a@syzkaller.appspotmail.com, Mark Fasheh , Joel Becker , Junxiao Bi , Changwei Ge , Jun Piao , Heming Zhao , Andrew Morton , Sasha Levin +Message-ID: <20260413155025.3145781-3-sashal@kernel.org> + +From: Joseph Qi + +[ Upstream commit 7bc5da4842bed3252d26e742213741a4d0ac1b14 ] + +KASAN reports a use-after-free write of 4086 bytes in +ocfs2_write_end_inline, called from ocfs2_write_end_nolock during a +copy_file_range splice fallback on a corrupted ocfs2 filesystem mounted on +a loop device. The actual bug is an out-of-bounds write past the inode +block buffer, not a true use-after-free. The write overflows into an +adjacent freed page, which KASAN reports as UAF. + +The root cause is that ocfs2_try_to_write_inline_data trusts the on-disk +id_count field to determine whether a write fits in inline data. On a +corrupted filesystem, id_count can exceed the physical maximum inline data +capacity, causing writes to overflow the inode block buffer. + +Call trace (crash path): + + vfs_copy_file_range (fs/read_write.c:1634) + do_splice_direct + splice_direct_to_actor + iter_file_splice_write + ocfs2_file_write_iter + generic_perform_write + ocfs2_write_end + ocfs2_write_end_nolock (fs/ocfs2/aops.c:1949) + ocfs2_write_end_inline (fs/ocfs2/aops.c:1915) + memcpy_from_folio <-- KASAN: write OOB + +So add id_count upper bound check in ocfs2_validate_inode_block() to +alongside the existing i_size check to fix it. + +Link: https://lkml.kernel.org/r/20260403063830.3662739-1-joseph.qi@linux.alibaba.com +Signed-off-by: Joseph Qi +Reported-by: syzbot+62c1793956716ea8b28a@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=62c1793956716ea8b28a +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ocfs2/inode.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -1427,6 +1427,16 @@ int ocfs2_validate_inode_block(struct su + goto bail; + } + ++ if (le16_to_cpu(data->id_count) > ++ ocfs2_max_inline_data_with_xattr(sb, di)) { ++ rc = ocfs2_error(sb, ++ "Invalid dinode #%llu: inline data id_count %u exceeds max %d\n", ++ (unsigned long long)bh->b_blocknr, ++ le16_to_cpu(data->id_count), ++ ocfs2_max_inline_data_with_xattr(sb, di)); ++ goto bail; ++ } ++ + if (le64_to_cpu(di->i_size) > le16_to_cpu(data->id_count)) { + rc = ocfs2_error(sb, + "Invalid dinode #%llu: inline data i_size %llu exceeds id_count %u\n", diff --git a/queue-5.15/ocfs2-fix-possible-deadlock-between-unlink-and-dio_end_io_write.patch b/queue-5.15/ocfs2-fix-possible-deadlock-between-unlink-and-dio_end_io_write.patch new file mode 100644 index 0000000000..1daf36e97c --- /dev/null +++ b/queue-5.15/ocfs2-fix-possible-deadlock-between-unlink-and-dio_end_io_write.patch @@ -0,0 +1,86 @@ +From stable+bounces-239240-greg=kroah.com@vger.kernel.org Mon Apr 20 17:35:05 2026 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:41:58 -0400 +Subject: ocfs2: fix possible deadlock between unlink and dio_end_io_write +To: stable@vger.kernel.org +Cc: Joseph Qi , syzbot+67b90111784a3eac8c04@syzkaller.appspotmail.com, Heming Zhao , Mark Fasheh , Joel Becker , Junxiao Bi , Joseph Qi , Changwei Ge , Jun Piao , Andrew Morton , Sasha Levin +Message-ID: <20260420144158.1143438-2-sashal@kernel.org> + +From: Joseph Qi + +[ Upstream commit b02da26a992db0c0e2559acbda0fc48d4a2fd337 ] + +ocfs2_unlink takes orphan dir inode_lock first and then ip_alloc_sem, +while in ocfs2_dio_end_io_write, it acquires these locks in reverse order. +This creates an ABBA lock ordering violation on lock classes +ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE] and +ocfs2_file_ip_alloc_sem_key. + +Lock Chain #0 (orphan dir inode_lock -> ip_alloc_sem): +ocfs2_unlink + ocfs2_prepare_orphan_dir + ocfs2_lookup_lock_orphan_dir + inode_lock(orphan_dir_inode) <- lock A + __ocfs2_prepare_orphan_dir + ocfs2_prepare_dir_for_insert + ocfs2_extend_dir + ocfs2_expand_inline_dir + down_write(&oi->ip_alloc_sem) <- Lock B + +Lock Chain #1 (ip_alloc_sem -> orphan dir inode_lock): +ocfs2_dio_end_io_write + down_write(&oi->ip_alloc_sem) <- Lock B + ocfs2_del_inode_from_orphan() + inode_lock(orphan_dir_inode) <- Lock A + +Deadlock Scenario: + CPU0 (unlink) CPU1 (dio_end_io_write) + ------ ------ + inode_lock(orphan_dir_inode) + down_write(ip_alloc_sem) + down_write(ip_alloc_sem) + inode_lock(orphan_dir_inode) + +Since ip_alloc_sem is to protect allocation changes, which is unrelated +with operations in ocfs2_del_inode_from_orphan. So move +ocfs2_del_inode_from_orphan out of ip_alloc_sem to fix the deadlock. + +Link: https://lkml.kernel.org/r/20260306032211.1016452-1-joseph.qi@linux.alibaba.com +Reported-by: syzbot+67b90111784a3eac8c04@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=67b90111784a3eac8c04 +Fixes: a86a72a4a4e0 ("ocfs2: take ip_alloc_sem in ocfs2_dio_get_block & ocfs2_dio_end_io_write") +Signed-off-by: Joseph Qi +Reviewed-by: Heming Zhao +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Joseph Qi +Cc: Changwei Ge +Cc: Jun Piao +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ocfs2/aops.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -2322,8 +2322,6 @@ static int ocfs2_dio_end_io_write(struct + goto out; + } + +- down_write(&oi->ip_alloc_sem); +- + /* Delete orphan before acquire i_rwsem. */ + if (dwc->dw_orphaned) { + BUG_ON(dwc->dw_writer_pid != task_pid_nr(current)); +@@ -2336,6 +2334,7 @@ static int ocfs2_dio_end_io_write(struct + mlog_errno(ret); + } + ++ down_write(&oi->ip_alloc_sem); + di = (struct ocfs2_dinode *)di_bh->b_data; + + ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh); diff --git a/queue-5.15/ocfs2-validate-inline-data-i_size-during-inode-read.patch b/queue-5.15/ocfs2-validate-inline-data-i_size-during-inode-read.patch new file mode 100644 index 0000000000..57133ebf3b --- /dev/null +++ b/queue-5.15/ocfs2-validate-inline-data-i_size-during-inode-read.patch @@ -0,0 +1,88 @@ +From stable+bounces-236157-greg=kroah.com@vger.kernel.org Mon Apr 13 17:50:32 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 11:50:24 -0400 +Subject: ocfs2: validate inline data i_size during inode read +To: stable@vger.kernel.org +Cc: Deepanshu Kartikey , syzbot+c897823f699449cc3eb4@syzkaller.appspotmail.com, Joseph Qi , Mark Fasheh , Joel Becker , Junxiao Bi , Changwei Ge , Jun Piao , Heming Zhao , Andrew Morton , Sasha Levin +Message-ID: <20260413155025.3145781-2-sashal@kernel.org> + +From: Deepanshu Kartikey + +[ Upstream commit 1524af3685b35feac76662cc551cbc37bd14775f ] + +When reading an inode from disk, ocfs2_validate_inode_block() performs +various sanity checks but does not validate the size of inline data. If +the filesystem is corrupted, an inode's i_size can exceed the actual +inline data capacity (id_count). + +This causes ocfs2_dir_foreach_blk_id() to iterate beyond the inline data +buffer, triggering a use-after-free when accessing directory entries from +freed memory. + +In the syzbot report: + - i_size was 1099511627576 bytes (~1TB) + - Actual inline data capacity (id_count) is typically <256 bytes + - A garbage rec_len (54648) caused ctx->pos to jump out of bounds + - This triggered a UAF in ocfs2_check_dir_entry() + +Fix by adding a validation check in ocfs2_validate_inode_block() to ensure +inodes with inline data have i_size <= id_count. This catches the +corruption early during inode read and prevents all downstream code from +operating on invalid data. + +Link: https://lkml.kernel.org/r/20251212052132.16750-1-kartikey406@gmail.com +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+c897823f699449cc3eb4@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=c897823f699449cc3eb4 +Tested-by: syzbot+c897823f699449cc3eb4@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/20251211115231.3560028-1-kartikey406@gmail.com/T/ [v1] +Link: https://lore.kernel.org/all/20251212040400.6377-1-kartikey406@gmail.com/T/ [v2] +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Stable-dep-of: 7bc5da4842be ("ocfs2: fix out-of-bounds write in ocfs2_write_end_inline") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ocfs2/inode.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -1416,12 +1416,25 @@ int ocfs2_validate_inode_block(struct su + goto bail; + } + +- if ((le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) && +- le32_to_cpu(di->i_clusters)) { +- rc = ocfs2_error(sb, "Invalid dinode %llu: %u clusters\n", +- (unsigned long long)bh->b_blocknr, +- le32_to_cpu(di->i_clusters)); +- goto bail; ++ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) { ++ struct ocfs2_inline_data *data = &di->id2.i_data; ++ ++ if (le32_to_cpu(di->i_clusters)) { ++ rc = ocfs2_error(sb, ++ "Invalid dinode %llu: %u clusters\n", ++ (unsigned long long)bh->b_blocknr, ++ le32_to_cpu(di->i_clusters)); ++ goto bail; ++ } ++ ++ if (le64_to_cpu(di->i_size) > le16_to_cpu(data->id_count)) { ++ rc = ocfs2_error(sb, ++ "Invalid dinode #%llu: inline data i_size %llu exceeds id_count %u\n", ++ (unsigned long long)bh->b_blocknr, ++ (unsigned long long)le64_to_cpu(di->i_size), ++ le16_to_cpu(data->id_count)); ++ goto bail; ++ } + } + + rc = 0; diff --git a/queue-5.15/powerpc64-bpf-do-not-increment-tailcall-count-when-prog-is-null.patch b/queue-5.15/powerpc64-bpf-do-not-increment-tailcall-count-when-prog-is-null.patch new file mode 100644 index 0000000000..a207dfc73e --- /dev/null +++ b/queue-5.15/powerpc64-bpf-do-not-increment-tailcall-count-when-prog-is-null.patch @@ -0,0 +1,74 @@ +From 521bd39d9d28ce54cbfec7f9b89c94ad4fdb8350 Mon Sep 17 00:00:00 2001 +From: Hari Bathini +Date: Tue, 3 Mar 2026 23:40:25 +0530 +Subject: powerpc64/bpf: do not increment tailcall count when prog is NULL + +From: Hari Bathini + +commit 521bd39d9d28ce54cbfec7f9b89c94ad4fdb8350 upstream. + +Do not increment tailcall count, if tailcall did not succeed due to +missing BPF program. + +Fixes: ce0761419fae ("powerpc/bpf: Implement support for tail calls") +Cc: stable@vger.kernel.org +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260303181031.390073-2-hbathini@linux.ibm.com +Signed-off-by: Greg Kroah-Hartman +[ Conflicts due to missing clean up commits + b10cb163c4b3 ("powerpc64/bpf elfv2: Setup kernel TOC in r2 on entry") + 49c3af43e65f ("powerpc/bpf: Simplify bpf_to_ppc() and adopt it for powerpc64") + 036d559c0bde ("powerpc/bpf: Use _Rn macros for GPRs") + and missing feature commit 2ed2d8f6fb38 ("powerpc64/bpf: Support + tailcalls with subprogs") resolved accordingly. ] +Signed-off-by: Hari Bathini +--- + arch/powerpc/net/bpf_jit_comp64.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +--- a/arch/powerpc/net/bpf_jit_comp64.c ++++ b/arch/powerpc/net/bpf_jit_comp64.c +@@ -239,30 +239,32 @@ static int bpf_jit_emit_tail_call(u32 *i + * tail_call_cnt++; + */ + EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 1)); +- PPC_BPF_STL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); + + /* prog = array->ptrs[index]; */ +- EMIT(PPC_RAW_MULI(b2p[TMP_REG_1], b2p_index, 8)); +- EMIT(PPC_RAW_ADD(b2p[TMP_REG_1], b2p[TMP_REG_1], b2p_bpf_array)); +- PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_array, ptrs)); ++ EMIT(PPC_RAW_MULI(b2p[TMP_REG_2], b2p_index, 8)); ++ EMIT(PPC_RAW_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], b2p_bpf_array)); ++ PPC_BPF_LL(b2p[TMP_REG_2], b2p[TMP_REG_2], offsetof(struct bpf_array, ptrs)); + + /* + * if (prog == NULL) + * goto out; + */ +- EMIT(PPC_RAW_CMPLDI(b2p[TMP_REG_1], 0)); ++ EMIT(PPC_RAW_CMPLDI(b2p[TMP_REG_2], 0)); + PPC_BCC(COND_EQ, out); + + /* goto *(prog->bpf_func + prologue_size); */ +- PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_prog, bpf_func)); ++ PPC_BPF_LL(b2p[TMP_REG_2], b2p[TMP_REG_2], offsetof(struct bpf_prog, bpf_func)); + #ifdef PPC64_ELF_ABI_v1 + /* skip past the function descriptor */ +- EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], ++ EMIT(PPC_RAW_ADDI(b2p[TMP_REG_2], b2p[TMP_REG_2], + FUNCTION_DESCR_SIZE + BPF_TAILCALL_PROLOGUE_SIZE)); + #else +- EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], BPF_TAILCALL_PROLOGUE_SIZE)); ++ EMIT(PPC_RAW_ADDI(b2p[TMP_REG_2], b2p[TMP_REG_2], BPF_TAILCALL_PROLOGUE_SIZE)); + #endif +- EMIT(PPC_RAW_MTCTR(b2p[TMP_REG_1])); ++ EMIT(PPC_RAW_MTCTR(b2p[TMP_REG_2])); ++ ++ /* Writeback updated tailcall count */ ++ PPC_BPF_STL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); + + /* tear down stack, restore NVRs, ... */ + bpf_jit_emit_common_epilogue(image, ctx); diff --git a/queue-5.15/revert-arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch b/queue-5.15/revert-arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch new file mode 100644 index 0000000000..b6e8c056c0 --- /dev/null +++ b/queue-5.15/revert-arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch @@ -0,0 +1,97 @@ +From stable+bounces-236110-greg=kroah.com@vger.kernel.org Mon Apr 13 16:22:55 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 10:20:56 -0400 +Subject: Revert "arm64: dts: imx8mq-librem5: Set the DVS voltages lower" +To: stable@vger.kernel.org +Cc: Sebastian Krzyszkowiak , Frank Li , Sasha Levin +Message-ID: <20260413142057.2909222-3-sashal@kernel.org> + +From: Sebastian Krzyszkowiak + +[ Upstream commit 4cd46ea0eb4504f7f4fea92cb4601c5c9a3e545e ] + +This reverts commit c24a9b698fb02cd0723fa8375abab07f94b97b10. + +It's been found that there's a significant per-unit variance in accepted +supply voltages and the current set still makes some units unstable. + +Revert back to nominal values. + +Cc: stable@vger.kernel.org +Fixes: c24a9b698fb0 ("arm64: dts: imx8mq-librem5: Set the DVS voltages lower") +Signed-off-by: Sebastian Krzyszkowiak +Signed-off-by: Frank Li +Stable-dep-of: 511f76bf1dce ("arm64: dts: imx8mq-librem5: Bump BUCK1 suspend voltage up to 0.85V") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts | 2 - + arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi | 22 +++++--------------- + 2 files changed, 7 insertions(+), 17 deletions(-) + +--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts +@@ -12,7 +12,7 @@ + + &a53_opp_table { + opp-1000000000 { +- opp-microvolt = <950000>; ++ opp-microvolt = <1000000>; + }; + }; + +--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi +@@ -704,8 +704,8 @@ + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; +- rohm,dvs-run-voltage = <880000>; +- rohm,dvs-idle-voltage = <820000>; ++ rohm,dvs-run-voltage = <900000>; ++ rohm,dvs-idle-voltage = <850000>; + rohm,dvs-suspend-voltage = <810000>; + regulator-always-on; + }; +@@ -716,8 +716,8 @@ + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; +- rohm,dvs-run-voltage = <950000>; +- rohm,dvs-idle-voltage = <850000>; ++ rohm,dvs-run-voltage = <1000000>; ++ rohm,dvs-idle-voltage = <900000>; + regulator-always-on; + }; + +@@ -726,14 +726,14 @@ + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; +- rohm,dvs-run-voltage = <850000>; ++ rohm,dvs-run-voltage = <900000>; + }; + + buck4_reg: BUCK4 { + regulator-name = "buck4"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; +- rohm,dvs-run-voltage = <930000>; ++ rohm,dvs-run-voltage = <1000000>; + }; + + buck5_reg: BUCK5 { +@@ -1214,13 +1214,3 @@ + fsl,ext-reset-output; + status = "okay"; + }; +- +-&a53_opp_table { +- opp-1000000000 { +- opp-microvolt = <850000>; +- }; +- +- opp-1500000000 { +- opp-microvolt = <950000>; +- }; +-}; diff --git a/queue-5.15/rxrpc-fix-call-removal-to-use-rcu-safe-deletion.patch b/queue-5.15/rxrpc-fix-call-removal-to-use-rcu-safe-deletion.patch new file mode 100644 index 0000000000..9e5c1588bf --- /dev/null +++ b/queue-5.15/rxrpc-fix-call-removal-to-use-rcu-safe-deletion.patch @@ -0,0 +1,93 @@ +From stable+bounces-237697-greg=kroah.com@vger.kernel.org Tue Apr 14 03:35:37 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 21:35:02 -0400 +Subject: rxrpc: Fix call removal to use RCU safe deletion +To: stable@vger.kernel.org +Cc: David Howells , Marc Dionne , Jeffrey Altman , Linus Torvalds , Simon Horman , linux-afs@lists.infradead.org, stable@kernel.org, Jakub Kicinski , Sasha Levin +Message-ID: <20260414013502.3857050-1-sashal@kernel.org> + +From: David Howells + +[ Upstream commit 146d4ab94cf129ee06cd467cb5c71368a6b5bad6 ] + +Fix rxrpc call removal from the rxnet->calls list to use list_del_rcu() +rather than list_del_init() to prevent stuffing up reading +/proc/net/rxrpc/calls from potentially getting into an infinite loop. + +This, however, means that list_empty() no longer works on an entry that's +been deleted from the list, making it harder to detect prior deletion. Fix +this by: + +Firstly, make rxrpc_destroy_all_calls() only dump the first ten calls that +are unexpectedly still on the list. Limiting the number of steps means +there's no need to call cond_resched() or to remove calls from the list +here, thereby eliminating the need for rxrpc_put_call() to check for that. + +rxrpc_put_call() can then be fixed to unconditionally delete the call from +the list as it is the only place that the deletion occurs. + +Fixes: 2baec2c3f854 ("rxrpc: Support network namespacing") +Closes: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Linus Torvalds +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260408121252.2249051-5-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +[ adapted to older API ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/call_object.c | 22 ++++++++-------------- + 1 file changed, 8 insertions(+), 14 deletions(-) + +--- a/net/rxrpc/call_object.c ++++ b/net/rxrpc/call_object.c +@@ -634,11 +634,9 @@ void rxrpc_put_call(struct rxrpc_call *c + _debug("call %d dead", call->debug_id); + ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); + +- if (!list_empty(&call->link)) { +- spin_lock_bh(&rxnet->call_lock); +- list_del_init(&call->link); +- spin_unlock_bh(&rxnet->call_lock); +- } ++ spin_lock_bh(&rxnet->call_lock); ++ list_del_rcu(&call->link); ++ spin_unlock_bh(&rxnet->call_lock); + + rxrpc_cleanup_call(call); + } +@@ -709,24 +707,20 @@ void rxrpc_destroy_all_calls(struct rxrp + _enter(""); + + if (!list_empty(&rxnet->calls)) { +- spin_lock_bh(&rxnet->call_lock); ++ int shown = 0; + +- while (!list_empty(&rxnet->calls)) { +- call = list_entry(rxnet->calls.next, +- struct rxrpc_call, link); +- _debug("Zapping call %p", call); ++ spin_lock_bh(&rxnet->call_lock); + ++ list_for_each_entry(call, &rxnet->calls, link) { + rxrpc_see_call(call); +- list_del_init(&call->link); + + pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n", + call, refcount_read(&call->ref), + rxrpc_call_states[call->state], + call->flags, call->events); + +- spin_unlock_bh(&rxnet->call_lock); +- cond_resched(); +- spin_lock_bh(&rxnet->call_lock); ++ if (++shown >= 10) ++ break; + } + + spin_unlock_bh(&rxnet->call_lock); diff --git a/queue-5.15/rxrpc-fix-key-quota-calculation-for-multitoken-keys.patch b/queue-5.15/rxrpc-fix-key-quota-calculation-for-multitoken-keys.patch new file mode 100644 index 0000000000..6f29df73b8 --- /dev/null +++ b/queue-5.15/rxrpc-fix-key-quota-calculation-for-multitoken-keys.patch @@ -0,0 +1,63 @@ +From stable+bounces-237683-greg=kroah.com@vger.kernel.org Tue Apr 14 02:17:46 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 20:17:39 -0400 +Subject: rxrpc: Fix key quota calculation for multitoken keys +To: stable@vger.kernel.org +Cc: David Howells , Marc Dionne , Jeffrey Altman , Simon Horman , linux-afs@lists.infradead.org, stable@kernel.org, Jakub Kicinski , Sasha Levin +Message-ID: <20260414001739.3796841-1-sashal@kernel.org> + +From: David Howells + +[ Upstream commit bdbfead6d38979475df0c2f4bad2b19394fe9bdc ] + +In the rxrpc key preparsing, every token extracted sets the proposed quota +value, but for multitoken keys, this will overwrite the previous proposed +quota, losing it. + +Fix this by adding to the proposed quota instead. + +Fixes: 8a7a3eb4ddbe ("KEYS: RxRPC: Use key preparsing") +Closes: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260408121252.2249051-2-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +[ dropped hunk for rxrpc_preparse_xdr_yfs_rxgk() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/key.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/net/rxrpc/key.c ++++ b/net/rxrpc/key.c +@@ -72,7 +72,7 @@ static int rxrpc_preparse_xdr_rxkad(stru + return -EKEYREJECTED; + + plen = sizeof(*token) + sizeof(*token->kad) + tktlen; +- prep->quotalen = datalen + plen; ++ prep->quotalen += datalen + plen; + + plen -= sizeof(*token); + token = kzalloc(sizeof(*token), GFP_KERNEL); +@@ -303,6 +303,7 @@ static int rxrpc_preparse(struct key_pre + memcpy(&kver, prep->data, sizeof(kver)); + prep->data += sizeof(kver); + prep->datalen -= sizeof(kver); ++ prep->quotalen = 0; + + _debug("KEY I/F VERSION: %u", kver); + +@@ -340,7 +341,7 @@ static int rxrpc_preparse(struct key_pre + goto error; + + plen = sizeof(*token->kad) + v1->ticket_length; +- prep->quotalen = plen + sizeof(*token); ++ prep->quotalen += plen + sizeof(*token); + + ret = -ENOMEM; + token = kzalloc(sizeof(*token), GFP_KERNEL); diff --git a/queue-5.15/rxrpc-reject-undecryptable-rxkad-response-tickets.patch b/queue-5.15/rxrpc-reject-undecryptable-rxkad-response-tickets.patch new file mode 100644 index 0000000000..3ed98bfe1a --- /dev/null +++ b/queue-5.15/rxrpc-reject-undecryptable-rxkad-response-tickets.patch @@ -0,0 +1,63 @@ +From stable+bounces-237840-greg=kroah.com@vger.kernel.org Tue Apr 14 14:04:30 2026 +From: Sasha Levin +Date: Tue, 14 Apr 2026 07:56:10 -0400 +Subject: rxrpc: reject undecryptable rxkad response tickets +To: stable@vger.kernel.org +Cc: Yuqi Xu , Yifan Wu , Juefei Pu , Yuan Tan , Xin Liu , Ren Wei , Ren Wei , David Howells , Marc Dionne , Simon Horman , linux-afs@lists.infradead.org, stable@kernel.org, Jakub Kicinski , Sasha Levin +Message-ID: <20260414115610.548230-1-sashal@kernel.org> + +From: Yuqi Xu + +[ Upstream commit fe4447cd95623b1cfacc15f280aab73a6d7340b2 ] + +rxkad_decrypt_ticket() decrypts the RXKAD response ticket and then +parses the buffer as plaintext without checking whether +crypto_skcipher_decrypt() succeeded. + +A malformed RESPONSE can therefore use a non-block-aligned ticket +length, make the decrypt operation fail, and still drive the ticket +parser with attacker-controlled bytes. + +Check the decrypt result and abort the connection with RXKADBADTICKET +when ticket decryption fails. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Yuqi Xu +Signed-off-by: Ren Wei +Signed-off-by: David Howells +cc: Marc Dionne +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260408121252.2249051-12-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +[ adapted `rxrpc_abort_conn()` call to existing `goto other_error` error-handling pattern ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/rxkad.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/net/rxrpc/rxkad.c ++++ b/net/rxrpc/rxkad.c +@@ -1013,8 +1013,13 @@ static int rxkad_decrypt_ticket(struct r + sg_init_one(&sg[0], ticket, ticket_len); + skcipher_request_set_callback(req, 0, NULL, NULL); + skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x); +- crypto_skcipher_decrypt(req); ++ ret = crypto_skcipher_decrypt(req); + skcipher_request_free(req); ++ if (ret < 0) { ++ abort_code = RXKADBADTICKET; ++ ret = -EPROTO; ++ goto other_error; ++ } + + p = ticket; + end = p + ticket_len; diff --git a/queue-5.15/series b/queue-5.15/series index 0fee0122cf..5959c2a4c2 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -97,3 +97,23 @@ gfs2-improve-gfs2_consist_inode-usage.patch gfs2-validate-i_depth-for-exhash-directories.patch wifi-mac80211-always-free-skb-on-ieee80211_tx_prepar.patch pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch +netfilter-nft_set_pipapo-do-not-rely-on-zero_size_ptr.patch +powerpc64-bpf-do-not-increment-tailcall-count-when-prog-is-null.patch +arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch +arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-to-0.81v.patch +revert-arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch +arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-up-to-0.85v.patch +ocfs2-add-inline-inode-consistency-check-to-ocfs2_validate_inode_block.patch +ocfs2-validate-inline-data-i_size-during-inode-read.patch +ocfs2-fix-out-of-bounds-write-in-ocfs2_write_end_inline.patch +xfrm-clear-trailing-padding-in-build_polexpire.patch +rxrpc-fix-key-quota-calculation-for-multitoken-keys.patch +rxrpc-fix-call-removal-to-use-rcu-safe-deletion.patch +rxrpc-reject-undecryptable-rxkad-response-tickets.patch +fs-ocfs2-fix-comments-mentioning-i_mutex.patch +ocfs2-fix-possible-deadlock-between-unlink-and-dio_end_io_write.patch +mm-blk-cgroup-fix-use-after-free-in-cgwb_release_workfn.patch +mptcp-fix-lock-class-name-family-in-pm_nl_create_listen_socket.patch +xen-netfront-handle-null-returned-by-xdp_convert_buff_to_frame.patch +tty-n_gsm-fix-deadlock-and-link-starvation-in-outgoing-data-path.patch +netdevsim-fix-memory-leak-of-nsim_dev-fa_cookie.patch diff --git a/queue-5.15/tty-n_gsm-fix-deadlock-and-link-starvation-in-outgoing-data-path.patch b/queue-5.15/tty-n_gsm-fix-deadlock-and-link-starvation-in-outgoing-data-path.patch new file mode 100644 index 0000000000..f4f2105f0e --- /dev/null +++ b/queue-5.15/tty-n_gsm-fix-deadlock-and-link-starvation-in-outgoing-data-path.patch @@ -0,0 +1,714 @@ +From stable+bounces-230427-greg=kroah.com@vger.kernel.org Thu Mar 26 07:52:10 2026 +From: Johnny Hao +Date: Thu, 26 Mar 2026 14:51:39 +0800 +Subject: tty: n_gsm: fix deadlock and link starvation in outgoing data path +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: linux-kernel@vger.kernel.org, Daniel Starke , Johnny Hao +Message-ID: <20260326065139.1735715-1-johnny_haocn@sina.com> + +From: Daniel Starke + +[ Upstream commit 0af021678d5d30c31f5a6b631f404ead3575212a ] + +The current implementation queues up new control and user packets as needed +and processes this queue down to the ldisc in the same code path. +That means that the upper and the lower layer are hard coupled in the code. +Due to this deadlocks can happen as seen below while transmitting data, +especially during ldisc congestion. Furthermore, the data channels starve +the control channel on high transmission load on the ldisc. + +Introduce an additional control channel data queue to prevent timeouts and +link hangups during ldisc congestion. This is being processed before the +user channel data queue in gsm_data_kick(), i.e. with the highest priority. +Put the queue to ldisc data path into a workqueue and trigger it whenever +new data has been put into the transmission queue. Change +gsm_dlci_data_sweep() accordingly to fill up the transmission queue until +TX_THRESH_HI. This solves the locking issue, keeps latency low and provides +good performance on high data load. +Note that now all packets from a DLCI are removed from the internal queue +if the associated DLCI was closed. This ensures that no data is sent by the +introduced write task to an already closed DLCI. + +BUG: spinlock recursion on CPU#0, test_v24_loop/124 + lock: serial8250_ports+0x3a8/0x7500, .magic: dead4ead, .owner: test_v24_loop/124, .owner_cpu: 0 +CPU: 0 PID: 124 Comm: test_v24_loop Tainted: G O 5.18.0-rc2 #3 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +Call Trace: + + dump_stack_lvl+0x34/0x44 + do_raw_spin_lock+0x76/0xa0 + _raw_spin_lock_irqsave+0x72/0x80 + uart_write_room+0x3b/0xc0 + gsm_data_kick+0x14b/0x240 [n_gsm] + gsmld_write_wakeup+0x35/0x70 [n_gsm] + tty_wakeup+0x53/0x60 + tty_port_default_wakeup+0x1b/0x30 + serial8250_tx_chars+0x12f/0x220 + serial8250_handle_irq.part.0+0xfe/0x150 + serial8250_default_handle_irq+0x48/0x80 + serial8250_interrupt+0x56/0xa0 + __handle_irq_event_percpu+0x78/0x1f0 + handle_irq_event+0x34/0x70 + handle_fasteoi_irq+0x90/0x1e0 + __common_interrupt+0x69/0x100 + common_interrupt+0x48/0xc0 + asm_common_interrupt+0x1e/0x40 +RIP: 0010:__do_softirq+0x83/0x34e +Code: 2a 0a ff 0f b7 ed c7 44 24 10 0a 00 00 00 48 c7 c7 51 2a 64 82 e8 2d +e2 d5 ff 65 66 c7 05 83 af 1e 7e 00 00 fb b8 ff ff ff ff <49> c7 c2 40 61 +80 82 0f bc c5 41 89 c4 41 83 c4 01 0f 84 e6 00 00 +RSP: 0018:ffffc90000003f98 EFLAGS: 00000286 +RAX: 00000000ffffffff RBX: 0000000000000000 RCX: 0000000000000000 +RDX: 0000000000000000 RSI: ffffffff82642a51 RDI: ffffffff825bb5e7 +RBP: 0000000000000200 R08: 00000008de3271a8 R09: 0000000000000000 +R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 +R13: 0000000000000030 R14: 0000000000000000 R15: 0000000000000000 + ? __do_softirq+0x73/0x34e + irq_exit_rcu+0xb5/0x100 + common_interrupt+0xa4/0xc0 + + + asm_common_interrupt+0x1e/0x40 +RIP: 0010:_raw_spin_unlock_irqrestore+0x2e/0x50 +Code: 00 55 48 89 fd 48 83 c7 18 53 48 89 f3 48 8b 74 24 10 e8 85 28 36 ff +48 89 ef e8 cd 58 36 ff 80 e7 02 74 01 fb bf 01 00 00 00 3d 97 33 ff +65 8b 05 96 23 2b 7e 85 c0 74 03 5b 5d c3 0f 1f 44 +RSP: 0018:ffffc9000020fd08 EFLAGS: 00000202 +RAX: 0000000000000000 RBX: 0000000000000246 RCX: 0000000000000000 +RDX: 0000000000000004 RSI: ffffffff8257fd74 RDI: 0000000000000001 +RBP: ffff8880057de3a0 R08: 00000008de233000 R09: 0000000000000000 +R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 +R13: 0000000000000100 R14: 0000000000000202 R15: ffff8880057df0b8 + ? _raw_spin_unlock_irqrestore+0x23/0x50 + gsmtty_write+0x65/0x80 [n_gsm] + n_tty_write+0x33f/0x530 + ? swake_up_all+0xe0/0xe0 + file_tty_write.constprop.0+0x1b1/0x320 + ? n_tty_flush_buffer+0xb0/0xb0 + new_sync_write+0x10c/0x190 + vfs_write+0x282/0x310 + ksys_write+0x68/0xe0 + do_syscall_64+0x3b/0x90 + entry_SYSCALL_64_after_hwframe+0x44/0xae +RIP: 0033:0x7f3e5e35c15c +Code: 8b 7c 24 08 89 c5 e8 c5 ff ff ff 89 ef 89 44 24 08 e8 58 bc 02 00 8b +44 24 08 48 83 c4 10 5d c3 48 63 ff b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff +ff 76 10 48 8b 15 fd fc 05 00 f7 d8 64 89 02 48 83 +RSP: 002b:00007ffcee77cd18 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +RAX: ffffffffffffffda RBX: 00007ffcee77cd70 RCX: 00007f3e5e35c15c +RDX: 0000000000000100 RSI: 00007ffcee77cd90 RDI: 0000000000000003 +RBP: 0000000000000100 R08: 0000000000000000 R09: 7efefefefefefeff +R10: 00007f3e5e3bddeb R11: 0000000000000246 R12: 00007ffcee77ce8f +R13: 0000000000000001 R14: 000056214404e010 R15: 00007ffcee77cd90 + + +Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220701122332.2039-1-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +[ The context change is due to the commit a8c5b8255f8a +("tty: n_gsm: fix broken virtual tty handling") in v5.18 +which is irrelevant to the logic of this patch. ] +Signed-off-by: Johnny Hao +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/n_gsm.c | 403 ++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 279 insertions(+), 124 deletions(-) + +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -5,6 +5,14 @@ + * + * * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE * + * ++ * Outgoing path: ++ * tty -> DLCI fifo -> scheduler -> GSM MUX data queue ---o-> ldisc ++ * control message -> GSM MUX control queue --´ ++ * ++ * Incoming path: ++ * ldisc -> gsm_queue() -o--> tty ++ * `-> gsm_control_response() ++ * + * TO DO: + * Mostly done: ioctls for setting modes/timing + * Partly done: hooks so you can pull off frames to non tty devs +@@ -212,6 +220,9 @@ struct gsm_mux { + /* Events on the GSM channel */ + wait_queue_head_t event; + ++ /* ldisc send work */ ++ struct work_struct tx_work; ++ + /* Bits for GSM mode decoding */ + + /* Framing Layer */ +@@ -243,7 +254,8 @@ struct gsm_mux { + unsigned int tx_bytes; /* TX data outstanding */ + #define TX_THRESH_HI 8192 + #define TX_THRESH_LO 2048 +- struct list_head tx_list; /* Pending data packets */ ++ struct list_head tx_ctrl_list; /* Pending control packets */ ++ struct list_head tx_data_list; /* Pending data packets */ + + /* Control messages */ + struct timer_list kick_timer; /* Kick TX queuing on timeout */ +@@ -377,6 +389,11 @@ static const u8 gsm_fcs8[256] = { + + static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); + static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk); ++static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, ++ u8 ctrl); ++static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg); ++static void gsmld_write_trigger(struct gsm_mux *gsm); ++static void gsmld_write_task(struct work_struct *work); + + /** + * gsm_fcs_add - update FCS +@@ -661,53 +678,73 @@ static int gsm_stuff_frame(const u8 *inp + * @cr: command/response bit seen as initiator + * @control: control byte including PF bit + * +- * Format up and transmit a control frame. These do not go via the +- * queueing logic as they should be transmitted ahead of data when +- * they are needed. +- * +- * FIXME: Lock versus data TX path ++ * Format up and transmit a control frame. These should be transmitted ++ * ahead of data when they are needed. + */ +- +-static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) ++static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) + { +- int len; +- u8 cbuf[10]; +- u8 ibuf[3]; ++ struct gsm_msg *msg; ++ u8 *dp; + int ocr; ++ unsigned long flags; ++ ++ msg = gsm_data_alloc(gsm, addr, 0, control); ++ if (!msg) ++ return -ENOMEM; + + /* toggle C/R coding if not initiator */ + ocr = cr ^ (gsm->initiator ? 0 : 1); + +- switch (gsm->encoding) { +- case 0: +- cbuf[0] = GSM0_SOF; +- cbuf[1] = (addr << 2) | (ocr << 1) | EA; +- cbuf[2] = control; +- cbuf[3] = EA; /* Length of data = 0 */ +- cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3); +- cbuf[5] = GSM0_SOF; +- len = 6; +- break; +- case 1: +- case 2: +- /* Control frame + packing (but not frame stuffing) in mode 1 */ +- ibuf[0] = (addr << 2) | (ocr << 1) | EA; +- ibuf[1] = control; +- ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2); +- /* Stuffing may double the size worst case */ +- len = gsm_stuff_frame(ibuf, cbuf + 1, 3); +- /* Now add the SOF markers */ +- cbuf[0] = GSM1_SOF; +- cbuf[len + 1] = GSM1_SOF; +- /* FIXME: we can omit the lead one in many cases */ +- len += 2; +- break; +- default: +- WARN_ON(1); +- return; ++ msg->data -= 3; ++ dp = msg->data; ++ *dp++ = (addr << 2) | (ocr << 1) | EA; ++ *dp++ = control; ++ ++ if (gsm->encoding == 0) ++ *dp++ = EA; /* Length of data = 0 */ ++ ++ *dp = 0xFF - gsm_fcs_add_block(INIT_FCS, msg->data, dp - msg->data); ++ msg->len = (dp - msg->data) + 1; ++ ++ gsm_print_packet("Q->", addr, cr, control, NULL, 0); ++ ++ spin_lock_irqsave(&gsm->tx_lock, flags); ++ list_add_tail(&msg->list, &gsm->tx_ctrl_list); ++ gsm->tx_bytes += msg->len; ++ spin_unlock_irqrestore(&gsm->tx_lock, flags); ++ gsmld_write_trigger(gsm); ++ ++ return 0; ++} ++ ++/** ++ * gsm_dlci_clear_queues - remove outstanding data for a DLCI ++ * @gsm: mux ++ * @dlci: clear for this DLCI ++ * ++ * Clears the data queues for a given DLCI. ++ */ ++static void gsm_dlci_clear_queues(struct gsm_mux *gsm, struct gsm_dlci *dlci) ++{ ++ struct gsm_msg *msg, *nmsg; ++ int addr = dlci->addr; ++ unsigned long flags; ++ ++ /* Clear DLCI write fifo first */ ++ spin_lock_irqsave(&dlci->lock, flags); ++ kfifo_reset(&dlci->fifo); ++ spin_unlock_irqrestore(&dlci->lock, flags); ++ ++ /* Clear data packets in MUX write queue */ ++ spin_lock_irqsave(&gsm->tx_lock, flags); ++ list_for_each_entry_safe(msg, nmsg, &gsm->tx_data_list, list) { ++ if (msg->addr != addr) ++ continue; ++ gsm->tx_bytes -= msg->len; ++ list_del(&msg->list); ++ kfree(msg); + } +- gsmld_output(gsm, cbuf, len); +- gsm_print_packet("-->", addr, cr, control, NULL, 0); ++ spin_unlock_irqrestore(&gsm->tx_lock, flags); + } + + /** +@@ -770,6 +807,45 @@ static struct gsm_msg *gsm_data_alloc(st + } + + /** ++ * gsm_send_packet - sends a single packet ++ * @gsm: GSM Mux ++ * @msg: packet to send ++ * ++ * The given packet is encoded and sent out. No memory is freed. ++ * The caller must hold the gsm tx lock. ++ */ ++static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg) ++{ ++ int len, ret; ++ ++ ++ if (gsm->encoding == 0) { ++ gsm->txframe[0] = GSM0_SOF; ++ memcpy(gsm->txframe + 1, msg->data, msg->len); ++ gsm->txframe[msg->len + 1] = GSM0_SOF; ++ len = msg->len + 2; ++ } else { ++ gsm->txframe[0] = GSM1_SOF; ++ len = gsm_stuff_frame(msg->data, gsm->txframe + 1, msg->len); ++ gsm->txframe[len + 1] = GSM1_SOF; ++ len += 2; ++ } ++ ++ if (debug & 4) ++ gsm_hex_dump_bytes(__func__, gsm->txframe, len); ++ gsm_print_packet("-->", msg->addr, gsm->initiator, msg->ctrl, msg->data, ++ msg->len); ++ ++ ret = gsmld_output(gsm, gsm->txframe, len); ++ if (ret <= 0) ++ return ret; ++ /* FIXME: Can eliminate one SOF in many more cases */ ++ gsm->tx_bytes -= msg->len; ++ ++ return 0; ++} ++ ++/** + * gsm_is_flow_ctrl_msg - checks if flow control message + * @msg: message to check + * +@@ -801,59 +877,81 @@ static bool gsm_is_flow_ctrl_msg(struct + } + + /** +- * gsm_data_kick - poke the queue ++ * gsm_data_kick - poke the queue + * @gsm: GSM Mux +- * @dlci: DLCI sending the data + * + * The tty device has called us to indicate that room has appeared in +- * the transmit queue. Ram more data into the pipe if we have any ++ * the transmit queue. Ram more data into the pipe if we have any. + * If we have been flow-stopped by a CMD_FCOFF, then we can only +- * send messages on DLCI0 until CMD_FCON +- * +- * FIXME: lock against link layer control transmissions ++ * send messages on DLCI0 until CMD_FCON. The caller must hold ++ * the gsm tx lock. + */ +- +-static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci) ++static int gsm_data_kick(struct gsm_mux *gsm) + { + struct gsm_msg *msg, *nmsg; +- int len; ++ struct gsm_dlci *dlci; ++ int ret; + +- list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { ++ clear_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags); ++ ++ /* Serialize control messages and control channel messages first */ ++ list_for_each_entry_safe(msg, nmsg, &gsm->tx_ctrl_list, list) { + if (gsm->constipated && !gsm_is_flow_ctrl_msg(msg)) ++ return -EAGAIN; ++ ret = gsm_send_packet(gsm, msg); ++ switch (ret) { ++ case -ENOSPC: ++ return -ENOSPC; ++ case -ENODEV: ++ /* ldisc not open */ ++ gsm->tx_bytes -= msg->len; ++ list_del(&msg->list); ++ kfree(msg); + continue; +- if (gsm->encoding != 0) { +- gsm->txframe[0] = GSM1_SOF; +- len = gsm_stuff_frame(msg->data, +- gsm->txframe + 1, msg->len); +- gsm->txframe[len + 1] = GSM1_SOF; +- len += 2; +- } else { +- gsm->txframe[0] = GSM0_SOF; +- memcpy(gsm->txframe + 1 , msg->data, msg->len); +- gsm->txframe[msg->len + 1] = GSM0_SOF; +- len = msg->len + 2; +- } +- +- if (debug & 4) +- gsm_hex_dump_bytes(__func__, gsm->txframe, len); +- if (gsmld_output(gsm, gsm->txframe, len) <= 0) ++ default: ++ if (ret >= 0) { ++ list_del(&msg->list); ++ kfree(msg); ++ } + break; +- /* FIXME: Can eliminate one SOF in many more cases */ +- gsm->tx_bytes -= msg->len; +- +- list_del(&msg->list); +- kfree(msg); ++ } ++ } + +- if (dlci) { +- tty_port_tty_wakeup(&dlci->port); +- } else { +- int i = 0; ++ if (gsm->constipated) ++ return -EAGAIN; + +- for (i = 0; i < NUM_DLCI; i++) +- if (gsm->dlci[i]) +- tty_port_tty_wakeup(&gsm->dlci[i]->port); ++ /* Serialize other channels */ ++ if (list_empty(&gsm->tx_data_list)) ++ return 0; ++ list_for_each_entry_safe(msg, nmsg, &gsm->tx_data_list, list) { ++ dlci = gsm->dlci[msg->addr]; ++ /* Send only messages for DLCIs with valid state */ ++ if (dlci->state != DLCI_OPEN) { ++ gsm->tx_bytes -= msg->len; ++ list_del(&msg->list); ++ kfree(msg); ++ continue; ++ } ++ ret = gsm_send_packet(gsm, msg); ++ switch (ret) { ++ case -ENOSPC: ++ return -ENOSPC; ++ case -ENODEV: ++ /* ldisc not open */ ++ gsm->tx_bytes -= msg->len; ++ list_del(&msg->list); ++ kfree(msg); ++ continue; ++ default: ++ if (ret >= 0) { ++ list_del(&msg->list); ++ kfree(msg); ++ } ++ break; + } + } ++ ++ return 1; + } + + /** +@@ -902,9 +1000,21 @@ static void __gsm_data_queue(struct gsm_ + msg->data = dp; + + /* Add to the actual output queue */ +- list_add_tail(&msg->list, &gsm->tx_list); ++ switch (msg->ctrl & ~PF) { ++ case UI: ++ case UIH: ++ if (msg->addr > 0) { ++ list_add_tail(&msg->list, &gsm->tx_data_list); ++ break; ++ } ++ fallthrough; ++ default: ++ list_add_tail(&msg->list, &gsm->tx_ctrl_list); ++ break; ++ } + gsm->tx_bytes += msg->len; +- gsm_data_kick(gsm, dlci); ++ ++ gsmld_write_trigger(gsm); + mod_timer(&gsm->kick_timer, jiffies + 10 * gsm->t1 * HZ / 100); + } + +@@ -1131,32 +1241,39 @@ static int gsm_dlci_modem_output(struct + + static int gsm_dlci_data_sweep(struct gsm_mux *gsm) + { +- int len, ret = 0; + /* Priority ordering: We should do priority with RR of the groups */ +- int i = 1; +- +- while (i < NUM_DLCI) { +- struct gsm_dlci *dlci; ++ int i, len, ret = 0; ++ bool sent; ++ struct gsm_dlci *dlci; + +- if (gsm->tx_bytes > TX_THRESH_HI) +- break; +- dlci = gsm->dlci[i]; +- if (dlci == NULL || dlci->constipated) { +- i++; +- continue; ++ while (gsm->tx_bytes < TX_THRESH_HI) { ++ for (sent = false, i = 1; i < NUM_DLCI; i++) { ++ dlci = gsm->dlci[i]; ++ /* skip unused or blocked channel */ ++ if (!dlci || dlci->constipated) ++ continue; ++ /* skip channels with invalid state */ ++ if (dlci->state != DLCI_OPEN) ++ continue; ++ /* count the sent data per adaption */ ++ if (dlci->adaption < 3 && !dlci->net) ++ len = gsm_dlci_data_output(gsm, dlci); ++ else ++ len = gsm_dlci_data_output_framed(gsm, dlci); ++ /* on error exit */ ++ if (len < 0) ++ return ret; ++ if (len > 0) { ++ ret++; ++ sent = true; ++ /* The lower DLCs can starve the higher DLCs! */ ++ break; ++ } ++ /* try next */ + } +- if (dlci->adaption < 3 && !dlci->net) +- len = gsm_dlci_data_output(gsm, dlci); +- else +- len = gsm_dlci_data_output_framed(gsm, dlci); +- if (len < 0) ++ if (!sent) + break; +- /* DLCI empty - try the next */ +- if (len == 0) +- i++; +- else +- ret++; +- } ++ }; + + return ret; + } +@@ -1405,7 +1522,6 @@ static void gsm_control_message(struct g + const u8 *data, int clen) + { + u8 buf[1]; +- unsigned long flags; + struct gsm_dlci *dlci; + int i; + int address; +@@ -1440,9 +1556,7 @@ static void gsm_control_message(struct g + gsm->constipated = false; + gsm_control_reply(gsm, CMD_FCON, NULL, 0); + /* Kick the link in case it is idling */ +- spin_lock_irqsave(&gsm->tx_lock, flags); +- gsm_data_kick(gsm, NULL); +- spin_unlock_irqrestore(&gsm->tx_lock, flags); ++ gsmld_write_trigger(gsm); + break; + case CMD_FCOFF: + /* Modem wants us to STFU */ +@@ -1645,8 +1759,6 @@ static int gsm_control_wait(struct gsm_m + + static void gsm_dlci_close(struct gsm_dlci *dlci) + { +- unsigned long flags; +- + del_timer(&dlci->t1); + if (debug & 8) + pr_debug("DLCI %d goes closed.\n", dlci->addr); +@@ -1655,17 +1767,16 @@ static void gsm_dlci_close(struct gsm_dl + dlci->constipated = true; + if (dlci->addr != 0) { + tty_port_tty_hangup(&dlci->port, false); +- spin_lock_irqsave(&dlci->lock, flags); +- kfifo_reset(&dlci->fifo); +- spin_unlock_irqrestore(&dlci->lock, flags); ++ gsm_dlci_clear_queues(dlci->gsm, dlci); + /* Ensure that gsmtty_open() can return. */ + tty_port_set_initialized(&dlci->port, 0); + wake_up_interruptible(&dlci->port.open_wait); + } else + dlci->gsm->dead = true; +- wake_up(&dlci->gsm->event); + /* A DLCI 0 close is a MUX termination so we need to kick that + back to userspace somehow */ ++ gsm_dlci_data_kick(dlci); ++ wake_up(&dlci->gsm->event); + } + + /** +@@ -1688,6 +1799,7 @@ static void gsm_dlci_open(struct gsm_dlc + /* Send current modem state */ + if (dlci->addr) + gsm_modem_update(dlci, 0); ++ gsm_dlci_data_kick(dlci); + wake_up(&dlci->gsm->event); + } + +@@ -2325,7 +2437,7 @@ static void gsm1_receive(struct gsm_mux + } else if ((c & ISO_IEC_646_MASK) == XOFF) { + gsm->constipated = false; + /* Kick the link in case it is idling */ +- gsm_data_kick(gsm, NULL); ++ gsmld_write_trigger(gsm); + return; + } + if (c == GSM1_SOF) { +@@ -2460,6 +2572,9 @@ static void gsm_cleanup_mux(struct gsm_m + del_timer_sync(&gsm->kick_timer); + del_timer_sync(&gsm->t2_timer); + ++ /* Finish writing to ldisc */ ++ flush_work(&gsm->tx_work); ++ + /* Free up any link layer users and finally the control channel */ + if (gsm->has_devices) { + gsm_unregister_devices(gsm_tty_driver, gsm->num); +@@ -2471,9 +2586,12 @@ static void gsm_cleanup_mux(struct gsm_m + mutex_unlock(&gsm->mutex); + /* Now wipe the queues */ + tty_ldisc_flush(gsm->tty); +- list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) ++ list_for_each_entry_safe(txq, ntxq, &gsm->tx_ctrl_list, list) ++ kfree(txq); ++ INIT_LIST_HEAD(&gsm->tx_ctrl_list); ++ list_for_each_entry_safe(txq, ntxq, &gsm->tx_data_list, list) + kfree(txq); +- INIT_LIST_HEAD(&gsm->tx_list); ++ INIT_LIST_HEAD(&gsm->tx_data_list); + } + + /** +@@ -2496,6 +2614,7 @@ static int gsm_activate_mux(struct gsm_m + + timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); + timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); ++ INIT_WORK(&gsm->tx_work, gsmld_write_task); + init_waitqueue_head(&gsm->event); + spin_lock_init(&gsm->control_lock); + spin_lock_init(&gsm->tx_lock); +@@ -2602,7 +2721,8 @@ static struct gsm_mux *gsm_alloc_mux(voi + spin_lock_init(&gsm->lock); + mutex_init(&gsm->mutex); + kref_init(&gsm->ref); +- INIT_LIST_HEAD(&gsm->tx_list); ++ INIT_LIST_HEAD(&gsm->tx_ctrl_list); ++ INIT_LIST_HEAD(&gsm->tx_data_list); + + gsm->t1 = T1; + gsm->t2 = T2; +@@ -2759,6 +2879,47 @@ static int gsmld_output(struct gsm_mux * + return gsm->tty->ops->write(gsm->tty, data, len); + } + ++ ++/** ++ * gsmld_write_trigger - schedule ldisc write task ++ * @gsm: our mux ++ */ ++static void gsmld_write_trigger(struct gsm_mux *gsm) ++{ ++ if (!gsm || !gsm->dlci[0] || gsm->dlci[0]->dead) ++ return; ++ schedule_work(&gsm->tx_work); ++} ++ ++ ++/** ++ * gsmld_write_task - ldisc write task ++ * @work: our tx write work ++ * ++ * Writes out data to the ldisc if possible. We are doing this here to ++ * avoid dead-locking. This returns if no space or data is left for output. ++ */ ++static void gsmld_write_task(struct work_struct *work) ++{ ++ struct gsm_mux *gsm = container_of(work, struct gsm_mux, tx_work); ++ unsigned long flags; ++ int i, ret; ++ ++ /* All outstanding control channel and control messages and one data ++ * frame is sent. ++ */ ++ ret = -ENODEV; ++ spin_lock_irqsave(&gsm->tx_lock, flags); ++ if (gsm->tty) ++ ret = gsm_data_kick(gsm); ++ spin_unlock_irqrestore(&gsm->tx_lock, flags); ++ ++ if (ret >= 0) ++ for (i = 0; i < NUM_DLCI; i++) ++ if (gsm->dlci[i]) ++ tty_port_tty_wakeup(&gsm->dlci[i]->port); ++} ++ + /** + * gsmld_attach_gsm - mode set up + * @tty: our tty structure +@@ -2902,6 +3063,7 @@ static int gsmld_open(struct tty_struct + + timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); + timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); ++ INIT_WORK(&gsm->tx_work, gsmld_write_task); + + return 0; + } +@@ -2918,16 +3080,9 @@ static int gsmld_open(struct tty_struct + static void gsmld_write_wakeup(struct tty_struct *tty) + { + struct gsm_mux *gsm = tty->disc_data; +- unsigned long flags; + + /* Queue poll */ +- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); +- spin_lock_irqsave(&gsm->tx_lock, flags); +- gsm_data_kick(gsm, NULL); +- if (gsm->tx_bytes < TX_THRESH_LO) { +- gsm_dlci_data_sweep(gsm); +- } +- spin_unlock_irqrestore(&gsm->tx_lock, flags); ++ gsmld_write_trigger(gsm); + } + + /** diff --git a/queue-5.15/xen-netfront-handle-null-returned-by-xdp_convert_buff_to_frame.patch b/queue-5.15/xen-netfront-handle-null-returned-by-xdp_convert_buff_to_frame.patch new file mode 100644 index 0000000000..247086064b --- /dev/null +++ b/queue-5.15/xen-netfront-handle-null-returned-by-xdp_convert_buff_to_frame.patch @@ -0,0 +1,69 @@ +From johnny_haocn@sina.com Fri Mar 27 06:59:57 2026 +From: Johnny Hao +Date: Fri, 27 Mar 2026 13:59:50 +0800 +Subject: xen-netfront: handle NULL returned by xdp_convert_buff_to_frame() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: linux-kernel@vger.kernel.org, Alexey Nepomnyashih , Jakub Kicinski , Johnny Hao +Message-ID: <20260327055950.2618928-1-johnny_haocn@sina.com> + +From: Alexey Nepomnyashih + +[ Upstream commit cc3628dcd851ddd8d418bf0c897024b4621ddc92 ] + +The function xdp_convert_buff_to_frame() may return NULL if it fails +to correctly convert the XDP buffer into an XDP frame due to memory +constraints, internal errors, or invalid data. Failing to check for NULL +may lead to a NULL pointer dereference if the result is used later in +processing, potentially causing crashes, data corruption, or undefined +behavior. + +On XDP redirect failure, the associated page must be released explicitly +if it was previously retained via get_page(). Failing to do so may result +in a memory leak, as the pages reference count is not decremented. + +Cc: stable@vger.kernel.org # v5.9+ +Fixes: 6c5aa6fc4def ("xen networking: add basic XDP support for xen-netfront") +Signed-off-by: Alexey Nepomnyashih +Link: https://patch.msgid.link/20250417122118.1009824-1-sdl@nppct.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Johnny Hao +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/xen-netfront.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -982,20 +982,27 @@ static u32 xennet_run_xdp(struct netfron + act = bpf_prog_run_xdp(prog, xdp); + switch (act) { + case XDP_TX: +- get_page(pdata); + xdpf = xdp_convert_buff_to_frame(xdp); ++ if (unlikely(!xdpf)) { ++ trace_xdp_exception(queue->info->netdev, prog, act); ++ break; ++ } ++ get_page(pdata); + err = xennet_xdp_xmit(queue->info->netdev, 1, &xdpf, 0); +- if (unlikely(!err)) ++ if (unlikely(err <= 0)) { ++ if (err < 0) ++ trace_xdp_exception(queue->info->netdev, prog, act); + xdp_return_frame_rx_napi(xdpf); +- else if (unlikely(err < 0)) +- trace_xdp_exception(queue->info->netdev, prog, act); ++ } + break; + case XDP_REDIRECT: + get_page(pdata); + err = xdp_do_redirect(queue->info->netdev, xdp, prog); + *need_xdp_flush = true; +- if (unlikely(err)) ++ if (unlikely(err)) { + trace_xdp_exception(queue->info->netdev, prog, act); ++ xdp_return_buff(xdp); ++ } + break; + case XDP_PASS: + case XDP_DROP: diff --git a/queue-5.15/xfrm-clear-trailing-padding-in-build_polexpire.patch b/queue-5.15/xfrm-clear-trailing-padding-in-build_polexpire.patch new file mode 100644 index 0000000000..ea7037c7bf --- /dev/null +++ b/queue-5.15/xfrm-clear-trailing-padding-in-build_polexpire.patch @@ -0,0 +1,48 @@ +From stable+bounces-237666-greg=kroah.com@vger.kernel.org Mon Apr 13 23:59:54 2026 +From: Sasha Levin +Date: Mon, 13 Apr 2026 17:59:48 -0400 +Subject: xfrm: clear trailing padding in build_polexpire() +To: stable@vger.kernel.org +Cc: Yasuaki Torimaru , Simon Horman , Breno Leitao , Steffen Klassert , Sasha Levin +Message-ID: <20260413215948.3711943-1-sashal@kernel.org> + +From: Yasuaki Torimaru + +[ Upstream commit 71a98248c63c535eaa4d4c22f099b68d902006d0 ] + +build_expire() clears the trailing padding bytes of struct +xfrm_user_expire after setting the hard field via memset_after(), +but the analogous function build_polexpire() does not do this for +struct xfrm_user_polexpire. + +The padding bytes after the __u8 hard field are left +uninitialized from the heap allocation, and are then sent to +userspace via netlink multicast to XFRMNLGRP_EXPIRE listeners, +leaking kernel heap memory contents. + +Add the missing memset_after() call, matching build_expire(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Yasuaki Torimaru +Reviewed-by: Simon Horman +Reviewed-by: Breno Leitao +Signed-off-by: Steffen Klassert +[ replaced `memset_after()` macro with equivalent manual `memset()` call ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_user.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -3389,6 +3389,8 @@ static int build_polexpire(struct sk_buf + return err; + } + upe->hard = !!hard; ++ /* clear the padding bytes */ ++ memset(&upe->hard + 1, 0, sizeof(*upe) - offsetofend(typeof(*upe), hard)); + + nlmsg_end(skb, nlh); + return 0;