Skip to content

Commit 5872331

Browse files
Eric Sandeentytso
authored andcommitted
ext4: fix potential negative array index in do_split()
If for any reason a directory passed to do_split() does not have enough active entries to exceed half the size of the block, we can end up iterating over all "count" entries without finding a split point. In this case, count == move, and split will be zero, and we will attempt a negative index into map[]. Guard against this by detecting this case, and falling back to split-to-half-of-count instead; in this case we will still have plenty of space (> half blocksize) in each split block. Fixes: ef2b02d ("ext34: ensure do_split leaves enough free space in both blocks") Signed-off-by: Eric Sandeen <[email protected]> Reviewed-by: Andreas Dilger <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 24dc986 commit 5872331

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

fs/ext4/namei.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,7 +1858,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
18581858
blocksize, hinfo, map);
18591859
map -= count;
18601860
dx_sort_map(map, count);
1861-
/* Split the existing block in the middle, size-wise */
1861+
/* Ensure that neither split block is over half full */
18621862
size = 0;
18631863
move = 0;
18641864
for (i = count-1; i >= 0; i--) {
@@ -1868,8 +1868,18 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
18681868
size += map[i].size;
18691869
move++;
18701870
}
1871-
/* map index at which we will split */
1872-
split = count - move;
1871+
/*
1872+
* map index at which we will split
1873+
*
1874+
* If the sum of active entries didn't exceed half the block size, just
1875+
* split it in half by count; each resulting block will have at least
1876+
* half the space free.
1877+
*/
1878+
if (i > 0)
1879+
split = count - move;
1880+
else
1881+
split = count/2;
1882+
18731883
hash2 = map[split].hash;
18741884
continued = hash2 == map[split - 1].hash;
18751885
dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n",

0 commit comments

Comments
 (0)