- Implement ->fileattr_set so chattr(1) compression changes (chattr +c/-c)

go through the generic VFS fileattr path and its permission and
    serialization checks instead of the raw FS_IOC_SETFLAGS fallback and
    remove the now-unreachable file flags ioctl handlers
 
  - Require stable pages when the connection is signed or SMB compression is
    enabled, so a buffered write can no longer modify a folio that is still in
    flight and corrupt its signature (surfaced as -EIO) or, with compression,
    silently corrupt the data stored on the server
 
  - Stop breaking a file's just-granted lease while probing it for a
    Minshall+French symlink, by reusing an already open handle or opening with
    the inode's lease key
 
  - Fix several out-of-bounds reads and use-after-free bug in SMB1
 
  - Fix an use-after-free bug in cifs_ses_add_channel()
 
  - Fix a NULL pointer dereference in the demultiplex thread when an encrypted
    read response matches no outstanding request and reclaim the credits
    granted on such responses to avoid starving the connection of credits
 
  - Fail sends fast when the connection needs to reconnect
 
  - Drop the redundant nls_table argument threaded through the session setup,
    tree connect and path-based call paths, allocate the session setup state
    on the stack and remove the internal CIFS version number along with a
    batch of write-only fields and commented-out code
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTcqRusfSdYROJQwGkpVtNKoQNdYwUCatK1agAKCRApVtNKoQNd
 Y/FwAQDau9Sqjpvi+QC4zYlzFj2WOkrqnHJhEFa2Tel8/VA9lgD9EORPujWKd1d4
 BO0sbFjv7wnc5sFN60AdUIUL1fOJKAM=
 =i2jV
 -----END PGP SIGNATURE-----

Merge tag 'cifs-for-7.4' of https://git.manguebit.org/linux

Pull smb client updates from Paulo Alcantara:

 - Implement ->fileattr_set so chattr(1) compression changes (chattr
   +c/-c) go through the generic VFS fileattr path and its permission
   and serialization checks instead of the raw FS_IOC_SETFLAGS fallback
   and remove the now-unreachable file flags ioctl handlers

 - Require stable pages when the connection is signed or SMB compression
   is enabled, so a buffered write can no longer modify a folio that is
   still in flight and corrupt its signature (surfaced as -EIO) or, with
   compression, silently corrupt the data stored on the server

 - Stop breaking a file's just-granted lease while probing it for a
   Minshall+French symlink, by reusing an already open handle or opening
   with the inode's lease key

 - Fix several out-of-bounds reads and use-after-free bug in SMB1

 - Fix an use-after-free bug in cifs_ses_add_channel()

 - Fix a NULL pointer dereference in the demultiplex thread when an
   encrypted read response matches no outstanding request and reclaim
   the credits granted on such responses to avoid starving the
   connection of credits

 - Fail sends fast when the connection needs to reconnect

 - Drop the redundant nls_table argument threaded through the session
   setup, tree connect and path-based call paths, allocate the session
   setup state on the stack and remove the internal CIFS version number
   along with a batch of write-only fields and commented-out code

* tag 'cifs-for-7.4' of https://git.manguebit.org/linux: (61 commits)
  smb: client: reclaim credits for decrypted reads with no matching mid
  smb: client: do not pass a NULL buf to is_oplock_break()
  smb: client: require stable pages for SMB compression
  smb: client: allocate struct SMB2_sess_data on the stack
  smb: client: allocate struct sess_data on the stack
  smb: client: drop redundant nls_table arg from CIFSSMBRenameOpenFile()
  smb: client: drop redundant nls_table arg from SMBLegacyOpen()
  smb: client: drop redundant nls_table arg from CIFSPOSIXCreate()
  smb: client: drop redundant nls_table arg from CIFSPOSIXDelFile()
  smb: client: drop redundant nls_table arg from ->tree_connect()
  smb: client: drop redundant nls_table arg from cifs_setup_session()
  smb: client: drop redundant nls_table arg from ->sess_setup()
  smb: client: drop unused nls_table arg from decode_ascii_ssetup()
  smb: client: drop redundant nls_table arg from decode_unicode_ssetup()
  smb: client: drop unused nls_table arg from ascii_ssetup_strings()
  smb: client: drop redundant nls_table arg from unicode_ssetup_strings()
  smb: client: drop unused nls_table arg from ascii_domain_string()
  smb: client: drop redundant nls_table arg from unicode_domain_string()
  smb: client: drop unused nls_table arg from ascii_oslm_strings()
  smb: client: drop redundant nls_table arg from build_ntlmssp_auth_blob()
  ...
This commit is contained in:
Linus Torvalds 2026-10-20 16:16:00 -10:00
commit 32543b0968
32 changed files with 740 additions and 549 deletions

View File

@ -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)

View File

@ -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");

View File

@ -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;

View File

@ -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");

View File

@ -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 */

View File

@ -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];

View File

@ -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,

View File

@ -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 {

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */
}

View File

@ -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,

View File

@ -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 */

View File

@ -10,6 +10,7 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/fileattr.h>
#include <linux/mount.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
@ -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, &current_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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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) &&

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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") \

View File

@ -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);

View File

@ -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);
}