Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 359616ce authored by Dongliang Mu's avatar Dongliang Mu Committed by Greg Kroah-Hartman
Browse files

fs: jfs: fix shift-out-of-bounds in dbAllocAG



[ Upstream commit 898f706695682b9954f280d95e49fa86ffa55d08 ]

Syzbot found a crash : UBSAN: shift-out-of-bounds in dbAllocAG. The
underlying bug is the missing check of bmp->db_agl2size. The field can
be greater than 64 and trigger the shift-out-of-bounds.

Fix this bug by adding a check of bmp->db_agl2size in dbMount since this
field is used in many following functions. The upper bound for this
field is L2MAXL2SIZE - L2MAXAG, thanks for the help of Dave Kleikamp.
Note that, for maintenance, I reorganized error handling code of dbMount.

Reported-by: default avatar <syzbot+15342c1aa6a00fb7a438@syzkaller.appspotmail.com>
Signed-off-by: default avatarDongliang Mu <mudongliangabcd@gmail.com>
Signed-off-by: default avatarDave Kleikamp <dave.kleikamp@oracle.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 419b8085
Loading
Loading
Loading
Loading
+16 −6
Original line number Diff line number Diff line
@@ -155,7 +155,7 @@ int dbMount(struct inode *ipbmap)
	struct bmap *bmp;
	struct dbmap_disk *dbmp_le;
	struct metapage *mp;
	int i;
	int i, err;

	/*
	 * allocate/initialize the in-memory bmap descriptor
@@ -170,8 +170,8 @@ int dbMount(struct inode *ipbmap)
			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,
			   PSIZE, 0);
	if (mp == NULL) {
		kfree(bmp);
		return -EIO;
		err = -EIO;
		goto err_kfree_bmp;
	}

	/* copy the on-disk bmap descriptor to its in-memory version. */
@@ -181,9 +181,8 @@ int dbMount(struct inode *ipbmap)
	bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
	bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);
	if (!bmp->db_numag) {
		release_metapage(mp);
		kfree(bmp);
		return -EINVAL;
		err = -EINVAL;
		goto err_release_metapage;
	}

	bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);
@@ -194,6 +193,11 @@ int dbMount(struct inode *ipbmap)
	bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
	bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
	bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
	if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG) {
		err = -EINVAL;
		goto err_release_metapage;
	}

	for (i = 0; i < MAXAG; i++)
		bmp->db_agfree[i] = le64_to_cpu(dbmp_le->dn_agfree[i]);
	bmp->db_agsize = le64_to_cpu(dbmp_le->dn_agsize);
@@ -214,6 +218,12 @@ int dbMount(struct inode *ipbmap)
	BMAP_LOCK_INIT(bmp);

	return (0);

err_release_metapage:
	release_metapage(mp);
err_kfree_bmp:
	kfree(bmp);
	return err;
}