CVE-2021-46990 is a vulnerability found in certain versions of the Linux kernel with PowerPC (64-bit, "64s") architecture. This bug involves the "entry flush" barrier, a mitigation designed to defend against side channel attacks like Spectre. The issue results in potential kernel crashes when enabling or disabling the entry flush at runtime. We'll break down exactly what happened, why it's dangerous, and how it was fixed—using real code snippets and a clear example. If you're maintaining Linux on PowerPC hardware, this is for you.

The entry flush mitigation can be toggled at runtime with a debugfs file

# You could enable/disable it like this:
echo 1 > /sys/kernel/debug/powerpc/entry_flush

Changing this setting causes the kernel to patch certain parts of its code _live_ (runtime patching, called "self-patching") to enable or disable mitigation.

But here's the catch:
On PowerPC/64s, depending on which mitigation is active, this patching IS NOT SAFE while other CPUs are active. If one CPU is in the middle of changing the code while another is running that same area, the second CPU could execute _incomplete_ or _broken_ code, leading to nasty problems like this:

sleeper[15639]: segfault (11) at c000000000004c20 nip c000000000004c20 lr c000000000004c20

This log shows a user-space return with a "corrupted" link register (LR)—a special register on PowerPC that remembers where to jump back after a function call—now pointing into the kernel code. This happens because a patch was done in the middle of execution: the CPU hit a transition point in the code where crucial instructions (like restoring the LR) were temporarily missing or broken due to incomplete patching.

What is the "Entry Flush"?

It's a defensive instruction sequence the kernel inserts or removes to block certain attacks (like Spectre V2) at user-kernel boundaries—specifically, when jumping from userspace into the kernel.

Why Not Just Patch Normally?

Normally, live patching in Linux is performed carefully, but on PowerPC/64s the situation is delicate because _the same code may be currently executing on another CPU_. If you patch one instruction at a time, it's possible for another CPU to fetch and execute code halfway patched (some instructions old, some new).

CPU B starts patching this code.

3. CPU A resumes, but the code has changed partway—registers or logic may not be restored, instructions may not complete, and the system crashes.

Before

// Code patching happened directly...
do_patch(entry_flush_enabled);
// Other CPUs might still be running this code!

After

// Fix: Patch code while all other CPUs are paused
stop_machine(do_patch, entry_flush_enabled, NULL);

stop_machine is a Linux internal function that *pauses* all CPUs except one. The remaining CPU safely patches the code; other CPUs are spinning in a safe "waiting room" and not running the code being changed.

The Patch: Official Commit

Here's an excerpt from the official commit:

+static void patch_entry_flush_stopped(void *info)
+{
+	patch_entry_flush();
+}
+... 
+	/* Use stop_machine to prevent concurrent execution */
+	stop_machine(patch_entry_flush_stopped, NULL, NULL);

Now the patching process is atomic and safe—no other CPU can execute the dangerous code while patching occurs.

Is This Bug Exploitable?

- Local Denial-of-Service: Yes. A regular unprivileged user could toggle the entry_flush, causing kernel patching. If timed perfectly (or with scripting), this could crash the whole system via a kernel panic or segfault, as the live patching temporarily corrupts execution flow.
- Privilege Escalation: Unlikely out-of-the-box, but a skilled attacker could perhaps leverage the crash for info leaks or further exploitation, depending on kernel protections.
- Security Context: You need access to toggle /sys/kernel/debug/…, which usually requires root or debug privileges, *unless* permissions are too loose (misconfigured systems).

If you have access

# WARNING: This may CRASH your system!

for i in {1..500}; do
  echo  > /sys/kernel/debug/powerpc/entry_flush
  echo 1 > /sys/kernel/debug/powerpc/entry_flush
done
# Now run processes on multiple CPUs and watch for segfaults / panics!

On vulnerable kernels, this may cause random weird crashes, including root-owned or critical processes.

How To Stay Safe

1. Patch! Upgrade to a kernel with this commit.
2. Restrict Debugfs: Ensure untrusted users can't write to /sys/kernel/debug/….
3. Monitor: If you see strange crashes around entry points (with corrupted LR/nip), investigate kernel patching events.

References

- Linux Kernel Commit Fix
- Linux Patch Mailing List Discussion
- Linux Kernel Source: stop_machine()
- CVE Details: CVE-2021-46990

Conclusion

CVE-2021-46990 demonstrates the dangers of runtime kernel patching, especially on multi-core hardware. While the bug mainly causes crashes and is best exploited as a denial-of-service, any opportunity for code corruption in the kernel is a major risk.

If you're running PowerPC/64s Linux systems, update as soon as possible, and never allow untrusted access to kernel debug interfaces. This bug is a clear example of why kernel self-modification is so tricky—and why proper CPU coordination is essential.

Timeline

Published on: 02/28/2024 09:15:37 UTC
Last modified on: 12/24/2024 14:30:57 UTC