Published: June 2024
Severity: Low to Medium
Affected Component: Linux kernel (Qualcomm GCC-IPQ6018 Clock Driver)
CVSS (Estimated): 4.4 (Medium)
Introduction
A new Linux kernel vulnerability, CVE-2024-26970, was recently resolved. It affects the Qualcomm Global Clock Controller (GCC) driver for IPQ6018 SoCs. This issue could lead to out-of-bounds memory access whenever certain frequency arrays are walked. In this article, we explain what this bug is, why it happened, how it was fixed, and how an attacker might exploit it. We'll also show you the actual code fix and reference all the important sources.
What is CVE-2024-26970?
In the Linux kernel, the clock framework is crucial for managing CPU and bus frequencies, especially on embedded hardware like the Qualcomm IPQ6018 series. This vulnerability was found in drivers/clk/qcom/gcc-ipq6018.c: the frequency table arrays defined for certain clocks were not properly terminated with an empty (all-zero) entry.
Failing to add this empty element could cause kernel code traversing these arrays (such as the qcom_find_freq() or qcom_find_freq_floor() functions) to read past the end of the array, resulting in an out-of-bounds memory access. In worst cases, this could lead to a kernel panic or, theoretically, provide an attacker with unwanted reads or writes in memory.
Why Do Terminating Entries Matter in C Code?
In the Linux kernel's Qualcomm clock code, frequency table arrays don't store their own length. Instead, they’re “null-terminated” with a zeroed-out struct entry (much like how strings use \ as the end). Here’s a simplified version:
static struct freq_tbl freq_table[] = {
{ 100000000, P_XO, 1, 2 },
{ 200000000, P_PLL, 1, 1 },
{ }
};
That { } at the end is the *terminator*.
Without this, a function that loops to the end would just keep reading whatever is after the array—possibly garbage memory, or even unrelated data.
Vulnerable code
static const struct freq_tbl ftbl_gcc_video_axi_clk_src[] = {
F(19200000, P_XO, 1, 1, 1),
F(125000000, P_GPLL_OUT_MAIN, 2, 1, 8),
// Missing terminating entry!
};
When a function like qcom_find_freq() walks the table (looping until zero), it could read *past the end*, causing undefined kernel behavior.
Traversing Function Example
for (int i = ; freq_tbl[i].freq != ; i++) {
// Process freq_tbl[i]
}
If no { } terminator exists, it never finds the freq == condition; it could run into unrelated (and potentially sensitive) data!
Patched code
static const struct freq_tbl ftbl_gcc_video_axi_clk_src[] = {
F(19200000, P_XO, 1, 1, 1),
F(125000000, P_GPLL_OUT_MAIN, 2, 1, 8),
{ } // Add empty terminator entry here
};
Commit message excerpt:
> The frequency table arrays are supposed to be terminated with an empty element. Add such entry to the end of the arrays where it is missing in order to avoid possible out-of-bound access when the table is traversed by functions like qcom_find_freq() or qcom_find_freq_floor().
Patch link:
- LKML Patch: clk: qcom: gcc-ipq6018: fix terminating of frequency table arrays
Exploitation Details
While this is not a straightforward remote code execution bug, it can result in a kernel crash (DoS) or, with significant work and very controlled circumstances, possible info leaks—since uninitialized data can be read from memory following a frequency table.
How an attacker might exploit
- Local privilege escalation: If a user can trigger the affected clock routines with custom frequency requests (typically not directly exposed to userspace, but sometimes through device drivers), they could try to crash the kernel.
- Stability impact: An unprivileged user could intentionally misconfigure devices, leading to kernel panics, which is enough to cause disruption on shared environments.
Here’s an example C snippet showing the danger of missing terminators
#include <stdio.h>
struct freq_tbl { unsigned int freq; };
// Simulated non-terminated table
struct freq_tbl tbl[] = {{100}, {200}};
void walk_tbl(struct freq_tbl *t) {
for (int i = ; t[i].freq != ; i++) {
printf("Freq: %u\n", t[i].freq);
}
}
int main() {
walk_tbl(tbl); // May read off end, printing garbage or segfaulting
return ;
}
Run this: you might see extra junk printed, or even a crash, depending on what follows tbl in memory!
Mitigation
- Update Kernel: Apply patches from your vendor or switch to a kernel version with this commit included (mainline 6.9+).
- Backport patch: If you maintain a custom kernel tree, manually add the curly-brace terminators to the affected arrays.
Additional References
- Linux Kernel Patch (git.kernel.org)
- LKML Discussion Thread
- Qualcomm clk Documentation
Conclusion
CVE-2024-26970 shows how a simple coding mistake like missing a terminating entry in a C array can have real stability and security implications in low-level software like the Linux kernel. While not the most critical bug, it’s a great example of secure coding principles in practice. Anyone running embedded Linux, especially on Qualcomm IPQ6018 hardware, should update as soon as they can.
Questions? Corrections? Comment below.
*This post was written just for you—please credit [author] if referencing elsewhere!*
Timeline
Published on: 05/01/2024 06:15:13 UTC
Last modified on: 07/03/2024 01:50:09 UTC