diff --git a/fs/smb/client/asn1.c b/fs/smb/client/asn1.c index 214a44509e7b..b610780c6802 100644 --- a/fs/smb/client/asn1.c +++ b/fs/smb/client/asn1.c @@ -46,8 +46,6 @@ int cifs_neg_token_init_mech_type(void *context, size_t hdrlen, oid = look_up_OID(value, vlen); if (oid == OID_mskrb5) server->sec_mskerberos = true; - else if (oid == OID_krb5u2u) - server->sec_kerberosu2u = true; else if (oid == OID_krb5) server->sec_kerberos = true; else if (oid == OID_ntlmssp) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 3761d3ad6088..577f0ddede90 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -450,7 +450,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_puts(m, "Display Internal CIFS Data Structures for Debugging\n" "---------------------------------------------------\n"); - seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); seq_printf(m, "Features:"); #ifdef CONFIG_CIFS_DFS_UPCALL seq_printf(m, " DFS"); diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c index 71a2a59123f5..c0bd4049f65f 100644 --- a/fs/smb/client/cifsencrypt.c +++ b/fs/smb/client/cifsencrypt.c @@ -100,8 +100,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, * and client time (total five av pairs and + one end of fields indicator. * Allocate domain name which gets freed when session struct is deallocated. */ -static int -build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp) +static int build_avpair_blob(struct cifs_ses *ses) { unsigned int dlen; unsigned int size = 2 * sizeof(struct ntlmssp2_name); @@ -141,7 +140,8 @@ build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp) attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); attrptr->length = cpu_to_le16(2 * dlen); blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); - cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, nls_cp); + cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, + ses->local_nls); return 0; } @@ -235,8 +235,7 @@ static __le64 find_timestamp(struct cifs_ses *ses) return cpu_to_le64(cifs_UnixTimeToNT(ts)); } -static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, - const struct nls_table *nls_cp) +static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash) { int len; char nt_hash[CIFS_NTHASH_SIZE]; @@ -246,7 +245,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, wchar_t *server; /* calculate md4 hash of password */ - E_md4hash(ses->password, nt_hash, nls_cp); + E_md4hash(ses->password, nt_hash, ses->local_nls); hmac_md5_init_usingrawkey(&hmac_ctx, nt_hash, CIFS_NTHASH_SIZE); memzero_explicit(nt_hash, sizeof(nt_hash)); @@ -258,7 +257,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, goto out_nomem; if (len) { - len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp); + len = cifs_strtoUTF16(user, ses->user_name, len, + ses->local_nls); UniStrupr(user); } else { *(u16 *)user = 0; @@ -276,7 +276,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, goto out_nomem; len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len, - nls_cp); + ses->local_nls); hmac_md5_update(&hmac_ctx, (const u8 *)domain, 2 * len); kfree(domain); } else { @@ -287,7 +287,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, if (server == NULL) goto out_nomem; - len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp); + len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, + ses->local_nls); hmac_md5_update(&hmac_ctx, (const u8 *)server, 2 * len); kfree(server); } @@ -372,8 +373,7 @@ static int set_auth_key_response(struct cifs_ses *ses) return rc; } -int -setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) +int setup_ntlmv2_rsp(struct cifs_ses *ses) { unsigned char *tiblob = NULL; /* target info blob */ struct ntlmv2_resp *ntlmv2; @@ -382,11 +382,6 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) __u64 cc; int rc; - if (nls_cp == NULL) { - cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__); - return -EINVAL; - } - if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { if (!ses->domainName) { if (ses->domainAuto) { @@ -414,7 +409,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) if (rc) goto setup_ntlmv2_rsp_ret; } else { - rc = build_avpair_blob(ses, nls_cp); + rc = build_avpair_blob(ses); if (rc) { cifs_dbg(VFS, "error %d building av pair blob\n", rc); goto setup_ntlmv2_rsp_ret; @@ -452,7 +447,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) } /* calculate ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); + rc = calc_ntlmv2_hash(ses, ntlmv2_hash); if (rc) { cifs_dbg(VFS, "Could not get NTLMv2 hash, rc=%d\n", rc); goto unlock; diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index f456b42986f6..576155caf888 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -71,7 +71,6 @@ bool enable_gcm_256 = true; bool require_gcm_256; /* false by default */ bool enable_negotiate_signing; /* false by default */ unsigned int global_secflags = CIFSSEC_DEF; -/* unsigned int ntlmv2_support = 0; */ /* * Global transaction id (XID) information @@ -464,7 +463,6 @@ cifs_alloc_inode(struct super_block *sb) * Can not set i_flags here - they get immediately overwritten to zero * by the VFS. */ - /* cifs_inode->netfs.inode.i_flags = S_NOATIME | S_NOCMTIME; */ INIT_LIST_HEAD(&cifs_inode->openFileList); INIT_LIST_HEAD(&cifs_inode->llist); INIT_LIST_HEAD(&cifs_inode->deferred_closes); @@ -858,8 +856,6 @@ static void cifs_umount_begin(struct super_block *sb) spin_unlock(&tcon->tc_lock); spin_unlock(&cifs_tcp_ses_lock); - /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ - /* cancel_notify_requests(tcon); */ if (tcon->ses && tcon->ses->server) { cifs_dbg(FYI, "wake up tasks now - umount begin not complete\n"); wake_up_all(&tcon->ses->server->request_q); @@ -1197,8 +1193,8 @@ int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) struct inode *inode = d_inode(dentry); u32 attrs; - /* Preserve FS_COMPR_FL previously reported by cifs_ioctl(). */ - if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) + /* Report the cached SMB compressed attribute as FS_COMPR_FL. */ + if (READ_ONCE(CIFS_I(inode)->cifsAttrs) & ATTR_COMPRESSED) fa->flags |= FS_COMPR_FL; /* @@ -1259,6 +1255,7 @@ const struct inode_operations cifs_dir_inode_ops = { .get_acl = cifs_get_acl, .set_acl = cifs_set_acl, .fileattr_get = cifs_fileattr_get, + .fileattr_set = cifs_fileattr_set, }; const struct inode_operations cifs_file_inode_ops = { @@ -1270,6 +1267,7 @@ const struct inode_operations cifs_file_inode_ops = { .get_acl = cifs_get_acl, .set_acl = cifs_set_acl, .fileattr_get = cifs_fileattr_get, + .fileattr_set = cifs_fileattr_set, }; const char *cifs_get_link(struct dentry *dentry, struct inode *inode, @@ -2253,7 +2251,6 @@ MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ MODULE_DESCRIPTION ("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and " "also older servers complying with the SNIA CIFS Specification)"); -MODULE_VERSION(CIFS_VERSION); MODULE_SOFTDEP("nls"); MODULE_SOFTDEP("aes"); MODULE_SOFTDEP("aead2"); diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index eb9cb1ecb1b5..7600467babb6 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -91,6 +91,8 @@ extern const struct inode_operations cifs_namespace_inode_operations; struct file_kattr; int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); +int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa); /* Functions related to files and directories */ @@ -167,7 +169,4 @@ char *cifs_silly_fullpath(struct dentry *dentry); extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ -/* when changing internal version - update following two lines at same time */ -#define SMB3_PRODUCT_BUILD 61 -#define CIFS_VERSION "2.61" #endif /* _CIFSFS_H */ diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 5c5b76a9e9fe..73b49dcb5215 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -373,13 +373,12 @@ struct smb_version_operations { unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx); /* setup smb sessionn */ int (*sess_setup)(const unsigned int, struct cifs_ses *, - struct TCP_Server_Info *server, - const struct nls_table *); + struct TCP_Server_Info *server); /* close smb session */ int (*logoff)(const unsigned int, struct cifs_ses *); /* connect to a server share */ int (*tree_connect)(const unsigned int, struct cifs_ses *, const char *, - struct cifs_tcon *, const struct nls_table *); + struct cifs_tcon *); /* close tree connection */ int (*tree_disconnect)(const unsigned int, struct cifs_tcon *); /* get DFS referrals */ @@ -543,9 +542,12 @@ struct smb_version_operations { struct cifsFileInfo *src_file, void __user *); int (*notify)(const unsigned int xid, struct file *pfile, void __user *pbuf, bool return_changes); - int (*query_mf_symlink)(unsigned int, struct cifs_tcon *, - struct cifs_sb_info *, const unsigned char *, - char *, unsigned int *); + int (*query_mf_symlink)(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, + struct inode *inode, char *pbuf, + unsigned int *pbytes_read); int (*create_mf_symlink)(unsigned int, struct cifs_tcon *, struct cifs_sb_info *, const unsigned char *, char *, unsigned int *); @@ -571,7 +573,7 @@ struct smb_version_operations { size_t, struct cifs_sb_info *); int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *, const char *, const void *, const __u16, - const struct nls_table *, struct cifs_sb_info *); + struct cifs_sb_info *); struct smb_ntsd * (*get_acl)(struct cifs_sb_info *cifssb, struct inode *ino, const char *patch, u32 *plen, u32 info); struct smb_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *cifssmb, @@ -730,9 +732,6 @@ struct TCP_Server_Info { /* message size the server can send or receive for non-raw SMBs */ /* maxBuf is returned by SMB NegotiateProtocol so maxBuf is only 0 */ /* when socket is setup (and during reconnect) before NegProt sent */ - unsigned int max_rw; /* maxRw specifies the maximum */ - /* message size the server can send or receive for */ - /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ unsigned int capabilities; /* selective disabling of caps by smb sess */ int timeAdj; /* Adjust for difference in server time zone in sec */ __u64 current_mid; /* multiplex id - rotating counter, protected by mid_counter_lock */ @@ -752,7 +751,6 @@ struct TCP_Server_Info { char negflavor; /* NEGOTIATE response flavor */ /* extended security flavors that server supports */ bool sec_ntlmssp; /* supports NTLMSSP */ - bool sec_kerberosu2u; /* supports U2U Kerberos */ bool sec_kerberos; /* supports plain Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_iakerb; /* supports pass-through auth for Kerberos (krb5 proxy) */ @@ -798,10 +796,10 @@ struct TCP_Server_Info { __le16 cipher_type; /* save initial negprot hash */ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; - bool signing_negotiated; /* true if valid signing context rcvd from server */ bool posix_ext_supported; struct delayed_work reconnect; /* reconnect workqueue job */ struct mutex reconnect_mutex; /* prevent simultaneous reconnects */ + bool need_sock_shutdown; /* shutdown socket when need to reconnect */ unsigned long echo_interval; /* @@ -1066,7 +1064,6 @@ struct cifs_ses { struct TCP_Server_Info *server; /* pointer to server info */ int ses_count; /* reference counter */ enum ses_status_enum ses_status; /* updates protected by cifs_tcp_ses_lock */ - unsigned int overrideSecFlg; /* if non-zero override global sec flags */ char *serverOS; /* name of operating system underlying server */ char *serverNOS; /* name of network operating system of server */ char *serverDomain; /* security realm of server */ @@ -1233,7 +1230,6 @@ struct cifs_tcon { atomic_t num_symlinks; atomic_t num_locks; atomic_t num_acl_get; - atomic_t num_acl_set; } cifs_stats; struct { atomic_t smb2_com_sent[NUMBER_OF_SMB2_COMMANDS]; @@ -2259,7 +2255,7 @@ struct smb2_compound_vars { struct kvec rsp_iov[MAX_COMPOUND]; struct smb_rqst rqst[MAX_COMPOUND]; struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; - struct kvec qi_iov; + struct kvec qi_iov[SMB2_QUERY_INFO_IOV_SIZE]; struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; struct kvec hl_iov[SMB2_SET_INFO_IOV_SIZE]; diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index e6beff8aafe0..f9ea35597bc2 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -131,6 +131,7 @@ void cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, bool mark_smb_session); int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session); +void smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server); bool backup_cred(struct cifs_sb_info *cifs_sb); bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file, bool from_readdir); @@ -290,8 +291,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon); int cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server); int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - struct nls_table *nls_info); + struct TCP_Server_Info *server); int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required); @@ -307,7 +307,7 @@ struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace); void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace); -int setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp); +int setup_ntlmv2_rsp(struct cifs_ses *ses); void cifs_crypto_secmech_release(struct TCP_Server_Info *server); int calc_seckey(struct cifs_ses *ses); int generate_smb30signingkey(struct cifs_ses *ses, @@ -319,9 +319,10 @@ int generate_smb311signingkey(struct cifs_ses *ses, #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb, const char *reason, int rc); bool couldbe_mf_symlink(const struct cifs_fattr *fattr); -int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, - const unsigned char *path); +int cifs_check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, struct inode *inode, + struct cifs_fattr *fattr); int E_md4hash(const unsigned char *passwd, unsigned char *p16, const struct nls_table *codepage); @@ -337,9 +338,11 @@ struct cifs_ses *cifs_get_smb_ses(struct TCP_Server_Info *server, int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid); -int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +int cifs_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, - const unsigned char *path, char *pbuf, + const char *full_path, + struct inode *inode, char *pbuf, unsigned int *pbytes_read); int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 6dddbd84b93b..50ca062a22bf 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -163,7 +163,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) return -EHOSTDOWN; goto again; } - rc = cifs_setup_session(0, ses, server, ses->local_nls); + rc = cifs_setup_session(0, ses, server); if ((rc == -EACCES) || (rc == -EHOSTDOWN) || (rc == -EKEYREVOKED)) { /* * Try alternate password for next reconnect if an alternate @@ -502,7 +502,6 @@ CIFSSMBNegotiate(const unsigned int xid, server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); /* set up max_read for readahead check */ server->max_read = server->maxBuf; - server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf); server->capabilities = le32_to_cpu(pSMBr->Capabilities); server->session_key_id = pSMBr->SessionKey; @@ -537,10 +536,8 @@ CIFSSMBNegotiate(const unsigned int xid, /* * Issue a TREE_CONNECT request. */ -int -CIFSTCon(const unsigned int xid, struct cifs_ses *ses, - const char *tree, struct cifs_tcon *tcon, - const struct nls_table *nls_codepage) +int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, const char *tree, + struct cifs_tcon *tcon) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; @@ -591,7 +588,8 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, length = cifs_strtoUTF16((__le16 *) bcc_ptr, tree, 6 /* max utf8 char length in bytes */ * - (/* server len*/ + 256 /* share len */), nls_codepage); + (/* server len*/ + 256 /* share len */), + ses->local_nls); bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* skip trailing null */ } else { /* ASCII */ @@ -649,7 +647,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, bytes_left, is_unicode, - nls_codepage); + ses->local_nls); cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); @@ -838,10 +836,8 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) return rc; } -int -CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, __u16 type, - const struct nls_table *nls_codepage, int remap) +int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, __u16 type, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -863,7 +859,7 @@ CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { @@ -1051,12 +1047,10 @@ CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode, return rc; } -int -CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, - __u32 posix_flags, __u64 mode, __u16 *netfid, - FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, - const char *name, const struct nls_table *nls_codepage, - int remap) +int CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, + __u32 posix_flags, __u64 mode, __u16 *netfid, + FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, + const char *name, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -1079,7 +1073,7 @@ CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, name, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { @@ -1235,12 +1229,11 @@ access_flags_to_smbopen_mode(const int access_flags) return SMBOPEN_READ; } -int -SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const int openDisposition, - const int access_flags, const int create_options, __u16 *netfid, - int *pOplock, FILE_ALL_INFO *pfile_info, - const struct nls_table *nls_codepage, int remap) +int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const int openDisposition, + const int access_flags, const int create_options, + __u16 *netfid, int *pOplock, FILE_ALL_INFO *pfile_info, + int remap) { int rc; OPENX_REQ *pSMB = NULL; @@ -1263,7 +1256,8 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, count = 1; /* account for one byte pad to word boundary */ name_len = cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), - fileName, PATH_MAX, nls_codepage, remap); + fileName, PATH_MAX, + tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { @@ -1308,9 +1302,6 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, cifs_dbg(FYI, "Error in Open = %d\n", rc); } else { /* BB verify if wct == 15 */ - -/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/ - *netfid = pSMBr->Fid; /* cifs fid stays in le */ /* Let caller know file was created so we can set the mode. */ /* Do we care about the CreateAction in any other cases? */ @@ -1796,7 +1787,6 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, *nbytes = 0; - /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/ if (tcon->ses == NULL) return -ECONNABORTED; @@ -2229,7 +2219,6 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon, { int rc = 0; LOCK_REQ *pSMB = NULL; -/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ unsigned int in_len; int bytes_returned; int flags = CIFS_WINDOWS_LOCK | CIFS_INTERRUPTIBLE_WAIT; @@ -2556,8 +2545,7 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, } int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, - int netfid, const char *target_name, - const struct nls_table *nls_codepage, int remap) + int netfid, const char *target_name, int remap) { struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; @@ -2606,12 +2594,13 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid); len_of_str = cifsConvertToUTF16((__le16 *)rename_info->target_name, - dummy_string, 24, nls_codepage, remap); + dummy_string, 24, + pTcon->ses->local_nls, remap); } else { len_of_str = cifsConvertToUTF16((__le16 *)rename_info->target_name, - target_name, PATH_MAX, nls_codepage, - remap); + target_name, PATH_MAX, + pTcon->ses->local_nls, remap); } rename_info->target_name_len = cpu_to_le32(2 * len_of_str); count = sizeof(struct set_file_rename) + (2 * len_of_str); @@ -3169,7 +3158,6 @@ struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data, &ea->ea_data[0], &ea->ea_data[ea->ea_name_length+1], le16_to_cpu(ea->ea_value_length), - cifs_sb->local_nls, cifs_sb); if (rc) goto out_close; @@ -4156,7 +4144,6 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, int name_len; __u16 params, byte_count; - /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */ QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -4408,10 +4395,11 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_search_info *psrch_inf, bool msearch) { /* level 257 SMB_ */ + unsigned int parm_off, parm_count, data_off, data_count; TRANSACTION2_FFIRST_REQ *pSMB = NULL; TRANSACTION2_FFIRST_RSP *pSMBr = NULL; - T2_FFIRST_RSP_PARMS *parms; struct nls_table *nls_codepage; + T2_FFIRST_RSP_PARMS *parms; unsigned int in_len, lnoff; __u16 params, byte_count; int bytes_returned = 0; @@ -4530,27 +4518,52 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, return rc; } + parm_off = le16_to_cpu(pSMBr->t2.ParameterOffset); + parm_count = le16_to_cpu(pSMBr->t2.ParameterCount); + if (parm_count < sizeof(*parms) || + parm_off + parm_count > (unsigned int)bytes_returned) { + cifs_dbg(FYI, "%s: bad parameter area offset %u count %u for response of %d\n", + __func__, parm_off, parm_count, bytes_returned); + rc = smb_EIO2(smb_eio_trace_ffirst_param_area, + parm_off, parm_count); + cifs_buf_release(pSMB); + return rc; + } + + data_off = le16_to_cpu(pSMBr->t2.DataOffset); + data_count = le16_to_cpu(pSMBr->t2.DataCount); + if (data_off + data_count > (unsigned int)bytes_returned) { + cifs_dbg(VFS, "%s: data area offset %u count %u past response length %d\n", + __func__, data_off, data_count, bytes_returned); + cifs_buf_release(pSMB); + return -EINVAL; + } + psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); psrch_inf->ntwrk_buf_start = (char *)pSMBr; psrch_inf->smallBuf = false; - psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.DataOffset); + psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol + data_off; - parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.ParameterOffset)); + parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol + parm_off); psrch_inf->endOfSearch = !!parms->EndofSearch; psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->entries_in_buffer; + psrch_inf->presume_name = NULL; + psrch_inf->resume_name_len = 0; + psrch_inf->resume_key = 0; + if (pnetfid) + *pnetfid = parms->SearchHandle; lnoff = le16_to_cpu(parms->LastNameOffset); - if (CIFSMaxBufSize < lnoff) { + if (!psrch_inf->entries_in_buffer) { + psrch_inf->last_entry = NULL; + } else if (psrch_inf->srch_entries_start + lnoff >= + psrch_inf->ntwrk_buf_start + bytes_returned) { cifs_dbg(VFS, "ignoring corrupt resume name\n"); psrch_inf->last_entry = NULL; } else { psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff; - if (pnetfid) - *pnetfid = parms->SearchHandle; } return 0; } @@ -4559,10 +4572,11 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, __u16 searchHandle, __u16 search_flags, struct cifs_search_info *psrch_inf) { + unsigned int parm_off, parm_count, data_off, data_count; TRANSACTION2_FNEXT_REQ *pSMB = NULL; TRANSACTION2_FNEXT_RSP *pSMBr = NULL; - T2_FNEXT_RSP_PARMS *parms; unsigned int name_len, in_len; + T2_FNEXT_RSP_PARMS *parms; unsigned int lnoff; __u16 params, byte_count; char *response_data; @@ -4607,7 +4621,10 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, name_len = psrch_inf->resume_name_len; params += name_len; if (name_len < PATH_MAX) { - memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); + if (name_len) { + memcpy(pSMB->ResumeFileName, + psrch_inf->presume_name, name_len); + } byte_count += name_len; /* 14 byte parm len above enough for 2 byte null terminator */ pSMB->ResumeFileName[name_len] = 0; @@ -4643,13 +4660,33 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, cifs_buf_release(pSMB); return rc; } + + parm_off = le16_to_cpu(pSMBr->t2.ParameterOffset); + parm_count = le16_to_cpu(pSMBr->t2.ParameterCount); + if (parm_count < sizeof(*parms) || + parm_off + parm_count > (unsigned int)bytes_returned) { + cifs_dbg(FYI, "%s: bad parameter area offset %u count %u for response of %d\n", + __func__, parm_off, parm_count, bytes_returned); + rc = smb_EIO2(smb_eio_trace_fnext_param_area, + parm_off, parm_count); + cifs_buf_release(pSMB); + return rc; + } + + data_off = le16_to_cpu(pSMBr->t2.DataOffset); + data_count = le16_to_cpu(pSMBr->t2.DataCount); + if (data_off + data_count > (unsigned int)bytes_returned) { + cifs_dbg(VFS, "%s: data area offset %u count %u past response length %d\n", + __func__, data_off, data_count, bytes_returned); + cifs_buf_release(pSMB); + return -EINVAL; + } + /* BB fixme add lock for file (srch_info) struct here */ psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); - response_data = (char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.ParameterOffset); + response_data = (char *)&pSMBr->hdr.Protocol + parm_off; parms = (T2_FNEXT_RSP_PARMS *)response_data; - response_data = (char *)&pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->t2.DataOffset); + response_data = (char *)&pSMBr->hdr.Protocol + data_off; if (psrch_inf->smallBuf) cifs_small_buf_release(psrch_inf->ntwrk_buf_start); @@ -4662,8 +4699,14 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, psrch_inf->endOfSearch = !!parms->EndofSearch; psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer; + psrch_inf->presume_name = NULL; + psrch_inf->resume_name_len = 0; + psrch_inf->resume_key = 0; lnoff = le16_to_cpu(parms->LastNameOffset); - if (CIFSMaxBufSize < lnoff) { + if (!psrch_inf->entries_in_buffer) { + psrch_inf->last_entry = NULL; + } else if (psrch_inf->srch_entries_start + lnoff >= + psrch_inf->ntwrk_buf_start + bytes_returned) { cifs_dbg(VFS, "ignoring corrupt resume name\n"); psrch_inf->last_entry = NULL; } else { @@ -5679,11 +5722,9 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -int -SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, __le32 attributes, __le64 write_time, - const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, __le32 attributes, + __le64 write_time, struct cifs_sb_info *cifs_sb) { SETATTR_REQ *pSMB; SETATTR_RSP *pSMBr; @@ -5705,7 +5746,8 @@ SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, - fileName, PATH_MAX, nls_codepage, + fileName, PATH_MAX, + tcon->ses->local_nls, cifs_remap(cifs_sb)); name_len++; /* trailing null */ name_len *= 2; @@ -5866,11 +5908,9 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -int -CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const FILE_BASIC_INFO *data, - const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const FILE_BASIC_INFO *data, + struct cifs_sb_info *cifs_sb) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -5894,7 +5934,7 @@ CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { @@ -6337,11 +6377,10 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, return (ssize_t)rc; } -int -CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const char *ea_name, const void *ea_value, - const __u16 ea_value_len, const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const char *ea_name, + const void *ea_value, const __u16 ea_value_len, + struct cifs_sb_info *cifs_sb) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -6366,7 +6405,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + PATH_MAX, tcon->ses->local_nls, remap); name_len++; /* trailing null */ name_len *= 2; } else { diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 28e1ddeb6182..c3614c077746 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -130,8 +130,11 @@ void smb2_query_server_interfaces(struct work_struct *work) #define set_need_reco(server) \ do { \ spin_lock(&server->srv_lock); \ - if (server->tcpStatus != CifsExiting) \ + if (server->tcpStatus != CifsExiting) { \ + if (server->tcpStatus != CifsNeedReconnect) \ + server->need_sock_shutdown = true; \ server->tcpStatus = CifsNeedReconnect; \ + } \ spin_unlock(&server->srv_lock); \ } while (0) @@ -353,6 +356,8 @@ cifs_abort_connection(struct TCP_Server_Info *server) static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num_targets) { + bool shutdown; + spin_lock(&server->srv_lock); server->nr_targets = num_targets; if (server->tcpStatus == CifsExiting) { @@ -365,9 +370,25 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num cifs_dbg(FYI, "Mark tcp session as need reconnect\n"); trace_smb3_reconnect(server->current_mid, server->conn_id, server->hostname); - server->tcpStatus = CifsNeedReconnect; + /* + * Cover cases where sender tasks didn't manage to shutdown the socket + * for some reason. + */ + shutdown = server->tcpStatus != CifsNeedReconnect || + server->need_sock_shutdown; + server->need_sock_shutdown = false; + server->tcpStatus = CifsNeedReconnect; spin_unlock(&server->srv_lock); + + if (shutdown) { + cifs_server_lock(server); + if (server->ssocket) + /* Don't release it here/yet! */ + kernel_sock_shutdown(server->ssocket, SHUT_RDWR); + cifs_server_unlock(server); + } + return true; } @@ -1228,8 +1249,7 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) return 0; } -static void -smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) +void smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) { struct smb2_hdr *shdr = (struct smb2_hdr *)buffer; int scredits, in_flight; @@ -1401,12 +1421,14 @@ cifs_demultiplex_thread(void *p) mid_execute_callback(server, mids[i]); release_mid(server, mids[i]); - } else if (server->ops->is_oplock_break && + } else if (bufs[i] && server->ops->is_oplock_break && server->ops->is_oplock_break(bufs[i], server)) { smb2_add_credits_from_hdr(bufs[i], server); cifs_dbg(FYI, "Received oplock break\n"); } else { + if (!bufs[i]) + continue; cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", atomic_read(&mid_count)); cifs_dump_mem("Received Data is: ", bufs[i], @@ -2064,7 +2086,7 @@ struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal) tcon->ses = ses; tcon->ipc = true; tcon->seal = seal; - rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls); + rc = server->ops->tree_connect(xid, ses, unc, tcon); free_xid(xid); if (rc) { @@ -2382,8 +2404,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) return ERR_PTR(rc); } - rc = cifs_setup_session(xid, ses, server, - ctx->local_nls); + rc = cifs_setup_session(xid, ses, server); if (rc) { if (((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) && !retries && ses->password2) { @@ -2500,7 +2521,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) mutex_lock(&ses->session_mutex); rc = cifs_negotiate_protocol(xid, ses, server); if (!rc) - rc = cifs_setup_session(xid, ses, server, ctx->local_nls); + rc = cifs_setup_session(xid, ses, server); mutex_unlock(&ses->session_mutex); /* each channel uses a different signing key */ @@ -2795,8 +2816,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) } xid = get_xid(); - rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon, - ctx->local_nls); + rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon); free_xid(xid); cifs_dbg(FYI, "Tcon rc = %d\n", rc); if (rc) @@ -4072,10 +4092,8 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, return rc; } -int -cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - struct nls_table *nls_info) +int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server) { int rc = 0; struct TCP_Server_Info *pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; @@ -4167,15 +4185,19 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, if (!rc) { if (server->ops->sess_setup) - rc = server->ops->sess_setup(xid, ses, server, nls_info); + rc = server->ops->sess_setup(xid, ses, server); else rc = -ENOSYS; } if (rc) { if (new_ses) { + enum securityEnum sectype; + + sectype = server->ops->select_sectype(server, + ses->sectype); cifs_server_dbg(VFS, "failed to create a new SMB session with %s: %d\n", - get_security_type_str(ses->sectype), rc); + get_security_type_str(sectype), rc); } spin_lock(&ses->ses_lock); if (ses->ses_status == SES_IN_SETUP) @@ -4539,8 +4561,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon) tcon->status = TID_IN_TCON; spin_unlock(&tcon->tc_lock); - rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, - tcon, tcon->ses->local_nls); + rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon); if (rc) { spin_lock(&tcon->tc_lock); if (tcon->status == TID_IN_TCON) diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c index f65a8a90ba27..b7143335d70a 100644 --- a/fs/smb/client/dfs.c +++ b/fs/smb/client/dfs.c @@ -371,7 +371,7 @@ static int tree_connect_dfs_target(const unsigned int xid, dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, tit); scnprintf(tree, MAX_TREE_SIZE, "\\%s", share); rc = ops->tree_connect(xid, tcon->ses, tree, - tcon, tcon->ses->local_nls); + tcon); if (islink && !rc && cifs_sb) rc = cifs_update_super_prepath(cifs_sb, prefix); break; @@ -426,7 +426,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon) scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); cifs_server_unlock(server); rc = ops->tree_connect(xid, tcon->ses, tree, - tcon, tcon->ses->local_nls); + tcon); goto out; } @@ -438,7 +438,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon) if (!server->leaf_fullpath || dfs_cache_noreq_find(server->leaf_fullpath + 1, &ref, &tl)) { rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, - tcon, tcon->ses->local_nls); + tcon); goto out; } diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c index a2cf3d35ca5d..2f6d769a9c83 100644 --- a/fs/smb/client/dir.c +++ b/fs/smb/client/dir.c @@ -419,7 +419,6 @@ static int __cifs_do_create(struct inode *dir, struct dentry *direntry, * BB implement mode setting via Windows security * descriptors e.g. */ - /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/ /* Could set r/o dos attribute if mode & 0222 == 0 */ } diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 11355d6bf89d..0767eb5f4687 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -516,8 +516,7 @@ int cifs_posix_open(const char *full_path, struct inode **pinode, posix_flags = cifs_posix_convert_flags(f_flags); rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, - poplock, full_path, cifs_sb->local_nls, - cifs_remap(cifs_sb)); + poplock, full_path, cifs_remap(cifs_sb)); cifs_put_tlink(tlink); if (rc) @@ -622,6 +621,10 @@ static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_ if (rdwr_for_fscache == 2) cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); + if (server->vals->protocol_id > SMB20_PROT_ID && + *oplock != SMB2_OPLOCK_LEVEL_NONE) + CIFS_I(inode)->lease_granted = true; + /* 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, diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index b6ff019e9923..2647785ec1e4 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -88,7 +88,9 @@ static void cifs_set_ops(struct inode *inode) else inode->i_data.a_ops = &cifs_addr_ops; mapping_set_large_folios(inode->i_mapping); - if (tcon->ses->server->sign) + if (tcon->ses->server->sign || + (tcon->ses->server->compression.enabled && + (tcon->share_flags & SMB2_SHAREFLAG_COMPRESS_DATA))) mapping_set_stable_writes(inode->i_mapping); break; case S_IFDIR: @@ -456,7 +458,7 @@ static int cifs_get_unix_fattr(const unsigned char *full_path, FILE_UNIX_BASIC_INFO find_data; struct cifs_tcon *tcon; struct tcon_link *tlink; - int rc, tmprc; + int rc; cifs_dbg(FYI, "Getting info on %s\n", full_path); @@ -486,8 +488,10 @@ static int cifs_get_unix_fattr(const unsigned char *full_path, /* check for Minshall+French symlinks */ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) { - tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); + rc = cifs_check_mf_symlink(xid, tcon, cifs_sb, full_path, + *pinode, fattr); + if (rc) + return rc; } if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) { @@ -1437,8 +1441,8 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, /* check for Minshall+French symlinks */ if (sbflags & CIFS_MOUNT_MF_SYMLINKS) { - tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); + rc = cifs_check_mf_symlink(xid, tcon, cifs_sb, full_path, + *inode, fattr); } out: @@ -1475,6 +1479,7 @@ int cifs_get_inode_info(struct inode **inode, static int smb311_posix_get_fattr(struct cifs_open_info_data *data, struct cifs_fattr *fattr, const char *full_path, + struct inode *inode, struct super_block *sb, const unsigned int xid) { @@ -1483,7 +1488,6 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data, struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_tcon *tcon; struct tcon_link *tlink; - int tmprc; int rc = 0; tlink = cifs_sb_tlink(cifs_sb); @@ -1537,8 +1541,8 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data, */ /* check for Minshall+French symlinks */ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) { - tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); - cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); + rc = cifs_check_mf_symlink(xid, tcon, cifs_sb, full_path, + inode, fattr); } out: @@ -1561,7 +1565,7 @@ int smb311_posix_get_inode_info(struct inode **inode, return 0; } - rc = smb311_posix_get_fattr(data, &fattr, full_path, sb, xid); + rc = smb311_posix_get_fattr(data, &fattr, full_path, *inode, sb, xid); if (rc) goto out; @@ -1713,7 +1717,7 @@ struct inode *cifs_root_iget(struct super_block *sb) convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); if (tcon->posix_extensions) - rc = smb311_posix_get_fattr(NULL, &fattr, path, sb, xid); + rc = smb311_posix_get_fattr(NULL, &fattr, path, inode, sb, xid); else rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path); @@ -1887,7 +1891,6 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, /* rename the file */ rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, - cifs_sb->local_nls, cifs_remap(cifs_sb)); if (rc != 0) { rc = -EBUSY; @@ -1929,7 +1932,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, */ undo_rename: CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, - cifs_sb->local_nls, cifs_remap(cifs_sb)); + cifs_remap(cifs_sb)); undo_setattr: if (dosattr != origattr) { info_buf->Attributes = cpu_to_le32(origattr); @@ -2017,8 +2020,7 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { rc = CIFSPOSIXDelFile(xid, tcon, full_path, - SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, - cifs_remap(cifs_sb)); + SMB_POSIX_UNLINK_FILE_TARGET, cifs_remap(cifs_sb)); cifs_dbg(FYI, "posix del rc %d\n", rc); if ((rc == 0) || (rc == -ENOENT)) goto psx_del_no_retry; @@ -2239,7 +2241,7 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, mode &= ~current_umask(); rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, NULL /* netfid */, info, &oplock, full_path, - cifs_sb->local_nls, cifs_remap(cifs_sb)); + cifs_remap(cifs_sb)); if (rc == -EOPNOTSUPP) goto posix_mkdir_out; else if (rc) { @@ -2521,7 +2523,7 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, if (rc == 0) { rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, (const char *) to_dentry->d_name.name, - cifs_sb->local_nls, cifs_remap(cifs_sb)); + cifs_remap(cifs_sb)); CIFSSMBClose(xid, tcon, fid.netfid); } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c index 2f152d76be7d..af4664f5b120 100644 --- a/fs/smb/client/ioctl.c +++ b/fs/smb/client/ioctl.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -67,11 +68,11 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, return rc; } -static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, +static int cifs_set_compression_by_path(unsigned int xid, struct dentry *dentry, struct cifs_tcon *tcon, __u16 compression_state) { - struct inode *inode = file_inode(filep); + struct inode *inode = d_inode(dentry); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct TCP_Server_Info *server = tcon->ses->server; struct cifs_open_parms oparms; @@ -92,11 +93,11 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, cifs_sb->mnt_cifs_serverino_autodisabled) return -EOPNOTSUPP; - if (d_unhashed(filep->f_path.dentry)) + if (d_unhashed(dentry)) return -ESTALE; page = alloc_dentry_path(); - full_path = build_path_from_dentry(filep->f_path.dentry, page); + full_path = build_path_from_dentry(dentry, page); if (IS_ERR(full_path)) { free_dentry_path(page); return PTR_ERR(full_path); @@ -123,6 +124,10 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, goto close; uniqueid = le64_to_cpu(data.fi.IndexNumber); + if (!uniqueid) { + rc = -EOPNOTSUPP; + goto close; + } if (uniqueid != CIFS_I(inode)->uniqueid) { rc = -ESTALE; goto close; @@ -140,14 +145,14 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, return rc; } -static int cifs_ioctl_set_compression(unsigned int xid, struct file *filep, - struct cifs_tcon *tcon, - struct cifsFileInfo *cfile, - __u16 compression_state) +static int cifs_set_compression(unsigned int xid, struct dentry *dentry, + struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, + __u16 compression_state) { struct cifsFileInfo *wfile; struct cifs_tcon *wtcon; - struct inode *inode = file_inode(filep); + struct inode *inode = d_inode(dentry); int rc; if (!tcon->ses->server->ops->set_compression) @@ -172,10 +177,68 @@ static int cifs_ioctl_set_compression(unsigned int xid, struct file *filep, return rc; } - return cifs_set_compression_by_path(xid, filep, tcon, + return cifs_set_compression_by_path(xid, dentry, tcon, compression_state); } +int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(dentry); + struct inode *inode = d_inode(dentry); + struct file_kattr current_fa = {}; + u32 allowed = FS_COMPR_FL; + struct tcon_link *tlink; + __u16 compression_state; + bool enable_compression; + struct cifs_tcon *tcon; + unsigned int xid; + int rc; + + if (!fa->flags_valid) + return -EOPNOTSUPP; + + /* + * chattr writes back all flags returned by fileattr_get(). Accept + * FS_CASEFOLD_FL only when it reflects the share's casefold state. + */ + if (fa->flags & FS_CASEFOLD_FL) { + rc = cifs_fileattr_get(dentry, ¤t_fa); + if (rc) + return rc; + if (current_fa.flags & FS_CASEFOLD_FL) + allowed |= FS_CASEFOLD_FL; + } + if (fa->flags & ~allowed) + return -EOPNOTSUPP; + + enable_compression = fa->flags & FS_COMPR_FL; + compression_state = enable_compression ? COMPRESSION_FORMAT_DEFAULT : + COMPRESSION_FORMAT_NONE; + + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + + xid = get_xid(); + rc = cifs_set_compression(xid, dentry, tcon, NULL, compression_state); + free_xid(xid); + cifs_put_tlink(tlink); + + if (!rc) { + spin_lock(&inode->i_lock); + if (enable_compression) + CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_COMPRESSED; + else + CIFS_I(inode)->cifsAttrs &= ~FILE_ATTRIBUTE_COMPRESSED; + spin_unlock(&inode->i_lock); + } + + cifs_dbg(FYI, "set compress flag rc %d\n", rc); + return rc; +} + static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file, unsigned long srcfd) { @@ -464,14 +527,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) struct cifs_tcon *tcon; struct tcon_link *tlink; struct cifs_sb_info *cifs_sb; - __u64 ExtAttrBits = 0; - bool enable_compression; - __u16 compression_state; -#ifdef CONFIG_CIFS_POSIX -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - __u64 caps; -#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -#endif /* CONFIG_CIFS_POSIX */ xid = get_xid(); @@ -482,80 +537,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) trace_smb3_ioctl(xid, pSMBFile->fid.persistent_fid, command); switch (command) { - case FS_IOC_GETFLAGS: - if (pSMBFile == NULL) - break; - tcon = tlink_tcon(pSMBFile->tlink); -#ifdef CONFIG_CIFS_POSIX -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - caps = le64_to_cpu(tcon->fsUnixInfo.Capability); - if (CIFS_UNIX_EXTATTR_CAP & caps) { - __u64 ExtAttrMask = 0; - rc = CIFSGetExtAttr(xid, tcon, - pSMBFile->fid.netfid, - &ExtAttrBits, &ExtAttrMask); - if (rc == 0) - rc = put_user(ExtAttrBits & - FS_FL_USER_VISIBLE, - (int __user *)arg); - if (rc != -EOPNOTSUPP) - break; - } -#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -#endif /* CONFIG_CIFS_POSIX */ - if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED) - ExtAttrBits |= FS_COMPR_FL; - - rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE, - (int __user *)arg); - break; - case FS_IOC_SETFLAGS: - if (pSMBFile == NULL) - break; - tcon = tlink_tcon(pSMBFile->tlink); - /* caps = le64_to_cpu(tcon->fsUnixInfo.Capability); */ - - if (get_user(ExtAttrBits, (int __user *)arg)) { - rc = -EFAULT; - break; - } - - /* - * if (CIFS_UNIX_EXTATTR_CAP & caps) - * rc = CIFSSetExtAttr(xid, tcon, - * pSMBFile->fid.netfid, - * extAttrBits, - * &ExtAttrMask); - * if (rc != -EOPNOTSUPP) - * break; - */ - - /* Currently only flag we can set or clear is compressed. */ - if (ExtAttrBits & ~FS_COMPR_FL) { - rc = -EOPNOTSUPP; - break; - } - - enable_compression = ExtAttrBits & FS_COMPR_FL; - compression_state = enable_compression ? - COMPRESSION_FORMAT_DEFAULT : - COMPRESSION_FORMAT_NONE; - - rc = cifs_ioctl_set_compression(xid, filep, tcon, - pSMBFile, - compression_state); - if (rc == 0) { - spin_lock(&inode->i_lock); - if (enable_compression) - CIFS_I(inode)->cifsAttrs |= - FILE_ATTRIBUTE_COMPRESSED; - else - CIFS_I(inode)->cifsAttrs &= - ~FILE_ATTRIBUTE_COMPRESSED; - spin_unlock(&inode->i_lock); - } - cifs_dbg(FYI, "set compress flag rc %d\n", rc); - break; case CIFS_IOC_COPYCHUNK_FILE: rc = cifs_ioctl_copychunk(xid, filep, arg); break; diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c index 76df31abeaea..e865aeea8dbb 100644 --- a/fs/smb/client/link.c +++ b/fs/smb/client/link.c @@ -17,6 +17,7 @@ #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "smb2proto.h" +#include "smb2glob.h" #include "cifs_ioctl.h" #include "fs_context.h" #include "reparse.h" @@ -166,30 +167,34 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -int -check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, - const unsigned char *path) +int cifs_check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, struct inode *inode, + struct cifs_fattr *fattr) { - int rc; - u8 *buf = NULL; - unsigned int link_len = 0; + struct TCP_Server_Info *server = tcon->ses->server; + char *buf __free(kfree) = NULL; unsigned int bytes_read = 0; + unsigned int link_len = 0; char *symlink = NULL; + int rc = 0; if (!couldbe_mf_symlink(fattr)) - /* it's not a symlink */ - return 0; + goto out; buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + rc = -ENOMEM; + goto out; + } - if (tcon->ses->server->ops->query_mf_symlink) - rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, - cifs_sb, path, buf, &bytes_read); - else + if (server->ops->query_mf_symlink) { + rc = server->ops->query_mf_symlink(xid, tcon, + cifs_sb, full_path, + inode, buf, &bytes_read); + } else { rc = -ENOSYS; + } if (rc) goto out; @@ -214,19 +219,17 @@ check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, fattr->cf_dtype = DT_LNK; fattr->cf_symlink_target = symlink; out: - kfree(buf); - return rc; + cifs_dbg(FYI, "%s: rc = %d\n", __func__, rc); + return rc == -ENOMEM ? rc : 0; } #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY -/* - * SMB 1.0 Protocol specific functions - */ - -int -cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, const unsigned char *path, - char *pbuf, unsigned int *pbytes_read) +int cifs_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, + struct inode *inode, char *pbuf, + unsigned int *pbytes_read) { int rc; int oplock = 0; @@ -242,7 +245,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, .desired_access = GENERIC_READ, .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), .disposition = FILE_OPEN, - .path = path, + .path = full_path, .fid = &fid, }; @@ -305,65 +308,189 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -/* - * SMB 2.1/SMB3 Protocol specific functions - */ -int -smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, const unsigned char *path, - char *pbuf, unsigned int *pbytes_read) +int smb2_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, + struct inode *inode, char *pbuf, + unsigned int *pbytes_read) { - int rc; + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; + struct kvec read_iov[2], close_iov; + struct cifsFileInfo *cfile = NULL; + struct smb2_read_rsp *read_rsp; + struct TCP_Server_Info *server; + int retries = 0, cur_sleep = 0; + struct cifs_io_parms io_parms; + struct smb2_read_req *req; + struct smb_rqst rqst[3]; + unsigned int total_len; + struct kvec rsp_iov[3]; struct cifs_fid fid; - struct cifs_open_parms oparms; - struct cifs_io_parms io_parms = {0}; - int buf_type = CIFS_NO_BUFFER; - __le16 *utf16_path; - __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; - struct cifs_open_info_data data = {}; + int rsp_buftype[3]; + struct kvec *riov; + int num_rqst; + __u8 oplock; + int flags; + u32 dlen; + int rc; - oparms = (struct cifs_open_parms) { - .tcon = tcon, - .cifs_sb = cifs_sb, - .path = path, - .desired_access = GENERIC_READ, - .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), - .disposition = FILE_OPEN, - .fid = &fid, - }; + cifs_get_readable_path(tcon, full_path, &cfile); + *pbytes_read = 0; +again: + flags = 0; + num_rqst = 0; + req = NULL; + oplock = SMB2_OPLOCK_LEVEL_NONE; + server = cifs_pick_channel(tcon->ses); - utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); - if (utf16_path == NULL) - return -ENOMEM; + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, &data, NULL, - NULL, NULL); - if (rc) - goto qmf_out_open_fail; + for (int i = 0; i < ARRAY_SIZE(rsp_buftype); i++) + rsp_buftype[i] = CIFS_NO_BUFFER; - if (data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { - /* it's not a symlink */ - rc = -ENOENT; /* Is there a better rc to return? */ - goto qmf_out; + memset(rqst, 0, sizeof(rqst)); + memset(rsp_iov, 0, sizeof(rsp_iov)); + + if (!cfile) { + __le16 *utf16_path __free(kfree) = NULL; + struct cifs_open_parms oparms; + + utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); + if (!utf16_path) { + rc = -ENOMEM; + goto out; + } + + if (inode && CIFS_I(inode)->lease_granted && + server->ops->get_lease_key) { + oplock = SMB2_OPLOCK_LEVEL_LEASE; + server->ops->get_lease_key(inode, &fid); + } + + oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, GENERIC_READ, + FILE_OPEN, CREATE_NOT_DIR, ACL_NO_MODE); + oparms.fid = &fid; + + memset(open_iov, 0, sizeof(open_iov)); + rqst[num_rqst].rq_iov = open_iov; + rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; + + rc = SMB2_open_init(tcon, server, &rqst[num_rqst], + &oplock, &oparms, utf16_path); + if (rc) + goto out; + smb2_set_next_command(tcon, &rqst[num_rqst++]); } - io_parms.netfid = fid.netfid; - io_parms.pid = current->tgid; - io_parms.tcon = tcon; - io_parms.offset = 0; - io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; - io_parms.persistent_fid = fid.persistent_fid; - io_parms.volatile_fid = fid.volatile_fid; - rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type); -qmf_out: - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); -qmf_out_open_fail: - kfree(utf16_path); + io_parms = (struct cifs_io_parms) { + .pid = current->tgid, + .tcon = tcon, + .length = CIFS_MF_SYMLINK_FILE_SIZE, + .server = server, + .persistent_fid = COMP_PID(cfile), + .volatile_fid = COMP_VID(cfile), + }; + + rc = smb2_new_read_req((void **)&req, &total_len, + &io_parms, NULL, 0, 0); + if (rc) + goto out; + + read_iov[0].iov_base = req; + read_iov[0].iov_len = total_len; + rqst[num_rqst].rq_iov = read_iov; + rqst[num_rqst].rq_nvec = 1; + if (!cfile) { + smb2_set_next_command(tcon, &rqst[num_rqst]); + smb2_set_related(&rqst[num_rqst]); + } + num_rqst++; + + if (!cfile) { + flags |= CIFS_CP_CREATE_CLOSE_OP; + memset(&close_iov, 0, sizeof(close_iov)); + rqst[num_rqst].rq_iov = &close_iov; + rqst[num_rqst].rq_nvec = 1; + rc = SMB2_close_init(tcon, server, &rqst[num_rqst], + COMPOUND_FID, COMPOUND_FID, false); + smb2_set_related(&rqst[num_rqst++]); + if (rc) + goto out; + } + + if (retries) { + if (cur_sleep) + msleep(cur_sleep); + for (int i = 0; i < num_rqst; i++) + smb2_set_replay(server, &rqst[i]); + } + + rc = compound_send_recv(xid, tcon->ses, server, flags, + num_rqst, rqst, rsp_buftype, rsp_iov); + if (rc) { + if (rc != -ENODATA) { + if (rc != -ENOENT) + cifs_stats_fail_inc(tcon, SMB2_READ_HE); + cifs_dbg(FYI, "%s: failed to read file: %d\n", + __func__, rc); + trace_smb3_read_err(0, 0, xid, req->PersistentFileId, + tcon->tid, tcon->ses->Suid, + io_parms.offset, io_parms.length, + rc); + } else { + trace_smb3_read_done(0, 0, xid, req->PersistentFileId, + tcon->tid, tcon->ses->Suid, + io_parms.offset, 0); + } + rc = rc == -ENODATA ? 0 : rc; + goto out; + } + trace_smb3_read_done(0, 0, xid, req->PersistentFileId, + tcon->tid, tcon->ses->Suid, + io_parms.offset, io_parms.length); + + riov = &rsp_iov[!cfile ? 1 : 0]; + read_rsp = riov->iov_base; + dlen = le32_to_cpu(read_rsp->DataLength); + if (dlen > CIFS_MAX_MSGSIZE || dlen > io_parms.length) { + cifs_dbg(FYI, "%s: bad length %u for count %u\n", + __func__, dlen, io_parms.length); + rc = smb_EIO2(smb_eio_trace_read_overlarge, + dlen, io_parms.length); + } else if (dlen != CIFS_MF_SYMLINK_FILE_SIZE) { + rc = -ENOENT; + } else { + rc = smb2_validate_iov(read_rsp->DataOffset, dlen, riov, + CIFS_MF_SYMLINK_FILE_SIZE); + } + + if (!rc) { + memcpy(pbuf, (u8 *)read_rsp + read_rsp->DataOffset, dlen); + *pbytes_read = dlen; + } + +out: + if (!cfile) { + SMB2_open_free(&rqst[0]); + SMB2_close_free(&rqst[2]); + } + cifs_small_buf_release(req); + for (int i = 0; i < ARRAY_SIZE(rsp_buftype); i++) + free_rsp_buf(rsp_buftype[i], rsp_iov[i].iov_base); + + if (is_replayable_error(rc) && + smb2_should_replay(tcon, &retries, &cur_sleep)) + goto again; + + if (cfile) + cifsFileInfo_put(cfile); return rc; } int -smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +smb2_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_written) { diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index 05168284f205..ec28f102ea08 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -215,10 +215,8 @@ cifs_buf_get(void) void cifs_buf_release(void *buf_to_free) { - if (buf_to_free == NULL) { - /* cifs_dbg(FYI, "Null buffer passed to cifs_buf_release\n");*/ + if (!buf_to_free) return; - } mempool_free(buf_to_free, cifs_req_poolp); atomic_dec(&buf_alloc_count); diff --git a/fs/smb/client/netmisc.c b/fs/smb/client/netmisc.c index bddadee82d0c..cf737ede1ab3 100644 --- a/fs/smb/client/netmisc.c +++ b/fs/smb/client/netmisc.c @@ -204,9 +204,6 @@ struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) sec += 24 * 60 * 60 * days; ts.tv_sec = sec + offset; - - /* cifs_dbg(FYI, "sec after cnvrt dos to unix time %d\n",sec); */ - ts.tv_nsec = 0; return ts; } diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index be0365f08396..0957b4002b9c 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -93,7 +93,7 @@ typedef struct _NEGOTIATE_MESSAGE { struct ntlmssp_version { __u8 ProductMajorVersion; __u8 ProductMinorVersion; - __le16 ProductBuild; /* we send the cifs.ko module version here */ + __le16 ProductBuild; /* we send the kernel sublevel here */ __u8 Reserved[3]; __u8 NTLMRevisionCurrent; /* currently 0x0F */ } __packed; @@ -146,13 +146,10 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses); int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 9530e5b01564..525f99181485 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -456,17 +456,20 @@ initiate_cifs_search(const unsigned int xid, struct file *file, } /* return length of unicode string in bytes */ -static int cifs_unicode_bytelen(const char *str) +static size_t cifs_unicode_bytelen(const char *str, size_t maxlen) { - int len; const __le16 *ustr = (const __le16 *)str; + size_t len; - for (len = 0; len <= PATH_MAX; len++) { + maxlen = umin(PATH_MAX + 1, maxlen / sizeof(__le16)); + for (len = 0; len < maxlen; len++) { if (ustr[len] == 0) - return len << 1; + return len * sizeof(__le16); } - cifs_dbg(FYI, "Unicode string longer than PATH_MAX found\n"); - return len << 1; + len *= sizeof(__le16); + cifs_dbg(FYI, "%s: Unicode string not terminated within %zu bytes\n", + __func__, len); + return len; } static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) @@ -532,13 +535,13 @@ static void cifs_fill_dirent_posix(struct cifs_dirent *de, } static void cifs_fill_dirent_unix(struct cifs_dirent *de, - const FILE_UNIX_INFO *info, bool is_unicode) + const FILE_UNIX_INFO *info, bool is_unicode, size_t maxlen) { de->name = &info->FileName[0]; if (is_unicode) - de->namelen = cifs_unicode_bytelen(de->name); + de->namelen = cifs_unicode_bytelen(de->name, maxlen); else - de->namelen = strnlen(de->name, PATH_MAX); + de->namelen = strnlen(de->name, min_t(size_t, maxlen, PATH_MAX)); de->resume_key = info->ResumeKey; de->ino = le64_to_cpu(info->basic.UniqueId); } @@ -586,30 +589,49 @@ static void cifs_fill_dirent_std(struct cifs_dirent *de, } static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, - u16 level, bool is_unicode) + const char *end, u16 level, bool is_unicode) { + size_t len = end > (const char *)info ? end - (const char *)info : 0; + size_t nul_len = 0; + memset(de, 0, sizeof(*de)); switch (level) { case SMB_FIND_FILE_POSIX_INFO: + if (len < sizeof(struct smb2_posix_info)) + goto too_short; cifs_fill_dirent_posix(de, info); break; case SMB_FIND_FILE_UNIX: - cifs_fill_dirent_unix(de, info, is_unicode); + if (len < offsetof(FILE_UNIX_INFO, FileName)) + goto too_short; + cifs_fill_dirent_unix(de, info, is_unicode, + len - offsetof(FILE_UNIX_INFO, FileName)); + nul_len = is_unicode ? sizeof(__le16) : sizeof(__u8); break; case SMB_FIND_FILE_DIRECTORY_INFO: + if (len < offsetof(FILE_DIRECTORY_INFO, FileName)) + goto too_short; cifs_fill_dirent_dir(de, info); break; case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + if (len < offsetof(FILE_FULL_DIRECTORY_INFO, FileName)) + goto too_short; cifs_fill_dirent_full(de, info); break; case SMB_FIND_FILE_ID_FULL_DIR_INFO: + if (len < offsetof(FILE_ID_FULL_DIR_INFO, FileName)) + goto too_short; cifs_fill_dirent_search(de, info); break; case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + if (len < offsetof(FILE_BOTH_DIRECTORY_INFO, FileName)) + goto too_short; cifs_fill_dirent_both(de, info); break; case SMB_FIND_FILE_INFO_STANDARD: + if (len < offsetof(FIND_FILE_STANDARD_INFO, FileName)) + goto too_short; cifs_fill_dirent_std(de, info); break; default: @@ -617,7 +639,20 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, return -EINVAL; } + if (de->name && + (end < de->name || + (size_t)(end - de->name) < de->namelen + nul_len)) { + cifs_dbg(VFS, "%s: search entry name extends past end of SMB\n", + __func__); + return -EINVAL; + } + return 0; + +too_short: + cifs_dbg(VFS, "%s: search entry extends past end of SMB\n", + __func__); + return -EINVAL; } #define UNICODE_DOT cpu_to_le16(0x2e) @@ -672,10 +707,14 @@ static int is_dir_changed(struct file *file) static int cifs_save_resume_key(const char *current_entry, struct cifsFileInfo *file_info) { + struct TCP_Server_Info *server = tlink_tcon(file_info->tlink)->ses->server; + char *buf = file_info->srch_inf.ntwrk_buf_start; + const char *end = buf + server->ops->calc_smb_size(buf); struct cifs_dirent de; int rc; - rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level, + rc = cifs_fill_dirent(&de, current_entry, end, + file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (!rc) { file_info->srch_inf.presume_name = de.name; @@ -752,6 +791,9 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, cfile->srch_inf.ntwrk_buf_start = NULL; cfile->srch_inf.srch_entries_start = NULL; cfile->srch_inf.last_entry = NULL; + cfile->srch_inf.presume_name = NULL; + cfile->srch_inf.resume_name_len = 0; + cfile->srch_inf.resume_key = 0; } rc = initiate_cifs_search(xid, file, full_path); if (rc) { @@ -974,22 +1016,12 @@ static int cifs_filldir(char *find_entry, struct file *file, struct qstr name; int rc = 0; - rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, + rc = cifs_fill_dirent(&de, find_entry, end_of_smb, + file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (rc) return rc; - if (de.namelen > max_len) { - cifs_dbg(VFS, "bad search response length %zd past smb end\n", - de.namelen); - return -EINVAL; - } - - if (de.name + de.namelen > end_of_smb) { - cifs_dbg(VFS, "search entry name extends past end of SMB\n"); - return -EINVAL; - } - /* skip . and .. since we added them first */ if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode)) return 0; diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index e095f41b5882..c1fc90726e2d 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -620,18 +620,19 @@ cifs_ses_add_channel(struct cifs_ses *ses, rc = cifs_negotiate_protocol(xid, ses, chan->server); if (!rc) - rc = cifs_setup_session(xid, ses, chan->server, ses->local_nls); + rc = cifs_setup_session(xid, ses, chan->server); mutex_unlock(&ses->session_mutex); out: if (rc && chan->server) { - cifs_put_tcp_session(chan->server, 0); + struct TCP_Server_Info *pserver; spin_lock(&ses->chan_lock); + pserver = chan->server; /* we rely on all bits beyond chan_count to be clear */ - cifs_chan_clear_need_reconnect(ses, chan->server); + cifs_chan_clear_need_reconnect(ses, pserver); ses->chan_count--; /* * chan_count should never reach 0 as at least the primary @@ -639,6 +640,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, */ WARN_ON(ses->chan_count < 1); spin_unlock(&ses->chan_lock); + cifs_put_tcp_session(pserver, 0); } kfree(ctx->UNC); @@ -792,8 +794,7 @@ static inline void cifs_security_buffer_from_str(SECURITY_BUFFER *pbuf, int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { int rc = 0; NEGOTIATE_MESSAGE *sec_blob; @@ -833,13 +834,13 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, NULL, CIFS_MAX_DOMAINNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->WorkstationName, NULL, CIFS_MAX_WORKSTATION_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); *buflen = tmp - *pbuffer; setup_ntlm_neg_ret: @@ -854,8 +855,7 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { int rc = 0; struct negotiate_message *sec_blob; @@ -888,7 +888,7 @@ int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR; sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL; - sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD); + sec_blob->Version.ProductBuild = cpu_to_le16(LINUX_VERSION_SUBLEVEL); sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; tmp = *pbuffer + sizeof(struct negotiate_message); @@ -900,13 +900,13 @@ int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, NULL, CIFS_MAX_DOMAINNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->WorkstationName, NULL, CIFS_MAX_WORKSTATION_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); *buflen = tmp - *pbuffer; setup_ntlm_smb3_neg_ret: @@ -918,8 +918,7 @@ int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { int rc; AUTHENTICATE_MESSAGE *sec_blob; @@ -927,7 +926,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, unsigned char *tmp; int len; - rc = setup_ntlmv2_rsp(ses, nls_cp); + rc = setup_ntlmv2_rsp(ses); if (rc) { cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); *buflen = 0; @@ -954,7 +953,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR; sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL; - sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD); + sec_blob->Version.ProductBuild = cpu_to_le16(LINUX_VERSION_SUBLEVEL); sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE); @@ -988,19 +987,19 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, ses->domainName, CIFS_MAX_DOMAINNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->UserName, ses->user_name, CIFS_MAX_USERNAME_LEN, *pbuffer, &tmp, - nls_cp); + ses->local_nls); cifs_security_buffer_from_str(&sec_blob->WorkstationName, ses->workstation_name, ntlmssp_workstation_name_size(ses), *pbuffer, &tmp, - nls_cp); + ses->local_nls); if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) && diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 3ac4126267f6..c0d0eb0cdd2c 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -815,7 +815,6 @@ cifs_clear_stats(struct cifs_tcon *tcon) atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0); atomic_set(&tcon->stats.cifs_stats.num_locks, 0); atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0); - atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0); } static void @@ -868,13 +867,12 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path, cifsInode = CIFS_I(inode); dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; info.Attributes = cpu_to_le32(dosattrs); - rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, - cifs_sb); + rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb); if (rc == -EOPNOTSUPP || rc == -EINVAL) rc = SMBSetInformation(xid, tcon, full_path, info.Attributes, 0 /* do not change write time */, - cifs_sb->local_nls, cifs_sb); + cifs_sb); if (rc == 0) cifsInode->cifsAttrs = dosattrs; } @@ -892,7 +890,6 @@ static int cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms oparms->desired_access, oparms->create_options, &oparms->fid->netfid, oplock, &fi, - oparms->cifs_sb->local_nls, cifs_remap(oparms->cifs_sb)); else rc = CIFS_open(xid, oparms, oplock, &fi); @@ -1023,8 +1020,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, if (open_file) goto set_via_filehandle; - rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, - cifs_sb); + rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb); if (rc == 0) { cinode->cifsAttrs = le32_to_cpu(buf->Attributes); goto out; @@ -1073,7 +1069,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, rc = SMBSetInformation(xid, tcon, full_path, buf->Attributes != 0 ? buf->Attributes : cpu_to_le32(cinode->cifsAttrs), write_time, - cifs_sb->local_nls, cifs_sb); + cifs_sb); if (rc == 0) cinode->cifsAttrs = le32_to_cpu(buf->Attributes); else @@ -1112,7 +1108,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, SMBSetInformation(xid, tcon, full_path, buf->Attributes, 0 /* do not change write time */, - cifs_sb->local_nls, cifs_sb); + cifs_sb); } out: if (tlink != NULL) diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 80eaeb3dd2ec..7175b458724c 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -33,13 +33,12 @@ int small_smb_init_no_tc(const int smb_command, const int wct, int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server); int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, const char *tree, - struct cifs_tcon *tcon, const struct nls_table *nls_codepage); + struct cifs_tcon *tcon); int CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon); int CIFSSMBEcho(struct TCP_Server_Info *server); int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses); int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, __u16 type, - const struct nls_table *nls_codepage, int remap); + const char *fileName, __u16 type, int remap); int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, struct cifs_sb_info *cifs_sb, struct dentry *dentry); @@ -51,13 +50,12 @@ int CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode, int CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, __u32 posix_flags, __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock, - const char *name, const struct nls_table *nls_codepage, - int remap); + const char *name, int remap); int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int openDisposition, const int access_flags, const int create_options, __u16 *netfid, int *pOplock, FILE_ALL_INFO *pfile_info, - const struct nls_table *nls_codepage, int remap); + int remap); int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, FILE_ALL_INFO *buf); int cifs_async_readv(struct cifs_io_subrequest *rdata); @@ -90,8 +88,7 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, struct dentry *source_dentry, const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb); int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, - int netfid, const char *target_name, - const struct nls_table *nls_codepage, int remap); + int netfid, const char *target_name, int remap); int CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, const char *fromName, const char *toName, const struct nls_table *nls_codepage, int remap); @@ -186,8 +183,7 @@ int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, bool set_allocation); int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, __le32 attributes, - __le64 write_time, const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb); + __le64 write_time, struct cifs_sb_info *cifs_sb); int CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener); @@ -196,7 +192,6 @@ int CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, __u32 pid_of_opener); int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const FILE_BASIC_INFO *data, - const struct nls_table *nls_codepage, struct cifs_sb_info *cifs_sb); int CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const struct cifs_unix_set_info_args *args, u16 fid, @@ -212,7 +207,6 @@ ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const char *ea_name, const void *ea_value, const __u16 ea_value_len, - const struct nls_table *nls_codepage, struct cifs_sb_info *cifs_sb); /* @@ -274,8 +268,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, * smb1session.c */ int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); /* * smb1transport.c diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 83bfbf0c068e..5f469b4d70f7 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -20,7 +20,6 @@ struct sess_data { unsigned int xid; struct cifs_ses *ses; struct TCP_Server_Info *server; - struct nls_table *nls_cp; void (*func)(struct sess_data *); int result; unsigned int in_len; @@ -106,8 +105,7 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) *pbcc_area = bcc_ptr; } -static void -ascii_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) +static void ascii_oslm_strings(char **pbcc_area) { char *bcc_ptr = *pbcc_area; @@ -122,8 +120,7 @@ ascii_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) *pbcc_area = bcc_ptr; } -static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int bytes_ret = 0; @@ -139,15 +136,15 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, bytes_ret = 0; } else bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName, - CIFS_MAX_DOMAINNAME_LEN, nls_cp); + CIFS_MAX_DOMAINNAME_LEN, + ses->local_nls); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null terminator */ *pbcc_area = bcc_ptr; } -static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int len; @@ -165,8 +162,7 @@ static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses, *pbcc_area = bcc_ptr; } -static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int bytes_ret = 0; @@ -180,19 +176,19 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, *(bcc_ptr+1) = 0; } else { bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name, - CIFS_MAX_USERNAME_LEN, nls_cp); + CIFS_MAX_USERNAME_LEN, + ses->local_nls); } bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ - unicode_domain_string(&bcc_ptr, ses, nls_cp); - unicode_oslm_strings(&bcc_ptr, nls_cp); + unicode_domain_string(&bcc_ptr, ses); + unicode_oslm_strings(&bcc_ptr, ses->local_nls); *pbcc_area = bcc_ptr; } -static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses) { char *bcc_ptr = *pbcc_area; int len; @@ -212,15 +208,14 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, /* BB check for overflow here */ - ascii_domain_string(&bcc_ptr, ses, nls_cp); - ascii_oslm_strings(&bcc_ptr, nls_cp); + ascii_domain_string(&bcc_ptr, ses); + ascii_oslm_strings(&bcc_ptr); *pbcc_area = bcc_ptr; } -static void -decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, - const struct nls_table *nls_cp) +static void decode_unicode_ssetup(char **pbcc_area, int bleft, + struct cifs_ses *ses) { int len; char *data = *pbcc_area; @@ -228,7 +223,8 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, cifs_dbg(FYI, "bleft %d\n", bleft); kfree(ses->serverOS); - ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp); + ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, + ses->local_nls); cifs_dbg(FYI, "serverOS=%s\n", ses->serverOS); len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; data += len; @@ -237,7 +233,8 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, return; kfree(ses->serverNOS); - ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp); + ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, + ses->local_nls); cifs_dbg(FYI, "serverNOS=%s\n", ses->serverNOS); len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; data += len; @@ -246,15 +243,15 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, return; kfree(ses->serverDomain); - ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, nls_cp); + ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, + ses->local_nls); cifs_dbg(FYI, "serverDomain=%s\n", ses->serverDomain); return; } static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft, - struct cifs_ses *ses, - const struct nls_table *nls_cp) + struct cifs_ses *ses) { int len; char *bcc_ptr = *pbcc_area; @@ -443,7 +440,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data) if (ses->user_name != NULL) { /* calculate nlmv2 response and session key */ - rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp); + rc = setup_ntlmv2_rsp(ses); if (rc) { cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc); goto out; @@ -467,9 +464,9 @@ sess_auth_ntlmv2(struct sess_data *sess_data) *bcc_ptr = 0; bcc_ptr++; } - unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); + unicode_ssetup_strings(&bcc_ptr, ses); } else { - ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); + ascii_ssetup_strings(&bcc_ptr, ses); } @@ -507,11 +504,9 @@ sess_auth_ntlmv2(struct sess_data *sess_data) ++bcc_ptr; --bytes_remaining; } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses); } rc = sess_establish_session(sess_data); @@ -592,11 +587,11 @@ sess_auth_kerberos(struct sess_data *sess_data) *bcc_ptr = 0; bcc_ptr++; } - unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); - unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + unicode_oslm_strings(&bcc_ptr, sess_data->ses->local_nls); + unicode_domain_string(&bcc_ptr, ses); } else { - ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp); - ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + ascii_oslm_strings(&bcc_ptr); + ascii_domain_string(&bcc_ptr, ses); } sess_data->iov[2].iov_len = (long) bcc_ptr - @@ -643,11 +638,9 @@ sess_auth_kerberos(struct sess_data *sess_data) ++bcc_ptr; --bytes_remaining; } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses); } rc = sess_establish_session(sess_data); @@ -692,9 +685,9 @@ _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data) *bcc_ptr = 0; bcc_ptr++; } - unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); + unicode_oslm_strings(&bcc_ptr, sess_data->ses->local_nls); } else { - ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp); + ascii_oslm_strings(&bcc_ptr); } sess_data->iov[2].iov_len = (long) bcc_ptr - @@ -741,8 +734,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) /* Build security blob before we assemble the request */ rc = build_ntlmssp_negotiate_blob(&ntlmsspblob, - &blob_len, ses, server, - sess_data->nls_cp); + &blob_len, ses, server); if (rc) goto out_free_ntlmsspblob; @@ -836,8 +828,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; smb_buf = (struct smb_hdr *)pSMB; rc = build_ntlmssp_auth_blob(&ntlmsspblob, - &blob_len, ses, server, - sess_data->nls_cp); + &blob_len, ses, server); if (rc) goto out_free_ntlmsspblob; sess_data->iov[1].iov_len = blob_len; @@ -896,11 +887,9 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) ++bcc_ptr; --bytes_remaining; } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses); } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); + decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses); } out_free_ntlmsspblob: @@ -958,38 +947,33 @@ static int select_sec(struct sess_data *sess_data) } int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) + struct TCP_Server_Info *server) { + struct sess_data sess_data; int rc = 0; - struct sess_data *sess_data; if (ses == NULL) { WARN(1, "%s: ses == NULL!", __func__); return -EINVAL; } - sess_data = kzalloc_obj(struct sess_data); - if (!sess_data) - return -ENOMEM; + sess_data = (struct sess_data) { + .xid = xid, + .ses = ses, + .server = server, + .buf0_type = CIFS_NO_BUFFER, + }; - sess_data->xid = xid; - sess_data->ses = ses; - sess_data->server = server; - sess_data->buf0_type = CIFS_NO_BUFFER; - sess_data->nls_cp = (struct nls_table *) nls_cp; - - rc = select_sec(sess_data); + rc = select_sec(&sess_data); if (rc) goto out; - while (sess_data->func) - sess_data->func(sess_data); + while (sess_data.func) + sess_data.func(&sess_data); - /* Store result before we free sess_data */ - rc = sess_data->result; + rc = sess_data.result; out: - kfree_sensitive(sess_data); + memzero_explicit(&sess_data, sizeof(sess_data)); return rc; } diff --git a/fs/smb/client/smb2glob.h b/fs/smb/client/smb2glob.h index 19da74b1edab..99c6f5a635fc 100644 --- a/fs/smb/client/smb2glob.h +++ b/fs/smb/client/smb2glob.h @@ -13,6 +13,14 @@ #ifndef _SMB2_GLOB_H #define _SMB2_GLOB_H +#define COMP_PID(cfile) ((cfile) ? (cfile)->fid.persistent_fid : COMPOUND_FID) +#define COMP_VID(cfile) ((cfile) ? (cfile)->fid.volatile_fid : COMPOUND_FID) + +static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) +{ + cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_failed[code]); +} + /* ***************************************************************** * Constants go here diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index f46a62eae659..cc29ff042c56 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -200,9 +200,6 @@ static void set_next_compound(struct cifs_tcon *tcon, (*num_rqst)++; } -#define COMP_PID(cfile) ((cfile) ? (cfile)->fid.persistent_fid : COMPOUND_FID) -#define COMP_VID(cfile) ((cfile) ? (cfile)->fid.volatile_fid : COMPOUND_FID) - /* * note: If cfile is passed, the reference to it is dropped here. * So make sure that you do not reuse cfile after return from this func. @@ -320,7 +317,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, /* Operation */ switch (cmds[i]) { case SMB2_OP_QUERY_INFO: - rqst[num_rqst].rq_iov = &vars->qi_iov; + rqst[num_rqst].rq_iov = vars->qi_iov; rqst[num_rqst].rq_nvec = 1; rc = SMB2_query_info_init(tcon, server, @@ -337,7 +334,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ses->Suid, full_path); break; case SMB2_OP_POSIX_QUERY_INFO: - rqst[num_rqst].rq_iov = &vars->qi_iov; + rqst[num_rqst].rq_iov = vars->qi_iov; rqst[num_rqst].rq_nvec = 1; /* TBD: fix following to allow for longer SIDs */ diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 279c41893f8e..20624f5dff9b 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1186,11 +1186,10 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -static int -smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, - const char *path, const char *ea_name, const void *ea_value, - const __u16 ea_value_len, const struct nls_table *nls_codepage, - struct cifs_sb_info *cifs_sb) +static int smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, + const char *path, const char *ea_name, + const void *ea_value, const __u16 ea_value_len, + struct cifs_sb_info *cifs_sb) { struct smb2_compound_vars *vars; struct cifs_ses *ses = tcon->ses; @@ -1728,7 +1727,7 @@ smb2_ioctl_query_info(const unsigned int xid, SMB2_O_INFO_FILE, 0, data, size); free_req1_func = SMB2_set_info_free; } else if (qi.flags == PASSTHRU_QUERY_INFO) { - rqst[1].rq_iov = &vars->qi_iov; + rqst[1].rq_iov = vars->qi_iov; rqst[1].rq_nvec = 1; rc = SMB2_query_info_init(tcon, server, @@ -3026,7 +3025,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, goto qic_exit; smb2_set_next_command(tcon, &rqst[0]); - rqst[1].rq_iov = &vars->qi_iov; + rqst[1].rq_iov = vars->qi_iov; rqst[1].rq_nvec = 1; if (cfid) { @@ -5265,9 +5264,10 @@ static void smb2_decrypt_offload(struct work_struct *work) dw->server->lstrp = jiffies; mid = smb2_find_dequeue_mid(dw->server, dw->buf); - if (mid == NULL) + if (mid == NULL) { cifs_dbg(FYI, "mid not found\n"); - else { + smb2_add_credits_from_hdr(dw->buf, dw->server); + } else { mid->decrypted = true; rc = handle_read_data(dw->server, mid, dw->buf, dw->server->vals->read_rsp_size, @@ -5398,6 +5398,8 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, *mid = smb2_find_mid(server, buf); if (*mid == NULL) { cifs_dbg(FYI, "mid not found\n"); + smb2_add_credits_from_hdr(buf, server); + rc = -1; } else { cifs_dbg(FYI, "mid found\n"); (*mid)->decrypted = true; @@ -5811,8 +5813,8 @@ struct smb_version_operations smb20_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, @@ -5914,8 +5916,8 @@ struct smb_version_operations smb21_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, @@ -6021,8 +6023,8 @@ struct smb_version_operations smb30_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, @@ -6137,8 +6139,8 @@ struct smb_version_operations smb311_operations = { .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, .get_reparse_point_buffer = smb2_get_reparse_point_buffer, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, + .query_mf_symlink = smb2_query_mf_symlink, + .create_mf_symlink = smb2_create_mf_symlink, .create_reparse_inode = smb2_create_reparse_inode, .open = smb2_open_file, .set_fid = smb2_set_fid, diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index cfe3c4b4abe7..b140ec0a71a8 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -395,7 +395,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, } } - rc = cifs_setup_session(0, ses, server, ses->local_nls); + rc = cifs_setup_session(0, ses, server); if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) { /* * Try alternate password for next reconnect (key rotation @@ -960,7 +960,6 @@ static void decode_signing_ctx(struct TCP_Server_Info *server, return; } - server->signing_negotiated = true; server->signing_algorithm = le16_to_cpu(pctxt->SigningAlgorithms[0]); cifs_dbg(FYI, "signing algorithm %d chosen\n", server->signing_algorithm); @@ -1530,7 +1529,6 @@ struct SMB2_sess_data { unsigned int xid; struct cifs_ses *ses; struct TCP_Server_Info *server; - struct nls_table *nls_cp; void (*func)(struct SMB2_sess_data *); int result; u64 previous_session; @@ -1834,8 +1832,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) goto out_err; rc = build_ntlmssp_smb3_negotiate_blob(&ntlmssp_blob, - &blob_length, ses, server, - sess_data->nls_cp); + &blob_length, ses, server); if (rc) goto out; @@ -1919,8 +1916,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) req->hdr.SessionId = cpu_to_le64(ses->Suid); rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, - ses, server, - sess_data->nls_cp); + ses, server); if (rc) { cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc); goto out; @@ -2005,13 +2001,11 @@ SMB2_select_sec(struct SMB2_sess_data *sess_data) return 0; } -int -SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) +int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server) { + struct SMB2_sess_data sess_data; int rc = 0; - struct SMB2_sess_data *sess_data; cifs_dbg(FYI, "Session Setup\n"); @@ -2020,18 +2014,15 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, return smb_EIO(smb_eio_trace_null_pointers); } - sess_data = kzalloc_obj(struct SMB2_sess_data); - if (!sess_data) - return -ENOMEM; + sess_data = (struct SMB2_sess_data) { + .xid = xid, + .ses = ses, + .server = server, + .buf0_type = CIFS_NO_BUFFER, + .previous_session = ses->Suid, + }; - sess_data->xid = xid; - sess_data->ses = ses; - sess_data->server = server; - sess_data->buf0_type = CIFS_NO_BUFFER; - sess_data->nls_cp = (struct nls_table *) nls_cp; - sess_data->previous_session = ses->Suid; - - rc = SMB2_select_sec(sess_data); + rc = SMB2_select_sec(&sess_data); if (rc) goto out; @@ -2041,14 +2032,14 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, memcpy(ses->preauth_sha_hash, server->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE); - while (sess_data->func) - sess_data->func(sess_data); + while (sess_data.func) + sess_data.func(&sess_data); if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign)) cifs_server_dbg(VFS, "signing requested but authenticated as guest\n"); - rc = sess_data->result; + rc = sess_data.result; out: - kfree_sensitive(sess_data); + memzero_explicit(&sess_data, sizeof(sess_data)); return rc; } @@ -2113,11 +2104,6 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) return rc; } -static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) -{ - cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_failed[code]); -} - #define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */) /* These are similar values to what Windows uses */ @@ -2128,9 +2114,8 @@ static inline void init_copy_chunk_defaults(struct cifs_tcon *tcon) tcon->max_bytes_copy = 16777216; } -int -SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, - struct cifs_tcon *tcon, const struct nls_table *cp) +int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, + struct cifs_tcon *tcon) { struct smb_rqst rqst; struct smb2_tree_connect_req *req; @@ -2154,7 +2139,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, if (unc_path == NULL) return -ENOMEM; - unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp); + unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), + ses->local_nls); if (unc_path_len <= 0) { rc = -EINVAL; goto free_unc_path; @@ -4581,10 +4567,10 @@ static inline bool smb3_use_rdma_offload(struct cifs_io_parms *io_parms) * To form a chain of read requests, any read requests after the first should * have the end_of_chain boolean set to true. */ -static int -smb2_new_read_req(void **buf, unsigned int *total_len, - struct cifs_io_parms *io_parms, struct cifs_io_subrequest *rdata, - unsigned int remaining_bytes, int request_type) +int smb2_new_read_req(void **buf, unsigned int *total_len, + struct cifs_io_parms *io_parms, + struct cifs_io_subrequest *rdata, + unsigned int remaining_bytes, int request_type) { int rc = -EACCES; struct smb2_read_req *req = NULL; diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index b37a1e3941a1..04e755d2cdd8 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -178,6 +178,9 @@ struct network_resiliency_req { */ #define SMB2_IOCTL_IOV_SIZE 2 +/* extra iov for the alignment padding smb2_set_next_command() may add */ +#define SMB2_QUERY_INFO_IOV_SIZE 2 + /* * PDU query infolevel structure definitions * BB consider moving to a different header diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 2e9f70096825..c79e5cb2ce26 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -91,13 +91,15 @@ int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, struct dentry *source_dentry, const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb); -int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +int smb2_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_written); -int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, +int smb2_query_mf_symlink(const unsigned int xid, + struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, - const unsigned char *path, char *pbuf, + const char *full_path, + struct inode *inode, char *pbuf, unsigned int *pbytes_read); int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_info *cifs_sb); @@ -129,11 +131,10 @@ bool smb2_should_replay(struct cifs_tcon *tcon, int *pretries, int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server); int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp); + struct TCP_Server_Info *server); int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses); int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, - struct cifs_tcon *tcon, const struct nls_table *cp); + struct cifs_tcon *tcon); int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct cifs_open_info_data *buf, @@ -172,6 +173,10 @@ int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst, struct cifs_tcon *tcon, struct TCP_Server_Info *server, u64 persistent_fid, u64 volatile_fid); void SMB2_flush_free(struct smb_rqst *rqst); +int smb2_new_read_req(void **buf, unsigned int *total_len, + struct cifs_io_parms *io_parms, + struct cifs_io_subrequest *rdata, + unsigned int remaining_bytes, int request_type); int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data); diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index bb8d0197cb54..2708bedb49ab 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -30,6 +30,8 @@ EM(smb_eio_trace_ea_next_offset, "ea_next_offset") \ EM(smb_eio_trace_ea_overrun, "ea_overrun") \ EM(smb_eio_trace_extract_will_pin, "extract_will_pin") \ + EM(smb_eio_trace_ffirst_param_area, "ffirst_param_area") \ + EM(smb_eio_trace_fnext_param_area, "fnext_param_area") \ EM(smb_eio_trace_forced_shutdown, "forced_shutdown") \ EM(smb_eio_trace_getacl_bcc_too_small, "getacl_bcc_too_small") \ EM(smb_eio_trace_getcifsacl_param_count, "getcifsacl_param_count") \ diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 93ff6a4dbb35..60699d2799fb 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -174,6 +174,17 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, */ scoped_guard(no_notify_signal) rc = sock_sendmsg(ssocket, smb_msg); + + /* + * If need to reconnect, blame it for any non-interrupt error + * and bail out early, even if -EAGAIN; reconnect will never + * happen in parallel as cifs_reconnect() needs server mutex + * (which we're already holding), so it's pointless to retry. + */ + if (unlikely(rc <= 0 && !is_interrupt_error(rc) && + READ_ONCE(server->tcpStatus) == CifsNeedReconnect)) + return -ECONNRESET; + if (rc == -EAGAIN) { retries++; if (retries >= 14 || @@ -649,6 +660,26 @@ int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *mid) return 0; } +static void cond_sock_shutdown(struct TCP_Server_Info *server) +{ + bool shutdown; + + lockdep_assert_held(&server->_srv_mutex); + + spin_lock(&server->srv_lock); + /* + * No need to check status, ->need_sock_shutdown is only set when it's + * CifsNeedReconnect. + */ + shutdown = server->need_sock_shutdown && server->ssocket; + server->need_sock_shutdown = false; + spin_unlock(&server->srv_lock); + + if (shutdown) + /* Don't release it here/yet! */ + kernel_sock_shutdown(server->ssocket, SHUT_RDWR); +} + /* * Send a SMB request and set the callback function in the mid to handle * the result. Caller is responsible for dealing with timeouts. @@ -719,6 +750,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, revert_current_mid(server, mid->credits); server->sequence_number -= 2; delete_mid(server, mid); + cond_sock_shutdown(server); } cifs_server_unlock(server); @@ -977,6 +1009,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, delete_mid(server, mid[i]); cancelled_mid[i] = true; } + cond_sock_shutdown(server); } cifs_server_unlock(server); diff --git a/fs/smb/client/xattr.c b/fs/smb/client/xattr.c index f6c9343016f7..a1048f2355d9 100644 --- a/fs/smb/client/xattr.c +++ b/fs/smb/client/xattr.c @@ -155,7 +155,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler, if (pTcon->ses->server->ops->set_EA) { rc = pTcon->ses->server->ops->set_EA(xid, pTcon, full_path, name, value, (__u16)size, - cifs_sb->local_nls, cifs_sb); + cifs_sb); if (rc == 0) inode_set_ctime_current(inode); }