diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 9ffc94ac2069..2936b38de98f 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -6215,9 +6215,11 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, int rc = 0; int bytes_returned; int list_len; + u32 ea_list_len; struct fealist *ea_response_data; struct fea *temp_fea; char *temp_ptr; + char *byte_area; char *end_of_smb; __u16 params, byte_count, data_offset; unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0; @@ -6296,9 +6298,19 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, ea_response_data = (struct fealist *) (((char *) &pSMBr->hdr.Protocol) + data_offset); - list_len = le32_to_cpu(ea_response_data->list_len); - cifs_dbg(FYI, "ea length %d\n", list_len); - if (list_len <= 8) { + byte_area = pByteArea(&pSMBr->hdr); + end_of_smb = byte_area + get_bcc(&pSMBr->hdr); + if ((char *)ea_response_data < byte_area || + (char *)ea_response_data > + end_of_smb - sizeof(ea_response_data->list_len)) { + rc = smb_EIO2(smb_eio_trace_qalleas_overlong, + data_offset, get_bcc(&pSMBr->hdr)); + goto QAllEAsOut; + } + + ea_list_len = le32_to_cpu(ea_response_data->list_len); + cifs_dbg(FYI, "%s: ea length: %u\n", __func__, ea_list_len); + if (ea_list_len <= 8) { cifs_dbg(FYI, "empty EA list returned from server\n"); /* didn't find the named attribute */ if (ea_name) @@ -6307,14 +6319,14 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, } /* make sure list_len doesn't go past end of SMB */ - end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); - if ((char *)ea_response_data + list_len > end_of_smb) { + if (ea_list_len > end_of_smb - (char *)ea_response_data) { cifs_dbg(FYI, "EA list appears to go beyond SMB\n"); rc = smb_EIO2(smb_eio_trace_qalleas_overlong, - (unsigned long)ea_response_data + list_len - (unsigned long)pSMBr, - (unsigned long)end_of_smb - (unsigned long)pSMBr); + ea_list_len, + end_of_smb - (char *)ea_response_data); goto QAllEAsOut; } + list_len = ea_list_len; /* account for ea list len */ list_len -= 4;