Conversation
Extensions run as a non-root user and get their capabilities as file capabilities of their binary. With the effective bit (setcap ...+eip), the kernel refuses to exec the binary as soon as one of them is not granted to the container, so an extension missing a single capability crash-loops. Without it (+ip) the binary starts with what the container grants, but the capabilities stay in the permitted set. - RaiseCapabilities moves the permitted set into the effective set on all threads (AllThreadsSyscall; needs a binary built without cgo) - MissingCapabilities and RequireCapabilities check the bounding set, which the container's securityContext decides and the root helpers spawned by the extension inherit, so actions can fail fast with the missing ones named - LogMissingCapabilities warns at startup
|
Claude finished @achoimet's task in 2m 5s —— View job Review complete
Prior review thread: The earlier comment about the cgo fallback path applying New changes since that review (commits
No new correctness, security, or concurrency issues found. |
…oes not make them fail
…e root helpers MissingCapabilities only checked the bounding set, which is an upper bound: it reported capabilities as present that neither the extension nor its root helpers can use. It now requires the capability in the bounding set and either held by the extension (permitted set) or obtainable by the root helpers it spawns: SETUID and SETGID held and no_new_privs off. Under no_new_privs (allowPrivilegeEscalation: false) an exec gains nothing beyond what its parent held, so the helpers only get what the extension holds. Capabilities newer than the kernel (BPF, PERFMON before 5.8, CHECKPOINT_RESTORE before 5.9) were part of SYS_ADMIN, which now stands in for them instead of reporting them as missing, e.g. BPF on kernel 5.4.
… itself Some actions use a capability in the extension's own process (a syscall, writing a file), which a root helper cannot do for them. They must check the effective set, which also reports what RaiseCapabilities could not raise.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Extensions such as extension-container and extension-host run as a non-root user and get their capabilities as file capabilities of their binary (
setcap …+eip). With the effective bit, the kernel refuses toexecthe binary as soon as one listed capability is not granted to the container: a cluster whose policy forbids a single capability (e.g.NET_ADMIN) gets a crash-looping extension instead of one where only the network attacks are unavailable.Dropping the effective bit (
+ip) lets the binary start with whatever the container grants, but the capabilities then stay in the permitted set. This PR adds what the extensions need to work that way.What
In
extruntime:RaiseCapabilities()moves the permitted set into the effective set on all threads (syscall.AllThreadsSyscall, which needs a binary built without cgo — the extensions build withCGO_ENABLED=0). Capabilities are per thread in Linux, so raising them on the calling thread only is not enough for Go.MissingCapabilities(...)/RequireCapabilities(what, ...)check the bounding set: it is what the container's securityContext grants, and what the root helpers the extensions spawn (runc, nsenter, tc, …) inherit. Actions can fail fast inpreparewith the missing capabilities named.LogMissingCapabilities(...)warns at startup.Verified on Linux
A test binary with file capabilities
cap_setuid,cap_setgid,cap_net_admin,cap_sys_admin, run as uid 10000 in Docker with several OS threads:NET_ADMINgranted+eip(today)+eip(today)exec: operation not permitted(the crash loop)+ipNET_ADMINeffective on all 8 threads+ipMissingCapabilitiesreportsNET_ADMIN, the granted ones effective on all 8 threadsUsed by the follow-up PRs in extension-container and extension-host (setcap
+ip, raise at startup, fail fast per action).