Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: cifs: fix length checks in checkSMB [CIFS] Update cifs minor version cifs: No need to check crypto blockcipher allocation cifs: clean up some compiler warnings cifs: make CIFS depend on CRYPTO_MD4 cifs: force a reconnect if there are too many MIDs in flight cifs: don't pop a printk when sending on a socket is interrupted cifs: simplify SMB header check routine cifs: send an NT_CANCEL request when a process is signalled cifs: handle cancelled requests better cifs: fix two compiler warning about uninitialized vars
This commit is contained in:
commit
405b864d3f
@ -3,6 +3,7 @@ config CIFS
|
||||
depends on INET
|
||||
select NLS
|
||||
select CRYPTO
|
||||
select CRYPTO_MD4
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_ARC4
|
||||
|
@ -282,8 +282,6 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
cFYI(1, "in %s", __func__);
|
||||
BUG_ON(IS_ROOT(mntpt));
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
/*
|
||||
* The MSDFS spec states that paths in DFS referral requests and
|
||||
* responses must be prefixed by a single '\' character instead of
|
||||
@ -293,7 +291,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
mnt = ERR_PTR(-ENOMEM);
|
||||
full_path = build_path_from_dentry(mntpt);
|
||||
if (full_path == NULL)
|
||||
goto free_xid;
|
||||
goto cdda_exit;
|
||||
|
||||
cifs_sb = CIFS_SB(mntpt->d_inode->i_sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
@ -303,9 +301,11 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
}
|
||||
ses = tlink_tcon(tlink)->ses;
|
||||
|
||||
xid = GetXid();
|
||||
rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
|
||||
&num_referrals, &referrals,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
FreeXid(xid);
|
||||
|
||||
cifs_put_tlink(tlink);
|
||||
|
||||
@ -338,8 +338,7 @@ success:
|
||||
free_dfs_info_array(referrals, num_referrals);
|
||||
free_full_path:
|
||||
kfree(full_path);
|
||||
free_xid:
|
||||
FreeXid(xid);
|
||||
cdda_exit:
|
||||
cFYI(1, "leaving %s" , __func__);
|
||||
return mnt;
|
||||
}
|
||||
|
@ -657,9 +657,10 @@ calc_seckey(struct cifsSesInfo *ses)
|
||||
get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
|
||||
|
||||
tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
|
||||
if (IS_ERR(tfm_arc4)) {
|
||||
rc = PTR_ERR(tfm_arc4);
|
||||
cERROR(1, "could not allocate crypto API arc4\n");
|
||||
return PTR_ERR(tfm_arc4);
|
||||
return rc;
|
||||
}
|
||||
|
||||
desc.tfm = tfm_arc4;
|
||||
|
@ -127,5 +127,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.69"
|
||||
#define CIFS_VERSION "1.70"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -4914,7 +4914,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
|
||||
__u16 fid, __u32 pid_of_opener, bool SetAllocation)
|
||||
{
|
||||
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
||||
char *data_offset;
|
||||
struct file_end_of_file_info *parm_data;
|
||||
int rc = 0;
|
||||
__u16 params, param_offset, offset, byte_count, count;
|
||||
@ -4938,8 +4937,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
|
||||
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
||||
offset = param_offset + params;
|
||||
|
||||
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
|
||||
|
||||
count = sizeof(struct file_end_of_file_info);
|
||||
pSMB->MaxParameterCount = cpu_to_le16(2);
|
||||
/* BB find exact max SMB PDU from sess structure BB */
|
||||
|
@ -346,7 +346,6 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
struct cifsTconInfo *tcon;
|
||||
struct tcon_link *tlink;
|
||||
struct cifsFileInfo *pCifsFile = NULL;
|
||||
struct cifsInodeInfo *pCifsInode;
|
||||
char *full_path = NULL;
|
||||
bool posix_open_ok = false;
|
||||
__u16 netfid;
|
||||
@ -361,8 +360,6 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
}
|
||||
tcon = tlink_tcon(tlink);
|
||||
|
||||
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
|
||||
|
||||
full_path = build_path_from_dentry(file->f_path.dentry);
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
@ -1146,7 +1143,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
||||
char *write_data;
|
||||
int rc = -EFAULT;
|
||||
int bytes_written = 0;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *inode;
|
||||
struct cifsFileInfo *open_file;
|
||||
|
||||
@ -1154,7 +1150,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
||||
return -EFAULT;
|
||||
|
||||
inode = page->mapping->host;
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
|
||||
offset += (loff_t)from;
|
||||
write_data = kmap(page);
|
||||
@ -1667,7 +1662,8 @@ static ssize_t
|
||||
cifs_iovec_write(struct file *file, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t *poffset)
|
||||
{
|
||||
size_t total_written = 0, written = 0;
|
||||
size_t total_written = 0;
|
||||
unsigned int written = 0;
|
||||
unsigned long num_pages, npages;
|
||||
size_t copied, len, cur_len, i;
|
||||
struct kvec *to_send;
|
||||
|
@ -55,8 +55,9 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
|
||||
|
||||
md5 = crypto_alloc_shash("md5", 0, 0);
|
||||
if (IS_ERR(md5)) {
|
||||
rc = PTR_ERR(md5);
|
||||
cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
|
||||
return PTR_ERR(md5);
|
||||
return rc;
|
||||
}
|
||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
|
||||
sdescmd5 = kmalloc(size, GFP_KERNEL);
|
||||
|
116
fs/cifs/misc.c
116
fs/cifs/misc.c
@ -236,10 +236,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
|
||||
{
|
||||
__u16 mid = 0;
|
||||
__u16 last_mid;
|
||||
int collision;
|
||||
|
||||
if (server == NULL)
|
||||
return mid;
|
||||
bool collision;
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
last_mid = server->CurrentMid; /* we do not want to loop forever */
|
||||
@ -252,24 +249,38 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
|
||||
(and it would also have to have been a request that
|
||||
did not time out) */
|
||||
while (server->CurrentMid != last_mid) {
|
||||
struct list_head *tmp;
|
||||
struct mid_q_entry *mid_entry;
|
||||
unsigned int num_mids;
|
||||
|
||||
collision = 0;
|
||||
collision = false;
|
||||
if (server->CurrentMid == 0)
|
||||
server->CurrentMid++;
|
||||
|
||||
list_for_each(tmp, &server->pending_mid_q) {
|
||||
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
|
||||
|
||||
if ((mid_entry->mid == server->CurrentMid) &&
|
||||
(mid_entry->midState == MID_REQUEST_SUBMITTED)) {
|
||||
num_mids = 0;
|
||||
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
|
||||
++num_mids;
|
||||
if (mid_entry->mid == server->CurrentMid &&
|
||||
mid_entry->midState == MID_REQUEST_SUBMITTED) {
|
||||
/* This mid is in use, try a different one */
|
||||
collision = 1;
|
||||
collision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (collision == 0) {
|
||||
|
||||
/*
|
||||
* if we have more than 32k mids in the list, then something
|
||||
* is very wrong. Possibly a local user is trying to DoS the
|
||||
* box by issuing long-running calls and SIGKILL'ing them. If
|
||||
* we get to 2^16 mids then we're in big trouble as this
|
||||
* function could loop forever.
|
||||
*
|
||||
* Go ahead and assign out the mid in this situation, but force
|
||||
* an eventual reconnect to clean out the pending_mid_q.
|
||||
*/
|
||||
if (num_mids > 32768)
|
||||
server->tcpStatus = CifsNeedReconnect;
|
||||
|
||||
if (!collision) {
|
||||
mid = server->CurrentMid;
|
||||
break;
|
||||
}
|
||||
@ -381,29 +392,31 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
||||
}
|
||||
|
||||
static int
|
||||
checkSMBhdr(struct smb_hdr *smb, __u16 mid)
|
||||
check_smb_hdr(struct smb_hdr *smb, __u16 mid)
|
||||
{
|
||||
/* Make sure that this really is an SMB, that it is a response,
|
||||
and that the message ids match */
|
||||
if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
|
||||
(mid == smb->Mid)) {
|
||||
if (smb->Flags & SMBFLG_RESPONSE)
|
||||
return 0;
|
||||
else {
|
||||
/* only one valid case where server sends us request */
|
||||
if (smb->Command == SMB_COM_LOCKING_ANDX)
|
||||
return 0;
|
||||
else
|
||||
cERROR(1, "Received Request not response");
|
||||
}
|
||||
} else { /* bad signature or mid */
|
||||
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
|
||||
cERROR(1, "Bad protocol string signature header %x",
|
||||
*(unsigned int *) smb->Protocol);
|
||||
if (mid != smb->Mid)
|
||||
cERROR(1, "Mids do not match");
|
||||
/* does it have the right SMB "signature" ? */
|
||||
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
|
||||
cERROR(1, "Bad protocol string signature header 0x%x",
|
||||
*(unsigned int *)smb->Protocol);
|
||||
return 1;
|
||||
}
|
||||
cERROR(1, "bad smb detected. The Mid=%d", smb->Mid);
|
||||
|
||||
/* Make sure that message ids match */
|
||||
if (mid != smb->Mid) {
|
||||
cERROR(1, "Mids do not match. received=%u expected=%u",
|
||||
smb->Mid, mid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if it's a response then accept */
|
||||
if (smb->Flags & SMBFLG_RESPONSE)
|
||||
return 0;
|
||||
|
||||
/* only one valid case where server sends us request */
|
||||
if (smb->Command == SMB_COM_LOCKING_ANDX)
|
||||
return 0;
|
||||
|
||||
cERROR(1, "Server sent request, not response. mid=%u", smb->Mid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -448,7 +461,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (checkSMBhdr(smb, mid))
|
||||
if (check_smb_hdr(smb, mid))
|
||||
return 1;
|
||||
clc_len = smbCalcSize_LE(smb);
|
||||
|
||||
@ -465,25 +478,26 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
|
||||
if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
|
||||
return 0; /* bcc wrapped */
|
||||
}
|
||||
cFYI(1, "Calculated size %d vs length %d mismatch for mid %d",
|
||||
cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u",
|
||||
clc_len, 4 + len, smb->Mid);
|
||||
/* Windows XP can return a few bytes too much, presumably
|
||||
an illegal pad, at the end of byte range lock responses
|
||||
so we allow for that three byte pad, as long as actual
|
||||
received length is as long or longer than calculated length */
|
||||
/* We have now had to extend this more, since there is a
|
||||
case in which it needs to be bigger still to handle a
|
||||
malformed response to transact2 findfirst from WinXP when
|
||||
access denied is returned and thus bcc and wct are zero
|
||||
but server says length is 0x21 bytes too long as if the server
|
||||
forget to reset the smb rfc1001 length when it reset the
|
||||
wct and bcc to minimum size and drop the t2 parms and data */
|
||||
if ((4+len > clc_len) && (len <= clc_len + 512))
|
||||
return 0;
|
||||
else {
|
||||
cERROR(1, "RFC1001 size %d bigger than SMB for Mid=%d",
|
||||
|
||||
if (4 + len < clc_len) {
|
||||
cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u",
|
||||
len, smb->Mid);
|
||||
return 1;
|
||||
} else if (len > clc_len + 512) {
|
||||
/*
|
||||
* Some servers (Windows XP in particular) send more
|
||||
* data than the lengths in the SMB packet would
|
||||
* indicate on certain calls (byte range locks and
|
||||
* trans2 find first calls in particular). While the
|
||||
* client can handle such a frame by ignoring the
|
||||
* trailing data, we choose limit the amount of extra
|
||||
* data to 512 bytes.
|
||||
*/
|
||||
cERROR(1, "RFC1001 size %u more than 512 bytes larger "
|
||||
"than SMB for mid=%u", len, smb->Mid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -764,7 +764,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
||||
{
|
||||
int rc = 0;
|
||||
int xid, i;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct cifsFileInfo *cifsFile = NULL;
|
||||
char *current_entry;
|
||||
@ -775,8 +774,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
|
||||
/*
|
||||
* Ensure FindFirst doesn't fail before doing filldir() for '.' and
|
||||
* '..'. Otherwise we won't be able to notify VFS in case of failure.
|
||||
|
@ -58,8 +58,9 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
|
||||
|
||||
md4 = crypto_alloc_shash("md4", 0, 0);
|
||||
if (IS_ERR(md4)) {
|
||||
rc = PTR_ERR(md4);
|
||||
cERROR(1, "%s: Crypto md4 allocation error %d\n", __func__, rc);
|
||||
return PTR_ERR(md4);
|
||||
return rc;
|
||||
}
|
||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(md4);
|
||||
sdescmd4 = kmalloc(size, GFP_KERNEL);
|
||||
|
@ -236,9 +236,9 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
|
||||
server->tcpStatus = CifsNeedReconnect;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
if (rc < 0 && rc != -EINTR)
|
||||
cERROR(1, "Error %d sending data on socket to server", rc);
|
||||
} else
|
||||
else
|
||||
rc = 0;
|
||||
|
||||
/* Don't want to modify the buffer as a
|
||||
@ -570,17 +570,33 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
#endif
|
||||
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
cifs_small_buf_release(in_buf);
|
||||
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
cifs_small_buf_release(in_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (long_op == CIFS_ASYNC_OP)
|
||||
if (long_op == CIFS_ASYNC_OP) {
|
||||
cifs_small_buf_release(in_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wait_for_response(ses->server, midQ);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
if (rc != 0) {
|
||||
send_nt_cancel(ses->server, in_buf, midQ);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
midQ->callback = DeleteMidQEntry;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
cifs_small_buf_release(in_buf);
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
|
||||
cifs_small_buf_release(in_buf);
|
||||
|
||||
rc = sync_mid_result(midQ, ses->server);
|
||||
if (rc != 0) {
|
||||
@ -724,8 +740,19 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
goto out;
|
||||
|
||||
rc = wait_for_response(ses->server, midQ);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
if (rc != 0) {
|
||||
send_nt_cancel(ses->server, in_buf, midQ);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = DeleteMidQEntry;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
|
||||
rc = sync_mid_result(midQ, ses->server);
|
||||
if (rc != 0) {
|
||||
@ -922,10 +949,21 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||
}
|
||||
}
|
||||
|
||||
if (wait_for_response(ses->server, midQ) == 0) {
|
||||
/* We got the response - restart system call. */
|
||||
rstart = 1;
|
||||
rc = wait_for_response(ses->server, midQ);
|
||||
if (rc) {
|
||||
send_nt_cancel(ses->server, in_buf, midQ);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = DeleteMidQEntry;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
|
||||
/* We got the response - restart system call. */
|
||||
rstart = 1;
|
||||
}
|
||||
|
||||
rc = sync_mid_result(midQ, ses->server);
|
||||
|
Loading…
Reference in New Issue
Block a user