@@ -80,18 +80,21 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
80
80
};
81
81
82
82
/*
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 .
85
85
*/
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 )
87
88
{
89
+ int ret = 0 ;
90
+
88
91
* off = 0 ;
89
92
* len = 0 ;
90
93
91
94
/* error reqeusts do not have data area */
92
95
if (hdr -> Status && hdr -> Status != STATUS_MORE_PROCESSING_REQUIRED &&
93
96
(((struct smb2_err_rsp * )hdr )-> StructureSize ) == SMB2_ERROR_STRUCTURE_SIZE2_LE )
94
- return NULL ;
97
+ return ret ;
95
98
96
99
/*
97
100
* 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)
165
168
case SMB2_IOCTL :
166
169
* off = le32_to_cpu (((struct smb2_ioctl_req * )hdr )-> InputOffset );
167
170
* len = le32_to_cpu (((struct smb2_ioctl_req * )hdr )-> InputCount );
168
-
169
171
break ;
170
172
default :
171
173
ksmbd_debug (SMB , "no length check for command\n" );
172
174
break ;
173
175
}
174
176
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
- */
179
177
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 ;
198
184
}
199
185
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 ;
205
187
}
206
188
207
189
/*
208
190
* Calculate the size of the SMB message based on the fixed header
209
191
* portion, the number of word parameters and the data portion of the message.
210
192
*/
211
- static unsigned int smb2_calc_size (void * buf )
193
+ static int smb2_calc_size (void * buf , unsigned int * len )
212
194
{
213
195
struct smb2_pdu * pdu = (struct smb2_pdu * )buf ;
214
196
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
+
217
201
/* 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 );
219
203
220
204
/*
221
205
* StructureSize2, ie length of fixed parameter area has already
222
206
* been checked to make sure it is the correct length.
223
207
*/
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 );
225
217
226
218
if (has_smb2_data_area [le16_to_cpu (hdr -> Command )] == false)
227
219
goto calc_size_exit ;
228
220
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 ,
231
225
offset );
232
226
233
227
if (data_length > 0 ) {
@@ -237,16 +231,19 @@ static unsigned int smb2_calc_size(void *buf)
237
231
* for some commands, typically those with odd StructureSize,
238
232
* so we must add one to the calculation.
239
233
*/
240
- if (offset + 1 < len )
234
+ if (offset + 1 < * len ) {
241
235
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 ;
246
242
}
243
+
247
244
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 ;
250
247
}
251
248
252
249
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)
391
388
return 1 ;
392
389
}
393
390
394
- clc_len = smb2_calc_size (hdr );
391
+ if (smb2_calc_size (hdr , & clc_len ))
392
+ return 1 ;
393
+
395
394
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] */
397
396
if (clc_len == len + 1 )
398
397
return 0 ;
399
398
@@ -418,9 +417,6 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
418
417
return 0 ;
419
418
}
420
419
421
- if (command == SMB2_LOCK_HE && len == 88 )
422
- return 0 ;
423
-
424
420
ksmbd_debug (SMB ,
425
421
"cli req too short, len %d not %d. cmd:%d mid:%llu\n" ,
426
422
len , clc_len , command ,
0 commit comments