diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-11 14:53:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-11 14:53:42 -0400 |
commit | 33807f4f0daec3b00565c2932d95f614f5833adf (patch) | |
tree | 07a90339612d799a56ce74fad0d4d27c943b875b /fs | |
parent | adf961d7e8006d2cb16ceee07582b145b9ef69f7 (diff) | |
parent | dca1c8d17a2feae056f9e334ea75a462ae4cb52a (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.h | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 24 | ||||
-rw-r--r-- | fs/cifs/transport.c | 29 |
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 { | |||
513 | static inline unsigned int | 513 | static inline unsigned int |
514 | get_rfc1002_length(void *buf) | 514 | get_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 | ||
519 | static inline void | 519 | static 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 | ||
273 | static unsigned long | ||
274 | rqst_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 | |||
273 | static int | 293 | static int |
274 | smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | 294 | smb_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 | ||