---
id: "CVE-2026-99227"
kind: "vulnerability"
aliases: ["CVE-2026-99227"]
title: "Linux kernel: repeated io_uring waitid cancellation can complete a request twice"
severity: "high"
cvss: 7.8
epss: null
exploited: false
status: "open"
category: "runtime"
products: []
ecosystems: []
tags: ["io_uring", "linux-kernel", "runtime", "self-hosted"]
not_affected_if: ["io_uring-disabled"]
published_at: "2026-11-02T16:17:47+00:00"
first_seen_at: "2026-11-02T16:24:05+00:00"
updated_at: "2026-11-02T16:29:33+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-99227", "first_seen_at": "2026-11-02T16:24:05+00:00"}, {"source": "analyst", "url": null, "first_seen_at": "2026-11-02T16:29:33+00:00"}]
---

# Linux kernel: repeated io_uring waitid cancellation can complete a request twice

A bug in the Linux kernel's io_uring waitid code lets repeated failed cancellation attempts wrap an internal reference counter to zero. A later cancellation can then complete the same request a second time, which can corrupt kernel state.

_Summary, check and fix written by a model from the sources; labelled as such._

## How to check

- Run uname -r and check your distro's kernel changelog/security tracker for CVE-2026-99227 or commit 98787d3fa4e9.
- Affected code is anything with IORING_OP_WAITID (introduced by commit f31ecf671ddc); kernels without it are not affected.
- cat /proc/sys/kernel/io_uring_disabled: 0 allows all users, 1 restricts to privileged/group, 2 disables io_uring. Setting 2 would block the path (sysctl semantics, not confirmed on the vendor page).

## Fix

Upstream fix is commit 98787d3fa4e99564d2b2bc21255b21f670c450d0 (io_uring/waitid: prevent cancel reference wrap). Fixed stable kernel versions not yet published in the sources read; install your distro kernel update that lists CVE-2026-99227 or contains this commit.

## Timeline

- 2026-11-02T16:24:05+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-99227
- 2026-11-02T16:29:33+00:00 analyst — Found upstream patch (Junyeong Lee, 2026-10-19) applied by Jens Axboe as commit 98787d3fa4e99564d2b2bc21255b21f670c450d0 in the io_uring tree; Fixes f31ecf671ddc (IORING_OP_WAITID support), Cc stable. No stable release numbers read yet; NVD page returned no text. Nothing verified.

## Documents

- [describes] [PATCH] io_uring/waitid: prevent cancel reference wrap (Junyeong Lee) https://lkml.iu.edu/2610.2/07793.html
- [fix] Re: [PATCH] io_uring/waitid: prevent cancel reference wrap (Jens Axboe, applied) https://lkml.iu.edu/2610.2/08336.html

## From the sources

In the Linux kernel, the following vulnerability has been resolved:

io_uring/waitid: prevent cancel reference wrap

io_waitid packs the cancellation state into bit 31 of ->refs and uses
bits 30:0 as a 31-bit reference counter:

  #define IO_WAITID_CANCEL_FLAG BIT(31)
  #define IO_WAITID_REF_MASK    GENMASK(30, 0)

__io_waitid_cancel() marks a request canceled, then increments the low
bits of ->refs to claim completion ownership. When another path owns the
request, the increment remains even though cancellation returns false.
The request remains discoverable by cancellation, so repeated failed
attempts can wrap the 31-bit reference field to zero. A later
cancellation can claim ownership and complete the request a second time.

Use atomic_fetch_or() when setting the cancel flag and inspect the old
flag value. The first cancel attempt continues to the existing ownership
increment, preserving its wake and issuer handoff semantics. Later
attempts see the cancel flag and return without incrementing the
reference field.

This makes repeated failed cancellation attempts idempotent while
leaving the first-cancel state transitions unchanged.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
