CVE-2026-23233

In the Linux kernel, the following vulnerability has been resolved: f2fs: fix to avoid mapping wrong physical block for swapfile Xiaolong Guo reported a f2fs bug in bugzilla [1] [1] https://bugzilla.kernel.org/show_bug.cgi?id=220951 Quoted: "When using stress-ng's swap stress test on F2FS filesystem with kernel 6.6+, the system experiences data corruption leading to either: 1 dm-verity corruption errors and device reboot 2 F2FS node corruption errors and boot hangs The issue occurs specifically when: 1 Using F2FS filesystem (ext4 is unaffected) 2 Swapfile size is less than F2FS section size (2MB) 3 Swapfile has fragmented physical layout (multiple non-contiguous extents) 4 Kernel version is 6.6+ (6.1 is unaffected) The root cause is in check_swap_activate() function in fs/f2fs/data.c. When the first extent of a small swapfile (< 2MB) is not aligned to section boundaries, the function incorrectly treats it as the last extent, failing to map subsequent extents. This results in incorrect swap_extent creation where only the first extent is mapped, causing subsequent swap writes to overwrite wrong physical locations (other files' data). Steps to Reproduce 1 Setup a device with F2FS-formatted userdata partition 2 Compile stress-ng from https://github.com/ColinIanKing/stress-ng 3 Run swap stress test: (Android devices) adb shell "cd /data/stressng; ./stress-ng-64 --metrics-brief --timeout 60 --swap 0" Log: 1 Ftrace shows in kernel 6.6, only first extent is mapped during second f2fs_map_blocks call in check_swap_activate(): stress-ng-swap-8990: f2fs_map_blocks: ino=11002, file offset=0, start blkaddr=0x43143, len=0x1 (Only 4KB mapped, not the full swapfile) 2 in kernel 6.1, both extents are correctly mapped: stress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=0, start blkaddr=0x13cd4, len=0x1 stress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=1, start blkaddr=0x60c84b, len=0xff The problematic code is in check_swap_activate(): if ((pblock - SM_I(sbi)->main_blkaddr) % blks_per_sec || nr_pblocks % blks_per_sec || !f2fs_valid_pinned_area(sbi, pblock)) { bool last_extent = false; not_aligned++; nr_pblocks = roundup(nr_pblocks, blks_per_sec); if (cur_lblock + nr_pblocks > sis->max) nr_pblocks -= blks_per_sec; /* this extent is last one */ if (!nr_pblocks) { nr_pblocks = last_lblock - cur_lblock; last_extent = true; } ret = f2fs_migrate_blocks(inode, cur_lblock, nr_pblocks); if (ret) { if (ret == -ENOENT) ret = -EINVAL; goto out; } if (!last_extent) goto retry; } When the first extent is unaligned and roundup(nr_pblocks, blks_per_sec) exceeds sis->max, we subtract blks_per_sec resulting in nr_pblocks = 0. The code then incorrectly assumes this is the last extent, sets nr_pblocks = last_lblock - cur_lblock (entire swapfile), and performs migration. After migration, it doesn't retry mapping, so subsequent extents are never processed. " In order to fix this issue, we need to lookup block mapping info after we migrate all blocks in the tail of swapfile.
Configurations

Configuration 1 (hide)

OR cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*

History

17 Mar 2026, 21:21

