FAILED: patch "[PATCH] smb: client: clear setuid/setgid bit on write with" failed to apply to 6.12-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.12-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.12.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 '2026090351-popper-penpal-d0a0@gregkh' --subject-prefix 'PATCH 6.12.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.
Stable-dep-of: b8e5dc4f95e5 ("smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions")
--- fs/smb/client/cifs_unicode.h | 17 +++++++++-------- fs/smb/client/inode.c | 26 ++++++++++++++------------ 2 files changed, 23 insertions(+), 20 deletions(-)
fs/smb/client/cifs_unicode.h +9 -8
@@ -56,19 +56,20 @@#ifdef __KERNEL__int cifs_from_utf16 (char *to,const __le16 *from,int tolen,int fromlen, -const struct nls_table *cp,int map_type); +const struct nls_table *codepage,int map_type);int cifs_utf16_bytes (const __le16 *from,int maxbytes,const struct nls_table *codepage); -int cifs_strtoUTF16 (__le16 *,const char *,int ,const struct nls_table *); +int cifs_strtoUTF16 (__le16 *to,const char *from,int len, +const struct nls_table *codepage);char *cifs_strndup_from_utf16 (const char *src,const int maxlen,const bool is_unicode,const struct nls_table *codepage); -extern int cifsConvertToUTF16 (__le16 *target,const char *source,int maxlen, -const struct nls_table *cp,int mapChars); -extern int cifs_remap (struct cifs_sb_info *cifs_sb); -extern __le16 *cifs_strndup_to_utf16 (const char *src,const int maxlen, -int *utf16_len,const struct nls_table *cp, -int remap); +int cifsConvertToUTF16 (__le16 *target,const char *source,int srclen, +const struct nls_table *cp,int map_chars); +int cifs_remap (struct cifs_sb_info *cifs_sb); +__le16 *cifs_strndup_to_utf16 (const char *src,const int maxlen, +int *utf16_len,const struct nls_table *cp, +int remap);#endif wchar_t cifs_toupper (wchar_t in);
fs/smb/client/inode.c +14 -12
@@ -3115,13 +3115,14 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) rc =cifs_set_file_size (inode, attrs, xid, full_path, direntry);if (rc !=0 ) goto out; + 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 ; - args =kmalloc (sizeof (*args),GFP_KERNEL ); + args =kmalloc_obj (*args);if (args ==NULL ) { rc = -ENOMEM ; goto out;
@@ -3217,6 +3218,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)struct inode *inode =d_inode (direntry);struct cifs_sb_info *cifs_sb =CIFS_SB (inode->i_sb);struct cifsInodeInfo *cifsInode =CIFS_I (inode); +unsigned int sbflags = cifs_sb->mnt_cifs_flags;struct cifsFileInfo *wfile;struct cifs_tcon *tcon;const char *full_path;
@@ -3231,7 +3233,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);
@@ -3265,7 +3267,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) rc =0 ;if ((attrs->ia_valid &ATTR_MTIME ) && - !(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOSSYNC )) { + !(sbflags &CIFS_MOUNT_NOSSYNC )) { rc =cifs_get_writable_file (cifsInode,FIND_WR_ANY , &wfile);if (!rc) { tcon =tlink_tcon (wfile->tlink);
@@ -3291,8 +3293,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)if (attrs->ia_valid &ATTR_GID ) gid = attrs->ia_gid; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_ACL ) || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID )) { +if ((sbflags &CIFS_MOUNT_CIFS_ACL ) || + (sbflags &CIFS_MOUNT_MODE_FROM_SID )) {if (uid_valid (uid) ||gid_valid (gid)) { mode =NO_CHANGE_64 ; rc = id_mode_to_cifs_acl(inode, full_path, &mode,
@@ -3303,9 +3305,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 ))
@@ -3314,8 +3316,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)if (attrs->ia_valid &ATTR_MODE ) { mode = attrs->ia_mode; rc =0 ; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_ACL ) || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID ) || +if ((sbflags &CIFS_MOUNT_CIFS_ACL ) || + (sbflags &CIFS_MOUNT_MODE_FROM_SID ) || posix) { rc =id_mode_to_cifs_acl (inode, full_path, &mode,INVALID_UID ,INVALID_GID );
@@ -3338,7 +3340,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) dosattr = cifsInode->cifsAttrs |ATTR_READONLY ;/* fix up mode if we're not using dynperm */ -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM ) ==0 ) +if ((sbflags &CIFS_MOUNT_DYNPERM ) ==0 ) attrs->ia_mode = inode->i_mode & ~S_IWUGO ; }else if ((mode &S_IWUGO ) && (cifsInode->cifsAttrs &ATTR_READONLY )) {
@@ -3349,7 +3351,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) dosattr |=ATTR_NORMAL ;/* reset local inode permissions to normal */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM )) { +if (!(sbflags &CIFS_MOUNT_DYNPERM )) { attrs->ia_mode &= ~(S_IALLUGO );if (S_ISDIR (inode->i_mode)) attrs->ia_mode |=
@@ -3358,7 +3360,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) attrs->ia_mode |= cifs_sb->ctx->file_mode; } - }else if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM )) { + }else if (!(sbflags &CIFS_MOUNT_DYNPERM )) {/* ignore mode change - ATTR_READONLY hasn't changed */ attrs->ia_valid &= ~ATTR_MODE ; }
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: SMB1 split: Create smb1proto.h for SMB1 declarations
In reply to Sasha LevinFrom: David Howells <[email protected]>
[ Upstream commit 86c666506ea2c42649879eeac7f29e7bedef2f23 ]
Stable-dep-of: b8e5dc4f95e5 ("smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions")
--- fs/smb/client/cifsglob.h | 2 -- fs/smb/client/cifsproto.h | 11 +---------- fs/smb/client/smb1proto.h | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 fs/smb/client/smb1proto.h
fs/smb/client/cifsglob.h +0 -2
@@ -2061,8 +2061,6 @@ extern mempool_t cifs_io_subrequest_pool;/* Operations for different SMB versions */ #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY -extern struct smb_version_operations smb1_operations; -extern struct smb_version_values smb1_values;extern struct smb_version_operations smb20_operations;extern struct smb_version_values smb20_values;#endif /* CIFS_ALLOW_INSECURE_LEGACY */
fs/smb/client/cifsproto.h +1 -10
@@ -13,6 +13,7 @@#ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" #endif +#include "smb1proto.h" struct statfs ;struct smb_rqst ;
@@ -421,16 +422,6 @@ extern int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile, __u64 size, bool set_allocation); -struct cifs_unix_set_info_args { -__u64 ctime; -__u64 atime; -__u64 mtime; -__u64 mode; -kuid_t uid; -kgid_t gid; -dev_t device; -}; - extern int CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const struct cifs_unix_set_info_args *args,
fs/smb/client/smb1proto.h new file +38 -0
@@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* +* +* Copyright (c) International Business Machines Corp., 2002,2008 +* Author(s): Steve French ([email protected]) +* +*/ +#ifndef _SMB1PROTO_H +#define _SMB1PROTO_H + +struct cifs_unix_set_info_args { +__u64 ctime; +__u64 atime; +__u64 mtime; +__u64 mode; +kuid_t uid; +kgid_t gid; +dev_t device; +}; + +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY + +/* +* cifssmb.c +*/ + +/* +* smb1ops.c +*/ +extern struct smb_version_operations smb1_operations; +extern struct smb_version_values smb1_values; + +/* +* smb1transport.c +*/ + +#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ +#endif /* _SMB1PROTO_H */
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 smb: client: use atomic_t for mnt_cifs_flags
In reply to Sasha LevinFrom: Paulo Alcantara <[email protected]>
[ Upstream commit 4fc3a433c13944ee5766ec5b9bf6f1eb4d29b880 ]
Use atomic_t for cifs_sb_info::mnt_cifs_flags as it's currently accessed locklessly and may be changed concurrently in mount/remount and reconnect paths.
[ sashal: Reduced backport -- upstream 4fc3a433c1394 touches 27 file(s), this
backport carries 24. Not backported here:
fs/smb/client/cifs_unicode.h
fs/smb/client/reparse.c
fs/smb/client/smb2file.c
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/cached_dir.c | 2 +- fs/smb/client/cifs_fs_sb.h | 2 +- fs/smb/client/cifs_ioctl.h | 2 +- fs/smb/client/cifs_unicode.c | 5 +- fs/smb/client/cifsacl.c | 6 +- fs/smb/client/cifsfs.c | 66 ++++++++++----------- fs/smb/client/cifsglob.h | 9 ++- fs/smb/client/connect.c | 53 +++++++++-------- fs/smb/client/dfs_cache.c | 2 +- fs/smb/client/dir.c | 16 ++--- fs/smb/client/file.c | 32 +++++----- fs/smb/client/fs_context.c | 112 ++++++++++++++++++----------------- fs/smb/client/fs_context.h | 2 +- fs/smb/client/inode.c | 64 ++++++++++---------- fs/smb/client/ioctl.c | 2 +- fs/smb/client/link.c | 4 +- fs/smb/client/misc.c | 12 ++-- fs/smb/client/readdir.c | 16 ++--- fs/smb/client/reparse.h | 4 +- fs/smb/client/smb1ops.c | 4 +- fs/smb/client/smb2misc.c | 4 +- fs/smb/client/smb2ops.c | 4 +- fs/smb/client/smb2pdu.c | 4 +- fs/smb/client/xattr.c | 6 +- 24 files changed, 222 insertions(+), 211 deletions(-)
fs/smb/client/cached_dir.c +1 -1
@@ -118,7 +118,7 @@ static const char *path_no_prefix(struct cifs_sb_info *cifs_sb,if (!*path)return path; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_USE_PREFIX_PATH ) && +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_USE_PREFIX_PATH ) && cifs_sb->prepath) { len =strlen (cifs_sb->prepath) +1 ;if (unlikely (len >strlen (path)))
fs/smb/client/cifs_fs_sb.h +1 -1
@@ -54,7 +54,7 @@ struct cifs_sb_info {struct nls_table *local_nls;struct smb3_fs_context *ctx;atomic_t active; -unsigned int mnt_cifs_flags; +atomic_t mnt_cifs_flags;struct delayed_work prune_tlinks;struct rcu_head rcu;
fs/smb/client/cifs_ioctl.h +1 -1
@@ -125,7 +125,7 @@ struct smb3_notify_info {static inline bool cifs_forced_shutdown (struct cifs_sb_info *sbi) { -if (CIFS_MOUNT_SHUTDOWN & sbi->mnt_cifs_flags) +if (CIFS_MOUNT_SHUTDOWN &atomic_read (&sbi->mnt_cifs_flags))return true;else return false;
fs/smb/client/cifs_unicode.c +3 -2
@@ -15,10 +15,11 @@int cifs_remap (struct cifs_sb_info *cifs_sb) {int map_type; +unsigned int sbflags =cifs_sb_flags (cifs_sb); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SFM_CHR ) +if (sbflags &CIFS_MOUNT_MAP_SFM_CHR ) map_type =SFM_MAP_UNI_RSVD ; -else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SPECIAL_CHR ) +else if (sbflags &CIFS_MOUNT_MAP_SPECIAL_CHR ) map_type =SFU_MAP_UNI_RSVD ;else map_type =NO_MAP_UNI_RSVD ;
fs/smb/client/cifsacl.c +3 -3
@@ -356,7 +356,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,return -EIO ; } -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UID_FROM_ACL ) || +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UID_FROM_ACL ) || (cifs_sb_master_tcon (cifs_sb)->posix_extensions)) {uint32_t unix_id;bool is_group;
@@ -1715,12 +1715,12 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,return rc; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MODE_FROM_SID ) mode_from_sid = true;else mode_from_sid = false; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UID_FROM_ACL ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UID_FROM_ACL ) id_from_sid = true;else id_from_sid = false;
fs/smb/client/cifsfs.c +33 -33
148 lines not on this page · raw message
fs/smb/client/cifsglob.h +6 -3
@@ -1500,9 +1500,9 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG) -#define CIFS_CACHE_READ (cinode) ((cinode->oplock & CIFS_CACHE_READ_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE)) +#define CIFS_CACHE_READ (cinode) ((cinode->oplock & CIFS_CACHE_READ_FLG) || (cifs_sb_flags(CIFS_SB(cinode->netfs.inode.i_sb)) & CIFS_MOUNT_RO_CACHE))#define CIFS_CACHE_HANDLE (cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG) -#define CIFS_CACHE_WRITE (cinode) ((cinode->oplock & CIFS_CACHE_WRITE_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)) +#define CIFS_CACHE_WRITE (cinode) ((cinode->oplock & CIFS_CACHE_WRITE_FLG) || (cifs_sb_flags(CIFS_SB(cinode->netfs.inode.i_sb)) & CIFS_MOUNT_RW_CACHE))/* * One of these for each file inode
@@ -1563,9 +1563,12 @@ CIFS_FILE_SB(struct file *file)return CIFS_SB (file_inode (file)->i_sb); } +#define cifs_sb_flags (cifs_sb) \ + ((unsigned int)atomic_read(&(cifs_sb)->mnt_cifs_flags)) +static inline char CIFS_DIR_SEP (const struct cifs_sb_info *cifs_sb) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS )return '/' ;else return '\\' ;
fs/smb/client/connect.c +29 -24
156 lines not on this page · raw message
fs/smb/client/dfs_cache.c +1 -1
@@ -1321,7 +1321,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)* Force the use of prefix path to support failover on DFS paths that resolve to targets * that have different prefix paths. */ - cifs_sb->mnt_cifs_flags |=CIFS_MOUNT_USE_PREFIX_PATH ; +atomic_or (CIFS_MOUNT_USE_PREFIX_PATH , &cifs_sb->mnt_cifs_flags);refresh_tcon_referral (tcon, true);return 0 ;
fs/smb/client/dir.c +8 -8
@@ -96,7 +96,7 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *paelse dfsplen =0 ; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_USE_PREFIX_PATH ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_USE_PREFIX_PATH ) pplen = cifs_sb->prepath ?strlen (cifs_sb->prepath) +1 :0 ; s =dentry_path_raw (direntry, page,PATH_MAX );
@@ -123,7 +123,7 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *paif (dfsplen) { s -= dfsplen;memcpy (s, tree, dfsplen); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS ) {int i;for (i =0 ; i < dfsplen; i++) {if (s[i] =='\\' )
@@ -160,7 +160,7 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon) le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))return -ENAMETOOLONG ; -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS )) { +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS )) {for (i =0 ; i < direntry->d_name.len; i++) {if (direntry->d_name.name[i] =='\\' ) {cifs_dbg (FYI ,"Invalid file name\n" );
@@ -350,7 +350,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned .device = 0, }; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SET_UID ) { args.uid =current_fsuid ();if (inode->i_mode &S_ISGID ) args.gid = inode->i_gid;
@@ -387,9 +387,9 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsignedif (server->ops->set_lease_key) server->ops->set_lease_key (newinode, fid);if ((*oplock &CIFS_CREATE_ACTION ) &&S_ISREG (newinode->i_mode)) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_DYNPERM ) newinode->i_mode = mode; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SET_UID ) { newinode->i_uid =current_fsuid ();if (inode->i_mode &S_ISGID ) newinode->i_gid = inode->i_gid;
@@ -519,8 +519,8 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, }if (file->f_flags &O_DIRECT && -CIFS_SB (inode->i_sb)->mnt_cifs_flags &CIFS_MOUNT_STRICT_IO ) { -if (CIFS_SB (inode->i_sb)->mnt_cifs_flags &CIFS_MOUNT_NO_BRL ) +cifs_sb_flags (CIFS_SB (inode->i_sb)) &CIFS_MOUNT_STRICT_IO ) { +if (cifs_sb_flags (CIFS_SB (inode->i_sb)) &CIFS_MOUNT_NO_BRL ) file->f_op = &cifs_file_direct_nobrl_ops;else file->f_op = &cifs_file_direct_ops;
fs/smb/client/file.c +16 -16
@@ -269,7 +269,7 @@ static int cifs_init_request(struct netfs_io_request *rreq, struct file *file) open_file = file->private_data; rreq->netfs_priv = file->private_data; req->cfile =cifsFileInfo_get (open_file); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_RWPIDFORWARD ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_RWPIDFORWARD ) req->pid = req->cfile->pid; }else if (rreq->origin !=NETFS_WRITEBACK ) {WARN_ON_ONCE (1 );
@@ -883,7 +883,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,* close because it may cause a error when we open this file * again and get at least level II oplock. */ -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_STRICT_IO ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_STRICT_IO )set_bit (CIFS_INO_INVALID_MAPPING , &cifsi->flags);cifs_set_oplock_level (cifsi,0 ); }
@@ -974,8 +974,8 @@ int cifs_open(struct inode *inode, struct file *file) inode, file->f_flags, full_path);if (file->f_flags &O_DIRECT && - cifs_sb->mnt_cifs_flags &CIFS_MOUNT_STRICT_IO ) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_BRL ) +cifs_sb_flags (cifs_sb) &CIFS_MOUNT_STRICT_IO ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_BRL ) file->f_op = &cifs_file_direct_nobrl_ops;else file->f_op = &cifs_file_direct_ops;
@@ -1123,7 +1123,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) rc =cifs_push_posix_locks (cfile); else#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -1919,7 +1919,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) rc =cifs_push_posix_locks (cfile); else#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -2327,7 +2327,7 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) posix_lck = true;if (!lock && !unlock) {
@@ -2377,7 +2377,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) posix_lck = true;/* * BB add code here to normalize offset and length to account for
@@ -2432,7 +2432,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,struct cifs_sb_info *cifs_sb =CIFS_SB (cifs_inode->netfs.inode.i_sb);/* only filter by fsuid on multiuser mounts */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MULTIUSER )) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MULTIUSER )) fsuid_only = false;spin_lock (&cifs_inode->open_file_lock);
@@ -2488,7 +2488,7 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags, cifs_sb =CIFS_SB (cifs_inode->netfs.inode.i_sb);/* only filter by fsuid on multiuser mounts */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MULTIUSER )) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MULTIUSER )) fsuid_only = false;spin_lock (&cifs_inode->open_file_lock);
@@ -2663,7 +2663,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, } tcon =tlink_tcon (smbfile->tlink); -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOSSYNC )) { +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOSSYNC )) { server = tcon->ses->server;if (server->ops->flush ==NULL ) { rc = -ENOSYS ;
@@ -2711,7 +2711,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) file, datasync); tcon =tlink_tcon (smbfile->tlink); -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOSSYNC )) { +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOSSYNC )) { server = tcon->ses->server;if (server->ops->flush ==NULL ) { rc = -ENOSYS ;
@@ -2780,7 +2780,7 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)if (rc <=0 ) goto out; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) && +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) && (cifs_find_lock_conflict (cfile, iocb->ki_pos,iov_iter_count (from), server->vals->exclusive_lock_type,0 ,NULL ,CIFS_WRITE_OP ))) {
@@ -2816,7 +2816,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)if (CIFS_CACHE_WRITE (cinode)) {if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) { + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) { written =netfs_file_write_iter (iocb, from); goto out; }
@@ -2921,7 +2921,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)if (!CIFS_CACHE_READ (cinode))return netfs_unbuffered_read_iter (iocb, to); -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 ) { +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 ) {if (iocb->ki_flags &IOCB_DIRECT )return netfs_unbuffered_read_iter (iocb, to);return netfs_buffered_read_iter (iocb, to);
@@ -3043,7 +3043,7 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,struct cifs_sb_info *cifs_sb; cifs_sb =CIFS_SB (cifsInode->netfs.inode.i_sb); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DIRECT_IO ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_DIRECT_IO ) {/* since no page cache to corrupt on directio we can change size safely */ return true;
fs/smb/client/fs_context.c +57 -55
205 lines not on this page · raw message
fs/smb/client/fs_context.h +1 -1
@@ -313,7 +313,7 @@ static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *fextern 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); +extern unsigned int smb3_update_mnt_flags (struct cifs_sb_info *cifs_sb);/* * max deferred close timeout (jiffies) - 2^30
fs/smb/client/inode.c +32 -32
216 lines not on this page · raw message
fs/smb/client/ioctl.c +1 -1
@@ -220,7 +220,7 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)*/ case CIFS_GOING_FLAGS_LOGFLUSH :case CIFS_GOING_FLAGS_NOLOGFLUSH : - sbi->mnt_cifs_flags |=CIFS_MOUNT_SHUTDOWN ; +atomic_or (CIFS_MOUNT_SHUTDOWN , &sbi->mnt_cifs_flags); goto shutdown_good;default : rc = -EINVAL ;
fs/smb/client/link.c +2 -2
@@ -604,9 +604,9 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,cifs_dbg (FYI ,"symname is %s\n" , symname);/* BB what if DFS and this volume is on different share? BB */ -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MF_SYMLINKS ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MF_SYMLINKS ) { rc =create_mf_symlink (xid, pTcon, cifs_sb, full_path, symname); - }else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL ) { + }else if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL ) { rc =__cifs_sfu_make_node (xid, inode, direntry, pTcon, full_path,S_IFLNK ,0 , symname);#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
fs/smb/client/misc.c +6 -6
@@ -562,13 +562,13 @@ dump_smb(void *buf, int smb_buf_length)void cifs_autodisable_serverino (struct cifs_sb_info *cifs_sb) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM ) {struct cifs_tcon *tcon =NULL ;if (cifs_sb->master_tlink) tcon =cifs_sb_master_tcon (cifs_sb); - cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM ; +atomic_andnot (CIFS_MOUNT_SERVER_INUM , &cifs_sb->mnt_cifs_flags); cifs_sb->mnt_cifs_serverino_autodisabled = true;cifs_dbg (VFS ,"Autodisabling the use of server inode numbers on %s\n" , tcon ? tcon->tree_name :"new server" );
@@ -669,11 +669,11 @@ void cifs_done_oplock_break(struct cifsInodeInfo *cinode)bool backup_cred (struct cifs_sb_info *cifs_sb) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_BACKUPUID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_CIFS_BACKUPUID ) {if (uid_eq (cifs_sb->ctx->backupuid,current_fsuid ()))return true; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_BACKUPGID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_CIFS_BACKUPGID ) {if (in_group_p (cifs_sb->ctx->backupgid))return true; }
@@ -1310,7 +1310,7 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)convert_delimiter (cifs_sb->prepath,CIFS_DIR_SEP (cifs_sb)); } - cifs_sb->mnt_cifs_flags |=CIFS_MOUNT_USE_PREFIX_PATH ; +atomic_or (CIFS_MOUNT_USE_PREFIX_PATH , &cifs_sb->mnt_cifs_flags);return 0 ; }
@@ -1339,7 +1339,7 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid,* look up or tcon is not DFS. */ if (strlen (full_path) <2 || !cifs_sb || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_DFS ) || + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_DFS ) || !is_tcon_dfs (tcon))return 0 ;
fs/smb/client/readdir.c +8 -8
@@ -121,7 +121,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,* want to clobber the existing one with the one that * the readdir code created. */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM )) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM )) fattr->cf_uniqueid =CIFS_I (inode)->uniqueid;/*
@@ -215,11 +215,11 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)* may look wrong since the inodes may not have timed out by the time * "ls" does a stat() call on them. */ -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_ACL ) || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID )) +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_CIFS_ACL ) || + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MODE_FROM_SID )) fattr->cf_flags |=CIFS_FATTR_NEED_REVAL ; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL && +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL && fattr->cf_cifsattrs &ATTR_SYSTEM ) {if (fattr->cf_eof ==0 ) { fattr->cf_mode &= ~S_IFMT ;
@@ -395,7 +395,7 @@ _initiate_cifs_search(const unsigned int xid, struct file *file,else if ((tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find) ==0 ) { cifsFile->srch_inf.info_level =SMB_FIND_FILE_INFO_STANDARD ; - }else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM ) { + }else if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM ) { cifsFile->srch_inf.info_level =SMB_FIND_FILE_ID_FULL_DIR_INFO ; }else /* not srvinos - BB fixme add check for backlevel? */ { cifsFile->srch_inf.info_level =SMB_FIND_FILE_FULL_DIRECTORY_INFO ;
@@ -412,7 +412,7 @@ _initiate_cifs_search(const unsigned int xid, struct file *file,if (rc ==0 ) { cifsFile->invalidHandle = false; }else if ((rc == -EOPNOTSUPP ) && - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM )) { + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM )) {cifs_autodisable_serverino (cifs_sb); goto ffirst_retry; }
@@ -1005,14 +1005,14 @@ static int cifs_filldir(char *find_entry, struct file *file,break ; } -if (de.ino && (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM )) { +if (de.ino && (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM )) { fattr.cf_uniqueid = de.ino; }else { fattr.cf_uniqueid =iunique (sb,ROOT_I );cifs_autodisable_serverino (cifs_sb); } -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MF_SYMLINKS ) && +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MF_SYMLINKS ) &&couldbe_mf_symlink (&fattr))/* * trying to get the type and mode can be slow,
fs/smb/client/reparse.h +2 -2
@@ -32,7 +32,7 @@ static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb, {u32 uid =le32_to_cpu (*(__le32 *)ptr); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_OVERR_UID ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_OVERR_UID )return cifs_sb->ctx->linux_uid;return make_kuid (current_user_ns (), uid); }
@@ -42,7 +42,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, {u32 gid =le32_to_cpu (*(__le32 *)ptr); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_OVERR_GID ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_OVERR_GID )return cifs_sb->ctx->linux_gid;return make_kgid (current_user_ns (), gid); }
fs/smb/client/smb1ops.c +2 -2
@@ -1323,7 +1323,7 @@ cifs_make_node(unsigned int xid, struct inode *inode, .mtime = NO_CHANGE_64, .device = dev, }; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SET_UID ) { args.uid =current_fsuid (); args.gid =current_fsgid (); }else {
@@ -1349,7 +1349,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,* supports block and char device, socket & fifo, * and was used by default in earlier versions of Windows */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL )) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL ))return -EPERM ;return cifs_sfu_make_node (xid, inode, dentry, tcon, full_path, mode, dev);
fs/smb/client/smb2misc.c +2 -2
@@ -495,9 +495,9 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)__le16 *to;int map_type; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SFM_CHR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MAP_SFM_CHR ) map_type =SFM_MAP_UNI_RSVD ; -else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SPECIAL_CHR ) +else if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MAP_SPECIAL_CHR ) map_type =SFU_MAP_UNI_RSVD ;else map_type =NO_MAP_UNI_RSVD ;
fs/smb/client/smb2ops.c +2 -2
@@ -1011,7 +1011,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, rc = -EREMOTE ; }if (rc == -EREMOTE &&IS_ENABLED (CONFIG_CIFS_DFS_UPCALL ) && cifs_sb && - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_DFS )) + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_DFS )) rc = -EOPNOTSUPP ; goto out; }
@@ -5321,7 +5321,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,* supports block and char device, socket & fifo, * and was used by default in earlier versions of Windows */ -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL ) { rc =cifs_sfu_make_node (xid, inode, dentry, tcon, full_path, mode, dev); }else {
fs/smb/client/smb2pdu.c +2 -2
@@ -3127,7 +3127,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,bool set_mode;bool set_owner; -if ((oparms->cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID ) && +if ((cifs_sb_flags (oparms->cifs_sb) &CIFS_MOUNT_MODE_FROM_SID ) && (oparms->mode !=ACL_NO_MODE )) set_mode = true;else {
@@ -3135,7 +3135,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, oparms->mode =ACL_NO_MODE ; } -if (oparms->cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UID_FROM_ACL ) +if (cifs_sb_flags (oparms->cifs_sb) &CIFS_MOUNT_UID_FROM_ACL ) set_owner = true;else set_owner = false;
fs/smb/client/xattr.c +3 -3
@@ -147,7 +147,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,break ; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_XATTR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_XATTR ) goto out;if (pTcon->ses->server->ops->set_EA) {
@@ -299,7 +299,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,break ; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_XATTR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_XATTR ) goto out;if (pTcon->ses->server->ops->query_all_EAs)
@@ -373,7 +373,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)if (unlikely (cifs_forced_shutdown (cifs_sb)))return -EIO ; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_XATTR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_XATTR )return -EOPNOTSUPP ; tlink =cifs_sb_tlink (cifs_sb);
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
@@ -3118,9 +3118,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 ) {
@@ -3309,8 +3313,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
Re: [PATCH 6.12.y 1/5] cifs: Scripted clean up fs/smb/client/cifs_unicode.h
In reply to Sasha LevinQuoted 166 lines · Sasha Levin
From: David Howells <[email protected]>
[ Upstream commit
696ca7d95658224ba807813101d0d5714d1d8aa4]Remove externs, correct argument names and reformat declarations.
Signed-off-by David Howells <[email protected]>cc Steve French <[email protected]>cc Paulo Alcantara <[email protected]>cc Enzo Matsumiya <[email protected]>Acked-by Enzo Matsumiya <[email protected]>Signed-off-by Steve French <[email protected]>Stable-dep-of:
b8e5dc4f95e5("smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions")Signed-off-by Sasha Levin <[email protected]>--- fs/smb/client/cifs_unicode.h | 17 +++++++++-------- fs/smb/client/inode.c | 26 ++++++++++++++------------ 2 files changed, 23 insertions(+), 20 deletions(-)fs/smb/client/cifs_unicode.h +9
-8@@ -56,19 +56,20 @@#ifdef __KERNEL__int cifs_from_utf16 (char *to,const __le16 *from,int tolen,int fromlen, -const struct nls_table *cp,int map_type); +const struct nls_table *codepage,int map_type);int cifs_utf16_bytes (const __le16 *from,int maxbytes,const struct nls_table *codepage); -int cifs_strtoUTF16 (__le16 *,const char *,int ,const struct nls_table *); +int cifs_strtoUTF16 (__le16 *to,const char *from,int len, +const struct nls_table *codepage);char *cifs_strndup_from_utf16 (const char *src,const int maxlen,const bool is_unicode,const struct nls_table *codepage); -extern int cifsConvertToUTF16 (__le16 *target,const char *source,int maxlen, -const struct nls_table *cp,int mapChars); -extern int cifs_remap (struct cifs_sb_info *cifs_sb); -extern __le16 *cifs_strndup_to_utf16 (const char *src,const int maxlen, -int *utf16_len,const struct nls_table *cp, -int remap); +int cifsConvertToUTF16 (__le16 *target,const char *source,int srclen, +const struct nls_table *cp,int map_chars); +int cifs_remap (struct cifs_sb_info *cifs_sb); +__le16 *cifs_strndup_to_utf16 (const char *src,const int maxlen, +int *utf16_len,const struct nls_table *cp, +int remap);#endif wchar_t cifs_toupper (wchar_t in);fs/smb/client/inode.c +14
-12@@ -3115,13 +3115,14 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) rc =cifs_set_file_size (inode, attrs, xid, full_path, direntry);if (rc !=0 ) goto out; + 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 ; - args =kmalloc (sizeof (*args),GFP_KERNEL ); + args =kmalloc_obj (*args);if (args ==NULL ) { rc = -ENOMEM ; goto out;@@ -3217,6 +3218,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)struct inode *inode =d_inode (direntry);struct cifs_sb_info *cifs_sb =CIFS_SB (inode->i_sb);struct cifsInodeInfo *cifsInode =CIFS_I (inode); +unsigned int sbflags = cifs_sb->mnt_cifs_flags;struct cifsFileInfo *wfile;struct cifs_tcon *tcon;const char *full_path;@@ -3231,7 +3233,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);@@ -3265,7 +3267,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) rc =0 ;if ((attrs->ia_valid &ATTR_MTIME ) && - !(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOSSYNC )) { + !(sbflags &CIFS_MOUNT_NOSSYNC )) { rc =cifs_get_writable_file (cifsInode,FIND_WR_ANY , &wfile);if (!rc) { tcon =tlink_tcon (wfile->tlink);@@ -3291,8 +3293,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)if (attrs->ia_valid &ATTR_GID ) gid = attrs->ia_gid; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_ACL ) || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID )) { +if ((sbflags &CIFS_MOUNT_CIFS_ACL ) || + (sbflags &CIFS_MOUNT_MODE_FROM_SID )) {if (uid_valid (uid) ||gid_valid (gid)) { mode =NO_CHANGE_64 ; rc = id_mode_to_cifs_acl(inode, full_path, &mode,@@ -3303,9 +3305,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 ))@@ -3314,8 +3316,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)if (attrs->ia_valid &ATTR_MODE ) { mode = attrs->ia_mode; rc =0 ; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_ACL ) || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID ) || +if ((sbflags &CIFS_MOUNT_CIFS_ACL ) || + (sbflags &CIFS_MOUNT_MODE_FROM_SID ) || posix) { rc =id_mode_to_cifs_acl (inode, full_path, &mode,INVALID_UID ,INVALID_GID );@@ -3338,7 +3340,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) dosattr = cifsInode->cifsAttrs |ATTR_READONLY ;/* fix up mode if we're not using dynperm */ -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM ) ==0 ) +if ((sbflags &CIFS_MOUNT_DYNPERM ) ==0 ) attrs->ia_mode = inode->i_mode & ~S_IWUGO ; }else if ((mode &S_IWUGO ) && (cifsInode->cifsAttrs &ATTR_READONLY )) {@@ -3349,7 +3351,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) dosattr |=ATTR_NORMAL ;/* reset local inode permissions to normal */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM )) { +if (!(sbflags &CIFS_MOUNT_DYNPERM )) { attrs->ia_mode &= ~(S_IALLUGO );if (S_ISDIR (inode->i_mode)) attrs->ia_mode |=@@ -3358,7 +3360,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) attrs->ia_mode |= cifs_sb->ctx->file_mode; } - }else if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM )) { + }else if (!(sbflags &CIFS_MOUNT_DYNPERM )) {/* ignore mode change - ATTR_READONLY hasn't changed */ attrs->ia_valid &= ~ATTR_MODE ; }Signature · 1 line
2.53.0
The two cifs series backports conflicts, so I'll drop both :(