diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-09-15 01:33:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-09-15 01:33:42 -0400 |
commit | 3a5af36b6d0e4a42ec2a8552ace87edbe2a90ae4 (patch) | |
tree | 08bf6540e9930a4095ae4e9a027d98cb0b112381 | |
parent | 589109df31843384f410ba09f6b8383464408d1e (diff) | |
parent | 097f5863b1a0c9901f180bbd56ae7d630655faaa (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/Kconfig | 1 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 11 | ||||
-rw-r--r-- | fs/cifs/misc.c | 8 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 11 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 29 |
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 | } |