Files
SKELETONKEY/tools/verify-vm/Vagrantfile
T
leviathan 312e7d89b5 verify-vm: kernel.ubuntu.com mainline integration — 22 modules verified
Unblocks the 4 previously-PIN_FAIL modules by adding a fallback path to
kernel.ubuntu.com/mainline/ for any kernel no longer in apt. Adds 4 more
matches to the verified_on table for a total of 22 modules confirmed
against real Linux VMs:

  af_unix_gc     ubuntu2204 + mainline 5.15.5  match
  nf_tables      ubuntu2204 + mainline 5.15.5  match
  nft_set_uaf    ubuntu2204 + mainline 5.15.5  match
  stackrot       ubuntu2204 + mainline 6.1.10  match

Mechanism:

  tools/verify-vm/Vagrantfile — new 'pin-mainline-<X.Y.Z>' shell
  provisioner. Fetches the directory index at
  https://kernel.ubuntu.com/mainline/v<X.Y.Z>/amd64/, parses out the 4
  canonical .deb filenames (linux-headers _all, linux-headers
  -generic _amd64, linux-image-unsigned -generic _amd64, linux-modules
  -generic _amd64; skips lowlatency), downloads them, runs 'dpkg -i' +
  'update-grub', and prints a reboot hint.

  Mainline package version like '5.15.5-051505' sorts ABOVE Ubuntu's
  stock '5.15.0-91' in debian-version-compare (numeric 51505 > 91), so
  update-grub puts it at the top of the boot menu and the next
  'vagrant reload' lands on it automatically. uname then reports
  '5.15.5-051505-generic' which our parser sees as 5.15.5 → in our
  kernel_range table's vulnerable window → empirical VULNERABLE.

  tools/verify-vm/verify.sh — new SKK_VM_MAINLINE_VERSION env passed to
  the Vagrantfile. Reload trigger now also fires when uname doesn't
  match the mainline target.

  tools/verify-vm/targets.yaml — new 'mainline_version' field on the 4
  PIN_FAIL targets. kernel_pkg is left empty; mainline_version drives
  the fetch. Picked 5.15.5 (Nov 2021) for the 5.15-line CVEs and
  6.1.10 (Feb 2023) for stackrot — both below every relevant backport.

Final sweep status (22 of 26 CVEs):

  ✓ MATCHES (22):
    pwnkit, cgroup_release_agent, netfilter_xtcompat, fuse_legacy,
    nft_fwd_dup, entrybleed, overlayfs, overlayfs_setuid,
    sudoedit_editor, ptrace_traceme, sudo_samedit, af_packet,
    pack2theroot, cls_route4, nft_payload, af_packet2, sequoia,
    dirty_pipe, nf_tables, af_unix_gc, nft_set_uaf, stackrot

  🚫 NOT VERIFIED (4 — flagged in targets.yaml with rationale):
    vmwgfx        — VMware-guest only; no public Vagrant box covers it
    dirtydecrypt  — needs Linux 7.0; not shipping as any distro kernel
    fragnesia     — needs Linux 7.0; same
    dirty_cow     — needs ≤ 4.4 kernel; older than every supported
                    Vagrant box (would need a custom image)

  copy_fail_family entries verified indirectly via the shared
  infrastructure tests in the kernel_range unit-test harness.

The 22 records are baked into core/verifications.c and surface in
--list (VFY ✓ column), --module-info (--- verified on --- section),
--explain (VERIFIED ON section), and JSON output (verified_on array).
22/26 CVEs is the new trust signal; with the mainline fetch path
production-ready, additional pin targets can be added to targets.yaml
without code changes.
2026-05-23 17:35:13 -04:00

153 lines
6.4 KiB
Ruby

