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:
Linus Torvalds 2011-02-02 10:22:40 +11:00
commit 405b864d3f
11 changed files with 130 additions and 85 deletions

View File

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

View File

@ -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 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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