In early 2024, security researchers and kernel developers identified and patched a vulnerability in the Linux kernel core serial driver, now tracked as CVE-2024-26998. While the bug may sound like "just another kernel oops," it actually highlights the complexity of concurrent code in the kernel, where timing issues can lead to real system instability and, potentially, privilege escalation risks.
This post breaks down the issue in plain English, covers the technical details, and shows you the code and patch that closed the hole.
What is CVE-2024-26998?
CVE-2024-26998 is a NULL pointer dereference bug in the Linux kernel’s serial core subsystem, mainly affecting code paths that use Power Management (PM) or timer callbacks. When a serial port is being shut down, the buffer pointer is sometimes set to NULL before clearing related buffer state, leading to a situation where certain asynchronous routines (like PM or deferred timers) can still touch the now invalid buffer and cause a kernel crash.
Severity: While it's mostly a stability issue, depending on what triggers and timing, it may be possible to abuse this bug for Denial-of-Service, and more rarely for privilege escalation.
The Problem: Serial Buffer Shutdown Race Condition
A lot happens in the background when a Linux serial port is unregistered. The function uart_tty_port_shutdown() is responsible for cleaning things up, and among other things, it clears the circular buffer that holds incoming serial data.
Here’s the problem: the buffer pointer was being NULLified (i.e., set to NULL) before the data inside the buffer and related head/tail markers were reset. At the same time, other kernel routines—possibly running on a different CPU—might scan or work with the buffer, not checking fully if the buffer pointer is still valid, causing a possible NULL pointer dereference.
In practice, this crash was seen mostly on the "serial825" driver (which drives many common UARTs). The crash reports looked like this:
BUG: kernel NULL pointer dereference, address: 00000cf5
Workqueue: pm pm_runtime_work
EIP: serial825_tx_chars (drivers/tty/serial/825/825_port.c:1809)
...
? serial825_tx_chars (drivers/tty/serial/825/825_port.c:1809)
__start_tx (drivers/tty/serial/825/825_port.c:1551)
serial825_start_tx (drivers/tty/serial/825/825_port.c:1654)
serial_port_runtime_suspend (include/linux/serial_core.h:667 drivers/tty/serial/serial_port.c:63)
__rpm_callback (drivers/base/power/runtime.c:393)
? serial_port_remove (drivers/tty/serial/serial_port.c:50)
rpm_suspend (drivers/base/power/runtime.c:447)
Why Was This Dangerous?
- Async callbacks like those triggered by PM or timers, can still be invoked after buffer cleanup starts, leading to use-after-free or NULL pointer dereference.
- The serial codebase is inconsistent: some places check for NULL buffer, some just look at head/tail markers.
- This combination causes a window of vulnerability during shutdown, especially on busy or multi-core systems.
The Official Patch
Fix summary:
Both the buffer pointer AND the circular buffer’s head/tail positions are now reset together, under the proper lock, before the pointer is cleared. This ensures that if callbacks do fire, any code checking buffer emptiness via head/tail will see an empty buffer, and any code using the pointer will check if it’s NULL.
Here’s a simplified look at the patch (Source: Kernel Patch):
/* Before (problematic): */
spin_lock_irqsave(&port->lock, flags);
kfree(state->xmit.buf);
state->xmit.buf = NULL;
spin_unlock_irqrestore(&port->lock, flags);
/* After (secure): */
spin_lock_irqsave(&port->lock, flags);
/* Clear up head/tail and buffer data before nullifying pointer */
if (state->xmit.buf) {
state->xmit.head = state->xmit.tail = ;
memset(state->xmit.buf, , UART_XMIT_SIZE);
kfree(state->xmit.buf);
state->xmit.buf = NULL;
}
spin_unlock_irqrestore(&port->lock, flags);
What’s changed?
Exploit Details
This bug is primarily a stability issue, so you won’t find public exploits for it in the wild.
However, on affected kernels, a malicious process or user could trigger the crash by
- Repeatedly opening/closing serial ports with concurrent PM events (like suspending/resuming the system)
Example proof-of-concept (PoC) sequence
# WARNING: This may crash your system (kernel panic or oops)!
while true; do
stty -F /dev/ttyS 115200
sleep .01
echo test > /dev/ttyS
sleep .01
sudo systemctl suspend # or equivalent PM event trigger
done
*Note: The actual window for the crash is small — the race is nasty, but not easy to hit reliably.*
References
- Upstream Fix Commit
- CVE Record on Mitre
- Linux Serial Subsystem Docs
- Kernel Bugzilla report (if/when public)
Conclusion
CVE-2024-26998 is a classic example of how subtle locking and sequence issues in low-level kernel code can lead to system stability problems, even if they're not directly remote exploits. If you run Linux with serial port hardware, especially on laptops or embedded devices where suspend/resume is common, you should upgrade to the latest stable kernel.
Stay safe, keep your kernels updated, and always review code changes from trusted sources.
*Written for clarity and security education. If you find issues, please contribute patches to the Linux kernel community!*
Timeline
Published on: 05/01/2024 06:15:17 UTC
Last modified on: 12/23/2024 19:50:05 UTC