Type Values Removed Values Added
CVSS v2 : unknown
v3 : unknown
v2 : unknown
v3 : 7.8
First Time Linux
Linux linux Kernel
References () https://git.kernel.org/stable/c/1ff415eef513bf12deb058fc50d57788c46c48e6 - () https://git.kernel.org/stable/c/1ff415eef513bf12deb058fc50d57788c46c48e6 - Patch
References () https://git.kernel.org/stable/c/5c145c03188bc9ba1c29e0bc4d527a5978fc47f9 - () https://git.kernel.org/stable/c/5c145c03188bc9ba1c29e0bc4d527a5978fc47f9 - Patch
References () https://git.kernel.org/stable/c/607cb9d83838d2cd9f0406c2403ed61aadf0edff - () https://git.kernel.org/stable/c/607cb9d83838d2cd9f0406c2403ed61aadf0edff - Patch
References () https://git.kernel.org/stable/c/d4534a7f6c92baaf7e12a45fc6e37332cafafc33 - () https://git.kernel.org/stable/c/d4534a7f6c92baaf7e12a45fc6e37332cafafc33 - Patch
References () https://git.kernel.org/stable/c/fee27b69dde1a05908b350eea42937af2387c4fe - () https://git.kernel.org/stable/c/fee27b69dde1a05908b350eea42937af2387c4fe - Patch
Summary
  • (es) En el kernel de Linux, la siguiente vulnerabilidad ha sido resuelta: f2fs: corrección para evitar mapear un bloque físico incorrecto para el archivo de intercambio Xiaolong Guo informó de un error de f2fs en bugzilla [1] [1] HTTPS://bugzilla.kernel.org/show_bug.cgi?id=220951 Citado: Cuando se utiliza la prueba de estrés de intercambio de stress-ng en el sistema de archivos F2FS con kernel 6.6+, el sistema experimenta corrupción de datos que lleva a una de las siguientes situaciones: 1 errores de corrupción de dm-verity y reinicio del dispositivo 2 errores de corrupción de nodo F2FS y cuelgues de arranque El problema ocurre específicamente cuando: 1 Se utiliza el sistema de archivos F2FS (ext4 no se ve afectado) 2 El tamaño del archivo de intercambio es menor que el tamaño de sección de F2FS (2MB) 3 El archivo de intercambio tiene un diseño físico fragmentado (múltiples extensiones no contiguas) 4 La versión del kernel es 6.6+ (6.1 no se ve afectada) La causa raíz está en la función check_swap_activate() en fs/f2fs/data.c. Cuando la primera extensión de un archivo de intercambio pequeño (&lt; 2MB) no está alineada con los límites de sección, la función lo trata incorrectamente como la última extensión, fallando en mapear extensiones subsiguientes. Esto resulta en una creación incorrecta de swap_extent donde solo la primera extensión es mapeada, causando que las escrituras de intercambio subsiguientes sobrescriban ubicaciones físicas incorrectas (datos de otros archivos). Pasos para Reproducir 1 Configurar un dispositivo con una partición de datos de usuario formateada en F2FS 2 Compilar stress-ng desde HTTPS://github.com/ColinIanKing/stress-ng 3 Ejecutar la prueba de estrés de intercambio: (dispositivos Android) adb shell 'cd /data/stressng; ./stress-ng-64 --metrics-brief --timeout 60 --swap 0' Registro: 1 Ftrace muestra que en el kernel 6.6, solo la primera extensión se mapea durante la segunda llamada a f2fs_map_blocks en check_swap_activate(): stress-ng-swap-8990: f2fs_map_blocks: ino=11002, file offset=0, start blkaddr=0x43143, len=0x1 (Solo 4KB mapeados, no el archivo de intercambio completo) 2 en el kernel 6.1, ambas extensiones se mapean correctamente: stress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=0, start blkaddr=0x13cd4, len=0x1 stress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=1, start blkaddr=0x60c84b, len=0xff El código problemático está en check_swap_activate(): if ((pblock - SM_I(sbi)-&gt;main_blkaddr) % blks_per_sec || nr_pblocks % blks_per_sec || !f2fs_valid_pinned_area(sbi, pblock)) { bool last_extent = false; not_aligned++; nr_pblocks = roundup(nr_pblocks, blks_per_sec); if (cur_lblock + nr_pblocks &gt; sis-&gt;max) nr_pblocks -= blks_per_sec; /* esta extensión es la última */ if (!nr_pblocks) { nr_pblocks = last_lblock - cur_lblock; last_extent = true; } ret = f2fs_migrate_blocks(inode, cur_lblock, nr_pblocks); if (ret) { if (ret == -ENOENT) ret = -EINVAL; goto out; } if (!last_extent) goto retry; } Cuando la primera extensión no está alineada y roundup(nr_pblocks, blks_per_sec) excede sis-&gt;max, restamos blks_per_sec resultando en nr_pblocks = 0. El código asume incorrectamente que esta es la última extensión, establece nr_pblocks = last_lblock - cur_lblock (archivo de intercambio completo), y realiza la migración. Después de la migración, no reintenta el mapeo, por lo que las extensiones subsiguientes nunca se procesan. Para solucionar este problema, necesitamos buscar la información de mapeo de bloques después de migrar todos los bloques en la cola del archivo de intercambio.
CWE CWE-787
CPE cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*

04 Mar 2026, 15:16

Type Values Removed Values Added
New CVE

Information

Published : 2026-03-04 15:16

Updated : 2026-03-17 21:21


NVD link : CVE-2026-23233

Mitre link : CVE-2026-23233

CVE.ORG link : CVE-2026-23233


JSON object : View

Products Affected

linux

  • linux_kernel
CWE
CWE-787

Out-of-bounds Write