
Seccomp-based mitigation for CVE-2026-31431, a Linux kernel LPE. Blocks AF_ALG socket via PAM module and standalone wrapper, with auto-detection of patched kernels.
A lightweight, reversible seccomp-based mitigation for CVE-2026-31431, a local privilege escalation vulnerability in the Linux kernel's algif_aead / authencesn crypto subsystem.
Type: Local Privilege Escalation (LPE)
Affected Component: Linux kernel crypto/algif_aead.c - in-place AEAD operation
Attack Primitive: A 4-byte controllable write into any readable file's page cache via the authencesn AEAD algorithm's scratch-write path. By targeting /etc/passwd, an attacker can change their UID to 0 (root) and obtain a root shell via su.
Affected Kernels: Confirmed on kernel 6.12+, 6.17+, 6.18+, and also reproduced on RHEL/CentOS 4.18/5.14 kernels.
Verified Environments: Rocky Linux 8 (kernel 4.18) and Rocky Linux 9 (kernel 5.14) - exploit fully blocked, safe removal confirmed.
Root Cause: Commit 72548b093ee3 introduced in-place AEAD operation. When spliced page-cache pages are used as the destination scatterlist, the AAD seqno_lo field is incorrectly written back into the page-cache during AEAD decrypt.
Upstream Fix: Revert to out-of-place AEAD operation.
This solution has two components:
PAM Module (pam_block_afalg.so) - The primary defense. Loaded by PAM during session open (pam_sm_open_session), it applies a seccomp BPF filter that blocks socket(AF_ALG, ...) before any user code runs. This covers ALL PAM-authenticated sessions: su -c, su -, SSH, TTY login, etc.
Standalone binary (block_afalg) - Optional. Can wrap specific programs for non-PAM scenarios (e.g., cron jobs, systemd services, manual invocation).
The seccomp filter:
socket(AF_ALG, ...) (returns EACCES)setuid, su, sudo)PAM session open (su, ssh, login, etc.)
|
v
pam_block_afalg.so (pam_sm_open_session)
|
+-- Check: is kernel vulnerable? (try socket(AF_ALG))
| |
| +-- No --> return PAM_SUCCESS (no-op)
| |
| +-- Yes --> prctl(PR_SET_SECCOMP, BPF filter)
| |
| +-- seccomp filter active on sshd child process
| +-- inherited by user's shell and ALL child processes
| +-- socket(AF_ALG, ...) returns EACCES
v
User's shell / command runs with seccomp protection
|
+-- su, sudo, and all other syscalls work normally
+-- Only AF_ALG socket is blocked
| File | Purpose |
|---|---|
pam_block_afalg.c | PAM module source. Applies seccomp filter at session open. |
gcc (for compilation)libpam (runtime, usually pre-installed)# 1. Compile PAM module
gcc -Wall -O2 -fPIC -shared -o pam_block_afalg.so pam_block_afalg.c \
/usr/lib64/libpam.so.0
# 2. Install (auto-adds PAM configs to su, sshd, login)
sudo ./deploy.sh install
# 3. Verify (must be a NEW session)
cat /proc/self/status | grep Seccomp
# Should show: Seccomp: 2
python3 -c "
import socket
try:
s = socket.socket(38,2,0); s.close()
print('VULNERABLE')
except OSError:
print('BLOCKED')
"
# Should show: BLOCKED
# 4. Uninstall
sudo ./deploy.sh remove
| Command | Description |
|---|---|
deploy.sh install | Compile PAM module, install to /lib64/security/, auto-add PAM configs |
deploy.sh remove | Full uninstall: remove module, clean PAM configs, delete files |
deploy.sh status |
For non-PAM scenarios, use block_afalg directly:
# Compile
gcc -Wall -O2 -o block_afalg block_afalg.c
# Run a command with AF_ALG blocked
./block_afalg python3 your_script.py
./block_afalg bash
python3 -c "
import socket
try:
s = socket.socket(38, socket.SOCK_SEQPACKET, 0)
s.close()
print('VULNERABLE: AF_ALG socket available')
except:
print('SAFE: AF_ALG socket blocked or unavailable')
"
# Check seccomp status
cat /proc/self/status | grep Seccomp
# Seccomp: 0 = not protected
# Seccomp: 2 = protected
# Test AF_ALG socket
python3 -c "
import socket
try:
s = socket.socket(38,2,0)
s.close()
print('AF_ALG available - NOT protected')
except OSError:
print('AF_ALG blocked - PROTECTED')
"
# Check PAM logs
grep pam_block_afalg /var/log/secure
# Should show: seccomp filter applied, AF_ALG blocked
__NR_socket on x86_64). Other architectures need the syscall number updated.exec() calls without PAM are not covered (use block_afalg for those).remove.yum update kernel then remove the module.This tool is provided for authorized security testing and defensive purposes only. Use only on systems you own or are explicitly authorized to assess.
pam_minimal.h | Minimal PAM type definitions (compiles without pam-devel). |
block_afalg.c | Standalone seccomp wrapper binary. For non-PAM use. |
deploy.sh | Deployment script. Compiles, installs, and manages the PAM module. |
| Show installation state, PAM configs, kernel status |