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
This commit is contained in:
commit
c2bf807eb3
2 changed files with 72 additions and 69 deletions
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
|
||||||
mid_entry->largeBuf = isLargeBuf;
|
|
||||||
multi_t2_fnd:
|
|
||||||
if (length == 0)
|
|
||||||
mid_entry->midState =
|
|
||||||
MID_RESPONSE_RECEIVED;
|
|
||||||
else
|
|
||||||
mid_entry->midState =
|
|
||||||
MID_RESPONSE_MALFORMED;
|
|
||||||
#ifdef CONFIG_CIFS_STATS2
|
|
||||||
mid_entry->when_received = jiffies;
|
|
||||||
#endif
|
|
||||||
list_del_init(&mid_entry->qhead);
|
|
||||||
mid_entry->callback(mid_entry);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mid_entry = NULL;
|
mid_entry->resp_buf = smb_buffer;
|
||||||
|
mid_entry->largeBuf = isLargeBuf;
|
||||||
|
multi_t2_fnd:
|
||||||
|
if (length == 0)
|
||||||
|
mid_entry->midState = MID_RESPONSE_RECEIVED;
|
||||||
|
else
|
||||||
|
mid_entry->midState = MID_RESPONSE_MALFORMED;
|
||||||
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
|
mid_entry->when_received = jiffies;
|
||||||
|
#endif
|
||||||
|
list_del_init(&mid_entry->qhead);
|
||||||
|
mid_entry->callback(mid_entry);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
Loading…
Reference in a new issue