2022-04-29 11:16:44

by Jan Kara

[permalink] [raw]
Subject: [PATCH 1/2] ext4: Verify dir block before splitting it

Before splitting a directory block verify its directory entries are sane
so that the splitting code does not access memory it should not.

CC: [email protected]
Signed-off-by: Jan Kara <[email protected]>
---
fs/ext4/namei.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 767b4bfe39c3..ca6ee9940599 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -277,9 +277,9 @@ static struct dx_frame *dx_probe(struct ext4_filename *fname,
struct dx_hash_info *hinfo,
struct dx_frame *frame);
static void dx_release(struct dx_frame *frames);
-static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
- unsigned blocksize, struct dx_hash_info *hinfo,
- struct dx_map_entry map[]);
+static int dx_make_map(struct inode *dir, struct buffer_head *bh,
+ struct dx_hash_info *hinfo,
+ struct dx_map_entry *map_tail);
static void dx_sort_map(struct dx_map_entry *map, unsigned count);
static struct ext4_dir_entry_2 *dx_move_dirents(struct inode *dir, char *from,
char *to, struct dx_map_entry *offsets,
@@ -1249,15 +1249,23 @@ static inline int search_dirblock(struct buffer_head *bh,
* Create map of hash values, offsets, and sizes, stored at end of block.
* Returns number of entries mapped.
*/
-static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
- unsigned blocksize, struct dx_hash_info *hinfo,
+static int dx_make_map(struct inode *dir, struct buffer_head *bh,
+ struct dx_hash_info *hinfo,
struct dx_map_entry *map_tail)
{
int count = 0;
- char *base = (char *) de;
+ struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)bh->b_data;
+ unsigned int buflen = bh->b_size;
+ char *base = bh->b_data;
struct dx_hash_info h = *hinfo;

- while ((char *) de < base + blocksize) {
+ if (ext4_has_metadata_csum(dir->i_sb))
+ buflen -= sizeof(struct ext4_dir_entry_tail);
+
+ while ((char *) de < base + buflen) {
+ if (ext4_check_dir_entry(dir, NULL, de, bh, base, buflen,
+ ((char *)de) - base))
+ return -EFSCORRUPTED;
if (de->name_len && de->inode) {
if (ext4_hash_in_dirent(dir))
h.hash = EXT4_DIRENT_HASH(de);
@@ -1270,7 +1278,6 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
count++;
cond_resched();
}
- /* XXX: do we need to check rec_len == 0 case? -Chris */
de = ext4_next_entry(de, blocksize);
}
return count;
@@ -1943,8 +1950,11 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,

/* create map in the end of data2 block */
map = (struct dx_map_entry *) (data2 + blocksize);
- count = dx_make_map(dir, (struct ext4_dir_entry_2 *) data1,
- blocksize, hinfo, map);
+ count = dx_make_map(dir, *bh, hinfo, map);
+ if (count < 0) {
+ err = count;
+ goto journal_error;
+ }
map -= count;
dx_sort_map(map, count);
/* Ensure that neither split block is over half full */
--
2.34.1


2022-05-18 09:10:23

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH 1/2] ext4: Verify dir block before splitting it

On Tue 17-05-22 19:40:11, Theodore Ts'o wrote:
> On Thu, Apr 28, 2022 at 08:31:37PM +0200, Jan Kara wrote:
> > Before splitting a directory block verify its directory entries are sane
> > so that the splitting code does not access memory it should not.
>
> This commit fails to build due to an undefined variable. It's fixed
> with this hunk in the next patch, which needs to be brought back into
> this commit:
>
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index 5951e9bb348e..7286472e9558 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -1278,7 +1278,7 @@ static int dx_make_map(struct inode *dir, struct buffer_head *bh,
> count++;
> cond_resched();
> }
> - de = ext4_next_entry(de, blocksize);
> + de = ext4_next_entry(de, dir->i_sb->s_blocksize);
> }
> return count;
> }
>
> I was thinking about folding in this change and apply the patch with
> that change --- and I may yet do that --- but it looks like there's a
> bigger problem with this patch series, which is that it's causing a
> crash when running ext4/052 due to what appears to be a smashed stack.
> More about that in the reply to patch 2/2 of this series....

Yup, I'll fix that. Thanks for catching this.

Honza
--
Jan Kara <[email protected]>
SUSE Labs, CR