CVE-2025-40007 (GCVE-0-2025-40007)

Vulnerability from cvelistv5 – Published: 2025-10-20 15:26 – Updated: 2026-05-23 16:01
VLAI
Title
netfs: fix reference leak
Summary
In the Linux kernel, the following vulnerability has been resolved: netfs: fix reference leak Commit 20d72b00ca81 ("netfs: Fix the request's work item to not require a ref") modified netfs_alloc_request() to initialize the reference counter to 2 instead of 1. The rationale was that the requet's "work" would release the second reference after completion (via netfs_{read,write}_collection_worker()). That works most of the time if all goes well. However, it leaks this additional reference if the request is released before the I/O operation has been submitted: the error code path only decrements the reference counter once and the work item will never be queued because there will never be a completion. This has caused outages of our whole server cluster today because tasks were blocked in netfs_wait_for_outstanding_io(), leading to deadlocks in Ceph (another bug that I will address soon in another patch). This was caused by a netfs_pgpriv2_begin_copy_to_cache() call which failed in fscache_begin_write_operation(). The leaked netfs_io_request was never completed, leaving `netfs_inode.io_count` with a positive value forever. All of this is super-fragile code. Finding out which code paths will lead to an eventual completion and which do not is hard to see: - Some functions like netfs_create_write_req() allocate a request, but will never submit any I/O. - netfs_unbuffered_read_iter_locked() calls netfs_unbuffered_read() and then netfs_put_request(); however, netfs_unbuffered_read() can also fail early before submitting the I/O request, therefore another netfs_put_request() call must be added there. A rule of thumb is that functions that return a `netfs_io_request` do not submit I/O, and all of their callers must be checked. For my taste, the whole netfs code needs an overhaul to make reference counting easier to understand and less fragile & obscure. But to fix this bug here and now and produce a patch that is adequate for a stable backport, I tried a minimal approach that quickly frees the request object upon early failure. I decided against adding a second netfs_put_request() each time because that would cause code duplication which obscures the code further. Instead, I added the function netfs_put_failed_request() which frees such a failed request synchronously under the assumption that the reference count is exactly 2 (as initially set by netfs_alloc_request() and never touched), verified by a WARN_ON_ONCE(). It then deinitializes the request object (without going through the "cleanup_work" indirection) and frees the allocation (with RCU protection to protect against concurrent access by netfs_requests_seq_start()). All code paths that fail early have been changed to call netfs_put_failed_request() instead of netfs_put_request(). Additionally, I have added a netfs_put_request() call to netfs_unbuffered_read() as explained above because the netfs_put_failed_request() approach does not work there.
Severity
No CVSS data available.
Assigner
Linux CNA under the mitre root
CNA scorecard D 53/100 over 6843 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
Linux Linux Affected: 20d72b00ca814d748f5663484e5c53bb2bf37a3a , < 8df142e93098b4531fadb5dfcf93087649f570b3 (git)
Affected: 20d72b00ca814d748f5663484e5c53bb2bf37a3a , < 4d428dca252c858bfac691c31fa95d26cd008706 (git)
Affected: 1a8360c2eed3b292ed654c2ac61b09de4a80e298 (git)
Affected: 6.15.3 , < 6.16 (semver)
guessed Create a notification for this product.
Linux Linux Affected: 6.16
Unaffected: 0 , < 6.16 (semver)
Unaffected: 6.16.10 , ≤ 6.16.* (semver)
Unaffected: 6.17 , ≤ * (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/netfs/buffered_read.c",
            "fs/netfs/direct_read.c",
            "fs/netfs/direct_write.c",
            "fs/netfs/internal.h",
            "fs/netfs/objects.c",
            "fs/netfs/read_pgpriv2.c",
            "fs/netfs/read_single.c",
            "fs/netfs/write_issue.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "8df142e93098b4531fadb5dfcf93087649f570b3",
              "status": "affected",
              "version": "20d72b00ca814d748f5663484e5c53bb2bf37a3a",
              "versionType": "git"
            },
            {
              "lessThan": "4d428dca252c858bfac691c31fa95d26cd008706",
              "status": "affected",
              "version": "20d72b00ca814d748f5663484e5c53bb2bf37a3a",
              "versionType": "git"
            },
            {
              "status": "affected",
              "version": "1a8360c2eed3b292ed654c2ac61b09de4a80e298",
              "versionType": "git"
            },
            {
              "lessThan": "6.16",
              "status": "affected",
              "version": "6.15.3",
              "versionType": "semver"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "fs/netfs/buffered_read.c",
            "fs/netfs/direct_read.c",
            "fs/netfs/direct_write.c",
            "fs/netfs/internal.h",
            "fs/netfs/objects.c",
            "fs/netfs/read_pgpriv2.c",
            "fs/netfs/read_single.c",
            "fs/netfs/write_issue.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "6.16"
            },
            {
              "lessThan": "6.16",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.16.*",
              "status": "unaffected",
              "version": "6.16.10",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "6.17",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.16.10",
                  "versionStartIncluding": "6.16",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.17",
                  "versionStartIncluding": "6.16",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionStartIncluding": "6.15.3",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nnetfs: fix reference leak\n\nCommit 20d72b00ca81 (\"netfs: Fix the request\u0027s work item to not\nrequire a ref\") modified netfs_alloc_request() to initialize the\nreference counter to 2 instead of 1.  The rationale was that the\nrequet\u0027s \"work\" would release the second reference after completion\n(via netfs_{read,write}_collection_worker()).  That works most of the\ntime if all goes well.\n\nHowever, it leaks this additional reference if the request is released\nbefore the I/O operation has been submitted: the error code path only\ndecrements the reference counter once and the work item will never be\nqueued because there will never be a completion.\n\nThis has caused outages of our whole server cluster today because\ntasks were blocked in netfs_wait_for_outstanding_io(), leading to\ndeadlocks in Ceph (another bug that I will address soon in another\npatch).  This was caused by a netfs_pgpriv2_begin_copy_to_cache() call\nwhich failed in fscache_begin_write_operation().  The leaked\nnetfs_io_request was never completed, leaving `netfs_inode.io_count`\nwith a positive value forever.\n\nAll of this is super-fragile code.  Finding out which code paths will\nlead to an eventual completion and which do not is hard to see:\n\n- Some functions like netfs_create_write_req() allocate a request, but\n  will never submit any I/O.\n\n- netfs_unbuffered_read_iter_locked() calls netfs_unbuffered_read()\n  and then netfs_put_request(); however, netfs_unbuffered_read() can\n  also fail early before submitting the I/O request, therefore another\n  netfs_put_request() call must be added there.\n\nA rule of thumb is that functions that return a `netfs_io_request` do\nnot submit I/O, and all of their callers must be checked.\n\nFor my taste, the whole netfs code needs an overhaul to make reference\ncounting easier to understand and less fragile \u0026 obscure.  But to fix\nthis bug here and now and produce a patch that is adequate for a\nstable backport, I tried a minimal approach that quickly frees the\nrequest object upon early failure.\n\nI decided against adding a second netfs_put_request() each time\nbecause that would cause code duplication which obscures the code\nfurther.  Instead, I added the function netfs_put_failed_request()\nwhich frees such a failed request synchronously under the assumption\nthat the reference count is exactly 2 (as initially set by\nnetfs_alloc_request() and never touched), verified by a\nWARN_ON_ONCE().  It then deinitializes the request object (without\ngoing through the \"cleanup_work\" indirection) and frees the allocation\n(with RCU protection to protect against concurrent access by\nnetfs_requests_seq_start()).\n\nAll code paths that fail early have been changed to call\nnetfs_put_failed_request() instead of netfs_put_request().\nAdditionally, I have added a netfs_put_request() call to\nnetfs_unbuffered_read() as explained above because the\nnetfs_put_failed_request() approach does not work there."
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-05-23T16:01:14.674Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/8df142e93098b4531fadb5dfcf93087649f570b3"
        },
        {
          "url": "https://git.kernel.org/stable/c/4d428dca252c858bfac691c31fa95d26cd008706"
        }
      ],
      "title": "netfs: fix reference leak",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2025-40007",
    "datePublished": "2025-10-20T15:26:53.880Z",
    "dateReserved": "2025-04-16T07:20:57.151Z",
    "dateUpdated": "2026-05-23T16:01:14.674Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2025-40007",
      "date": "2026-10-22",
      "epss": "0.00225",
      "percentile": "0.12408"
    },
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "defaultStatus": "unaffected",
                "product": "Linux",
                "programFiles": [
                  "fs/netfs/buffered_read.c",
                  "fs/netfs/direct_read.c",
                  "fs/netfs/direct_write.c",
                  "fs/netfs/internal.h",
                  "fs/netfs/objects.c",
                  "fs/netfs/read_pgpriv2.c",
                  "fs/netfs/read_single.c",
                  "fs/netfs/write_issue.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "lessThan": "8df142e93098b4531fadb5dfcf93087649f570b3",
                    "status": "affected",
                    "version": "20d72b00ca814d748f5663484e5c53bb2bf37a3a",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "4d428dca252c858bfac691c31fa95d26cd008706",
                    "status": "affected",
                    "version": "20d72b00ca814d748f5663484e5c53bb2bf37a3a",
                    "versionType": "git"
                  },
                  {
                    "status": "affected",
                    "version": "1a8360c2eed3b292ed654c2ac61b09de4a80e298",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "6.16",
                    "status": "affected",
                    "version": "6.15.3",
                    "versionType": "semver"
                  }
                ]
              },
              {
                "defaultStatus": "affected",
                "product": "Linux",
                "programFiles": [
                  "fs/netfs/buffered_read.c",
                  "fs/netfs/direct_read.c",
                  "fs/netfs/direct_write.c",
                  "fs/netfs/internal.h",
                  "fs/netfs/objects.c",
                  "fs/netfs/read_pgpriv2.c",
                  "fs/netfs/read_single.c",
                  "fs/netfs/write_issue.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "status": "affected",
                    "version": "6.16"
                  },
                  {
                    "lessThan": "6.16",
                    "status": "unaffected",
                    "version": "0",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.16.*",
                    "status": "unaffected",
                    "version": "6.16.10",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "*",
                    "status": "unaffected",
                    "version": "6.17",
                    "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\nnetfs: fix reference leak\n\nCommit 20d72b00ca81 (\"netfs: Fix the request\u0027s work item to not\nrequire a ref\") modified netfs_alloc_request() to initialize the\nreference counter to 2 instead of 1.  The rationale was that the\nrequet\u0027s \"work\" would release the second reference after completion\n(via netfs_{read,write}_collection_worker()).  That works most of the\ntime if all goes well.\n\nHowever, it leaks this additional reference if the request is released\nbefore the I/O operation has been submitted: the error code path only\ndecrements the reference counter once and the work item will never be\nqueued because there will never be a completion.\n\nThis has caused outages of our whole server cluster today because\ntasks were blocked in netfs_wait_for_outstanding_io(), leading to\ndeadlocks in Ceph (another bug that I will address soon in another\npatch).  This was caused by a netfs_pgpriv2_begin_copy_to_cache() call\nwhich failed in fscache_begin_write_operation().  The leaked\nnetfs_io_request was never completed, leaving `netfs_inode.io_count`\nwith a positive value forever.\n\nAll of this is super-fragile code.  Finding out which code paths will\nlead to an eventual completion and which do not is hard to see:\n\n- Some functions like netfs_create_write_req() allocate a request, but\n  will never submit any I/O.\n\n- netfs_unbuffered_read_iter_locked() calls netfs_unbuffered_read()\n  and then netfs_put_request(); however, netfs_unbuffered_read() can\n  also fail early before submitting the I/O request, therefore another\n  netfs_put_request() call must be added there.\n\nA rule of thumb is that functions that return a `netfs_io_request` do\nnot submit I/O, and all of their callers must be checked.\n\nFor my taste, the whole netfs code needs an overhaul to make reference\ncounting easier to understand and less fragile \u0026 obscure.  But to fix\nthis bug here and now and produce a patch that is adequate for a\nstable backport, I tried a minimal approach that quickly frees the\nrequest object upon early failure.\n\nI decided against adding a second netfs_put_request() each time\nbecause that would cause code duplication which obscures the code\nfurther.  Instead, I added the function netfs_put_failed_request()\nwhich frees such a failed request synchronously under the assumption\nthat the reference count is exactly 2 (as initially set by\nnetfs_alloc_request() and never touched), verified by a\nWARN_ON_ONCE().  It then deinitializes the request object (without\ngoing through the \"cleanup_work\" indirection) and frees the allocation\n(with RCU protection to protect against concurrent access by\nnetfs_requests_seq_start()).\n\nAll code paths that fail early have been changed to call\nnetfs_put_failed_request() instead of netfs_put_request().\nAdditionally, I have added a netfs_put_request() call to\nnetfs_unbuffered_read() as explained above because the\nnetfs_put_failed_request() approach does not work there."
          },
          {
            "lang": "es",
            "value": "En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:\n\nnetfs: corregir fuga de referencia\n\nEl commit 20d72b00ca81 (\u0027netfs: Corregir el elemento de trabajo de la solicitud para que no requiera una referencia\u0027) modific\u00f3 netfs_alloc_request() para inicializar el contador de referencias a 2 en lugar de 1. La justificaci\u00f3n era que el \u0027trabajo\u0027 de la solicitud liberar\u00eda la segunda referencia despu\u00e9s de la finalizaci\u00f3n (a trav\u00e9s de netfs_{read,write}_collection_worker()). Eso funciona la mayor parte del tiempo si todo va bien.\n\nSin embargo, fuga esta referencia adicional si la solicitud se libera antes de que se haya enviado la operaci\u00f3n de E/S: la ruta del c\u00f3digo de error solo decrementa el contador de referencias una vez y el elemento de trabajo nunca se pondr\u00e1 en cola porque nunca habr\u00e1 una finalizaci\u00f3n.\n\nEsto ha causado interrupciones en todo nuestro cl\u00faster de servidores hoy porque las tareas estaban bloqueadas en netfs_wait_for_outstanding_io(), lo que llev\u00f3 a interbloqueos en Ceph (otro error que abordar\u00e9 pronto en otro parche). Esto fue causado por una llamada a netfs_pgpriv2_begin_copy_to_cache() que fall\u00f3 en fscache_begin_write_operation(). La netfs_io_request fugada nunca se complet\u00f3, dejando \u0027netfs_inode.io_count\u0027 con un valor positivo para siempre.\n\nTodo esto es c\u00f3digo s\u00faper fr\u00e1gil. Descubrir qu\u00e9 rutas de c\u00f3digo conducir\u00e1n a una eventual finalizaci\u00f3n y cu\u00e1les no es dif\u00edcil de ver:\n\n- Algunas funciones como netfs_create_write_req() asignan una solicitud, pero nunca enviar\u00e1n ninguna E/S.\n\n- netfs_unbuffered_read_iter_locked() llama a netfs_unbuffered_read() y luego a netfs_put_request(); sin embargo, netfs_unbuffered_read() tambi\u00e9n puede fallar tempranamente antes de enviar la solicitud de E/S, por lo tanto, se debe agregar otra llamada a netfs_put_request() all\u00ed.\n\nUna regla general es que las funciones que devuelven una \u0027netfs_io_request\u0027 no env\u00edan E/S, y todos sus llamadores deben ser revisados.\n\nPara mi gusto, todo el c\u00f3digo netfs necesita una revisi\u00f3n para que el conteo de referencias sea m\u00e1s f\u00e1cil de entender y menos fr\u00e1gil y oscuro. Pero para corregir este error aqu\u00ed y ahora y producir un parche que sea adecuado para un backport estable, prob\u00e9 un enfoque m\u00ednimo que libera r\u00e1pidamente el objeto de solicitud ante un fallo temprano.\n\nDecid\u00ed no agregar una segunda netfs_put_request() cada vez porque eso causar\u00eda duplicaci\u00f3n de c\u00f3digo que oscurece a\u00fan m\u00e1s el c\u00f3digo. En su lugar, agregu\u00e9 la funci\u00f3n netfs_put_failed_request() que libera dicha solicitud fallida sincr\u00f3nicamente bajo la suposici\u00f3n de que el conteo de referencias es exactamente 2 (como se estableci\u00f3 inicialmente por netfs_alloc_request() y nunca se toc\u00f3), verificado por un WARN_ON_ONCE(). Luego desinicializa el objeto de solicitud (sin pasar por la indirecci\u00f3n \u0027cleanup_work\u0027) y libera la asignaci\u00f3n (con protecci\u00f3n RCU para proteger contra el acceso concurrente por netfs_requests_seq_start()).\n\nTodas las rutas de c\u00f3digo que fallan tempranamente se han cambiado para llamar a netfs_put_failed_request() en lugar de netfs_put_request(). Adem\u00e1s, he agregado una llamada a netfs_put_request() a netfs_unbuffered_read() como se explic\u00f3 anteriormente porque el enfoque de netfs_put_failed_request() no funciona all\u00ed."
          }
        ],
        "id": "CVE-2025-40007",
        "lastModified": "2026-10-19T21:10:00.160",
        "metrics": {},
        "published": "2025-10-20T16:15:37.357",
        "references": [
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/4d428dca252c858bfac691c31fa95d26cd008706"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/8df142e93098b4531fadb5dfcf93087649f570b3"
          }
        ],
        "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "vulnStatus": "Deferred"
      }
    },
    "redhat_vex": {
      "aggregate_severity": "Moderate",
      "current_release_date": "2026-06-30T01:28:54+00:00",
      "cve": "CVE-2025-40007",
      "id": "CVE-2025-40007",
      "initial_release_date": "2025-10-20T00:00:00+00:00",
      "product_status:known_affected": "76",
      "product_status:known_not_affected": "198",
      "source": "Red Hat CSAF VEX",
      "status": "final",
      "title": "kernel: netfs: fix reference leak",
      "url": "https://security.access.redhat.com/data/csaf/v2/vex/2025/cve-2025-40007.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.