CVE-2025-68168: Add .vulnerable file

Root Cause Commit: 95e2b352c03b0a86c5717ba1d24ea20969abcacc
Title: "FS: JFS: Check for read-only mounted filesystem in txBegin"
Author: Immad Mir
Date: June 23, 2023

Technical Details:

The Fix Commit (300b072df72694ea330c4c673c035253e07827b8)

The fix modifies txInit() in fs/jfs/jfs_txnmgr.c to ensure all
TxBlock[] entries have their waitqueues initialized, including
TxBlock[0]:

Before:
    for (k = 1; k < nTxBlock - 1; k++) {
        TxBlock[k].next = k + 1;
        init_waitqueue_head(&TxBlock[k].gcwait);
        init_waitqueue_head(&TxBlock[k].waitor);
    }
    TxBlock[k].next = 0;
    init_waitqueue_head(&TxBlock[k].gcwait);
    init_waitqueue_head(&TxBlock[k].waitor);

After:
    for (k = 0; k < nTxBlock; k++) {
        init_waitqueue_head(&TxBlock[k].gcwait);
        init_waitqueue_head(&TxBlock[k].waitor);
    }
    for (k = 1; k < nTxBlock - 1; k++) {
        TxBlock[k].next = k + 1;
    }

The Bug Chain:

1. Original Design (since Linux 2.6.12-rc2, commit 1da177e4c3f4):
   - TxBlock[0] was intentionally not initialized because tid=0 was
     "reserved" and never used
   - The code comment at fs/jfs/jfs_txnmgr.c:289 states: "tid = 0 is
     reserved."
   - txBegin() would NEVER return 0 - it would block and retry via
     TXN_SLEEP() if no tids were available
   - TxAnchor.freetid was initialized to 1, not 0

2. Root Cause (commit 95e2b352c03b, June 2023):
This commit added a read-only filesystem check at the beginning of
txBegin():

       if (!log) {
           jfs_error(sb, "read-only filesystem\n");
           return 0;  // <-- BUG INTRODUCED HERE
       }

   This creates a NEW code path where txBegin() returns tid=0.

3. Exploitation Path:
   - When a JFS filesystem is mounted read-only, JFS_SBI(sb)->log is
     NULL
   - txBegin() now returns tid=0
   - Callers like jfs_write_inode() don't check for tid=0 and proceed to
     call txEnd(tid)
   - txEnd(0) calls tid_to_tblock(0) which expands to &TxBlock[0]
     (defined
     in fs/jfs/jfs_txnmgr.h:13)
   - txEnd() then calls TXN_WAKEUP(&tblk->waitor) at line 504
   - TxBlock[0].waitor was NEVER initialized, causing a lockdep warning
     and crash:
         INFO: trying to register non-static key in txEnd

Why Commit 95e2b352c03b is the Root Cause:

Before this commit:
- txBegin() would always return a valid tid >= 1 or block waiting
- The loop "if ((t = TxAnchor.freetid) == 0) { TXN_SLEEP(...); goto
  retry; }" ensured no 0 return
- TxBlock[0] not being initialized was irrelevant since it was never
  accessed

After this commit:
- txBegin() can return 0 immediately on read-only filesystems
- Callers proceed to use this tid=0, eventually calling txEnd(0)
- txEnd(0) accesses the uninitialized TxBlock[0].waitor, triggering the
  crash

The commit intended to fix a NULL pointer dereference on log access,
but inadvertently broke the invariant that tid=0 is never used, exposing
the latent uninitialized memory in TxBlock[0].

Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 file changed