CVE-2026-99231 (GCVE-0-2026-99231)

Vulnerability from cvelistv5 – Published: 2026-11-02 16:06 – Updated: 2026-11-02 16:06
VLAI
Title
io_uring/waitid: own the request before clearing ->head
Summary
In the Linux kernel, the following vulnerability has been resolved: io_uring/waitid: own the request before clearing ->head io_waitid_remove_wq() only takes the wait queue lock if ->head is set. io_waitid_wait() clears ->head first thing, before it tries to become the owner of the request by bumping ->refs. If somebody else owns the request at that point, nothing keeps it from completing the request while the wake up handler is still going to touch it: CPU0 (io_waitid_wait) CPU1 (io_waitid, holds a ref) list_del_init(&wait->entry) smp_store_release(&iw->head, NULL) __do_wait() finds another child io_waitid_remove_wq() // ->head == NULL, no locking io_waitid_finish(), IOU_COMPLETE // request freed and reused atomic_fetch_inc(&iw->refs) The same goes for __io_waitid_cancel() if it claims the request in that window. ->refs is part of the per opcode data of the request, so this increments whatever the next user of the request keeps there. If that happens to be zero, the handler concludes that it owns the request, and queues io_waitid_cb() for it. With the window held open by a delay, and the request reused for a receive that is waiting for data: BUG: KASAN: slab-use-after-free in __wake_up_common+0x1ca/0x1f0 __wake_up_sync_key+0x36/0x50 sock_def_readable+0xf1/0x420 unix_stream_sendmsg+0x60b/0x1110 Allocated by task 87: io_arm_apoll+0x1ed/0x940 Freed by task 87: __io_submit_flush_completions+0x118d/0x1a10 tctx_task_work_run+0x327/0x950 Only clear ->head once the handler owns the request. If it doesn't, the owner finds ->head set and has to wait for the lock, which is held by the caller of the handler. Deleting the already deleted entry again is harmless.
Assigner
Linux CNA under the mitre root
CNA scorecard D 53/100 over 6848 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
Linux Linux Affected: 09951a4d37e33b0197afc7fb77e39f09a3213ee6 , < bf01da1a9cca4a54e5c30b8344e52c26afb87be7 (git)
Affected: 934ffdd1cdef232eb125e63c2ebafb7f2deff6af , < 8381a912c65b8de16e8a848225c7c5a56b6ea834 (git)
Affected: ab673c1bcaf20ac70352eeb6bf5b828462676693 , < c10ad2813e15186fb51b37a4d17fafddc99e89a5 (git)
Affected: 6.12.113 , < 6.12.115 (semver)
Affected: 6.18.52 , < 6.18.60 (semver)
guessed Create a notification for this product.
Linux Linux Affected: 6.19
Unaffected: 0 , < 6.19 (semver)
Unaffected: 6.12.115 , ≤ 6.12.* (semver)
Unaffected: 6.18.60 , ≤ 6.18.* (semver)
Unaffected: 7.2.14 , ≤ 7.2.* (semver)
guessed Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "io_uring/waitid.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "bf01da1a9cca4a54e5c30b8344e52c26afb87be7",
              "status": "affected",
              "version": "09951a4d37e33b0197afc7fb77e39f09a3213ee6",
              "versionType": "git"
            },
            {
              "lessThan": "8381a912c65b8de16e8a848225c7c5a56b6ea834",
              "status": "affected",
              "version": "934ffdd1cdef232eb125e63c2ebafb7f2deff6af",
              "versionType": "git"
            },
            {
              "lessThan": "c10ad2813e15186fb51b37a4d17fafddc99e89a5",
              "status": "affected",
              "version": "ab673c1bcaf20ac70352eeb6bf5b828462676693",
              "versionType": "git"
            },
            {
              "lessThan": "6.12.115",
              "status": "affected",
              "version": "6.12.113",
              "versionType": "semver"
            },
            {
              "lessThan": "6.18.60",
              "status": "affected",
              "version": "6.18.52",
              "versionType": "semver"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "io_uring/waitid.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "6.19"
            },
            {
              "lessThan": "6.19",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.12.*",
              "status": "unaffected",
              "version": "6.12.115",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.18.*",
              "status": "unaffected",
              "version": "6.18.60",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "7.2.*",
              "status": "unaffected",
              "version": "7.2.14",
              "versionType": "semver"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.12.115",
                  "versionStartIncluding": "6.12.113",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.18.60",
                  "versionStartIncluding": "6.18.52",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.2.14",
                  "versionStartIncluding": "6.19",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nio_uring/waitid: own the request before clearing -\u003ehead\n\nio_waitid_remove_wq() only takes the wait queue lock if -\u003ehead is set.\nio_waitid_wait() clears -\u003ehead first thing, before it tries to become the\nowner of the request by bumping -\u003erefs. If somebody else owns the request\nat that point, nothing keeps it from completing the request while the\nwake up handler is still going to touch it:\n\nCPU0 (io_waitid_wait)                 CPU1 (io_waitid, holds a ref)\nlist_del_init(\u0026wait-\u003eentry)\nsmp_store_release(\u0026iw-\u003ehead, NULL)\n                                      __do_wait() finds another child\n                                      io_waitid_remove_wq()\n                                        // -\u003ehead == NULL, no locking\n                                      io_waitid_finish(), IOU_COMPLETE\n                                      // request freed and reused\natomic_fetch_inc(\u0026iw-\u003erefs)\n\nThe same goes for __io_waitid_cancel() if it claims the request in that\nwindow. -\u003erefs is part of the per opcode data of the request, so this\nincrements whatever the next user of the request keeps there. If that\nhappens to be zero, the handler concludes that it owns the request, and\nqueues io_waitid_cb() for it. With the window held open by a delay, and\nthe request reused for a receive that is waiting for data:\n\n  BUG: KASAN: slab-use-after-free in __wake_up_common+0x1ca/0x1f0\n   __wake_up_sync_key+0x36/0x50\n   sock_def_readable+0xf1/0x420\n   unix_stream_sendmsg+0x60b/0x1110\n  Allocated by task 87:\n   io_arm_apoll+0x1ed/0x940\n  Freed by task 87:\n   __io_submit_flush_completions+0x118d/0x1a10\n   tctx_task_work_run+0x327/0x950\n\nOnly clear -\u003ehead once the handler owns the request. If it doesn\u0027t, the\nowner finds -\u003ehead set and has to wait for the lock, which is held by the\ncaller of the handler. Deleting the already deleted entry again is\nharmless."
        }
      ],
      "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 - io_uring_enter() submits an IORING_OP_WAITID SQE via io_submit_sqes()-\u003eio_init_req()-\u003eio_waitid_prep()/io_queue_sqe()-\u003eio_issue_sqe()-\u003eio_waitid(), which arms io_waitid_wait() on current-\u003esignal-\u003ewait_chldexit; the trigger is that local SQE plus the attacker\u2019s own child exit through __wake_up_parent(), not a remote protocol message.\nAC:L - The attacker owns both sides of the race in io_waitid_wait(): they fork children so __wake_up_parent() runs the callback while io_waitid() still holds the issue ref in __do_wait(), or another thread\u2019s IORING_OP_ASYNC_CANCEL claims the request in __io_waitid_cancel(), then recycle the freed io_kiocb from the request cache with a follow-up recv SQE.\nPR:L - io_uring_setup() calls io_uring_allowed(), and sysctl_io_uring_disabled defaults to 0 so no capability is required; IORING_OP_WAITID\u2019s io_issue_def has no extra privilege flag, and kernel_waitid_prepare() only looks up the caller\u2019s own children.\nUI:N - The same local process creates the ring, submits IORING_OP_WAITID, forks and exits its own children to wake wait_chldexit, and optionally submits IORING_OP_ASYNC_CANCEL; no other user must act.\nS:U - The use-after-free is of an io_kiocb in the host io_uring request cache; impact stays inside the same kernel authority and does not cross a VM, IOMMU, or guest/host boundary.\nC:H - After io_waitid_finish() frees the request, io_waitid_wait() still does atomic_fetch_inc(\u0026iw-\u003erefs) on the cmd overlay of the recycled io_kiocb; occupying it with IORING_OP_RECV (as in the commit\u2019s KASAN trace) and queueing io_waitid_cb() on that object yields a kernel read of the reused request.\nI:H - The same UAF lets io_waitid_wait() write req-\u003eio_task_work.func=io_waitid_cb on a request already reused as a receive, so io_waitid_complete() frees an in-flight poll wait; the commit\u2019s KASAN hit in __wake_up_common() from unix_stream_sendmsg() is a type-confused write/control-flow primitive.\nA:H - Completing and freeing the io_kiocb while io_waitid_wait() still touches iw-\u003erefs, or running io_waitid_cb() on a recycled receive, produces the documented KASAN slab-use-after-free in __wake_up_common() and a kernel oops."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T16:06:38.553Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/bf01da1a9cca4a54e5c30b8344e52c26afb87be7"
        },
        {
          "url": "https://git.kernel.org/stable/c/8381a912c65b8de16e8a848225c7c5a56b6ea834"
        },
        {
          "url": "https://git.kernel.org/stable/c/c10ad2813e15186fb51b37a4d17fafddc99e89a5"
        }
      ],
      "title": "io_uring/waitid: own the request before clearing -\u003ehead",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2026-99231",
    "datePublished": "2026-11-02T16:06:38.553Z",
    "dateReserved": "2026-09-25T10:25:14.402Z",
    "dateUpdated": "2026-11-02T16:06:38.553Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-99231",
      "date": "2026-11-03",
      "epss": "0.00115",
      "percentile": "0.01578"
    },
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "defaultStatus": "unaffected",
                "product": "Linux",
                "programFiles": [
                  "io_uring/waitid.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "lessThan": "bf01da1a9cca4a54e5c30b8344e52c26afb87be7",
                    "status": "affected",
                    "version": "09951a4d37e33b0197afc7fb77e39f09a3213ee6",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "8381a912c65b8de16e8a848225c7c5a56b6ea834",
                    "status": "affected",
                    "version": "934ffdd1cdef232eb125e63c2ebafb7f2deff6af",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "c10ad2813e15186fb51b37a4d17fafddc99e89a5",
                    "status": "affected",
                    "version": "ab673c1bcaf20ac70352eeb6bf5b828462676693",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "6.12.115",
                    "status": "affected",
                    "version": "6.12.113",
                    "versionType": "semver"
                  },
                  {
                    "lessThan": "6.18.60",
                    "status": "affected",
                    "version": "6.18.52",
                    "versionType": "semver"
                  }
                ]
              },
              {
                "defaultStatus": "affected",
                "product": "Linux",
                "programFiles": [
                  "io_uring/waitid.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "status": "affected",
                    "version": "6.19"
                  },
                  {
                    "lessThan": "6.19",
                    "status": "unaffected",
                    "version": "0",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.12.*",
                    "status": "unaffected",
                    "version": "6.12.115",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.18.*",
                    "status": "unaffected",
                    "version": "6.18.60",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "7.2.*",
                    "status": "unaffected",
                    "version": "7.2.14",
                    "versionType": "semver"
                  }
                ]
              }
            ],
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
          }
        ],
        "cveTags": [],
        "descriptions": [
          {
            "lang": "en",
            "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nio_uring/waitid: own the request before clearing -\u003ehead\n\nio_waitid_remove_wq() only takes the wait queue lock if -\u003ehead is set.\nio_waitid_wait() clears -\u003ehead first thing, before it tries to become the\nowner of the request by bumping -\u003erefs. If somebody else owns the request\nat that point, nothing keeps it from completing the request while the\nwake up handler is still going to touch it:\n\nCPU0 (io_waitid_wait)                 CPU1 (io_waitid, holds a ref)\nlist_del_init(\u0026wait-\u003eentry)\nsmp_store_release(\u0026iw-\u003ehead, NULL)\n                                      __do_wait() finds another child\n                                      io_waitid_remove_wq()\n                                        // -\u003ehead == NULL, no locking\n                                      io_waitid_finish(), IOU_COMPLETE\n                                      // request freed and reused\natomic_fetch_inc(\u0026iw-\u003erefs)\n\nThe same goes for __io_waitid_cancel() if it claims the request in that\nwindow. -\u003erefs is part of the per opcode data of the request, so this\nincrements whatever the next user of the request keeps there. If that\nhappens to be zero, the handler concludes that it owns the request, and\nqueues io_waitid_cb() for it. With the window held open by a delay, and\nthe request reused for a receive that is waiting for data:\n\n  BUG: KASAN: slab-use-after-free in __wake_up_common+0x1ca/0x1f0\n   __wake_up_sync_key+0x36/0x50\n   sock_def_readable+0xf1/0x420\n   unix_stream_sendmsg+0x60b/0x1110\n  Allocated by task 87:\n   io_arm_apoll+0x1ed/0x940\n  Freed by task 87:\n   __io_submit_flush_completions+0x118d/0x1a10\n   tctx_task_work_run+0x327/0x950\n\nOnly clear -\u003ehead once the handler owns the request. If it doesn\u0027t, the\nowner finds -\u003ehead set and has to wait for the lock, which is held by the\ncaller of the handler. Deleting the already deleted entry again is\nharmless."
          }
        ],
        "id": "CVE-2026-99231",
        "lastModified": "2026-11-02T16:17:48.060",
        "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": "2026-11-02T16:17:48.060",
        "references": [
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/8381a912c65b8de16e8a848225c7c5a56b6ea834"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/bf01da1a9cca4a54e5c30b8344e52c26afb87be7"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/c10ad2813e15186fb51b37a4d17fafddc99e89a5"
          }
        ],
        "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "vulnStatus": "Received"
      }
    },
    "redhat_vex": {
      "aggregate_severity": "Important",
      "current_release_date": "2026-11-02T19:33:32+00:00",
      "cve": "CVE-2026-99231",
      "id": "CVE-2026-99231",
      "initial_release_date": "2026-11-02T16:06:38.553000+00:00",
      "product_status:known_not_affected": "280",
      "source": "Red Hat CSAF VEX",
      "status": "final",
      "title": "kernel: kernel: Privilege escalation via use-after-free in io_uring waitid",
      "url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-99231.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
How durations are calculated

Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.

Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.

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.