mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
iomap: avoid potential null folio->mapping deref during error reporting
When a buffered read fails, iomap_finish_folio_read() reports the error
with fserror_report_io(folio->mapping->host, ...). This is called after
ifs->read_bytes_pending has been decremented by the bytes attempted to
be read.
For a folio split across multiple read completions, the folio is only
guaranteed to stay locked while read_bytes_pending > 0. Once
iomap_finish_folio_read() decrements read_bytes_pending, another
in-flight read can complete and end the read on the folio, which unlocks
it. This allows truncate logic to run and detach the folio (set
folio->mapping to NULL). The error reporting path then can dereference a
NULL folio->mapping. As reported by Sam Sun, this is the race that can
occur:
CPU0: failed completion CPU1: final completion CPU2: truncate
----------------------- ---------------------- --------------
read_bytes_pending -= len
finished = false
/* preempted before
fserror_report_io() */
read_bytes_pending -= len
finished = true
folio_end_read()
truncate clears
folio->mapping
fserror_report_io(
folio->mapping->host, ...)
^ NULL deref
Fix this by reporting the error first before decrementing
ifs->read_bytes_pending.
Fixes: a9d573ee88 ("iomap: report file I/O errors to the VFS")
Cc: stable@vger.kernel.org
Reported-by: Sam Sun <samsun1006219@gmail.com>
Closes: https://lore.kernel.org/linux-fsdevel/CAEkJfYPhWdd59RKmuNLJg-bkypHz7xiOwaWyNVu3A8CUqQCnvg@mail.gmail.com/
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Link: https://patch.msgid.link/20260604011858.2297561-1-joannelkoong@gmail.com
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
committed by
Christian Brauner
parent
40ab6644b9
commit
2eea7f44b9
@@ -400,6 +400,11 @@ void iomap_finish_folio_read(struct folio *folio, size_t off, size_t len,
|
||||
bool uptodate = !error;
|
||||
bool finished = true;
|
||||
|
||||
if (error)
|
||||
fserror_report_io(folio->mapping->host, FSERR_BUFFERED_READ,
|
||||
folio_pos(folio) + off, len, error,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (ifs) {
|
||||
unsigned long flags;
|
||||
|
||||
@@ -411,11 +416,6 @@ void iomap_finish_folio_read(struct folio *folio, size_t off, size_t len,
|
||||
spin_unlock_irqrestore(&ifs->state_lock, flags);
|
||||
}
|
||||
|
||||
if (error)
|
||||
fserror_report_io(folio->mapping->host, FSERR_BUFFERED_READ,
|
||||
folio_pos(folio) + off, len, error,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (finished)
|
||||
folio_end_read(folio, uptodate);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user