{"id":25870,"date":"2026-09-18T04:32:00","date_gmt":"2026-09-17T20:32:00","guid":{"rendered":"https:\/\/www.54iter.cn\/?vuln=cve-2026-92501"},"modified":"2026-09-18T04:32:00","modified_gmt":"2026-09-17T20:32:00","slug":"cve-2026-92501","status":"publish","type":"vuln","link":"https:\/\/www.54iter.cn\/?vuln=cve-2026-92501","title":{"rendered":"CVE-2026-92501 &#8211; In the Linux kernel, the following vulnerability has been resolved:\n\next4: drain in-flight"},"content":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>ext4: drain in-flight DIO before buffered write fallback<\/p>\n<p>generic\/746 started failing intermittently on ext3 (no-extent inodes).<br \/>\nThe test triggers &#8216;Page cache invalidation failure on direct I\/O&#8217;<br \/>\nwarnings and subsequent fsync returns -EIO. Adding a 50ms delay<br \/>\nbetween ext4_buffered_write_iter() and filemap_write_and_wait_range()<br \/>\nin ext4_dio_write_iter() makes the race almost always reproducible.<\/p>\n<p>On no-extent inodes, DIO writes to holes cannot use unwritten extents,<br \/>\nso ext4_iomap_alloc() leaves m_flags=0 and ext4_map_blocks() returns 0.<br \/>\nThe iomap layer then returns -ENOTBLK, causing fallback to buffered I\/O.<\/p>\n<p>The fallback path in ext4_dio_write_iter() calls<br \/>\next4_buffered_write_iter() which dirties pages, then does flush and<br \/>\ninvalidate. However, there&#8217;s an unprotected window between<br \/>\next4_buffered_write_iter() returning (with inode lock released) and<br \/>\nthe subsequent flush+invalidate.<\/p>\n<p>Concurrent async DIO completions from other threads can run<br \/>\nkiocb_invalidate_post_direct_write() during this window. If pages have<br \/>\nbeen re-dirtied, post-invalidation finds dirty pages and triggers the<br \/>\nwarning, setting -EIO in the error sequence.<\/p>\n<p>Consider a file with two 4k extents: [hole][written]. Thread A does<br \/>\nDIO to the written extent, while thread B does DIO spanning both:<\/p>\n<p>  kworker A (4k DIO, allocated block)    kworker B (8k DIO, fallback)<br \/>\n  &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;    &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\n  inode_lock_shared()                    inode_lock_shared()<br \/>\n  iomap_dio_rw():                        iomap_dio_rw():<br \/>\n    kiocb_invalidate_pages -&gt; clean        iomap_begin -&gt; -ENOTBLK<br \/>\n    submit_bio (async)                     dio-&gt;size = 0<br \/>\n  inode_unlock_shared()                  inode_unlock_shared()<\/p>\n<p>  [bio pending in block layer]           \/* fallback: lock released *\/<br \/>\n                                         ext4_buffered_write_iter()<br \/>\n                                           inode_lock(exclusive)<br \/>\n                                           generic_perform_write()<br \/>\n                                             -&gt; dirty pages [0, 8k]<br \/>\n                                           inode_unlock(exclusive)<\/p>\n<p>                                         \/* pages dirty, no lock *\/<br \/>\n  [bio completes]                        filemap_write_and_wait_range()<br \/>\n  iomap_dio_complete()                     -&gt; flush dirty pages<br \/>\n    kiocb_invalidate_post_direct_write() invalidate_mapping_pages()<br \/>\n      invalidate_inode_pages2_range()<br \/>\n      -&gt; finds dirty page!<br \/>\n      -&gt; dio_warn_stale_pagecache()<br \/>\n      -&gt; errseq_set(-EIO)<\/p>\n<p>This issue can be triggered through normal I\/O paths, not just<br \/>\nintentionally overlapping DIO writes from userspace. For example,<br \/>\ngeneric\/746 uses a loop device where multiple kworkers issue concurrent<br \/>\nI\/O to the backing file. Additionally, when block_size &lt; folio_size,<br \/>\nnon-overlapping DIO writes that share a large folio can also trigger<br \/>\nthe race.<\/p>\n<p>Add inode_dio_wait() in ext4_buffered_write_iter() before<br \/>\next4_write_checks() to drain all in-flight DIO. This ensures that<br \/>\nall DIO clears existing pages before submitting IO (via<br \/>\nkiocb_invalidate_pages()), all BIO waits for all DIO to complete<br \/>\n(via inode_dio_wait()), and ext4_write_checks() observes the inode<br \/>\nsize after all completed DIO so that ext4_block_zero_eof() does not<br \/>\nrace with in-flight DIO, thus eliminating the race.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>ext4: drain in-flight DIO before buffered write fallback<\/p>\n<p>generic\/746 started failing intermittently on ext3 (no-extent inodes).<br \/>\nTh<\/p>\n","protected":false},"template":"","meta":[],"categories":[],"tags":[],"class_list":["post-25870","vuln","type-vuln","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln\/25870","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln"}],"about":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/types\/vuln"}],"wp:attachment":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=25870"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=25870"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=25870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}