CVE-2026-98840 Overview
CVE-2026-98840 is a use-after-free (UAF) vulnerability in the Linux kernel's vc_screen subsystem. The flaw resides in vcs_write(), where the reload of the vc pointer sits after the if (ret) block. When copy_from_user() fails during the unlocked window, the break path exits the loop without reloading vc. If the virtual console was freed by vc_port_destruct through a concurrent VT_DISALLOCATE ioctl, the post-loop vcs_scr_updated(vc) call dereferences stale memory. The vcs_notifier() handler then reads param->vc->vc_num from freed slab memory, producing a KASAN slab-use-after-free report.
Critical Impact
Local attackers with write access to /dev/vcs* devices can trigger kernel memory corruption through a race between vcs_write() and VT_DISALLOCATE, potentially leading to privilege escalation or denial of service.
Affected Products
- Linux kernel versions containing commit 8fb9ea65c9d1 and a287620312dc prior to the fix
- Linux kernel stable branches referenced in the upstream patch series
- Distributions shipping affected kernels with virtual console support enabled
Discovery Timeline
- 2026-10-18 - CVE-2026-98840 published to NVD
- 2026-10-21 - Last updated in NVD database
Technical Details for CVE-2026-98840
Vulnerability Analysis
The vulnerability is a use-after-free [CWE-416] in the virtual console screen driver (drivers/tty/vt/vc_screen.c). The function vcs_write() copies user data into kernel buffers inside a loop guarded by console_lock(). Because copy_from_user() must run with the console lock dropped, the driver reloads the vc pointer after reacquiring the lock to account for concurrent teardown.
An earlier fix in commit 8fb9ea65c9d1 placed the reload after the if (ret) check that handles copy failures. On the copy-failure path, the loop breaks before vc is refreshed. If a parallel VT_DISALLOCATE ioctl invokes vc_port_destruct and kfree()s the vc_data structure during the unlocked window, the post-loop code reaches if (written && vc) vcs_scr_updated(vc) with a stale, non-NULL pointer.
The NULL guard added in commit a287620312dc does not catch this condition because the pointer is still non-NULL. vcs_scr_updated() then invokes the atomic notifier chain, and vcs_notifier() reads two bytes from freed slab memory at param->vc->vc_num.
Root Cause
The root cause is incorrect placement of the pointer reload inside vcs_write(). The reload must occur before any branch that can exit the loop, otherwise copy-failure paths carry a stale pointer out of the critical section. The existing NULL guard addresses only the explicit nullification case, not the stale-dangling-pointer case produced by concurrent kfree().
Attack Vector
A local attacker with permission to open /dev/vcs* or /dev/vcsa* and invoke VT_DISALLOCATE can race two threads: one performing write() with a user buffer that triggers copy_from_user() failure (for example, by unmapping the source page mid-copy), and another issuing VT_DISALLOCATE to free the target vc_data. Successful races yield a kernel read from freed memory, enabling information disclosure, kernel panic, or exploitation primitives for privilege escalation when combined with heap-grooming techniques.
See the upstream fix at Kernel Git Commit 1485a3d for the exact code change.
Detection Methods for CVE-2026-98840
Indicators of Compromise
- KASAN reports in dmesg containing slab-use-after-free in vcs_notifier with call traces through vcs_scr_updated and vcs_write.
- Unexpected kernel oops or panic reports referencing vcs_notifier+0x7c/0xd0 or atomic_notifier_call_chain from TTY write paths.
- Audit records showing unprivileged processes repeatedly invoking ioctl(VT_DISALLOCATE) alongside concurrent writes to /dev/vcs* nodes.
Detection Strategies
- Enable KASAN on test and canary kernels to surface the exact UAF signature described in the upstream commit message.
- Hunt for processes with simultaneous open handles to /dev/vcsa* and /dev/tty* performing VT_DISALLOCATE ioctls, which is atypical for normal workloads.
- Correlate kernel.ring_buffer KASAN output with process execution telemetry to identify the triggering binary.
Monitoring Recommendations
- Forward kernel logs to a centralized data lake and alert on KASAN, BUG:, and vcs_notifier strings.
- Monitor for unexpected virtual console allocation and deallocation patterns on multi-user Linux hosts.
- Track EDR process telemetry for binaries opening /dev/vcs* devices outside of trusted administrative tooling.
How to Mitigate CVE-2026-98840
Immediate Actions Required
- Apply the upstream Linux kernel patch that moves the vc reload to immediately after console_lock(), before the if (ret) branch.
- Update to kernel versions incorporating the commits listed in the NVD advisory and reboot affected systems.
- Restrict write access to /dev/vcs* and /dev/vcsa* device nodes to privileged administrative accounts only.
Patch Information
The fix is distributed across the following upstream kernel commits:
- Kernel Git Commit 1485a3d
- Kernel Git Commit 226bd56
- Kernel Git Commit 233a2e1
- Kernel Git Commit 9dfcadc
- Kernel Git Commit c073d01
Workarounds
- Harden permissions on virtual console device nodes using udev rules so only root or trusted groups can open them for write.
- Disable or unload optional virtual terminal functionality on servers that do not require interactive console access.
- Deploy seccomp or LSM policies that block the VT_DISALLOCATE ioctl for untrusted processes.
# Restrict /dev/vcs* access via udev rule
# /etc/udev/rules.d/90-vcs-restrict.rules
KERNEL=="vcs*", MODE="0600", OWNER="root", GROUP="root"
KERNEL=="vcsa*", MODE="0600", OWNER="root", GROUP="root"
# Reload udev rules and apply
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=vc
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

