summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-03-11 14:53:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-03-11 14:53:42 -0400
commit33807f4f0daec3b00565c2932d95f614f5833adf (patch)
tree07a90339612d799a56ce74fad0d4d27c943b875b /fs
parentadf961d7e8006d2cb16ceee07582b145b9ef69f7 (diff)
parentdca1c8d17a2feae056f9e334ea75a462ae4cb52a (diff)
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
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/file.c24
-rw-r--r--fs/cifs/transport.c29
3 files changed, 36 insertions, 19 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index cf32f0393369..c0f3718b77a8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -513,7 +513,7 @@ struct cifs_mnt_data {
513static inline unsigned int 513static inline unsigned int
514get_rfc1002_length(void *buf) 514get_rfc1002_length(void *buf)
515{ 515{
516 return be32_to_cpu(*((__be32 *)buf)); 516 return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
517} 517}
518 518
519static inline void 519static inline void
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 53c15074bb36..834fce759d80 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2579,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
2579 struct cifsInodeInfo *cinode = CIFS_I(inode); 2579 struct cifsInodeInfo *cinode = CIFS_I(inode);
2580 struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; 2580 struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
2581 ssize_t rc = -EACCES; 2581 ssize_t rc = -EACCES;
2582 loff_t lock_pos = pos;
2582 2583
2583 BUG_ON(iocb->ki_pos != pos); 2584 if (file->f_flags & O_APPEND)
2584 2585 lock_pos = i_size_read(inode);
2585 /* 2586 /*
2586 * We need to hold the sem to be sure nobody modifies lock list 2587 * We need to hold the sem to be sure nobody modifies lock list
2587 * with a brlock that prevents writing. 2588 * with a brlock that prevents writing.
2588 */ 2589 */
2589 down_read(&cinode->lock_sem); 2590 down_read(&cinode->lock_sem);
2590 if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), 2591 if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
2591 server->vals->exclusive_lock_type, NULL, 2592 server->vals->exclusive_lock_type, NULL,
2592 CIFS_WRITE_OP)) { 2593 CIFS_WRITE_OP))
2593 mutex_lock(&inode->i_mutex); 2594 rc = generic_file_aio_write(iocb, iov, nr_segs, pos);
2594 rc = __generic_file_aio_write(iocb, iov, nr_segs,
2595 &iocb->ki_pos);
2596 mutex_unlock(&inode->i_mutex);
2597 }
2598
2599 if (rc > 0) {
2600 ssize_t err;
2601
2602 err = generic_write_sync(file, iocb->ki_pos - rc, rc);
2603 if (err < 0)
2604 rc = err;
2605 }
2606
2607 up_read(&cinode->lock_sem); 2595 up_read(&cinode->lock_sem);
2608 return rc; 2596 return rc;
2609} 2597}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index b37570952846..18cd5650a5fc 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -270,6 +270,26 @@ cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
270 iov->iov_len = rqst->rq_pagesz; 270 iov->iov_len = rqst->rq_pagesz;
271} 271}
272 272
273static unsigned long
274rqst_len(struct smb_rqst *rqst)
275{
276 unsigned int i;
277 struct kvec *iov = rqst->rq_iov;
278 unsigned long buflen = 0;
279
280 /* total up iov array first */
281 for (i = 0; i < rqst->rq_nvec; i++)
282 buflen += iov[i].iov_len;
283
284 /* add in the page array if there is one */
285 if (rqst->rq_npages) {
286 buflen += rqst->rq_pagesz * (rqst->rq_npages - 1);
287 buflen += rqst->rq_tailsz;
288 }
289
290 return buflen;
291}
292
273static int 293static int
274smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) 294smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
275{ 295{
@@ -277,6 +297,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
277 struct kvec *iov = rqst->rq_iov; 297 struct kvec *iov = rqst->rq_iov;
278 int n_vec = rqst->rq_nvec; 298 int n_vec = rqst->rq_nvec;
279 unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); 299 unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
300 unsigned long send_length;
280 unsigned int i; 301 unsigned int i;
281 size_t total_len = 0, sent; 302 size_t total_len = 0, sent;
282 struct socket *ssocket = server->ssocket; 303 struct socket *ssocket = server->ssocket;
@@ -285,6 +306,14 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
285 if (ssocket == NULL) 306 if (ssocket == NULL)
286 return -ENOTSOCK; 307 return -ENOTSOCK;
287 308
309 /* sanity check send length */
310 send_length = rqst_len(rqst);
311 if (send_length != smb_buf_length + 4) {
312 WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
313 send_length, smb_buf_length);
314 return -EIO;
315 }
316
288 cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length); 317 cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
289 dump_smb(iov[0].iov_base, iov[0].iov_len); 318 dump_smb(iov[0].iov_base, iov[0].iov_len);
290 319