# -*- mode: ruby -*-
# vi: set ft=ruby :
#
# tools/verify-vm/Vagrantfile — parameterized verifier VM.
#
# Driven by env vars set by tools/verify-vm/verify.sh:
#
# SKK_VM_BOX generic/<box> name (e.g. generic/debian11)
# SKK_VM_KERNEL_PKG optional apt package for the vulnerable kernel
# (e.g. linux-image-5.13.0-19-generic). Empty = use stock.
# SKK_VM_KERNEL_VERSION expected kernel version after install
# SKK_VM_HOSTNAME hostname for this VM (used in vagrant box name)
#
# The Vagrantfile mounts the repo root at /vagrant (Vagrant default) so the
# in-VM `make` builds against your live source — no rebuild loop.
require "yaml"
REPO_ROOT = File.expand_path("../..", __dir__)
box = ENV["SKK_VM_BOX"] || "generic/debian12"
pkg = ENV["SKK_VM_KERNEL_PKG"] || ""
mainline = ENV["SKK_VM_MAINLINE_VERSION"] || ""
kver = ENV["SKK_VM_KERNEL_VERSION"] || ""
host = ENV["SKK_VM_HOSTNAME"] || "skk-verify"
Vagrant.configure("2") do |c|
# Define ONE Vagrant machine named after SKK_VM_HOSTNAME. Per-module
# isolation: each module gets its own `skk-<module>` machine that
# vagrant tracks in .vagrant/machines/skk-<module>/parallels/.
c.vm.define host do |m|
m.vm.box = box
# Guest hostnames forbid underscores per RFC 952. Vagrant machine
# names allow them (we keep skk-cgroup_release_agent so per-module
# state stays isolated in .vagrant/machines/), but inside the VM
# we translate to hyphens so the hostname is RFC-valid.
m.vm.hostname = host.gsub("_", "-")
m.vm.synced_folder REPO_ROOT, "/vagrant",
type: "rsync", rsync__exclude: ["build/", ".git/", "*.o", "skeletonkey-test*"]
m.vm.provider "parallels" do |p|
p.memory = 2048
p.cpus = 2
p.name = host
# Don't auto-update Parallels Tools: the installer fails on older
# guest kernels (e.g. Ubuntu 20.04's 5.4.0-169 is "outdated and
# not supported" by latest tools). We use rsync over SSH for
# sync_folder, which doesn't need the guest tools at all.
p.update_guest_tools = false
p.check_guest_tools = false
end
# 1. Always install build deps + sudo (needed for module verification).
m.vm.provision "shell", inline: <<-SHELL
set -e
if command -v apt-get >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq build-essential libglib2.0-dev pkg-config sudo curl ca-certificates
elif command -v dnf >/dev/null 2>&1; then
dnf install -y -q gcc make glib2-devel pkgconfig sudo curl
fi
SHELL
# 2a. Pin via apt if requested. Reboot needed afterward.
if !pkg.empty?
m.vm.provision "shell", name: "pin-kernel-#{pkg}", inline: <<-SHELL
set -e
if dpkg-query -W -f='${Status}' #{pkg} 2>/dev/null | grep -q 'install ok installed'; then
echo "[=] #{pkg} already installed"
else
echo "[+] installing #{pkg} (kernel target #{kver})"
export DEBIAN_FRONTEND=noninteractive
apt-get install -y -qq #{pkg}
echo "[i] kernel #{pkg} installed; reboot via 'vagrant reload'"
fi
SHELL
end
# 2b. Pin via kernel.ubuntu.com/mainline/ if mainline_version is set.
# Fetches the four .debs (linux-headers _all, linux-headers _amd64
# generic, linux-image-unsigned generic, linux-modules generic),
# dpkg -i's them, regenerates grub, and prints a reboot hint.
# Mainline kernel package version like "5.15.5-051505" sorts ABOVE
# Ubuntu's stock "5.15.0-91" in debian-version-compare (numeric
# 51505 > 91), so update-grub puts it at boot index 0 and the next
# boot lands on it automatically.
if !mainline.empty?
m.vm.provision "shell", name: "pin-mainline-#{mainline}", inline: <<-SHELL
set -e
KVER="#{mainline}"
# already booted into it?
if uname -r | grep -q "^${KVER}-[0-9]\\+-generic"; then
echo "[=] mainline ${KVER} already booted ($(uname -r))"
exit 0
fi
# already installed on disk (waiting on reboot)?
if ls /boot/vmlinuz-${KVER}-* >/dev/null 2>&1; then
echo "[=] mainline ${KVER} already installed; needs reboot"
exit 0
fi
echo "[+] fetching kernel.ubuntu.com mainline v${KVER}"
URL="https://kernel.ubuntu.com/mainline/v${KVER}/amd64/"
TMP=$(mktemp -d)
cd "$TMP"
# Pick the 4 canonical generic-kernel .debs by pattern match against
# the directory index. Skip lowlatency variants.
DEBS=$(curl -sL "$URL" | \\
grep -oE 'href="[^"]+\\.deb"' | sed 's/href="//; s/"$//' | \\
grep -E '(linux-image-unsigned|linux-modules|linux-headers)-[0-9.]+-[0-9]+-generic_|linux-headers-[0-9.]+-[0-9]+_[^_]+_all\\.deb' | \\
grep -v lowlatency)
if [ -z "$DEBS" ]; then
echo "[-] no .debs found at $URL — does the version exist on kernel.ubuntu.com?" >&2
exit 2
fi
for f in $DEBS; do
echo "[+] $f"
curl -fsSL -O "${URL}${f}"
done
export DEBIAN_FRONTEND=noninteractive
dpkg -i *.deb || apt-get install -f -y -qq
update-grub 2>&1 | tail -3
echo "[i] mainline ${KVER} installed; reboot via 'vagrant reload'"
SHELL
end
# 3. Build SKELETONKEY in-VM and run --explain --active for the target
# module. Runs as the unprivileged 'vagrant' user (NOT root) — most
# detect()s gate on "are you already root?" and short-circuit if so,
# which would invalidate every verification (pack2theroot was the
# motivating case). 'privileged: false' is how vagrant downshifts.
# SKK_MODULE is set by verify.sh on the second-pass `vagrant
# provision` call (post-reboot if kernel was pinned).
m.vm.provision "shell", name: "build-and-verify", run: "never",
privileged: false,
env: { "SKK_MODULE" => ENV["SKK_MODULE"] || "" },
inline: <<-SHELL
set -e
cd /vagrant
echo "[*] running as $(id)"
echo "[*] kernel: $(uname -r)"
echo "[*] building skeletonkey..."
make clean >/dev/null 2>&1 || true
make 2>&1 | tail -3
echo
echo "[*] running: skeletonkey --explain ${SKK_MODULE} --active"
echo
./skeletonkey --explain "${SKK_MODULE}" --active 2>&1 || true
SHELL
end
end