[linux-cifs-client] [PATCH 4/4] cifs: verify lengths of QueryAllEAs reply
Jeff Layton
jlayton at redhat.com
Mon Jan 11 14:02:01 MST 2010
Make sure the lengths in a QUERY_ALL_EAS reply don't make the parser walk
off the end of the SMB.
Signed-off-by: Jeff Layton <jlayton at redhat.com>
---
fs/cifs/cifssmb.c | 30 +++++++++++++++++++++++++++---
1 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f5e1527..fb19f43 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5285,6 +5285,7 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
struct fealist *ea_response_data;
struct fea *temp_fea;
char *temp_ptr;
+ char *end_of_smb;
__u16 params, byte_count, data_offset;
cFYI(1, ("In Query All EAs path %s", searchName));
@@ -5360,11 +5361,19 @@ QAllEAsRetry:
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
ea_response_data = (struct fealist *)
(((char *) &pSMBr->hdr.Protocol) + data_offset);
-
list_len = le32_to_cpu(ea_response_data->list_len);
cFYI(1, ("ea length %d", list_len));
if (list_len <= 8) {
cFYI(1, ("empty EA list returned from server"));
+ rc = -EIO;
+ goto QAllEAsOut;
+ }
+
+ /* make sure list_len doesn't go past end of SMB */
+ end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
+ if ((char *)ea_response_data + list_len > end_of_smb) {
+ cFYI(1, ("list_len goes beyond SMB"));
+ rc = -EIO;
goto QAllEAsOut;
}
@@ -5373,10 +5382,26 @@ QAllEAsRetry:
temp_fea = ea_response_data->list;
temp_ptr = (char *)temp_fea;
while (list_len > 0) {
+ __u8 name_len;
__u16 value_len;
list_len -= 4;
temp_ptr += 4;
- rc += temp_fea->name_len;
+ /* make sure we can read name_len and value_len */
+ if (temp_ptr > end_of_smb) {
+ cFYI(1, ("fealist goes beyond end of SMB"));
+ rc = -EIO;
+ goto QAllEAsOut;
+ }
+
+ name_len = temp_fea->name_len;
+ value_len = le16_to_cpu(temp_fea->value_len);
+ if (temp_ptr + name_len + value_len > end_of_smb) {
+ cFYI(1, ("fealist goes beyond end of SMB"));
+ rc = -EIO;
+ goto QAllEAsOut;
+ }
+
+ rc += name_len;
/* account for prefix user. and trailing null */
rc = rc + 5 + 1;
if (rc < (int) buf_size) {
@@ -5399,7 +5424,6 @@ QAllEAsRetry:
/* account for trailing null */
list_len--;
temp_ptr++;
- value_len = le16_to_cpu(temp_fea->value_len);
list_len -= value_len;
temp_ptr += value_len;
/* BB check that temp_ptr is still
--
1.6.5.2
More information about the linux-cifs-client
mailing list