summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/smb/client/cifssmb.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index e335686a68f2..9ffc94ac2069 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -3787,9 +3787,10 @@ static int
validate_ntransact(char *buf, char **ppparm, char **ppdata,
__u32 *pparmlen, __u32 *pdatalen)
{
- char *end_of_smb;
__u32 data_count, data_offset, parm_count, parm_offset;
struct smb_com_ntransact_rsp *pSMBr;
+ size_t buflen;
+ char *end_buf;
u16 bcc;
*pdatalen = 0;
@@ -3800,37 +3801,42 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
pSMBr = (struct smb_com_ntransact_rsp *)buf;
+ if (pSMBr->hdr.WordCount != 18) {
+ cifs_dbg(FYI, "invalid NT transaction WordCount %u\n",
+ pSMBr->hdr.WordCount);
+ return -EINVAL;
+ }
+
bcc = get_bcc(&pSMBr->hdr);
- end_of_smb = 2 /* sizeof byte count */ + bcc +
- (char *)&pSMBr->ByteCount;
+ end_buf = 2 /* sizeof byte count */ + bcc + (char *)&pSMBr->ByteCount;
+ buflen = end_buf - buf;
data_offset = le32_to_cpu(pSMBr->DataOffset);
data_count = le32_to_cpu(pSMBr->DataCount);
parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
parm_count = le32_to_cpu(pSMBr->ParameterCount);
- *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
- *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
-
/* should we also check that parm and data areas do not overlap? */
- if (*ppparm > end_of_smb) {
+ if (parm_offset > buflen) {
cifs_dbg(FYI, "parms start after end of smb\n");
return -EINVAL;
- } else if (parm_count + *ppparm > end_of_smb) {
+ } else if (parm_count > buflen - parm_offset) {
cifs_dbg(FYI, "parm end after end of smb\n");
return -EINVAL;
- } else if (*ppdata > end_of_smb) {
+ } else if (data_offset > buflen) {
cifs_dbg(FYI, "data starts after end of smb\n");
return -EINVAL;
- } else if (data_count + *ppdata > end_of_smb) {
- cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
- *ppdata, data_count, (data_count + *ppdata),
- end_of_smb, pSMBr);
+ } else if (data_count > buflen - data_offset) {
+ cifs_dbg(FYI, "data offset %u + count %u past smb length %zu\n",
+ data_offset, data_count, buflen);
return -EINVAL;
} else if (parm_count + data_count > bcc) {
cifs_dbg(FYI, "parm count and data count larger than SMB\n");
return -EINVAL;
}
+
+ *ppparm = buf + parm_offset;
+ *ppdata = buf + data_offset;
*pdatalen = data_count;
*pparmlen = parm_count;
return 0;