Commit 3a5af36b authored by Linus Torvalds's avatar Linus Torvalds

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
parents 589109df 097f5863
...@@ -6,6 +6,7 @@ config CIFS ...@@ -6,6 +6,7 @@ config CIFS
select CRYPTO_MD4 select CRYPTO_MD4
select CRYPTO_MD5 select CRYPTO_MD5
select CRYPTO_SHA256 select CRYPTO_SHA256
select CRYPTO_SHA512
select CRYPTO_CMAC select CRYPTO_CMAC
select CRYPTO_HMAC select CRYPTO_HMAC
select CRYPTO_ARC4 select CRYPTO_ARC4
......
...@@ -601,10 +601,15 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -601,10 +601,15 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
} }
count = 0; count = 0;
/*
* We know that all the name entries in the protocols array
* are short (< 16 bytes anyway) and are NUL terminated.
*/
for (i = 0; i < CIFS_NUM_PROT; i++) { for (i = 0; i < CIFS_NUM_PROT; i++) {
strncpy(pSMB->DialectsArray+count, protocols[i].name, 16); size_t len = strlen(protocols[i].name) + 1;
count += strlen(protocols[i].name) + 1;
/* null at end of source and target buffers anyway */ memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
count += len;
} }
inc_rfc1001_len(pSMB, count); inc_rfc1001_len(pSMB, count);
pSMB->ByteCount = cpu_to_le16(count); pSMB->ByteCount = cpu_to_le16(count);
......
...@@ -402,9 +402,17 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) ...@@ -402,9 +402,17 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
(struct smb_com_transaction_change_notify_rsp *)buf; (struct smb_com_transaction_change_notify_rsp *)buf;
struct file_notify_information *pnotify; struct file_notify_information *pnotify;
__u32 data_offset = 0; __u32 data_offset = 0;
size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
if (get_bcc(buf) > sizeof(struct file_notify_information)) { if (get_bcc(buf) > sizeof(struct file_notify_information)) {
data_offset = le32_to_cpu(pSMBr->DataOffset); data_offset = le32_to_cpu(pSMBr->DataOffset);
if (data_offset >
len - sizeof(struct file_notify_information)) {
cifs_dbg(FYI, "invalid data_offset %u\n",
data_offset);
return true;
}
pnotify = (struct file_notify_information *) pnotify = (struct file_notify_information *)
((char *)&pSMBr->hdr.Protocol + data_offset); ((char *)&pSMBr->hdr.Protocol + data_offset);
cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n", cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
......
...@@ -376,8 +376,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) ...@@ -376,8 +376,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
pfData->FileNameLength; pfData->FileNameLength;
} else } else {
new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset);
if (old_entry + next_offset < old_entry) {
cifs_dbg(VFS, "invalid offset %u\n", next_offset);
return NULL;
}
new_entry = old_entry + next_offset;
}
cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry); cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry);
/* validate that new_entry is not past end of SMB */ /* validate that new_entry is not past end of SMB */
if (new_entry >= end_of_smb) { if (new_entry >= end_of_smb) {
......
...@@ -2459,14 +2459,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -2459,14 +2459,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
/* We check for obvious errors in the output buffer length and offset */ /* We check for obvious errors in the output buffer length and offset */
if (*plen == 0) if (*plen == 0)
goto ioctl_exit; /* server returned no data */ goto ioctl_exit; /* server returned no data */
else if (*plen > 0xFF00) { else if (*plen > rsp_iov.iov_len || *plen > 0xFF00) {
cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen); cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
*plen = 0; *plen = 0;
rc = -EIO; rc = -EIO;
goto ioctl_exit; goto ioctl_exit;
} }
if (rsp_iov.iov_len < le32_to_cpu(rsp->OutputOffset) + *plen) { if (rsp_iov.iov_len - *plen < le32_to_cpu(rsp->OutputOffset)) {
cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen, cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
le32_to_cpu(rsp->OutputOffset)); le32_to_cpu(rsp->OutputOffset));
*plen = 0; *plen = 0;
...@@ -3577,33 +3577,38 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size) ...@@ -3577,33 +3577,38 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
int len; int len;
unsigned int entrycount = 0; unsigned int entrycount = 0;
unsigned int next_offset = 0; unsigned int next_offset = 0;
FILE_DIRECTORY_INFO *entryptr; char *entryptr;
FILE_DIRECTORY_INFO *dir_info;
if (bufstart == NULL) if (bufstart == NULL)
return 0; return 0;
entryptr = (FILE_DIRECTORY_INFO *)bufstart; entryptr = bufstart;
while (1) { while (1) {
entryptr = (FILE_DIRECTORY_INFO *) if (entryptr + next_offset < entryptr ||
((char *)entryptr + next_offset); entryptr + next_offset > end_of_buf ||
entryptr + next_offset + size > end_of_buf) {
if ((char *)entryptr + size > end_of_buf) {
cifs_dbg(VFS, "malformed search entry would overflow\n"); cifs_dbg(VFS, "malformed search entry would overflow\n");
break; break;
} }
len = le32_to_cpu(entryptr->FileNameLength); entryptr = entryptr + next_offset;
if ((char *)entryptr + len + size > end_of_buf) { dir_info = (FILE_DIRECTORY_INFO *)entryptr;
len = le32_to_cpu(dir_info->FileNameLength);
if (entryptr + len < entryptr ||
entryptr + len > end_of_buf ||
entryptr + len + size > end_of_buf) {
cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n", cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n",
end_of_buf); end_of_buf);
break; break;
} }
*lastentry = (char *)entryptr; *lastentry = entryptr;
entrycount++; entrycount++;
next_offset = le32_to_cpu(entryptr->NextEntryOffset); next_offset = le32_to_cpu(dir_info->NextEntryOffset);
if (!next_offset) if (!next_offset)
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment