Commit 74ecdda6 authored by Manas Ghandat's avatar Manas Ghandat Committed by Dave Kleikamp

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

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: syzbot+39ba34a099ac2e9bd3cb@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=39ba34a099ac2e9bd3cbSigned-off-by: default avatarManas Ghandat <ghandatmanas@gmail.com>
Signed-off-by: default avatarDave Kleikamp <dave.kleikamp@oracle.com>
parent fa5492ee
...@@ -63,10 +63,10 @@ ...@@ -63,10 +63,10 @@
*/ */
static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
int nblocks); int nblocks);
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);
static int dbBackSplit(dmtree_t * tp, int leafno); static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl);
static int dbJoin(dmtree_t * tp, int leafno, int newval); static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl);
static void dbAdjTree(dmtree_t * tp, int leafno, int newval); 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, static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc,
int level); int level);
static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results); static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results);
...@@ -2103,7 +2103,7 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, ...@@ -2103,7 +2103,7 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
* system. * system.
*/ */
if (dp->tree.stree[word] == NOFREE) if (dp->tree.stree[word] == NOFREE)
dbBackSplit((dmtree_t *) & dp->tree, word); dbBackSplit((dmtree_t *)&dp->tree, word, false);
dbAllocBits(bmp, dp, blkno, nblocks); dbAllocBits(bmp, dp, blkno, nblocks);
} }
...@@ -2189,7 +2189,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, ...@@ -2189,7 +2189,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
* the binary system of the leaves if need be. * the binary system of the leaves if need be.
*/ */
dbSplit(tp, word, BUDMIN, dbSplit(tp, word, BUDMIN,
dbMaxBud((u8 *) & dp->wmap[word])); dbMaxBud((u8 *)&dp->wmap[word]), false);
word += 1; word += 1;
} else { } else {
...@@ -2229,7 +2229,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, ...@@ -2229,7 +2229,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
* system of the leaves to reflect the current * system of the leaves to reflect the current
* allocation (size). * allocation (size).
*/ */
dbSplit(tp, word, size, NOFREE); dbSplit(tp, word, size, NOFREE, false);
/* get the number of dmap words handled */ /* get the number of dmap words handled */
nw = BUDSIZE(size, BUDMIN); nw = BUDSIZE(size, BUDMIN);
...@@ -2336,7 +2336,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno, ...@@ -2336,7 +2336,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
/* update the leaf for this dmap word. /* update the leaf for this dmap word.
*/ */
rc = dbJoin(tp, word, rc = dbJoin(tp, word,
dbMaxBud((u8 *) & dp->wmap[word])); dbMaxBud((u8 *)&dp->wmap[word]), false);
if (rc) if (rc)
return rc; return rc;
...@@ -2369,7 +2369,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno, ...@@ -2369,7 +2369,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
/* update the leaf. /* update the leaf.
*/ */
rc = dbJoin(tp, word, size); rc = dbJoin(tp, word, size, false);
if (rc) if (rc)
return rc; return rc;
...@@ -2521,16 +2521,16 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) ...@@ -2521,16 +2521,16 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
* that it is at the front of a binary buddy system. * that it is at the front of a binary buddy system.
*/ */
if (oldval == NOFREE) { if (oldval == NOFREE) {
rc = dbBackSplit((dmtree_t *) dcp, leafno); rc = dbBackSplit((dmtree_t *)dcp, leafno, true);
if (rc) { if (rc) {
release_metapage(mp); release_metapage(mp);
return rc; return rc;
} }
oldval = dcp->stree[ti]; oldval = dcp->stree[ti];
} }
dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval); dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval, true);
} else { } else {
rc = dbJoin((dmtree_t *) dcp, leafno, newval); rc = dbJoin((dmtree_t *) dcp, leafno, newval, true);
if (rc) { if (rc) {
release_metapage(mp); release_metapage(mp);
return rc; return rc;
...@@ -2561,7 +2561,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) ...@@ -2561,7 +2561,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
*/ */
if (alloc) { if (alloc) {
dbJoin((dmtree_t *) dcp, leafno, dbJoin((dmtree_t *) dcp, leafno,
oldval); oldval, true);
} else { } else {
/* the dbJoin() above might have /* the dbJoin() above might have
* caused a larger binary buddy system * caused a larger binary buddy system
...@@ -2571,9 +2571,9 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) ...@@ -2571,9 +2571,9 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
*/ */
if (dcp->stree[ti] == NOFREE) if (dcp->stree[ti] == NOFREE)
dbBackSplit((dmtree_t *) dbBackSplit((dmtree_t *)
dcp, leafno); dcp, leafno, true);
dbSplit((dmtree_t *) dcp, leafno, dbSplit((dmtree_t *) dcp, leafno,
dcp->budmin, oldval); dcp->budmin, oldval, true);
} }
/* release the buffer and return the error. /* release the buffer and return the error.
...@@ -2621,7 +2621,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) ...@@ -2621,7 +2621,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; * 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 budsz;
int cursz; int cursz;
...@@ -2643,7 +2643,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) ...@@ -2643,7 +2643,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
while (cursz >= splitsz) { while (cursz >= splitsz) {
/* update the buddy's leaf with its new value. /* 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. /* on to the next size and buddy.
*/ */
...@@ -2655,7 +2655,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) ...@@ -2655,7 +2655,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
/* adjust the dmap tree to reflect the specified leaf's new /* adjust the dmap tree to reflect the specified leaf's new
* value. * value.
*/ */
dbAdjTree(tp, leafno, newval); dbAdjTree(tp, leafno, newval, is_ctl);
} }
...@@ -2686,7 +2686,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) ...@@ -2686,7 +2686,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; * 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 budsz, bud, w, bsz, size;
int cursz; int cursz;
...@@ -2737,7 +2737,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno) ...@@ -2737,7 +2737,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno)
* system in two. * system in two.
*/ */
cursz = leaf[bud] - 1; cursz = leaf[bud] - 1;
dbSplit(tp, bud, cursz, cursz); dbSplit(tp, bud, cursz, cursz, is_ctl);
break; break;
} }
} }
...@@ -2765,7 +2765,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno) ...@@ -2765,7 +2765,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno)
* *
* RETURN VALUES: none * 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; int budsz, buddy;
s8 *leaf; s8 *leaf;
...@@ -2820,12 +2820,12 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval) ...@@ -2820,12 +2820,12 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)
if (leafno < buddy) { if (leafno < buddy) {
/* leafno is the left buddy. /* leafno is the left buddy.
*/ */
dbAdjTree(tp, buddy, NOFREE); dbAdjTree(tp, buddy, NOFREE, is_ctl);
} else { } else {
/* buddy is the left buddy and becomes /* buddy is the left buddy and becomes
* leafno. * leafno.
*/ */
dbAdjTree(tp, leafno, NOFREE); dbAdjTree(tp, leafno, NOFREE, is_ctl);
leafno = buddy; leafno = buddy;
} }
...@@ -2838,7 +2838,7 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval) ...@@ -2838,7 +2838,7 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)
/* update the leaf value. /* update the leaf value.
*/ */
dbAdjTree(tp, leafno, newval); dbAdjTree(tp, leafno, newval, is_ctl);
return 0; return 0;
} }
...@@ -2859,21 +2859,23 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval) ...@@ -2859,21 +2859,23 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)
* *
* RETURN VALUES: none * 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 lp, pp, k;
int max; int max, size;
size = is_ctl ? CTLTREESIZE : TREESIZE;
/* pick up the index of the leaf for this leafno. /* pick up the index of the leaf for this leafno.
*/ */
lp = leafno + le32_to_cpu(tp->dmt_leafidx); 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, /* is the current value the same as the old value ? if so,
* there is nothing to do. * there is nothing to do.
*/ */
if (WARN_ON_ONCE(lp >= CTLTREESIZE))
return;
if (tp->dmt_stree[lp] == newval) if (tp->dmt_stree[lp] == newval)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment