Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2bf807e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 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
parents a3a4a5ac 16541ba1
Loading
Loading
Loading
Loading
+67 −53
Original line number Diff line number Diff line
@@ -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_buf2;
	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);

@@ -287,7 +288,7 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
	remaining = total_data_size - total_in_buf;

	if (remaining < 0)
		return -EINVAL;
		return -EPROTO;

	if (remaining == 0) /* nothing to do, ignore */
		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;

	/* 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;
	/* 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);

	/* fix up the BCC */
	byte_count = get_bcc_le(pTargetSMB);
	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);

	byte_count = pTargetSMB->smb_buf_length;
	byte_count += total_in_buf2;

	/* BB also add check that we are not beyond maximum buffer size */

	/* don't allow buffer to overflow */
	if (byte_count > CIFSMaxBufSize)
		return -ENOBUFS;
	pTargetSMB->smb_buf_length = byte_count;

	memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);

	if (remaining == total_in_buf2) {
		cFYI(1, "found the last secondary response");
		return 0; /* we are done */
@@ -607,37 +617,45 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);

			if ((mid_entry->mid == smb_buffer->Mid) &&
			    (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
			    (mid_entry->command == smb_buffer->Command)) {
			if (mid_entry->mid != smb_buffer->Mid ||
			    mid_entry->midState != MID_REQUEST_SUBMITTED ||
			    mid_entry->command != smb_buffer->Command) {
				mid_entry = NULL;
				continue;
			}

			if (length == 0 &&
			    check2ndT2(smb_buffer, server->maxBuf) > 0) {
				/* We have a multipart transact2 resp */
				isMultiRsp = true;
				if (mid_entry->resp_buf) {
					/* merge response - fix up 1st*/
						if (coalesce_t2(smb_buffer,
							mid_entry->resp_buf)) {
							mid_entry->multiRsp =
								 true;
					length = coalesce_t2(smb_buffer,
							mid_entry->resp_buf);
					if (length > 0) {
						length = 0;
						mid_entry->multiRsp = true;
						break;
					} else {
							/* all parts received */
							mid_entry->multiEnd =
								 true;
						/* all parts received or
						 * packet is malformed
						 */
						mid_entry->multiEnd = true;
						goto multi_t2_fnd;
					}
				} else {
					if (!isLargeBuf) {
							cERROR(1, "1st trans2 resp needs bigbuf");
					/* BB maybe we can fix this up,  switch
					   to already allocated large buffer? */
						/*
						 * FIXME: switch to already
						 *        allocated largebuf?
						 */
						cERROR(1, "1st trans2 resp "
							  "needs bigbuf");
					} else {
						/* Have first buffer */
						mid_entry->resp_buf =
							 smb_buffer;
							mid_entry->largeBuf =
								 true;
						mid_entry->largeBuf = true;
						bigbuf = NULL;
					}
				}
@@ -647,11 +665,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
			mid_entry->largeBuf = isLargeBuf;
multi_t2_fnd:
			if (length == 0)
					mid_entry->midState =
							MID_RESPONSE_RECEIVED;
				mid_entry->midState = MID_RESPONSE_RECEIVED;
			else
					mid_entry->midState =
							MID_RESPONSE_MALFORMED;
				mid_entry->midState = MID_RESPONSE_MALFORMED;
#ifdef CONFIG_CIFS_STATS2
			mid_entry->when_received = jiffies;
#endif
@@ -659,8 +675,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
			mid_entry->callback(mid_entry);
			break;
		}
			mid_entry = NULL;
		}
		spin_unlock(&GlobalMid_Lock);

		if (mid_entry != NULL) {
+4 −15
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
}

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)
{
	int len;
@@ -284,19 +284,6 @@ decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses,

	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);
	ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp);
	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 */
	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 */
		if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
			++bcc_ptr;