GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

CVE-2026-89675 (GCVE-0-2026-89675)

Vulnerability from cvelistv5 – Published: 2026-09-11 19:45 – Updated: 2026-09-13 06:32
VLAI
Title
nfsd: fix UAF in async copy cancel and shutdown
Summary
In the Linux kernel, the following vulnerability has been resolved: nfsd: fix UAF in async copy cancel and shutdown An async copy could be freed or used after free while a teardown caller (OFFLOAD_CANCEL, nfsd4_shutdown_copy, nfsd4_cancel_copy_by_sb) raced the copy kthread: - find_async_copy() bumped copy->refcount but left the copy on clp->async_copies, so the reaper's cleanup_async_copy() could run release_copy_files() concurrently with a cancel/shutdown caller. Both put and NULL nf_src/nf_dst without a common lock, double-putting the nfsd_file and freeing it early. - nfsd4_do_async_copy() set NFSD4_COPY_F_STOPPED before its final uses of the copy (nfsd_update_cmtime_attr() on copy->nf_dst, nfsd4_send_cb_offload()). nfsd4_stop_copy() treats a set STOPPED bit as "kthread done, skip kthread_stop()", so a teardown caller ran release_copy_files() -- which puts and NULLs nf_dst -- while the kthread still dereferenced it (NULL/UAF). - copy->copy_task was never pinned. The one-shot kthread self-reaps on return, so kthread_stop()'s get_task_struct() could touch a freed task_struct. - co_cb is embedded in the copy, but nfsd4_send_cb_offload() held a reference only on the client, so a concurrent teardown could free the copy while the CB_OFFLOAD callback was in flight. Fix the teardown lifetime as a whole: - find_async_copy() unlinks the copy (clear cp_clp, list_del_init) under async_lock; the cancel, shutdown, and sb-cancel paths drop the list-membership reference via nfs4_put_copy() after nfsd4_stop_copy(). Drop the now-redundant list_del fixup from cleanup_async_copy(). - Because unlinking hides the copy from the reaper, its cleanup_async_copy() can no longer remove the copy's s2s_cp_stateids entry; the cancel/shutdown/sb-cancel paths now call nfs4_free_copy_state() themselves (while cp_clp is still valid) so the entry does not dangle at freed memory for the laundromat and manage_cpntf_state() to dereference. - Give the kthread its own reference, taken in nfsd4_copy() before wake_up_process() and dropped at the end of nfsd4_do_async_copy(); call wake_up_process() before list_add(). - Pin the task_struct with get_task_struct() in nfsd4_copy(), released in nfs4_put_copy(), so kthread_stop() is safe whenever the kthread exits. Set NFSD4_COPY_F_STOPPED only in nfsd4_stop_copy(), which now always kthread_stop()s before release_copy_files(); completion is still reported via NFSD4_COPY_F_COMPLETED, so nfsd4_has_active_async_copies() is unaffected. Each teardown caller removes the copy from clp->async_copies first, so kthread_stop() runs exactly once. - Take a copy reference in nfsd4_send_cb_offload(), dropped in nfsd4_cb_offload_release(). The kthread still holds its own reference there, so the refcount_inc() cannot race the final free. - Read cp_clp with smp_load_acquire() to pair with the unordered set_bit()/clear_bit() writers (Documentation/atomic_bitops.rst).
Impacted products
Vendor Product Version CPE status
Linux Linux Affected: e0639dc5805a9d4faaa2c07ad98fa853b9529dd3 , < 9031493ef7369d5c59c4bacc96f0c85965f09a98 (git)
Affected: e0639dc5805a9d4faaa2c07ad98fa853b9529dd3 , < a385cf5e016b748babf94cc664e43a26e17db117 (git)
Affected: e0639dc5805a9d4faaa2c07ad98fa853b9529dd3 , < 62c0f6eaf050bb9284c1f9cac6ed1770092e6b95 (git)
guessed Create a notification for this product.
Linux Linux Affected: 4.20
Unaffected: 0 , < 4.20 (semver)
Unaffected: 6.18.51 , ≤ 6.18.* (semver)
Unaffected: 7.2.4 , ≤ 7.2.* (semver)
Unaffected: 7.3-rc1 , ≤ * (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/nfsd/nfs4proc.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "9031493ef7369d5c59c4bacc96f0c85965f09a98",
              "status": "affected",
              "version": "e0639dc5805a9d4faaa2c07ad98fa853b9529dd3",
              "versionType": "git"
            },
            {
              "lessThan": "a385cf5e016b748babf94cc664e43a26e17db117",
              "status": "affected",
              "version": "e0639dc5805a9d4faaa2c07ad98fa853b9529dd3",
              "versionType": "git"
            },
            {
              "lessThan": "62c0f6eaf050bb9284c1f9cac6ed1770092e6b95",
              "status": "affected",
              "version": "e0639dc5805a9d4faaa2c07ad98fa853b9529dd3",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "fs/nfsd/nfs4proc.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "4.20"
            },
            {
              "lessThan": "4.20",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.18.*",
              "status": "unaffected",
              "version": "6.18.51",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "7.2.*",
              "status": "unaffected",
              "version": "7.2.4",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "7.3-rc1",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.18.51",
                  "versionStartIncluding": "4.20",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.2.4",
                  "versionStartIncluding": "4.20",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.3-rc1",
                  "versionStartIncluding": "4.20",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nnfsd: fix UAF in async copy cancel and shutdown\n\nAn async copy could be freed or used after free while a teardown caller\n(OFFLOAD_CANCEL, nfsd4_shutdown_copy, nfsd4_cancel_copy_by_sb) raced the\ncopy kthread:\n\n  - find_async_copy() bumped copy-\u003erefcount but left the copy on\n    clp-\u003easync_copies, so the reaper\u0027s cleanup_async_copy() could run\n    release_copy_files() concurrently with a cancel/shutdown caller. Both\n    put and NULL nf_src/nf_dst without a common lock, double-putting the\n    nfsd_file and freeing it early.\n\n  - nfsd4_do_async_copy() set NFSD4_COPY_F_STOPPED before its final uses\n    of the copy (nfsd_update_cmtime_attr() on copy-\u003enf_dst,\n    nfsd4_send_cb_offload()). nfsd4_stop_copy() treats a set STOPPED bit\n    as \"kthread done, skip kthread_stop()\", so a teardown caller ran\n    release_copy_files() -- which puts and NULLs nf_dst -- while the\n    kthread still dereferenced it (NULL/UAF).\n\n  - copy-\u003ecopy_task was never pinned. The one-shot kthread self-reaps on\n    return, so kthread_stop()\u0027s get_task_struct() could touch a freed\n    task_struct.\n\n  - co_cb is embedded in the copy, but nfsd4_send_cb_offload() held a\n    reference only on the client, so a concurrent teardown could free\n    the copy while the CB_OFFLOAD callback was in flight.\n\nFix the teardown lifetime as a whole:\n\n  - find_async_copy() unlinks the copy (clear cp_clp, list_del_init)\n    under async_lock; the cancel, shutdown, and sb-cancel paths drop the\n    list-membership reference via nfs4_put_copy() after nfsd4_stop_copy().\n    Drop the now-redundant list_del fixup from cleanup_async_copy().\n\n  - Because unlinking hides the copy from the reaper, its\n    cleanup_async_copy() can no longer remove the copy\u0027s s2s_cp_stateids\n    entry; the cancel/shutdown/sb-cancel paths now call\n    nfs4_free_copy_state() themselves (while cp_clp is still valid) so\n    the entry does not dangle at freed memory for the laundromat and\n    manage_cpntf_state() to dereference.\n\n  - Give the kthread its own reference, taken in nfsd4_copy() before\n    wake_up_process() and dropped at the end of nfsd4_do_async_copy();\n    call wake_up_process() before list_add().\n\n  - Pin the task_struct with get_task_struct() in nfsd4_copy(), released\n    in nfs4_put_copy(), so kthread_stop() is safe whenever the kthread\n    exits. Set NFSD4_COPY_F_STOPPED only in nfsd4_stop_copy(), which now\n    always kthread_stop()s before release_copy_files(); completion is\n    still reported via NFSD4_COPY_F_COMPLETED, so\n    nfsd4_has_active_async_copies() is unaffected. Each teardown caller\n    removes the copy from clp-\u003easync_copies first, so kthread_stop() runs\n    exactly once.\n\n  - Take a copy reference in nfsd4_send_cb_offload(), dropped in\n    nfsd4_cb_offload_release(). The kthread still holds its own reference\n    there, so the refcount_inc() cannot race the final free.\n\n  - Read cp_clp with smp_load_acquire() to pair with the unordered\n    set_bit()/clear_bit() writers (Documentation/atomic_bitops.rst)."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "baseScore": 9.8,
            "baseSeverity": "CRITICAL",
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            "version": "3.1"
          },
          "scenarios": [
            {
              "lang": "en",
              "value": "AV:N - The flaw is in nfsd\u0027s NFSv4.2 OP_COPY and OP_OFFLOAD_CANCEL handlers (nfsd4_copy/nfsd4_offload_cancel in fs/nfsd/nfs4proc.c), reached by sending COMPOUND RPCs over TCP port 2049 to the in-kernel NFS server; no local access to the host is required.\nAC:L - The attacker controls both sides of the race by starting an async COPY then issuing OFFLOAD_CANCEL or DESTROY_CLIENTID, and can stall CB_OFFLOAD replies so the embedded callback stays in flight on freed memory; the window is retryable and does not depend on uninfluenced victim state.\nPR:N - Under AUTH_SYS, the default NFS configuration, the server verifies no secret; EXCHANGE_ID, CREATE_SESSION, and OPEN succeed for any host permitted by the export, so a remote NFSv4.2 client needs no kernel-verified credentials or local privileges on the server.\nUI:N - The attacker\u0027s own NFS client issues COPY and OFFLOAD_CANCEL (or DESTROY_CLIENTID) against an already-running nfsd export; no administrator or other user action on the server is required.\nS:U - Impact is kernel heap use-after-free and nfsd state corruption within the same host kernel security authority; it does not cross a VM, hypervisor, or IOMMU boundary.\nC:H - Use-after-free of the nfsd4_copy object (including its embedded nfsd4_callback), nfsd_file src/dst objects, and the copy kthread task_struct allows slab reuse that can be leveraged for arbitrary kernel memory reads.\nI:H - The same UAFs enable heap spraying and arbitrary writes; CB_OFFLOAD work and rpc_task callbacks invoke cb_ops function pointers that live inside the freed copy, supporting control-flow hijack.\nA:H - Concurrent release_copy_files() double-puts nfsd_file, kthread_stop() can touch a self-reaped task_struct, and the copy kthread can NULL-dereference nf_dst after teardown, each of which oopses or panics the kernel."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-13T06:32:57.451Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/9031493ef7369d5c59c4bacc96f0c85965f09a98"
        },
        {
          "url": "https://git.kernel.org/stable/c/a385cf5e016b748babf94cc664e43a26e17db117"
        },
        {
          "url": "https://git.kernel.org/stable/c/62c0f6eaf050bb9284c1f9cac6ed1770092e6b95"
        }
      ],
      "title": "nfsd: fix UAF in async copy cancel and shutdown",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2026-89675",
    "datePublished": "2026-09-11T19:45:59.635Z",
    "dateReserved": "2026-09-11T19:38:34.747Z",
    "dateUpdated": "2026-09-13T06:32:57.451Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-89675",
      "date": "2026-09-16",
      "epss": "0.00448",
      "percentile": "0.38091"
    },
    "nvd": "{\"cve\":{\"id\":\"CVE-2026-89675\",\"sourceIdentifier\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"published\":\"2026-09-11T20:19:54.143\",\"lastModified\":\"2026-09-13T07:17:33.177\",\"vulnStatus\":\"Received\",\"cveTags\":[],\"descriptions\":[{\"lang\":\"en\",\"value\":\"In the Linux kernel, the following vulnerability has been resolved:\\n\\nnfsd: fix UAF in async copy cancel and shutdown\\n\\nAn async copy could be freed or used after free while a teardown caller\\n(OFFLOAD_CANCEL, nfsd4_shutdown_copy, nfsd4_cancel_copy_by_sb) raced the\\ncopy kthread:\\n\\n  - find_async_copy() bumped copy-\u003erefcount but left the copy on\\n    clp-\u003easync_copies, so the reaper\u0027s cleanup_async_copy() could run\\n    release_copy_files() concurrently with a cancel/shutdown caller. Both\\n    put and NULL nf_src/nf_dst without a common lock, double-putting the\\n    nfsd_file and freeing it early.\\n\\n  - nfsd4_do_async_copy() set NFSD4_COPY_F_STOPPED before its final uses\\n    of the copy (nfsd_update_cmtime_attr() on copy-\u003enf_dst,\\n    nfsd4_send_cb_offload()). nfsd4_stop_copy() treats a set STOPPED bit\\n    as \\\"kthread done, skip kthread_stop()\\\", so a teardown caller ran\\n    release_copy_files() -- which puts and NULLs nf_dst -- while the\\n    kthread still dereferenced it (NULL/UAF).\\n\\n  - copy-\u003ecopy_task was never pinned. The one-shot kthread self-reaps on\\n    return, so kthread_stop()\u0027s get_task_struct() could touch a freed\\n    task_struct.\\n\\n  - co_cb is embedded in the copy, but nfsd4_send_cb_offload() held a\\n    reference only on the client, so a concurrent teardown could free\\n    the copy while the CB_OFFLOAD callback was in flight.\\n\\nFix the teardown lifetime as a whole:\\n\\n  - find_async_copy() unlinks the copy (clear cp_clp, list_del_init)\\n    under async_lock; the cancel, shutdown, and sb-cancel paths drop the\\n    list-membership reference via nfs4_put_copy() after nfsd4_stop_copy().\\n    Drop the now-redundant list_del fixup from cleanup_async_copy().\\n\\n  - Because unlinking hides the copy from the reaper, its\\n    cleanup_async_copy() can no longer remove the copy\u0027s s2s_cp_stateids\\n    entry; the cancel/shutdown/sb-cancel paths now call\\n    nfs4_free_copy_state() themselves (while cp_clp is still valid) so\\n    the entry does not dangle at freed memory for the laundromat and\\n    manage_cpntf_state() to dereference.\\n\\n  - Give the kthread its own reference, taken in nfsd4_copy() before\\n    wake_up_process() and dropped at the end of nfsd4_do_async_copy();\\n    call wake_up_process() before list_add().\\n\\n  - Pin the task_struct with get_task_struct() in nfsd4_copy(), released\\n    in nfs4_put_copy(), so kthread_stop() is safe whenever the kthread\\n    exits. Set NFSD4_COPY_F_STOPPED only in nfsd4_stop_copy(), which now\\n    always kthread_stop()s before release_copy_files(); completion is\\n    still reported via NFSD4_COPY_F_COMPLETED, so\\n    nfsd4_has_active_async_copies() is unaffected. Each teardown caller\\n    removes the copy from clp-\u003easync_copies first, so kthread_stop() runs\\n    exactly once.\\n\\n  - Take a copy reference in nfsd4_send_cb_offload(), dropped in\\n    nfsd4_cb_offload_release(). The kthread still holds its own reference\\n    there, so the refcount_inc() cannot race the final free.\\n\\n  - Read cp_clp with smp_load_acquire() to pair with the unordered\\n    set_bit()/clear_bit() writers (Documentation/atomic_bitops.rst).\"}],\"affected\":[{\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"affectedData\":[{\"vendor\":\"Linux\",\"product\":\"Linux\",\"defaultStatus\":\"unaffected\",\"programFiles\":[\"fs/nfsd/nfs4proc.c\"],\"repo\":\"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\"versions\":[{\"version\":\"e0639dc5805a9d4faaa2c07ad98fa853b9529dd3\",\"lessThan\":\"9031493ef7369d5c59c4bacc96f0c85965f09a98\",\"versionType\":\"git\",\"status\":\"affected\"},{\"version\":\"e0639dc5805a9d4faaa2c07ad98fa853b9529dd3\",\"lessThan\":\"a385cf5e016b748babf94cc664e43a26e17db117\",\"versionType\":\"git\",\"status\":\"affected\"},{\"version\":\"e0639dc5805a9d4faaa2c07ad98fa853b9529dd3\",\"lessThan\":\"62c0f6eaf050bb9284c1f9cac6ed1770092e6b95\",\"versionType\":\"git\",\"status\":\"affected\"}]},{\"vendor\":\"Linux\",\"product\":\"Linux\",\"defaultStatus\":\"affected\",\"programFiles\":[\"fs/nfsd/nfs4proc.c\"],\"repo\":\"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\"versions\":[{\"version\":\"4.20\",\"status\":\"affected\"},{\"version\":\"0\",\"lessThan\":\"4.20\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"6.18.51\",\"lessThanOrEqual\":\"6.18.*\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"7.2.4\",\"lessThanOrEqual\":\"7.2.*\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"7.3-rc1\",\"lessThanOrEqual\":\"*\",\"versionType\":\"original_commit_for_fix\",\"status\":\"unaffected\"}]}]}],\"metrics\":{\"cvssMetricV31\":[{\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"type\":\"Secondary\",\"cvssData\":{\"version\":\"3.1\",\"vectorString\":\"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\",\"baseScore\":9.8,\"baseSeverity\":\"CRITICAL\",\"attackVector\":\"NETWORK\",\"attackComplexity\":\"LOW\",\"privilegesRequired\":\"NONE\",\"userInteraction\":\"NONE\",\"scope\":\"UNCHANGED\",\"confidentialityImpact\":\"HIGH\",\"integrityImpact\":\"HIGH\",\"availabilityImpact\":\"HIGH\"},\"exploitabilityScore\":3.9,\"impactScore\":5.9}]},\"references\":[{\"url\":\"https://git.kernel.org/stable/c/62c0f6eaf050bb9284c1f9cac6ed1770092e6b95\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/9031493ef7369d5c59c4bacc96f0c85965f09a98\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/a385cf5e016b748babf94cc664e43a26e17db117\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"}]}}",
    "redhat_vex": {
      "aggregate_severity": "Important",
      "current_release_date": "2026-09-13T06:51:47+00:00",
      "cve": "CVE-2026-89675",
      "id": "CVE-2026-89675",
      "initial_release_date": "2026-09-11T19:45:59.635000+00:00",
      "product_status:known_affected": "2",
      "source": "Red Hat CSAF VEX",
      "status": "final",
      "title": "kernel: nfsd: Linux kernel (nfsd): Use-After-Free vulnerability in asynchronous copy handling",
      "url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-89675.json",
      "version": "3"
    },
    "suse_vex": {
      "aggregate_severity": "moderate",
      "current_release_date": "2026-09-16T00:00:30Z",
      "cve": "CVE-2026-89675",
      "id": "CVE-2026-89675",
      "initial_release_date": "2026-09-15T00:57:26Z",
      "product_status:known_affected": "260",
      "product_status:known_not_affected": "93",
      "source": "SUSE CSAF VEX",
      "status": "interim",
      "title": "SUSE CVE CVE-2026-89675",
      "url": "https://ftp.suse.com/pub/projects/security/csaf-vex/cve-2026-89675.json",
      "version": "3"
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

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.

Loading…

Detection rules are retrieved from Rulezet.

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.


Loading…