[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251121131305.332698-1-kartikey406@gmail.com>
Date: Fri, 21 Nov 2025 18:43:05 +0530
From: Deepanshu Kartikey <kartikey406@...il.com>
To: tytso@....edu,
adilger.kernel@...ger.ca
Cc: linux-ext4@...r.kernel.org,
linux-kernel@...r.kernel.org,
Deepanshu Kartikey <kartikey406@...il.com>,
syzbot+b0a0670332b6b3230a0a@...kaller.appspotmail.com
Subject: [PATCH] ext4: check folio uptodate state in ext4_page_mkwrite()
When a write fault occurs on a memory-mapped ext4 file, ext4_page_mkwrite()
is called to prepare the folio for writing. However, if the folio could
not be read successfully due to filesystem corruption or I/O errors, it
will not be marked uptodate.
Attempting to write to a non-uptodate folio is problematic because:
1. We don't have valid data from the backing store to preserve
2. A subsequent writeback could write uninitialized data to disk
3. It triggers a warning in __folio_mark_dirty():
WARN_ON_ONCE(warn && !folio_test_uptodate(folio))
This issue can be reproduced by:
1. Creating a corrupted ext4 filesystem with invalid extent entries
2. Memory-mapping a file on that filesystem
3. Attempting to write to the mapped region
The sequence of events is:
- User accesses mmap region -> page fault
- ext4_filemap_fault() -> ext4_map_blocks() detects corruption
- Returns error, folio allocated but NOT marked uptodate
- User writes to same region -> ext4_page_mkwrite() called
- Without check: folio marked dirty -> WARNING
- With check: return VM_FAULT_SIGBUS immediately
Fix this by checking folio_test_uptodate() early in ext4_page_mkwrite(),
before any code paths (delalloc, journal data, or normal). This ensures
all paths are protected. If the folio is not uptodate, unlock it and
return VM_FAULT_SIGBUS to signal the error to userspace.
Reported-by: syzbot+b0a0670332b6b3230a0a@...kaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b0a0670332b6b3230a0a
Signed-off-by: Deepanshu Kartikey <kartikey406@...il.com>
---
fs/ext4/inode.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index e99306a8f47c..18a029362c1f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -6688,6 +6688,14 @@ vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf)
if (err)
goto out_ret;
+ folio_lock(folio);
+ if (!folio_test_uptodate(folio)) {
+ folio_unlock(folio);
+ ret = VM_FAULT_SIGBUS;
+ goto out;
+ }
+ folio_unlock(folio);
+
/*
* On data journalling we skip straight to the transaction handle:
* there's no delalloc; page truncated will be checked later; the
--
2.43.0
Powered by blists - more mailing lists