[PATCH 3.16 05/10] ext4: zero out the unused memory region in the extent tree block

From: Ben Hutchings
Date: Tue Jun 18 2019 - 10:34:10 EST


3.16.69-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Sriram Rajagopalan <sriramr@xxxxxxxxxx>

commit 592acbf16821288ecdc4192c47e3774a4c48bb64 upstream.

This commit zeroes out the unused memory region in the buffer_head
corresponding to the extent metablock after writing the extent header
and the corresponding extent node entries.

This is done to prevent random uninitialized data from getting into
the filesystem when the extent block is synced.

This fixes CVE-2019-11833.

Signed-off-by: Sriram Rajagopalan <sriramr@xxxxxxxxxx>
Signed-off-by: Theodore Ts'o <tytso@xxxxxxx>
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
fs/ext4/extents.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1016,6 +1016,7 @@ static int ext4_ext_split(handle_t *hand
__le32 border;
ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */
int err = 0;
+ size_t ext_size = 0;

/* make decision: where to split? */
/* FIXME: now decision is simplest: at current extent */
@@ -1107,6 +1108,10 @@ static int ext4_ext_split(handle_t *hand
le16_add_cpu(&neh->eh_entries, m);
}

+ /* zero out unused area in the extent block */
+ ext_size = sizeof(struct ext4_extent_header) +
+ sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries);
+ memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size);
ext4_extent_block_csum_set(inode, neh);
set_buffer_uptodate(bh);
unlock_buffer(bh);
@@ -1186,6 +1191,11 @@ static int ext4_ext_split(handle_t *hand
sizeof(struct ext4_extent_idx) * m);
le16_add_cpu(&neh->eh_entries, m);
}
+ /* zero out unused area in the extent block */
+ ext_size = sizeof(struct ext4_extent_header) +
+ (sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries));
+ memset(bh->b_data + ext_size, 0,
+ inode->i_sb->s_blocksize - ext_size);
ext4_extent_block_csum_set(inode, neh);
set_buffer_uptodate(bh);
unlock_buffer(bh);
@@ -1251,6 +1261,7 @@ static int ext4_ext_grow_indepth(handle_
struct buffer_head *bh;
ext4_fsblk_t newblock;
int err = 0;
+ size_t ext_size = 0;

newblock = ext4_ext_new_meta_block(handle, inode, NULL,
newext, &err, flags);
@@ -1268,9 +1279,11 @@ static int ext4_ext_grow_indepth(handle_
goto out;
}

+ ext_size = sizeof(EXT4_I(inode)->i_data);
/* move top-level index/leaf into new block */
- memmove(bh->b_data, EXT4_I(inode)->i_data,
- sizeof(EXT4_I(inode)->i_data));
+ memmove(bh->b_data, EXT4_I(inode)->i_data, ext_size);
+ /* zero out unused area in the extent block */
+ memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size);

/* set size of new block */
neh = ext_block_hdr(bh);