In 2021, developers caught a tricky bug in the Linux kernel, affecting Intel’s i915 Direct Rendering Manager (DRM) driver. This bug, now tracked as CVE-2021-46976, could cause the whole system to crash. Here’s a straightforward rundown of what went wrong, why it mattered, and how it was fixed, with code snippets and real kernel output logs.
What Was the Problem?
At the heart of the issue was how the i915 driver implemented its “retire” logic. To save a little memory, the code tried to stuff extra information (flags) into the bottom two bits of a function pointer—specifically, the pointer to the auto_retire function. But not every function in kernel code is properly aligned on a 4-byte boundary, which is necessary if you want to stash data in the last two bits. If a function pointer isn’t aligned, storing data like this can lead you to a wrong address when you try to call it—causing a kernel crash.
The C code tried to be clever like this
#define RETIRE_FLAGS x3 // lower 2 bits
void (*retire_func)(void *) = auto_retire;
// Use lower bits for metadata
unsigned long tagged_ptr = (unsigned long)retire_func | flags;
// Extract the pointer when needed
void (*real_retire_func)(void *) = (void *) (tagged_ptr & ~RETIRE_FLAGS);
// Call it (oops! might be misaligned)
real_retire_func(work_data);
If auto_retire happened to not be 4-byte aligned, masking and calling that pointer could jump to the wrong instruction—resulting in an invalid opcode and crash.
What Did It Look Like in the Wild?
On affected Linux systems (especially Chrome OS with recent Intel chips), people started seeing scary kernel crash logs like this:
WARNING kernel: [ 516.876914] RIP: 001:auto_retire+x1/x20
WARNING kernel: [ 516.876916] Code: ... <1f> 44 00 00 55 ...
WARNING kernel: [ 516.876930] PKRU: 55555554
WARNING kernel: [ 516.876931] Call Trace:
WARNING kernel: [ 516.876935] __active_retire+x77/xcf
WARNING kernel: [ 516.876939] process_one_work+x1da/x394
WARNING kernel: [ 516.876941] worker_thread+x216/x375
WARNING kernel: [ 516.876944] kthread+x147/x156
WARNING kernel: [ 516.876950] ret_from_fork+x1f/x40
In plain English: the kernel tried to call the auto_retire function, but thanks to those mangled pointer bits, it jumped into garbage code and crashed.
CVE-2021-46976 is entered as
> In the Linux kernel through 5.12.2, when using two lower bits of a function pointer for custom flags in i915’s retire logic, misaligned function pointers could cause control flow to jump to the wrong code location, leading to crash (invalid opcode execution).
- Component: Linux kernel, DRM/i915 module
- Impact: Immediate kernel panic/HW crash (Local denial of service)
- Root Cause: Not all function pointers in the kernel are guaranteed to be word-aligned. Masking pointer bits and jumping to them is risky.
Original Patch and Fix
How did they fix it?
The developers changed the logic so it stopped using the least significant bits of the function pointer for metadata. Instead, they used other means to pass that information—either dedicated fields or safer methods.
Patch Example
- void (*retire_func)(void *) = auto_retire;
- unsigned long tagged_ptr = (unsigned long)retire_func | flags;
- ...
- void (*real_retire_func)(void *) = (void *) (tagged_ptr & ~RETIRE_FLAGS);
- real_retire_func(work_data);
+ // Use a separate field for flags, don't store them in pointer bits!
+ work->retire_func = auto_retire;
+ work->flags = flags;
You can see the official patch here in the kernel git tree.
Proof-of-Concept: Can You Exploit It?
This bug doesn't allow for privilege escalation or code execution, but you CAN crash your machine. If you can trigger an operation that causes the auto_retire function to be called (for instance, by using certain 3D applications, GPU stress test tools, or custom workloads crafted to clean up GPU objects under certain timing), you can cause a kernel panic.
There’s no user-level code needed; just running the right (or wrong!) graphics workloads can hit this bug on a vulnerable kernel.
Mitigation and Detection
Are you vulnerable?
How to check if you have the fix
# Run this as root to see your current kernel version
uname -r
# Check dmesg output for "auto_retire" crashes
dmesg | grep auto_retire
Upgrade your kernel if you see suspicious results or if your version is known to be affected.
References & More Info
- Kernel Patch Commit
- Red Hat Bugzilla report #1957366
- CVE-2021-46976 at NVD
- LKML Discussion: drm/i915: Fix crash in auto_retire
Summary
CVE-2021-46976 is a great example of how a small detail—like assuming pointer alignment—can result in a serious system crash. No exploit is needed: just the right system activity and *boom*—your Linux box is down for the count.
Lesson for developers: Never assume memory layout tricks are safe across all hardware/platforms, especially in system code!
*Exclusive writeup by [yourfriendlykernelhacker], June 2024. If you found this useful, share and patch your systems!*
Timeline
Published on: 02/28/2024 09:15:37 UTC
Last modified on: 01/10/2025 18:21:14 UTC