diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-20 13:08:19 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-20 13:08:19 -0800 |
commit | 582888130702b86daa44ff6bfee585e4d4050ba0 (patch) | |
tree | 7502277e1f44379b8d1ded389ce9c92385b4c625 /fs | |
parent | 48342fc07272eec454fc5b400ed3ce3739c7e950 (diff) | |
parent | 9541b81322e60120b299222919957becd7a13683 (diff) |
Merge tag '5.11-rc-smb3-part2' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French:
"Four small CIFS/SMB3 fixes (witness protocol and reconnect related),
and two that add ability to get and set auditing information in the
security descriptor (SACL), which can be helpful not just for backup
scenarios ("smbinfo secdesc" etc.) but also for improving security"
* tag '5.11-rc-smb3-part2' of git://git.samba.org/sfrench/cifs-2.6:
Add SMB 2 support for getting and setting SACLs
SMB3: Add support for getting and setting SACLs
cifs: Avoid error pointer dereference
cifs: Re-indent cifs_swn_reconnect()
cifs: Unlock on errors in cifs_swn_reconnect()
cifs: Delete a stray unlock in cifs_swn_reconnect()
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifs_swn.c | 73 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 15 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/connect.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 35 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 7 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 4 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 81 |
10 files changed, 140 insertions, 86 deletions
diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index c594e588a8b5..d35f599aa00e 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -285,8 +285,6 @@ static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) continue; } - mutex_unlock(&cifs_swnreg_idr_mutex); - cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name, swnreg->share_name); @@ -482,48 +480,51 @@ static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new, static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr) { + int ret = 0; + /* Store the reconnect address */ mutex_lock(&tcon->ses->server->srv_mutex); - if (!cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) { - int ret; - - ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr, - &tcon->ses->server->swn_dstaddr); - if (ret < 0) { - cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); - return ret; - } - tcon->ses->server->use_swn_dstaddr = true; + if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) + goto unlock; - /* - * Unregister to stop receiving notifications for the old IP address. - */ - ret = cifs_swn_unregister(tcon); - if (ret < 0) { - cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", - __func__, ret); - return ret; - } + ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr, + &tcon->ses->server->swn_dstaddr); + if (ret < 0) { + cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); + goto unlock; + } + tcon->ses->server->use_swn_dstaddr = true; - /* - * And register to receive notifications for the new IP address now that we have - * stored the new address. - */ - ret = cifs_swn_register(tcon); - if (ret < 0) { - cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n", - __func__, ret); - return ret; - } + /* + * Unregister to stop receiving notifications for the old IP address. + */ + ret = cifs_swn_unregister(tcon); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", + __func__, ret); + goto unlock; + } - spin_lock(&GlobalMid_Lock); - if (tcon->ses->server->tcpStatus != CifsExiting) - tcon->ses->server->tcpStatus = CifsNeedReconnect; - spin_unlock(&GlobalMid_Lock); + /* + * And register to receive notifications for the new IP address now that we have + * stored the new address. + */ + ret = cifs_swn_register(tcon); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n", + __func__, ret); + goto unlock; } + + spin_lock(&GlobalMid_Lock); + if (tcon->ses->server->tcpStatus != CifsExiting) + tcon->ses->server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + +unlock: mutex_unlock(&tcon->ses->server->srv_mutex); - return 0; + return ret; } static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 2f21f89871cc..562913e2b3f2 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -1195,7 +1195,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, } struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, - const struct cifs_fid *cifsfid, u32 *pacllen) + const struct cifs_fid *cifsfid, u32 *pacllen, + u32 __maybe_unused unused) { struct cifs_ntsd *pntsd = NULL; unsigned int xid; @@ -1263,7 +1264,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, /* Retrieve an ACL from the server */ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, struct inode *inode, const char *path, - u32 *pacllen) + u32 *pacllen, u32 info) { struct cifs_ntsd *pntsd = NULL; struct cifsFileInfo *open_file = NULL; @@ -1273,7 +1274,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); - pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen); + pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info); cifsFileInfo_put(open_file); return pntsd; } @@ -1338,6 +1339,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, int rc = 0; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct smb_version_operations *ops; + const u32 info = 0; cifs_dbg(NOISY, "converting ACL to mode for %s\n", path); @@ -1347,9 +1349,9 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, ops = tlink_tcon(tlink)->ses->server->ops; if (pfid && (ops->get_acl_by_fid)) - pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen); + pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info); else if (ops->get_acl) - pntsd = ops->get_acl(cifs_sb, inode, path, &acllen); + pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info); else { cifs_put_tlink(tlink); return -EOPNOTSUPP; @@ -1388,6 +1390,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct smb_version_operations *ops; bool mode_from_sid, id_from_sid; + const u32 info = 0; if (IS_ERR(tlink)) return PTR_ERR(tlink); @@ -1403,7 +1406,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, return -EOPNOTSUPP; } - pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen); + pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen, info); if (IS_ERR(pntsd)) { rc = PTR_ERR(pntsd); cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 720d0f6a982d..50fcb65920e8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -456,9 +456,9 @@ struct smb_version_operations { const char *, const void *, const __u16, const struct nls_table *, struct cifs_sb_info *); struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *, - const char *, u32 *); + const char *, u32 *, u32); struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *, - const struct cifs_fid *, u32 *); + const struct cifs_fid *, u32 *, u32); int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, int); /* writepages retry size */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index ce51183ecaf4..64fe5a47b5e8 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -240,6 +240,8 @@ #define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ /* synchronize with the completion */ /* of an input/output request */ +#define SYSTEM_SECURITY 0x01000000 /* The system access control list */ + /* can be read and changed */ #define GENERIC_ALL 0x10000000 #define GENERIC_EXECUTE 0x20000000 #define GENERIC_WRITE 0x40000000 diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index bd1c9b038568..340ff81ee87b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -218,9 +218,9 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, kuid_t uid, kgid_t gid); extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, - const char *, u32 *); + const char *, u32 *, u32); extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *, - const struct cifs_fid *, u32 *); + const struct cifs_fid *, u32 *, u32); extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, const char *, int); extern unsigned int setup_authusers_ACE(struct cifs_ace *pace); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 509a41ff56b8..b9df85506938 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -155,6 +155,7 @@ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, cifs_dbg(FYI, "%s: failed to extract hostname from target: %ld\n", __func__, PTR_ERR(server->hostname)); + return; } rc = reconn_set_ipaddr_from_hostname(server); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 949cd1177147..f19274857292 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3214,7 +3214,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, static struct cifs_ntsd * get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb, - const struct cifs_fid *cifsfid, u32 *pacllen) + const struct cifs_fid *cifsfid, u32 *pacllen, u32 info) { struct cifs_ntsd *pntsd = NULL; unsigned int xid; @@ -3228,7 +3228,8 @@ get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb, cifs_dbg(FYI, "trying to get acl\n"); rc = SMB2_query_acl(xid, tlink_tcon(tlink), cifsfid->persistent_fid, - cifsfid->volatile_fid, (void **)&pntsd, pacllen); + cifsfid->volatile_fid, (void **)&pntsd, pacllen, + info); free_xid(xid); cifs_put_tlink(tlink); @@ -3242,7 +3243,7 @@ get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb, static struct cifs_ntsd * get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, - const char *path, u32 *pacllen) + const char *path, u32 *pacllen, u32 info) { struct cifs_ntsd *pntsd = NULL; u8 oplock = SMB2_OPLOCK_LEVEL_NONE; @@ -3280,12 +3281,16 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, oparms.fid = &fid; oparms.reconnect = false; + if (info & SACL_SECINFO) + oparms.desired_access |= SYSTEM_SECURITY; + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL, NULL); kfree(utf16_path); if (!rc) { rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid, - fid.volatile_fid, (void **)&pntsd, pacllen); + fid.volatile_fid, (void **)&pntsd, pacllen, + info); SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); } @@ -3319,10 +3324,12 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen, tcon = tlink_tcon(tlink); xid = get_xid(); - if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP) - access_flags = WRITE_OWNER; - else - access_flags = WRITE_DAC; + if (aclflag & CIFS_ACL_OWNER || aclflag & CIFS_ACL_GROUP) + access_flags |= WRITE_OWNER; + if (aclflag & CIFS_ACL_SACL) + access_flags |= SYSTEM_SECURITY; + if (aclflag & CIFS_ACL_DACL) + access_flags |= WRITE_DAC; utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); if (!utf16_path) { @@ -3356,18 +3363,18 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen, /* Retrieve an ACL from the server */ static struct cifs_ntsd * get_smb2_acl(struct cifs_sb_info *cifs_sb, - struct inode *inode, const char *path, - u32 *pacllen) + struct inode *inode, const char *path, + u32 *pacllen, u32 info) { struct cifs_ntsd *pntsd = NULL; struct cifsFileInfo *open_file = NULL; - if (inode) + if (inode && !(info & SACL_SECINFO)) open_file = find_readable_file(CIFS_I(inode), true); - if (!open_file) - return get_smb2_acl_by_path(cifs_sb, path, pacllen); + if (!open_file || (info & SACL_SECINFO)) + return get_smb2_acl_by_path(cifs_sb, path, pacllen, info); - pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen); + pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info); cifsFileInfo_put(open_file); return pntsd; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index fc06c762fbbf..067eb44c7baa 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -3479,10 +3479,11 @@ SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon, int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, - u64 persistent_fid, u64 volatile_fid, - void **data, u32 *plen) + u64 persistent_fid, u64 volatile_fid, + void **data, u32 *plen, u32 extra_info) { - __u32 additional_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO; + __u32 additional_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | + extra_info; *plen = 0; return query_info(xid, tcon, persistent_fid, volatile_fid, diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index d4110447ee3a..9565e27681a5 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -200,8 +200,8 @@ extern int SMB2_query_info_init(struct cifs_tcon *tcon, size_t input_len, void *input); extern void SMB2_query_info_free(struct smb_rqst *rqst); extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, - u64 persistent_file_id, u64 volatile_file_id, - void **data, unsigned int *plen); + u64 persistent_file_id, u64 volatile_file_id, + void **data, unsigned int *plen, u32 info); extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid); diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index b8299173ea7e..6b658a1172ef 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -34,6 +34,7 @@ #define MAX_EA_VALUE_SIZE CIFSMaxBufSize #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" /* DACL only */ #define CIFS_XATTR_CIFS_NTSD "system.cifs_ntsd" /* owner plus DACL */ +#define CIFS_XATTR_CIFS_NTSD_FULL "system.cifs_ntsd_full" /* owner/DACL/SACL */ #define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */ #define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */ /* @@ -43,12 +44,13 @@ */ #define SMB3_XATTR_CIFS_ACL "system.smb3_acl" /* DACL only */ #define SMB3_XATTR_CIFS_NTSD "system.smb3_ntsd" /* owner plus DACL */ +#define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */ #define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */ #define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */ /* BB need to add server (Samba e.g) support for security and trusted prefix */ enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT, - XATTR_CIFS_NTSD }; + XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL }; static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon, struct inode *inode, char *full_path, @@ -164,7 +166,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler, break; case XATTR_CIFS_ACL: - case XATTR_CIFS_NTSD: { + case XATTR_CIFS_NTSD: + case XATTR_CIFS_NTSD_FULL: { struct cifs_ntsd *pacl; if (!value) @@ -174,23 +177,27 @@ static int cifs_xattr_set(const struct xattr_handler *handler, rc = -ENOMEM; } else { memcpy(pacl, value, size); - if (value && - pTcon->ses->server->ops->set_acl) { + if (pTcon->ses->server->ops->set_acl) { + int aclflags = 0; rc = 0; - if (handler->flags == XATTR_CIFS_NTSD) { - /* set owner and DACL */ - rc = pTcon->ses->server->ops->set_acl( - pacl, size, inode, - full_path, - CIFS_ACL_OWNER); - } - if (rc == 0) { - /* set DACL */ - rc = pTcon->ses->server->ops->set_acl( - pacl, size, inode, - full_path, - CIFS_ACL_DACL); + + switch (handler->flags) { + case XATTR_CIFS_NTSD_FULL: + aclflags = (CIFS_ACL_OWNER | + CIFS_ACL_DACL | + CIFS_ACL_SACL); + break; + case XATTR_CIFS_NTSD: + aclflags = (CIFS_ACL_OWNER | + CIFS_ACL_DACL); + break; + case XATTR_CIFS_ACL: + default: + aclflags = CIFS_ACL_DACL; } + + rc = pTcon->ses->server->ops->set_acl(pacl, + size, inode, full_path, aclflags); } else { rc = -EOPNOTSUPP; } @@ -327,16 +334,25 @@ static int cifs_xattr_get(const struct xattr_handler *handler, break; case XATTR_CIFS_ACL: - case XATTR_CIFS_NTSD: { - /* the whole ntsd is fetched regardless */ - u32 acllen; + case XATTR_CIFS_NTSD: + case XATTR_CIFS_NTSD_FULL: { + /* + * fetch owner, DACL, and SACL if asked for full descriptor, + * fetch owner and DACL otherwise + */ + u32 acllen, extra_info; struct cifs_ntsd *pacl; if (pTcon->ses->server->ops->get_acl == NULL) goto out; /* rc already EOPNOTSUPP */ + if (handler->flags == XATTR_CIFS_NTSD_FULL) { + extra_info = SACL_SECINFO; + } else { + extra_info = 0; + } pacl = pTcon->ses->server->ops->get_acl(cifs_sb, - inode, full_path, &acllen); + inode, full_path, &acllen, extra_info); if (IS_ERR(pacl)) { rc = PTR_ERR(pacl); cifs_dbg(VFS, "%s: error %zd getting sec desc\n", @@ -486,6 +502,27 @@ static const struct xattr_handler smb3_ntsd_xattr_handler = { .set = cifs_xattr_set, }; +static const struct xattr_handler cifs_cifs_ntsd_full_xattr_handler = { + .name = CIFS_XATTR_CIFS_NTSD_FULL, + .flags = XATTR_CIFS_NTSD_FULL, + .get = cifs_xattr_get, + .set = cifs_xattr_set, +}; + +/* + * Although this is just an alias for the above, need to move away from + * confusing users and using the 20 year old term 'cifs' when it is no + * longer secure and was replaced by SMB2/SMB3 a long time ago, and + * SMB3 and later are highly secure. + */ +static const struct xattr_handler smb3_ntsd_full_xattr_handler = { + .name = SMB3_XATTR_CIFS_NTSD_FULL, + .flags = XATTR_CIFS_NTSD_FULL, + .get = cifs_xattr_get, + .set = cifs_xattr_set, +}; + + static const struct xattr_handler cifs_posix_acl_access_xattr_handler = { .name = XATTR_NAME_POSIX_ACL_ACCESS, .flags = XATTR_ACL_ACCESS, @@ -507,6 +544,8 @@ const struct xattr_handler *cifs_xattr_handlers[] = { &smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */ &cifs_cifs_ntsd_xattr_handler, &smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */ + &cifs_cifs_ntsd_full_xattr_handler, + &smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */ &cifs_posix_acl_access_xattr_handler, &cifs_posix_acl_default_xattr_handler, NULL |