@@ -294,23 +294,28 @@ static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len,
294
294
* bh passed here can be an inode block or a dir data block, depending
295
295
* on the inode inline data flag.
296
296
*/
297
- static int ocfs2_check_dir_entry (struct inode * dir ,
298
- struct ocfs2_dir_entry * de ,
299
- struct buffer_head * bh ,
297
+ static int ocfs2_check_dir_entry (struct inode * dir ,
298
+ struct ocfs2_dir_entry * de ,
299
+ struct buffer_head * bh ,
300
+ char * buf ,
301
+ unsigned int size ,
300
302
unsigned long offset )
301
303
{
302
304
const char * error_msg = NULL ;
303
305
const int rlen = le16_to_cpu (de -> rec_len );
306
+ const unsigned long next_offset = ((char * ) de - buf ) + rlen ;
304
307
305
308
if (unlikely (rlen < OCFS2_DIR_REC_LEN (1 )))
306
309
error_msg = "rec_len is smaller than minimal" ;
307
310
else if (unlikely (rlen % 4 != 0 ))
308
311
error_msg = "rec_len % 4 != 0" ;
309
312
else if (unlikely (rlen < OCFS2_DIR_REC_LEN (de -> name_len )))
310
313
error_msg = "rec_len is too small for name_len" ;
311
- else if (unlikely (
312
- ((char * ) de - bh -> b_data ) + rlen > dir -> i_sb -> s_blocksize ))
313
- error_msg = "directory entry across blocks" ;
314
+ else if (unlikely (next_offset > size ))
315
+ error_msg = "directory entry overrun" ;
316
+ else if (unlikely (next_offset > size - OCFS2_DIR_REC_LEN (1 )) &&
317
+ next_offset != size )
318
+ error_msg = "directory entry too close to end" ;
314
319
315
320
if (unlikely (error_msg != NULL ))
316
321
mlog (ML_ERROR , "bad entry in directory #%llu: %s - "
@@ -352,16 +357,17 @@ static inline int ocfs2_search_dirblock(struct buffer_head *bh,
352
357
de_buf = first_de ;
353
358
dlimit = de_buf + bytes ;
354
359
355
- while (de_buf < dlimit ) {
360
+ while (de_buf < dlimit - OCFS2_DIR_MEMBER_LEN ) {
356
361
/* this code is executed quadratically often */
357
362
/* do minimal checking `by hand' */
358
363
359
364
de = (struct ocfs2_dir_entry * ) de_buf ;
360
365
361
- if (de_buf + namelen <= dlimit &&
366
+ if (de -> name + namelen <= dlimit &&
362
367
ocfs2_match (namelen , name , de )) {
363
368
/* found a match - just to be sure, do a full check */
364
- if (!ocfs2_check_dir_entry (dir , de , bh , offset )) {
369
+ if (!ocfs2_check_dir_entry (dir , de , bh , first_de ,
370
+ bytes , offset )) {
365
371
ret = -1 ;
366
372
goto bail ;
367
373
}
@@ -1138,7 +1144,7 @@ static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
1138
1144
pde = NULL ;
1139
1145
de = (struct ocfs2_dir_entry * ) first_de ;
1140
1146
while (i < bytes ) {
1141
- if (!ocfs2_check_dir_entry (dir , de , bh , i )) {
1147
+ if (!ocfs2_check_dir_entry (dir , de , bh , first_de , bytes , i )) {
1142
1148
status = - EIO ;
1143
1149
mlog_errno (status );
1144
1150
goto bail ;
@@ -1635,7 +1641,8 @@ int __ocfs2_add_entry(handle_t *handle,
1635
1641
/* These checks should've already been passed by the
1636
1642
* prepare function, but I guess we can leave them
1637
1643
* here anyway. */
1638
- if (!ocfs2_check_dir_entry (dir , de , insert_bh , offset )) {
1644
+ if (!ocfs2_check_dir_entry (dir , de , insert_bh , data_start ,
1645
+ size , offset )) {
1639
1646
retval = - ENOENT ;
1640
1647
goto bail ;
1641
1648
}
@@ -1774,7 +1781,8 @@ static int ocfs2_dir_foreach_blk_id(struct inode *inode,
1774
1781
}
1775
1782
1776
1783
de = (struct ocfs2_dir_entry * ) (data -> id_data + ctx -> pos );
1777
- if (!ocfs2_check_dir_entry (inode , de , di_bh , ctx -> pos )) {
1784
+ if (!ocfs2_check_dir_entry (inode , de , di_bh , (char * )data -> id_data ,
1785
+ i_size_read (inode ), ctx -> pos )) {
1778
1786
/* On error, skip the f_pos to the end. */
1779
1787
ctx -> pos = i_size_read (inode );
1780
1788
break ;
@@ -1867,7 +1875,8 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
1867
1875
while (ctx -> pos < i_size_read (inode )
1868
1876
&& offset < sb -> s_blocksize ) {
1869
1877
de = (struct ocfs2_dir_entry * ) (bh -> b_data + offset );
1870
- if (!ocfs2_check_dir_entry (inode , de , bh , offset )) {
1878
+ if (!ocfs2_check_dir_entry (inode , de , bh , bh -> b_data ,
1879
+ sb -> s_blocksize , offset )) {
1871
1880
/* On error, skip the f_pos to the
1872
1881
next block. */
1873
1882
ctx -> pos = (ctx -> pos | (sb -> s_blocksize - 1 )) + 1 ;
@@ -3339,7 +3348,7 @@ static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
3339
3348
struct super_block * sb = dir -> i_sb ;
3340
3349
struct ocfs2_dinode * di = (struct ocfs2_dinode * )di_bh -> b_data ;
3341
3350
struct ocfs2_dir_entry * de , * last_de = NULL ;
3342
- char * de_buf , * limit ;
3351
+ char * first_de , * de_buf , * limit ;
3343
3352
unsigned long offset = 0 ;
3344
3353
unsigned int rec_len , new_rec_len , free_space ;
3345
3354
@@ -3352,14 +3361,16 @@ static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
3352
3361
else
3353
3362
free_space = dir -> i_sb -> s_blocksize - i_size_read (dir );
3354
3363
3355
- de_buf = di -> id2 .i_data .id_data ;
3364
+ first_de = di -> id2 .i_data .id_data ;
3365
+ de_buf = first_de ;
3356
3366
limit = de_buf + i_size_read (dir );
3357
3367
rec_len = OCFS2_DIR_REC_LEN (namelen );
3358
3368
3359
3369
while (de_buf < limit ) {
3360
3370
de = (struct ocfs2_dir_entry * )de_buf ;
3361
3371
3362
- if (!ocfs2_check_dir_entry (dir , de , di_bh , offset )) {
3372
+ if (!ocfs2_check_dir_entry (dir , de , di_bh , first_de ,
3373
+ i_size_read (dir ), offset )) {
3363
3374
ret = - ENOENT ;
3364
3375
goto out ;
3365
3376
}
@@ -3441,7 +3452,8 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
3441
3452
/* move to next block */
3442
3453
de = (struct ocfs2_dir_entry * ) bh -> b_data ;
3443
3454
}
3444
- if (!ocfs2_check_dir_entry (dir , de , bh , offset )) {
3455
+ if (!ocfs2_check_dir_entry (dir , de , bh , bh -> b_data , blocksize ,
3456
+ offset )) {
3445
3457
status = - ENOENT ;
3446
3458
goto bail ;
3447
3459
}
0 commit comments