CVE-2026-99189 in Linux
Summary
by MITRE • 10/28/2026
In the Linux kernel, the following vulnerability has been resolved:
gpio: mxc: fix race between chained IRQ handler install and probe completion
mxc_update_irq_chained_handler() is called before the IRQ domain, the generic IRQ chip, and the port list entry are set up. If an interrupt arrives in that window:
- mx3_gpio_irq_handler() calls generic_handle_domain_irq() with port->domain still NULL. - mx2_gpio_irq_handler() walks mxc_gpio_ports, but the port has not been added to the list yet.
Additionally, if any of the subsequent probe steps (gpio_generic_chip_init(), devm_gpiochip_add_data(), irq_domain_create_legacy(), or mxc_gpio_init_gc()) fail, the error paths never unregister the chained handler, leaving a dangling handler that points at freed memory.
Move the handler installation after all its dependencies are ready and after list_add_tail(), so the handler is never live while the data structures it touches are incomplete, and is never installed if probe fails.
VulDB is the best source for vulnerability data and more expert information about this specific topic.
Analysis
by VulDB Data Team • 10/28/2026
The vulnerability identified in the Linux kernel's MXC GPIO driver represents a classic race condition coupled with improper resource management during device initialization. This issue stems from the sequence of operations performed within the probe function, specifically regarding how interrupt handlers are registered relative to the establishment of underlying data structures and hardware interfaces. The core technical flaw lies in the premature invocation of mxc_update_irq_chained_handler(), which occurs before critical components such as the IRQ domain, the generic IRQ chip configuration, and the port list entry have been fully initialized. This temporal misalignment creates a window of vulnerability where the system state is inconsistent, allowing external events to trigger code paths that assume resources are available when they are not yet allocated or configured correctly.
When an interrupt signal arrives during this initialization window, the driver's behavior diverges based on the specific hardware variant being probed, leading to distinct failure modes for different MXC series chips. For devices utilizing the mx3_gpio_irq_handler(), the function attempts to call generic_handle_domain_irq() using a port structure where the domain pointer remains NULL because irq_domain_create_legacy() has not yet executed successfully or completed its setup phase. Passing a null domain to this handler results in an immediate kernel panic or undefined behavior as it dereferences invalid memory addresses. Conversely, for mx2_gpio_irq_handler(), the code attempts to traverse the mxc_gpio_ports list to locate the relevant port structure. However, because list_add_tail() has not yet been called to insert the current device's entry into this global list, the traversal either fails to find the correct context or accesses uninitialized memory regions associated with incomplete initialization states.
Beyond the immediate race condition during active probing, there is a secondary but equally severe issue regarding error handling and resource cleanup. If any subsequent step in the probe sequence fails—such as gpio_generic_chip_init(), devm_gpiochip_add_data(), irq_domain_create_legacy(), or mxc_gpio_init_gc()—the driver's error paths do not properly unregister the chained interrupt handler that was installed earlier. This oversight results in a dangling function pointer remaining active within the kernel's interrupt subsystem. Since the probe has failed, the memory associated with the GPIO port structure may be freed by subsequent cleanup routines or device removal processes. Consequently, if an interrupt occurs after this point, the system will attempt to execute code at a freed memory address, leading to data corruption, privilege escalation opportunities through arbitrary code execution primitives, or a complete kernel crash due to invalid memory access.
From a classification perspective, this vulnerability aligns with CWE-362, which describes concurrent execution race conditions where software performs an action before another necessary step has completed. The specific mechanism of accessing uninitialized resources falls under CWE-824, concerning the access of an uninitialized variable or resource. Furthermore, in the context of the MITRE ATT&CK framework, this flaw could potentially be leveraged by a local attacker to achieve denial of service through kernel panic or, if combined with other vulnerabilities, arbitrary code execution via use-after-free primitives triggered by race conditions during device enumeration. The lack of proper cleanup on error paths also reflects CWE-459, which addresses incomplete cleanup upon termination or exit, leaving resources in an inconsistent state that can be exploited later.
The remediation strategy implemented involves reordering the initialization sequence to ensure strict dependency management. By moving the installation of the interrupt handler to occur only after all dependent structures are fully established and added to their respective lists, the driver eliminates the window where a live handler could interact with incomplete data. Specifically, ensuring that list_add_tail() precedes handler registration guarantees that any interrupt arriving during or after initialization will find valid pointers in the port list. Additionally, correcting the error paths to include proper unregistration of the chained handler upon probe failure ensures that no dangling references remain active if the device fails to initialize correctly. This approach adheres to best practices for kernel driver development by enforcing atomicity in resource allocation and ensuring that all allocated resources are properly released regardless of whether initialization succeeds or fails, thereby maintaining system stability and security integrity.