---
id: "CVE-2026-98999"
kind: "vulnerability"
aliases: ["CVE-2026-98999"]
title: "Linux kernel xe driver: stale list entry leads to use-after-free"
severity: "unknown"
cvss: null
epss: 0.00219
exploited: false
status: "open"
category: "runtime"
products: []
ecosystems: []
tags: ["drm", "intel-xe", "kernel", "linux", "runtime"]
not_affected_if: []
published_at: "2026-10-23T13:17:22+00:00"
first_seen_at: "2026-10-23T21:57:33+00:00"
updated_at: "2026-10-25T12:38:50+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-98999", "first_seen_at": "2026-10-23T21:57:33+00:00"}, {"source": "epss", "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-98999", "first_seen_at": "2026-10-25T12:38:50+00:00"}]
---

# Linux kernel xe driver: stale list entry leads to use-after-free

In the Intel Xe DRM driver, a buffer pinned both externally (for example by dma-buf export) and as a display framebuffer can stay linked on a kernel pinned list after its final unpin. Once that buffer is freed, the dangling list entry can corrupt the list or cause a use-after-free.

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

## How to check

- unknown

## Fix

- unknown

## Timeline

- 2026-10-23T21:57:33+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-98999
- 2026-10-25T12:38:50+00:00 epss https://api.first.org/data/v1/epss?cve=CVE-2026-98999

## From the sources

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

drm/xe: Fix stale pinned_link entry when fb-pin performs the final unpin

xe_bo_pin_external() and xe_bo_unpin_external() maintain the bo's
pinned_link list membership in xe->pinned.late.external, based on
whether the current call is the outermost pin or the final unpin.
However, the same external bo's pin_count can also be raised and
lowered directly by __xe_pin_fb_vma()/__xe_unpin_fb_vma(), which pin
the bo as a display scanout buffer without going through
xe_bo_pin_external()/xe_bo_unpin_external() at all, and have no
notion of, or ownership over, pinned_link.

If a bo is pinned both externally (e.g. dma-buf export) and as an fb,
and the external unpin happens first, xe_bo_unpin_external() correctly
observes pin_count > 1 and leaves the bo on pinned_link. When the fb
unpin later performs the true last unpin (pin_count 1 -> 0), it never
touches pinned_link, leaving the bo linked on xe->pinned.late.external
indefinitely. Once the bo is subsequently freed, this stale list entry
points into freed memory, corrupting the list and risking a
use-after-free the next time the list is walked or spliced.

The backup object pin/unpin sites in xe_bo_notifier_prepare_pinned()/
xe_bo_notifier_unprepare_pinned() have the same bypass characteristic,
though they never add their bo to a pinned list, so are not affected
by this particular list-corruption issue.

Move the pinned_link removal into xe_bo_account_unpin(), which already
runs on every unpin path (kernel, external, framebuffer, backup
object) right before the true 1 -> 0 pin_count transition. Since
list_del_init() only operates on the node itself, this removal is
list-agnostic and safe to perform regardless of which list (external
or kernel_bo_present) the bo happens to be linked on, or which code
path is performing the final unpin. Drop the now-redundant explicit
list_del_init() calls in xe_bo_unpin_external() and xe_bo_unpin().

v2:
- New patch

v3:
- Rebased on changes to previous patch.

(cherry picked from commit ca58d36a1f93af586ee93b340c9f9fd81312cc01)

---

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