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

Commit 3f8217c3 authored by Manas Ghandat's avatar Manas Ghandat Committed by Greg Kroah-Hartman
Browse files

jfs: fix array-index-out-of-bounds in dbAdjTree

[ Upstream commit 74ecdda68242b174920fe7c6133a856fb7d8559b ]

Currently there is a bound check missing in the dbAdjTree while
accessing the dmt_stree. To add the required check added the bool is_ctl
which is required to determine the size as suggest in the following
commit.
https://lore.kernel.org/linux-kernel-mentees/f9475918-2186-49b8-b801-6f0f9e75f4fa@oracle.com/



Reported-by: default avatar <syzbot+39ba34a099ac2e9bd3cb@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=39ba34a099ac2e9bd3cb


Signed-off-by: default avatarManas Ghandat <ghandatmanas@gmail.com>
Signed-off-by: default avatarDave Kleikamp <dave.kleikamp@oracle.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 1b9d6828
Loading
Loading
Loading
Loading
+31 −29
Original line number Diff line number Diff line
@@ -63,10 +63,10 @@
 */
static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
			int nblocks);
static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval);
static int dbBackSplit(dmtree_t * tp, int leafno);
static int dbJoin(dmtree_t * tp, int leafno, int newval);
static void dbAdjTree(dmtree_t * tp, int leafno, int newval);
static void dbSplit(dmtree_t *tp, int leafno, int splitsz, int newval, bool is_ctl);
static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl);
static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl);
static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl);
static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc,
		    int level);
static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results);
@@ -2171,7 +2171,7 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
		 * system.
		 */
		if (dp->tree.stree[word] == NOFREE)
			dbBackSplit((dmtree_t *) & dp->tree, word);
			dbBackSplit((dmtree_t *)&dp->tree, word, false);

		dbAllocBits(bmp, dp, blkno, nblocks);
	}
@@ -2257,7 +2257,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
			 * the binary system of the leaves if need be.
			 */
			dbSplit(tp, word, BUDMIN,
				dbMaxBud((u8 *) & dp->wmap[word]));
				dbMaxBud((u8 *)&dp->wmap[word]), false);

			word += 1;
		} else {
@@ -2297,7 +2297,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
				 * system of the leaves to reflect the current
				 * allocation (size).
				 */
				dbSplit(tp, word, size, NOFREE);
				dbSplit(tp, word, size, NOFREE, false);

				/* get the number of dmap words handled */
				nw = BUDSIZE(size, BUDMIN);
@@ -2404,7 +2404,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
			/* update the leaf for this dmap word.
			 */
			rc = dbJoin(tp, word,
				    dbMaxBud((u8 *) & dp->wmap[word]));
				    dbMaxBud((u8 *)&dp->wmap[word]), false);
			if (rc)
				return rc;

@@ -2437,7 +2437,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,

				/* update the leaf.
				 */
				rc = dbJoin(tp, word, size);
				rc = dbJoin(tp, word, size, false);
				if (rc)
					return rc;

@@ -2589,14 +2589,14 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
		 * that it is at the front of a binary buddy system.
		 */
		if (oldval == NOFREE) {
			rc = dbBackSplit((dmtree_t *) dcp, leafno);
			rc = dbBackSplit((dmtree_t *)dcp, leafno, true);
			if (rc)
				return rc;
			oldval = dcp->stree[ti];
		}
		dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval);
		dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval, true);
	} else {
		rc = dbJoin((dmtree_t *) dcp, leafno, newval);
		rc = dbJoin((dmtree_t *) dcp, leafno, newval, true);
		if (rc)
			return rc;
	}
@@ -2625,7 +2625,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
				 */
				if (alloc) {
					dbJoin((dmtree_t *) dcp, leafno,
					       oldval);
					       oldval, true);
				} else {
					/* the dbJoin() above might have
					 * caused a larger binary buddy system
@@ -2635,9 +2635,9 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
					 */
					if (dcp->stree[ti] == NOFREE)
						dbBackSplit((dmtree_t *)
							    dcp, leafno);
							    dcp, leafno, true);
					dbSplit((dmtree_t *) dcp, leafno,
						dcp->budmin, oldval);
						dcp->budmin, oldval, true);
				}

				/* release the buffer and return the error.
@@ -2685,7 +2685,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
 *
 * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
 */
static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
static void dbSplit(dmtree_t *tp, int leafno, int splitsz, int newval, bool is_ctl)
{
	int budsz;
	int cursz;
@@ -2707,7 +2707,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
		while (cursz >= splitsz) {
			/* update the buddy's leaf with its new value.
			 */
			dbAdjTree(tp, leafno ^ budsz, cursz);
			dbAdjTree(tp, leafno ^ budsz, cursz, is_ctl);

			/* on to the next size and buddy.
			 */
@@ -2719,7 +2719,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
	/* adjust the dmap tree to reflect the specified leaf's new
	 * value.
	 */
	dbAdjTree(tp, leafno, newval);
	dbAdjTree(tp, leafno, newval, is_ctl);
}


@@ -2750,7 +2750,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
 *
 * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
 */
static int dbBackSplit(dmtree_t * tp, int leafno)
static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl)
{
	int budsz, bud, w, bsz, size;
	int cursz;
@@ -2801,7 +2801,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno)
				 * system in two.
				 */
				cursz = leaf[bud] - 1;
				dbSplit(tp, bud, cursz, cursz);
				dbSplit(tp, bud, cursz, cursz, is_ctl);
				break;
			}
		}
@@ -2829,7 +2829,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno)
 *
 * RETURN VALUES: none
 */
static int dbJoin(dmtree_t * tp, int leafno, int newval)
static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl)
{
	int budsz, buddy;
	s8 *leaf;
@@ -2884,12 +2884,12 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)
			if (leafno < buddy) {
				/* leafno is the left buddy.
				 */
				dbAdjTree(tp, buddy, NOFREE);
				dbAdjTree(tp, buddy, NOFREE, is_ctl);
			} else {
				/* buddy is the left buddy and becomes
				 * leafno.
				 */
				dbAdjTree(tp, leafno, NOFREE);
				dbAdjTree(tp, leafno, NOFREE, is_ctl);
				leafno = buddy;
			}

@@ -2902,7 +2902,7 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)

	/* update the leaf value.
	 */
	dbAdjTree(tp, leafno, newval);
	dbAdjTree(tp, leafno, newval, is_ctl);

	return 0;
}
@@ -2923,21 +2923,23 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)
 *
 * RETURN VALUES: none
 */
static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl)
{
	int lp, pp, k;
	int max;
	int max, size;

	size = is_ctl ? CTLTREESIZE : TREESIZE;

	/* pick up the index of the leaf for this leafno.
	 */
	lp = leafno + le32_to_cpu(tp->dmt_leafidx);

	if (WARN_ON_ONCE(lp >= size || lp < 0))
		return;

	/* is the current value the same as the old value ?  if so,
	 * there is nothing to do.
	 */
	if (WARN_ON_ONCE(lp >= CTLTREESIZE))
		return;

	if (tp->dmt_stree[lp] == newval)
		return;