diff options
author | Jeff Layton <jlayton@redhat.com> | 2010-02-10 16:18:26 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2010-02-23 15:47:11 -0500 |
commit | 0cd126b504cede8a74acf7583a44eba32f9a1da1 (patch) | |
tree | c62a5835dbc50a2d5958a29ef511b349dff2842d | |
parent | e529614ad0c2bf1f3a6fcf1402aa77430ecfaa2c (diff) |
cifs: verify lengths of QueryAllEAs reply
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@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifssmb.c | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4f24f83ce623..e197e1647d5d 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -5285,6 +5285,7 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | |||
5285 | struct fealist *ea_response_data; | 5285 | struct fealist *ea_response_data; |
5286 | struct fea *temp_fea; | 5286 | struct fea *temp_fea; |
5287 | char *temp_ptr; | 5287 | char *temp_ptr; |
5288 | char *end_of_smb; | ||
5288 | __u16 params, byte_count, data_offset; | 5289 | __u16 params, byte_count, data_offset; |
5289 | 5290 | ||
5290 | cFYI(1, ("In Query All EAs path %s", searchName)); | 5291 | cFYI(1, ("In Query All EAs path %s", searchName)); |
@@ -5368,22 +5369,47 @@ QAllEAsRetry: | |||
5368 | goto QAllEAsOut; | 5369 | goto QAllEAsOut; |
5369 | } | 5370 | } |
5370 | 5371 | ||
5372 | /* make sure list_len doesn't go past end of SMB */ | ||
5373 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); | ||
5374 | if ((char *)ea_response_data + list_len > end_of_smb) { | ||
5375 | cFYI(1, ("EA list appears to go beyond SMB")); | ||
5376 | rc = -EIO; | ||
5377 | goto QAllEAsOut; | ||
5378 | } | ||
5379 | |||
5371 | /* account for ea list len */ | 5380 | /* account for ea list len */ |
5372 | list_len -= 4; | 5381 | list_len -= 4; |
5373 | temp_fea = ea_response_data->list; | 5382 | temp_fea = ea_response_data->list; |
5374 | temp_ptr = (char *)temp_fea; | 5383 | temp_ptr = (char *)temp_fea; |
5375 | while (list_len > 0) { | 5384 | while (list_len > 0) { |
5385 | __u8 name_len; | ||
5376 | __u16 value_len; | 5386 | __u16 value_len; |
5387 | |||
5377 | list_len -= 4; | 5388 | list_len -= 4; |
5378 | temp_ptr += 4; | 5389 | temp_ptr += 4; |
5379 | rc += temp_fea->name_len; | 5390 | /* make sure we can read name_len and value_len */ |
5391 | if (list_len < 0) { | ||
5392 | cFYI(1, ("EA entry goes beyond length of list")); | ||
5393 | rc = -EIO; | ||
5394 | goto QAllEAsOut; | ||
5395 | } | ||
5396 | |||
5397 | name_len = temp_fea->name_len; | ||
5398 | value_len = le16_to_cpu(temp_fea->value_len); | ||
5399 | list_len -= name_len + 1 + value_len; | ||
5400 | if (list_len < 0) { | ||
5401 | cFYI(1, ("EA entry goes beyond length of list")); | ||
5402 | rc = -EIO; | ||
5403 | goto QAllEAsOut; | ||
5404 | } | ||
5405 | |||
5380 | /* account for prefix user. and trailing null */ | 5406 | /* account for prefix user. and trailing null */ |
5381 | rc = rc + 5 + 1; | 5407 | rc += (5 + 1 + name_len); |
5382 | if (rc < (int) buf_size) { | 5408 | if (rc < (int) buf_size) { |
5383 | memcpy(EAData, "user.", 5); | 5409 | memcpy(EAData, "user.", 5); |
5384 | EAData += 5; | 5410 | EAData += 5; |
5385 | memcpy(EAData, temp_ptr, temp_fea->name_len); | 5411 | memcpy(EAData, temp_ptr, name_len); |
5386 | EAData += temp_fea->name_len; | 5412 | EAData += name_len; |
5387 | /* null terminate name */ | 5413 | /* null terminate name */ |
5388 | *EAData = 0; | 5414 | *EAData = 0; |
5389 | ++EAData; | 5415 | ++EAData; |
@@ -5394,20 +5420,7 @@ QAllEAsRetry: | |||
5394 | rc = -ERANGE; | 5420 | rc = -ERANGE; |
5395 | break; | 5421 | break; |
5396 | } | 5422 | } |
5397 | list_len -= temp_fea->name_len; | 5423 | temp_ptr += name_len + 1 + value_len; |
5398 | temp_ptr += temp_fea->name_len; | ||
5399 | /* account for trailing null */ | ||
5400 | list_len--; | ||
5401 | temp_ptr++; | ||
5402 | value_len = le16_to_cpu(temp_fea->value_len); | ||
5403 | list_len -= value_len; | ||
5404 | temp_ptr += value_len; | ||
5405 | /* BB check that temp_ptr is still | ||
5406 | within the SMB BB*/ | ||
5407 | |||
5408 | /* no trailing null to account for | ||
5409 | in value len */ | ||
5410 | /* go on to next EA */ | ||
5411 | temp_fea = (struct fea *)temp_ptr; | 5424 | temp_fea = (struct fea *)temp_ptr; |
5412 | } | 5425 | } |
5413 | 5426 | ||