CVE-2026-99222 in Linux
Summary
by MITRE • 11/02/2026
In the Linux kernel, the following vulnerability has been resolved:
keys: Protect the read method check against type removal
keyctl_read_key() checks key->type->read without holding key->sem. A reference keeps the key alive, but does not pin the module containing its type. A surviving RxRPC key can therefore be read while AF_RXRPC is being unloaded:
KEYCTL_READ task Module unload and key GC ---------------- ------------------------ lookup_user_key() permission / possession checks load key->type af_rxrpc_exit() unregister_key_type() GC: down_write(key->sem) GC: retype to key_type_dead GC: up_write(key->sem) unregister_key_type() returns free_module() read saved type's read member
The final access can read freed module storage. The read invocation in __keyctl_read_key() is already protected by key->sem, but the earlier method check is outside that critical section.
Move the method check into __keyctl_read_key(), after key_validate() and under its existing read hold on key->sem. The check and invocation then use the same protected type for length queries and every read retry. The GC cannot retype the key until the semaphore is released, and type unregistration waits for that GC pass before the module can be freed.
Return -EOPNOTSUPP when validation succeeds and the type has no read method. A temporary buffer may now be allocated before this result; allocation and copying to userspace remain outside the semaphore.
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.
Analysis
by VulDB Data Team • 11/02/2026
The Linux kernel key management subsystem contains a race condition vulnerability within the keyctl_read_key function that allows for use-after-free access when reading keys associated with modules undergoing unloading. This flaw stems from an insufficient synchronization mechanism protecting the verification of whether a specific read method exists on a key type before attempting to invoke it. While the actual invocation of the read operation is protected by the key semaphore, the preliminary check determining if the read pointer is valid occurs outside this critical section. Consequently, there exists a narrow time window where a user-space process can initiate a read request for a key while the kernel simultaneously unloads the module containing that key's type definition.
The operational mechanics of this vulnerability involve the interaction between reference counting and memory management during module teardown. A surviving RxRPC key maintains a reference count that keeps the key structure itself alive in memory, but it does not pin the underlying kernel module where the key_type struct resides. When the AF_RXRPC subsystem is being unloaded via af_rxrpc_exit(), it calls unregister_key_type(). This triggers garbage collection logic which acquires the write lock on the key semaphore to safely retype the key to a dead state before freeing associated resources. However, because the initial method check in lookup_user_key or related paths does not hold this semaphore, a concurrent read operation can proceed past its validation step after the module has been unloaded but before the garbage collection completes and frees the module memory.
This race condition results in a classic use-after-free scenario where the kernel attempts to dereference function pointers located within freed module storage space. The sequence begins with lookup_user_key performing permission checks, followed by loading the key type pointer. Simultaneously or subsequently, the garbage collector acquires the write lock on the key semaphore and changes the key's type to a dead state. Once the garbage collection releases the semaphore, unregister_key_type proceeds to free the module memory. If the read operation had already passed its initial check but not yet executed the actual read call under protection of the semaphore, it will attempt to access the now-freed memory region associated with the original key type's read method pointer. This leads to undefined behavior, potential kernel crashes, or arbitrary code execution if an attacker can control the contents of the freed memory through other means.
From a technical remediation perspective, the vulnerability is resolved by moving the validation check for the existence of the read method into __keyctl_read_key(), specifically after key_validate() and while holding the existing read lock on the key semaphore. This ensures that both the length query and any subsequent retry logic utilize the same protected type instance, preventing the garbage collector from retyping or freeing the module during the critical evaluation window. The fix also introduces a return value of -EOPNOTSUPP when validation succeeds but no read method is present, ensuring graceful handling rather than null pointer dereferences. Allocation and copying to user space remain outside the semaphore hold to minimize lock contention and maintain performance stability under high concurrency.
This vulnerability aligns with CWE-416, Use After Free, as it involves accessing memory that has been deallocated due to a race condition in synchronization primitives. It also relates to CWE-362, Concurrent Execution using Shared Resource with Improper Synchronization, specifically regarding the failure to properly serialize access to shared data structures during state transitions like module unloading and garbage collection. In terms of MITRE ATT&CK mapping, this flaw could be leveraged within T1059, Command and Scripting Interpreter, or potentially escalated for privilege escalation if combined with other vulnerabilities, as kernel memory corruption often serves as a precursor to gaining higher system privileges.
Mitigation strategies primarily involve applying the upstream Linux kernel patch that corrects the locking scope in keyctl_read_key. For systems unable to immediately update the kernel, administrators should monitor for unusual activity involving RxRPC keys and ensure that module unloading operations are coordinated with user-space interactions where possible. Regular security updates and adherence to vendor-supported lifecycle policies remain the most effective defense against such low-level concurrency bugs inherent in complex operating system kernels like Linux.