提交 c2bf807e 编写于 作者: L Linus Torvalds

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: handle errors from coalesce_t2
  cifs: refactor mid finding loop in cifs_demultiplex_thread
  cifs: sanitize length checking in coalesce_t2 (try #3)
  cifs: check for bytes_remaining going to zero in CIFS_SessSetup
  cifs: change bleft in decode_unicode_ssetup back to signed type
...@@ -274,7 +274,8 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) ...@@ -274,7 +274,8 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
char *data_area_of_target; char *data_area_of_target;
char *data_area_of_buf2; char *data_area_of_buf2;
int remaining; int remaining;
__u16 byte_count, total_data_size, total_in_buf, total_in_buf2; unsigned int byte_count, total_in_buf;
__u16 total_data_size, total_in_buf2;
total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
...@@ -287,7 +288,7 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) ...@@ -287,7 +288,7 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
remaining = total_data_size - total_in_buf; remaining = total_data_size - total_in_buf;
if (remaining < 0) if (remaining < 0)
return -EINVAL; return -EPROTO;
if (remaining == 0) /* nothing to do, ignore */ if (remaining == 0) /* nothing to do, ignore */
return 0; return 0;
...@@ -308,20 +309,29 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) ...@@ -308,20 +309,29 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
data_area_of_target += total_in_buf; data_area_of_target += total_in_buf;
/* copy second buffer into end of first buffer */ /* copy second buffer into end of first buffer */
memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
total_in_buf += total_in_buf2; total_in_buf += total_in_buf2;
/* is the result too big for the field? */
if (total_in_buf > USHRT_MAX)
return -EPROTO;
put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
/* fix up the BCC */
byte_count = get_bcc_le(pTargetSMB); byte_count = get_bcc_le(pTargetSMB);
byte_count += total_in_buf2; byte_count += total_in_buf2;
/* is the result too big for the field? */
if (byte_count > USHRT_MAX)
return -EPROTO;
put_bcc_le(byte_count, pTargetSMB); put_bcc_le(byte_count, pTargetSMB);
byte_count = pTargetSMB->smb_buf_length; byte_count = pTargetSMB->smb_buf_length;
byte_count += total_in_buf2; byte_count += total_in_buf2;
/* don't allow buffer to overflow */
/* BB also add check that we are not beyond maximum buffer size */ if (byte_count > CIFSMaxBufSize)
return -ENOBUFS;
pTargetSMB->smb_buf_length = byte_count; pTargetSMB->smb_buf_length = byte_count;
memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
if (remaining == total_in_buf2) { if (remaining == total_in_buf2) {
cFYI(1, "found the last secondary response"); cFYI(1, "found the last secondary response");
return 0; /* we are done */ return 0; /* we are done */
...@@ -607,59 +617,63 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -607,59 +617,63 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if ((mid_entry->mid == smb_buffer->Mid) && if (mid_entry->mid != smb_buffer->Mid ||
(mid_entry->midState == MID_REQUEST_SUBMITTED) && mid_entry->midState != MID_REQUEST_SUBMITTED ||
(mid_entry->command == smb_buffer->Command)) { mid_entry->command != smb_buffer->Command) {
if (length == 0 && mid_entry = NULL;
check2ndT2(smb_buffer, server->maxBuf) > 0) { continue;
/* We have a multipart transact2 resp */ }
isMultiRsp = true;
if (mid_entry->resp_buf) { if (length == 0 &&
/* merge response - fix up 1st*/ check2ndT2(smb_buffer, server->maxBuf) > 0) {
if (coalesce_t2(smb_buffer, /* We have a multipart transact2 resp */
mid_entry->resp_buf)) { isMultiRsp = true;
mid_entry->multiRsp = if (mid_entry->resp_buf) {
true; /* merge response - fix up 1st*/
break; length = coalesce_t2(smb_buffer,
} else { mid_entry->resp_buf);
/* all parts received */ if (length > 0) {
mid_entry->multiEnd = length = 0;
true; mid_entry->multiRsp = true;
goto multi_t2_fnd; break;
}
} else { } else {
if (!isLargeBuf) { /* all parts received or
cERROR(1, "1st trans2 resp needs bigbuf"); * packet is malformed
/* BB maybe we can fix this up, switch */
to already allocated large buffer? */ mid_entry->multiEnd = true;
} else { goto multi_t2_fnd;
/* Have first buffer */ }
mid_entry->resp_buf = } else {
smb_buffer; if (!isLargeBuf) {
mid_entry->largeBuf = /*
true; * FIXME: switch to already
bigbuf = NULL; * allocated largebuf?
} */
cERROR(1, "1st trans2 resp "
"needs bigbuf");
} else {
/* Have first buffer */
mid_entry->resp_buf =
smb_buffer;
mid_entry->largeBuf = true;
bigbuf = NULL;
} }
break;
} }
mid_entry->resp_buf = smb_buffer; break;
mid_entry->largeBuf = isLargeBuf; }
mid_entry->resp_buf = smb_buffer;
mid_entry->largeBuf = isLargeBuf;
multi_t2_fnd: multi_t2_fnd:
if (length == 0) if (length == 0)
mid_entry->midState = mid_entry->midState = MID_RESPONSE_RECEIVED;
MID_RESPONSE_RECEIVED; else
else mid_entry->midState = MID_RESPONSE_MALFORMED;
mid_entry->midState =
MID_RESPONSE_MALFORMED;
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
mid_entry->when_received = jiffies; mid_entry->when_received = jiffies;
#endif #endif
list_del_init(&mid_entry->qhead); list_del_init(&mid_entry->qhead);
mid_entry->callback(mid_entry); mid_entry->callback(mid_entry);
break; break;
}
mid_entry = NULL;
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
......
...@@ -276,7 +276,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, ...@@ -276,7 +276,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
} }
static void static void
decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses, decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
const struct nls_table *nls_cp) const struct nls_table *nls_cp)
{ {
int len; int len;
...@@ -284,19 +284,6 @@ decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses, ...@@ -284,19 +284,6 @@ decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses,
cFYI(1, "bleft %d", bleft); cFYI(1, "bleft %d", bleft);
/*
* Windows servers do not always double null terminate their final
* Unicode string. Check to see if there are an uneven number of bytes
* left. If so, then add an extra NULL pad byte to the end of the
* response.
*
* See section 2.7.2 in "Implementing CIFS" for details
*/
if (bleft % 2) {
data[bleft] = 0;
++bleft;
}
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp);
cFYI(1, "serverOS=%s", ses->serverOS); cFYI(1, "serverOS=%s", ses->serverOS);
...@@ -929,7 +916,9 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -929,7 +916,9 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
} }
/* BB check if Unicode and decode strings */ /* BB check if Unicode and decode strings */
if (smb_buf->Flags2 & SMBFLG2_UNICODE) { if (bytes_remaining == 0) {
/* no string area to decode, do nothing */
} else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
/* unicode string area must be word-aligned */ /* unicode string area must be word-aligned */
if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
++bcc_ptr; ++bcc_ptr;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册