Skip to content

Commit c2e99d4

Browse files
namjaejeonSteve French
authored andcommitted
ksmbd: check strictly data area in ksmbd_smb2_check_message()
When invalid data offset and data length in request, ksmbd_smb2_check_message check strictly and doesn't allow to process such requests. Cc: Tom Talpey <[email protected]> Cc: Ronnie Sahlberg <[email protected]> Cc: Ralph Böhme <[email protected]> Acked-by: Hyunchul Lee <[email protected]> Reviewed-by: Ralph Boehme <[email protected]> Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 3639999 commit c2e99d4

File tree

1 file changed

+47
-51
lines changed

1 file changed

+47
-51
lines changed

fs/ksmbd/smb2misc.c

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,21 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
8080
};
8181

8282
/*
83-
* Returns the pointer to the beginning of the data area. Length of the data
84-
* area and the offset to it (from the beginning of the smb are also returned.
83+
* Set length of the data area and the offset to arguments.
84+
* if they are invalid, return error.
8585
*/
86-
static char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
86+
static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
87+
struct smb2_hdr *hdr)
8788
{
89+
int ret = 0;
90+
8891
*off = 0;
8992
*len = 0;
9093

9194
/* error reqeusts do not have data area */
9295
if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
9396
(((struct smb2_err_rsp *)hdr)->StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2_LE)
94-
return NULL;
97+
return ret;
9598

9699
/*
97100
* Following commands have data areas so we have to get the location
@@ -165,69 +168,60 @@ static char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
165168
case SMB2_IOCTL:
166169
*off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset);
167170
*len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount);
168-
169171
break;
170172
default:
171173
ksmbd_debug(SMB, "no length check for command\n");
172174
break;
173175
}
174176

175-
/*
176-
* Invalid length or offset probably means data area is invalid, but
177-
* we have little choice but to ignore the data area in this case.
178-
*/
179177
if (*off > 4096) {
180-
ksmbd_debug(SMB, "offset %d too large, data area ignored\n",
181-
*off);
182-
*len = 0;
183-
*off = 0;
184-
} else if (*off < 0) {
185-
ksmbd_debug(SMB,
186-
"negative offset %d to data invalid ignore data area\n",
187-
*off);
188-
*off = 0;
189-
*len = 0;
190-
} else if (*len < 0) {
191-
ksmbd_debug(SMB,
192-
"negative data length %d invalid, data area ignored\n",
193-
*len);
194-
*len = 0;
195-
} else if (*len > 128 * 1024) {
196-
ksmbd_debug(SMB, "data area larger than 128K: %d\n", *len);
197-
*len = 0;
178+
ksmbd_debug(SMB, "offset %d too large\n", *off);
179+
ret = -EINVAL;
180+
} else if ((u64)*off + *len > MAX_STREAM_PROT_LEN) {
181+
ksmbd_debug(SMB, "Request is larger than maximum stream protocol length(%u): %llu\n",
182+
MAX_STREAM_PROT_LEN, (u64)*off + *len);
183+
ret = -EINVAL;
198184
}
199185

200-
/* return pointer to beginning of data area, ie offset from SMB start */
201-
if ((*off != 0) && (*len != 0))
202-
return (char *)hdr + *off;
203-
else
204-
return NULL;
186+
return ret;
205187
}
206188

207189
/*
208190
* Calculate the size of the SMB message based on the fixed header
209191
* portion, the number of word parameters and the data portion of the message.
210192
*/
211-
static unsigned int smb2_calc_size(void *buf)
193+
static int smb2_calc_size(void *buf, unsigned int *len)
212194
{
213195
struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
214196
struct smb2_hdr *hdr = &pdu->hdr;
215-
int offset; /* the offset from the beginning of SMB to data area */
216-
int data_length; /* the length of the variable length data area */
197+
unsigned int offset; /* the offset from the beginning of SMB to data area */
198+
unsigned int data_length; /* the length of the variable length data area */
199+
int ret;
200+
217201
/* Structure Size has already been checked to make sure it is 64 */
218-
int len = le16_to_cpu(hdr->StructureSize);
202+
*len = le16_to_cpu(hdr->StructureSize);
219203

220204
/*
221205
* StructureSize2, ie length of fixed parameter area has already
222206
* been checked to make sure it is the correct length.
223207
*/
224-
len += le16_to_cpu(pdu->StructureSize2);
208+
*len += le16_to_cpu(pdu->StructureSize2);
209+
/*
210+
* StructureSize2 of smb2_lock pdu is set to 48, indicating
211+
* the size of smb2 lock request with single smb2_lock_element
212+
* regardless of number of locks. Subtract single
213+
* smb2_lock_element for correct buffer size check.
214+
*/
215+
if (hdr->Command == SMB2_LOCK)
216+
*len -= sizeof(struct smb2_lock_element);
225217

226218
if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)
227219
goto calc_size_exit;
228220

229-
smb2_get_data_area_len(&offset, &data_length, hdr);
230-
ksmbd_debug(SMB, "SMB2 data length %d offset %d\n", data_length,
221+
ret = smb2_get_data_area_len(&offset, &data_length, hdr);
222+
if (ret)
223+
return ret;
224+
ksmbd_debug(SMB, "SMB2 data length %u offset %u\n", data_length,
231225
offset);
232226

233227
if (data_length > 0) {
@@ -237,16 +231,19 @@ static unsigned int smb2_calc_size(void *buf)
237231
* for some commands, typically those with odd StructureSize,
238232
* so we must add one to the calculation.
239233
*/
240-
if (offset + 1 < len)
234+
if (offset + 1 < *len) {
241235
ksmbd_debug(SMB,
242-
"data area offset %d overlaps SMB2 header %d\n",
243-
offset + 1, len);
244-
else
245-
len = offset + data_length;
236+
"data area offset %d overlaps SMB2 header %u\n",
237+
offset + 1, *len);
238+
return -EINVAL;
239+
}
240+
241+
*len = offset + data_length;
246242
}
243+
247244
calc_size_exit:
248-
ksmbd_debug(SMB, "SMB2 len %d\n", len);
249-
return len;
245+
ksmbd_debug(SMB, "SMB2 len %u\n", *len);
246+
return 0;
250247
}
251248

252249
static inline int smb2_query_info_req_len(struct smb2_query_info_req *h)
@@ -391,9 +388,11 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
391388
return 1;
392389
}
393390

394-
clc_len = smb2_calc_size(hdr);
391+
if (smb2_calc_size(hdr, &clc_len))
392+
return 1;
393+
395394
if (len != clc_len) {
396-
/* server can return one byte more due to implied bcc[0] */
395+
/* client can return one byte more due to implied bcc[0] */
397396
if (clc_len == len + 1)
398397
return 0;
399398

@@ -418,9 +417,6 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
418417
return 0;
419418
}
420419

421-
if (command == SMB2_LOCK_HE && len == 88)
422-
return 0;
423-
424420
ksmbd_debug(SMB,
425421
"cli req too short, len %d not %d. cmd:%d mid:%llu\n",
426422
len, clc_len, command,

0 commit comments

Comments
 (0)