78 lines
3.3 KiB
Bash
Executable File
78 lines
3.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# vm-native-cpuid - manage the automatic cpuid_passthrough toggle for hardened guests.
|
|
#
|
|
# vm-native-cpuid enable <domain> apply the automatic cpuid passthrough to <domain>
|
|
# vm-native-cpuid disable <domain> stop applying it to <domain>
|
|
# vm-native-cpuid status show the config and the live module state
|
|
# vm-native-cpuid revert remove the hook, watcher and config; reset the module
|
|
#
|
|
# The switch and brand string are one global kvm_amd parameter, so it serves one
|
|
# hardened guest at a time. It is off until you enable it here - no domain is
|
|
# touched otherwise. Around an enabled guest the libvirt hook forces the switch off
|
|
# for the cold boot, a watcher flips it on once the guest's network is up, and it
|
|
# goes off again on stop.
|
|
|
|
set -uo pipefail
|
|
|
|
CONF=/etc/vfio-native/cpuid-passthrough.conf
|
|
HOOK=/etc/libvirt/hooks/qemu.d/30-cpuid-passthrough.sh
|
|
WATCH=/usr/lib/vfio-native/cpuid-passthrough-watch
|
|
PARAM=/sys/module/kvm_amd/parameters
|
|
SELF=$(cd "$(dirname "$0")/.." 2>/dev/null && pwd)
|
|
|
|
die() { echo "$*" >&2; exit 1; }
|
|
need_root() { [ "$(id -u)" = 0 ] || die "run this as root"; }
|
|
|
|
load() { ENABLED=yes; DOMAINS=""; [ -r "$CONF" ] && . "$CONF"; }
|
|
save() { mkdir -p "$(dirname "$CONF")"; printf 'ENABLED=%s\nDOMAINS="%s"\n' "$ENABLED" "$DOMAINS" > "$CONF"; }
|
|
|
|
# copy the hook and watcher into place from the installed tree or this checkout
|
|
install_hook() {
|
|
local src=""
|
|
for d in /usr/share/vfio-native "$SELF"; do
|
|
[ -f "$d/scripts/libvirt-hook-cpuid-passthrough.sh" ] && src="$d"
|
|
done
|
|
[ -n "$src" ] || die "cannot find the hook source (install vfio-native, or run from a checkout)"
|
|
install -Dm755 "$src/scripts/libvirt-hook-cpuid-passthrough.sh" "$HOOK"
|
|
install -Dm755 "$src/scripts/cpuid-passthrough-watch" "$WATCH"
|
|
}
|
|
|
|
case "${1:-}" in
|
|
enable)
|
|
need_root; [ -n "${2:-}" ] || die "usage: vm-native-cpuid enable <domain>"
|
|
load; install_hook; ENABLED=yes
|
|
case " $DOMAINS " in *" $2 "*) ;; *) DOMAINS="${DOMAINS:+$DOMAINS }$2" ;; esac
|
|
save
|
|
echo "$2 enabled. cpuid passthrough is now automatic for: $DOMAINS"
|
|
echo "on start it forces N for the cold boot, flips Y once the guest is on the network, N again on stop."
|
|
;;
|
|
disable)
|
|
need_root; [ -n "${2:-}" ] || die "usage: vm-native-cpuid disable <domain>"
|
|
load; DOMAINS=$(printf ' %s ' "$DOMAINS" | sed "s/ $2 / /g" | xargs || true); save
|
|
systemctl stop "vfio-cpuid-watch-$2.service" 2>/dev/null || true
|
|
echo "$2 disabled. remaining: ${DOMAINS:-none}"
|
|
;;
|
|
status)
|
|
load
|
|
echo "config: $CONF"
|
|
echo "enabled: $ENABLED"
|
|
echo "domains: ${DOMAINS:-none}"
|
|
echo "hook: $([ -f "$HOOK" ] && echo installed || echo 'not installed')"
|
|
if [ -r "$PARAM/cpuid_passthrough" ]; then
|
|
echo "module: cpuid_passthrough=$(cat "$PARAM/cpuid_passthrough") brand='$(cat "$PARAM/brand_string")'"
|
|
else
|
|
echo "module: patched kvm_amd not loaded"
|
|
fi
|
|
;;
|
|
revert)
|
|
need_root; load
|
|
for d in $DOMAINS; do systemctl stop "vfio-cpuid-watch-$d.service" 2>/dev/null || true; done
|
|
rm -f "$HOOK" "$WATCH" "$CONF" /run/vfio-native/cpuid-active
|
|
[ -w "$PARAM/cpuid_passthrough" ] && echo N > "$PARAM/cpuid_passthrough"
|
|
echo "reverted: hook, watcher and config removed; cpuid_passthrough=N."
|
|
;;
|
|
*)
|
|
sed -n '2,13p' "$0" | sed 's/^#\( \|$\)//'
|
|
;;
|
|
esac
|