// For flags

CVE-2021-46989

hfsplus: prevent corruption in shrinking truncate

Severity Score

"-"
*CVSS v-

Exploit Likelihood

*EPSS

Affected Versions

*CPE

Public Exploits

0
*Multiple Sources

Exploited in Wild

-
*KEV

Decision

Track
*SSVC
Descriptions

In the Linux kernel, the following vulnerability has been resolved:

hfsplus: prevent corruption in shrinking truncate

I believe there are some issues introduced by commit 31651c607151
("hfsplus: avoid deadlock on file truncation")

HFS+ has extent records which always contains 8 extents. In case the
first extent record in catalog file gets full, new ones are allocated from
extents overflow file.

In case shrinking truncate happens to middle of an extent record which
locates in extents overflow file, the logic in hfsplus_file_truncate() was
changed so that call to hfs_brec_remove() is not guarded any more.

Right action would be just freeing the extents that exceed the new size
inside extent record by calling hfsplus_free_extents(), and then check if
the whole extent record should be removed. However since the guard
(blk_cnt > start) is now after the call to hfs_brec_remove(), this has
unfortunate effect that the last matching extent record is removed
unconditionally.

To reproduce this issue, create a file which has at least 10 extents, and
then perform shrinking truncate into middle of the last extent record, so
that the number of remaining extents is not under or divisible by 8. This
causes the last extent record (8 extents) to be removed totally instead of
truncating into middle of it. Thus this causes corruption, and lost data.

Fix for this is simply checking if the new truncated end is below the
start of this extent record, making it safe to remove the full extent
record. However call to hfs_brec_remove() can't be moved to it's previous
place since we're dropping ->tree_lock and it can cause a race condition
and the cached info being invalidated possibly corrupting the node data.

Another issue is related to this one. When entering into the block
(blk_cnt > start) we are not holding the ->tree_lock. We break out from
the loop not holding the lock, but hfs_find_exit() does unlock it. Not
sure if it's possible for someone else to take the lock under our feet,
but it can cause hard to debug errors and premature unlocking. Even if
there's no real risk of it, the locking should still always be kept in
balance. Thus taking the lock now just before the check.

En el kernel de Linux, se resolvió la siguiente vulnerabilidad: hfsplus: evita la corrupción al reducir y truncar Creo que hay algunos problemas introducidos por el commit 31651c607151 ("hfsplus: evita el punto muerto en el truncamiento de archivos") HFS+ tiene registros de extensión que siempre contienen 8 extensiones. En caso de que el primer registro de extensión en el archivo de catálogo se llene, se asignan nuevos registros desde el archivo de desbordamiento de extensiones. En caso de que se produzca un truncamiento reducido en la mitad de un registro de extensión que se ubica en un archivo de desbordamiento de extensiones, la lógica en hfsplus_file_truncate() se cambió para que la llamada a hfs_brec_remove() ya no esté protegida. La acción correcta sería simplemente liberar las extensiones que exceden el nuevo tamaño dentro del registro de extensión llamando a hfsplus_free_extents() y luego verificar si se debe eliminar todo el registro de extensión. Sin embargo, dado que la guardia (blk_cnt > start) está ahora después de la llamada a hfs_brec_remove(), esto tiene el efecto desafortunado de que el último registro de extensión coincidente se elimina incondicionalmente. Para reproducir este problema, cree un archivo que tenga al menos 10 extensiones y luego realice un truncamiento reducido hasta la mitad del último registro de extensión, de modo que el número de extensiones restantes no sea menor o divisible por 8. Esto hace que el último registro de extensión ( 8 extensiones) para eliminarse por completo en lugar de truncarse a la mitad. Por tanto, esto provoca corrupción y pérdida de datos. La solución para esto es simplemente verificar si el nuevo final truncado está debajo del inicio de este registro de extensión, lo que hace que sea seguro eliminar el registro de extensión completo. Sin embargo, la llamada a hfs_brec_remove() no se puede mover a su lugar anterior ya que estamos eliminando ->tree_lock y puede provocar una condición de ejecución y la invalidación de la información almacenada en caché, posiblemente corrompiendo los datos del nodo. Otro tema está relacionado con éste. Al ingresar al bloque (blk_cnt > start) no mantenemos ->tree_lock. Salimos del bucle sin mantener el bloqueo, pero hfs_find_exit() lo desbloquea. No estoy seguro de si es posible que otra persona tome el bloqueo bajo nuestros pies, pero puede causar errores difíciles de depurar y desbloqueo prematuro. Aunque no exista ningún riesgo real, el bloqueo siempre debe mantenerse en equilibrio. Tomando así el candado ahora justo antes del control.

*Credits: N/A
CVSS Scores
Attack Vector
-
Attack Complexity
-
Privileges Required
-
User Interaction
-
Scope
-
Confidentiality
-
Integrity
-
Availability
-
* Common Vulnerability Scoring System
SSVC
  • Decision:Track
Exploitation
None
Automatable
No
Tech. Impact
Partial
* Organization's Worst-case Scenario
Timeline
  • 2024-02-27 CVE Reserved
  • 2024-02-28 CVE Published
  • 2024-02-29 EPSS Updated
  • 2024-08-04 CVE Updated
  • ---------- Exploited in Wild
  • ---------- KEV Due Date
  • ---------- First Exploit
CWE
CAPEC
Affected Vendors, Products, and Versions
Vendor Product Version Other Status
Vendor Product Version Other Status <-- --> Vendor Product Version Other Status
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.19 < 4.19.191
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.19 < 4.19.191"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.19 < 5.4.120
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.19 < 5.4.120"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.19 < 5.10.38
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.19 < 5.10.38"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.19 < 5.11.22
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.19 < 5.11.22"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.19 < 5.12.5
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.19 < 5.12.5"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.19 < 5.13
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.19 < 5.13"
en
Affected