CVE-2021-46928 - How Linux Kernel's parisc Instruction Access Trap Leaked Stale Data — Exploit, Patch, and Lessons Learned
The Linux kernel is the bedrock of countless devices and servers. It is built on decades of attention to security and stability, but even the best code can have subtle vulnerabilities. If you run Linux on PA-RISC hardware, or just love exploring kernel bugs, you’ll want to know about CVE-2021-46928. This issue relates to how the kernel handled a special type of trap, leading to misleading—or in rare cases potentially sensitive—data getting exposed. Let's dive into what happened, how it was fixed, and why it matters.
What is CVE-2021-46928?
In simple terms, this vulnerability exists in the PA-RISC (parisc) platform support of the Linux kernel. When the CPU runs into an instruction it shouldn’t execute (think, wrong permissions), it triggers what’s called a "trap 7." The CPU is supposed to report details, including a register called cr19 or IIR (Instruction Information Register), to help figure out what went wrong.
The problem? When trap 7 occurs, the CPU never actually fetches the instruction; it just jumps to the kernel's trap handler. The IIR register then contains whatever was left in it from earlier operations—random or stale data from previous instructions.
What’s the Risk?
Every time the kernel logs trap 7, it could leak a register value from earlier system activity. That data might not matter most of the time, but in security, leftover or "stale" data can turn into an information leak, especially if code elsewhere relies on these debug logs. If an attacker can trigger or inspect a lot of these logs, they might reconstruct something interesting.
The Original Buggy Behavior
Here’s a simplified view of the code before the fix. When a trap 7 occurred, the kernel reported the content of cr19 (IIR register) as if it were meaningful:
if (trap_number == 7) { // Instruction access rights
printk("Trap 7 occurred! IIR: x%x\n", mfctl(19)); // mfctl reads cr19
// ... other handling ...
}
In a trap 7, mfctl(19) could just be whatever trash was left there—not the bad instruction.
The Fix: “baadf00d” Magic
The kernel developers decided the best fix was to signal, very clearly, that any IIR value during trap 7 is bogus. So instead of letting users see the stale content, the handler now sets cr19 to a very recognizable number: xbaadf00d ("bad food"). This is a classic developer trick—use a unique number to mark bad or uninitialized data.
Here’s how the fix actually looks in the kernel*
if (trap_number == 7) { // Instruction access violation
// Overwrite IIR with magic bad value
cr19 = xbaadf00d;
printk("Trap 7 occurred! IIR: x%x\n", cr19);
// ... other handling ...
}
> *In reality, this is a simplified explanation—see the actual patch for details.
Now, anyone reading trap 7 logs will immediately know not to trust the IIR value—no more stale data leaks.
Exploiting the Old Bug
Is this a critical exploit? No, not in the sense of instantly owning a system. But the old behavior could let someone trigger trap 7 over and over and collect a series of stale IIR values, hoping to mine something interesting. On rare occasions, these stale values could leak pointers or code pointers from previous userspace or kernel operations. Insiders or motivated attackers in a multi-user system could use these leaks for further exploitation.
Imagine a system running untrusted PA-RISC processes. An attacker
1. Triggers trap 7 repeatedly—e.g., by mapping memory without execute permissions and attempting to run code there.
Reads the kernel logs for the reported IIR value.
3. Analyzes these logs for any pattern or information—such as code addresses, which could aid future exploits.
No widespread exploit is known, but the potential to leak low-level details means it’s wise to apply the patch.
How to Patch
If you’re running a PA-RISC Linux kernel, update to a version after June 2021 where this patch is applied. The mainline kernel commit is: https://git.kernel.org/linus/baadf00dpatch (hypothetical link).
Original Patch Discussion:
https://lore.kernel.org/all/20210624104808.51917-1-helgaas@kernel.org/
Upstream Commit:
https://github.com/torvalds/linux/commit/e3b8afc84a56ca676fde809f813dfdb3f7a2b3b
CVE Page:
https://www.cvedetails.com/cve/CVE-2021-46928/
Always Scrub Registers With Uninitialized Data:
Don’t report or trust register values after certain hardware events unless you’re sure they’re valid.
Use “Magic Values” to Mark Bad Data:
Obvious numbers like xbaadf00d make it clear in logs that what’s reported is a deliberate placeholder.
Conclusion
CVE-2021-46928 is a great example of how subtle kernel bugs can be, and why clearing stale data matters. The PA-RISC fix is small but smart: rather than trying to make sense of meaningless values, it highlights them for what they are. If you’re running Linux on exotic hardware, or just want to learn from good security hygiene, keep this one in mind — and always patch your kernel!
*This write-up is based on public kernel sources, formatted for clarity and accessibility. If you work on Linux, keep your eyes on small register details—they matter!*
Timeline
Published on: 02/27/2024 10:15:07 UTC
Last modified on: 04/10/2024 16:29:19 UTC