--- /dev/null
+From 09cc7451932b608d2e1ca3da99956af6f9ef6015 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 10:28:49 +0800
+Subject: s390/debug: Reject zero-length input before trimming a newline
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit c366a7b5ed7564e41345c380285bd3f6cb98971b ]
+
+debug_get_user_string() copies the userspace buffer into a newly
+allocated NUL-terminated buffer and then unconditionally looks at
+buffer[user_len - 1] to strip a trailing newline.
+
+A zero-length write reaches this helper unchanged, so the newline trim
+reads before the start of the allocated buffer.
+
+Reject empty writes before accessing the last input byte.
+
+Fixes: 66a464dbc8e0 ("[PATCH] s390: debug feature changes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
+Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
+Tested-by: Vasily Gorbik <gor@linux.ibm.com>
+Link: https://lore.kernel.org/r/20260417073530.96002-1-pengpeng@iscas.ac.cn
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/debug.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
+index ece21ebf6558f..a347f6244654a 100644
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -1211,6 +1211,9 @@ static inline char *debug_get_user_string(const char __user *user_buf,
+ {
+ char *buffer;
+
++ if (!user_len)
++ return ERR_PTR(-EINVAL);
++
+ buffer = kmalloc(user_len + 1, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+--
+2.53.0
+
--- /dev/null
+From cde6bc671b5ec15da7887b36aa6a15c3d8d98dd9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 May 2021 20:17:54 -0700
+Subject: selftests: lib.mk: Also install "config" and "settings"
+
+From: Kees Cook <keescook@chromium.org>
+
+[ Upstream commit de53fa9baa701963722e9fa3d0fe34b897104497 ]
+
+Installed seccomp tests would time out because the "settings" file was
+missing. Install both "settings" (needed for proper test execution) and
+"config" (needed for informational purposes) with the other test
+targets.
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/lib.mk | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
+index 56e360e019ecc..a3df78b7702c1 100644
+--- a/tools/testing/selftests/lib.mk
++++ b/tools/testing/selftests/lib.mk
+@@ -101,6 +101,7 @@ define INSTALL_RULE
+ $(eval INSTALL_LIST = $(TEST_CUSTOM_PROGS)) $(INSTALL_SINGLE_RULE)
+ $(eval INSTALL_LIST = $(TEST_GEN_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE)
+ $(eval INSTALL_LIST = $(TEST_GEN_FILES)) $(INSTALL_SINGLE_RULE)
++ $(eval INSTALL_LIST = $(wildcard config settings)) $(INSTALL_SINGLE_RULE)
+ endef
+
+ install: all
+--
+2.53.0
+
drm-gma500-oaktrail_hdmi-fix-i2c-adapter-leak-on-setup.patch
io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch
net-rds-reset-op_nents-when-zerocopy-page-pin-fails.patch
+s390-debug-reject-zero-length-input-before-trimming-.patch
+selftests-lib.mk-also-install-config-and-settings.patch
--- /dev/null
+From a0f4558747dd5218b3f0de44d5f76a880bd0a469 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 14:28:33 +0800
+Subject: io_uring: prevent opcode speculation
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit 1e988c3fe1264708f4f92109203ac5b1d65de50b ]
+
+sqe->opcode is used for different tables, make sure we santitise it
+against speculations.
+
+Cc: stable@vger.kernel.org
+Fixes: d3656344fea03 ("io_uring: add lookup table for various opcode needs")
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Reviewed-by: Li Zetao <lizetao1@huawei.com>
+Link: https://lore.kernel.org/r/7eddbf31c8ca0a3947f8ed98271acc2b4349c016.1739568408.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+[ Use req->opcode instead of opcode here. ]
+Signed-off-by: Robert Garcia <rob_garcia@163.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index cb54ebda0a8a7..8ecf01f1b689e 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -7366,6 +7366,8 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
+ return -EINVAL;
+ if (unlikely(req->opcode >= IORING_OP_LAST))
+ return -EINVAL;
++ req->opcode = array_index_nospec(req->opcode, IORING_OP_LAST);
++
+ if (!io_check_restriction(ctx, req, sqe_flags))
+ return -EACCES;
+
+--
+2.53.0
+
--- /dev/null
+From 67bbc6674d5ddb9e7f2fc066c4d9fadf547064e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 10:28:44 +0800
+Subject: s390/debug: Reject zero-length input before trimming a newline
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit c366a7b5ed7564e41345c380285bd3f6cb98971b ]
+
+debug_get_user_string() copies the userspace buffer into a newly
+allocated NUL-terminated buffer and then unconditionally looks at
+buffer[user_len - 1] to strip a trailing newline.
+
+A zero-length write reaches this helper unchanged, so the newline trim
+reads before the start of the allocated buffer.
+
+Reject empty writes before accessing the last input byte.
+
+Fixes: 66a464dbc8e0 ("[PATCH] s390: debug feature changes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
+Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
+Tested-by: Vasily Gorbik <gor@linux.ibm.com>
+Link: https://lore.kernel.org/r/20260417073530.96002-1-pengpeng@iscas.ac.cn
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/debug.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
+index 089d91a3cf5a1..1d7b619acdf30 100644
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -1268,6 +1268,9 @@ static inline char *debug_get_user_string(const char __user *user_buf,
+ {
+ char *buffer;
+
++ if (!user_len)
++ return ERR_PTR(-EINVAL);
++
+ buffer = kmalloc(user_len + 1, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+--
+2.53.0
+
drm-gma500-oaktrail_hdmi-fix-i2c-adapter-leak-on-setup.patch
io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch
net-rds-reset-op_nents-when-zerocopy-page-pin-fails.patch
+io_uring-prevent-opcode-speculation.patch
+s390-debug-reject-zero-length-input-before-trimming-.patch
--- /dev/null
+From 63a69ee23ce4980618c5304dbdcbf10bf82a7f1a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 13:49:19 +0800
+Subject: io_uring: prevent opcode speculation
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit 1e988c3fe1264708f4f92109203ac5b1d65de50b ]
+
+sqe->opcode is used for different tables, make sure we santitise it
+against speculations.
+
+Cc: stable@vger.kernel.org
+Fixes: d3656344fea03 ("io_uring: add lookup table for various opcode needs")
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Reviewed-by: Li Zetao <lizetao1@huawei.com>
+Link: https://lore.kernel.org/r/7eddbf31c8ca0a3947f8ed98271acc2b4349c016.1739568408.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Robert Garcia <rob_garcia@163.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index d0d9ff6b87a08..fdb8afdb01353 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -2031,6 +2031,8 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
+ req->opcode = 0;
+ return io_init_fail_req(req, -EINVAL);
+ }
++ opcode = array_index_nospec(opcode, IORING_OP_LAST);
++
+ def = &io_op_defs[opcode];
+ if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
+ /* enforce forwards compatibility on users */
+--
+2.53.0
+
--- /dev/null
+From 6855bc14b0b41855665bb9062c8c55917450ac26 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 10:28:39 +0800
+Subject: s390/debug: Reject zero-length input before trimming a newline
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit c366a7b5ed7564e41345c380285bd3f6cb98971b ]
+
+debug_get_user_string() copies the userspace buffer into a newly
+allocated NUL-terminated buffer and then unconditionally looks at
+buffer[user_len - 1] to strip a trailing newline.
+
+A zero-length write reaches this helper unchanged, so the newline trim
+reads before the start of the allocated buffer.
+
+Reject empty writes before accessing the last input byte.
+
+Fixes: 66a464dbc8e0 ("[PATCH] s390: debug feature changes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
+Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
+Tested-by: Vasily Gorbik <gor@linux.ibm.com>
+Link: https://lore.kernel.org/r/20260417073530.96002-1-pengpeng@iscas.ac.cn
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/debug.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
+index 9a94979ee4de5..65302aea77e85 100644
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -1268,6 +1268,9 @@ static inline char *debug_get_user_string(const char __user *user_buf,
+ {
+ char *buffer;
+
++ if (!user_len)
++ return ERR_PTR(-EINVAL);
++
+ buffer = kmalloc(user_len + 1, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+--
+2.53.0
+
drm-gma500-oaktrail_lvds-fix-i2c-adapter-leaks-on-init.patch
io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch
net-rds-reset-op_nents-when-zerocopy-page-pin-fails.patch
+io_uring-prevent-opcode-speculation.patch
+s390-debug-reject-zero-length-input-before-trimming-.patch
--- /dev/null
+From 7b88280e0ecc6ff061528c7431048fd3e8b958b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 May 2026 16:40:58 -0300
+Subject: drm/xe/hdcp: Add NULL check for media_gt in
+ intel_hdcp_gsc_check_status()
+
+From: Gustavo Sousa <gustavo.sousa@intel.com>
+
+commit 60a1e131a811b68703da58fd805ab359b704ab03 upstream.
+
+When media GT is disabled via configfs, there is no allocation for
+media_gt, which is kept as NULL. In such scenario,
+intel_hdcp_gsc_check_status() results in a kernel pagefault error due to
+>->uc.gsc being evaluated as an invalid memory address.
+
+Fix that by introducing a NULL check on media_gt and bailing out early
+if so.
+
+While at it, also drop the NULL check for gsc, since it can't be NULL if
+media_gt is not NULL.
+
+v2:
+ - Get address for gsc only after checking that gt is not NULL.
+ (Shuicheng)
+ - Drop the NULL check for gsc. (Shuicheng)
+v3:
+ - Add "Fixes" and "Cc: <stable...>" tags. (Matt)
+
+Fixes: 4af50beb4e0f ("drm/xe: Use gsc_proxy_init_done to check proxy status")
+Cc: <stable@vger.kernel.org> # v6.10+
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+Reviewed-by: Shuicheng Lin <shuicheng.lin@intel.com>
+Link: https://patch.msgid.link/20260416-check-for-null-media_gt-in-intel_hdcp_gsc_check_status-v2-1-9adb9fd3b621@intel.com
+Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
+(cherry picked from commit bfaf87e84ca3ca3f6e275f9ae56da47a8b55ffd1)
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/display/xe_hdcp_gsc.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+index f4332f06b6c80..695d625c83ee6 100644
+--- a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
++++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+@@ -39,10 +39,18 @@ bool intel_hdcp_gsc_check_status(struct xe_device *xe)
+ {
+ struct xe_tile *tile = xe_device_get_root_tile(xe);
+ struct xe_gt *gt = tile->media_gt;
+- struct xe_gsc *gsc = >->uc.gsc;
++ struct xe_gsc *gsc;
+ bool ret = true;
+
+- if (!gsc || !xe_uc_fw_is_enabled(&gsc->fw)) {
++ if (!gt) {
++ drm_dbg_kms(&xe->drm,
++ "not checking GSC status for HDCP2.x: media GT not present or disabled\n");
++ return false;
++ }
++
++ gsc = >->uc.gsc;
++
++ if (!xe_uc_fw_is_enabled(&gsc->fw)) {
+ drm_dbg_kms(&xe->drm,
+ "GSC Components not ready for HDCP2.x\n");
+ return false;
+--
+2.53.0
+
--- /dev/null
+From 8b7f7f2e71f479151b87f7729ff68b0b9980597e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 May 2026 15:25:12 +0800
+Subject: ksmbd: validate owner of durable handle on reconnect
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 49110a8ce654bbe56bef7c5e44cce31f4b102b8a ]
+
+Currently, ksmbd does not verify if the user attempting to reconnect
+to a durable handle is the same user who originally opened the file.
+This allows any authenticated user to hijack an orphaned durable handle
+by predicting or brute-forcing the persistent ID.
+
+According to MS-SMB2, the server MUST verify that the SecurityContext
+of the reconnect request matches the SecurityContext associated with
+the existing open.
+Add a durable_owner structure to ksmbd_file to store the original opener's
+UID, GID, and account name. and catpure the owner information when a file
+handle becomes orphaned. and implementing ksmbd_vfs_compare_durable_owner()
+to validate the identity of the requester during SMB2_CREATE (DHnC).
+
+Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2")
+Reported-by: Davide Ornaghi <d.ornaghi97@gmail.com>
+Reported-by: Navaneeth K <knavaneeth786@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+[ Minor context conflict resolved. ]
+Signed-off-by: Alva Lan <alvalan9@foxmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/mgmt/user_session.c | 7 ++-
+ fs/smb/server/oplock.c | 7 +++
+ fs/smb/server/oplock.h | 1 +
+ fs/smb/server/smb2pdu.c | 3 +-
+ fs/smb/server/vfs_cache.c | 87 +++++++++++++++++++++++++++----
+ fs/smb/server/vfs_cache.h | 12 ++++-
+ 6 files changed, 102 insertions(+), 15 deletions(-)
+
+diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
+index 151248e02e9eb..ecd511351f19b 100644
+--- a/fs/smb/server/mgmt/user_session.c
++++ b/fs/smb/server/mgmt/user_session.c
+@@ -161,11 +161,10 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
+ if (!sess)
+ return;
+
++ ksmbd_tree_conn_session_logoff(sess);
++ ksmbd_destroy_file_table(sess);
+ if (sess->user)
+ ksmbd_free_user(sess->user);
+-
+- ksmbd_tree_conn_session_logoff(sess);
+- ksmbd_destroy_file_table(&sess->file_table);
+ ksmbd_launch_ksmbd_durable_scavenger();
+ ksmbd_session_rpc_clear_list(sess);
+ free_channel_list(sess);
+@@ -402,7 +401,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
+ goto out;
+ }
+
+- ksmbd_destroy_file_table(&prev_sess->file_table);
++ ksmbd_destroy_file_table(prev_sess);
+ prev_sess->state = SMB2_SESSION_EXPIRED;
+ ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
+ ksmbd_launch_ksmbd_durable_scavenger();
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index 590ddd31a68da..bbb2cb3782d0c 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -1841,6 +1841,7 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn,
+ struct ksmbd_share_config *share,
+ struct ksmbd_file *fp,
+ struct lease_ctx_info *lctx,
++ struct ksmbd_user *user,
+ char *name)
+ {
+ struct oplock_info *opinfo = opinfo_get(fp);
+@@ -1849,6 +1850,12 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn,
+ if (!opinfo)
+ return 0;
+
++ if (ksmbd_vfs_compare_durable_owner(fp, user) == false) {
++ ksmbd_debug(SMB, "Durable handle reconnect failed: owner mismatch\n");
++ ret = -EBADF;
++ goto out;
++ }
++
+ if (opinfo->is_lease == false) {
+ if (lctx) {
+ pr_err("create context include lease\n");
+diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h
+index 921e3199e4df4..d91a8266e065e 100644
+--- a/fs/smb/server/oplock.h
++++ b/fs/smb/server/oplock.h
+@@ -126,5 +126,6 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn,
+ struct ksmbd_share_config *share,
+ struct ksmbd_file *fp,
+ struct lease_ctx_info *lctx,
++ struct ksmbd_user *user,
+ char *name);
+ #endif /* __KSMBD_OPLOCK_H */
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index 700d9da3c65a9..a691801e1d7bd 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -3016,7 +3016,8 @@ int smb2_open(struct ksmbd_work *work)
+ }
+
+ if (dh_info.reconnected == true) {
+- rc = smb2_check_durable_oplock(conn, share, dh_info.fp, lc, name);
++ rc = smb2_check_durable_oplock(conn, share, dh_info.fp,
++ lc, sess->user, name);
+ if (rc) {
+ ksmbd_put_durable_fd(dh_info.fp);
+ goto err_out2;
+diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
+index 08f25a2d75416..d29cc1d01bd2c 100644
+--- a/fs/smb/server/vfs_cache.c
++++ b/fs/smb/server/vfs_cache.c
+@@ -18,6 +18,7 @@
+ #include "connection.h"
+ #include "mgmt/tree_connect.h"
+ #include "mgmt/user_session.h"
++#include "mgmt/user_config.h"
+ #include "smb_common.h"
+ #include "server.h"
+
+@@ -383,6 +384,8 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
+
+ if (ksmbd_stream_fd(fp))
+ kfree(fp->stream.name);
++ kfree(fp->owner.name);
++
+ kmem_cache_free(filp_cache, fp);
+ }
+
+@@ -694,11 +697,13 @@ void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
+ }
+
+ static int
+-__close_file_table_ids(struct ksmbd_file_table *ft,
++__close_file_table_ids(struct ksmbd_session *sess,
+ struct ksmbd_tree_connect *tcon,
+ bool (*skip)(struct ksmbd_tree_connect *tcon,
+- struct ksmbd_file *fp))
++ struct ksmbd_file *fp,
++ struct ksmbd_user *user))
+ {
++ struct ksmbd_file_table *ft = &sess->file_table;
+ struct ksmbd_file *fp;
+ unsigned int id = 0;
+ int num = 0;
+@@ -711,7 +716,7 @@ __close_file_table_ids(struct ksmbd_file_table *ft,
+ break;
+ }
+
+- if (skip(tcon, fp) ||
++ if (skip(tcon, fp, sess->user) ||
+ !atomic_dec_and_test(&fp->refcount)) {
+ id++;
+ write_unlock(&ft->lock);
+@@ -763,7 +768,8 @@ static inline bool is_reconnectable(struct ksmbd_file *fp)
+ }
+
+ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
+- struct ksmbd_file *fp)
++ struct ksmbd_file *fp,
++ struct ksmbd_user *user)
+ {
+ return fp->tcon != tcon;
+ }
+@@ -898,8 +904,62 @@ void ksmbd_stop_durable_scavenger(void)
+ kthread_stop(server_conf.dh_task);
+ }
+
++/*
++ * ksmbd_vfs_copy_durable_owner - Copy owner info for durable reconnect
++ * @fp: ksmbd file pointer to store owner info
++ * @user: user pointer to copy from
++ *
++ * This function binds the current user's identity to the file handle
++ * to satisfy MS-SMB2 Step 8 (SecurityContext matching) during reconnect.
++ *
++ * Return: 0 on success, or negative error code on failure
++ */
++static int ksmbd_vfs_copy_durable_owner(struct ksmbd_file *fp,
++ struct ksmbd_user *user)
++{
++ if (!user)
++ return -EINVAL;
++
++ /* Duplicate the user name to ensure identity persistence */
++ fp->owner.name = kstrdup(user->name, GFP_KERNEL);
++ if (!fp->owner.name)
++ return -ENOMEM;
++
++ fp->owner.uid = user->uid;
++ fp->owner.gid = user->gid;
++
++ return 0;
++}
++
++/**
++ * ksmbd_vfs_compare_durable_owner - Verify if the requester is original owner
++ * @fp: existing ksmbd file pointer
++ * @user: user pointer of the reconnect requester
++ *
++ * Compares the UID, GID, and name of the current requester against the
++ * original owner stored in the file handle.
++ *
++ * Return: true if the user matches, false otherwise
++ */
++bool ksmbd_vfs_compare_durable_owner(struct ksmbd_file *fp,
++ struct ksmbd_user *user)
++{
++ if (!user || !fp->owner.name)
++ return false;
++
++ /* Check if the UID and GID match first (fast path) */
++ if (fp->owner.uid != user->uid || fp->owner.gid != user->gid)
++ return false;
++
++ /* Validate the account name to ensure the same SecurityContext */
++ if (strcmp(fp->owner.name, user->name))
++ return false;
++
++ return true;
++}
++
+ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
+- struct ksmbd_file *fp)
++ struct ksmbd_file *fp, struct ksmbd_user *user)
+ {
+ struct ksmbd_inode *ci;
+ struct oplock_info *op;
+@@ -909,6 +969,9 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
+ if (!is_reconnectable(fp))
+ return false;
+
++ if (ksmbd_vfs_copy_durable_owner(fp, user))
++ return false;
++
+ conn = fp->conn;
+ ci = fp->f_ci;
+ down_write(&ci->m_lock);
+@@ -940,7 +1003,7 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
+
+ void ksmbd_close_tree_conn_fds(struct ksmbd_work *work)
+ {
+- int num = __close_file_table_ids(&work->sess->file_table,
++ int num = __close_file_table_ids(work->sess,
+ work->tcon,
+ tree_conn_fd_check);
+
+@@ -949,7 +1012,7 @@ void ksmbd_close_tree_conn_fds(struct ksmbd_work *work)
+
+ void ksmbd_close_session_fds(struct ksmbd_work *work)
+ {
+- int num = __close_file_table_ids(&work->sess->file_table,
++ int num = __close_file_table_ids(work->sess,
+ work->tcon,
+ session_fd_check);
+
+@@ -1046,6 +1109,10 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
+ }
+ up_write(&ci->m_lock);
+
++ fp->owner.uid = fp->owner.gid = 0;
++ kfree(fp->owner.name);
++ fp->owner.name = NULL;
++
+ return 0;
+ }
+
+@@ -1060,12 +1127,14 @@ int ksmbd_init_file_table(struct ksmbd_file_table *ft)
+ return 0;
+ }
+
+-void ksmbd_destroy_file_table(struct ksmbd_file_table *ft)
++void ksmbd_destroy_file_table(struct ksmbd_session *sess)
+ {
++ struct ksmbd_file_table *ft = &sess->file_table;
++
+ if (!ft->idr)
+ return;
+
+- __close_file_table_ids(ft, NULL, session_fd_check);
++ __close_file_table_ids(sess, NULL, session_fd_check);
+ idr_destroy(ft->idr);
+ kfree(ft->idr);
+ ft->idr = NULL;
+diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
+index 5bbb179736c29..1b2a947490ca5 100644
+--- a/fs/smb/server/vfs_cache.h
++++ b/fs/smb/server/vfs_cache.h
+@@ -67,6 +67,13 @@ enum {
+ FP_CLOSED
+ };
+
++/* Owner information for durable handle reconnect */
++struct durable_owner {
++ unsigned int uid;
++ unsigned int gid;
++ char *name;
++};
++
+ struct ksmbd_file {
+ struct file *filp;
+ u64 persistent_id;
+@@ -111,6 +118,7 @@ struct ksmbd_file {
+ bool is_durable;
+ bool is_persistent;
+ bool is_resilient;
++ struct durable_owner owner;
+ };
+
+ static inline void set_ctx_actor(struct dir_context *ctx,
+@@ -137,7 +145,7 @@ static inline bool ksmbd_stream_fd(struct ksmbd_file *fp)
+ }
+
+ int ksmbd_init_file_table(struct ksmbd_file_table *ft);
+-void ksmbd_destroy_file_table(struct ksmbd_file_table *ft);
++void ksmbd_destroy_file_table(struct ksmbd_session *sess);
+ int ksmbd_close_fd(struct ksmbd_work *work, u64 id);
+ struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, u64 id);
+ struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id);
+@@ -163,6 +171,8 @@ void ksmbd_free_global_file_table(void);
+ void ksmbd_set_fd_limit(unsigned long limit);
+ void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
+ unsigned int state);
++bool ksmbd_vfs_compare_durable_owner(struct ksmbd_file *fp,
++ struct ksmbd_user *user);
+
+ /*
+ * INODE hash
+--
+2.53.0
+
--- /dev/null
+From cdadf9d85c986650e37a2c7a7d17c343677513aa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:08:48 +0200
+Subject: mptcp: pm: ADD_ADDR rtx: allow ID 0
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+commit 03f324f3f1f7619a47b9c91282cb12775ab0a2f1 upstream.
+
+ADD_ADDR can be sent for the ID 0, which corresponds to the local
+address and port linked to the initial subflow.
+
+Indeed, this address could be removed, and re-added later on, e.g. what
+is done in the "delete re-add signal" MPTCP Join selftests. So no reason
+to ignore it.
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-2-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ applied to net/mptcp/pm_netlink.c instead of upstream's pm_kernel.c ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/pm_netlink.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
+index 5d892583ab4ef..857e8db670a75 100644
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -304,9 +304,6 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ if (inet_sk_state_load(sk) == TCP_CLOSE)
+ return;
+
+- if (!entry->addr.id)
+- return;
+-
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) {
+ /* Try again later. */
+--
+2.53.0
+
--- /dev/null
+From dd1e3ca71e8ed4d5b7e3ca41f25d4da15b8e03df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:08:49 +0200
+Subject: mptcp: pm: ADD_ADDR rtx: always decrease sk refcount
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+commit 9634cb35af17019baec21ca648516ce376fa10e6 upstream.
+
+When an ADD_ADDR is retransmitted, the sk is held in sk_reset_timer().
+It should then be released in all cases at the end.
+
+Some (unlikely) checks were returning directly instead of calling
+sock_put() to decrease the refcount. Jump to a new 'exit' label to call
+__sock_put() (which will become sock_put() in the next commit) to fix
+this potential leak.
+
+While at it, drop the '!msk' check which cannot happen because it is
+never reset, and explicitly mark the remaining one as "unlikely".
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-4-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ applied to net/mptcp/pm_netlink.c instead of upstream's pm_kernel.c ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/pm_netlink.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
+index 857e8db670a75..be531df02c371 100644
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -298,11 +298,8 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+
+ pr_debug("msk=%p\n", msk);
+
+- if (!msk)
+- return;
+-
+- if (inet_sk_state_load(sk) == TCP_CLOSE)
+- return;
++ if (unlikely(inet_sk_state_load(sk) == TCP_CLOSE))
++ goto exit;
+
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) {
+@@ -340,6 +337,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+
+ out:
+ bh_unlock_sock(sk);
++exit:
+ __sock_put(sk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 4c2a4761538bc2d0cb491cc4d417bed5f2065790 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:08:50 +0200
+Subject: mptcp: pm: ADD_ADDR rtx: free sk if last
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+commit b7b9a461569734d33d3259d58d2507adfac107ed upstream.
+
+When an ADD_ADDR is retransmitted, the sk is held in sk_reset_timer(),
+and released at the end.
+
+If at that moment, it was the last reference being held, the sk would
+not be freed. sock_put() should then be called instead of __sock_put().
+
+But that's not enough: if it is the last reference, sock_put() will call
+sk_free(), which will end up calling sk_stop_timer_sync() on the same
+timer, and waiting indefinitely to finish. So it is needed to mark that
+the timer is done at the end of the timer handler when it has not been
+rescheduled, not to call sk_stop_timer_sync() on "itself".
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-5-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Applied to net/mptcp/pm_netlink.c instead of upstream's pm_kernel.c.
+ Also, there were conflicts, because commit 30549eebc4d8 ("mptcp: make
+ ADD_ADDR retransmission timeout adaptive") is not in this version and
+ changed the context. Also, other conflicts were due to newer patches
+ being backported with resolved conflicts before this one. ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/pm_netlink.c | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
+index be531df02c371..4ff6721ad5c7a 100644
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -22,6 +22,7 @@ struct mptcp_pm_add_entry {
+ struct list_head list;
+ struct mptcp_addr_info addr;
+ u8 retrans_times;
++ bool timer_done;
+ struct timer_list add_timer;
+ struct mptcp_sock *sock;
+ struct rcu_head rcu;
+@@ -294,22 +295,22 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ struct mptcp_pm_add_entry *entry = from_timer(entry, timer, add_timer);
+ struct mptcp_sock *msk = entry->sock;
+ struct sock *sk = (struct sock *)msk;
+- unsigned int timeout;
++ unsigned int timeout = 0;
+
+ pr_debug("msk=%p\n", msk);
+
++ bh_lock_sock(sk);
+ if (unlikely(inet_sk_state_load(sk) == TCP_CLOSE))
+- goto exit;
++ goto out;
+
+- bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) {
+ /* Try again later. */
+- sk_reset_timer(sk, timer, jiffies + HZ / 20);
++ timeout = HZ / 20;
+ goto out;
+ }
+
+ if (mptcp_pm_should_add_signal_addr(msk)) {
+- sk_reset_timer(sk, timer, jiffies + HZ);
++ timeout = HZ;
+ goto out;
+ }
+
+@@ -326,9 +327,8 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ entry->retrans_times++;
+ }
+
+- if (entry->retrans_times < ADD_ADDR_RETRANS_MAX)
+- sk_reset_timer(sk, timer,
+- jiffies + timeout);
++ if (entry->retrans_times >= ADD_ADDR_RETRANS_MAX)
++ timeout = 0;
+
+ spin_unlock_bh(&msk->pm.lock);
+
+@@ -336,9 +336,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ mptcp_pm_subflow_established(msk);
+
+ out:
++ if (timeout)
++ sk_reset_timer(sk, timer, jiffies + timeout);
++ else
++ /* if sock_put calls sk_free: avoid waiting for this timer */
++ entry->timer_done = true;
+ bh_unlock_sock(sk);
+-exit:
+- __sock_put(sk);
++ sock_put(sk);
+ }
+
+ struct mptcp_pm_add_entry *
+@@ -402,6 +406,7 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
+
+ timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0);
+ reset_timer:
++ add_entry->timer_done = false;
+ timeout = mptcp_get_add_addr_timeout(net);
+ if (timeout)
+ sk_reset_timer(sk, &add_entry->add_timer, jiffies + timeout);
+@@ -422,7 +427,8 @@ void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
+ spin_unlock_bh(&msk->pm.lock);
+
+ list_for_each_entry_safe(entry, tmp, &free_list, list) {
+- sk_stop_timer_sync(sk, &entry->add_timer);
++ if (!entry->timer_done)
++ sk_stop_timer_sync(sk, &entry->add_timer);
+ kfree_rcu(entry, rcu);
+ }
+ }
+--
+2.53.0
+
--- /dev/null
+From 480cb287ee0fc8988f79ff97c57b801c8fc9fb40 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:08:47 +0200
+Subject: mptcp: sync the msk->sndbuf at accept() time
+
+From: Gang Yan <yangang@kylinos.cn>
+
+commit fcf04b14334641f4b0b8647824480935e9416d52 upstream.
+
+On passive MPTCP connections, the msk sndbuf is not updated correctly.
+
+The root cause is an order issue in the accept path:
+
+- tcp_check_req() -> subflow_syn_recv_sock() -> mptcp_sk_clone_init()
+ calls __mptcp_propagate_sndbuf() to copy the ssk sndbuf into msk
+
+- Later, tcp_child_process() -> tcp_init_transfer() ->
+ tcp_sndbuf_expand() grows the ssk sndbuf.
+
+So __mptcp_propagate_sndbuf() runs before the ssk sndbuf has been
+expanded and the msk ends up with a much smaller sndbuf than the
+subflow:
+
+ MPTCP: msk->sndbuf:20480, msk->first->sndbuf:2626560
+
+Fix this by moving the __mptcp_propagate_sndbuf() call from
+mptcp_sk_clone_init() -- the ssk sndbuf is not yet finalized there -- to
+__mptcp_propagate_sndbuf() at accept() time, when the ssk sndbuf has
+been fully expanded by tcp_sndbuf_expand().
+
+Fixes: 8005184fd1ca ("mptcp: refactor sndbuf auto-tuning")
+Cc: stable@vger.kernel.org
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/602
+Signed-off-by: Gang Yan <yangang@kylinos.cn>
+Acked-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260420-net-mptcp-sync-sndbuf-accept-v1-1-e3523e3aeb44@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ No conflicts, but move __mptcp_propagate_sndbuf() above the for-loop
+ (mptcp_for_each_subflow()) present in this version, which will modify
+ 'subflow' used by __mptcp_propagate_sndbuf() in this new patch. ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index 7dbb666c72c30..c1b1fb0fe8bcb 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -3493,7 +3493,6 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
+ * uses the correct data
+ */
+ mptcp_copy_inaddrs(nsk, ssk);
+- __mptcp_propagate_sndbuf(nsk, ssk);
+
+ mptcp_rcv_space_init(msk, ssk);
+ msk->rcvq_space.time = mptcp_stamp();
+@@ -4101,6 +4100,8 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
+ msk = mptcp_sk(newsk);
+ msk->in_accept_queue = 0;
+
++ __mptcp_propagate_sndbuf(newsk, mptcp_subflow_tcp_sock(subflow));
++
+ /* set ssk->sk_socket of accept()ed flows to mptcp socket.
+ * This is needed so NOSPACE flag can be set from tcp stack.
+ */
+--
+2.53.0
+
--- /dev/null
+From a9982a19d49df8c9a2e0d654fb5e0e53f94cda44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 10:28:29 +0800
+Subject: s390/debug: Reject zero-length input before trimming a newline
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit c366a7b5ed7564e41345c380285bd3f6cb98971b ]
+
+debug_get_user_string() copies the userspace buffer into a newly
+allocated NUL-terminated buffer and then unconditionally looks at
+buffer[user_len - 1] to strip a trailing newline.
+
+A zero-length write reaches this helper unchanged, so the newline trim
+reads before the start of the allocated buffer.
+
+Reject empty writes before accessing the last input byte.
+
+Fixes: 66a464dbc8e0 ("[PATCH] s390: debug feature changes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
+Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
+Tested-by: Vasily Gorbik <gor@linux.ibm.com>
+Link: https://lore.kernel.org/r/20260417073530.96002-1-pengpeng@iscas.ac.cn
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/debug.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
+index e4b324dcfe0d3..16bb554a07fef 100644
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -1256,6 +1256,9 @@ static inline char *debug_get_user_string(const char __user *user_buf,
+ {
+ char *buffer;
+
++ if (!user_len)
++ return ERR_PTR(-EINVAL);
++
+ buffer = kmalloc(user_len + 1, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+--
+2.53.0
+
--- /dev/null
+mptcp-sync-the-msk-sndbuf-at-accept-time.patch
+mptcp-pm-add_addr-rtx-allow-id-0.patch
+mptcp-pm-add_addr-rtx-always-decrease-sk-refcount.patch
+mptcp-pm-add_addr-rtx-free-sk-if-last.patch
+ksmbd-validate-owner-of-durable-handle-on-reconnect.patch
+drm-xe-hdcp-add-null-check-for-media_gt-in-intel_hdc.patch
+s390-debug-reject-zero-length-input-before-trimming-.patch
--- /dev/null
+From 40136dd811ff5838af10483a8b38b16688d2a90b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 May 2026 15:47:22 -0300
+Subject: drm/xe/hdcp: Add NULL check for media_gt in
+ intel_hdcp_gsc_check_status()
+
+From: Gustavo Sousa <gustavo.sousa@intel.com>
+
+commit 60a1e131a811b68703da58fd805ab359b704ab03 upstream.
+
+When media GT is disabled via configfs, there is no allocation for
+media_gt, which is kept as NULL. In such scenario,
+intel_hdcp_gsc_check_status() results in a kernel pagefault error due to
+>->uc.gsc being evaluated as an invalid memory address.
+
+Fix that by introducing a NULL check on media_gt and bailing out early
+if so.
+
+While at it, also drop the NULL check for gsc, since it can't be NULL if
+media_gt is not NULL.
+
+v2:
+ - Get address for gsc only after checking that gt is not NULL.
+ (Shuicheng)
+ - Drop the NULL check for gsc. (Shuicheng)
+v3:
+ - Add "Fixes" and "Cc: <stable...>" tags. (Matt)
+
+Fixes: 4af50beb4e0f ("drm/xe: Use gsc_proxy_init_done to check proxy status")
+Cc: <stable@vger.kernel.org> # v6.10+
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+Reviewed-by: Shuicheng Lin <shuicheng.lin@intel.com>
+Link: https://patch.msgid.link/20260416-check-for-null-media_gt-in-intel_hdcp_gsc_check_status-v2-1-9adb9fd3b621@intel.com
+Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
+(cherry picked from commit bfaf87e84ca3ca3f6e275f9ae56da47a8b55ffd1)
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/display/xe_hdcp_gsc.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+index 4ae847b628e23..6324f526dcfab 100644
+--- a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
++++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+@@ -35,11 +35,19 @@ bool intel_hdcp_gsc_check_status(struct drm_device *drm)
+ struct xe_device *xe = to_xe_device(drm);
+ struct xe_tile *tile = xe_device_get_root_tile(xe);
+ struct xe_gt *gt = tile->media_gt;
+- struct xe_gsc *gsc = >->uc.gsc;
++ struct xe_gsc *gsc;
+ bool ret = true;
+ unsigned int fw_ref;
+
+- if (!gsc || !xe_uc_fw_is_enabled(&gsc->fw)) {
++ if (!gt) {
++ drm_dbg_kms(&xe->drm,
++ "not checking GSC status for HDCP2.x: media GT not present or disabled\n");
++ return false;
++ }
++
++ gsc = >->uc.gsc;
++
++ if (!xe_uc_fw_is_enabled(&gsc->fw)) {
+ drm_dbg_kms(&xe->drm,
+ "GSC Components not ready for HDCP2.x\n");
+ return false;
+--
+2.53.0
+
--- /dev/null
+From fddfcb84e88aa2811927313beab1a8e996714169 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Mar 2026 15:37:54 +0800
+Subject: iommu/amd: Fix illegal cap/mmio access in IOMMU debugfs
+
+From: Guanghui Feng <guanghuifeng@linux.alibaba.com>
+
+[ Upstream commit 0e59645683b7b6fa20eceb21a6f420e4f7412943 ]
+
+In the current AMD IOMMU debugfs, when multiple processes simultaneously
+access the IOMMU mmio/cap registers using the IOMMU debugfs, illegal
+access issues can occur in the following execution flow:
+
+1. CPU1: Sets a valid access address using iommu_mmio/capability_write,
+and verifies the access address's validity in iommu_mmio/capability_show
+
+2. CPU2: Sets an invalid address using iommu_mmio/capability_write
+
+3. CPU1: accesses the IOMMU mmio/cap registers based on the invalid
+address, resulting in an illegal access.
+
+This patch modifies the execution process to first verify the address's
+validity and then access it based on the same address, ensuring
+correctness and robustness.
+
+Signed-off-by: Guanghui Feng <guanghuifeng@linux.alibaba.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Stable-dep-of: 8dfd3d8d7443 ("iommu/amd: Remove latent out-of-bounds access in IOMMU debugfs")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/debugfs.c | 42 +++++++++++++++++--------------------
+ 1 file changed, 19 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c
+index 20b04996441d6..0584ca2f859d9 100644
+--- a/drivers/iommu/amd/debugfs.c
++++ b/drivers/iommu/amd/debugfs.c
+@@ -26,22 +26,19 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf,
+ {
+ struct seq_file *m = filp->private_data;
+ struct amd_iommu *iommu = m->private;
+- int ret;
+-
+- iommu->dbg_mmio_offset = -1;
++ int ret, dbg_mmio_offset = iommu->dbg_mmio_offset = -1;
+
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_mmio_offset);
++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
+ if (ret)
+ return ret;
+
+- if (iommu->dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) {
+- iommu->dbg_mmio_offset = -1;
+- return -EINVAL;
+- }
++ if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64))
++ return -EINVAL;
+
++ iommu->dbg_mmio_offset = dbg_mmio_offset;
+ return cnt;
+ }
+
+@@ -49,14 +46,16 @@ static int iommu_mmio_show(struct seq_file *m, void *unused)
+ {
+ struct amd_iommu *iommu = m->private;
+ u64 value;
++ int dbg_mmio_offset = iommu->dbg_mmio_offset;
+
+- if (iommu->dbg_mmio_offset < 0) {
++ if (dbg_mmio_offset < 0 || dbg_mmio_offset >
++ iommu->mmio_phys_end - sizeof(u64)) {
+ seq_puts(m, "Please provide mmio register's offset\n");
+ return 0;
+ }
+
+- value = readq(iommu->mmio_base + iommu->dbg_mmio_offset);
+- seq_printf(m, "Offset:0x%x Value:0x%016llx\n", iommu->dbg_mmio_offset, value);
++ value = readq(iommu->mmio_base + dbg_mmio_offset);
++ seq_printf(m, "Offset:0x%x Value:0x%016llx\n", dbg_mmio_offset, value);
+
+ return 0;
+ }
+@@ -67,23 +66,20 @@ static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf
+ {
+ struct seq_file *m = filp->private_data;
+ struct amd_iommu *iommu = m->private;
+- int ret;
+-
+- iommu->dbg_cap_offset = -1;
++ int ret, dbg_cap_offset = iommu->dbg_cap_offset = -1;
+
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_cap_offset);
++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
+ if (ret)
+ return ret;
+
+ /* Capability register at offset 0x14 is the last IOMMU capability register. */
+- if (iommu->dbg_cap_offset > 0x14) {
+- iommu->dbg_cap_offset = -1;
++ if (dbg_cap_offset > 0x14)
+ return -EINVAL;
+- }
+
++ iommu->dbg_cap_offset = dbg_cap_offset;
+ return cnt;
+ }
+
+@@ -91,21 +87,21 @@ static int iommu_capability_show(struct seq_file *m, void *unused)
+ {
+ struct amd_iommu *iommu = m->private;
+ u32 value;
+- int err;
++ int err, dbg_cap_offset = iommu->dbg_cap_offset;
+
+- if (iommu->dbg_cap_offset < 0) {
++ if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14) {
+ seq_puts(m, "Please provide capability register's offset in the range [0x00 - 0x14]\n");
+ return 0;
+ }
+
+- err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + iommu->dbg_cap_offset, &value);
++ err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + dbg_cap_offset, &value);
+ if (err) {
+ seq_printf(m, "Not able to read capability register at 0x%x\n",
+- iommu->dbg_cap_offset);
++ dbg_cap_offset);
+ return 0;
+ }
+
+- seq_printf(m, "Offset:0x%x Value:0x%08x\n", iommu->dbg_cap_offset, value);
++ seq_printf(m, "Offset:0x%x Value:0x%08x\n", dbg_cap_offset, value);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From f243339518fa09ba6d6a8aa8807901dbb6e15db3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Apr 2026 14:55:50 +0200
+Subject: iommu/amd: Remove latent out-of-bounds access in IOMMU debugfs
+
+From: Eder Zulian <ezulian@redhat.com>
+
+[ Upstream commit 8dfd3d8d74435344ee8dc9237596959c8b2a6cbe ]
+
+In iommu_mmio_write() and iommu_capability_write(), the variables
+dbg_mmio_offset and dbg_cap_offset are declared as int. However, they
+are populated using kstrtou32_from_user(). If a user provides a
+sufficiently large value, it can become a negative integer.
+
+Prior to this patch, the AMD IOMMU debugfs implementation was already
+protected by different mechanisms.
+
+1. #define OFS_IN_SZ 8 ensures the user string <= 8 bytes, so
+ e.g. 0xffffffff isn't a valid input.
+
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+2. Implicit type promotion in iommu_mmio_write(), dbg_mmio_offset is int
+ and iommu->mmio_phys_end is u64
+
+ if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64))
+ return -EINVAL;
+
+3. The show handlers would currently catch the negative number and
+ refuse to perform the read.
+
+Replace kstrtou32_from_user() with kstrtos32_from_user() to parse the
+input, and check for negative values to explicitly prevent out-of-bounds
+memory accesses directly in iommu_mmio_write() and
+iommu_capability_write().
+
+Signed-off-by: Eder Zulian <ezulian@redhat.com>
+Fixes: 7a4ee419e8c1 ("iommu/amd: Add debugfs support to dump IOMMU MMIO registers")
+Cc: stable@vger.kernel.org
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/debugfs.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c
+index 0584ca2f859d9..3909a1fb218e9 100644
+--- a/drivers/iommu/amd/debugfs.c
++++ b/drivers/iommu/amd/debugfs.c
+@@ -31,11 +31,12 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf,
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
++ ret = kstrtos32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
+ if (ret)
+ return ret;
+
+- if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64))
++ if (dbg_mmio_offset < 0 || dbg_mmio_offset >
++ iommu->mmio_phys_end - sizeof(u64))
+ return -EINVAL;
+
+ iommu->dbg_mmio_offset = dbg_mmio_offset;
+@@ -71,12 +72,12 @@ static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
++ ret = kstrtos32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
+ if (ret)
+ return ret;
+
+ /* Capability register at offset 0x14 is the last IOMMU capability register. */
+- if (dbg_cap_offset > 0x14)
++ if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14)
+ return -EINVAL;
+
+ iommu->dbg_cap_offset = dbg_cap_offset;
+--
+2.53.0
+
--- /dev/null
+drm-xe-hdcp-add-null-check-for-media_gt-in-intel_hdc.patch
+iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch
+iommu-amd-remove-latent-out-of-bounds-access-in-iomm.patch
--- /dev/null
+From 2fa22e22ad8668384cd35b8042028395606799a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 14:01:59 +0000
+Subject: driver core: generalize driver_override in struct device
+
+From: Danilo Krummrich <dakr@kernel.org>
+
+[ Upstream commit cb3d1049f4ea77d5ad93f17d8ac1f2ed4da70501 ]
+
+Currently, there are 12 busses (including platform and PCI) that
+duplicate the driver_override logic for their individual devices.
+
+All of them seem to be prone to the bug described in [1].
+
+While this could be solved for every bus individually using a separate
+lock, solving this in the driver-core generically results in less (and
+cleaner) changes overall.
+
+Thus, move driver_override to struct device, provide corresponding
+accessors for busses and handle locking with a separate lock internally.
+
+In particular, add device_set_driver_override(),
+device_has_driver_override(), device_match_driver_override() and
+generalize the sysfs store() and show() callbacks via a driver_override
+feature flag in struct bus_type.
+
+Until all busses have migrated, keep driver_set_override() in place.
+
+Note that we can't use the device lock for the reasons described in [2].
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=220789 [1]
+Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [2]
+Tested-by: Gui-Dong Han <hanguidong02@gmail.com>
+Co-developed-by: Gui-Dong Han <hanguidong02@gmail.com>
+Signed-off-by: Gui-Dong Han <hanguidong02@gmail.com>
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Link: https://patch.msgid.link/20260303115720.48783-2-dakr@kernel.org
+[ Use dev->bus instead of sp->bus for consistency; fix commit message to
+ refer to the struct bus_type's driver_override feature flag. - Danilo ]
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Stable-dep-of: 2b38efc05bf7 ("driver core: platform: use generic driver_override infrastructure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: David Sauerwein <dssauerw@amazon.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/bus.c | 43 ++++++++++++++++++++++++++-
+ drivers/base/core.c | 2 ++
+ drivers/base/dd.c | 60 ++++++++++++++++++++++++++++++++++++++
+ include/linux/device.h | 54 ++++++++++++++++++++++++++++++++++
+ include/linux/device/bus.h | 4 +++
+ 5 files changed, 162 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/base/bus.c b/drivers/base/bus.c
+index b97e13a52c330..ae57df879bca2 100644
+--- a/drivers/base/bus.c
++++ b/drivers/base/bus.c
+@@ -463,6 +463,36 @@ int bus_for_each_drv(const struct bus_type *bus, struct device_driver *start,
+ }
+ EXPORT_SYMBOL_GPL(bus_for_each_drv);
+
++static ssize_t driver_override_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int ret;
++
++ ret = __device_set_driver_override(dev, buf, count);
++ if (ret)
++ return ret;
++
++ return count;
++}
++
++static ssize_t driver_override_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ guard(spinlock)(&dev->driver_override.lock);
++ return sysfs_emit(buf, "%s\n", dev->driver_override.name);
++}
++static DEVICE_ATTR_RW(driver_override);
++
++static struct attribute *driver_override_dev_attrs[] = {
++ &dev_attr_driver_override.attr,
++ NULL,
++};
++
++static const struct attribute_group driver_override_dev_group = {
++ .attrs = driver_override_dev_attrs,
++};
++
+ /**
+ * bus_add_device - add device to bus
+ * @dev: device being added
+@@ -496,9 +526,15 @@ int bus_add_device(struct device *dev)
+ if (error)
+ goto out_put;
+
++ if (dev->bus->driver_override) {
++ error = device_add_group(dev, &driver_override_dev_group);
++ if (error)
++ goto out_groups;
++ }
++
+ error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev));
+ if (error)
+- goto out_groups;
++ goto out_override;
+
+ error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem");
+ if (error)
+@@ -509,6 +545,9 @@ int bus_add_device(struct device *dev)
+
+ out_subsys:
+ sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
++out_override:
++ if (dev->bus->driver_override)
++ device_remove_group(dev, &driver_override_dev_group);
+ out_groups:
+ device_remove_groups(dev, sp->bus->dev_groups);
+ out_put:
+@@ -567,6 +606,8 @@ void bus_remove_device(struct device *dev)
+
+ sysfs_remove_link(&dev->kobj, "subsystem");
+ sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
++ if (dev->bus->driver_override)
++ device_remove_group(dev, &driver_override_dev_group);
+ device_remove_groups(dev, dev->bus->dev_groups);
+ if (klist_node_attached(&dev->p->knode_bus))
+ klist_del(&dev->p->knode_bus);
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index 3c172e6d3fe0d..5048849cb97a9 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -2505,6 +2505,7 @@ static void device_release(struct kobject *kobj)
+ devres_release_all(dev);
+
+ kfree(dev->dma_range_map);
++ kfree(dev->driver_override.name);
+
+ if (dev->release)
+ dev->release(dev);
+@@ -3153,6 +3154,7 @@ void device_initialize(struct device *dev)
+ kobject_init(&dev->kobj, &device_ktype);
+ INIT_LIST_HEAD(&dev->dma_pools);
+ mutex_init(&dev->mutex);
++ spin_lock_init(&dev->driver_override.lock);
+ lockdep_set_novalidate_class(&dev->mutex);
+ spin_lock_init(&dev->devres_lock);
+ INIT_LIST_HEAD(&dev->devres_head);
+diff --git a/drivers/base/dd.c b/drivers/base/dd.c
+index d371c3437dc6b..44f9d0a06d5b7 100644
+--- a/drivers/base/dd.c
++++ b/drivers/base/dd.c
+@@ -380,6 +380,66 @@ static void __exit deferred_probe_exit(void)
+ }
+ __exitcall(deferred_probe_exit);
+
++int __device_set_driver_override(struct device *dev, const char *s, size_t len)
++{
++ const char *new, *old;
++ char *cp;
++
++ if (!s)
++ return -EINVAL;
++
++ /*
++ * The stored value will be used in sysfs show callback (sysfs_emit()),
++ * which has a length limit of PAGE_SIZE and adds a trailing newline.
++ * Thus we can store one character less to avoid truncation during sysfs
++ * show.
++ */
++ if (len >= (PAGE_SIZE - 1))
++ return -EINVAL;
++
++ /*
++ * Compute the real length of the string in case userspace sends us a
++ * bunch of \0 characters like python likes to do.
++ */
++ len = strlen(s);
++
++ if (!len) {
++ /* Empty string passed - clear override */
++ spin_lock(&dev->driver_override.lock);
++ old = dev->driver_override.name;
++ dev->driver_override.name = NULL;
++ spin_unlock(&dev->driver_override.lock);
++ kfree(old);
++
++ return 0;
++ }
++
++ cp = strnchr(s, len, '\n');
++ if (cp)
++ len = cp - s;
++
++ new = kstrndup(s, len, GFP_KERNEL);
++ if (!new)
++ return -ENOMEM;
++
++ spin_lock(&dev->driver_override.lock);
++ old = dev->driver_override.name;
++ if (cp != s) {
++ dev->driver_override.name = new;
++ spin_unlock(&dev->driver_override.lock);
++ } else {
++ /* "\n" passed - clear override */
++ dev->driver_override.name = NULL;
++ spin_unlock(&dev->driver_override.lock);
++
++ kfree(new);
++ }
++ kfree(old);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(__device_set_driver_override);
++
+ /**
+ * device_is_bound() - Check if device is bound to a driver
+ * @dev: device to check
+diff --git a/include/linux/device.h b/include/linux/device.h
+index 8fb9bd71fcd0b..2a9017eec15c2 100644
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -643,6 +643,8 @@ enum struct_device_flags {
+ * on. This shrinks the "Board Support Packages" (BSPs) and
+ * minimizes board-specific #ifdefs in drivers.
+ * @driver_data: Private pointer for driver specific info.
++ * @driver_override: Driver name to force a match. Do not touch directly; use
++ * device_set_driver_override() instead.
+ * @links: Links to suppliers and consumers of this device.
+ * @power: For device power management.
+ * See Documentation/driver-api/pm/devices.rst for details.
+@@ -735,6 +737,10 @@ struct device {
+ core doesn't touch it */
+ void *driver_data; /* Driver data, set and get with
+ dev_set_drvdata/dev_get_drvdata */
++ struct {
++ const char *name;
++ spinlock_t lock;
++ } driver_override;
+ struct mutex mutex; /* mutex to synchronize calls to
+ * its driver.
+ */
+@@ -882,6 +888,54 @@ struct device_link {
+
+ #define kobj_to_dev(__kobj) container_of_const(__kobj, struct device, kobj)
+
++int __device_set_driver_override(struct device *dev, const char *s, size_t len);
++
++/**
++ * device_set_driver_override() - Helper to set or clear driver override.
++ * @dev: Device to change
++ * @s: NUL-terminated string, new driver name to force a match, pass empty
++ * string to clear it ("" or "\n", where the latter is only for sysfs
++ * interface).
++ *
++ * Helper to set or clear driver override of a device.
++ *
++ * Returns: 0 on success or a negative error code on failure.
++ */
++static inline int device_set_driver_override(struct device *dev, const char *s)
++{
++ return __device_set_driver_override(dev, s, s ? strlen(s) : 0);
++}
++
++/**
++ * device_has_driver_override() - Check if a driver override has been set.
++ * @dev: device to check
++ *
++ * Returns true if a driver override has been set for this device.
++ */
++static inline bool device_has_driver_override(struct device *dev)
++{
++ guard(spinlock)(&dev->driver_override.lock);
++ return !!dev->driver_override.name;
++}
++
++/**
++ * device_match_driver_override() - Match a driver against the device's driver_override.
++ * @dev: device to check
++ * @drv: driver to match against
++ *
++ * Returns > 0 if a driver override is set and matches the given driver, 0 if a
++ * driver override is set but does not match, or < 0 if a driver override is not
++ * set at all.
++ */
++static inline int device_match_driver_override(struct device *dev,
++ const struct device_driver *drv)
++{
++ guard(spinlock)(&dev->driver_override.lock);
++ if (dev->driver_override.name)
++ return !strcmp(dev->driver_override.name, drv->name);
++ return -1;
++}
++
+ /**
+ * device_iommu_mapped - Returns true when the device DMA is translated
+ * by an IOMMU
+diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h
+index ae10c43227543..d43ce072d747e 100644
+--- a/include/linux/device/bus.h
++++ b/include/linux/device/bus.h
+@@ -65,6 +65,9 @@ struct fwnode_handle;
+ * @iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU
+ * driver implementations to a bus and allow the driver to do
+ * bus-specific setup
++ * @driver_override: Set to true if this bus supports the driver_override
++ * mechanism, which allows userspace to force a specific
++ * driver to bind to a device via a sysfs attribute.
+ * @need_parent_lock: When probing or removing a device on this bus, the
+ * device core should lock the device's parent.
+ *
+@@ -106,6 +109,7 @@ struct bus_type {
+
+ const struct iommu_ops *iommu_ops;
+
++ bool driver_override;
+ bool need_parent_lock;
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 0112df6ef8d1c90e445e2aea0a9b29ab308d1924 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 14:02:00 +0000
+Subject: driver core: platform: use generic driver_override infrastructure
+
+From: Danilo Krummrich <dakr@kernel.org>
+
+[ Upstream commit 2b38efc05bf7a8568ec74bfffea0f5cfa62bc01d ]
+
+When a driver is probed through __driver_attach(), the bus' match()
+callback is called without the device lock held, thus accessing the
+driver_override field without a lock, which can cause a UAF.
+
+Fix this by using the driver-core driver_override infrastructure taking
+care of proper locking internally.
+
+Note that calling match() from __driver_attach() without the device lock
+held is intentional. [1]
+
+Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1]
+Reported-by: Gui-Dong Han <hanguidong02@gmail.com>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789
+Fixes: 3d713e0e382e ("driver core: platform: add device binding path 'driver_override'")
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Link: https://patch.msgid.link/20260303115720.48783-5-dakr@kernel.org
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: David Sauerwein <dssauerw@amazon.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/platform.c | 37 +++++----------------------------
+ drivers/bus/simple-pm-bus.c | 4 ++--
+ drivers/clk/imx/clk-scu.c | 3 +--
+ drivers/slimbus/qcom-ngd-ctrl.c | 6 ++----
+ include/linux/platform_device.h | 5 -----
+ sound/soc/samsung/i2s.c | 6 +++---
+ 6 files changed, 13 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index 76bfcba250039..1cc9a876b3cde 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -561,7 +561,6 @@ static void platform_device_release(struct device *dev)
+ kfree(pa->pdev.dev.platform_data);
+ kfree(pa->pdev.mfd_cell);
+ kfree(pa->pdev.resource);
+- kfree(pa->pdev.driver_override);
+ kfree(pa);
+ }
+
+@@ -1265,38 +1264,9 @@ static ssize_t numa_node_show(struct device *dev,
+ }
+ static DEVICE_ATTR_RO(numa_node);
+
+-static ssize_t driver_override_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- ssize_t len;
+-
+- device_lock(dev);
+- len = sysfs_emit(buf, "%s\n", pdev->driver_override);
+- device_unlock(dev);
+-
+- return len;
+-}
+-
+-static ssize_t driver_override_store(struct device *dev,
+- struct device_attribute *attr,
+- const char *buf, size_t count)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- int ret;
+-
+- ret = driver_set_override(dev, &pdev->driver_override, buf, count);
+- if (ret)
+- return ret;
+-
+- return count;
+-}
+-static DEVICE_ATTR_RW(driver_override);
+-
+ static struct attribute *platform_dev_attrs[] = {
+ &dev_attr_modalias.attr,
+ &dev_attr_numa_node.attr,
+- &dev_attr_driver_override.attr,
+ NULL,
+ };
+
+@@ -1336,10 +1306,12 @@ static int platform_match(struct device *dev, struct device_driver *drv)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct platform_driver *pdrv = to_platform_driver(drv);
++ int ret;
+
+ /* When driver_override is set, only bind to the matching driver */
+- if (pdev->driver_override)
+- return !strcmp(pdev->driver_override, drv->name);
++ ret = device_match_driver_override(dev, drv);
++ if (ret >= 0)
++ return ret;
+
+ /* Attempt an OF style match first */
+ if (of_driver_match_device(dev, drv))
+@@ -1482,6 +1454,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
+ struct bus_type platform_bus_type = {
+ .name = "platform",
+ .dev_groups = platform_dev_groups,
++ .driver_override = true,
+ .match = platform_match,
+ .uevent = platform_uevent,
+ .probe = platform_probe,
+diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c
+index aafcc481de91d..cb71774400d42 100644
+--- a/drivers/bus/simple-pm-bus.c
++++ b/drivers/bus/simple-pm-bus.c
+@@ -36,7 +36,7 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
+ * that's not listed in simple_pm_bus_of_match. We don't want to do any
+ * of the simple-pm-bus tasks for these devices, so return early.
+ */
+- if (pdev->driver_override)
++ if (device_has_driver_override(&pdev->dev))
+ return 0;
+
+ match = of_match_device(dev->driver->of_match_table, dev);
+@@ -78,7 +78,7 @@ static int simple_pm_bus_remove(struct platform_device *pdev)
+ {
+ const void *data = of_device_get_match_data(&pdev->dev);
+
+- if (pdev->driver_override || data)
++ if (device_has_driver_override(&pdev->dev) || data)
+ return 0;
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
+index 564f549ec204f..3a68576cdae76 100644
+--- a/drivers/clk/imx/clk-scu.c
++++ b/drivers/clk/imx/clk-scu.c
+@@ -700,8 +700,7 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
+ return ERR_PTR(ret);
+ }
+
+- ret = driver_set_override(&pdev->dev, &pdev->driver_override,
+- "imx-scu-clk", strlen("imx-scu-clk"));
++ ret = device_set_driver_override(&pdev->dev, "imx-scu-clk");
+ if (ret) {
+ platform_device_put(pdev);
+ return ERR_PTR(ret);
+diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
+index fe3a96577f31f..d0d289c49c8d1 100644
+--- a/drivers/slimbus/qcom-ngd-ctrl.c
++++ b/drivers/slimbus/qcom-ngd-ctrl.c
+@@ -1537,10 +1537,8 @@ static int of_qcom_slim_ngd_register(struct device *parent,
+ ngd->id = id;
+ ngd->pdev->dev.parent = parent;
+
+- ret = driver_set_override(&ngd->pdev->dev,
+- &ngd->pdev->driver_override,
+- QCOM_SLIM_NGD_DRV_NAME,
+- strlen(QCOM_SLIM_NGD_DRV_NAME));
++ ret = device_set_driver_override(&ngd->pdev->dev,
++ QCOM_SLIM_NGD_DRV_NAME);
+ if (ret) {
+ platform_device_put(ngd->pdev);
+ kfree(ngd);
+diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
+index 7a41c72c19591..8828b0d275d79 100644
+--- a/include/linux/platform_device.h
++++ b/include/linux/platform_device.h
+@@ -31,11 +31,6 @@ struct platform_device {
+ struct resource *resource;
+
+ const struct platform_device_id *id_entry;
+- /*
+- * Driver name to force a match. Do not set directly, because core
+- * frees it. Use driver_set_override() to set or clear it.
+- */
+- const char *driver_override;
+
+ /* MFD cell pointer */
+ struct mfd_cell *mfd_cell;
+diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
+index 3af48c9b5ab7b..925782e676730 100644
+--- a/sound/soc/samsung/i2s.c
++++ b/sound/soc/samsung/i2s.c
+@@ -1364,10 +1364,10 @@ static int i2s_create_secondary_device(struct samsung_i2s_priv *priv)
+ if (!pdev_sec)
+ return -ENOMEM;
+
+- pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL);
+- if (!pdev_sec->driver_override) {
++ ret = device_set_driver_override(&pdev_sec->dev, "samsung-i2s");
++ if (ret) {
+ platform_device_put(pdev_sec);
+- return -ENOMEM;
++ return ret;
+ }
+
+ ret = platform_device_add(pdev_sec);
+--
+2.53.0
+
--- /dev/null
+From 15074b69b8ae9e602c4837924b2610beee3ec659 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:19:09 +0200
+Subject: mptcp: pm: ADD_ADDR rtx: allow ID 0
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+commit 03f324f3f1f7619a47b9c91282cb12775ab0a2f1 upstream.
+
+ADD_ADDR can be sent for the ID 0, which corresponds to the local
+address and port linked to the initial subflow.
+
+Indeed, this address could be removed, and re-added later on, e.g. what
+is done in the "delete re-add signal" MPTCP Join selftests. So no reason
+to ignore it.
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-2-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ applied to net/mptcp/pm_netlink.c instead of upstream's pm_kernel.c ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/pm_netlink.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
+index 4a5802126c8e4..23aef214f30d8 100644
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -305,9 +305,6 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ if (inet_sk_state_load(sk) == TCP_CLOSE)
+ return;
+
+- if (!entry->addr.id)
+- return;
+-
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) {
+ /* Try again later. */
+--
+2.53.0
+
--- /dev/null
+From f7f5b43743cb6a0ee2fbd4fa88ed8cb7a15bb7d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:19:10 +0200
+Subject: mptcp: pm: ADD_ADDR rtx: always decrease sk refcount
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+commit 9634cb35af17019baec21ca648516ce376fa10e6 upstream.
+
+When an ADD_ADDR is retransmitted, the sk is held in sk_reset_timer().
+It should then be released in all cases at the end.
+
+Some (unlikely) checks were returning directly instead of calling
+sock_put() to decrease the refcount. Jump to a new 'exit' label to call
+__sock_put() (which will become sock_put() in the next commit) to fix
+this potential leak.
+
+While at it, drop the '!msk' check which cannot happen because it is
+never reset, and explicitly mark the remaining one as "unlikely".
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-4-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ applied to net/mptcp/pm_netlink.c instead of upstream's pm_kernel.c ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/pm_netlink.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
+index 23aef214f30d8..d087d5fc3067d 100644
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -299,11 +299,8 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+
+ pr_debug("msk=%p\n", msk);
+
+- if (!msk)
+- return;
+-
+- if (inet_sk_state_load(sk) == TCP_CLOSE)
+- return;
++ if (unlikely(inet_sk_state_load(sk) == TCP_CLOSE))
++ goto exit;
+
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) {
+@@ -341,6 +338,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+
+ out:
+ bh_unlock_sock(sk);
++exit:
+ __sock_put(sk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 64abb07cc1e185dc8de2427440ee79393353c666 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:19:11 +0200
+Subject: mptcp: pm: ADD_ADDR rtx: free sk if last
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+commit b7b9a461569734d33d3259d58d2507adfac107ed upstream.
+
+When an ADD_ADDR is retransmitted, the sk is held in sk_reset_timer(),
+and released at the end.
+
+If at that moment, it was the last reference being held, the sk would
+not be freed. sock_put() should then be called instead of __sock_put().
+
+But that's not enough: if it is the last reference, sock_put() will call
+sk_free(), which will end up calling sk_stop_timer_sync() on the same
+timer, and waiting indefinitely to finish. So it is needed to mark that
+the timer is done at the end of the timer handler when it has not been
+rescheduled, not to call sk_stop_timer_sync() on "itself".
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-5-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Applied to net/mptcp/pm_netlink.c instead of upstream's pm_kernel.c.
+ Also, there were conflicts, because commit 30549eebc4d8 ("mptcp: make
+ ADD_ADDR retransmission timeout adaptive") is not in this version and
+ changed the context. Also, other conflicts were due to newer patches
+ being backported with resolved conflicts before this one. ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/pm_netlink.c | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
+index d087d5fc3067d..6e5570f97236a 100644
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -27,6 +27,7 @@ struct mptcp_pm_add_entry {
+ struct list_head list;
+ struct mptcp_addr_info addr;
+ u8 retrans_times;
++ bool timer_done;
+ struct timer_list add_timer;
+ struct mptcp_sock *sock;
+ struct rcu_head rcu;
+@@ -295,22 +296,22 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ struct mptcp_pm_add_entry *entry = from_timer(entry, timer, add_timer);
+ struct mptcp_sock *msk = entry->sock;
+ struct sock *sk = (struct sock *)msk;
+- unsigned int timeout;
++ unsigned int timeout = 0;
+
+ pr_debug("msk=%p\n", msk);
+
++ bh_lock_sock(sk);
+ if (unlikely(inet_sk_state_load(sk) == TCP_CLOSE))
+- goto exit;
++ goto out;
+
+- bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) {
+ /* Try again later. */
+- sk_reset_timer(sk, timer, jiffies + HZ / 20);
++ timeout = HZ / 20;
+ goto out;
+ }
+
+ if (mptcp_pm_should_add_signal_addr(msk)) {
+- sk_reset_timer(sk, timer, jiffies + HZ);
++ timeout = HZ;
+ goto out;
+ }
+
+@@ -327,9 +328,8 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ entry->retrans_times++;
+ }
+
+- if (entry->retrans_times < ADD_ADDR_RETRANS_MAX)
+- sk_reset_timer(sk, timer,
+- jiffies + timeout);
++ if (entry->retrans_times >= ADD_ADDR_RETRANS_MAX)
++ timeout = 0;
+
+ spin_unlock_bh(&msk->pm.lock);
+
+@@ -337,9 +337,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
+ mptcp_pm_subflow_established(msk);
+
+ out:
++ if (timeout)
++ sk_reset_timer(sk, timer, jiffies + timeout);
++ else
++ /* if sock_put calls sk_free: avoid waiting for this timer */
++ entry->timer_done = true;
+ bh_unlock_sock(sk);
+-exit:
+- __sock_put(sk);
++ sock_put(sk);
+ }
+
+ struct mptcp_pm_add_entry *
+@@ -403,6 +407,7 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
+
+ timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0);
+ reset_timer:
++ add_entry->timer_done = false;
+ timeout = mptcp_get_add_addr_timeout(net);
+ if (timeout)
+ sk_reset_timer(sk, &add_entry->add_timer, jiffies + timeout);
+@@ -423,7 +428,8 @@ void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
+ spin_unlock_bh(&msk->pm.lock);
+
+ list_for_each_entry_safe(entry, tmp, &free_list, list) {
+- sk_stop_timer_sync(sk, &entry->add_timer);
++ if (!entry->timer_done)
++ sk_stop_timer_sync(sk, &entry->add_timer);
+ kfree_rcu(entry, rcu);
+ }
+ }
+--
+2.53.0
+
--- /dev/null
+From 980948a7233c762028c98372b3935f6a0a3ff0af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 05:19:08 +0200
+Subject: mptcp: sync the msk->sndbuf at accept() time
+
+From: Gang Yan <yangang@kylinos.cn>
+
+commit fcf04b14334641f4b0b8647824480935e9416d52 upstream.
+
+On passive MPTCP connections, the msk sndbuf is not updated correctly.
+
+The root cause is an order issue in the accept path:
+
+- tcp_check_req() -> subflow_syn_recv_sock() -> mptcp_sk_clone_init()
+ calls __mptcp_propagate_sndbuf() to copy the ssk sndbuf into msk
+
+- Later, tcp_child_process() -> tcp_init_transfer() ->
+ tcp_sndbuf_expand() grows the ssk sndbuf.
+
+So __mptcp_propagate_sndbuf() runs before the ssk sndbuf has been
+expanded and the msk ends up with a much smaller sndbuf than the
+subflow:
+
+ MPTCP: msk->sndbuf:20480, msk->first->sndbuf:2626560
+
+Fix this by moving the __mptcp_propagate_sndbuf() call from
+mptcp_sk_clone_init() -- the ssk sndbuf is not yet finalized there -- to
+__mptcp_propagate_sndbuf() at accept() time, when the ssk sndbuf has
+been fully expanded by tcp_sndbuf_expand().
+
+Fixes: 8005184fd1ca ("mptcp: refactor sndbuf auto-tuning")
+Cc: stable@vger.kernel.org
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/602
+Signed-off-by: Gang Yan <yangang@kylinos.cn>
+Acked-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260420-net-mptcp-sync-sndbuf-accept-v1-1-e3523e3aeb44@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ No conflicts, but move __mptcp_propagate_sndbuf() above the for-loop
+ (mptcp_for_each_subflow()) present in this version, which will modify
+ 'subflow' used by __mptcp_propagate_sndbuf() in this new patch. ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index aed6c04c7de67..ff1632d03a96d 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -3451,7 +3451,6 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
+ * uses the correct data
+ */
+ mptcp_copy_inaddrs(nsk, ssk);
+- __mptcp_propagate_sndbuf(nsk, ssk);
+
+ mptcp_rcv_space_init(msk, ssk);
+ msk->rcvq_space.time = mptcp_stamp();
+@@ -4064,6 +4063,8 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
+ msk = mptcp_sk(newsk);
+ msk->in_accept_queue = 0;
+
++ __mptcp_propagate_sndbuf(newsk, mptcp_subflow_tcp_sock(subflow));
++
+ /* set ssk->sk_socket of accept()ed flows to mptcp socket.
+ * This is needed so NOSPACE flag can be set from tcp stack.
+ */
+--
+2.53.0
+
--- /dev/null
+From b01ce81fcc381342ba9dbf349e045bdd9acce867 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 10:28:34 +0800
+Subject: s390/debug: Reject zero-length input before trimming a newline
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit c366a7b5ed7564e41345c380285bd3f6cb98971b ]
+
+debug_get_user_string() copies the userspace buffer into a newly
+allocated NUL-terminated buffer and then unconditionally looks at
+buffer[user_len - 1] to strip a trailing newline.
+
+A zero-length write reaches this helper unchanged, so the newline trim
+reads before the start of the allocated buffer.
+
+Reject empty writes before accessing the last input byte.
+
+Fixes: 66a464dbc8e0 ("[PATCH] s390: debug feature changes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
+Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
+Tested-by: Vasily Gorbik <gor@linux.ibm.com>
+Link: https://lore.kernel.org/r/20260417073530.96002-1-pengpeng@iscas.ac.cn
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/debug.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
+index cbe209fe0df15..893c35aeb746a 100644
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -1258,6 +1258,9 @@ static inline char *debug_get_user_string(const char __user *user_buf,
+ {
+ char *buffer;
+
++ if (!user_len)
++ return ERR_PTR(-EINVAL);
++
+ buffer = kmalloc(user_len + 1, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+--
+2.53.0
+
--- /dev/null
+mptcp-sync-the-msk-sndbuf-at-accept-time.patch
+mptcp-pm-add_addr-rtx-allow-id-0.patch
+mptcp-pm-add_addr-rtx-always-decrease-sk-refcount.patch
+mptcp-pm-add_addr-rtx-free-sk-if-last.patch
+spi-spidev-fix-lock-inversion-between-spi_lock-and-b.patch
+driver-core-generalize-driver_override-in-struct-dev.patch
+driver-core-platform-use-generic-driver_override-inf.patch
+s390-debug-reject-zero-length-input-before-trimming-.patch
--- /dev/null
+From 2b8b474394ed878185b5f908ff92e8e6a6db7258 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 14:10:51 +0800
+Subject: spi: spidev: fix lock inversion between spi_lock and buf_lock
+
+From: Fabian Godehardt <fg@emlix.com>
+
+[ Upstream commit 40534d19ed2afb880ecf202dab26a8e7a5808d16 ]
+
+The spidev driver previously used two mutexes, spi_lock and buf_lock,
+but acquired them in different orders depending on the code path:
+
+ write()/read(): buf_lock -> spi_lock
+ ioctl(): spi_lock -> buf_lock
+
+This AB-BA locking pattern triggers lockdep warnings and can
+cause real deadlocks:
+
+ WARNING: possible circular locking dependency detected
+ spidev_ioctl() -> mutex_lock(&spidev->buf_lock)
+ spidev_sync_write() -> mutex_lock(&spidev->spi_lock)
+ *** DEADLOCK ***
+
+The issue is reproducible with a simple userspace program that
+performs write() and SPI_IOC_WR_MAX_SPEED_HZ ioctl() calls from
+separate threads on the same spidev file descriptor.
+
+Fix this by simplifying the locking model and removing the lock
+inversion entirely. spidev_sync() no longer performs any locking,
+and all callers serialize access using spi_lock.
+
+buf_lock is removed since its functionality is fully covered by
+spi_lock, eliminating the possibility of lock ordering issues.
+
+This removes the lock inversion and prevents deadlocks without
+changing userspace ABI or behaviour.
+
+Signed-off-by: Fabian Godehardt <fg@emlix.com>
+Link: https://patch.msgid.link/20260211072616.489522-1-fg@emlix.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ Minor context conflict resolved. ]
+Signed-off-by: Wenshan Lan <jetlan9@163.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spidev.c | 63 ++++++++++++++++----------------------------
+ 1 file changed, 22 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
+index 16bb4fc3a4ba9..2024532dfc447 100644
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -74,7 +74,6 @@ struct spidev_data {
+ struct list_head device_entry;
+
+ /* TX/RX buffers are NULL unless this device is open (users > 0) */
+- struct mutex buf_lock;
+ unsigned users;
+ u8 *tx_buffer;
+ u8 *rx_buffer;
+@@ -102,24 +101,6 @@ spidev_sync_unlocked(struct spi_device *spi, struct spi_message *message)
+ return status;
+ }
+
+-static ssize_t
+-spidev_sync(struct spidev_data *spidev, struct spi_message *message)
+-{
+- ssize_t status;
+- struct spi_device *spi;
+-
+- mutex_lock(&spidev->spi_lock);
+- spi = spidev->spi;
+-
+- if (spi == NULL)
+- status = -ESHUTDOWN;
+- else
+- status = spidev_sync_unlocked(spi, message);
+-
+- mutex_unlock(&spidev->spi_lock);
+- return status;
+-}
+-
+ static inline ssize_t
+ spidev_sync_write(struct spidev_data *spidev, size_t len)
+ {
+@@ -132,7 +113,8 @@ spidev_sync_write(struct spidev_data *spidev, size_t len)
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+- return spidev_sync(spidev, &m);
++
++ return spidev_sync_unlocked(spidev->spi, &m);
+ }
+
+ static inline ssize_t
+@@ -147,7 +129,8 @@ spidev_sync_read(struct spidev_data *spidev, size_t len)
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+- return spidev_sync(spidev, &m);
++
++ return spidev_sync_unlocked(spidev->spi, &m);
+ }
+
+ /*-------------------------------------------------------------------------*/
+@@ -157,7 +140,7 @@ static ssize_t
+ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+ {
+ struct spidev_data *spidev;
+- ssize_t status;
++ ssize_t status = -ESHUTDOWN;
+
+ /* chipselect only toggles at start or end of operation */
+ if (count > bufsiz)
+@@ -165,7 +148,11 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+
+ spidev = filp->private_data;
+
+- mutex_lock(&spidev->buf_lock);
++ mutex_lock(&spidev->spi_lock);
++
++ if (spidev->spi == NULL)
++ goto err_spi_removed;
++
+ status = spidev_sync_read(spidev, count);
+ if (status > 0) {
+ unsigned long missing;
+@@ -176,7 +163,9 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+ else
+ status = status - missing;
+ }
+- mutex_unlock(&spidev->buf_lock);
++
++err_spi_removed:
++ mutex_unlock(&spidev->spi_lock);
+
+ return status;
+ }
+@@ -187,7 +176,7 @@ spidev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+ {
+ struct spidev_data *spidev;
+- ssize_t status;
++ ssize_t status = -ESHUTDOWN;
+ unsigned long missing;
+
+ /* chipselect only toggles at start or end of operation */
+@@ -196,13 +185,19 @@ spidev_write(struct file *filp, const char __user *buf,
+
+ spidev = filp->private_data;
+
+- mutex_lock(&spidev->buf_lock);
++ mutex_lock(&spidev->spi_lock);
++
++ if (spidev->spi == NULL)
++ goto err_spi_removed;
++
+ missing = copy_from_user(spidev->tx_buffer, buf, count);
+ if (missing == 0)
+ status = spidev_sync_write(spidev, count);
+ else
+ status = -EFAULT;
+- mutex_unlock(&spidev->buf_lock);
++
++err_spi_removed:
++ mutex_unlock(&spidev->spi_lock);
+
+ return status;
+ }
+@@ -376,14 +371,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ return -ESHUTDOWN;
+ }
+
+- /* use the buffer lock here for triple duty:
+- * - prevent I/O (from us) so calling spi_setup() is safe;
+- * - prevent concurrent SPI_IOC_WR_* from morphing
+- * data fields while SPI_IOC_RD_* reads them;
+- * - SPI_IOC_MESSAGE needs the buffer locked "normally".
+- */
+- mutex_lock(&spidev->buf_lock);
+-
+ switch (cmd) {
+ /* read requests */
+ case SPI_IOC_RD_MODE:
+@@ -516,7 +503,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ break;
+ }
+
+- mutex_unlock(&spidev->buf_lock);
+ spi_dev_put(spi);
+ mutex_unlock(&spidev->spi_lock);
+ return retval;
+@@ -547,9 +533,6 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
+ return -ESHUTDOWN;
+ }
+
+- /* SPI_IOC_MESSAGE needs the buffer locked "normally" */
+- mutex_lock(&spidev->buf_lock);
+-
+ /* Check message and copy into scratch area */
+ ioc = spidev_get_ioc_message(cmd, u_ioc, &n_ioc);
+ if (IS_ERR(ioc)) {
+@@ -570,7 +553,6 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
+ kfree(ioc);
+
+ done:
+- mutex_unlock(&spidev->buf_lock);
+ spi_dev_put(spi);
+ mutex_unlock(&spidev->spi_lock);
+ return retval;
+@@ -795,7 +777,6 @@ static int spidev_probe(struct spi_device *spi)
+ /* Initialize the driver data */
+ spidev->spi = spi;
+ mutex_init(&spidev->spi_lock);
+- mutex_init(&spidev->buf_lock);
+
+ INIT_LIST_HEAD(&spidev->device_entry);
+
+--
+2.53.0
+
--- /dev/null
+From 74bfa9059f07c553d9a534dedc5baeafe68e8573 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Mar 2026 15:37:54 +0800
+Subject: iommu/amd: Fix illegal cap/mmio access in IOMMU debugfs
+
+From: Guanghui Feng <guanghuifeng@linux.alibaba.com>
+
+[ Upstream commit 0e59645683b7b6fa20eceb21a6f420e4f7412943 ]
+
+In the current AMD IOMMU debugfs, when multiple processes simultaneously
+access the IOMMU mmio/cap registers using the IOMMU debugfs, illegal
+access issues can occur in the following execution flow:
+
+1. CPU1: Sets a valid access address using iommu_mmio/capability_write,
+and verifies the access address's validity in iommu_mmio/capability_show
+
+2. CPU2: Sets an invalid address using iommu_mmio/capability_write
+
+3. CPU1: accesses the IOMMU mmio/cap registers based on the invalid
+address, resulting in an illegal access.
+
+This patch modifies the execution process to first verify the address's
+validity and then access it based on the same address, ensuring
+correctness and robustness.
+
+Signed-off-by: Guanghui Feng <guanghuifeng@linux.alibaba.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Stable-dep-of: 8dfd3d8d7443 ("iommu/amd: Remove latent out-of-bounds access in IOMMU debugfs")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/debugfs.c | 42 +++++++++++++++++--------------------
+ 1 file changed, 19 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c
+index 20b04996441d6..0584ca2f859d9 100644
+--- a/drivers/iommu/amd/debugfs.c
++++ b/drivers/iommu/amd/debugfs.c
+@@ -26,22 +26,19 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf,
+ {
+ struct seq_file *m = filp->private_data;
+ struct amd_iommu *iommu = m->private;
+- int ret;
+-
+- iommu->dbg_mmio_offset = -1;
++ int ret, dbg_mmio_offset = iommu->dbg_mmio_offset = -1;
+
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_mmio_offset);
++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
+ if (ret)
+ return ret;
+
+- if (iommu->dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) {
+- iommu->dbg_mmio_offset = -1;
+- return -EINVAL;
+- }
++ if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64))
++ return -EINVAL;
+
++ iommu->dbg_mmio_offset = dbg_mmio_offset;
+ return cnt;
+ }
+
+@@ -49,14 +46,16 @@ static int iommu_mmio_show(struct seq_file *m, void *unused)
+ {
+ struct amd_iommu *iommu = m->private;
+ u64 value;
++ int dbg_mmio_offset = iommu->dbg_mmio_offset;
+
+- if (iommu->dbg_mmio_offset < 0) {
++ if (dbg_mmio_offset < 0 || dbg_mmio_offset >
++ iommu->mmio_phys_end - sizeof(u64)) {
+ seq_puts(m, "Please provide mmio register's offset\n");
+ return 0;
+ }
+
+- value = readq(iommu->mmio_base + iommu->dbg_mmio_offset);
+- seq_printf(m, "Offset:0x%x Value:0x%016llx\n", iommu->dbg_mmio_offset, value);
++ value = readq(iommu->mmio_base + dbg_mmio_offset);
++ seq_printf(m, "Offset:0x%x Value:0x%016llx\n", dbg_mmio_offset, value);
+
+ return 0;
+ }
+@@ -67,23 +66,20 @@ static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf
+ {
+ struct seq_file *m = filp->private_data;
+ struct amd_iommu *iommu = m->private;
+- int ret;
+-
+- iommu->dbg_cap_offset = -1;
++ int ret, dbg_cap_offset = iommu->dbg_cap_offset = -1;
+
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_cap_offset);
++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
+ if (ret)
+ return ret;
+
+ /* Capability register at offset 0x14 is the last IOMMU capability register. */
+- if (iommu->dbg_cap_offset > 0x14) {
+- iommu->dbg_cap_offset = -1;
++ if (dbg_cap_offset > 0x14)
+ return -EINVAL;
+- }
+
++ iommu->dbg_cap_offset = dbg_cap_offset;
+ return cnt;
+ }
+
+@@ -91,21 +87,21 @@ static int iommu_capability_show(struct seq_file *m, void *unused)
+ {
+ struct amd_iommu *iommu = m->private;
+ u32 value;
+- int err;
++ int err, dbg_cap_offset = iommu->dbg_cap_offset;
+
+- if (iommu->dbg_cap_offset < 0) {
++ if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14) {
+ seq_puts(m, "Please provide capability register's offset in the range [0x00 - 0x14]\n");
+ return 0;
+ }
+
+- err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + iommu->dbg_cap_offset, &value);
++ err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + dbg_cap_offset, &value);
+ if (err) {
+ seq_printf(m, "Not able to read capability register at 0x%x\n",
+- iommu->dbg_cap_offset);
++ dbg_cap_offset);
+ return 0;
+ }
+
+- seq_printf(m, "Offset:0x%x Value:0x%08x\n", iommu->dbg_cap_offset, value);
++ seq_printf(m, "Offset:0x%x Value:0x%08x\n", dbg_cap_offset, value);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 5031bd461b1741d62806c7eefb7db628330ad6fd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Apr 2026 14:55:50 +0200
+Subject: iommu/amd: Remove latent out-of-bounds access in IOMMU debugfs
+
+From: Eder Zulian <ezulian@redhat.com>
+
+[ Upstream commit 8dfd3d8d74435344ee8dc9237596959c8b2a6cbe ]
+
+In iommu_mmio_write() and iommu_capability_write(), the variables
+dbg_mmio_offset and dbg_cap_offset are declared as int. However, they
+are populated using kstrtou32_from_user(). If a user provides a
+sufficiently large value, it can become a negative integer.
+
+Prior to this patch, the AMD IOMMU debugfs implementation was already
+protected by different mechanisms.
+
+1. #define OFS_IN_SZ 8 ensures the user string <= 8 bytes, so
+ e.g. 0xffffffff isn't a valid input.
+
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+2. Implicit type promotion in iommu_mmio_write(), dbg_mmio_offset is int
+ and iommu->mmio_phys_end is u64
+
+ if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64))
+ return -EINVAL;
+
+3. The show handlers would currently catch the negative number and
+ refuse to perform the read.
+
+Replace kstrtou32_from_user() with kstrtos32_from_user() to parse the
+input, and check for negative values to explicitly prevent out-of-bounds
+memory accesses directly in iommu_mmio_write() and
+iommu_capability_write().
+
+Signed-off-by: Eder Zulian <ezulian@redhat.com>
+Fixes: 7a4ee419e8c1 ("iommu/amd: Add debugfs support to dump IOMMU MMIO registers")
+Cc: stable@vger.kernel.org
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/debugfs.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c
+index 0584ca2f859d9..3909a1fb218e9 100644
+--- a/drivers/iommu/amd/debugfs.c
++++ b/drivers/iommu/amd/debugfs.c
+@@ -31,11 +31,12 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf,
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
++ ret = kstrtos32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
+ if (ret)
+ return ret;
+
+- if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64))
++ if (dbg_mmio_offset < 0 || dbg_mmio_offset >
++ iommu->mmio_phys_end - sizeof(u64))
+ return -EINVAL;
+
+ iommu->dbg_mmio_offset = dbg_mmio_offset;
+@@ -71,12 +72,12 @@ static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf
+ if (cnt > OFS_IN_SZ)
+ return -EINVAL;
+
+- ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
++ ret = kstrtos32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
+ if (ret)
+ return ret;
+
+ /* Capability register at offset 0x14 is the last IOMMU capability register. */
+- if (dbg_cap_offset > 0x14)
++ if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14)
+ return -EINVAL;
+
+ iommu->dbg_cap_offset = dbg_cap_offset;
+--
+2.53.0
+
--- /dev/null
+iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch
+iommu-amd-remove-latent-out-of-bounds-access-in-iomm.patch