[BUG] ocfs2: NULL osb->journal deref via ocfs2_checkpoint_inode on unmount

From: Farhad Alemi

Date: Fri May 29 2026 - 01:40:05 EST


Hello Joseph, Mark, Joel, and the ocfs2 team,

I am reporting a KASAN null-ptr-deref GPF in the ocfs2 unmount path
found by syzkaller as part of research at the SEFCOM Lab at ASU.

Summary:
During unmount, ocfs2_clear_inode() calls ocfs2_checkpoint_inode()
without checking that osb->journal is still live. At
fs/ocfs2/inode.c:1223-1224:

if (!(oi->ip_flags & OCFS2_INODE_DELETED))
ocfs2_checkpoint_inode(inode);

ocfs2_checkpoint_inode() (fs/ocfs2/journal.h:192) reaches
ocfs2_ci_fully_checkpointed() (fs/ocfs2/journal.h:91), which loads
osb->journal and dereferences it:

struct ocfs2_journal *journal =
OCFS2_SB(ocfs2_metadata_cache_get_super(ci))->journal;
spin_lock(&trans_inc_lock);
ret = time_after(journal->j_trans_id, ci->ci_last_trans); <-- :98

On the unmount-side slot-info eviction, ocfs2_journal_shutdown() has
already set osb->journal = NULL (fs/ocfs2/journal.c:1130) before
ocfs2_delete_osb() evicts the slot inodes, so the journal->j_trans_id
load at journal.h:98 faults. The KASAN range is [0x70, 0x77] (see
crash-report.txt); the RIP chain is:

ocfs2_ci_fully_checkpointed fs/ocfs2/journal.h:98 [inline]
ocfs2_checkpoint_inode fs/ocfs2/journal.h:199 [inline]
ocfs2_clear_inode fs/ocfs2/inode.c:1224 [inline]
ocfs2_evict_inode+0x244c/0x43c0 fs/ocfs2/inode.c:1303

Observed on:
- Linux v7.1-rc3-200-g70eda68668d1-dirty,
x86_64, QEMU Q35
- KASAN enabled
- The only local dirty file in my tree is
drivers/tty/serial/serial_core.c, a ttyS0 console guard for the
fuzzing harness, unrelated to fs/ocfs2/.
- Source inspection of linus/master at commit e8c2f9fdadee
(v7.1-rc4-754-ge8c2f9fdadee) shows the structure is unchanged:
ocfs2_clear_inode() at fs/ocfs2/inode.c:1223-1224 still calls
ocfs2_checkpoint_inode() with no osb->journal check, and
ocfs2_ci_fully_checkpointed() at fs/ocfs2/journal.h:98 still
dereferences journal->j_trans_id unconditionally. As no reproducer
is available for this seed, I have not re-run it against e8c2f9fdadee.

Impact:
An ocfs2 unmount kills the kernel with a GPF / KASAN null-ptr-deref.
The full Oops header, register dump, and call trace are in
crash-report.txt.

Expected behavior:
Either ocfs2_clear_inode() should skip ocfs2_checkpoint_inode() when
osb->journal is NULL (the same shape as the existing guard at
fs/ocfs2/inode.c:1286), or ocfs2_ci_fully_checkpointed() should treat
a NULL journal as "fully checkpointed".

Reproducer:
A standalone .syz or C reproducer was not produced for this seed; the
crash fired during automated ocfs2 mount/unmount fuzzing. The console
report is attached as crash-report.txt.

Novelty check:
I searched the syzbot dashboard's upstream open, fixed, stable, and
invalid (per-subsystem ocfs2) namespaces; the Android dashboard; the
marc.info linux-fsdevel archive; and lore, for
"ocfs2_ci_fully_checkpointed", "ocfs2_checkpoint_inode",
"ocfs2_clear_inode" + journal, and "ocfs2_evict_inode" + GPF. I did
not find a prior report of this specific dereference.

