[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251120154339.1040921-1-yun.zhou@windriver.com>
Date: Thu, 20 Nov 2025 23:43:39 +0800
From: Yun Zhou <yun.zhou@...driver.com>
To: <shaggy@...nel.org>
CC: <rand.sec96@...il.com>, <contact@...aud-lcm.com>, <kovalev@...linux.org>,
<zheng.yu@...thwestern.edu>, <eadavis@...com>,
<yun.zhou@...driver.com>, <jfs-discussion@...ts.sourceforge.net>,
<linux-kernel@...r.kernel.org>
Subject: [PATCH] jfs: add linelock->index boundary check
This patch adds checks to ensure that the line lock index (dtlck->index,
rdtlck->index, etc.) does not exceed the maximum allowed count(maxcnt)
before accessing the lock's lv array.
When the line lock index reaches or exceeds maxcnt, direct access to
lv[index] would cause an array index overflow. To prevent this, we check
if the index is out of bounds and, if so, call txLinelock() to extend
the lock structure, ensuring valid access to the lv array.
The checks are added in critical sections where line lock entries are
modified or accessed, including:
- dtSplitPage() in jfs_dtree.c (both for left and right sibling pages)
- dtExtendPage() in jfs_dtree.c
- dtMoveEntry() in jfs_dtree.c (for source and destination locks)
- diWrite() in jfs_imap.c (for inode inline symlink, extended
attributes, and base inode data)
This prevents potential out-of-bounds memory accesses and improves the
stability of JFS's transactional line locking mechanism.
This fixes the following Oops reported by syzkaller.
[ 261.432595][ T5998] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000005: 0000 [#1] SMP KASAN PTI
[ 261.432605][ T5998] KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f]
[ 261.432614][ T5998] CPU: 2 UID: 0 PID: 5998 Comm: 9489c9f9f3d4372 Tainted: G E 6.18.0-rc4-00248-g439fc29dfd3b #113 PREEMPT_{RT,(full)}
[ 261.432624][ T5998] Tainted: [E]=UNSIGNED_MODULE
[ 261.432626][ T5998] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 261.432630][ T5998] RIP: 0010:txCommit+0xafb/0x5430 [jfs]
[ 261.432715][ T5998] Code: 3c 10 00 74 12 4c 89 f7 e8 92 92 b8 e1 48 ba 00 00 00 00 00 fc ff df 4c 89 74 24 68 4d 8b 36 4d 8d 7e 28 4c 89 f8 48 c1 e8 03 <80> 3c 10 00 74 12 4c 89 ff e8 67 92 b8 e1 48 ba 00 00 00 00c
[ 261.432721][ T5998] RSP: 0018:ffffc900047e74e0 EFLAGS: 00010206
[ 261.432728][ T5998] RAX: 0000000000000005 RBX: 0000000000000948 RCX: 1ffff92000a3a348
[ 261.432732][ T5998] RDX: dffffc0000000000 RSI: 0000000000000000 RDI: 0000000000000000
[ 261.432737][ T5998] RBP: ffffc900047e76b0 R08: 0000000000000000 R09: 0000000000000000
[ 261.432741][ T5998] R10: dffffc0000000000 R11: fffffbfff1d6ab2f R12: 0000000000000002
[ 261.432745][ T5998] R13: ffffc900051cd000 R14: 0000000000000000 R15: 0000000000000028
[ 261.432749][ T5998] FS: 00007f569ce8f6c0(0000) GS:ffff888127123000(0000) knlGS:0000000000000000
[ 261.432754][ T5998] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 261.432759][ T5998] CR2: 00007f1f3862f000 CR3: 0000000036cdc000 CR4: 00000000000006f0
[ 261.432765][ T5998] Call Trace:
[ 261.432768][ T5998] <TASK>
[ 261.432774][ T5998] ? __pfx_txCommit+0x10/0x10 [jfs]
[ 261.432855][ T5998] ? rcu_is_watching+0x15/0xb0
[ 261.432873][ T5998] ? __mark_inode_dirty+0x3d2/0xe10
[ 261.432882][ T5998] jfs_create+0x865/0xa80 [jfs]
[ 261.432964][ T5998] ? __pfx_jfs_create+0x10/0x10 [jfs]
[ 261.433044][ T5998] ? __pfx_jfs_lookup+0x10/0x10 [jfs]
[ 261.433127][ T5998] ? generic_permission+0x2e5/0x690
[ 261.433139][ T5998] ? bpf_lsm_inode_create+0x9/0x20
[ 261.433148][ T5998] ? __pfx_jfs_create+0x10/0x10 [jfs]
[ 261.433229][ T5998] path_openat+0x1500/0x3840
[ 261.433240][ T5998] ? __pfx_path_openat+0x10/0x10
[ 261.433249][ T5998] ? _raw_spin_unlock_irqrestore+0x85/0x110
[ 261.433263][ T5998] ? lockdep_hardirqs_on+0x9c/0x150
[ 261.433272][ T5998] ? _raw_spin_unlock_irqrestore+0xad/0x110
[ 261.433282][ T5998] do_filp_open+0x1fa/0x410
[ 261.433289][ T5998] ? __pfx_do_filp_open+0x10/0x10
[ 261.433296][ T5998] ? rt_mutex_slowunlock+0x493/0x8a0
[ 261.433307][ T5998] ? alloc_fd+0x64f/0x6c0
[ 261.433318][ T5998] do_sys_openat2+0x121/0x1c0
[ 261.433325][ T5998] ? __pfx_do_sys_openat2+0x10/0x10
[ 261.433332][ T5998] ? __pfx___se_sys_futex+0x10/0x10
[ 261.433340][ T5998] __x64_sys_creat+0x8f/0xc0
[ 261.433347][ T5998] do_syscall_64+0xfa/0xfa0
[ 261.433356][ T5998] ? lockdep_hardirqs_on+0x9c/0x150
[ 261.433365][ T5998] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 261.433372][ T5998] ? exc_page_fault+0xab/0x100
[ 261.433380][ T5998] entry_SYSCALL_64_after_hwframe+0x77/0x7f
Reported-by: syzbot+9489c9f9f3d437221ea2@...kaller.appspotmail.com
Signed-off-by: Yun Zhou <yun.zhou@...driver.com>
---
fs/jfs/jfs_dtree.c | 19 +++++++++++++++++++
fs/jfs/jfs_imap.c | 9 +++++++++
2 files changed, 28 insertions(+)
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 0ab83bb7bbdf..d9cf2071c41f 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -1440,6 +1440,9 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
* but it's not. Be my guest.)
*/
if (nextbn == 0 && split->index == sp->header.nextindex) {
+ /* open new linelock */
+ if (unlikely(rdtlck->index >= rdtlck->maxcnt))
+ rdtlck = txLinelock(rdtlck);
/* linelock header + stbl (first slot) of new page */
rlv = & rdtlck->lv[rdtlck->index];
rlv->offset = 0;
@@ -1483,6 +1486,10 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
tlck, ip, mp);
dtlck = (struct dt_lock *) & tlck->lock;
+ /* open new linelock */
+ if (unlikely(dtlck->index >= dtlck->maxcnt))
+ dtlck = txLinelock(dtlck);
+
/* linelock header of previous right sibling page */
lv = & dtlck->lv[dtlck->index];
lv->offset = 0;
@@ -1552,6 +1559,9 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
* split page moved out entries are linelocked;
* new/right page moved in entries are linelocked;
*/
+ /* open new linelock */
+ if (unlikely(rdtlck->index >= rdtlck->maxcnt))
+ rdtlck = txLinelock(rdtlck);
/* linelock header + stbl of new right page */
rlv = & rdtlck->lv[rdtlck->index];
rlv->offset = 0;
@@ -1834,6 +1844,9 @@ static int dtExtendPage(tid_t tid,
*/
tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
dtlck = (struct dt_lock *) & tlck->lock;
+ /* open new linelock */
+ if (unlikely(dtlck->index >= dtlck->maxcnt))
+ dtlck = txLinelock(dtlck);
lv = & dtlck->lv[dtlck->index];
/* linelock parent entry - 1st slot */
@@ -3809,10 +3822,16 @@ static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
sfsi = sp->header.freelist;
/* linelock destination entry slot */
+ /* open new linelock */
+ if (unlikely(ddtlck->index >= ddtlck->maxcnt))
+ ddtlck = txLinelock(ddtlck);
dlv = & ddtlck->lv[ddtlck->index];
dlv->offset = dsi;
/* linelock source entry slot */
+ /* open new linelock */
+ if (unlikely(sdtlck->index >= sdtlck->maxcnt))
+ sdtlck = txLinelock(sdtlck);
slv = & sdtlck->lv[sdtlck->index];
slv->offset = sstbl[si];
xssi = slv->offset - 1;
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index ecb8e05b8b84..194cb05b42b9 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -762,6 +762,9 @@ int diWrite(tid_t tid, struct inode *ip)
* copy inline symlink from in-memory inode to on-disk inode
*/
if (S_ISLNK(ip->i_mode) && ip->i_size < IDATASIZE) {
+ /* open new linelock */
+ if (unlikely(dilinelock->index >= dilinelock->maxcnt))
+ dilinelock = txLinelock(dilinelock);
lv = & dilinelock->lv[dilinelock->index];
lv->offset = (dioffset + 2 * 128) >> L2INODESLOTSIZE;
lv->length = 2;
@@ -773,6 +776,9 @@ int diWrite(tid_t tid, struct inode *ip)
* 128 byte slot granularity
*/
if (test_cflag(COMMIT_Inlineea, ip)) {
+ /* open new linelock */
+ if (unlikely(dilinelock->index >= dilinelock->maxcnt))
+ dilinelock = txLinelock(dilinelock);
lv = & dilinelock->lv[dilinelock->index];
lv->offset = (dioffset + 3 * 128) >> L2INODESLOTSIZE;
lv->length = 1;
@@ -785,6 +791,9 @@ int diWrite(tid_t tid, struct inode *ip)
/*
* lock/copy inode base: 128 byte slot granularity
*/
+ /* open new linelock */
+ if (unlikely(dilinelock->index >= dilinelock->maxcnt))
+ dilinelock = txLinelock(dilinelock);
lv = & dilinelock->lv[dilinelock->index];
lv->offset = dioffset >> L2INODESLOTSIZE;
copy_to_dinode(dp, ip);
--
2.34.1
Powered by blists - more mailing lists