diff options
| author | Dan Carpenter <dan.carpenter@oracle.com> | 2018-09-06 05:48:22 -0400 |
|---|---|---|
| committer | Steve French <stfrench@microsoft.com> | 2018-09-12 10:32:07 -0400 |
| commit | 56446f218af1133c802dad8e9e116f07f381846c (patch) | |
| tree | 1f35fa87689fcfdb7eead9d9e0b12164ce384e33 | |
| parent | 8ad8aa353524d89fa2e09522f3078166ff78ec42 (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.c | 25 |
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 | } |
