Kernel-CVE's en backports: waarom uname -r je niets vertelt over je patchniveau
Een scanner die 6.8.0 ziet en 40 kernel-CVE's meldt, kent de Ubuntu- en Debian-backports niet. Zo lees je zelf de changelog van je kernelpackage, vergelijk je de draaiende kernel met de geïnstalleerde, controleer je hardware-mitigaties in /sys en beslis je wanneer livepatch de moeite is. Met de gratis bronnen: USN, Debian Security Tracker en de package-changelog.
Inhoud
- Stap 1: welke kernel draait er, en welke staat er geïnstalleerd?
- Stap 2: welke CVE's zijn in mijn kernelpackage gefixt?
- Stap 3: wat zegt de distributie over open kernel-CVE's?
- Stap 4: hardware-mitigaties — de CVE's die geen package hebben
- Stap 5: wanneer livepatch de moeite is
- Stap 6: het wekelijkse rapport
- Valkuilen
- Wat je hiermee nog niet hebt
- Zo doet monsys het
- FAQ
uname -r geeft 6.8.0-45-generic. Een vulnerability-scanner ziet "6.8.0", zoekt in de NVD naar alles wat in 6.8.x is gefixt, en rapporteert veertig CVE's. Ondertussen heeft Ubuntu die veertig al in 6.8.0-45.45 gebackport zonder het upstream-nummer te veranderen. Het omgekeerde bestaat ook: de kernel die je geïnstalleerd hebt is gepatcht, maar de kernel die draait is die van voor de reboot van drie weken geleden. Twee vragen dus, en uname -r beantwoordt er geen van beide.
Stap 1: welke kernel draait er, en welke staat er geïnstalleerd?
# Draaiend
uname -r # 6.8.0-45-generic
cat /proc/version # bevat build-datum en compiler — handig bij custom builds
# Geïnstalleerd (kan nieuwer zijn dan draaiend)
dpkg -l 'linux-image-*' | awk '/^ii/{print $2, $3}'
# linux-image-6.8.0-45-generic 6.8.0-45.45
# linux-image-6.8.0-47-generic 6.8.0-47.47 ← nieuwer, nog niet geboot
# linux-image-generic 6.8.0-47.47 ← metapackage wijst naar de nieuwste
# Zegt het systeem zelf dat er een reboot nodig is?
cat /var/run/reboot-required 2>/dev/null && cat /var/run/reboot-required.pkgs
# Of, vollediger (ook voor services met oude libraries):
sudo needrestart -b | grep -E 'KSTA|KCUR|KEXP'
# NEEDRESTART-KCUR: 6.8.0-45-generic
# NEEDRESTART-KEXP: 6.8.0-47-generic
# NEEDRESTART-KSTA: 3 ← 1 = ok, 2 = ABI-compatibele update, 3 = reboot nodig
De Debian-variant is identiek, met 6.1.0-25-amd64-stijl versies. needrestart staat op Ubuntu-servers standaard geïnstalleerd; op Debian: apt install needrestart.
Als KCUR ≠ KEXP, is elke CVE-analyse van de geïnstalleerde kernel irrelevant: je draait de oude. Dat is de eerste en meest voorkomende fout.
Stap 2: welke CVE's zijn in mijn kernelpackage gefixt?
De autoriteit is niet de NVD maar de changelog van het package dat je draait. Ubuntu en Debian vermelden elk CVE-nummer expliciet.
# Ubuntu: de changelog van het draaiende kernelpackage, alle CVE's.
# LET OP: op een Secure Boot-machine is linux-image-<ver> het *signed* package, en dié
# changelog bevat alleen "Packaging resync"-regels — nul CVE's. Vraag daarom de changelog
# van het unsigned package (source: linux), dat is waar de fixes staan.
apt changelog "linux-image-unsigned-$(uname -r)" 2>/dev/null | grep -oE 'CVE-[0-9]{4}-[0-9]+' | sort -u > /tmp/fixed-in-running.txt
wc -l < /tmp/fixed-in-running.txt # honderden op een LTS-kernel die een jaar oud is
# Geeft dat 0? Dan bestaat het unsigned package niet in je cache; linux-modules-<ver> deelt dezelfde source:
apt changelog "linux-modules-$(uname -r)" 2>/dev/null | grep -oE 'CVE-[0-9]{4}-[0-9]+' | sort -u > /tmp/fixed-in-running.txt
# Debian: changelog zit lokaal
zcat "/usr/share/doc/linux-image-$(uname -r)/changelog.Debian.gz" | grep -oE 'CVE-[0-9]{4}-[0-9]+' | sort -u > /tmp/fixed-in-running.txt
# Zit een specifieke CVE erin?
grep -q CVE-2024-1086 /tmp/fixed-in-running.txt && echo "gefixt in draaiende kernel" || echo "NIET gefixt (of niet van toepassing)"
"Niet in de changelog" betekent niet automatisch "kwetsbaar". Het kan ook zijn dat de CVE een subsysteem betreft dat niet in deze kernel is gecompileerd, of dat de kwetsbare code pas in een nieuwere upstream-versie is toegevoegd. Daar geeft de distributie-tracker uitsluitsel.
Stap 3: wat zegt de distributie over open kernel-CVE's?
Ubuntu publiceert per CVE een status per release. De handigste bron is de OSV-feed (dezelfde als in de OS-package-how-to), met linux als source package:
. /etc/os-release
# Source package van de draaiende kernel. Signed kernels heten "linux-signed[-aws|-azure|…]"
# in dpkg, maar OSV kent ze als "linux[-aws|-azure|…]" — daarom de sed.
SRC=$(dpkg-query -W -f='${source:Package}' "linux-image-$(uname -r)" | sed 's/-signed//')
VER=$(dpkg-query -W -f='${source:Version}' "linux-image-$(uname -r)")
echo "$SRC $VER" # linux 6.8.0-45.45
curl -s -X POST https://api.osv.dev/v1/query -H 'Content-Type: application/json' \
-d "{\"package\":{\"name\":\"$SRC\",\"ecosystem\":\"Ubuntu:$VERSION_ID\"},\"version\":\"$VER\"}" \
| jq -r '.vulns[]? | .id' | sort -u > /tmp/open-kernel.txt
wc -l < /tmp/open-kernel.txt
Dat is de lijst CVE's waarvoor Ubuntu jouw exacte kernelversie als kwetsbaar beschouwt — na verrekening van alle backports. Op een kernel die deze maand is bijgewerkt: meestal enkele tientallen "medium/low" waar Ubuntu nog aan werkt of die als deferred staan. Op een kernel van een half jaar oud: honderden.
Debian heeft de Security Tracker met een JSON-export. Hij is groot (tientallen MB) maar compleet:
curl -s https://security-tracker.debian.org/tracker/data/json -o /tmp/debsec.json
jq -r --arg rel "$VERSION_CODENAME" '
.linux | to_entries[]
| select(.value.releases[$rel].status == "open")
| [.key, .value.releases[$rel].urgency, (.value.description // "")[0:80]] | @tsv' /tmp/debsec.json \
| sort | column -t -s $'\t' | head -30
De kolom urgency (unimportant, low, medium, high) is Debians eigen inschatting; unimportant betekent doorgaans "raakt de Debian-build niet".
Stap 4: hardware-mitigaties — de CVE's die geen package hebben
Spectre, Meltdown, MDS, Retbleed, Downfall, Zenbleed: dat zijn CVE's in de CPU, gemitigeerd door kernel én microcode. Of jouw machine beschermd is, staat niet in een changelog maar in /sys:
grep -H . /sys/devices/system/cpu/vulnerabilities/* | sed 's|.*/vulnerabilities/||'
# spectre_v2:Mitigation: Enhanced / Automatic IBRS; IBPB: conditional; RSB filling; ...
# mds:Not affected
# gather_data_sampling:Vulnerable: No microcode ← dit wil je zien
# retbleed:Mitigation: Enhanced IBRS
Alles wat Vulnerable zegt, is een openstaand item. De fix is meestal microcode (apt install intel-microcode of amd64-microcode, daarna reboot) — op een VPS kan alleen de hoster dat doen, en dan is het een vraag aan de hoster, geen actie op de server. Neem de output op in je bewijs; een auditor die "Spectre" vraagt, krijgt zo een feitelijk antwoord.
Stap 5: wanneer livepatch de moeite is
Livepatch (Ubuntu Pro / canonical-livepatch, of kpatch op RHEL) patcht kritieke kernel-CVE's in het draaiende geheugen, zonder reboot. Het dekt alleen de CVE's die Canonical als high/critical inschat en die livepatchbaar zijn — dus niet alles.
# Ubuntu Pro is gratis voor 5 machines (persoonlijk account)
sudo pro attach <token>
sudo pro enable livepatch
canonical-livepatch status --verbose
# ...
# patchState: applied
# fixes: CVE-2024-xxxx, CVE-2024-yyyy
De afweging is simpel: livepatch koopt tijd tussen "CVE gepubliceerd" en "gepland reboot-venster". Het vervangt de reboot niet; needrestart blijft KSTA 3 melden tot je echt herstart. Voor een server die je elke maand toch herstart in een onderhoudsvenster, is livepatch vooral nuttig voor de zeldzame critical die op dag 0 wordt misbruikt. Voor een database die maar twee keer per jaar down mag, is het essentieel.
Stap 6: het wekelijkse rapport
Alles samen in één script dat per server vijf regels oplevert:
sudo tee /usr/local/sbin/kernel-status.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
. /etc/os-release
RUN=$(uname -r)
INST=$(dpkg -l 'linux-image-[0-9]*' | awk '/^ii/{print $2}' | sed 's/linux-image-//' | sort -V | tail -1)
KSTA=$(needrestart -b 2>/dev/null | awk -F': ' '/KSTA/{print $2}')
VULN=$(grep -l -E '^Vulnerable' /sys/devices/system/cpu/vulnerabilities/* 2>/dev/null | xargs -rn1 basename | paste -sd, -)
SRC=$(dpkg-query -W -f='${source:Package}' "linux-image-$RUN" 2>/dev/null | sed 's/-signed//')
VER=$(dpkg-query -W -f='${source:Version}' "linux-image-$RUN" 2>/dev/null)
OPEN=$(curl -s -m 20 -X POST https://api.osv.dev/v1/query -H 'Content-Type: application/json' \
-d "{\"package\":{\"name\":\"${SRC:-linux}\",\"ecosystem\":\"Ubuntu:$VERSION_ID\"},\"version\":\"$VER\"}" \
| jq -r '.vulns // [] | length')
printf 'host=%s running=%s installed=%s reboot_state=%s cpu_vulnerable=%s open_kernel_cves=%s\n' \
"$(hostname -s)" "$RUN" "$INST" "${KSTA:-?}" "${VULN:--}" "${OPEN:-?}"
EOF
sudo chmod 0755 /usr/local/sbin/kernel-status.sh
sudo /usr/local/sbin/kernel-status.sh
# host=web-01 running=6.8.0-45-generic installed=6.8.0-47-generic reboot_state=3 cpu_vulnerable=gather_data_sampling open_kernel_cves=23
Die ene regel per host, wekelijks in een bestand of naar ntfy, beantwoordt beide vragen uit de inleiding: draai ik wat ik heb geïnstalleerd, en hoeveel staat er nog open voor wat ik draai.
Valkuilen
- Cloud- en signed kernels.
-aws,-azure,-gcp,-kvmzijn aparte source packages (linux-aws, …) met eigen changelogs en eigen USN's. En op elke machine met Secure Boot heet het source package in dpkglinux-signed(oflinux-signed-aws), terwijl OSV en de USN'slinuxgebruiken. Vraag het source package altijd aan dpkg en strip-signed; hardcodedlinuxis fout op AWS, hardcodedlinux-signedlevert nul resultaten op. - Custom en vendor-kernels. Een kernel van een hoster (
5.15.0-hoster1) of een zelfgebouwde (6.9.0-custom) heeft geen changelog met CVE's en geen tracker-entry./proc/versionzonderbuildd@is de aanwijzing. Die kernels behandel je als "onbekend patchniveau", wat in een audit hetzelfde is als "kwetsbaar". - De changelog van het verkeerde package.
apt changelog linux-image-$(uname -r)op een Secure Boot-machine geeft de changelog vanlinux-signed, en die bevat geen enkele CVE. Je concludeert dan "niets gefixt" terwijl er 200 CVE's in zitten. Gebruiklinux-image-unsigned-…oflinux-modules-…. /bootvol. Elke kernel neemt 100–150 MB. Als/bootvol is, faalt de installatie van de nieuwe kernel halverwege en draai je stilzwijgend door op de oude.apt autoremove --purgeruimt op; hou er altijd twee.- Scanners die versienummers vergelijken. Als je Nessus, OpenVAS of Trivy op hosts draait, filter kernel-CVE's uit hun rapport en gebruik de distributie-tracker. Anders discussieer je elke maand over veertig false positives.
- Reboot-required is geen kernel-only signaal.
/var/run/reboot-requiredverschijnt ook voor glibc, systemd en dbus. De.pkgs-file vertelt welke.
Wat je hiermee nog niet hebt
- Fleet-overzicht. "Welke hosts draaien een kernel met een open KEV-CVE?" is een
for h in $(cat hosts); do ssh $h kernel-status.sh; done— en dan nog de KEV-lijst ernaast leggen. - Reboot-orkestratie. Weten dat 14 servers moeten herstarten is stap één; ze in de juiste volgorde, in het juiste venster, met een rollback-plan herstarten is het echte werk. Zie de how-to over kernel-updates op productie.
- Bewijs met datum. Voor NIS2 en ISO 27001 A.8.8 wil je kunnen tonen: CVE gepubliceerd op X, kernel geïnstalleerd op Y, gereboot op Z. Dat zijn drie tijdstempels die nu in drie verschillende logs staan.
Zo doet monsys het
De monsys-agent rapporteert de draaiende kernel, de geïnstalleerde kernels, reboot_required, is_custom_build en de geladen modules. De hub's kernel-CVE-pipeline legt die tegen de Ubuntu USN's, de Debian Security Tracker, RHEL CSAF en Gentoo GLSA — backport-bewust, per source package (ook linux-aws en consorten). Open kernel-CVE's worden verrijkt met EPSS en KEV en meegewogen in de Trust Score. Kernel-updates plan je in batches met reboot-vensters, waarbij de aanvrager en de goedkeurder verschillende personen moeten zijn (segregation of duty) — en elk stadium is ondertekend gelogd.
FAQ
Mijn scanner zegt dat kernel 6.8.0 veertig CVE's heeft. Klopt dat?
Bijna zeker niet. Ubuntu en Debian backporten fixes zonder het upstream-versienummer te wijzigen. Controleer de changelog van je kernelpackage (apt changelog linux-image-$(uname -r)) of de OSV-feed met je exacte packageversie; die kennen de backports wel.
Moet ik na elke kernel-update herstarten?
Ja, om de nieuwe kernel te draaien. Zonder reboot staat de gepatchte kernel op schijf terwijl de oude in het geheugen doorwerkt. Livepatch is de uitzondering voor een beperkte set kritieke CVE's, maar ook dan blijft een reboot uiteindelijk nodig.
Is Ubuntu Pro livepatch gratis?
Voor maximaal vijf machines met een persoonlijk Ubuntu One-account, ja. Daarboven is het een betaald abonnement. Debian heeft geen officieel livepatch-equivalent; daar is een gepland reboot-venster de praktijk.
Geschreven door het monsys-team — sysadmins die dit dagelijks doen.
Zelf gedaan? Laat monsys het bijhouden.
Alles uit deze how-to draait in monsys als doorlopende check, met historie, alerts en audit-bewijs. 5 servers gratis, EU-gehost in België, geïnstalleerd in 60 seconden.