From 5865985416ebb5a0c198a819a098b5cc300ac8a4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 5 Jun 2020 17:19:46 -0500 Subject: smb3: extend fscache mount volume coherency check It is better to check volume id and creation time, not just the root inode number to verify if the volume has changed when remounting. Reviewed-by: David Howells Signed-off-by: Steve French --- fs/cifs/cache.c | 9 ++------- fs/cifs/fscache.c | 17 +++++++++++++++-- fs/cifs/fscache.h | 9 +++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index b7420e605b28..0f2adecb94f2 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -53,13 +53,6 @@ const struct fscache_cookie_def cifs_fscache_server_index_def = { .type = FSCACHE_COOKIE_TYPE_INDEX, }; -/* - * Auxiliary data attached to CIFS superblock within the cache - */ -struct cifs_fscache_super_auxdata { - u64 resource_id; /* unique server resource id */ -}; - char *extract_sharename(const char *treename) { const char *src; @@ -98,6 +91,8 @@ fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, memset(&auxdata, 0, sizeof(auxdata)); auxdata.resource_id = tcon->resource_id; + auxdata.vol_create_time = tcon->vol_create_time; + auxdata.vol_serial_number = tcon->vol_serial_number; if (memcmp(data, &auxdata, datalen) != 0) return FSCACHE_CHECKAUX_OBSOLETE; diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index ea6ace9c2417..da688185403c 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -96,6 +96,7 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) { struct TCP_Server_Info *server = tcon->ses->server; char *sharename; + struct cifs_fscache_super_auxdata auxdata; sharename = extract_sharename(tcon->treeName); if (IS_ERR(sharename)) { @@ -104,11 +105,16 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) return; } + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.resource_id = tcon->resource_id; + auxdata.vol_create_time = tcon->vol_create_time; + auxdata.vol_serial_number = tcon->vol_serial_number; + tcon->fscache = fscache_acquire_cookie(server->fscache, &cifs_fscache_super_index_def, sharename, strlen(sharename), - &tcon->resource_id, sizeof(tcon->resource_id), + &auxdata, sizeof(auxdata), tcon, 0, true); kfree(sharename); cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", @@ -117,8 +123,15 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) { + struct cifs_fscache_super_auxdata auxdata; + + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.resource_id = tcon->resource_id; + auxdata.vol_create_time = tcon->vol_create_time; + auxdata.vol_serial_number = tcon->vol_serial_number; + cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); - fscache_relinquish_cookie(tcon->fscache, &tcon->resource_id, false); + fscache_relinquish_cookie(tcon->fscache, &auxdata, false); tcon->fscache = NULL; } diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 8c0862e41306..1091633d2adb 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -27,6 +27,15 @@ #ifdef CONFIG_CIFS_FSCACHE +/* + * Auxiliary data attached to CIFS superblock within the cache + */ +struct cifs_fscache_super_auxdata { + u64 resource_id; /* unique server resource id */ + __le64 vol_create_time; + u32 vol_serial_number; +} __packed; + /* * Auxiliary data attached to CIFS inode within the cache */ -- cgit v1.2.3 From 0b0430c6a10a22813e3d40c5658ae644acda4303 Mon Sep 17 00:00:00 2001 From: Kenneth D'souza Date: Tue, 9 Jun 2020 10:12:10 +0530 Subject: cifs: Add get_security_type_str function to return sec type. This code is more organized and robust. Signed-off-by: Kenneth D'souza Signed-off-by: Roberto Bergantinos Corpas Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 4 +--- fs/cifs/cifsglob.h | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 3ad1a98fd567..fc98b97b396a 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -221,8 +221,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) struct cifs_ses *ses; struct cifs_tcon *tcon; int i, j; - const char *security_types[] = {"Unspecified", "LANMAN", "NTLM", - "NTLMv2", "RawNTLMSSP", "Kerberos"}; seq_puts(m, "Display Internal CIFS Data Structures for Debugging\n" @@ -379,7 +377,7 @@ skip_rdma: } seq_printf(m,"Security type: %s\n", - security_types[server->ops->select_sectype(server, ses->sectype)]); + get_security_type_str(server->ops->select_sectype(server, ses->sectype))); if (server->rdma) seq_printf(m, "RDMA\n\t"); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e133bb3e172f..fad37d61910a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -2008,6 +2008,24 @@ extern struct smb_version_values smb302_values; extern struct smb_version_operations smb311_operations; extern struct smb_version_values smb311_values; +static inline char *get_security_type_str(enum securityEnum sectype) +{ + switch (sectype) { + case RawNTLMSSP: + return "RawNTLMSSP"; + case Kerberos: + return "Kerberos"; + case NTLMv2: + return "NTLMv2"; + case NTLM: + return "NTLM"; + case LANMAN: + return "LANMAN"; + default: + return "Unknown"; + } +} + static inline bool is_smb1_server(struct TCP_Server_Info *server) { return strcmp(server->vals->version_string, SMB1_VERSION_STRING) == 0; -- cgit v1.2.3 From 7866c177a03b18be3d83175014c643546e5b53c6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 9 Jun 2020 19:50:40 -0500 Subject: smb3: fix typo in mount options displayed in /proc/mounts Missing the final 's' in "max_channels" mount option when displayed in /proc/mounts (or by mount command) CC: Stable Signed-off-by: Steve French Reviewed-by: Shyam Prasad N --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 889f9c71049b..0fb99d25e8a8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -623,7 +623,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); if (tcon->ses->chan_max > 1) - seq_printf(s, ",multichannel,max_channel=%zu", + seq_printf(s, ",multichannel,max_channels=%zu", tcon->ses->chan_max); return 0; -- cgit v1.2.3 From ebf57440ec59a36e1fc5fe91e31d66ae0d1662d0 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 11 Jun 2020 11:21:19 +0900 Subject: smb3: add indatalen that can be a non-zero value to calculation of credit charge in smb2 ioctl Some of tests in xfstests failed with cifsd kernel server since commit e80ddeb2f70e. cifsd kernel server validates credit charge from client by calculating it base on max((InputCount + OutputCount) and (MaxInputResponse + MaxOutputResponse)) according to specification. MS-SMB2 specification describe credit charge calculation of smb2 ioctl : If Connection.SupportsMultiCredit is TRUE, the server MUST validate CreditCharge based on the maximum of (InputCount + OutputCount) and (MaxInputResponse + MaxOutputResponse), as specified in section 3.3.5.2.5. If the validation fails, it MUST fail the IOCTL request with STATUS_INVALID_PARAMETER. This patch add indatalen that can be a non-zero value to calculation of credit charge in SMB2_ioctl_init(). Fixes: e80ddeb2f70e ("smb3: fix incorrect number of credits when ioctl MaxOutputResponse > 64K") Cc: Stable Reviewed-by: Aurelien Aptel Cc: Steve French Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/cifs/smb2pdu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ded96b529a4d..3f232c8da390 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2973,7 +2973,9 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, * response size smaller. */ req->MaxOutputResponse = cpu_to_le32(max_response_size); - req->sync_hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(max_response_size, SMB2_MAX_BUFFER_SIZE)); + req->sync_hdr.CreditCharge = + cpu_to_le16(DIV_ROUND_UP(max(indatalen, max_response_size), + SMB2_MAX_BUFFER_SIZE)); if (is_fsctl) req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); else -- cgit v1.2.3 From 6a5f6592a0b606eac3147f786c958f1696c337f3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 11 Jun 2020 19:25:47 -0500 Subject: SMB311: Add support for query info using posix extensions (level 100) Adds support for better query info on dentry revalidation (using the SMB3.1.1 POSIX extensions level 100). Followon patch will add support for translating the UID/GID from the SID and also will add support for using the posix query info on lookup. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Reviewed-by: Aurelien Aptel --- fs/cifs/cifsproto.h | 2 + fs/cifs/inode.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/smb2glob.h | 1 + fs/cifs/smb2inode.c | 108 ++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 27 +++++++- fs/cifs/smb2proto.h | 4 ++ 6 files changed, 316 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index bd92070ca30c..b603da73f4f5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -198,6 +198,8 @@ extern struct inode *cifs_iget(struct super_block *sb, extern int cifs_get_inode_info(struct inode **inode, const char *full_path, FILE_ALL_INFO *data, struct super_block *sb, int xid, const struct cifs_fid *fid); +extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path, + struct super_block *sb, unsigned int xid); extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, struct super_block *sb, unsigned int xid); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 5072bcaf4be1..c367195bdb08 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -32,6 +32,7 @@ #include "cifspdu.h" #include "cifsglob.h" #include "cifsproto.h" +#include "smb2proto.h" #include "cifs_debug.h" #include "cifs_fs_sb.h" #include "cifs_unicode.h" @@ -595,6 +596,62 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, #endif } +/* Fill a cifs_fattr struct with info from POSIX info struct */ +static void +smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *info, + struct super_block *sb, bool adjust_tz, bool symlink) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + + memset(fattr, 0, sizeof(*fattr)); + + /* no fattr->flags to set */ + fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); + fattr->cf_uniqueid = le64_to_cpu(info->Inode); + + if (info->LastAccessTime) + fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); + else + ktime_get_coarse_real_ts64(&fattr->cf_atime); + + fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); + fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); + + if (adjust_tz) { + fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; + fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; + } + + fattr->cf_eof = le64_to_cpu(info->EndOfFile); + fattr->cf_bytes = le64_to_cpu(info->AllocationSize); + fattr->cf_createtime = le64_to_cpu(info->CreationTime); + + fattr->cf_nlink = le32_to_cpu(info->HardLinks); + fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); + /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ + /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ + + if (symlink) { + fattr->cf_mode |= S_IFLNK; + fattr->cf_dtype = DT_LNK; + } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { + fattr->cf_mode |= S_IFDIR; + fattr->cf_dtype = DT_DIR; + } else { /* file */ + fattr->cf_mode |= S_IFREG; + fattr->cf_dtype = DT_REG; + } + /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ + + fattr->cf_uid = cifs_sb->mnt_uid; /* TODO: map uid and gid from SID */ + fattr->cf_gid = cifs_sb->mnt_gid; + + cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", + fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); +} + + /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ static void cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, @@ -1023,6 +1080,121 @@ out: return rc; } +int +smb311_posix_get_inode_info(struct inode **inode, + const char *full_path, + struct super_block *sb, unsigned int xid) +{ + struct cifs_tcon *tcon; + struct TCP_Server_Info *server; + struct tcon_link *tlink; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + bool adjust_tz = false; + struct cifs_fattr fattr = {0}; + bool symlink = false; + struct smb311_posix_qinfo *data = NULL; + int rc = 0; + int tmprc = 0; + + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + server = tcon->ses->server; + + /* + * 1. Fetch file metadata + */ + + if (is_inode_cache_good(*inode)) { + cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); + goto out; + } + data = kmalloc(sizeof(struct smb311_posix_qinfo), GFP_KERNEL); + if (!data) { + rc = -ENOMEM; + goto out; + } + + rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, + full_path, data, + &adjust_tz, &symlink); + + /* + * 2. Convert it to internal cifs metadata (fattr) + */ + + switch (rc) { + case 0: + smb311_posix_info_to_fattr(&fattr, data, sb, adjust_tz, symlink); + break; + case -EREMOTE: + /* DFS link, no metadata available on this server */ + cifs_create_dfs_fattr(&fattr, sb); + rc = 0; + break; + case -EACCES: + /* + * For SMB2 and later the backup intent flag + * is already sent if needed on open and there + * is no path based FindFirst operation to use + * to retry with so nothing we can do, bail out + */ + goto out; + default: + cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); + goto out; + } + + + /* + * 4. Tweak fattr based on mount options + */ + + /* check for Minshall+French symlinks */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { + tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, + full_path); + if (tmprc) + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); + } + + /* + * 5. Update inode with final fattr data + */ + + if (!*inode) { + *inode = cifs_iget(sb, &fattr); + if (!*inode) + rc = -ENOMEM; + } else { + /* we already have inode, update it */ + + /* if uniqueid is different, return error */ + if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && + CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { + CIFS_I(*inode)->time = 0; /* force reval */ + rc = -ESTALE; + goto out; + } + + /* if filetype is different, return error */ + if (unlikely(((*inode)->i_mode & S_IFMT) != + (fattr.cf_mode & S_IFMT))) { + CIFS_I(*inode)->time = 0; /* force reval */ + rc = -ESTALE; + goto out; + } + + cifs_fattr_to_inode(*inode, &fattr); + } +out: + cifs_put_tlink(tlink); + kfree(data); + return rc; +} + + static const struct inode_operations cifs_ipc_inode_ops = { .lookup = cifs_lookup, }; @@ -2114,7 +2286,9 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) dentry, cifs_get_time(dentry), jiffies); again: - if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) + if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) + rc = smb311_posix_get_inode_info(&inode, full_path, sb, xid); + else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index dd10f0ce4cd5..cf20f0b5d836 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -45,6 +45,7 @@ #define SMB2_OP_HARDLINK 8 #define SMB2_OP_SET_EOF 9 #define SMB2_OP_RMDIR 10 +#define SMB2_OP_POSIX_QUERY_INFO 11 /* Used when constructing chained read requests. */ #define CHAINED_REQUEST 1 diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 0a116fc490a9..5154956311f0 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -160,6 +160,41 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, } } + if (rc) + goto finished; + num_rqst++; + trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid, + full_path); + break; + case SMB2_OP_POSIX_QUERY_INFO: + rqst[num_rqst].rq_iov = &vars->qi_iov[0]; + rqst[num_rqst].rq_nvec = 1; + + if (cfile) + rc = SMB2_query_info_init(tcon, server, + &rqst[num_rqst], + cfile->fid.persistent_fid, + cfile->fid.volatile_fid, + SMB_FIND_FILE_POSIX_INFO, + SMB2_O_INFO_FILE, 0, + /* TBD: fix following to allow for longer SIDs */ + sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + + (sizeof(struct cifs_sid) * 2), 0, NULL); + else { + rc = SMB2_query_info_init(tcon, server, + &rqst[num_rqst], + COMPOUND_FID, + COMPOUND_FID, + SMB_FIND_FILE_POSIX_INFO, + SMB2_O_INFO_FILE, 0, + sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + + (sizeof(struct cifs_sid) * 2), 0, NULL); + if (!rc) { + smb2_set_next_command(tcon, &rqst[num_rqst]); + smb2_set_related(&rqst[num_rqst]); + } + } + if (rc) goto finished; num_rqst++; @@ -379,6 +414,26 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, trace_smb3_query_info_compound_done(xid, ses->Suid, tcon->tid); break; + case SMB2_OP_POSIX_QUERY_INFO: + if (rc == 0) { + qi_rsp = (struct smb2_query_info_rsp *) + rsp_iov[1].iov_base; + rc = smb2_validate_and_copy_iov( + le16_to_cpu(qi_rsp->OutputBufferOffset), + le32_to_cpu(qi_rsp->OutputBufferLength), + &rsp_iov[1], sizeof(struct smb311_posix_qinfo) /* add SIDs */, ptr); + } + if (rqst[1].rq_iov) + SMB2_query_info_free(&rqst[1]); + if (rqst[2].rq_iov) + SMB2_close_free(&rqst[2]); + if (rc) + trace_smb3_query_info_compound_err(xid, ses->Suid, + tcon->tid, rc); + else + trace_smb3_query_info_compound_done(xid, ses->Suid, + tcon->tid); + break; case SMB2_OP_DELETE: if (rc) trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); @@ -512,6 +567,59 @@ out: return rc; } + +int +smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const char *full_path, + struct smb311_posix_qinfo *data, bool *adjust_tz, bool *symlink) +{ + int rc; + __u32 create_options = 0; + struct cifsFileInfo *cfile; + struct smb311_posix_qinfo *smb2_data; + + *adjust_tz = false; + *symlink = false; + + /* BB TODO: Make struct larger when add support for parsing owner SIDs */ + smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo), + GFP_KERNEL); + if (smb2_data == NULL) + return -ENOMEM; + + /* + * BB TODO: Add support for using the cached root handle. + * Create SMB2_query_posix_info worker function to do non-compounded query + * when we already have an open file handle for this. For now this is fast enough + * (always using the compounded version). + */ + + cifs_get_readable_path(tcon, full_path, &cfile); + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, + FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, + ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile); + if (rc == -EOPNOTSUPP) { + /* BB TODO: When support for special files added to Samba re-verify this path */ + *symlink = true; + create_options |= OPEN_REPARSE_POINT; + + /* Failed on a symbolic link - query a reparse point info */ + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, + FILE_READ_ATTRIBUTES, FILE_OPEN, + create_options, ACL_NO_MODE, + smb2_data, SMB2_OP_POSIX_QUERY_INFO, NULL); + } + if (rc) + goto out; + + /* TODO: will need to allow for the 2 SIDs when add support for getting owner UID/GID */ + memcpy(data, smb2_data, sizeof(struct smb311_posix_qinfo)); + +out: + kfree(smb2_data); + return rc; +} + int smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, struct cifs_tcon *tcon, const char *name, diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 3b0e6acf9d7d..236814d61248 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -1653,7 +1653,7 @@ struct create_posix_rsp { } __packed; /* - * SMB2-only POSIX info level + * SMB2-only POSIX info level for query dir * * See posix_info_sid_size(), posix_info_extra_size() and * posix_info_parse() to help with the handling of this struct. @@ -1683,6 +1683,31 @@ struct smb2_posix_info { */ } __packed; +/* Level 100 query info */ +struct smb311_posix_qinfo { + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 DosAttributes; + __le64 Inode; + __le32 DeviceId; + __le32 Zero; + /* beginning of POSIX Create Context Response */ + __le32 HardLinks; + __le32 ReparseTag; + __le32 Mode; + u8 Sids[]; + /* + * var sized owner SID + * var sized group SID + * le32 filenamelength + * u8 filename[] + */ +} __packed; + /* * Parsed version of the above struct. Allows direct access to the * variable length fields diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 71ba74792c9e..a5c6da59847e 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -289,6 +289,10 @@ extern int smb2_query_info_compound(const unsigned int xid, u32 class, u32 type, u32 output_len, struct kvec *rsp, int *buftype, struct cifs_sb_info *cifs_sb); +/* query path info from the server using SMB311 POSIX extensions*/ +extern int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *sb, const char *path, struct smb311_posix_qinfo *qinf, + bool *adjust_tx, bool *symlink); int posix_info_parse(const void *beg, const void *end, struct smb2_posix_info_parsed *out); int posix_info_sid_size(const void *beg, const void *end); -- cgit v1.2.3 From b1bc1874b885683df5da9d9548ca66dfc0e407f2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 11 Jun 2020 20:23:38 -0500 Subject: smb311: Add support for SMB311 query info (non-compounded) Add worker function for non-compounded SMB3.1.1 POSIX Extensions query info. This is needed for revalidate of root (cached) directory for example. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Reviewed-by: Aurelien Aptel --- fs/cifs/smb2pdu.c | 13 +++++++++++++ fs/cifs/smb2proto.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 3f232c8da390..3f5c3dd57c86 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -3458,6 +3458,19 @@ int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, NULL); } +int +SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen) +{ + size_t output_len = sizeof(struct smb311_posix_qinfo *) + + (sizeof(struct cifs_sid) * 2) + (PATH_MAX * 2); + *plen = 0; + + return query_info(xid, tcon, persistent_fid, volatile_fid, + SMB_FIND_FILE_POSIX_INFO, SMB2_O_INFO_FILE, 0, + output_len, sizeof(struct smb311_posix_qinfo), (void **)&data, plen); +} + int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index a5c6da59847e..2f8ecbf54214 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -182,6 +182,8 @@ extern int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst, struct TCP_Server_Info *server, u64 persistent_file_id, u64 volatile_file_id); extern void SMB2_flush_free(struct smb_rqst *rqst); +extern int SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen); extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct smb2_file_all_info *data); -- cgit v1.2.3 From 790434ff9848a4d44f067a6a5416b49a2db89a59 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 11 Jun 2020 22:28:49 -0500 Subject: smb311: Add support for lookup with posix extensions query info Improve support for lookup when using SMB3.1.1 posix mounts. Use new info level 100 (posix query info) Signed-off-by: Steve French Reviewed-by: Aurelien Aptel --- fs/cifs/dir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 36e7b2fd2190..aa61ffab8ab8 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -700,7 +700,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, d_inode(direntry)); - if (pTcon->unix_ext) { + if (pTcon->posix_extensions) + rc = smb311_posix_get_inode_info(&newInode, full_path, parent_dir_inode->i_sb, xid); + else if (pTcon->unix_ext) { rc = cifs_get_inode_info_unix(&newInode, full_path, parent_dir_inode->i_sb, xid); } else { -- cgit v1.2.3 From d313852d7ad044476df7f640801aac17080e0521 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 11 Jun 2020 22:43:01 -0500 Subject: smb311: add support for using info level for posix extensions query Adds calls to the newer info level for query info using SMB3.1.1 posix extensions. The remaining two places that call the older query info (non-SMB3.1.1 POSIX) require passing in the fid and can be updated in a later patch. Signed-off-by: Steve French Reviewed-by: Aurelien Aptel --- fs/cifs/dir.c | 1 + fs/cifs/file.c | 5 ++++- fs/cifs/inode.c | 9 +++++++-- fs/cifs/link.c | 4 +++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index aa61ffab8ab8..398c1eef7190 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -411,6 +411,7 @@ cifs_create_get_file_info: rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); else { + /* TODO: Add support for calling POSIX query info here, but passing in fid */ rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, xid, fid); if (newinode) { diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8277859d12a3..4fe757cfc360 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -243,6 +243,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, if (rc) goto out; + /* TODO: Add support for calling posix query info but with passing in fid */ if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, xid); @@ -800,7 +801,9 @@ reopen_success: if (!is_interrupt_error(rc)) mapping_set_error(inode->i_mapping, rc); - if (tcon->unix_ext) + if (tcon->posix_extensions) + rc = smb311_posix_get_inode_info(&inode, full_path, inode->i_sb, xid); + else if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, xid); else diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index c367195bdb08..15ac63ff8ffc 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1333,7 +1333,10 @@ struct inode *cifs_root_iget(struct super_block *sb) } convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); - rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL); + if (tcon->posix_extensions) + rc = smb311_posix_get_inode_info(&inode, path, sb, xid); + else + rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL); iget_no_retry: if (!inode) { @@ -1689,7 +1692,9 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, int rc = 0; struct inode *inode = NULL; - if (tcon->unix_ext) + if (tcon->posix_extensions) + rc = smb311_posix_get_inode_info(&inode, full_path, parent->i_sb, xid); + else if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb, xid); else diff --git a/fs/cifs/link.c b/fs/cifs/link.c index c381d2d03ef6..94dab4309fbb 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -701,7 +701,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) cifs_sb_target->local_nls); */ if (rc == 0) { - if (pTcon->unix_ext) + if (pTcon->posix_extensions) + rc = smb311_posix_get_inode_info(&newinode, full_path, inode->i_sb, xid); + else if (pTcon->unix_ext) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); else -- cgit v1.2.3 From e4bd7c4a8d2a8471d821dd29919378d1b8567091 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 11 Jun 2020 23:02:33 -0500 Subject: smb311: Add tracepoints for new compound posix query info Add dynamic tracepoints for new SMB3.1.1. posix extensions query info level (100) Signed-off-by: Steve French Reviewed-by: Aurelien Aptel --- fs/cifs/smb2inode.c | 9 +++------ fs/cifs/trace.h | 3 +++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 5154956311f0..b9db73687eaa 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -198,8 +198,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, if (rc) goto finished; num_rqst++; - trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid, - full_path); + trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path); break; case SMB2_OP_DELETE: trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); @@ -428,11 +427,9 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, if (rqst[2].rq_iov) SMB2_close_free(&rqst[2]); if (rc) - trace_smb3_query_info_compound_err(xid, ses->Suid, - tcon->tid, rc); + trace_smb3_posix_query_info_compound_err(xid, ses->Suid, tcon->tid, rc); else - trace_smb3_query_info_compound_done(xid, ses->Suid, - tcon->tid); + trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid); break; case SMB2_OP_DELETE: if (rc) diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index 4cb0d5f7ce45..eef4b08c7208 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h @@ -318,6 +318,7 @@ DEFINE_EVENT(smb3_inf_compound_enter_class, smb3_##name, \ TP_ARGS(xid, tid, sesid, full_path)) DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_info_compound_enter); +DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(posix_query_info_compound_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(hardlink_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rename_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter); @@ -354,6 +355,7 @@ DEFINE_EVENT(smb3_inf_compound_done_class, smb3_##name, \ TP_ARGS(xid, tid, sesid)) DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_info_compound_done); +DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(posix_query_info_compound_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(hardlink_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rename_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done); @@ -395,6 +397,7 @@ DEFINE_EVENT(smb3_inf_compound_err_class, smb3_##name, \ TP_ARGS(xid, tid, sesid, rc)) DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_info_compound_err); +DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(posix_query_info_compound_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(hardlink_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rename_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err); -- cgit v1.2.3 From 975221eca5fbfdb4b6b1d17c9e540d4d7627ce18 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 12 Jun 2020 09:25:21 -0500 Subject: smb3: allow uid and gid owners to be set on create with idsfromsid mount option Currently idsfromsid mount option allows querying owner information from the special sids used to represent POSIX uids and gids but needed changes to populate the security descriptor context with the owner information when idsfromsid mount option was used. Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/cifsacl.c | 22 +++++++++++ fs/cifs/cifsacl.h | 15 +++++++ fs/cifs/cifsproto.h | 1 + fs/cifs/smb2pdu.c | 112 ++++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 129 insertions(+), 21 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index ae421634aa42..63aaa363ed14 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -849,6 +849,28 @@ unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode) return ace_size; } +unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace) +{ + int i; + unsigned int ace_size = 28; + + pntace->type = ACCESS_ALLOWED_ACE_TYPE; + pntace->flags = 0x0; + pntace->access_req = cpu_to_le32(GENERIC_ALL); + pntace->sid.num_subauth = 3; + pntace->sid.revision = 1; + for (i = 0; i < NUM_AUTHS; i++) + pntace->sid.authority[i] = sid_unix_NFS_users.authority[i]; + + pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0]; + pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1]; + pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val); + + /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ + pntace->size = cpu_to_le16(ace_size); + return ace_size; +} + static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid) { diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 21d7dee98d01..17562ea00e18 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -176,6 +176,21 @@ struct smb3_acl { __le16 Sbz2; /* MBZ */ } __packed; +/* + * Used to store the special 'NFS SIDs' used to persist the POSIX uid and gid + * See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx + */ +struct owner_sid { + u8 Revision; + u8 NumAuth; + u8 Authority[6]; + __le32 SubAuthorities[3]; +} __packed; + +struct owner_group_sids { + struct owner_sid owner; + struct owner_sid group; +} __packed; /* * Minimum security identifier can be one for system defined Users diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b603da73f4f5..7a836ec0438e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -222,6 +222,7 @@ extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, const char *, int); extern unsigned int setup_authusers_ACE(struct cifs_ace *pace); extern unsigned int setup_special_mode_ACE(struct cifs_ace *pace, __u64 nmode); +extern unsigned int setup_special_user_owner_ACE(struct cifs_ace *pace); extern void dequeue_mid(struct mid_q_entry *mid, bool malformed); extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 3f5c3dd57c86..c6b9e617343a 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2317,28 +2317,73 @@ add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp) return 0; } +/* See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */ +static void setup_owner_group_sids(char *buf) +{ + struct owner_group_sids *sids = (struct owner_group_sids *)buf; + + /* Populate the user ownership fields S-1-5-88-1 */ + sids->owner.Revision = 1; + sids->owner.NumAuth = 3; + sids->owner.Authority[5] = 5; + sids->owner.SubAuthorities[0] = cpu_to_le32(88); + sids->owner.SubAuthorities[1] = cpu_to_le32(1); + sids->owner.SubAuthorities[2] = cpu_to_le32(current_fsuid().val); + + /* Populate the group ownership fields S-1-5-88-2 */ + sids->group.Revision = 1; + sids->group.NumAuth = 3; + sids->group.Authority[5] = 5; + sids->group.SubAuthorities[0] = cpu_to_le32(88); + sids->group.SubAuthorities[1] = cpu_to_le32(2); + sids->group.SubAuthorities[2] = cpu_to_le32(current_fsgid().val); +} + /* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */ static struct crt_sd_ctxt * -create_sd_buf(umode_t mode, unsigned int *len) +create_sd_buf(umode_t mode, bool set_owner, unsigned int *len) { struct crt_sd_ctxt *buf; struct cifs_ace *pace; unsigned int sdlen, acelen; + unsigned int owner_offset = 0; + unsigned int group_offset = 0; + + *len = roundup(sizeof(struct crt_sd_ctxt) + (sizeof(struct cifs_ace) * 2), 8); + + if (set_owner) { + /* offset fields are from beginning of security descriptor not of create context */ + owner_offset = sizeof(struct smb3_acl) + (sizeof(struct cifs_ace) * 2); + + /* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */ + *len += sizeof(struct owner_group_sids); + } - *len = roundup(sizeof(struct crt_sd_ctxt) + sizeof(struct cifs_ace) * 2, - 8); buf = kzalloc(*len, GFP_KERNEL); if (buf == NULL) return buf; + if (set_owner) { + buf->sd.OffsetOwner = cpu_to_le32(owner_offset); + group_offset = owner_offset + sizeof(struct owner_sid); + buf->sd.OffsetGroup = cpu_to_le32(group_offset); + } else { + buf->sd.OffsetOwner = 0; + buf->sd.OffsetGroup = 0; + } + sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) + 2 * sizeof(struct cifs_ace); + if (set_owner) { + sdlen += sizeof(struct owner_group_sids); + setup_owner_group_sids(owner_offset + sizeof(struct create_context) + 8 /* name */ + + (char *)buf); + } buf->ccontext.DataOffset = cpu_to_le16(offsetof (struct crt_sd_ctxt, sd)); buf->ccontext.DataLength = cpu_to_le32(sdlen); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct crt_sd_ctxt, Name)); + buf->ccontext.NameOffset = cpu_to_le16(offsetof(struct crt_sd_ctxt, Name)); buf->ccontext.NameLength = cpu_to_le16(4); /* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */ buf->Name[0] = 'S'; @@ -2359,23 +2404,34 @@ create_sd_buf(umode_t mode, unsigned int *len) /* create one ACE to hold the mode embedded in reserved special SID */ pace = (struct cifs_ace *)(sizeof(struct crt_sd_ctxt) + (char *)buf); acelen = setup_special_mode_ACE(pace, (__u64)mode); + + if (set_owner) { + /* we do not need to reallocate buffer to add the two more ACEs. plenty of space */ + pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + (char *)buf)); + acelen += setup_special_user_owner_ACE(pace); + /* it does not appear necessary to add an ACE for the NFS group SID */ + buf->acl.AceCount = cpu_to_le16(3); + } else + buf->acl.AceCount = cpu_to_le16(2); + /* and one more ACE to allow access for authenticated users */ pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + (char *)buf)); acelen += setup_authusers_ACE(pace); + buf->acl.AclSize = cpu_to_le16(sizeof(struct cifs_acl) + acelen); - buf->acl.AceCount = cpu_to_le16(2); + return buf; } static int -add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) +add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner) { struct smb2_create_req *req = iov[0].iov_base; unsigned int num = *num_iovec; unsigned int len = 0; - iov[num].iov_base = create_sd_buf(mode, &len); + iov[num].iov_base = create_sd_buf(mode, set_owner, &len); if (iov[num].iov_base == NULL) return -ENOMEM; iov[num].iov_len = len; @@ -2764,21 +2820,35 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, return rc; } - if ((oparms->disposition != FILE_OPEN) && - (oparms->cifs_sb) && - (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) && - (oparms->mode != ACL_NO_MODE)) { - if (n_iov > 2) { - struct create_context *ccontext = - (struct create_context *)iov[n_iov-1].iov_base; - ccontext->Next = - cpu_to_le32(iov[n_iov-1].iov_len); + if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) { + bool set_mode; + bool set_owner; + + if ((oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) && + (oparms->mode != ACL_NO_MODE)) + set_mode = true; + else { + set_mode = false; + oparms->mode = ACL_NO_MODE; } - cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode); - rc = add_sd_context(iov, &n_iov, oparms->mode); - if (rc) - return rc; + if (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) + set_owner = true; + else + set_owner = false; + + if (set_owner | set_mode) { + if (n_iov > 2) { + struct create_context *ccontext = + (struct create_context *)iov[n_iov-1].iov_base; + ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len); + } + + cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode); + rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner); + if (rc) + return rc; + } } if (n_iov > 2) { -- cgit v1.2.3 From a6603398278480aafef644d4c40549b5c5064c73 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 12 Jun 2020 10:36:37 -0500 Subject: cifs: fix chown and chgrp when idsfromsid mount option enabled idsfromsid was ignored in chown and chgrp causing it to fail when upcalls were not configured for lookup. idsfromsid allows mapping users when setting user or group ownership using "special SID" (reserved for this). Add support for chmod and chgrp when idsfromsid mount option is enabled. Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/cifsacl.c | 57 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 63aaa363ed14..6025d7fc7bbf 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -1000,7 +1000,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, /* Convert permission bits from mode to equivalent CIFS ACL */ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, - bool mode_from_sid, int *aclflag) + bool mode_from_sid, bool id_from_sid, int *aclflag) { int rc = 0; __u32 dacloffset; @@ -1041,12 +1041,23 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, if (!nowner_sid_ptr) return -ENOMEM; id = from_kuid(&init_user_ns, uid); - rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); - if (rc) { - cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n", - __func__, rc, id); - kfree(nowner_sid_ptr); - return rc; + if (id_from_sid) { + struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr; + /* Populate the user ownership fields S-1-5-88-1 */ + osid->Revision = 1; + osid->NumAuth = 3; + osid->Authority[5] = 5; + osid->SubAuthorities[0] = cpu_to_le32(88); + osid->SubAuthorities[1] = cpu_to_le32(1); + osid->SubAuthorities[2] = cpu_to_le32(id); + } else { /* lookup sid with upcall */ + rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); + if (rc) { + cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n", + __func__, rc, id); + kfree(nowner_sid_ptr); + return rc; + } } cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr); kfree(nowner_sid_ptr); @@ -1061,12 +1072,23 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, if (!ngroup_sid_ptr) return -ENOMEM; id = from_kgid(&init_user_ns, gid); - rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); - if (rc) { - cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n", - __func__, rc, id); - kfree(ngroup_sid_ptr); - return rc; + if (id_from_sid) { + struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr; + /* Populate the group ownership fields S-1-5-88-2 */ + gsid->Revision = 1; + gsid->NumAuth = 3; + gsid->Authority[5] = 5; + gsid->SubAuthorities[0] = cpu_to_le32(88); + gsid->SubAuthorities[1] = cpu_to_le32(2); + gsid->SubAuthorities[2] = cpu_to_le32(id); + } else { /* lookup sid with upcall */ + rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); + if (rc) { + cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n", + __func__, rc, id); + kfree(ngroup_sid_ptr); + return rc; + } } cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr); kfree(ngroup_sid_ptr); @@ -1269,7 +1291,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct smb_version_operations *ops; - bool mode_from_sid; + bool mode_from_sid, id_from_sid; if (IS_ERR(tlink)) return PTR_ERR(tlink); @@ -1312,8 +1334,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, else mode_from_sid = false; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) + id_from_sid = true; + else + id_from_sid = false; + rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, - mode_from_sid, &aclflag); + mode_from_sid, id_from_sid, &aclflag); cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); -- cgit v1.2.3 From a7a519a4926214ba4161bc30109f4a8d69defb8d Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 12 Jun 2020 14:49:47 -0500 Subject: smb3: Add debug message for new file creation with idsfromsid mount option Pavel noticed that a debug message (disabled by default) in creating the security descriptor context could be useful for new file creation owner fields (as we already have for the mode) when using mount parm idsfromsid. [38120.392272] CIFS: FYI: owner S-1-5-88-1-0, group S-1-5-88-2-0 [38125.792637] CIFS: FYI: owner S-1-5-88-1-1000, group S-1-5-88-2-1000 Also cleans up a typo in a comment Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/inode.c | 4 ++-- fs/cifs/smb2pdu.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 15ac63ff8ffc..583f5e4008c2 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1148,7 +1148,7 @@ smb311_posix_get_inode_info(struct inode **inode, /* - * 4. Tweak fattr based on mount options + * 3. Tweak fattr based on mount options */ /* check for Minshall+French symlinks */ @@ -1160,7 +1160,7 @@ smb311_posix_get_inode_info(struct inode **inode, } /* - * 5. Update inode with final fattr data + * 4. Update inode with final fattr data */ if (!*inode) { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index c6b9e617343a..2f4cdd290c46 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2337,6 +2337,8 @@ static void setup_owner_group_sids(char *buf) sids->group.SubAuthorities[0] = cpu_to_le32(88); sids->group.SubAuthorities[1] = cpu_to_le32(2); sids->group.SubAuthorities[2] = cpu_to_le32(current_fsgid().val); + + cifs_dbg(FYI, "owner S-1-5-88-1-%d, group S-1-5-88-2-%d\n", current_fsuid().val, current_fsgid().val); } /* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */ -- cgit v1.2.3