## https://sploitus.com/exploit?id=A5EC936E-7FE0-56D9-9D7A-997CF9440079
# CVE-2026-31431 Seccomp Mitigation
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. Uses a **PAM module** to apply seccomp filters at session open time, covering ALL session types: `su`, `ssh`, `login`, and more. ---
# CVE-2026-31431 Seccomp Mitigation Solution
A lightweight, reversible seccomp-based mitigation for CVE-2026-31431. This vulnerability is a local privilege escalation issue in the Linux kernel’s `algif_aead` / `authencesn` crypto subsystem. The mitigation employs a **PAM module** to apply seccomp filters during session creation, covering all session types: `su`, `ssh`, `login`, etc. ---
## Vulnerability Overview / Vulnerability Description
### Type: Local Privilege Escalation (LPE)
### Affected Component: Linux kernel `crypto/algif_aead.c` – in-place AEAD operation
### Attack Principle: A 4-byte controllable write can be made to any readable file’s page cache via the `authencesn` AEAD algorithm’s scratch-write path. By targeting `/etc/passwd`, an attacker can change the UID to 0 (root) and gain a root shell via `su`. **Affected Kernels:** Confirmed on kernels 6.12+, 6.17+, 6.18+, and also reproduced on RHEL/CentOS 4.18 kernels. **Root Cause:** The commit `72548b093ee3` introduced an 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 decryption. **Upstream Fix:** Reverted to an out-of-place AEAD operation. ###
### Type: Local Privilege Escalation (LPE)
### Affected Component: Linux kernel `crypto/algif_aead.c` – in-place AEAD operation
### Attack Principle: A 4-byte controllable write can be made to the page cache of any readable file via the `authencesn` AEAD algorithm’s scratch-write path. By targeting `/etc/passwd`, an attacker can change the UID to 0 (root) and gain a root shell via `su`. **Affected Kernels:** Confirmed on kernels 6.12+, 6.17+, 6.18+, and also reproduced on RHEL/CentOS 4.18 kernels. **Root Cause:** The commit `72548b093ee3` introduced an 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 decryption. **Upstream Fix:** Reverted to an out-of-place AEAD operation. ###
## How This Mitigation Works / How the Mitigation Works
This solution consists of **two components**:
1. **PAM Module (`pam_block_afalg.so`)** – The primary defense. It is loaded by PAM during session opening (`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. 2. **Standalone Binary (`block_afalg`)** – Optional. It can be used for specific programs in non-PAM scenarios (e.g., cron jobs, systemd services, manual invocations). The seccomp filter:
- Blocks only `socket(AF_ALG,...)` (returning EACCES)
- Has zero impact on all other system calls (including `setuid`, `su`, `sudo`)
- Is inherited by all child processes (fork + exec)
- Automatically detects patched kernels and acts as a no-op. ###
## Architecture / Architecture
```
PAM session opening (su, ssh, login, etc.)
|
v
pam_block_afalg.so (pam_sm_open_session)
|
+-- Check: Is the 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
```
## Files /
| File | Purpose |
|------|---------|
| `pam_block_afalg.c` | PAM module source. Applies seccomp filter at session open. |
| `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. |
| `README.md` | This file. |
## Requirements /
- Linux kernel with seccomp support (most modern kernels)
- `gcc` (for compilation)
- `libpam` (runtime, usually pre-installed)
- Root/sudo access (for installation)
- x86_64 architecture (BPF filter uses x86_64 syscall numbers)
## Quick Start /
```bash
# 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
sudo cp pam_block_afalg.so /lib64/security/
sudo chmod 755 /lib64/security/pam_block_afalg.so
# 3. Activate - APPEND to PAM configs (important: use >>, not sed -i '1i')
echo 'session optional pam_block_afalg.so' | sudo tee -a /etc/pam.d/su
echo 'session optional pam_block_afalg.so' | sudo tee -a /etc/pam.d/sshd
echo 'session optional pam_block_afalg.so' | sudo tee -a /etc/pam.d/login
# 4. Verify (must be a NEW session - existing sessions are not affected)
# Open a new SSH connection or su session, then:
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
# 5. Uninstall
sudo rm /lib64/security/pam_block_afalg.so
sudo sed -i '/pam_block_afalg/d' /etc/pam.d/su /etc/pam.d/sshd /etc/pam.d/login
```
## Important Notes /
### PAM Config Placement / PAM
**Always APPEND the module to the end of PAM configs.** Never insert at the top. ** PAM 。 ** 。 ** Incorrect /:
```bash
# DON'T - this breaks SELinux and other required session modules
sudo sed -i '1i session optional pam_block_afalg.so' /etc/pam.d/sshd
```
Correct /:
```bash
# DO - append to the end
echo 'session optional pam_block_afalg.so' | sudo tee -a /etc/pam.d/sshd
```
Placing the module before `pam_selinux.so` or other `required` session modules can break authentication and privilege escalation (su/sudo). `pam_selinux.so` `required` session (su/sudo)。 ### Existing Sessions /
The seccomp filter is applied at session open time. **Existing sessions started before the module was installed are NOT affected.** You must log out and log back in for the protection to take effect. seccomp 。 **。** 。 ```bash
# Check if current session is protected /
cat /proc/self/status | grep Seccomp
```
# Seccomp: 0 = not protected (old session)
# Seccomp: 2 = protected (new session with module)
### PR_SET_NO_NEW_PRIVS / PR_SET_NO_NEW_PRIVS Issue
The module **does NOT** set `PR_SET_NO_NEW_PRIVS`. This flag prevents `setuid` transitions, which would break `su` and `sudo`. Since PAM modules run as root (with `CAP_SYS_ADMIN`), the seccomp filter can be loaded without this flag. The filter is still inherited by all child processes. The module **does NOT** set `PR_SET_NO_NEW_PRIVS`. This flag prevents `setuid` transitions, causing `su` and `sudo` to fail. Since PAM modules run as root (with `CAP_SYS_ADMIN`), the seccomp filter can be loaded without this flag. The filter is still inherited by all child processes.
## Command Reference /
| Command | Description | |
|---------|-------------|------|
| `deploy.sh install` | Compile PAM module, install it to `/lib64/security/`, create an uninstall script | PAM , `/lib64/security/`, |
| `deploy.sh remove` | Complete uninstall: removes the module, cleans PAM configurations, deletes files | :、 PAM 、 |
| `deploy.sh status` | Shows installation status, PAM configurations, kernel status | 、PAM 、 |
## Design Principles /
### Covers All Session Types /
The PAM module approach ensures protection for:
- `su - user -c "command"` (the previously bypassed case)
- `su - user` (interactive login)
- SSH sessions
- TTY/console login
- Any other PAM-authenticated session
PAM modules ensure that the following scenarios are protected:
- `su - user -c "command"` (the previously bypassed case)
- `su - user` (interactive login)
- SSH sessions
- TTY/console login
- All other PAM-authenticated sessions
### Minimal Impact /
- **Single syscall filter:** Only `socket(AF_ALG,...)` is blocked. All other system calls work normally.
- **No user shell modification:** Users keep their original login shell.
- **No system package modification:** Only a `.so` file is added to `/lib64/security/`.
- **Optional PAM configuration:** Use the `optional` flag so that login never fails due to the module.
- **`su/sudo` unaffected:** `setuid` operations work normally.
### Reversibility /
- `deploy.sh remove` completely cleans up: removes the module binary, removes PAM configuration entries, deletes all files.
- Or manually: `sudo rm /lib64/security/pam_block_afalg.so && sudo sed -i '/pam_block_afalg/d' /etc/pam.d/su /etc/pam.d/sshd /etc/pam.d/login`
- No persistent changes remain after cleaning.
- Existing sessions retain their seccomp filter until they end.
### Kernel Upgrade Safety /
- The PAM module checks every session to see if the kernel is still vulnerable.
- If the kernel has been patched (e.g., AF_ALG socket creation fails), the module acts as if it’s inactive.
- No manual intervention is required after kernel upgrades.
### Standalone Usage /
For non-PAM scenarios, use `block_afalg` directly:
```bash
# Compile /
gcc -Wall -O2 -o block_afalg block_afalg.c
# Run a command with AF_ALG blocked / AF_ALG
```./block_afalg python3 your_script.py./block_afalg bash
## Verification /
### Check if the kernel is vulnerable /
```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')
"
```
### Verify that the PAM module is active / PAM
```bash
# Check seccomp status / seccomp
cat /proc/self/status | grep Seccomp
# Seccomp: 0 = not protected
# Seccomp: 2 = protected
# Test AF_ALG socket / AF_ALG
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 / PAM
grep pam_block_afalg /var/log/secure
# Should show: seccomp filter applied, AF_ALG blocked
## Troubleshooting /
### su/sudo not working after installing the module / su/sudo
This was caused by `PR_SET_NO_NEW_PRIVS` in earlier versions. The current version does NOT use this flag. Update the module:
This was caused by `PR_SET_NO_NEW_PRIVS` in earlier versions. The current version does NOT use this flag. Update the module:
```bash
gcc -Wall -O2 -fPIC -shared -o pam_block_afalg.so pam_block_afalg.c /usr/lib64/libpam.so.0
sudo cp pam_block_afalg.so /lib64/security/
```
### The module is placed at the top of the PAM configuration / PAM
This breaks `pam_selinux.so` and other required modules. Move it to the end:
This will break `pam_selinux.so` and other required modules. Move it to the end:
```bash
sudo sed -i '/pam_block_afalg/d' /etc/pam.d/sshd
echo 'session optional pam_block_afalg.so' | sudo tee -a /etc/pam.d/sshd
```
### Existing sessions are not protected /
The seccomp filter is applied at session creation. Log out and log back in:
The seccomp filter is applied at session creation. Log out and log back in:
```bash
# Exit the current session
exit
# Reconnect
ssh user@host
# Verify
cat /proc/self/status | grep Seccomp
```
## Limitations /
- **Only x86_64:** The BPF filter hardcodes the system call number 41 (`__NRSocket` on x86_64). Other architectures require updating the system call number. - **PAM-dependent:** Only protects sessions that pass through PAM. Direct `exec()` calls without PAM are not covered (use `block_afalg` for those). - **No runtime disable:** Once the seccomp filter is applied to a process, it cannot be removed. The kernel ensures it’s only applied when needed. - **Only new sessions:** Existing sessions started before the module installation are not retroactively protected. x86_64:
- BPF 41(x86_64 `__NRSocket`)。 。 PAM:
- PAM 。 PAM `exec()` ( `block_afalg` )。 :
- seccomp 。 。 :
- 。 ## When to Remove /
1. **Official kernel patches are applied** - The PAM module automatically detects this, but you can still remove it using `remove`. 2. **RHEL/CentOS releases a patched kernel** - `yum update kernel` will then remove the module. :
1. **** - PAM ,。 2. **RHEL/CentOS ** - `yum update kernel` 。 ## License /
This tool is provided for authorized security testing and defensive purposes only. Use it only on systems you own or are explicitly authorized to assess. 。 。