@@ -294,23 +294,28 @@ static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len,
294294 * bh passed here can be an inode block or a dir data block, depending
295295 * on the inode inline data flag.
296296 */
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 ,
300302 unsigned long offset )
301303{
302304 const char * error_msg = NULL ;
303305 const int rlen = le16_to_cpu (de -> rec_len );
306+ const unsigned long next_offset = ((char * ) de - buf ) + rlen ;
304307
305308 if (unlikely (rlen < OCFS2_DIR_REC_LEN (1 )))
306309 error_msg = "rec_len is smaller than minimal" ;
307310 else if (unlikely (rlen % 4 != 0 ))
308311 error_msg = "rec_len % 4 != 0" ;
309312 else if (unlikely (rlen < OCFS2_DIR_REC_LEN (de -> name_len )))
310313 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" ;
314319
315320 if (unlikely (error_msg != NULL ))
316321 mlog (ML_ERROR , "bad entry in directory #%llu: %s - "
@@ -352,16 +357,17 @@ static inline int ocfs2_search_dirblock(struct buffer_head *bh,
352357 de_buf = first_de ;
353358 dlimit = de_buf + bytes ;
354359
355- while (de_buf < dlimit ) {
360+ while (de_buf < dlimit - OCFS2_DIR_MEMBER_LEN ) {
356361 /* this code is executed quadratically often */
357362 /* do minimal checking `by hand' */
358363
359364 de = (struct ocfs2_dir_entry * ) de_buf ;
360365
361- if (de_buf + namelen <= dlimit &&
366+ if (de -> name + namelen <= dlimit &&
362367 ocfs2_match (namelen , name , de )) {
363368 /* 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 )) {
365371 ret = -1 ;
366372 goto bail ;
367373 }
@@ -1138,7 +1144,7 @@ static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
11381144 pde = NULL ;
11391145 de = (struct ocfs2_dir_entry * ) first_de ;
11401146 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 )) {
11421148 status = - EIO ;
11431149 mlog_errno (status );
11441150 goto bail ;
@@ -1635,7 +1641,8 @@ int __ocfs2_add_entry(handle_t *handle,
16351641 /* These checks should've already been passed by the
16361642 * prepare function, but I guess we can leave them
16371643 * 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 )) {
16391646 retval = - ENOENT ;
16401647 goto bail ;
16411648 }
@@ -1774,7 +1781,8 @@ static int ocfs2_dir_foreach_blk_id(struct inode *inode,
17741781 }
17751782
17761783 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 )) {
17781786 /* On error, skip the f_pos to the end. */
17791787 ctx -> pos = i_size_read (inode );
17801788 break ;
@@ -1867,7 +1875,8 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
18671875 while (ctx -> pos < i_size_read (inode )
18681876 && offset < sb -> s_blocksize ) {
18691877 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 )) {
18711880 /* On error, skip the f_pos to the
18721881 next block. */
18731882 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,
33393348 struct super_block * sb = dir -> i_sb ;
33403349 struct ocfs2_dinode * di = (struct ocfs2_dinode * )di_bh -> b_data ;
33413350 struct ocfs2_dir_entry * de , * last_de = NULL ;
3342- char * de_buf , * limit ;
3351+ char * first_de , * de_buf , * limit ;
33433352 unsigned long offset = 0 ;
33443353 unsigned int rec_len , new_rec_len , free_space ;
33453354
@@ -3352,14 +3361,16 @@ static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
33523361 else
33533362 free_space = dir -> i_sb -> s_blocksize - i_size_read (dir );
33543363
3355- de_buf = di -> id2 .i_data .id_data ;
3364+ first_de = di -> id2 .i_data .id_data ;
3365+ de_buf = first_de ;
33563366 limit = de_buf + i_size_read (dir );
33573367 rec_len = OCFS2_DIR_REC_LEN (namelen );
33583368
33593369 while (de_buf < limit ) {
33603370 de = (struct ocfs2_dir_entry * )de_buf ;
33613371
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 )) {
33633374 ret = - ENOENT ;
33643375 goto out ;
33653376 }
@@ -3441,7 +3452,8 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
34413452 /* move to next block */
34423453 de = (struct ocfs2_dir_entry * ) bh -> b_data ;
34433454 }
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 )) {
34453457 status = - ENOENT ;
34463458 goto bail ;
34473459 }
0 commit comments