From 039d354b824d5cdbe6c4306e0d69e51a6442da6c Mon Sep 17 00:00:00 2001 From: Marketen Date: Tue, 5 May 2026 09:35:30 +0200 Subject: [PATCH 1/2] copy-fail-patch --- src/upgrades/upgrade_014.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 src/upgrades/upgrade_014.sh diff --git a/src/upgrades/upgrade_014.sh b/src/upgrades/upgrade_014.sh new file mode 100755 index 0000000..c4e245b --- /dev/null +++ b/src/upgrades/upgrade_014.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# Mitigate CVE-2026-31431 (Copy Fail) +# Local privilege escalation via algif_aead kernel module page-cache write. +# Fix: disable algif_aead module loading and unload if currently loaded. +# Impact: none for Docker/container workloads. AF_ALG aead is not used by +# dm-crypt, LUKS, kTLS, IPsec, SSH, OpenSSL/GnuTLS defaults, or Docker. + +MODPROBE_CONF="/etc/modprobe.d/disable-algif-aead.conf" + +# 1. Prevent algif_aead from loading on future boots +if [ ! -f "$MODPROBE_CONF" ]; then + echo "CVE-2026-31431: Creating ${MODPROBE_CONF} to disable algif_aead..." + echo "# CVE-2026-31431 mitigation - disable vulnerable algif_aead module" > "$MODPROBE_CONF" + echo "install algif_aead /bin/false" >> "$MODPROBE_CONF" +else + echo "CVE-2026-31431: ${MODPROBE_CONF} already exists, skipping." +fi + +# 2. Unload the module immediately if loaded (requires host kernel access) +docker run --rm --privileged --pid=host -t alpine:3.18 nsenter -t 1 -m -u -n -i sh -c ' + if lsmod | grep -q "^algif_aead"; then + echo "CVE-2026-31431: algif_aead is loaded, removing..." + rmmod algif_aead && echo "CVE-2026-31431: algif_aead removed successfully." || echo "CVE-2026-31431: WARNING - could not remove algif_aead (may be in use). It will not reload after reboot." + else + echo "CVE-2026-31431: algif_aead is not currently loaded." + fi +' From 79e81b013b74deb18ee3d2dc666f76166bdd997e Mon Sep 17 00:00:00 2001 From: Marketen Date: Tue, 5 May 2026 16:03:34 +0200 Subject: [PATCH 2/2] copyfail script Co-authored-by: Copilot --- src/scripts/mitigate_copy_fail_algif_aead.sh | 93 ++++++++++++++++++++ src/upgrades/upgrade_014.sh | 29 +----- 2 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 src/scripts/mitigate_copy_fail_algif_aead.sh diff --git a/src/scripts/mitigate_copy_fail_algif_aead.sh b/src/scripts/mitigate_copy_fail_algif_aead.sh new file mode 100644 index 0000000..93ad853 --- /dev/null +++ b/src/scripts/mitigate_copy_fail_algif_aead.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +# Host-side mitigation for CVE-2026-31431 (Copy Fail). +# The permanent fix is a patched kernel. Until then, block the vulnerable +# algif_aead userspace crypto module and unload it if it is currently loaded. + +MODULE="algif_aead" +MODPROBE_DIR="/etc/modprobe.d" +MODPROBE_CONF="${MODPROBE_DIR}/dappnode-disable-algif_aead.conf" +MODPROBE_RULE="install ${MODULE} /bin/false" + +# Check if the module is currently loaded +module_is_loaded() { + grep -qE "^${MODULE}[[:space:]]" /proc/modules 2>/dev/null +} + +# Check if a modprobe rule already exists to disable the module +module_has_disable_rule() { + for conf in "${MODPROBE_DIR}"/*.conf; do + [ -e "$conf" ] || continue + grep -qE "^[[:space:]]*install[[:space:]]+${MODULE}[[:space:]]+/bin/false([[:space:]]|$)" "$conf" && return 0 + done + return 1 +} + +# Attempt to unload the module using various common tools and paths +# Returns 0 if the module was successfully unloaded, or 1 if it could not be unloaded +unload_module() { + if command -v rmmod >/dev/null 2>&1 && rmmod "$MODULE" 2>/dev/null; then + return 0 + fi + + if [ -x /sbin/rmmod ] && /sbin/rmmod "$MODULE" 2>/dev/null; then + return 0 + fi + + if [ -x /usr/sbin/rmmod ] && /usr/sbin/rmmod "$MODULE" 2>/dev/null; then + return 0 + fi + + if command -v modprobe >/dev/null 2>&1 && modprobe -r "$MODULE" 2>/dev/null; then + return 0 + fi + + if [ -x /sbin/modprobe ] && /sbin/modprobe -r "$MODULE" 2>/dev/null; then + return 0 + fi + + if [ -x /usr/sbin/modprobe ] && /usr/sbin/modprobe -r "$MODULE" 2>/dev/null; then + return 0 + fi + + return 1 +} + +# Main logic +echo "[INFO] Applying CVE-2026-31431 mitigation for ${MODULE}" + +mkdir -p "$MODPROBE_DIR" + +if module_has_disable_rule; then + echo "[INFO] ${MODULE} already has a modprobe disable rule" +else + if { + echo "# DAppNode mitigation for CVE-2026-31431 (Copy Fail)" + echo "# Blocks the vulnerable AF_ALG AEAD module until the host kernel is patched." + echo "# Remove this file if AF_ALG AEAD support is required after applying a fixed kernel." + echo "$MODPROBE_RULE" + } > "$MODPROBE_CONF"; then + echo "[INFO] Created ${MODPROBE_CONF}" + else + echo "[WARN] Could not create ${MODPROBE_CONF}" + fi +fi + +if module_is_loaded; then + echo "[INFO] ${MODULE} is loaded; attempting to unload it" + if unload_module; then + echo "[INFO] ${MODULE} unloaded" + else + echo "[WARN] Could not unload ${MODULE}; reboot the host to complete the mitigation" + fi +else + echo "[INFO] ${MODULE} is not currently loaded" +fi + +if module_is_loaded; then + echo "[WARN] ${MODULE} is still loaded; reboot or unload it manually to complete the mitigation" +elif [ -d "/sys/module/${MODULE}" ]; then + echo "[WARN] ${MODULE} appears to be built into this kernel; use a patched kernel or block AF_ALG with seccomp" +else + echo "[INFO] CVE-2026-31431 mitigation active" +fi diff --git a/src/upgrades/upgrade_014.sh b/src/upgrades/upgrade_014.sh index c4e245b..7a7eb38 100755 --- a/src/upgrades/upgrade_014.sh +++ b/src/upgrades/upgrade_014.sh @@ -1,28 +1,7 @@ #!/bin/sh # Mitigate CVE-2026-31431 (Copy Fail) -# Local privilege escalation via algif_aead kernel module page-cache write. -# Fix: disable algif_aead module loading and unload if currently loaded. -# Impact: none for Docker/container workloads. AF_ALG aead is not used by -# dm-crypt, LUKS, kTLS, IPsec, SSH, OpenSSL/GnuTLS defaults, or Docker. - -MODPROBE_CONF="/etc/modprobe.d/disable-algif-aead.conf" - -# 1. Prevent algif_aead from loading on future boots -if [ ! -f "$MODPROBE_CONF" ]; then - echo "CVE-2026-31431: Creating ${MODPROBE_CONF} to disable algif_aead..." - echo "# CVE-2026-31431 mitigation - disable vulnerable algif_aead module" > "$MODPROBE_CONF" - echo "install algif_aead /bin/false" >> "$MODPROBE_CONF" -else - echo "CVE-2026-31431: ${MODPROBE_CONF} already exists, skipping." -fi - -# 2. Unload the module immediately if loaded (requires host kernel access) -docker run --rm --privileged --pid=host -t alpine:3.18 nsenter -t 1 -m -u -n -i sh -c ' - if lsmod | grep -q "^algif_aead"; then - echo "CVE-2026-31431: algif_aead is loaded, removing..." - rmmod algif_aead && echo "CVE-2026-31431: algif_aead removed successfully." || echo "CVE-2026-31431: WARNING - could not remove algif_aead (may be in use). It will not reload after reboot." - else - echo "CVE-2026-31431: algif_aead is not currently loaded." - fi -' +# Run the mitigation on the host so the loaded kernel module can be removed +# immediately. The core container can write /etc through the bind mount, but it +# does not have CAP_SYS_MODULE in the host namespace. +docker run --rm --privileged --pid=host -t alpine:3.8 nsenter -t 1 -m -u -n -i /usr/src/dappnode/DNCORE/scripts/upgrade/mitigate_copy_fail_algif_aead.sh