fkie_cve-2024-47741
Vulnerability from fkie_nvd
Published
2024-10-21 13:15
Modified
2024-10-23 22:14
Severity ?
Summary
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.
References
Impacted products
Vendor | Product | Version | |
---|---|---|---|
linux | linux_kernel | * | |
linux | linux_kernel | * | |
linux | linux_kernel | * |
{ "configurations": [ { "nodes": [ { "cpeMatch": [ { "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "matchCriteriaId": "D448821D-C085-4CAF-88FA-2DDE7BE21976", "versionEndExcluding": "6.6.54", "versionStartIncluding": "6.2", "vulnerable": true }, { "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "matchCriteriaId": "CE94BB8D-B0AB-4563-9ED7-A12122B56EBE", "versionEndExcluding": "6.10.13", "versionStartIncluding": "6.7", "vulnerable": true }, { "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "matchCriteriaId": "AB755D26-97F4-43B6-8604-CD076811E181", "versionEndExcluding": "6.11.2", "versionStartIncluding": "6.11", "vulnerable": true } ], "negate": false, "operator": "OR" } ] } ], "cveTags": [], "descriptions": [ { "lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nbtrfs: fix race setting file private on concurrent lseek using same fd\n\nWhen doing concurrent lseek(2) system calls against the same file\ndescriptor, using multiple threads belonging to the same process, we have\na short time window where a race happens and can result in a memory leak.\n\nThe race happens like this:\n\n1) A program opens a file descriptor for a file and then spawns two\n threads (with the pthreads library for example), lets call them\n task A and task B;\n\n2) Task A calls lseek with SEEK_DATA or SEEK_HOLE and ends up at\n file.c:find_desired_extent() while holding a read lock on the inode;\n\n3) At the start of find_desired_extent(), it extracts the file\u0027s\n private_data pointer into a local variable named \u0027private\u0027, which has\n a value of NULL;\n\n4) Task B also calls lseek with SEEK_DATA or SEEK_HOLE, locks the inode\n in shared mode and enters file.c:find_desired_extent(), where it also\n extracts file-\u003eprivate_data into its local variable \u0027private\u0027, which\n has a NULL value;\n\n5) Because it saw a NULL file private, task A allocates a private\n structure and assigns to the file structure;\n\n6) Task B also saw a NULL file private so it also allocates its own file\n private and then assigns it to the same file structure, since both\n tasks are using the same file descriptor.\n\n At this point we leak the private structure allocated by task A.\n\nBesides the memory leak, there\u0027s also the detail that both tasks end up\nusing the same cached state record in the private structure (struct\nbtrfs_file_private::llseek_cached_state), which can result in a\nuse-after-free problem since one task can free it while the other is\nstill using it (only one task took a reference count on it). Also, sharing\nthe cached state is not a good idea since it could result in incorrect\nresults in the future - right now it should not be a problem because it\nend ups being used only in extent-io-tree.c:count_range_bits() where we do\nrange validation before using the cached state.\n\nFix this by protecting the private assignment and check of a file while\nholding the inode\u0027s spinlock and keep track of the task that allocated\nthe private, so that it\u0027s used only by that task in order to prevent\nuser-after-free issues with the cached state record as well as potentially\nusing it incorrectly in the future." }, { "lang": "es", "value": "En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: btrfs: arreglo de ejecuci\u00f3n que establece el archivo privado en lseek concurrente usando el mismo fd Al realizar llamadas al sistema lseek(2) concurrentes contra el mismo descriptor de archivo, usando m\u00faltiples subprocesos que pertenecen al mismo proceso, tenemos una ventana de tiempo corta donde ocurre una ejecuci\u00f3n y puede resultar en una p\u00e9rdida de memoria. La ejecuci\u00f3n ocurre as\u00ed: 1) Un programa abre un descriptor de archivo para un archivo y luego genera dos subprocesos (con la librer\u00eda pthreads por ejemplo), llam\u00e9moslos tarea A y tarea B; 2) La tarea A llama a lseek con SEEK_DATA o SEEK_HOLE y termina en file.c:find_desired_extent() mientras mantiene un bloqueo de lectura en el inodo; 3) Al comienzo de find_desired_extent(), extrae el puntero private_data del archivo en una variable local llamada \u0027private\u0027, que tiene un valor de NULL; 4) La tarea B tambi\u00e9n llama a lseek con SEEK_DATA o SEEK_HOLE, bloquea el inodo en modo compartido e ingresa a file.c:find_desired_extent(), donde tambi\u00e9n extrae file-\u0026gt;private_data en su variable local \u0027private\u0027, que tiene un valor NULL; 5) Debido a que vio un archivo privado NULL, la tarea A asigna una estructura privada y la asigna a la estructura de archivo; 6) La tarea B tambi\u00e9n vio un archivo privado NULL, por lo que tambi\u00e9n asigna su propio archivo privado y luego lo asigna a la misma estructura de archivo, ya que ambas tareas est\u00e1n usando el mismo descriptor de archivo. En este punto filtramos la estructura privada asignada por la tarea A. Adem\u00e1s de la fuga de memoria, tambi\u00e9n est\u00e1 el detalle de que ambas tareas terminan usando el mismo registro de estado en cach\u00e9 en la estructura privada (struct btrfs_file_private::llseek_cached_state), lo que puede resultar en un problema de use after free, ya que una tarea puede liberarlo mientras la otra todav\u00eda lo est\u00e1 usando (solo una tarea tom\u00f3 un recuento de referencia en \u00e9l). Adem\u00e1s, compartir el estado en cach\u00e9 no es una buena idea, ya que podr\u00eda resultar en resultados incorrectos en el futuro; en este momento no deber\u00eda ser un problema porque termina siendo utilizado solo en extended-io-tree.c:count_range_bits() donde realizamos la validaci\u00f3n de rango antes de usar el estado en cach\u00e9. Solucione esto protegiendo la asignaci\u00f3n privada y la verificaci\u00f3n de un archivo mientras mantiene el spinlock del inodo y realice un seguimiento de la tarea que asign\u00f3 el privado, de modo que solo lo use esa tarea para evitar problemas de use after free con el registro de estado en cach\u00e9, as\u00ed como potencialmente usarlo incorrectamente en el futuro." } ], "id": "CVE-2024-47741", "lastModified": "2024-10-23T22:14:34.090", "metrics": { "cvssMetricV31": [ { "cvssData": { "attackComplexity": "HIGH", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "baseScore": 7.0, "baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "scope": "UNCHANGED", "userInteraction": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.1" }, "exploitabilityScore": 1.0, "impactScore": 5.9, "source": "nvd@nist.gov", "type": "Primary" } ] }, "published": "2024-10-21T13:15:04.207", "references": [ { "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "tags": [ "Patch" ], "url": "https://git.kernel.org/stable/c/33d1310d4496e904123dab9c28b2d8d2c1800f97" }, { "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "tags": [ "Patch" ], "url": "https://git.kernel.org/stable/c/7ee85f5515e86a4e2a2f51969795920733912bad" }, { "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "tags": [ "Patch" ], "url": "https://git.kernel.org/stable/c/a412ca489ac27b9d0e603499315b7139c948130d" }, { "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "tags": [ "Patch" ], "url": "https://git.kernel.org/stable/c/f56a6d9c267ec7fa558ede7755551c047b1034cd" } ], "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "vulnStatus": "Analyzed", "weaknesses": [ { "description": [ { "lang": "en", "value": "CWE-362" } ], "source": "nvd@nist.gov", "type": "Primary" } ] }
Loading…
Loading…
Sightings
Author | Source | Type | Date |
---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.