diff options
Diffstat (limited to 'fs/smb/server/smb2misc.c')
-rw-r--r-- | fs/smb/server/smb2misc.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c index 23bd3d1209df..727cb49926ee 100644 --- a/fs/smb/server/smb2misc.c +++ b/fs/smb/server/smb2misc.c @@ -101,29 +101,46 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, *len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength); break; case SMB2_TREE_CONNECT: - *off = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset); + *off = max_t(unsigned short int, + le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset), + offsetof(struct smb2_tree_connect_req, Buffer)); *len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength); break; case SMB2_CREATE: { + unsigned short int name_off = + max_t(unsigned short int, + le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset), + offsetof(struct smb2_create_req, Buffer)); + unsigned short int name_len = + le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength); + if (((struct smb2_create_req *)hdr)->CreateContextsLength) { *off = le32_to_cpu(((struct smb2_create_req *) hdr)->CreateContextsOffset); *len = le32_to_cpu(((struct smb2_create_req *) hdr)->CreateContextsLength); - break; + if (!name_len) + break; + + if (name_off + name_len < (u64)*off + *len) + break; } - *off = le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset); - *len = le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength); + *off = name_off; + *len = name_len; break; } case SMB2_QUERY_INFO: - *off = le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset); + *off = max_t(unsigned int, + le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset), + offsetof(struct smb2_query_info_req, Buffer)); *len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength); break; case SMB2_SET_INFO: - *off = le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset); + *off = max_t(unsigned int, + le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset), + offsetof(struct smb2_set_info_req, Buffer)); *len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength); break; case SMB2_READ: @@ -133,7 +150,7 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, case SMB2_WRITE: if (((struct smb2_write_req *)hdr)->DataOffset || ((struct smb2_write_req *)hdr)->Length) { - *off = max_t(unsigned int, + *off = max_t(unsigned short int, le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset), offsetof(struct smb2_write_req, Buffer)); *len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length); @@ -144,7 +161,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, *len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength); break; case SMB2_QUERY_DIRECTORY: - *off = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset); + *off = max_t(unsigned short int, + le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset), + offsetof(struct smb2_query_directory_req, Buffer)); *len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength); break; case SMB2_LOCK: @@ -159,7 +178,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, break; } case SMB2_IOCTL: - *off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset); + *off = max_t(unsigned int, + le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset), + offsetof(struct smb2_ioctl_req, Buffer)); *len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount); break; default: |