Cloudanix VulnDB

CVE-2026-92501

None

CVSS

—

EPSS

0.2%

Published

Sep 17, 2026

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

A timing flaw in the Linux file system can cause some programs to see unexpected errors when they write data in two different fast modes at the same time.

Exploitation
Local Privilege
Attacker needs
Local User
Complexity
Moderate
Impact
Other
Component
OS kernel
Class
Race Condition
Remediation
Patch
Effort
Medium
Patch risk
Low

What it actually does

Race condition in ext4 allows concurrent async DIO completions to observe re-dirtied pages after buffered-write fallback, causing invalidate_inode_pages2_range to fail and set -EIO via errseq_set.

Why it matters to the business

Intermittent I/O errors on fsync can disrupt applications performing mixed direct and buffered writes on ext4, leading to unexpected application failures or perceived data-integrity issues on production file systems.

How an attack unfolds

An attacker or workload triggers concurrent DIO writes to files with holes or shared large folios on no-extent inodes; one thread falls back to buffered I/O while another completes async DIO, racing through the unprotected window between inode unlock and filemap_write_and_wait_range to leave dirty pages that later trigger the stale-pagecache warning.

How to fix it

Apply the upstream fix that inserts inode_dio_wait before ext4_write_checks in ext4_buffered_write_iter; rebuild and deploy the patched kernel across all affected systems.

How to confirm the fix worked

Confirm the patch is present by inspecting ext4_file.c for the inode_dio_wait call; re-run fstests generic/746 under load to verify absence of Page cache invalidation failure warnings.

Typical attack path

  1. Identify ext4 file system with no-extent inodes or block_size < folio_size
  2. Issue overlapping or concurrent DIO writes from multiple threads or kworkers
  3. Force fallback path via -ENOTBLK from iomap on hole extents
  4. Exploit timing window after ext4_buffered_write_iter releases lock but before invalidate
  5. Observe dio_warn_stale_pagecache and subsequent -EIO on fsync

How to detect it

Search kernel logs and dmesg for 'Page cache invalidation failure on direct I/O' or 'dio_warn_stale_pagecache'; correlate with ext4 fsync returning EIO on files recently written via O_DIRECT.

  • dio_warn_stale_pagecache
  • Page cache invalidation failure on direct I/O
  • ext4_dio_write_iter.*-EIO

What your security team should do

  • Prioritize kernel upgrade on all ext4 systems handling mixed DIO workloads
  • Monitor kernel logs for dio_warn_stale_pagecache messages
  • Temporarily disable direct I/O in applications if patching is delayed

The record

In the Linux kernel, the following vulnerability has been resolved: ext4: drain in-flight DIO before buffered write fallback generic/746 started failing intermittently on ext3 (no-extent inodes). The test triggers 'Page cache invalidation failure on direct I/O' warnings and subsequent fsync returns -EIO. Adding a 50ms delay between ext4_buffered_write_iter() and filemap_write_and_wait_range() in ext4_dio_write_iter() makes the race almost always reproducible. On no-extent inodes, DIO writes to holes cannot use unwritten extents, so ext4_iomap_alloc() leaves m_flags=0 and ext4_map_blocks() returns 0. The iomap layer then returns -ENOTBLK, causing fallback to buffered I/O. The fallback path in ext4_dio_write_iter() calls ext4_buffered_write_iter() which dirties pages, then does flush and invalidate. However, there's an unprotected window between ext4_buffered_write_iter() returning (with inode lock released) and the subsequent flush+invalidate. Concurrent async DIO completions from other threads can run kiocb_invalidate_post_direct_write() during this window. If pages have been re-dirtied, post-invalidation finds dirty pages and triggers the warning, setting -EIO in the error sequence. Consider a file with two 4k extents: [hole][written]. Thread A does DIO to the written extent, while thread B does DIO spanning both: kworker A (4k DIO, allocated block) kworker B (8k DIO, fallback) ----------------------------------- ---------------------------- inode_lock_shared() inode_lock_shared() iomap_dio_rw(): iomap_dio_rw(): kiocb_invalidate_pages -> clean iomap_begin -> -ENOTBLK submit_bio (async) dio->size = 0 inode_unlock_shared() inode_unlock_shared() [bio pending in block layer] /* fallback: lock released */ ext4_buffered_write_iter() inode_lock(exclusive) generic_perform_write() -> dirty pages [0, 8k] inode_unlock(exclusive) /* pages dirty, no lock */ [bio completes] filemap_write_and_wait_range() iomap_dio_complete() -> flush dirty pages kiocb_invalidate_post_direct_write() invalidate_mapping_pages() invalidate_inode_pages2_range() -> finds dirty page! -> dio_warn_stale_pagecache() -> errseq_set(-EIO) This issue can be triggered through normal I/O paths, not just intentionally overlapping DIO writes from userspace. For example, generic/746 uses a loop device where multiple kworkers issue concurrent I/O to the backing file. Additionally, when block_size < folio_size, non-overlapping DIO writes that share a large folio can also trigger the race. Add inode_dio_wait() in ext4_buffered_write_iter() before ext4_write_checks() to drain all in-flight DIO. This ensures that all DIO clears existing pages before submitting IO (via kiocb_invalidate_pages()), all BIO waits for all DIO to complete (via inode_dio_wait()), and ext4_write_checks() observes the inode size after all completed DIO so that ext4_block_zero_eof() does not race with in-flight DIO, thus eliminating the race.

Affected packages

Ecosystem Package Introduced Fixed