CVE-2025-40303 (GCVE-0-2025-40303)

Vulnerability from cvelistv5 – Published: 2025-12-08 00:46 – Updated: 2026-08-05 12:09
VLAI
Title
btrfs: ensure no dirty metadata is written back for an fs with errors
Summary
In the Linux kernel, the following vulnerability has been resolved: btrfs: ensure no dirty metadata is written back for an fs with errors [BUG] During development of a minor feature (make sure all btrfs_bio::end_io() is called in task context), I noticed a crash in generic/388, where metadata writes triggered new works after btrfs_stop_all_workers(). It turns out that it can even happen without any code modification, just using RAID5 for metadata and the same workload from generic/388 is going to trigger the use-after-free. [CAUSE] If btrfs hits an error, the fs is marked as error, no new transaction is allowed thus metadata is in a frozen state. But there are some metadata modifications before that error, and they are still in the btree inode page cache. Since there will be no real transaction commit, all those dirty folios are just kept as is in the page cache, and they can not be invalidated by invalidate_inode_pages2() call inside close_ctree(), because they are dirty. And finally after btrfs_stop_all_workers(), we call iput() on btree inode, which triggers writeback of those dirty metadata. And if the fs is using RAID56 metadata, this will trigger RMW and queue new works into rmw_workers, which is already stopped, causing warning from queue_work() and use-after-free. [FIX] Add a special handling for write_one_eb(), that if the fs is already in an error state, immediately mark the bbio as failure, instead of really submitting them. Then during close_ctree(), iput() will just discard all those dirty tree blocks without really writing them back, thus no more new jobs for already stopped-and-freed workqueues. The extra discard in write_one_eb() also acts as an extra safenet. E.g. the transaction abort is triggered by some extent/free space tree corruptions, and since extent/free space tree is already corrupted some tree blocks may be allocated where they shouldn't be (overwriting existing tree blocks). In that case writing them back will further corrupting the fs.
Assigner
Linux CNA under the mitre root
CNA scorecard D 53/100 over 7056 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
Linux Linux Affected: 13e6c37b989859e70b0d73d3f2cb0aa022159b17 , < 066ee13f05fbd82ada01883e51f0695172f98dff (git)
Affected: 13e6c37b989859e70b0d73d3f2cb0aa022159b17 , < e2b3859067bf012d53c49b3f885fef40624a2c83 (git)
Affected: 13e6c37b989859e70b0d73d3f2cb0aa022159b17 , < 54a5b5a15588e3b0b294df31474d08a2678d4291 (git)
Affected: 13e6c37b989859e70b0d73d3f2cb0aa022159b17 , < 2618849f31e7cf51fadd4a5242458501a6d5b315 (git)
guessed Create a notification for this product.
Linux Linux Affected: 3.10
Unaffected: 0 , < 3.10 (semver)
Unaffected: 6.6.117 , ≤ 6.6.* (semver)
Unaffected: 6.12.58 , ≤ 6.12.* (semver)
Unaffected: 6.17.8 , ≤ 6.17.* (semver)
Unaffected: 6.18 , ≤ * (original_commit_for_fix)
guessed Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "fs/btrfs/extent_io.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "066ee13f05fbd82ada01883e51f0695172f98dff",
              "status": "affected",
              "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
              "versionType": "git"
            },
            {
              "lessThan": "e2b3859067bf012d53c49b3f885fef40624a2c83",
              "status": "affected",
              "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
              "versionType": "git"
            },
            {
              "lessThan": "54a5b5a15588e3b0b294df31474d08a2678d4291",
              "status": "affected",
              "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
              "versionType": "git"
            },
            {
              "lessThan": "2618849f31e7cf51fadd4a5242458501a6d5b315",
              "status": "affected",
              "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "fs/btrfs/extent_io.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "3.10"
            },
            {
              "lessThan": "3.10",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.6.*",
              "status": "unaffected",
              "version": "6.6.117",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.12.*",
              "status": "unaffected",
              "version": "6.12.58",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.17.*",
              "status": "unaffected",
              "version": "6.17.8",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "6.18",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.6.117",
                  "versionStartIncluding": "3.10",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.12.58",
                  "versionStartIncluding": "3.10",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.17.8",
                  "versionStartIncluding": "3.10",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.18",
                  "versionStartIncluding": "3.10",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nbtrfs: ensure no dirty metadata is written back for an fs with errors\n\n[BUG]\nDuring development of a minor feature (make sure all btrfs_bio::end_io()\nis called in task context), I noticed a crash in generic/388, where\nmetadata writes triggered new works after btrfs_stop_all_workers().\n\nIt turns out that it can even happen without any code modification, just\nusing RAID5 for metadata and the same workload from generic/388 is going\nto trigger the use-after-free.\n\n[CAUSE]\nIf btrfs hits an error, the fs is marked as error, no new\ntransaction is allowed thus metadata is in a frozen state.\n\nBut there are some metadata modifications before that error, and they are\nstill in the btree inode page cache.\n\nSince there will be no real transaction commit, all those dirty folios\nare just kept as is in the page cache, and they can not be invalidated\nby invalidate_inode_pages2() call inside close_ctree(), because they are\ndirty.\n\nAnd finally after btrfs_stop_all_workers(), we call iput() on btree\ninode, which triggers writeback of those dirty metadata.\n\nAnd if the fs is using RAID56 metadata, this will trigger RMW and queue\nnew works into rmw_workers, which is already stopped, causing warning\nfrom queue_work() and use-after-free.\n\n[FIX]\nAdd a special handling for write_one_eb(), that if the fs is already in\nan error state, immediately mark the bbio as failure, instead of really\nsubmitting them.\n\nThen during close_ctree(), iput() will just discard all those dirty\ntree blocks without really writing them back, thus no more new jobs for\nalready stopped-and-freed workqueues.\n\nThe extra discard in write_one_eb() also acts as an extra safenet.\nE.g. the transaction abort is triggered by some extent/free space\ntree corruptions, and since extent/free space tree is already corrupted\nsome tree blocks may be allocated where they shouldn\u0027t be (overwriting\nexisting tree blocks). In that case writing them back will further\ncorrupting the fs."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "baseScore": 7.8,
            "baseSeverity": "HIGH",
            "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
            "version": "3.1"
          },
          "scenarios": [
            {
              "lang": "en",
              "value": "AV:L - btrfs is a local filesystem; the bug is reached through ordinary local filesystem activity that dirties btree metadata plus the unmount path (`close_ctree()`), with no network-facing component.\nAC:L - The sequence (fs error state with pending dirty metadata \u2192 unmount \u2192 writeback into the already-destroyed rmw_workers workqueue) is deterministic rather than a race, and the author reproduced it with an unmodified kernel using the stock generic/388 workload on RAID5 metadata, a profile an attacker supplying the image chooses freely.\nPR:L - An unprivileged local user with write access to a btrfs mount generates the dirty metadata and can drive the workload; on desktop/kiosk systems udisks2 auto-mounts and unmounts attacker-supplied removable media without any root credential, so real root in the initial namespace is not required.\nUI:N - No separate victim action is needed \u2014 the attacker\u0027s own workload dirties the metadata and the unmount/eject that triggers the freed-workqueue use is performed by the attacker or occurs automatically during normal system operation.\nS:U - The corruption stays within kernel memory and the filesystem managed by the same kernel; no VM, IOMMU, or sandbox boundary is crossed.\nC:H - queue_work() dereferences the freed workqueue_struct and its per-CPU pwq/pool, reading freed slab memory that an attacker can reclaim with sprayed objects, yielding an information-disclosure primitive on kernel memory.\nI:H - The use-after-free performs list insertions into the freed workqueue/pool structures, giving a write primitive into attacker-groomed memory, and the commit additionally documents that submitting these tree blocks can overwrite live metadata and further corrupt the on-disk filesystem.\nA:H - The bug produces a queue_work() WARN and a use-after-free during unmount, crashing the kernel on a code path that runs after the workqueues have been torn down."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-08-05T12:09:22.649Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/066ee13f05fbd82ada01883e51f0695172f98dff"
        },
        {
          "url": "https://git.kernel.org/stable/c/e2b3859067bf012d53c49b3f885fef40624a2c83"
        },
        {
          "url": "https://git.kernel.org/stable/c/54a5b5a15588e3b0b294df31474d08a2678d4291"
        },
        {
          "url": "https://git.kernel.org/stable/c/2618849f31e7cf51fadd4a5242458501a6d5b315"
        }
      ],
      "title": "btrfs: ensure no dirty metadata is written back for an fs with errors",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2025-40303",
    "datePublished": "2025-12-08T00:46:27.820Z",
    "dateReserved": "2025-04-16T07:20:57.185Z",
    "dateUpdated": "2026-08-05T12:09:22.649Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2025-40303",
      "date": "2026-10-24",
      "epss": "0.00138",
      "percentile": "0.02926"
    },
    "microsoft_vex": {
      "current_release_date": "2025-12-16T14:39:56.000Z",
      "cve": "CVE-2025-40303",
      "id": "msrc_CVE-2025-40303",
      "initial_release_date": "2025-12-02T00:00:00.000Z",
      "product_status:fixed": "1",
      "product_status:known_affected": "1",
      "source": "Microsoft CSAF VEX",
      "status": "final",
      "title": "btrfs: ensure no dirty metadata is written back for an fs with errors",
      "url": "https://msrc.microsoft.com/csaf/vex/2025/msrc_cve-2025-40303.json",
      "version": "2"
    },
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "defaultStatus": "unaffected",
                "product": "Linux",
                "programFiles": [
                  "fs/btrfs/extent_io.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "lessThan": "066ee13f05fbd82ada01883e51f0695172f98dff",
                    "status": "affected",
                    "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "e2b3859067bf012d53c49b3f885fef40624a2c83",
                    "status": "affected",
                    "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "54a5b5a15588e3b0b294df31474d08a2678d4291",
                    "status": "affected",
                    "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "2618849f31e7cf51fadd4a5242458501a6d5b315",
                    "status": "affected",
                    "version": "13e6c37b989859e70b0d73d3f2cb0aa022159b17",
                    "versionType": "git"
                  }
                ]
              },
              {
                "defaultStatus": "affected",
                "product": "Linux",
                "programFiles": [
                  "fs/btrfs/extent_io.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "status": "affected",
                    "version": "3.10"
                  },
                  {
                    "lessThan": "3.10",
                    "status": "unaffected",
                    "version": "0",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.6.*",
                    "status": "unaffected",
                    "version": "6.6.117",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.12.*",
                    "status": "unaffected",
                    "version": "6.12.58",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.17.*",
                    "status": "unaffected",
                    "version": "6.17.8",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "*",
                    "status": "unaffected",
                    "version": "6.18",
                    "versionType": "original_commit_for_fix"
                  }
                ]
              }
            ],
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
          }
        ],
        "cveTags": [],
        "descriptions": [
          {
            "lang": "en",
            "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nbtrfs: ensure no dirty metadata is written back for an fs with errors\n\n[BUG]\nDuring development of a minor feature (make sure all btrfs_bio::end_io()\nis called in task context), I noticed a crash in generic/388, where\nmetadata writes triggered new works after btrfs_stop_all_workers().\n\nIt turns out that it can even happen without any code modification, just\nusing RAID5 for metadata and the same workload from generic/388 is going\nto trigger the use-after-free.\n\n[CAUSE]\nIf btrfs hits an error, the fs is marked as error, no new\ntransaction is allowed thus metadata is in a frozen state.\n\nBut there are some metadata modifications before that error, and they are\nstill in the btree inode page cache.\n\nSince there will be no real transaction commit, all those dirty folios\nare just kept as is in the page cache, and they can not be invalidated\nby invalidate_inode_pages2() call inside close_ctree(), because they are\ndirty.\n\nAnd finally after btrfs_stop_all_workers(), we call iput() on btree\ninode, which triggers writeback of those dirty metadata.\n\nAnd if the fs is using RAID56 metadata, this will trigger RMW and queue\nnew works into rmw_workers, which is already stopped, causing warning\nfrom queue_work() and use-after-free.\n\n[FIX]\nAdd a special handling for write_one_eb(), that if the fs is already in\nan error state, immediately mark the bbio as failure, instead of really\nsubmitting them.\n\nThen during close_ctree(), iput() will just discard all those dirty\ntree blocks without really writing them back, thus no more new jobs for\nalready stopped-and-freed workqueues.\n\nThe extra discard in write_one_eb() also acts as an extra safenet.\nE.g. the transaction abort is triggered by some extent/free space\ntree corruptions, and since extent/free space tree is already corrupted\nsome tree blocks may be allocated where they shouldn\u0027t be (overwriting\nexisting tree blocks). In that case writing them back will further\ncorrupting the fs."
          },
          {
            "lang": "es",
            "value": "En el kernel de Linux, la siguiente vulnerabilidad ha sido resuelta:\n\nbtrfs: asegurar que no se escriban metadatos sucios para un sistema de archivos con errores\n\n[ERROR]\nDurante el desarrollo de una caracter\u00edstica menor (asegurar que todas las llamadas a btrfs_bio::end_io() se realicen en contexto de tarea), not\u00e9 un fallo en generic/388, donde las escrituras de metadatos activaron nuevos trabajos despu\u00e9s de btrfs_stop_all_workers().\n\nResulta que puede ocurrir incluso sin ninguna modificaci\u00f3n de c\u00f3digo, solo usando RAID5 para metadatos y la misma carga de trabajo de generic/388 va a activar el uso despu\u00e9s de liberaci\u00f3n.\n\n[CAUSA]\nSi btrfs encuentra un error, el sistema de archivos se marca como error, no se permite ninguna nueva transacci\u00f3n, por lo tanto, los metadatos est\u00e1n en un estado congelado.\n\nPero hay algunas modificaciones de metadatos antes de ese error, y todav\u00eda est\u00e1n en la cach\u00e9 de p\u00e1ginas de inodos del btree.\n\nDado que no habr\u00e1 una confirmaci\u00f3n de transacci\u00f3n real, todos esos folios sucios se mantienen tal cual en la cach\u00e9 de p\u00e1ginas, y no pueden ser invalidados por la llamada a invalidate_inode_pages2() dentro de close_ctree(), porque est\u00e1n sucios.\n\nY finalmente despu\u00e9s de btrfs_stop_all_workers(), llamamos a iput() en el inodo del btree, lo que activa la escritura de esos metadatos sucios.\n\nY si el sistema de archivos est\u00e1 usando metadatos RAID56, esto activar\u00e1 RMW y encolar\u00e1 nuevos trabajos en rmw_workers, que ya est\u00e1 detenido, causando una advertencia de queue_work() y uso despu\u00e9s de liberaci\u00f3n.\n\n[SOLUCI\u00d3N]\nA\u00f1adir un manejo especial para write_one_eb(), que si el sistema de archivos ya est\u00e1 en un estado de error, marque inmediatamente el bbio como fallo, en lugar de realmente enviarlos.\n\nLuego, durante close_ctree(), iput() simplemente descartar\u00e1 todos esos bloques de \u00e1rbol sucios sin realmente escribirlos de vuelta, por lo tanto, no m\u00e1s trabajos nuevos para las colas de trabajo ya detenidas y liberadas.\n\nEl descarte adicional en write_one_eb() tambi\u00e9n act\u00faa como una red de seguridad adicional.\nPor ejemplo, la anulaci\u00f3n de la transacci\u00f3n es activada por algunas corrupciones del \u00e1rbol de extensiones/espacio libre, y dado que el \u00e1rbol de extensiones/espacio libre ya est\u00e1 corrupto, algunos bloques de \u00e1rbol pueden ser asignados donde no deber\u00edan (sobrescribiendo bloques de \u00e1rbol existentes). En ese caso, escribirlos de vuelta corromper\u00e1 a\u00fan m\u00e1s el sistema de archivos."
          }
        ],
        "id": "CVE-2025-40303",
        "lastModified": "2026-10-14T22:10:00.210",
        "metrics": {
          "cvssMetricV31": [
            {
              "cvssData": {
                "attackComplexity": "LOW",
                "attackVector": "LOCAL",
                "availabilityImpact": "HIGH",
                "baseScore": 7.8,
                "baseSeverity": "HIGH",
                "confidentialityImpact": "HIGH",
                "integrityImpact": "HIGH",
                "privilegesRequired": "LOW",
                "scope": "UNCHANGED",
                "userInteraction": "NONE",
                "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
                "version": "3.1"
              },
              "exploitabilityScore": 1.8,
              "impactScore": 5.9,
              "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
              "type": "Secondary"
            }
          ]
        },
        "published": "2025-12-08T01:16:02.440",
        "references": [
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/066ee13f05fbd82ada01883e51f0695172f98dff"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/2618849f31e7cf51fadd4a5242458501a6d5b315"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/54a5b5a15588e3b0b294df31474d08a2678d4291"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/e2b3859067bf012d53c49b3f885fef40624a2c83"
          }
        ],
        "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "vulnStatus": "Deferred"
      }
    },
    "redhat_vex": {
      "aggregate_severity": "Low",
      "current_release_date": "2026-10-16T23:24:11+00:00",
      "cve": "CVE-2025-40303",
      "id": "CVE-2025-40303",
      "initial_release_date": "2025-12-08T00:00:00+00:00",
      "product_status:known_affected": "42",
      "product_status:known_not_affected": "233",
      "source": "Red Hat CSAF VEX",
      "status": "final",
      "title": "kernel: btrfs: ensure no dirty metadata is written back for an fs with errors",
      "url": "https://security.access.redhat.com/data/csaf/v2/vex/2025/cve-2025-40303.json",
      "version": "3"
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.