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)
Leer descripción completaMostrar menos
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
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.
Detalles técnicos trazas, registros y código del informe original
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;
}CVSS
- Versión: 3.1
- Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
- Puntuación base: 7.8
Probabilidad de explotación (EPSS)
- Probabilidad de explotación en los próximos 30 días: 0.16%
- Percentil entre todas las CVEs puntuadas: 5
- Fecha de la puntuación: 6/10/2026
EPSS (Exploit Prediction Scoring System, de FIRST) estima la probabilidad de que una vulnerabilidad sea explotada en 30 días. Complementa a CVSS (impacto) y a CISA KEV (explotación confirmada).
🎯 Técnicas ATT&CK
Cómo se explota esta vulnerabilidad y qué consigue el atacante, en el lenguaje de MITRE ATT&CK.
- Explotación
T1068Exploitation for Privilege Escalationprivilege escalation85 % - Impacto principal
T1565.001Stored Data Manipulationimpact90 % - Impacto secundario
T1499.004Application or System Exploitationimpact75 %
Vulnerabilidad local (AV:L, PR:L) que permite escalada mediante corrupción de memoria en f2fs/data.c. Mapeo incorrecto de bloques de swap causa sobrescritura de datos de otros ficheros, resultando en corrupción de datos y DoS del sistema.
Inferido por nuestro agente de análisis a partir de la descripción oficial, el vector CVSS y la CWE, y comprobado por un supervisor. Puede contener errores.
🛡️ Mitigaciones ATT&CK que cubren estas técnicas
Tecnologías afectadas (1)
CWE
- CWE-787
Referencias
- https://git.kernel.org/stable/c/1ff415eef513bf12deb058fc50d57788c46c48e6
- https://git.kernel.org/stable/c/5c145c03188bc9ba1c29e0bc4d527a5978fc47f9
- https://git.kernel.org/stable/c/607cb9d83838d2cd9f0406c2403ed61aadf0edff
- https://git.kernel.org/stable/c/d4534a7f6c92baaf7e12a45fc6e37332cafafc33
- https://git.kernel.org/stable/c/fee27b69dde1a05908b350eea42937af2387c4fe
JSON original (NVD)
Mostrar
{
"id": "CVE-2026-23233",
"cveTags": [],
"metrics": {
"cvssMetricV31": [
{
"type": "Primary",
"source": "nvd@nist.gov",
"cvssData": {
"scope": "UNCHANGED",
"version": "3.1",
"baseScore": 7.8,
"attackVector": "LOCAL",
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"integrityImpact": "HIGH",
"userInteraction": "NONE",
"attackComplexity": "LOW",
"availabilityImpact": "HIGH",
"privilegesRequired": "LOW",
"confidentialityImpact": "HIGH"
},
"impactScore": 5.9,
"exploitabilityScore": 1.8
}
]
},
"affected": [
{
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"affectedData": [
{
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
"vendor": "Linux",
"product": "Linux",
"versions": [
{
"status": "affected",
"version": "40d76c393cca83938b11eb7ca8983aa3cd0ed69b",
"lessThan": "d4534a7f6c92baaf7e12a45fc6e37332cafafc33",
"versionType": "git"
},
{
"status": "affected",
"version": "9703d69d9d153bb230711d0d577454552aeb13d4",
"lessThan": "1ff415eef513bf12deb058fc50d57788c46c48e6",
"versionType": "git"
},
{
"status": "affected",
"version": "9703d69d9d153bb230711d0d577454552aeb13d4",
"lessThan": "fee27b69dde1a05908b350eea42937af2387c4fe",
"versionType": "git"
},
{
"status": "affected",
"version": "9703d69d9d153bb230711d0d577454552aeb13d4",
"lessThan": "607cb9d83838d2cd9f0406c2403ed61aadf0edff",
"versionType": "git"
},
{
"status": "affected",
"version": "9703d69d9d153bb230711d0d577454552aeb13d4",
"lessThan": "5c145c03188bc9ba1c29e0bc4d527a5978fc47f9",
"versionType": "git"
},
{
"status": "affected",
"version": "6.6.33",
"lessThan": "6.6.127",
"versionType": "semver"
}
],
"programFiles": [
"fs/f2fs/data.c"
],
"defaultStatus": "unaffected"
},
{
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
"vendor": "Linux",
"product": "Linux",
"versions": [
{
"status": "affected",
"version": "6.9"
},
{
"status": "unaffected",
"version": "0",
"lessThan": "6.9",
"versionType": "semver"
},
{
"status": "unaffected",
"version": "6.6.127",
"versionType": "semver",
"lessThanOrEqual": "6.6.*"
},
{
"status": "unaffected",
"version": "6.12.74",
"versionType": "semver",
"lessThanOrEqual": "6.12.*"
},
{
"status": "unaffected",
"version": "6.18.13",
"versionType": "semver",
"lessThanOrEqual": "6.18.*"
},
{
"status": "unaffected",
"version": "6.19.3",
"versionType": "semver",
"lessThanOrEqual": "6.19.*"
},
{
"status": "unaffected",
"version": "7.0",
"versionType": "original_commit_for_fix",
"lessThanOrEqual": "*"
}
],
"programFiles": [
"fs/f2fs/data.c"
],
"defaultStatus": "affected"
}
]
}
],
"published": "2026-03-04T15:16:13.603",
"references": [
{
"url": "https://git.kernel.org/stable/c/1ff415eef513bf12deb058fc50d57788c46c48e6",
"tags": [
"Patch"
],
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
},
{
"url": "https://git.kernel.org/stable/c/5c145c03188bc9ba1c29e0bc4d527a5978fc47f9",
"tags": [
"Patch"
],
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
},
{
"url": "https://git.kernel.org/stable/c/607cb9d83838d2cd9f0406c2403ed61aadf0edff",
"tags": [
"Patch"
],
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
},
{
"url": "https://git.kernel.org/stable/c/d4534a7f6c92baaf7e12a45fc6e37332cafafc33",
"tags": [
"Patch"
],
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
},
{
"url": "https://git.kernel.org/stable/c/fee27b69dde1a05908b350eea42937af2387c4fe",
"tags": [
"Patch"
],
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
}
],
"vulnStatus": "Analyzed",
"weaknesses": [
{
"type": "Primary",
"source": "nvd@nist.gov",
"description": [
{
"lang": "en",
"value": "CWE-787"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "In the Linux kernel, the following vulnerability has been resolved:\n\nf2fs: fix to avoid mapping wrong physical block for swapfile\n\nXiaolong Guo reported a f2fs bug in bugzilla [1]\n\n[1] https://bugzilla.kernel.org/show_bug.cgi?id=220951\n\nQuoted:\n\n\"When using stress-ng's swap stress test on F2FS filesystem with kernel 6.6+,\nthe system experiences data corruption leading to either:\n1 dm-verity corruption errors and device reboot\n2 F2FS node corruption errors and boot hangs\n\nThe issue occurs specifically when:\n1 Using F2FS filesystem (ext4 is unaffected)\n2 Swapfile size is less than F2FS section size (2MB)\n3 Swapfile has fragmented physical layout (multiple non-contiguous extents)\n4 Kernel version is 6.6+ (6.1 is unaffected)\n\nThe root cause is in check_swap_activate() function in fs/f2fs/data.c. When the\nfirst extent of a small swapfile (< 2MB) is not aligned to section boundaries,\nthe function incorrectly treats it as the last extent, failing to map\nsubsequent extents. This results in incorrect swap_extent creation where only\nthe first extent is mapped, causing subsequent swap writes to overwrite wrong\nphysical locations (other files' data).\n\nSteps to Reproduce\n1 Setup a device with F2FS-formatted userdata partition\n2 Compile stress-ng from https://github.com/ColinIanKing/stress-ng\n3 Run swap stress test: (Android devices)\nadb shell \"cd /data/stressng; ./stress-ng-64 --metrics-brief --timeout 60\n--swap 0\"\n\nLog:\n1 Ftrace shows in kernel 6.6, only first extent is mapped during second\nf2fs_map_blocks call in check_swap_activate():\nstress-ng-swap-8990: f2fs_map_blocks: ino=11002, file offset=0, start\nblkaddr=0x43143, len=0x1\n(Only 4KB mapped, not the full swapfile)\n2 in kernel 6.1, both extents are correctly mapped:\nstress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=0, start\nblkaddr=0x13cd4, len=0x1\nstress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=1, start\nblkaddr=0x60c84b, len=0xff\n\nThe problematic code is in check_swap_activate():\nif ((pblock - SM_I(sbi)->main_blkaddr) % blks_per_sec ||\n nr_pblocks % blks_per_sec ||\n !f2fs_valid_pinned_area(sbi, pblock)) {\n bool last_extent = false;\n\n not_aligned++;\n\n nr_pblocks = roundup(nr_pblocks, blks_per_sec);\n if (cur_lblock + nr_pblocks > sis->max)\n nr_pblocks -= blks_per_sec;\n\n /* this extent is last one */\n if (!nr_pblocks) {\n nr_pblocks = last_lblock - cur_lblock;\n last_extent = true;\n }\n\n ret = f2fs_migrate_blocks(inode, cur_lblock, nr_pblocks);\n if (ret) {\n if (ret == -ENOENT)\n ret = -EINVAL;\n goto out;\n }\n\n if (!last_extent)\n goto retry;\n}\n\nWhen the first extent is unaligned and roundup(nr_pblocks, blks_per_sec)\nexceeds sis->max, we subtract blks_per_sec resulting in nr_pblocks = 0. The\ncode then incorrectly assumes this is the last extent, sets nr_pblocks =\nlast_lblock - cur_lblock (entire swapfile), and performs migration. After\nmigration, it doesn't retry mapping, so subsequent extents are never processed.\n\"\n\nIn order to fix this issue, we need to lookup block mapping info after\nwe migrate all blocks in the tail of swapfile."
},
{
"lang": "es",
"value": "En el kernel de Linux, la siguiente vulnerabilidad ha sido resuelta:\n\nf2fs: corrección para evitar mapear un bloque físico incorrecto para el archivo de intercambio\n\nXiaolong Guo informó de un error de f2fs en bugzilla [1]\n\n[1] HTTPS://bugzilla.kernel.org/show_bug.cgi?id=220951\n\nCitado:\n\nCuando 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:\n1 errores de corrupción de dm-verity y reinicio del dispositivo\n2 errores de corrupción de nodo F2FS y cuelgues de arranque\n\nEl problema ocurre específicamente cuando:\n1 Se utiliza el sistema de archivos F2FS (ext4 no se ve afectado)\n2 El tamaño del archivo de intercambio es menor que el tamaño de sección de F2FS (2MB)\n3 El archivo de intercambio tiene un diseño físico fragmentado (múltiples extensiones no contiguas)\n4 La versión del kernel es 6.6+ (6.1 no se ve afectada)\n\nLa 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 (< 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).\n\nPasos para Reproducir\n1 Configurar un dispositivo con una partición de datos de usuario formateada en F2FS\n2 Compilar stress-ng desde HTTPS://github.com/ColinIanKing/stress-ng\n3 Ejecutar la prueba de estrés de intercambio: (dispositivos Android)\nadb shell 'cd /data/stressng; ./stress-ng-64 --metrics-brief --timeout 60 --swap 0'\n\nRegistro:\n1 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():\nstress-ng-swap-8990: f2fs_map_blocks: ino=11002, file offset=0, start blkaddr=0x43143, len=0x1\n(Solo 4KB mapeados, no el archivo de intercambio completo)\n2 en el kernel 6.1, ambas extensiones se mapean correctamente:\nstress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=0, start blkaddr=0x13cd4, len=0x1\nstress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=1, start blkaddr=0x60c84b, len=0xff\n\nEl código problemático está en check_swap_activate():\nif ((pblock - SM_I(sbi)->main_blkaddr) % blks_per_sec ||\n nr_pblocks % blks_per_sec ||\n !f2fs_valid_pinned_area(sbi, pblock)) {\n bool last_extent = false;\n\n not_aligned++;\n\n nr_pblocks = roundup(nr_pblocks, blks_per_sec);\n if (cur_lblock + nr_pblocks > sis->max)\n nr_pblocks -= blks_per_sec;\n\n /* esta extensión es la última */\n if (!nr_pblocks) {\n nr_pblocks = last_lblock - cur_lblock;\n last_extent = true;\n }\n\n ret = f2fs_migrate_blocks(inode, cur_lblock, nr_pblocks);\n if (ret) {\n if (ret == -ENOENT)\n ret = -EINVAL;\n goto out;\n }\n\n if (!last_extent)\n goto retry;\n}\n\nCuando la primera extensión no está alineada y roundup(nr_pblocks, blks_per_sec) excede sis->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.\n\nPara 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."
}
],
"lastModified": "2026-06-17T10:21:09.187",
"configurations": [
{
"nodes": [
{
"negate": false,
"cpeMatch": [
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"vulnerable": true,
"matchCriteriaId": "9F91BA22-77B9-4D50-8EDF-CF73844D56F2",
"versionEndExcluding": "6.6.127",
"versionStartIncluding": "6.6.33"
},
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"vulnerable": true,
"matchCriteriaId": "78063C1B-6788-4C2F-AB8B-2EE10C43515A",
"versionEndExcluding": "6.12.74",
"versionStartIncluding": "6.9"
},
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"vulnerable": true,
"matchCriteriaId": "6BDEF9FB-423E-49F6-991B-9277CC3AF400",
"versionEndExcluding": "6.18.13",
"versionStartIncluding": "6.13"
},
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"vulnerable": true,
"matchCriteriaId": "7853A337-FB2A-4E19-AB47-4E38343532AA",
"versionEndExcluding": "6.19.3",
"versionStartIncluding": "6.19"
}
],
"operator": "OR"
}
]
}
],
"sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
}