@@ -193,8 +193,9 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
193
193
{
194
194
const struct MFT_REC * rec = mi -> mrec ;
195
195
u32 used = le32_to_cpu (rec -> used );
196
- u32 t32 , off , asize ;
196
+ u32 t32 , off , asize , prev_type ;
197
197
u16 t16 ;
198
+ u64 data_size , alloc_size , tot_size ;
198
199
199
200
if (!attr ) {
200
201
u32 total = le32_to_cpu (rec -> total );
@@ -213,6 +214,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
213
214
if (!is_rec_inuse (rec ))
214
215
return NULL ;
215
216
217
+ prev_type = 0 ;
216
218
attr = Add2Ptr (rec , off );
217
219
} else {
218
220
/* Check if input attr inside record. */
@@ -226,11 +228,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
226
228
return NULL ;
227
229
}
228
230
229
- if ( off + asize < off ) {
230
- /* Overflow check. */
231
+ /* Overflow check. */
232
+ if ( off + asize < off )
231
233
return NULL ;
232
- }
233
234
235
+ prev_type = le32_to_cpu (attr -> type );
234
236
attr = Add2Ptr (attr , asize );
235
237
off += asize ;
236
238
}
@@ -250,7 +252,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
250
252
251
253
/* 0x100 is last known attribute for now. */
252
254
t32 = le32_to_cpu (attr -> type );
253
- if ((t32 & 0xf ) || (t32 > 0x100 ))
255
+ if (!t32 || (t32 & 0xf ) || (t32 > 0x100 ))
256
+ return NULL ;
257
+
258
+ /* attributes in record must be ordered by type */
259
+ if (t32 < prev_type )
254
260
return NULL ;
255
261
256
262
/* Check overflow and boundary. */
@@ -259,16 +265,15 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
259
265
260
266
/* Check size of attribute. */
261
267
if (!attr -> non_res ) {
268
+ /* Check resident fields. */
262
269
if (asize < SIZEOF_RESIDENT )
263
270
return NULL ;
264
271
265
272
t16 = le16_to_cpu (attr -> res .data_off );
266
-
267
273
if (t16 > asize )
268
274
return NULL ;
269
275
270
- t32 = le32_to_cpu (attr -> res .data_size );
271
- if (t16 + t32 > asize )
276
+ if (t16 + le32_to_cpu (attr -> res .data_size ) > asize )
272
277
return NULL ;
273
278
274
279
t32 = sizeof (short ) * attr -> name_len ;
@@ -278,21 +283,52 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
278
283
return attr ;
279
284
}
280
285
281
- /* Check some nonresident fields. */
282
- if (attr -> name_len &&
283
- le16_to_cpu (attr -> name_off ) + sizeof (short ) * attr -> name_len >
284
- le16_to_cpu (attr -> nres .run_off )) {
286
+ /* Check nonresident fields. */
287
+ if (attr -> non_res != 1 )
288
+ return NULL ;
289
+
290
+ t16 = le16_to_cpu (attr -> nres .run_off );
291
+ if (t16 > asize )
292
+ return NULL ;
293
+
294
+ t32 = sizeof (short ) * attr -> name_len ;
295
+ if (t32 && le16_to_cpu (attr -> name_off ) + t32 > t16 )
296
+ return NULL ;
297
+
298
+ /* Check start/end vcn. */
299
+ if (le64_to_cpu (attr -> nres .svcn ) > le64_to_cpu (attr -> nres .evcn ) + 1 )
300
+ return NULL ;
301
+
302
+ data_size = le64_to_cpu (attr -> nres .data_size );
303
+ if (le64_to_cpu (attr -> nres .valid_size ) > data_size )
285
304
return NULL ;
286
- }
287
305
288
- if (attr -> nres .svcn || !is_attr_ext (attr )) {
306
+ alloc_size = le64_to_cpu (attr -> nres .alloc_size );
307
+ if (data_size > alloc_size )
308
+ return NULL ;
309
+
310
+ t32 = mi -> sbi -> cluster_mask ;
311
+ if (alloc_size & t32 )
312
+ return NULL ;
313
+
314
+ if (!attr -> nres .svcn && is_attr_ext (attr )) {
315
+ /* First segment of sparse/compressed attribute */
316
+ if (asize + 8 < SIZEOF_NONRESIDENT_EX )
317
+ return NULL ;
318
+
319
+ tot_size = le64_to_cpu (attr -> nres .total_size );
320
+ if (tot_size & t32 )
321
+ return NULL ;
322
+
323
+ if (tot_size > alloc_size )
324
+ return NULL ;
325
+ } else {
289
326
if (asize + 8 < SIZEOF_NONRESIDENT )
290
327
return NULL ;
291
328
292
329
if (attr -> nres .c_unit )
293
330
return NULL ;
294
- } else if (asize + 8 < SIZEOF_NONRESIDENT_EX )
295
- return NULL ;
331
+ }
296
332
297
333
return attr ;
298
334
}
0 commit comments