FAILED: patch "[PATCH] smb: client: clear setuid/setgid bit on write with" failed to apply to 6.18-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x b8e5dc4f95e5484159b343903f302eb6d783f2e6
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090324-defraud-tremble-b3d8@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b8e5dc4f95e5484159b343903f302eb6d783f2e6 Mon Sep 17 00:00:00 2001
From: Jiangshan Yi <[email protected]>
Date: Thu, 16 Jul 2026 10:22:14 +0800
Subject: [PATCH] smb: client: clear setuid/setgid bit on write with
cifsacl/modefromsid/posix extensions
When a file has the setuid or setgid bit set and is written to, the VFS strips those bits and issues a setattr with ATTR_KILL_SUID/ATTR_KILL_SGID together with an ATTR_MODE carrying the already-cleared mode.
Both cifs_setattr_unix() and cifs_setattr_nounix() unconditionally dropped ATTR_MODE in that case:
/* skip mode change if it's just for clearing setuid/setgid */ if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) attrs->ia_valid &= ~ATTR_MODE;
This is fine for the default mount, where the mode is only emulated via the DOS read-only attribute and cannot represent the setuid/setgid bits anyway. However, with the "cifsacl" or "modefromsid" mount options the mode is stored on the server through an ACL (id_mode_to_cifs_acl()), with the SMB3.1.1 POSIX extensions the mode is sent to the server directly, and with the SMB1 Unix extensions (cifs_setattr_unix) the mode is sent via CIFSSMBUnixSetPathInfo(). In all those cases dropping ATTR_MODE means the cleared mode is never pushed to the server, so the setuid/setgid bit survives the write.
This is a security issue: on local filesystems the setuid bit is stripped when a file is written, but over these cifs.ko mounts the bit persists on the server, potentially allowing an unexpected privilege escalation on subsequent execution.
Fix this in two places:
1. cifs_setattr_nounix(): only take the "skip mode change" shortcut when the mode is emulated via the DOS read-only attribute (i.e. neither cifsacl/modefromsid nor the SMB3.1.1 POSIX extensions are in effect), so that the cleared mode is propagated to the server in the ACL / POSIX cases.
2. cifs_setattr_unix(): this function is only called when Unix extensions are in effect, so the mode is always stored on the server. Remove the shortcut entirely so that the cleared mode is always pushed.
fs/smb/client/inode.c +24 -5
@@ -3214,9 +3214,13 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) attrs->ia_valid &= ~(ATTR_CTIME |ATTR_MTIME ); } -/* skip mode change if it's just for clearing setuid/setgid */ -if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) - attrs->ia_valid &= ~ATTR_MODE ; +/* +* This function is only called when Unix extensions are in effect, +* so the mode is always sent to and stored on the server. Do not +* skip the mode change when clearing setuid/setgid bits: dropping +* ATTR_MODE here would leave those bits set on the server after a +* write, which is a security issue. +*/ args =kmalloc_obj (*args);if (args ==NULL ) {
@@ -3425,8 +3429,23 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) attrs->ia_valid &= ~(ATTR_UID |ATTR_GID ); } -/* skip mode change if it's just for clearing setuid/setgid */ -if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) +/* +* Skip the mode change if it is only being done to clear the +* setuid/setgid bits *and* the mode is emulated via the DOS +* read-only attribute (the default, non-ACL case), which cannot +* represent the setuid/setgid bits anyway. +* +* When the mode is instead stored on the server - i.e. with the +* cifsacl or modefromsid mount options (via an ACL) or with the +* SMB3.1.1 POSIX extensions - the cleared mode must be pushed to +* the server. Dropping ATTR_MODE here would leave the setuid/ +* setgid bit set on the server after a write, which is a security +* issue (the bits are not stripped as they are on local +* filesystems). +*/ +if ((attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) && + !((sbflags & (CIFS_MOUNT_CIFS_ACL |CIFS_MOUNT_MODE_FROM_SID )) || +cifs_sb_master_tcon (cifs_sb)->posix_extensions)) attrs->ia_valid &= ~ATTR_MODE ;if (attrs->ia_valid &ATTR_MODE ) {
Sasha Levin
maintainerPATCH 1/5 cifs: Scripted clean up fs/smb/client/cifs_unicode.h
From: David Howells <[email protected]>
[ Upstream commit 696ca7d95658224ba807813101d0d5714d1d8aa4 ]
Remove externs, correct argument names and reformat declarations.
For the stable backport, drop the original header cleanup because the stable-only __KERNEL__ guard makes it conflict and the target does not touch or depend on those declarations. Instead, carry only a behavior-preserving local snapshot of mnt_cifs_flags in cifs_setattr_nounix(); the target patch refers to that snapshot in its new setuid/setgid condition.
[ sashal: Reduced backport -- upstream 696ca7d956582 touches 1 file(s), this
backport carries 1. Not backported here:
fs/smb/client/cifs_unicode.h
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: b8e5dc4f95e5 ("smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions")
--- fs/smb/client/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/smb/client/inode.c +2 -1
@@ -3292,6 +3292,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)kgid_t gid =INVALID_GID ;struct inode *inode =d_inode (direntry);struct cifs_sb_info *cifs_sb =CIFS_SB (inode->i_sb); +unsigned int sbflags = cifs_sb->mnt_cifs_flags;struct cifsInodeInfo *cifsInode =CIFS_I (inode);struct cifsFileInfo *cfile =NULL ;const char *full_path;
@@ -3306,7 +3307,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)cifs_dbg (FYI ,"setattr on file %pd attrs->ia_valid 0x%x\n" , direntry, attrs->ia_valid); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_PERM ) +if (sbflags &CIFS_MOUNT_NO_PERM ) attrs->ia_valid |=ATTR_FORCE ; rc =setattr_prepare (&nop_mnt_idmap, direntry, attrs);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 cifs: Scripted clean up fs/smb/client/fscache.h
From: David Howells <[email protected]>
[ Upstream commit bc3de356aae666de5d8b5131545be87cf7754431 ]
Remove externs, correct argument names and reformat declarations.
Stable-dep-of: b8e5dc4f95e5 ("smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions")
--- fs/smb/client/fscache.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/smb/client/fscache.h +5 -5
@@ -38,12 +38,12 @@ struct cifs_fscache_inode_coherency_data {/* * fscache.c */ -extern int cifs_fscache_get_super_cookie (struct cifs_tcon *); -extern void cifs_fscache_release_super_cookie (struct cifs_tcon *); +int cifs_fscache_get_super_cookie (struct cifs_tcon *tcon); +void cifs_fscache_release_super_cookie (struct cifs_tcon *tcon); -extern void cifs_fscache_get_inode_cookie (struct inode *inode); -extern void cifs_fscache_release_inode_cookie (struct inode *); -extern void cifs_fscache_unuse_inode_cookie (struct inode *inode,bool update); +void cifs_fscache_get_inode_cookie (struct inode *inode); +void cifs_fscache_release_inode_cookie (struct inode *inode); +void cifs_fscache_unuse_inode_cookie (struct inode *inode,bool update); static inline void cifs_fscache_fill_coherency(struct inode *inode,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 cifs: Scripted clean up fs/smb/client/fs_context.h
In reply to Sasha LevinFrom: David Howells <[email protected]>
[ Upstream commit 047e504766a357ab751f76ccdec7a2e824e75e6d ]
Remove externs, correct argument names and reformat declarations.
Stable-dep-of: b8e5dc4f95e5 ("smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions")
--- fs/smb/client/fs_context.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
fs/smb/client/fs_context.h +9 -7
@@ -359,18 +359,20 @@ static inline enum cifs_symlink_type cifs_symlink_type(struct cifs_sb_info *cifsreturn CIFS_SYMLINK_TYPE_NONE ; } -extern int smb3_init_fs_context (struct fs_context *fc); -extern void smb3_cleanup_fs_context_contents (struct smb3_fs_context *ctx); -extern void smb3_cleanup_fs_context (struct smb3_fs_context *ctx); +int smb3_init_fs_context (struct fs_context *fc); +void smb3_cleanup_fs_context_contents (struct smb3_fs_context *ctx); +void smb3_cleanup_fs_context (struct smb3_fs_context *ctx);static inline struct smb3_fs_context *smb3_fc2context (const struct fs_context *fc) {return fc->fs_private; } -extern int smb3_fs_context_dup (struct smb3_fs_context *new_ctx,struct smb3_fs_context *ctx); -extern int smb3_sync_session_ctx_passwords (struct cifs_sb_info *cifs_sb,struct cifs_ses *ses); -extern void smb3_update_mnt_flags (struct cifs_sb_info *cifs_sb); +int smb3_fs_context_dup (struct smb3_fs_context *new_ctx, +struct smb3_fs_context *ctx); +int smb3_sync_session_ctx_passwords (struct cifs_sb_info *cifs_sb, +struct cifs_ses *ses); +void smb3_update_mnt_flags (struct cifs_sb_info *cifs_sb);/* * max deferred close timeout (jiffies) - 2^30
@@ -378,7 +380,7 @@ extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);#define SMB3_MAX_DCLOSETIMEO (1 << 30)#define SMB3_DEF_DCLOSETIMEO (1 * HZ)/* even 1 sec enough to help eg open/write/close/open/read */ #define MAX_CACHED_FIDS 16 -extern char *cifs_sanitize_prepath (char *prepath,gfp_t gfp); +char *cifs_sanitize_prepath (char *prepath,gfp_t gfp);extern struct mutex cifs_mount_mutex;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 cifs: Scripted clean up fs/smb/client/smb2proto.h
In reply to Sasha LevinFrom: David Howells <[email protected]>
[ Upstream commit 1e009e3346db230787685a3989fd9c346fb412fb ]
Remove externs, correct argument names and reformat declarations.
For the stable backport, drop the original smb2proto.h cleanup because the stable header has gained and changed declarations that make the scripted rewrite conflict, while the target does not touch or depend on the header. Instead, carry only behavior-preserving context preparation in inode.c: use the type-safe kmalloc_obj() spelling and the existing local sbflags snapshot, and brace the adjacent else-if. This allows both target hunks to apply cleanly without pre-applying the target's behavioral change.
[ sashal: Reduced backport -- upstream 1e009e3346db touches 1 file(s), this
backport carries 1. Not backported here:
fs/smb/client/smb2proto.h
This note is generated from the file lists only; see the resolution record for the reasoning. ]
[ sashal: Reduced backport -- upstream 1e009e3346db2 touches 1 file(s), this
backport carries 1. Not backported here:
fs/smb/client/smb2proto.h
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: b8e5dc4f95e5 ("smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions")
--- fs/smb/client/inode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/smb/client/inode.c +3 -3
@@ -3187,7 +3187,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) attrs->ia_valid &= ~ATTR_MODE ; - args =kmalloc (sizeof (*args),GFP_KERNEL ); + args =kmalloc_obj (*args);if (args ==NULL ) { rc = -ENOMEM ; goto out;
@@ -3380,9 +3380,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) goto cifs_setattr_exit; } } - }else -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID )) + }else if (!(sbflags &CIFS_MOUNT_SET_UID )) { attrs->ia_valid &= ~(ATTR_UID |ATTR_GID ); + }/* skip mode change if it's just for clearing setuid/setgid */ if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID ))
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/5 smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions
In reply to Sasha LevinFrom: Jiangshan Yi <[email protected]>
[ Upstream commit b8e5dc4f95e5484159b343903f302eb6d783f2e6 ]
When a file has the setuid or setgid bit set and is written to, the VFS strips those bits and issues a setattr with ATTR_KILL_SUID/ATTR_KILL_SGID together with an ATTR_MODE carrying the already-cleared mode.
Both cifs_setattr_unix() and cifs_setattr_nounix() unconditionally dropped ATTR_MODE in that case:
/* skip mode change if it's just for clearing setuid/setgid */ if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) attrs->ia_valid &= ~ATTR_MODE;
This is fine for the default mount, where the mode is only emulated via the DOS read-only attribute and cannot represent the setuid/setgid bits anyway. However, with the "cifsacl" or "modefromsid" mount options the mode is stored on the server through an ACL (id_mode_to_cifs_acl()), with the SMB3.1.1 POSIX extensions the mode is sent to the server directly, and with the SMB1 Unix extensions (cifs_setattr_unix) the mode is sent via CIFSSMBUnixSetPathInfo(). In all those cases dropping ATTR_MODE means the cleared mode is never pushed to the server, so the setuid/setgid bit survives the write.
This is a security issue: on local filesystems the setuid bit is stripped when a file is written, but over these cifs.ko mounts the bit persists on the server, potentially allowing an unexpected privilege escalation on subsequent execution.
Fix this in two places:
1. cifs_setattr_nounix(): only take the "skip mode change" shortcut when the mode is emulated via the DOS read-only attribute (i.e. neither cifsacl/modefromsid nor the SMB3.1.1 POSIX extensions are in effect), so that the cleared mode is propagated to the server in the ACL / POSIX cases.
2. cifs_setattr_unix(): this function is only called when Unix extensions are in effect, so the mode is always stored on the server. Remove the shortcut entirely so that the cleared mode is always pushed.
--- fs/smb/client/inode.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-)
fs/smb/client/inode.c +24 -5
@@ -3183,9 +3183,13 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) attrs->ia_valid &= ~(ATTR_CTIME |ATTR_MTIME ); } -/* skip mode change if it's just for clearing setuid/setgid */ -if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) - attrs->ia_valid &= ~ATTR_MODE ; +/* +* This function is only called when Unix extensions are in effect, +* so the mode is always sent to and stored on the server. Do not +* skip the mode change when clearing setuid/setgid bits: dropping +* ATTR_MODE here would leave those bits set on the server after a +* write, which is a security issue. +*/ args =kmalloc_obj (*args);if (args ==NULL ) {
@@ -3384,8 +3388,23 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) attrs->ia_valid &= ~(ATTR_UID |ATTR_GID ); } -/* skip mode change if it's just for clearing setuid/setgid */ -if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) +/* +* Skip the mode change if it is only being done to clear the +* setuid/setgid bits *and* the mode is emulated via the DOS +* read-only attribute (the default, non-ACL case), which cannot +* represent the setuid/setgid bits anyway. +* +* When the mode is instead stored on the server - i.e. with the +* cifsacl or modefromsid mount options (via an ACL) or with the +* SMB3.1.1 POSIX extensions - the cleared mode must be pushed to +* the server. Dropping ATTR_MODE here would leave the setuid/ +* setgid bit set on the server after a write, which is a security +* issue (the bits are not stripped as they are on local +* filesystems). +*/ +if ((attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) && + !((sbflags & (CIFS_MOUNT_CIFS_ACL |CIFS_MOUNT_MODE_FROM_SID )) || +cifs_sb_master_tcon (cifs_sb)->posix_extensions)) attrs->ia_valid &= ~ATTR_MODE ;if (attrs->ia_valid &ATTR_MODE ) {
Signature · 1 line
2.53.0