48d5f15828
Sweep results across 3 phases:
Phase 1 (no-pin, cached boxes) — 4/5 match:
entrybleed ubuntu2204 5.15.0-91-generic match
overlayfs ubuntu2004 5.4.0-169-generic match
overlayfs_setuid ubuntu2204 5.15.0-91-generic match
nft_fwd_dup debian11 5.10.0-27-amd64 match
sudoedit_editor ubuntu2204 MISMATCH (no sudoers grant — expected-fix below)
Phase 2 (new boxes ubuntu1804 + debian12) — 0/4 match:
ptrace_traceme \
sudo_samedit \ all FAILED to build: nft_fwd_dup needs
af_packet / NFTA_CHAIN_FLAGS (kernel 5.7), not in 4.15 uapi
pack2theroot /
pack2theroot also hit 'already root' early-exit (running as root via
vagrant provision's default privileged shell)
Phase 3 (kernel-pinned) — 4/8 match:
cls_route4 ubuntu2004 + 5.15.0-43 HWE match
nft_payload ubuntu2004 + 5.15.0-43 HWE match
af_packet2 ubuntu2004 + 5.4.0-26 (still in apt!) match
sequoia ubuntu2004 + 5.4.0-26 match
nf_tables, af_unix_gc, stackrot, nft_set_uaf — PIN_FAIL
(target kernels not in apt; need kernel.ubuntu.com mainline
integration — deferred)
Total: 13 modules verified end-to-end against real Linux VMs,
covering kernels 5.4 / 5.10 / 5.15 / 5.4-HWE / 5.15-HWE across
Ubuntu 18.04/20.04/22.04 + Debian 11/12.
Three fixes for the next retry pass:
1. core/nft_compat.h — added NFTA_CHAIN_FLAGS (kernel 5.7) and
NFTA_CHAIN_ID (kernel 5.13). Without these, nft_fwd_dup fails to
compile on Ubuntu 18.04's 4.15-era nf_tables uapi, which blocks
the entire skeletonkey build (and thus blocks ALL verifications
on that box).
2. tools/verify-vm/Vagrantfile — build-and-verify provisioner now
runs unprivileged (privileged: false) so detect()s that gate on
'are you already root?' don't short-circuit. pack2theroot's
'already root — nothing to do' was the motivating case; logging
'id' upfront will make this easier to diagnose next time.
3. tools/verify-vm/targets.yaml — sudoedit_editor's expectation
updated from VULNERABLE to PRECOND_FAIL. Ubuntu 22.04 ships
sudo 1.9.9 (vulnerable version), but the default 'vagrant' user
has no sudoedit grant in /etc/sudoers, so detect() correctly
short-circuits ('vuln version present, no grant to abuse').
Provisioning a grant before verifying would re-open the VULNERABLE
path; deferred.
Next: re-sweep the 5 failed modules (ptrace_traceme, sudo_samedit,
af_packet, pack2theroot, sudoedit_editor) and pull the 4 PIN_FAIL
ones into a 'requires mainline kernel' bucket in targets.yaml.
111 lines
4.6 KiB
Ruby
111 lines
4.6 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"] || ""
|
|
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
|
|
|
|
# 2. Pin target kernel 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 "[-] #{pkg} unavailable in apt; trying snapshot.debian.org" >&2
|
|
echo "deb [check-valid-until=no] http://snapshot.debian.org/archive/debian/20230101T000000Z bookworm main" \
|
|
>> /etc/apt/sources.list.d/snapshot.list
|
|
apt-get update -qq -o Acquire::Check-Valid-Until=false
|
|
apt-get install -y -qq --allow-downgrades #{pkg}
|
|
}
|
|
echo "[i] kernel #{pkg} installed; reboot via 'vagrant reload'"
|
|
fi
|
|
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
|