#!/bin/sh
# CVE-2026-98432 (Linux kernel IPv4 TCP use-after-free) self-check
# Read-only: prints facts about this server. It installs, changes and sends nothing.
# Usage: sh check-cve-2026-98432.sh
# Source: https://blog.uriui.com/linux-kernel-cve-2026-98432-check/

CVE=CVE-2026-98432
[ -r /etc/os-release ] && . /etc/os-release

running=$(uname -r)
newest=$(ls /boot/vmlinuz-* 2>/dev/null | sed 's|/boot/vmlinuz-||' | grep -v rescue | sort -V | tail -1)

echo "== $CVE check (read-only) =="
echo "[1] OS               : ${PRETTY_NAME:-unknown}"
echo "[2] Running kernel   : $running"
echo "    Build string     : $(uname -v)"
# Package version of a kernel release name (prints nothing if unknown)
pkg_of() {
  dpkg-query -W -f='${Version}' "linux-image-$1" 2>/dev/null && return
  v=$(rpm -q --qf '%{VERSION}-%{RELEASE}' "kernel-core-$1" 2>/dev/null) && { echo "$v"; return; }
  v=$(rpm -q --qf '%{VERSION}-%{RELEASE}' "kernel-$1" 2>/dev/null) && echo "$v"
}

if [ -z "$newest" ] && command -v rpm >/dev/null 2>&1; then
  # some systems keep kernels only under /lib/modules
  newest=$(rpm -q --qf '%{VERSION}-%{RELEASE}.%{ARCH}\n' kernel-core 2>/dev/null | sort -V | tail -1)
fi
pkgver=""
[ -n "$newest" ] && pkgver=$(pkg_of "$newest")
echo "[3] Newest installed : ${newest:-none found}${pkgver:+ (package $pkgver)}"

# Debian puts the package version in the build string: "... Debian 6.1.190-1 (date)"
built=$(uname -v | sed -n 's/.* Debian \([^ ]*\) .*/\1/p')
if [ -f /.dockerenv ] || [ -f /run/.containerenv ]; then
  echo "[4] Reboot needed?   : n/a - this is a container; run on the host server"
elif [ -z "$newest" ]; then
  echo "[4] Reboot needed?   : unknown (no installed kernel found)"
elif [ "$running" != "$newest" ]; then
  echo "[4] Reboot needed?   : YES - newest kernel is installed but not running"
elif [ -n "$built" ] && [ -n "$pkgver" ] && [ "$built" != "$pkgver" ]; then
  echo "[4] Reboot needed?   : YES - same name, but running build $built != installed $pkgver"
elif [ -f /var/run/reboot-required ]; then
  echo "[4] Reboot needed?   : YES - /var/run/reboot-required exists"
elif command -v needs-restarting >/dev/null 2>&1 && { needs-restarting -r >/dev/null 2>&1; [ $? -eq 1 ]; }; then
  echo "[4] Reboot needed?   : YES - needs-restarting -r says so"
else
  echo "[4] Reboot needed?   : no - running the newest installed kernel"
fi

# [5] Does the newest installed kernel package changelog name this CVE?
found=unknown
case " ${ID:-} ${ID_LIKE:-} " in
  *" debian "*|*" ubuntu "*)
    for f in /usr/share/doc/linux-image-"$newest"/changelog*.gz; do
      [ -f "$f" ] || continue
      if zcat "$f" 2>/dev/null | grep -q "$CVE"; then found=yes; break; else found=no; fi
    done
    up=$(apt list --upgradable 2>/dev/null | grep -E '^linux-(image|generic|virtual|aws|azure|gcp|oracle|kvm)' | cut -d/ -f1 | tr '\n' ' ')
    ;;
  *" rhel "*|*" fedora "*|*" centos "*)
    for pkg in "kernel-core-$newest" "kernel-$newest"; do
      rpm -q "$pkg" >/dev/null 2>&1 || continue
      if rpm -q --changelog "$pkg" 2>/dev/null | grep -q "$CVE"; then found=yes; else found=no; fi
      break
    done
    up=$(dnf -q check-update 'kernel*' 2>/dev/null | awk '/^kernel/{print $1}' | tr '\n' ' ')
    ;;
esac
echo "[5] CVE in changelog : $found"
echo "[6] Kernel updates   : ${up:-none listed (run your package update first)}"
echo "[7] tcp_migrate_req  : $(cat /proc/sys/net/ipv4/tcp_migrate_req 2>/dev/null || echo n/a)"

case "${ID:-}" in
  debian) url="https://security-tracker.debian.org/tracker/$CVE" ;;
  ubuntu) url="https://ubuntu.com/security/$CVE" ;;
  rhel|centos|rocky|almalinux|ol) url="https://access.redhat.com/security/cve/$CVE" ;;
  amzn) url="https://explore.alas.aws.amazon.com/$CVE.html" ;;
  *) url="https://www.cve.org/CVERecord?id=$CVE" ;;
esac
echo "[8] Fixed version    : see $url"
