mirror of
https://gitee.com/bianbu-linux/linux-6.6-fh
synced 2025-04-25 03:07:06 -04:00
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: syzbot+39ba34a099ac2e9bd3cb@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=39ba34a099ac2e9bd3cb Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com> Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
7110650b85
commit
2e16a1389b
1 changed files with 31 additions and 29 deletions
|
@ -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,
|
||||||
* 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,
|
||||||
* 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,
|
||||||
* 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,
|
||||||
/* 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,
|
||||||
|
|
||||||
/* 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)
|
||||||
* 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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
* 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)
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
*
|
*
|
||||||
* 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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue