CVE-2024-42158 - Linux Kernel s390/pkey Information Leak Resolved — Vulnerability Deep Dive and Exploit Possibility
In June 2024, a security vulnerability was found and patched in the Linux kernel component specific to IBM System z (s390) hardware, specifically the s390/pkey (protected keys) subsystem. Let's break down what happened, why it matters, and what potential exploit avenues existed before the fix.
What is CVE-2024-42158?
The vulnerability (CVE-2024-42158) centers on improper handling of sensitive memory related to protected cryptographic keys in the Linux kernel for s390/pkey. The issue is not an outright bug leading to privilege escalation or remote code execution by itself, but rather an information leak: certain cleanup code did not securely erase secrets from memory before freeing them, giving a theoretical attacker a narrow window to recover cryptographic material.
How Was It Detected?
The problem was flagged by Coccinelle, a static analysis tool that detects potential code improvements and security weaknesses in the Linux kernel source. Coccinelle noticed that the kernel only ran memzero_explicit() (to blank memory) and then kfree() (to free memory), instead of just calling kfree_sensitive() which does both.
Example warnings
WARNING opportunity for kfree_sensitive/kvfree_sensitive (line 1506)
WARNING opportunity for kfree_sensitive/kvfree_sensitive (line 1643)
WARNING opportunity for kfree_sensitive/kvfree_sensitive (line 177)
Prior code
memzero_explicit(ptr, size);
kfree(ptr);
Fixed code
kfree_sensitive(ptr, size);
kfree_sensitive() is a kernel helper that securely wipes the memory (using memory barriers to prevent compiler bugs) and then frees it, preventing sensitive information from lingering in RAM after an object is deallocated.
Why Does It Matter?
If you only use memzero_explicit() followed by kfree(), and for some reason the compiler optimizes away your zeroing or an error occurs in order, you risk sensitive data (like cryptographic keys or plaintext secrets) remaining readable in RAM after the pointer is freed. An attacker with direct memory access, such as through a kernel module bug, /dev/mem access, or local privilege escalation techniques, could recover these secrets.
Exploit Scenario (Theoretical Example)
Let’s make this real with a simple (synthetic) exploit example that could have been feasible without the fix.
Step 1: Trigger Key Deletion
Suppose an unprivileged process requests deletion of a cryptographic key, which in the vulnerable kernel does:
memzero_explicit(key_ptr, KEY_SIZE);
kfree(key_ptr);
But, due to compiler or hardware optimizations, the memory is not always cleaned.
Step 2: Race to Reallocate
Attacker sprays the heap with objects immediately after, trying to cause their own object to be allocated where the key used to be.
char *buffer = malloc(KEY_SIZE);
// This buffer might now contain the old key!
Step 3: Read Uninitialized Memory
If Linux did not initialize buffer, attacker could read residual data.
printf("Potential key: %s\n", buffer);
If lucky, the kernel heap would now leak cryptographic material. While direct exploitation is hard, privilege escalation or forensic recovery could expose secrets.
PoC: Simulated Kernel Memory Leak
While a real kernel exploit is complex, here’s a userspace "analogy" illustrating why secure free is essential:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *key = malloc(32);
strcpy(key, "super_secret_crypto_key");
free(key); // Just frees, does not zero memory.
// Simulate kernel allocating same area again.
char *leaked = malloc(32);
printf("Possibly leaked key: %s\n", leaked); // Oops — "super_secret_crypto_key" may print!
free(leaked);
return ;
}
If you change free() to first zero the memory, you fix the leak. That’s what kfree_sensitive() does in the kernel.
References
- Linux Kernel Patch discussion for CVE-2024-42158
- Coccinelle documentation
- manpage for kfree_sensitive()
Upstream commit:
commit a4b417d0306ec Linux s390/pkey: Use kfree_sensitive()
How Was It Fixed?
Patch author replaced all instances where memory containing secrets was erased and freed, with a single call for kfree_sensitive()—simpler, safer, impossible to screw up.
Old code
memzero_explicit(pkey_struct, sizeof(*pkey_struct));
kfree(pkey_struct);
New code
kfree_sensitive(pkey_struct, sizeof(*pkey_struct));
Any kernel without the patched commit.
Fix: Update to a kernel with the patch applied, or backport the kfree_sensitive() improvement to your kernel version.
Takeaway: Use Secure Free for Secrets
Information leaks are subtle but dangerous. Always use the most robust cleanup primitives (kfree_sensitive(), memset_s(), etc.) whenever secrets live in RAM, especially in privileged code like the kernel.
Timeline
Published on: 07/30/2024 08:15:07 UTC
Last modified on: 08/02/2024 14:31:04 UTC