mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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®