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

Commit 33807f4f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

Pull CIFS fixes from Steve French:
 "A fix for the problem which Al spotted in cifs_writev and a followup
  (noticed when fixing CVE-2014-0069) patch to ensure that cifs never
  sends more than the smb frame length over the socket (as we saw with
  that cifs_iovec_write problem that Jeff fixed last month)"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: mask off top byte in get_rfc1002_length()
  cifs: sanity check length of data to send before sending
  CIFS: Fix wrong pos argument of cifs_find_lock_conflict
parents adf961d7 dca1c8d1
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -513,7 +513,7 @@ struct cifs_mnt_data {
static inline unsigned int
static inline unsigned int
get_rfc1002_length(void *buf)
get_rfc1002_length(void *buf)
{
{
	return be32_to_cpu(*((__be32 *)buf));
	return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
}
}


static inline void
static inline void
+6 −18
Original line number Original line Diff line number Diff line
@@ -2579,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
	struct cifsInodeInfo *cinode = CIFS_I(inode);
	struct cifsInodeInfo *cinode = CIFS_I(inode);
	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
	ssize_t rc = -EACCES;
	ssize_t rc = -EACCES;
	loff_t lock_pos = pos;


	BUG_ON(iocb->ki_pos != pos);
	if (file->f_flags & O_APPEND)

		lock_pos = i_size_read(inode);
	/*
	/*
	 * We need to hold the sem to be sure nobody modifies lock list
	 * We need to hold the sem to be sure nobody modifies lock list
	 * with a brlock that prevents writing.
	 * with a brlock that prevents writing.
	 */
	 */
	down_read(&cinode->lock_sem);
	down_read(&cinode->lock_sem);
	if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
	if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
				     server->vals->exclusive_lock_type, NULL,
				     server->vals->exclusive_lock_type, NULL,
				     CIFS_WRITE_OP)) {
				     CIFS_WRITE_OP))
		mutex_lock(&inode->i_mutex);
		rc = generic_file_aio_write(iocb, iov, nr_segs, pos);
		rc = __generic_file_aio_write(iocb, iov, nr_segs,
					       &iocb->ki_pos);
		mutex_unlock(&inode->i_mutex);
	}

	if (rc > 0) {
		ssize_t err;

		err = generic_write_sync(file, iocb->ki_pos - rc, rc);
		if (err < 0)
			rc = err;
	}

	up_read(&cinode->lock_sem);
	up_read(&cinode->lock_sem);
	return rc;
	return rc;
}
}
+29 −0
Original line number Original line Diff line number Diff line
@@ -270,6 +270,26 @@ cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
		iov->iov_len = rqst->rq_pagesz;
		iov->iov_len = rqst->rq_pagesz;
}
}


static unsigned long
rqst_len(struct smb_rqst *rqst)
{
	unsigned int i;
	struct kvec *iov = rqst->rq_iov;
	unsigned long buflen = 0;

	/* total up iov array first */
	for (i = 0; i < rqst->rq_nvec; i++)
		buflen += iov[i].iov_len;

	/* add in the page array if there is one */
	if (rqst->rq_npages) {
		buflen += rqst->rq_pagesz * (rqst->rq_npages - 1);
		buflen += rqst->rq_tailsz;
	}

	return buflen;
}

static int
static int
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{
{
@@ -277,6 +297,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
	struct kvec *iov = rqst->rq_iov;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	int n_vec = rqst->rq_nvec;
	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
	unsigned long send_length;
	unsigned int i;
	unsigned int i;
	size_t total_len = 0, sent;
	size_t total_len = 0, sent;
	struct socket *ssocket = server->ssocket;
	struct socket *ssocket = server->ssocket;
@@ -285,6 +306,14 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
	if (ssocket == NULL)
	if (ssocket == NULL)
		return -ENOTSOCK;
		return -ENOTSOCK;


	/* sanity check send length */
	send_length = rqst_len(rqst);
	if (send_length != smb_buf_length + 4) {
		WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
			send_length, smb_buf_length);
		return -EIO;
	}

	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
	dump_smb(iov[0].iov_base, iov[0].iov_len);
	dump_smb(iov[0].iov_base, iov[0].iov_len);