| From bippy-5f407fcff5a0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2024-47741: btrfs: fix race setting file private on concurrent lseek using same fd |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| btrfs: fix race setting file private on concurrent lseek using same fd |
| |
| When doing concurrent lseek(2) system calls against the same file |
| descriptor, using multiple threads belonging to the same process, we have |
| a short time window where a race happens and can result in a memory leak. |
| |
| The race happens like this: |
| |
| 1) A program opens a file descriptor for a file and then spawns two |
| threads (with the pthreads library for example), lets call them |
| task A and task B; |
| |
| 2) Task A calls lseek with SEEK_DATA or SEEK_HOLE and ends up at |
| file.c:find_desired_extent() while holding a read lock on the inode; |
| |
| 3) At the start of find_desired_extent(), it extracts the file's |
| private_data pointer into a local variable named 'private', which has |
| a value of NULL; |
| |
| 4) Task B also calls lseek with SEEK_DATA or SEEK_HOLE, locks the inode |
| in shared mode and enters file.c:find_desired_extent(), where it also |
| extracts file->private_data into its local variable 'private', which |
| has a NULL value; |
| |
| 5) Because it saw a NULL file private, task A allocates a private |
| structure and assigns to the file structure; |
| |
| 6) Task B also saw a NULL file private so it also allocates its own file |
| private and then assigns it to the same file structure, since both |
| tasks are using the same file descriptor. |
| |
| At this point we leak the private structure allocated by task A. |
| |
| Besides the memory leak, there's also the detail that both tasks end up |
| using the same cached state record in the private structure (struct |
| btrfs_file_private::llseek_cached_state), which can result in a |
| use-after-free problem since one task can free it while the other is |
| still using it (only one task took a reference count on it). Also, sharing |
| the cached state is not a good idea since it could result in incorrect |
| results in the future - right now it should not be a problem because it |
| end ups being used only in extent-io-tree.c:count_range_bits() where we do |
| range validation before using the cached state. |
| |
| Fix this by protecting the private assignment and check of a file while |
| holding the inode's spinlock and keep track of the task that allocated |
| the private, so that it's used only by that task in order to prevent |
| user-after-free issues with the cached state record as well as potentially |
| using it incorrectly in the future. |
| |
| The Linux kernel CVE team has assigned CVE-2024-47741 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 6.2 with commit 3c32c7212f1639471ec0197ff1179b8ef2e0f3d3 and fixed in 6.6.54 with commit f56a6d9c267ec7fa558ede7755551c047b1034cd |
| Issue introduced in 6.2 with commit 3c32c7212f1639471ec0197ff1179b8ef2e0f3d3 and fixed in 6.10.13 with commit a412ca489ac27b9d0e603499315b7139c948130d |
| Issue introduced in 6.2 with commit 3c32c7212f1639471ec0197ff1179b8ef2e0f3d3 and fixed in 6.11.2 with commit 33d1310d4496e904123dab9c28b2d8d2c1800f97 |
| Issue introduced in 6.2 with commit 3c32c7212f1639471ec0197ff1179b8ef2e0f3d3 and fixed in 6.12 with commit 7ee85f5515e86a4e2a2f51969795920733912bad |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2024-47741 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| fs/btrfs/btrfs_inode.h |
| fs/btrfs/ctree.h |
| fs/btrfs/file.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/f56a6d9c267ec7fa558ede7755551c047b1034cd |
| https://git.kernel.org/stable/c/a412ca489ac27b9d0e603499315b7139c948130d |
| https://git.kernel.org/stable/c/33d1310d4496e904123dab9c28b2d8d2c1800f97 |
| https://git.kernel.org/stable/c/7ee85f5515e86a4e2a2f51969795920733912bad |