There are three closely related syzbot reports, all titled by the
outer frame:
"general protection fault in ocfs2_evict_inode" (id 9d4aa7d1...),
"general protection fault in ocfs2_clear_inode" (id 9eca3ca3...),
and "...ocfs2_clear_inode (2)" (id 9e34a0dc...). They share this
unmount slot-info eviction reach path but fault at offset 0x8 of the
NULL pointer (KASAN range [0x8, 0xf]); this crash faults at offset
0x70, inside ocfs2_ci_fully_checkpointed() at journal.h:98 (the
journal->j_trans_id read) -- a distinct dereference site. Commit
f46e8ef8bb7b ("ocfs2: prevent release journal inode after journal
shutdown", first in v6.17-rc5) added an osb->journal guard before the
jbd2_journal_release_jbd_inode() call at fs/ocfs2/inode.c:1286, but
the earlier ocfs2_checkpoint_inode() call in the same
ocfs2_clear_inode() is not guarded.


I appreciate your time and consideration, and I'm grateful for your
work on this subsystem. I'd be glad to test any candidate patches.

Regards,
ocfs2: Unmounting device (7,3) on (node 0)
Oops: general protection fault, probably for non-canonical address 0xdffffc000000000e: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077]
CPU: 0 UID: 0 PID: 8131 Comm: syz-executor Not tainted 7.1.0-rc3-00200-g70eda68668d1-dirty #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:ocfs2_ci_fully_checkpointed fs/ocfs2/journal.h:98 [inline]
RIP: 0010:ocfs2_checkpoint_inode fs/ocfs2/journal.h:199 [inline]
RIP: 0010:ocfs2_clear_inode fs/ocfs2/inode.c:1224 [inline]
RIP: 0010:ocfs2_evict_inode+0x244c/0x43c0 fs/ocfs2/inode.c:1303
Code: c1 ec 03 43 80 3c 2c 00 74 08 48 89 df e8 3c d1 d6 fe 4c 8b 2b 49 83 c6 70 4c 89 f0 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 4c 89 f7 e8 16 d1 d6 fe 4d 8b 36 48 c7 c7 a0 89
RSP: 0018:ffffc90000557320 EFLAGS: 00010202
RAX: 000000000000000e RBX: ffff88812e722428 RCX: dffffc0000000000
RDX: 0000000000000001 RSI: 0000000000000004 RDI: ffffc900005572a0
RBP: ffffc90000557a50 R08: 0000000000000003 R09: 0000000000000004
R10: dffffc0000000000 R11: fffff520000aae54 R12: 1ffff11025ce4485
R13: 0000000000000000 R14: 0000000000000070 R15: fffff520000aae74
FS: 000055556a0f8500(0000) GS:ffff8882ab6b6000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ffc654f2d60 CR3: 000000014aaf7000 CR4: 0000000000750ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000600
PKRU: 80000000
Call Trace:
<TASK>
evict+0x623/0xb10 fs/inode.c:841
__ocfs2_free_slot_info fs/ocfs2/slot_map.c:311 [inline]
ocfs2_free_slot_info+0x7e/0x260 fs/ocfs2/slot_map.c:465
ocfs2_delete_osb+0x5d/0x180 fs/ocfs2/super.c:2450
ocfs2_dismount_volume+0x57d/0x8e0 fs/ocfs2/super.c:1884
generic_shutdown_super+0x142/0x2d0 fs/super.c:646
kill_block_super+0x49/0xa0 fs/super.c:1725
deactivate_locked_super+0xc1/0x130 fs/super.c:476
cleanup_mnt+0x43c/0x4e0 fs/namespace.c:1312
task_work_run+0x1de/0x270 kernel/task_work.c:233
resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
__exit_to_user_mode_loop kernel/entry/common.c:67 [inline]
exit_to_user_mode_loop+0xe7/0x4b0 kernel/entry/common.c:98
__exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
do_syscall_64+0x33e/0x560 arch/x86/entry/syscall_64.c:100
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f2c4160918b
Code: 3b 16 00 00 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 31 f6 e9 05 00 00 00 0f 1f 44 00 00 f3 0f 1e fa b8 a6 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 05 c3 0f 1f 40 00 48 c7 c2 b0 ff ff ff f7 d8
RSP: 002b:00007ffc654f3428 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
RAX: 0000000000000000 RBX: 00007f2c416adfed RCX: 00007f2c4160918b
RDX: 00007f2c414b35c1 RSI: 0000000000000009 RDI: 00007ffc654f34e0
RBP: 00007ffc654f34e0 R08: 0000000000000073 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffc654f45b0
R13: 00007f2c416adfed R14: 0000000000000032 R15: 0000000000080599
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:ocfs2_ci_fully_checkpointed fs/ocfs2/journal.h:98 [inline]
RIP: 0010:ocfs2_checkpoint_inode fs/ocfs2/journal.h:199 [inline]
RIP: 0010:ocfs2_clear_inode fs/ocfs2/inode.c:1224 [inline]
RIP: 0010:ocfs2_evict_inode+0x244c/0x43c0 fs/ocfs2/inode.c:1303
Code: c1 ec 03 43 80 3c 2c 00 74 08 48 89 df e8 3c d1 d6 fe 4c 8b 2b 49 83 c6 70 4c 89 f0 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 4c 89 f7 e8 16 d1 d6 fe 4d 8b 36 48 c7 c7 a0 89
RSP: 0018:ffffc90000557320 EFLAGS: 00010202
RAX: 000000000000000e RBX: ffff88812e722428 RCX: dffffc0000000000
RDX: 0000000000000001 RSI: 0000000000000004 RDI: ffffc900005572a0
RBP: ffffc90000557a50 R08: 0000000000000003 R09: 0000000000000004
R10: dffffc0000000000 R11: fffff520000aae54 R12: 1ffff11025ce4485
R13: 0000000000000000 R14: 0000000000000070 R15: fffff520000aae74
FS: 000055556a0f8500(0000) GS:ffff8882ab6b6000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ffc654f2d60 CR3: 000000014aaf7000 CR4: 0000000000750ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000600
PKRU: 80000000
----------------
Code disassembly (best guess):
0: c1 ec 03 shr $0x3,%esp
3: 43 80 3c 2c 00 cmpb $0x0,(%r12,%r13,1)
8: 74 08 je 0x12
a: 48 89 df mov %rbx,%rdi
d: e8 3c d1 d6 fe call 0xfed6d14e
12: 4c 8b 2b mov (%rbx),%r13
15: 49 83 c6 70 add $0x70,%r14
19: 4c 89 f0 mov %r14,%rax
1c: 48 c1 e8 03 shr $0x3,%rax
20: 48 b9 00 00 00 00 00 movabs $0xdffffc0000000000,%rcx
27: fc ff df
* 2a: 80 3c 08 00 cmpb $0x0,(%rax,%rcx,1) <-- trapping instruction
2e: 74 08 je 0x38
30: 4c 89 f7 mov %r14,%rdi
33: e8 16 d1 d6 fe call 0xfed6d14e
38: 4d 8b 36 mov (%r14),%r14
3b: 48 rex.W
3c: c7 .byte 0xc7
3d: c7 (bad)
3e: a0 .byte 0xa0
3f: 89 .byte 0x89

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>