CVE-2024-47741

Severity CVSS v4.0:
Pending analysis
Type:
CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
Publication date:
21/10/2024
Last modified:
23/10/2024

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> btrfs: fix race setting file private on concurrent lseek using same fd<br /> <br /> When doing concurrent lseek(2) system calls against the same file<br /> descriptor, using multiple threads belonging to the same process, we have<br /> a short time window where a race happens and can result in a memory leak.<br /> <br /> The race happens like this:<br /> <br /> 1) A program opens a file descriptor for a file and then spawns two<br /> threads (with the pthreads library for example), lets call them<br /> task A and task B;<br /> <br /> 2) Task A calls lseek with SEEK_DATA or SEEK_HOLE and ends up at<br /> file.c:find_desired_extent() while holding a read lock on the inode;<br /> <br /> 3) At the start of find_desired_extent(), it extracts the file&amp;#39;s<br /> private_data pointer into a local variable named &amp;#39;private&amp;#39;, which has<br /> a value of NULL;<br /> <br /> 4) Task B also calls lseek with SEEK_DATA or SEEK_HOLE, locks the inode<br /> in shared mode and enters file.c:find_desired_extent(), where it also<br /> extracts file-&gt;private_data into its local variable &amp;#39;private&amp;#39;, which<br /> has a NULL value;<br /> <br /> 5) Because it saw a NULL file private, task A allocates a private<br /> structure and assigns to the file structure;<br /> <br /> 6) Task B also saw a NULL file private so it also allocates its own file<br /> private and then assigns it to the same file structure, since both<br /> tasks are using the same file descriptor.<br /> <br /> At this point we leak the private structure allocated by task A.<br /> <br /> Besides the memory leak, there&amp;#39;s also the detail that both tasks end up<br /> using the same cached state record in the private structure (struct<br /> btrfs_file_private::llseek_cached_state), which can result in a<br /> use-after-free problem since one task can free it while the other is<br /> still using it (only one task took a reference count on it). Also, sharing<br /> the cached state is not a good idea since it could result in incorrect<br /> results in the future - right now it should not be a problem because it<br /> end ups being used only in extent-io-tree.c:count_range_bits() where we do<br /> range validation before using the cached state.<br /> <br /> Fix this by protecting the private assignment and check of a file while<br /> holding the inode&amp;#39;s spinlock and keep track of the task that allocated<br /> the private, so that it&amp;#39;s used only by that task in order to prevent<br /> user-after-free issues with the cached state record as well as potentially<br /> using it incorrectly in the future.

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.2 (including) 6.6.54 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.7 (including) 6.10.13 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.11 (including) 6.11.2 (excluding)