Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ name: Compat
# Whether a checkpoint the newest release saved resumes on this change's machine, and whether the
# fingerprint still accounts for every ROM the machine maps (boot:compat, boot:roms): after every
# change on main to what a resumed guest is loaded into - the machine's definition, QEMU, the
# kernel, the firmware and their pins - and before every release.
# kernel, the firmware and their pins - and before every release. And whether that kernel, booted,
# is locked down (boot:lockdown).
#
# On the KVM fleet (spin-stack/ci), because it boots: the newest release is unpacked as the machine
# before, and the machine here is that tree with this change's QEMU, firmware and kernel built over
Expand All @@ -29,6 +30,8 @@ on:
- kernel/**
- boot/compat_test.go
- boot/roms_test.go
- boot/lockdown_test.go
- boot/testdata/lockdown-check.sh
- versions.yaml
- .github/workflows/compat.yml
workflow_dispatch:
Expand Down Expand Up @@ -91,3 +94,9 @@ jobs:

- name: A checkpoint of the release before resumes here
run: go tool task boot:compat

# This change's kernel, booted: lockdown at confidentiality that root cannot lower, the BPF
# LSM, no /dev/mem or /proc/kcore. kernel/Dockerfile checks the config; this checks the
# kernel that came out of it.
- name: The kernel is locked down
run: go tool task boot:lockdown
8 changes: 5 additions & 3 deletions boot/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ tasks:
kernel and spin-machine in place of its own, in _output/compat/here. Both are exported to
the steps after in CI (SPIN_COMPAT_PREVIOUS, SPIN_MACHINE_OUTPUT). Needs a built QEMU,
kernel and tools.
# The base image is the release's: a checkpoint resumes with the disks it was saved with.
# The base image is the release's: a checkpoint resumes with the disks it was saved with. So
# are the e2fsprogs tools that edit a copy of it (boot:lockdown's debugfs), which is why bin/
# loses only what this tree replaces; the release's TCG QEMU goes with its QEMU.
cmds:
- task: previous
- |
set -euo pipefail
previous=$(cat {{.OUTPUT_ABS}}/compat/previous)
here={{.OUTPUT_ABS}}/compat/here
rm -rf "$here" && cp -as "$previous" "$here"
rm -rf "$here/bin" "$here/qemu" "$here/kernel"
mkdir -p "$here/bin" "$here/kernel"
rm -rf "$here"/bin/qemu-* "$here/qemu" "$here/kernel"
mkdir -p "$here/kernel"
cp {{.OUTPUT_ABS}}/bin/qemu-system-x86_64 {{.OUTPUT_ABS}}/bin/qemu-img {{.OUTPUT_ABS}}/bin/spin-machine "$here/bin/"
cp -r {{.OUTPUT_ABS}}/qemu "$here/qemu"
cp {{.OUTPUT_ABS}}/kernel/vmlinux "$here/kernel/vmlinux"
Expand Down
21 changes: 18 additions & 3 deletions kernel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,27 @@ The guest's root is not the kernel's. The kernel runs two LSMs, `lockdown` and `
it, root reads or rewrites the kernel those programs live in.

What enforcing the policy is for, and how, is the consumer's. That this kernel does both is
what `kernel/Dockerfile` checks after olddefconfig, and `task boot:lockdown` asks a booted guest.
what `kernel/Dockerfile` checks after olddefconfig, and `task boot:lockdown` asks a booted guest:
`compat.yml` runs it on every kernel change on main and before every release.

Lockdown at confidentiality also takes away the tenant's kernel tracing: kprobes,
`bpf_probe_read_kernel` and perf on the kernel. User-space tracing and networking eBPF are
untouched. systemd notices at boot: it logs `use of bpf to read kernel RAM is restricted` and
carries on, and logins are unaffected (`task boot:logind`).
untouched, and so is a BPF LSM program that reads no kernel memory.

systemd notices at boot, and the console shows two lines that read like missing protection
and are lockdown working:

```
bpf-restrict-fs: Failed to load BPF object: Invalid argument
Lockdown: init: use of bpf to read kernel RAM is restricted; see man kernel_lockdown.7
```

The second is lockdown refusing `bpf_probe_read_kernel` to PID 1. The first is what that costs:
systemd's `RestrictFileSystems=` program reads each file's filesystem type out of kernel memory
with that helper, the verifier rejects it, and systemd carries on without it. So a unit in the
guest cannot use `RestrictFileSystems=`; it is not enforced, and systemd does not say so per
unit. That is the price of confidentiality, kept on purpose: integrity would give it back by
letting root read the kernel's memory again. Logins are unaffected (`task boot:logind`).

Measured 2026-10-01, `task boot:initcalls` with `SPIN_KERNEL_B` set to the kernel without these
options: no cost that can be told from noise. Over 20 interleaved boots each, kernel start to
Expand Down
Loading