aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Carpenter <dan.carpenter@oracle.com>2018-09-06 05:48:22 -0400
committerSteve French <stfrench@microsoft.com>2018-09-12 10:32:07 -0400
commit56446f218af1133c802dad8e9e116f07f381846c (patch)
tree1f35fa87689fcfdb7eead9d9e0b12164ce384e33
parent8ad8aa353524d89fa2e09522f3078166ff78ec42 (diff)
CIFS: fix wrapping bugs in num_entries()
The problem is that "entryptr + next_offset" and "entryptr + len + size" can wrap. I ended up changing the type of "entryptr" because it makes the math easier when we don't have to do so much casting. Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com> CC: Stable <stable@vger.kernel.org>
-rw-r--r--fs/cifs/smb2pdu.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index c08acfc77abc..6f0e6b42599c 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -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 }