Skip to content

v0.21.0 — assertions that hold

Choose a tag to compare

@cwayne18 cwayne18 released this 20 Sep 18:26
· 14 commits to main since this release
85dd02b

Three changes to the path you take to discharge a taint, and to making that path work at fleet scale without a way to get a wrong answer out of it.

Block conclusions on a --roots path that does not resolve (#29)

--roots is how you answer an exec taint, usually alongside --exec-policy=assume-none. A root that named nothing was logged and dropped — the closure lost a root and reported code it would have reached as unreachable, while the same command line discharged the taint that would have withheld the conclusion.

Measured on kube-vip, a one-character typo produced 10 ruled-out findings, 7 of them wrong, in a report byte-identical in size to the correct one. Now it raises a blocking, global missing-root taint: 0 ruled out, every finding names the path.

This rules out no additional CVEs. It converts a silent wrong answer into a visible refusal.

Per-image assertions in a fleet list (#29)

The assertion flags were global — fine for one image, unusable for fifty-eight.

docker.io/rancher/mirrored-cilium-cilium:v1.16.1 exec-policy=assume-none
docker.io/rancher/hardened-coredns:v1.11.1 roots=/coredns

Keys: roots, dlopen-policy, exec-policy, dynamic-import-policy. A per-image assertion replaces the global flag for that image. Unknown keys and unparseable values are errors raised before anything is pulled.

On RKE2 v1.29.9+rke2r1, over the five images whose open base OS findings were withheld by the exec taint alone:

image bare open asserted recovered
harvester-cloud-provider:v0.2.2 16 0 16
harvester-csi-driver:v0.1.7 136 0 136
mirrored-cilium-cilium:v1.16.1 502 0 502
mirrored-kube-vip-kube-vip-iptables:v0.6.0 22 0 22
nginx-ingress-controller:v1.10.4-hardened3 249 249 0
TOTAL 925 249 676 (73%)

Fleet-wide that is 33% of all open base OS findings, every one already proven unreachable. nginx-ingress recovers nothing, correctly — three taints, one assertion.

An asserted root stands down escalation (#30)

A shell entrypoint roots every program in the image, and --roots was ignored on that path. Escalation now stands down against both halves of an assertion — --roots plus --exec-policy=assume-none. Either alone still escalates, and an unresolvable root counts for neither.

image roots reachable objects proven unreached
hardened-calico:v3.28.1 491 → 9 595 → 15 of 668 2 → 141 of 148
hardened-flannel:v0.25.6 546 → 15 663 → 38 of 825 —

What this release does not do, and why

The open count does not move on a Rancher hardened image. Those are cgo/FIPS Go builds, so the entrypoint is statically linked and may hold a copy of any C library, and static-elf blocks globally. On hardened-cni-plugins the closure narrows to a single reachable object and all 11 open OS findings are held by one line:

/opt/cni/bin/bridge is statically linked, so the libraries it uses are inside it and not on disk

It is discharged per-CVE by reading the entrypoint's own symbol table (#26), which needs a mined symbol.

Measurement across RKE2 v1.29.9 (58 images) found no further sound inference worth building — scoped exec recovers 11%, sharper dlopen 1%, exempting exec from presence 2% — and put the remaining reduction on running a real LLM miner rather than a stub. 766 open findings are both reached by the closure and unmined.