CVE-2024-27080

Severity CVSS v4.0:
Pending analysis
Type:
CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
Publication date:
01/05/2024
Last modified:
18/09/2025

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> btrfs: fix race when detecting delalloc ranges during fiemap<br /> <br /> For fiemap we recently stopped locking the target extent range for the<br /> whole duration of the fiemap call, in order to avoid a deadlock in a<br /> scenario where the fiemap buffer happens to be a memory mapped range of<br /> the same file. This use case is very unlikely to be useful in practice but<br /> it may be triggered by fuzz testing (syzbot, etc).<br /> <br /> This however introduced a race that makes us miss delalloc ranges for<br /> file regions that are currently holes, so the caller of fiemap will not<br /> be aware that there&amp;#39;s data for some file regions. This can be quite<br /> serious for some use cases - for example in coreutils versions before 9.0,<br /> the cp program used fiemap to detect holes and data in the source file,<br /> copying only regions with data (extents or delalloc) from the source file<br /> to the destination file in order to preserve holes (see the documentation<br /> for its --sparse command line option). This means that if cp was used<br /> with a source file that had delalloc in a hole, the destination file could<br /> end up without that data, which is effectively a data loss issue, if it<br /> happened to hit the race described below.<br /> <br /> The race happens like this:<br /> <br /> 1) Fiemap is called, without the FIEMAP_FLAG_SYNC flag, for a file that<br /> has delalloc in the file range [64M, 65M[, which is currently a hole;<br /> <br /> 2) Fiemap locks the inode in shared mode, then starts iterating the<br /> inode&amp;#39;s subvolume tree searching for file extent items, without having<br /> the whole fiemap target range locked in the inode&amp;#39;s io tree - the<br /> change introduced recently by commit b0ad381fa769 ("btrfs: fix<br /> deadlock with fiemap and extent locking"). It only locks ranges in<br /> the io tree when it finds a hole or prealloc extent since that<br /> commit;<br /> <br /> 3) Note that fiemap clones each leaf before using it, and this is to<br /> avoid deadlocks when locking a file range in the inode&amp;#39;s io tree and<br /> the fiemap buffer is memory mapped to some file, because writing<br /> to the page with btrfs_page_mkwrite() will wait on any ordered extent<br /> for the page&amp;#39;s range and the ordered extent needs to lock the range<br /> and may need to modify the same leaf, therefore leading to a deadlock<br /> on the leaf;<br /> <br /> 4) While iterating the file extent items in the cloned leaf before<br /> finding the hole in the range [64M, 65M[, the delalloc in that range<br /> is flushed and its ordered extent completes - meaning the corresponding<br /> file extent item is in the inode&amp;#39;s subvolume tree, but not present in<br /> the cloned leaf that fiemap is iterating over;<br /> <br /> 5) When fiemap finds the hole in the [64M, 65M[ range by seeing the gap in<br /> the cloned leaf (or a file extent item with disk_bytenr == 0 in case<br /> the NO_HOLES feature is not enabled), it will lock that file range in<br /> the inode&amp;#39;s io tree and then search for delalloc by checking for the<br /> EXTENT_DELALLOC bit in the io tree for that range and ordered extents<br /> (with btrfs_find_delalloc_in_range()). But it finds nothing since the<br /> delalloc in that range was already flushed and the ordered extent<br /> completed and is gone - as a result fiemap will not report that there&amp;#39;s<br /> delalloc or an extent for the range [64M, 65M[, so user space will be<br /> mislead into thinking that there&amp;#39;s a hole in that range.<br /> <br /> This could actually be sporadically triggered with test case generic/094<br /> from fstests, which reports a missing extent/delalloc range like this:<br /> <br /> generic/094 2s ... - output mismatch (see /home/fdmanana/git/hub/xfstests/results//generic/094.out.bad)<br /> --- tests/generic/094.out 2020-06-10 19:29:03.830519425 +0100<br /> +++ /home/fdmanana/git/hub/xfstests/results//generic/094.out.bad 2024-02-28 11:00:00.381071525 +0000<br /> @@ -1,3 +1,9 @@<br /> QA output created by 094<br /> fiemap run with sync<br /> fiemap run without sync<br /> +ERROR: couldn&amp;#39;t find extent at 7<br /> +map is &amp;#39;HHDDHPPDPHPH&amp;#39;<br /> +logical: [ 5.. 6] phys:<br /> ---truncated---

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.6.24 (including) 6.6.26 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.7.12 (including) 6.8 (excluding)
cpe:2.3:o:linux:linux_kernel:6.8:-:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.8:rc6:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.8:rc7:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.8.1:*:*:*:*:*:*:*