aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-09-15 01:33:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-09-15 01:33:42 -0400
commit3a5af36b6d0e4a42ec2a8552ace87edbe2a90ae4 (patch)
tree08bf6540e9930a4095ae4e9a027d98cb0b112381
parent589109df31843384f410ba09f6b8383464408d1e (diff)
parent097f5863b1a0c9901f180bbd56ae7d630655faaa (diff)
Merge tag '4.19-rc3-smb3-cifs' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "Fixes for four CIFS/SMB3 potential pointer overflow issues, one minor build fix, and a build warning cleanup" * tag '4.19-rc3-smb3-cifs' of git://git.samba.org/sfrench/cifs-2.6: cifs: read overflow in is_valid_oplock_break() cifs: integer overflow in in SMB2_ioctl() CIFS: fix wrapping bugs in num_entries() cifs: prevent integer overflow in nxt_dir_entry() fs/cifs: require sha512 fs/cifs: suppress a string overflow warning
-rw-r--r--fs/cifs/Kconfig1
-rw-r--r--fs/cifs/cifssmb.c11
-rw-r--r--fs/cifs/misc.c8
-rw-r--r--fs/cifs/readdir.c11
-rw-r--r--fs/cifs/smb2pdu.c29
5 files changed, 43 insertions, 17 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 35c83fe7dba0..abcd78e332fe 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -6,6 +6,7 @@ config CIFS
6 select CRYPTO_MD4 6 select CRYPTO_MD4
7 select CRYPTO_MD5 7 select CRYPTO_MD5
8 select CRYPTO_SHA256 8 select CRYPTO_SHA256
9 select CRYPTO_SHA512
9 select CRYPTO_CMAC 10 select CRYPTO_CMAC
10 select CRYPTO_HMAC 11 select CRYPTO_HMAC
11 select CRYPTO_ARC4 12 select CRYPTO_ARC4
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index dc2f4cf08fe9..5657b79dbc99 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -601,10 +601,15 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
601 } 601 }
602 602
603 count = 0; 603 count = 0;
604 /*
605 * We know that all the name entries in the protocols array
606 * are short (< 16 bytes anyway) and are NUL terminated.
607 */
604 for (i = 0; i < CIFS_NUM_PROT; i++) { 608 for (i = 0; i < CIFS_NUM_PROT; i++) {
605 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16); 609 size_t len = strlen(protocols[i].name) + 1;
606 count += strlen(protocols[i].name) + 1; 610
607 /* null at end of source and target buffers anyway */ 611 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
612 count += len;
608 } 613 }
609 inc_rfc1001_len(pSMB, count); 614 inc_rfc1001_len(pSMB, count);
610 pSMB->ByteCount = cpu_to_le16(count); 615 pSMB->ByteCount = cpu_to_le16(count);
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index dacb2c05674c..6926685e513c 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -402,9 +402,17 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
402 (struct smb_com_transaction_change_notify_rsp *)buf; 402 (struct smb_com_transaction_change_notify_rsp *)buf;
403 struct file_notify_information *pnotify; 403 struct file_notify_information *pnotify;
404 __u32 data_offset = 0; 404 __u32 data_offset = 0;
405 size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
406
405 if (get_bcc(buf) > sizeof(struct file_notify_information)) { 407 if (get_bcc(buf) > sizeof(struct file_notify_information)) {
406 data_offset = le32_to_cpu(pSMBr->DataOffset); 408 data_offset = le32_to_cpu(pSMBr->DataOffset);
407 409
410 if (data_offset >
411 len - sizeof(struct file_notify_information)) {
412 cifs_dbg(FYI, "invalid data_offset %u\n",
413 data_offset);
414 return true;
415 }
408 pnotify = (struct file_notify_information *) 416 pnotify = (struct file_notify_information *)
409 ((char *)&pSMBr->hdr.Protocol + data_offset); 417 ((char *)&pSMBr->hdr.Protocol + data_offset);
410 cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n", 418 cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index eeab81c9452f..e169e1a5fd35 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -376,8 +376,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
376 376
377 new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + 377 new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
378 pfData->FileNameLength; 378 pfData->FileNameLength;
379 } else 379 } else {
380 new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); 380 u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset);
381
382 if (old_entry + next_offset < old_entry) {
383 cifs_dbg(VFS, "invalid offset %u\n", next_offset);
384 return NULL;
385 }
386 new_entry = old_entry + next_offset;
387 }
381 cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry); 388 cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry);
382 /* validate that new_entry is not past end of SMB */ 389 /* validate that new_entry is not past end of SMB */
383 if (new_entry >= end_of_smb) { 390 if (new_entry >= end_of_smb) {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index c08acfc77abc..f54d07bda067 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2459,14 +2459,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
2459 /* We check for obvious errors in the output buffer length and offset */ 2459 /* We check for obvious errors in the output buffer length and offset */
2460 if (*plen == 0) 2460 if (*plen == 0)
2461 goto ioctl_exit; /* server returned no data */ 2461 goto ioctl_exit; /* server returned no data */
2462 else if (*plen > 0xFF00) { 2462 else if (*plen > rsp_iov.iov_len || *plen > 0xFF00) {
2463 cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen); 2463 cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
2464 *plen = 0; 2464 *plen = 0;
2465 rc = -EIO; 2465 rc = -EIO;
2466 goto ioctl_exit; 2466 goto ioctl_exit;
2467 } 2467 }
2468 2468
2469 if (rsp_iov.iov_len < le32_to_cpu(rsp->OutputOffset) + *plen) { 2469 if (rsp_iov.iov_len - *plen < le32_to_cpu(rsp->OutputOffset)) {
2470 cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen, 2470 cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
2471 le32_to_cpu(rsp->OutputOffset)); 2471 le32_to_cpu(rsp->OutputOffset));
2472 *plen = 0; 2472 *plen = 0;
@@ -3577,33 +3577,38 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
3577 int len; 3577 int len;
3578 unsigned int entrycount = 0; 3578 unsigned int entrycount = 0;
3579 unsigned int next_offset = 0; 3579 unsigned int next_offset = 0;
3580 FILE_DIRECTORY_INFO *entryptr; 3580 char *entryptr;
3581 FILE_DIRECTORY_INFO *dir_info;
3581 3582
3582 if (bufstart == NULL) 3583 if (bufstart == NULL)
3583 return 0; 3584 return 0;
3584 3585
3585 entryptr = (FILE_DIRECTORY_INFO *)bufstart; 3586 entryptr = bufstart;
3586 3587
3587 while (1) { 3588 while (1) {
3588 entryptr = (FILE_DIRECTORY_INFO *) 3589 if (entryptr + next_offset < entryptr ||
3589 ((char *)entryptr + next_offset); 3590 entryptr + next_offset > end_of_buf ||
3590 3591 entryptr + next_offset + size > end_of_buf) {
3591 if ((char *)entryptr + size > end_of_buf) {
3592 cifs_dbg(VFS, "malformed search entry would overflow\n"); 3592 cifs_dbg(VFS, "malformed search entry would overflow\n");
3593 break; 3593 break;
3594 } 3594 }
3595 3595
3596 len = le32_to_cpu(entryptr->FileNameLength); 3596 entryptr = entryptr + next_offset;
3597 if ((char *)entryptr + len + size > end_of_buf) { 3597 dir_info = (FILE_DIRECTORY_INFO *)entryptr;
3598
3599 len = le32_to_cpu(dir_info->FileNameLength);
3600 if (entryptr + len < entryptr ||
3601 entryptr + len > end_of_buf ||
3602 entryptr + len + size > end_of_buf) {
3598 cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n", 3603 cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n",
3599 end_of_buf); 3604 end_of_buf);
3600 break; 3605 break;
3601 } 3606 }
3602 3607
3603 *lastentry = (char *)entryptr; 3608 *lastentry = entryptr;
3604 entrycount++; 3609 entrycount++;
3605 3610
3606 next_offset = le32_to_cpu(entryptr->NextEntryOffset); 3611 next_offset = le32_to_cpu(dir_info->NextEntryOffset);
3607 if (!next_offset) 3612 if (!next_offset)
3608 break; 3613 break;
3609 } 3614 }