From: Rohinthan P <rokinthanp03@gmail.com>
To: Dave Kleikamp <shaggy@kernel.org>
Cc: jfs-discussion@lists.sourceforge.net,
linux-kernel@vger.kernel.org,
syzbot+0266f74df36ca702aedf@syzkaller.appspotmail.com
Subject: [PATCH] jfs: fix general protection fault in dbDiscardAG
Date: Sat, 3 Oct 2026 09:56:02 +0530 [thread overview]
Message-ID: <20261003042602.22602-1-rokinthanp03@gmail.com> (raw)
syzbot reported a general protection fault in dbDiscardAG():
Oops: general protection fault, probably for non-canonical
address 0xdffffc0000000003: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range
[0x0000000000000018-0x000000000000001f]
RIP: 0010:dbDiscardAG+0x648/0x8f0 fs/jfs/jfs_dmap.c:1726
...
Call Trace:
<TASK>
jfs_ioc_trim+0x436/0x680 fs/jfs/jfs_discard.c:106
jfs_ioctl+0x291/0x3b0 fs/jfs/ioctl.c:131
In dbDiscardAG(), nblocks is initialized from bmp->db_agfree[agno].
On a corrupted filesystem or when free block accounting underflows,
nblocks can be negative (e.g. -1LL / 0xffffffffffffffff).
When max_ranges is assigned from nblocks (as u64) and divided by minlen,
max_ranges retains 0xffffffffffffffff. Then max_ranges + 1 overflows to 0,
causing min_t(u64, max_ranges + 1, 32 * 1024) to evaluate to 0.
As a result, kmalloc_objs(struct range2trim, 0, GFP_NOFS) returns
ZERO_SIZE_PTR (0x10). The check (totrim == NULL) does not catch this,
the loop while (nblocks >= minlen) is skipped because nblocks is negative,
and tt->nblocks = 0 dereferences offset 8 of ZERO_SIZE_PTR (0x18),
triggering a KASAN null-ptr-deref / general protection fault.
Fix this by:
1. Validating agno against bmp->db_numag and minlen > 0.
2. Checking if nblocks < minlen before allocation; if an AG does not have
enough free blocks to satisfy minlen, there are no extents to discard,
so return 0 immediately.
3. Clamping nblocks to bmp->db_agsize.
4. Checking ZERO_OR_NULL_PTR(totrim) instead of just NULL.
5. In jfs_ioc_trim(), clamping agno and agno_end to db_numag - 1 and
handling potential integer overflow in the range calculation.
Fixes: b40c2e665cd5 ("fs/jfs: TRIM support for JFS Filesystem")
Reported-by: syzbot+0266f74df36ca702aedf@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=0266f74df36ca702aedf
Signed-off-by: Rohinthan P <rokinthanp03@gmail.com>
---
fs/jfs/jfs_discard.c | 9 ++++++++-
fs/jfs/jfs_dmap.c | 15 ++++++++++++++-
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/fs/jfs/jfs_discard.c b/fs/jfs/jfs_discard.c
index 4b66029..3cf8d84 100644
--- a/fs/jfs/jfs_discard.c
+++ b/fs/jfs/jfs_discard.c
@@ -94,7 +94,7 @@ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
return -EINVAL;
}
- if (end >= bmp->db_mapsize)
+ if (end >= bmp->db_mapsize || end < start)
end = bmp->db_mapsize - 1;
/**
@@ -102,6 +102,13 @@ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
*/
agno = BLKTOAG(start, JFS_SBI(ip->i_sb));
agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb));
+ if (agno >= bmp->db_numag) {
+ up_read(&sb->s_umount);
+ return 0;
+ }
+ if (agno_end >= bmp->db_numag)
+ agno_end = bmp->db_numag - 1;
+
while (agno <= agno_end) {
trimmed += dbDiscardAG(ip, agno, minlen);
agno++;
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index a841cf2..cee0b8e 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -1673,15 +1673,26 @@ s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen)
int count = 0, range_cnt;
u64 max_ranges;
+ if (agno < 0 || agno >= bmp->db_numag || minlen <= 0)
+ return 0;
+
/* prevent others from writing new stuff here, while trimming */
IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
nblocks = bmp->db_agfree[agno];
+ if (nblocks < minlen) {
+ IWRITE_UNLOCK(ipbmap);
+ return 0;
+ }
+
+ if (nblocks > bmp->db_agsize)
+ nblocks = bmp->db_agsize;
+
max_ranges = nblocks;
do_div(max_ranges, minlen);
range_cnt = min_t(u64, max_ranges + 1, 32 * 1024);
totrim = kmalloc_objs(struct range2trim, range_cnt, GFP_NOFS);
- if (totrim == NULL) {
+ if (ZERO_OR_NULL_PTR(totrim)) {
jfs_error(bmp->db_ipbmap->i_sb, "no memory for trim array\n");
IWRITE_UNLOCK(ipbmap);
return 0;
@@ -1704,6 +1715,8 @@ s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen)
/* give a hint for the next while */
nblocks = bmp->db_agfree[agno];
+ if (nblocks > bmp->db_agsize)
+ nblocks = bmp->db_agsize;
continue;
} else if (rc == -ENOSPC) {
/* search for next smaller log2 block */
--
2.53.0
reply other threads:[~2026-10-03 4:26 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261003042602.22602-1-rokinthanp03@gmail.com \
--to=rokinthanp03@gmail.com \
--cc=jfs-discussion@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=shaggy@kernel.org \
--cc=syzbot+0266f74df36ca702aedf@syzkaller.appspotmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®