* [PATCH] ext4: fix use-after-free in ext4 delayed I/O completion
@ 2026-07-09 7:56 Longxing Li
2026-07-09 13:46 ` Matthew Wilcox
2026-07-10 7:48 ` [syzbot ci] " syzbot ci
0 siblings, 2 replies; 4+ messages in thread
From: Longxing Li @ 2026-07-09 7:56 UTC (permalink / raw)
To: akpm, willy, linux-ext4, adilger.kernel, linux-fsdevel, linux-mm
Cc: linux-kernel, Longxing Li
ext4_add_complete_io() queues the inode's i_rsv_conversion_work without
holding an extra reference to the inode. If the inode is unlinked and
evicted before the delayed work runs, the inode slab object gets freed.
When ext4_do_flush_completed_IO() later accesses io_end->inode, it is
accessing a freed/reallocated object -- a use-after-free detected by KASAN.
Take igrab(inode) when first queueing the work (only when list is empty to
avoid duplicate references), and drop the reference in
ext4_do_flush_completed_IO() after processing all io_ends.
A per-inode bit (i_rsv_need_iput) tracks whether the extra reference
was taken.
This is a defense-in-depth fix complementary to the upstream fix
c678bdc99875 ("ext4: fix inode use after free in ext4_end_io_rsv_work()")
which adds consistency checks in ext4_io_end_defer_completion(). Both fixes
address the same root race but from different angles.
Fixes: ce51afb8cc5e ("ext4: abort journal on data writeback failure if in data_err=abort mode")
Reported-by: Longxing Li <coregee2000@gmail.com>
Signed-off-by: Longxing Li <coregee2000@gmail.com>
---
fs/ext4/ext4.h | 2 ++
fs/ext4/page-io.c | 15 +++++++++++++--
fs/ext4/super.c | 1 +
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 56112f201cac..239e6c0a3d3c 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1179,6 +1179,8 @@ struct ext4_inode_info {
/* Lock protecting lists below */
spinlock_t i_completed_io_lock;
+ /* Track if ext4_add_complete_io() took an extra inode reference. */
+ unsigned short i_rsv_need_iput:1;
/*
* Completed IOs that need unwritten extents handling and have
* transaction reserved
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 39abfeec5f36..294c0bcbbb7f 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -262,8 +262,12 @@ static void ext4_add_complete_io(ext4_io_end_t *io_end)
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
wq = sbi->rsv_conversion_wq;
- if (list_empty(&ei->i_rsv_conversion_list))
- queue_work(wq, &ei->i_rsv_conversion_work);
+ if (list_empty(&ei->i_rsv_conversion_list)) {
+ if (igrab(io_end->inode)) {
+ ei->i_rsv_need_iput = 1;
+ queue_work(wq, &ei->i_rsv_conversion_work);
+ }
+ }
list_add_tail(&io_end->list, &ei->i_rsv_conversion_list);
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
}
@@ -291,6 +295,13 @@ static int ext4_do_flush_completed_IO(struct inode *inode,
if (unlikely(!ret && err))
ret = err;
}
+
+ /* Release inode reference from ext4_add_complete_io. */
+ if (ei->i_rsv_need_iput) {
+ ei->i_rsv_need_iput = 0;
+ iput(&ei->vfs_inode);
+ }
+
return ret;
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 87205660c5d0..10a5d863d9b9 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1418,6 +1418,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
ei->jinode = NULL;
INIT_LIST_HEAD(&ei->i_rsv_conversion_list);
spin_lock_init(&ei->i_completed_io_lock);
+ ei->i_rsv_need_iput = 0;
ei->i_sync_tid = 0;
ei->i_datasync_tid = 0;
INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] ext4: fix use-after-free in ext4 delayed I/O completion
2026-07-09 7:56 [PATCH] ext4: fix use-after-free in ext4 delayed I/O completion Longxing Li
@ 2026-07-09 13:46 ` Matthew Wilcox
2026-07-10 14:06 ` Theodore Tso
2026-07-10 7:48 ` [syzbot ci] " syzbot ci
1 sibling, 1 reply; 4+ messages in thread
From: Matthew Wilcox @ 2026-07-09 13:46 UTC (permalink / raw)
To: Longxing Li, Theodore Ts'o
Cc: akpm, linux-ext4, adilger.kernel, linux-fsdevel, linux-mm,
linux-kernel
On Thu, Jul 09, 2026 at 03:56:13PM +0800, Longxing Li wrote:
> ext4_add_complete_io() queues the inode's i_rsv_conversion_work without
> holding an extra reference to the inode. If the inode is unlinked and
> evicted before the delayed work runs, the inode slab object gets freed.
> When ext4_do_flush_completed_IO() later accesses io_end->inode, it is
> accessing a freed/reallocated object -- a use-after-free detected by KASAN.
>
> Take igrab(inode) when first queueing the work (only when list is empty to
> avoid duplicate references), and drop the reference in
> ext4_do_flush_completed_IO() after processing all io_ends.
> A per-inode bit (i_rsv_need_iput) tracks whether the extra reference
> was taken.
>
> This is a defense-in-depth fix complementary to the upstream fix
> c678bdc99875 ("ext4: fix inode use after free in ext4_end_io_rsv_work()")
> which adds consistency checks in ext4_io_end_defer_completion(). Both fixes
> address the same root race but from different angles.
Um. You've cc'd everybody except the maintainer. And this is already
fixed, but you want to fix it even more? I don't get it.
(also if this patch isn't AI slop, it's doing a Really Good Job of
pretending to be AI slop. Why would you choose 'unsigned short' as
the type?)
> Fixes: ce51afb8cc5e ("ext4: abort journal on data writeback failure if in data_err=abort mode")
> Reported-by: Longxing Li <coregee2000@gmail.com>
> Signed-off-by: Longxing Li <coregee2000@gmail.com>
> ---
> fs/ext4/ext4.h | 2 ++
> fs/ext4/page-io.c | 15 +++++++++++++--
> fs/ext4/super.c | 1 +
> 3 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 56112f201cac..239e6c0a3d3c 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -1179,6 +1179,8 @@ struct ext4_inode_info {
>
> /* Lock protecting lists below */
> spinlock_t i_completed_io_lock;
> + /* Track if ext4_add_complete_io() took an extra inode reference. */
> + unsigned short i_rsv_need_iput:1;
> /*
> * Completed IOs that need unwritten extents handling and have
> * transaction reserved
> diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
> index 39abfeec5f36..294c0bcbbb7f 100644
> --- a/fs/ext4/page-io.c
> +++ b/fs/ext4/page-io.c
> @@ -262,8 +262,12 @@ static void ext4_add_complete_io(ext4_io_end_t *io_end)
>
> spin_lock_irqsave(&ei->i_completed_io_lock, flags);
> wq = sbi->rsv_conversion_wq;
> - if (list_empty(&ei->i_rsv_conversion_list))
> - queue_work(wq, &ei->i_rsv_conversion_work);
> + if (list_empty(&ei->i_rsv_conversion_list)) {
> + if (igrab(io_end->inode)) {
> + ei->i_rsv_need_iput = 1;
> + queue_work(wq, &ei->i_rsv_conversion_work);
> + }
> + }
> list_add_tail(&io_end->list, &ei->i_rsv_conversion_list);
> spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
> }
> @@ -291,6 +295,13 @@ static int ext4_do_flush_completed_IO(struct inode *inode,
> if (unlikely(!ret && err))
> ret = err;
> }
> +
> + /* Release inode reference from ext4_add_complete_io. */
> + if (ei->i_rsv_need_iput) {
> + ei->i_rsv_need_iput = 0;
> + iput(&ei->vfs_inode);
> + }
> +
> return ret;
> }
>
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 87205660c5d0..10a5d863d9b9 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1418,6 +1418,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
> ei->jinode = NULL;
> INIT_LIST_HEAD(&ei->i_rsv_conversion_list);
> spin_lock_init(&ei->i_completed_io_lock);
> + ei->i_rsv_need_iput = 0;
> ei->i_sync_tid = 0;
> ei->i_datasync_tid = 0;
> INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* [syzbot ci] Re: ext4: fix use-after-free in ext4 delayed I/O completion
2026-07-09 7:56 [PATCH] ext4: fix use-after-free in ext4 delayed I/O completion Longxing Li
2026-07-09 13:46 ` Matthew Wilcox
@ 2026-07-10 7:48 ` syzbot ci
1 sibling, 0 replies; 4+ messages in thread
From: syzbot ci @ 2026-07-10 7:48 UTC (permalink / raw)
To: adilger.kernel, akpm, coregee2000, linux-ext4, linux-fsdevel,
linux-kernel, linux-mm, willy
Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v1] ext4: fix use-after-free in ext4 delayed I/O completion
https://lore.kernel.org/all/20260709075613.854-1-coregee2000@gmail.com
* [PATCH] ext4: fix use-after-free in ext4 delayed I/O completion
and found the following issue:
inconsistent lock state in igrab
Full report is available here:
https://ci.syzbot.org/series/91c98fac-dc4f-4090-8c56-abbc36b7cd36
***
inconsistent lock state in igrab
tree: mm-new
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/akpm/mm.git
base: 86f436567f2516a0083b210bedc933544826a2c3
arch: amd64
compiler: Debian clang version 22.1.6 (++20260514074242+fc4aad7b5db3-1~exp1~20260514074407.73), Debian LLD 22.1.6
config: https://ci.syzbot.org/builds/7d4608a1-deef-4f49-aff7-ee231c101f0a/config
================================
WARNING: inconsistent lock state
syzkaller #0 Not tainted
--------------------------------
inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage.
swapper/0/0 [HC0[0]:SC1[1]:HE0:SE0] takes:
ffff888112ebb350 (&sb->s_type->i_lock_key#23){+.?.}-{3:3}, at: igrab+0x2d/0x1e0
{SOFTIRQ-ON-W} state was registered at:
lock_acquire+0x116/0x340
_raw_spin_lock+0x2e/0x40
iget_locked+0x397/0x6a0
__ext4_iget+0x242/0x4290
ext4_get_journal_inode+0x30/0x1c0
ext4_load_and_init_journal+0x231/0x23f0
ext4_fill_super+0x3a64/0x6560
get_tree_bdev_flags+0x430/0x4f0
vfs_get_tree+0x92/0x2a0
do_new_mount+0x325/0xac0
init_mount+0xc3/0x110
do_mount_root+0xf4/0x260
mount_root_generic+0x1a7/0x370
prepare_namespace+0x71/0xa0
kernel_init_freeable+0x36e/0x4b0
kernel_init+0x1d/0x1d0
ret_from_fork+0x5b0/0xb20
ret_from_fork_asm+0x1a/0x30
irq event stamp: 682389
hardirqs last enabled at (682388): [<ffffffff81862340>] handle_softirqs+0x1a0/0x850
hardirqs last disabled at (682389): [<ffffffff8b73ff0e>] _raw_spin_lock_irqsave+0x8e/0x100
softirqs last enabled at (682374): [<ffffffff81862c35>] __irq_exit_rcu+0xd5/0x1f0
softirqs last disabled at (682387): [<ffffffff81862c35>] __irq_exit_rcu+0xd5/0x1f0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(&sb->s_type->i_lock_key#23);
<Interrupt>
lock(&sb->s_type->i_lock_key#23);
*** DEADLOCK ***
1 lock held by swapper/0/0:
#0: ffff888112ebb880 (&ei->i_completed_io_lock){..-.}-{3:3}, at: ext4_put_io_end_defer+0x442/0x700
stack backtrace:
CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
Call Trace:
<IRQ>
dump_stack_lvl+0x1a9/0x280
print_usage_bug+0x28b/0x2e0
mark_lock_irq+0x410/0x420
mark_lock+0x115/0x190
__lock_acquire+0x65c/0x2cd0
lock_acquire+0x116/0x340
_raw_spin_lock+0x2e/0x40
igrab+0x2d/0x1e0
ext4_put_io_end_defer+0x4d0/0x700
blk_update_request+0x57b/0xe30
scsi_end_request+0x77/0x820
scsi_io_completion+0x133/0x360
blk_done_softirq+0x10a/0x160
handle_softirqs+0x275/0x850
__irq_exit_rcu+0xd5/0x1f0
irq_exit_rcu+0x9/0x30
common_interrupt+0xbb/0xe0
</IRQ>
<TASK>
asm_common_interrupt+0x26/0x40
RIP: 0010:pv_native_safe_halt+0xf/0x20
Code: 57 5e 02 c3 cc cc cc cc cc cc cc 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa eb 07 0f 00 2d d3 07 18 00 fb f4 <e9> cc f3 02 00 cc cc cc cc cc cc cc cc cc cc cc cc 90 90 90 90 90
RSP: 0018:ffffffff8e007d80 EFLAGS: 00000286
RAX: ec158cdc8cc84600 RBX: ffffffff8198983a RCX: ec158cdc8cc84600
RDX: 0000000000000001 RSI: ffffffff8da4eee4 RDI: ffffffff8be557c0
RBP: ffffffff8e007eb0 R08: ffff8881210336db R09: 1ffff110242066db
R10: dffffc0000000000 R11: ffffed10242066dc R12: 1ffffffff1c12a78
R13: dffffc0000000000 R14: 0000000000000000 R15: 1ffffffff1c00fbc
default_idle+0x9/0x20
default_idle_call+0x72/0xb0
do_idle+0x1ea/0x4e0
cpu_startup_entry+0x43/0x60
rest_init+0x2de/0x300
start_kernel+0x3a6/0x400
x86_64_start_reservations+0x24/0x30
x86_64_start_kernel+0x137/0x1b0
common_startup_64+0x13e/0x147
</TASK>
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
To test a patch for this bug, please reply with `#syz test`
(should be on a separate line).
The patch should be attached to the email.
Note: arguments like custom git repos and branches are not supported.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] ext4: fix use-after-free in ext4 delayed I/O completion
2026-07-09 13:46 ` Matthew Wilcox
@ 2026-07-10 14:06 ` Theodore Tso
0 siblings, 0 replies; 4+ messages in thread
From: Theodore Tso @ 2026-07-10 14:06 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Longxing Li, akpm, linux-ext4, adilger.kernel, linux-fsdevel,
linux-mm, linux-kernel
On Thu, Jul 09, 2026 at 02:46:43PM -0500, Matthew Wilcox wrote:
>
> (also if this patch isn't AI slop, it's doing a Really Good Job of
> pretending to be AI slop. Why would you choose 'unsigned short' as
> the type?)
It's AI slop that didn't even bother to run it by an AI patch quality
review process such as Sashiko:
- [High] Skipping `queue_work()` when `igrab()` fails causes a permanent deadlock
during inode eviction by stranding pages in writeback state.
- [High] A data race and logical flaw with the 1-bit `i_rsv_need_iput` flag causes
permanent inode reference leaks during concurrent I/O completions.
Syzbot also reported the inconsistent igrab state issue. So it's AI
slop that wasted resources both with Shashiko and Syzbot....
Longxing Li, whether or not this is AI slop, this patch will tend to
cause me to distrust any future code submissions form you. I suggest
that you test patches and look at the code much more carefully before
sending, if you don't want to have a bad reputation as a patch
submitter.
Best regards,
- Ted
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-10 14:06 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-09 7:56 [PATCH] ext4: fix use-after-free in ext4 delayed I/O completion Longxing Li
2026-07-09 13:46 ` Matthew Wilcox
2026-07-10 14:06 ` Theodore Tso
2026-07-10 7:48 ` [syzbot ci] " syzbot ci
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox