Skip to content

Instantly share code, notes, and snippets.

@GottZ
Created April 30, 2026 06:50
Show Gist options
  • Select an option

  • Save GottZ/7cb012306afcb77f31b34fb62158d9c3 to your computer and use it in GitHub Desktop.

Select an option

Save GottZ/7cb012306afcb77f31b34fb62158d9c3 to your computer and use it in GitHub Desktop.
CVE-2026-31431 ('Copy Fail') ad-hoc mitigation: blacklist algif_aead/authencesn without reboot. --apply/--check/--revert/--help.
#!/bin/bash
# cve-2026-31431-mitigate.sh
#
# Ad-hoc mitigation for CVE-2026-31431 ("Copy Fail") — an algif_aead /
# authencesn page-cache scratch-write primitive in the Linux kernel crypto
# userspace API. Applying this script blocks the vulnerable code paths
# without requiring a kernel reboot.
#
# Strategy:
# 1. Unload algif_aead, authencesn, authenc (refcnt permitting).
# 2. Persist a modprobe blacklist + `install … /bin/false` so neither
# auto-load nor explicit `modprobe` can bring them back.
# 3. Verify by trying to instantiate "aead" via AF_ALG (must fail).
#
# Side effects on a typical server:
# * dm-crypt / LUKS keep working (they use the in-kernel crypto API, not
# AF_ALG).
# * `cryptsetup benchmark` still works (uses algif_skcipher, not aead).
# * Anything that explicitly requests AEAD via AF_ALG (rare: some
# libkcapi consumers, custom IPsec userland) will get ENOENT.
#
# Usage:
# sudo ./cve-2026-31431-mitigate.sh # apply (default)
# sudo ./cve-2026-31431-mitigate.sh --check # report status, change nothing
# sudo ./cve-2026-31431-mitigate.sh --revert # remove the blacklist
# sudo ./cve-2026-31431-mitigate.sh --help
set -euo pipefail
CONF=/etc/modprobe.d/cve-2026-31431.conf
TARGETS=(algif_aead authencesn authenc)
c_red() { printf '\033[31m%s\033[0m\n' "$*"; }
c_grn() { printf '\033[32m%s\033[0m\n' "$*"; }
c_ylw() { printf '\033[33m%s\033[0m\n' "$*"; }
c_dim() { printf '\033[2m%s\033[0m\n' "$*"; }
usage() {
awk '
NR==1 && /^#!/ { next }
/^#/ { sub(/^# ?/, ""); print; next }
{ exit }
' "$0"
exit 0
}
require_root() {
if [ "$(id -u)" -ne 0 ]; then
c_red "[!] Must run as root (modprobe / /etc/modprobe.d write)."
exit 1
fi
}
module_loaded() { [ -d "/sys/module/$1" ]; }
module_refcnt() {
if [ -r "/sys/module/$1/refcnt" ]; then
cat "/sys/module/$1/refcnt"
else
echo "?"
fi
}
af_alg_aead_reachable() {
# Returns 0 if a userspace process can still instantiate the AEAD path.
python3 - <<'PY' 2>/dev/null
import socket, sys
try:
s = socket.socket(38, socket.SOCK_SEQPACKET, 0) # AF_ALG = 38
s.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
s.close()
sys.exit(0)
except OSError:
sys.exit(1)
PY
}
show_status() {
echo "kernel : $(uname -r)"
echo "modprobe : $CONF $( [ -f "$CONF" ] && echo '(present)' || echo '(absent)' )"
echo "modules :"
for m in "${TARGETS[@]}"; do
if module_loaded "$m"; then
printf ' %-12s loaded refcnt=%s\n' "$m" "$(module_refcnt "$m")"
else
printf ' %-12s unloaded\n' "$m"
fi
done
if af_alg_aead_reachable; then
c_red "AEAD path : REACHABLE via AF_ALG (system is exposed)"
return 1
else
c_grn "AEAD path : blocked (AF_ALG bind to authencesn fails)"
return 0
fi
}
apply() {
require_root
if [ -f "$CONF" ] && ! af_alg_aead_reachable; then
c_grn "[+] Already mitigated. Nothing to do."
show_status || true
return 0
fi
echo "[*] Writing $CONF"
cat >"$CONF" <<'EOF'
# CVE-2026-31431 ("Copy Fail") — algif_aead / authencesn scratch-write.
# Mitigation written by cve-2026-31431-mitigate.sh
# Revert: delete this file, then `modprobe algif_aead` if you actually need it.
blacklist algif_aead
blacklist authencesn
blacklist authenc
install algif_aead /bin/false
install authencesn /bin/false
install authenc /bin/false
EOF
echo "[*] Unloading modules (if loaded and idle)"
for m in "${TARGETS[@]}"; do
if module_loaded "$m"; then
rc=$(module_refcnt "$m")
if [ "$rc" = "0" ]; then
if modprobe -r "$m" 2>/dev/null; then
c_grn " $m: removed"
else
c_ylw " $m: rmmod failed (will stay until next reboot, but blacklist is active)"
fi
else
c_ylw " $m: in use (refcnt=$rc) — leaving loaded; blacklist prevents future loads"
fi
else
c_dim " $m: not loaded"
fi
done
echo
echo "[*] Verification"
if show_status; then
c_grn "[+] Mitigation applied successfully."
return 0
else
c_red "[!] Mitigation did NOT block the AEAD path. Investigate."
return 2
fi
}
revert() {
require_root
if [ -f "$CONF" ]; then
rm -f "$CONF"
c_grn "[+] Removed $CONF"
else
c_dim "[i] $CONF was not present"
fi
echo "[i] Modules will load on demand again. Run 'modprobe algif_aead' to test."
}
main() {
case "${1:-apply}" in
-h|--help|help) usage ;;
--check|check|status) show_status ;;
--revert|revert) revert ;;
--apply|apply|"") apply ;;
*) c_red "unknown arg: $1"; echo "try --help"; exit 1 ;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment