feat: allow local system-tests to be run as root#10650
Merged
Merged
Conversation
Make the Local (QEMU) system-test backend work when the driver runs as root inside a nested user namespace whose network namespace is owned by an ancestor user namespace (e.g. on a Remote Build Execution cluster). Two changes to the local backend: - `net_admin`: when running as root, run the net-admin script directly via `/bin/sh -c` instead of the file-capability `capsh` launcher. A root process already holds the needed capabilities, and `capsh`'s file capabilities are not honored across the user-namespace boundary (it would fail with EPERM while setting inheritable capabilities). - `ensure_administrable_netns`: at driver startup, when running as root without CAP_NET_ADMIN over the current network namespace, `unshare` a fresh, self-owned network namespace so RTNETLINK operations succeed. This runs before the tokio runtime and any task subprocess is spawned, so the whole process tree shares the netns. `group.rs` invokes `ensure_administrable_netns` early, only under the Local backend. Extracted from #10579.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the Local (QEMU) system-test backend to work correctly when the driver process is executed as root in environments like RBE, where the current network namespace may be owned by an ancestor user namespace and RTNETLINK operations would otherwise fail.
Changes:
- Adjust
net_adminexecution: when running as root, runsh -cdirectly instead of using the file-capabilitycapshlauncher. - Add
ensure_administrable_netnsto detect non-administrable netns situations andunshare(CLONE_NEWNET)into a self-owned netns early in driver startup. - Invoke
ensure_administrable_netnsearly under the Local backend (before tokio runtime / subprocess spawning).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| rs/tests/driver/src/driver/local_backend.rs | Adds root-aware net-admin execution and early netns self-healing via unshare(CLONE_NEWNET); introduces running_as_root() helper. |
| rs/tests/driver/src/driver/group.rs | Calls LocalBackend::ensure_administrable_netns(...) early when using the Local backend. |
Comments suppressed due to low confidence (1)
rs/tests/driver/src/driver/local_backend.rs:1399
current_username()returns$USERverbatim, but its result is interpolated into shell scripts executed bynet_admin(). With this PR, the root path runs those scripts as root (/bin/sh -c ...), so an unexpected$USERvalue containing shell metacharacters could become a shell-injection vector. Restrict the username to a safe token (or fall back) before using it in scripts.
/// The current user's login name, used to tag TAP device ownership so an
/// unprivileged QEMU may open them. Falls back to the `USER` environment
/// variable and finally to `ubuntu` (the container's default user).
fn current_username() -> String {
std::env::var("USER").unwrap_or_else(|_| "ubuntu".to_string())
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
basvandijk
commented
Jul 3, 2026
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
nmattia
approved these changes
Jul 3, 2026
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.
Overview
Make the Local (QEMU) system-test backend (
SYSTEM_TEST_INFRA=local) work when the driver runs as root inside a nested user namespace whose network namespace is owned by an ancestor user namespace — e.g. on a Remote Build Execution cluster, where the_localaction runs as root but is left in a netns it does not own, so RTNETLINK operations are denied.These changes were extracted from #10579 (the RBE @ Namespace experiment) so they can land independently. The unprivileged dev-container / internal-CI path is unchanged.
Changes
Both changes are confined to the local backend:
net_admin(local_backend.rs): when running as root, run thenet-adminscript directly via/bin/sh -cinstead of the file-capabilitycapshlauncher (NET_ADMIN_LAUNCHER). A root process already holds the needed capabilities and its children inherit them; meanwhilecapsh's file capabilities are not honored across the user-namespace boundary, so its inheritable-set step fails withEPERM.ensure_administrable_netns(local_backend.rs): at driver startup, when running as root withoutCAP_NET_ADMINover the current network namespace,unshare(CLONE_NEWNET)into a fresh, self-owned netns so RTNETLINK operations succeed — recreating whatlinux-sandboxgives the unprivileged case. It must run before the tokio runtime and any task subprocess is spawned so the whole process tree (task subprocesses, QEMU,dnsmasq) shares the netns. Aprobe_netlinkhelper (create + delete a short-lived bridge) decides whether the unshare is needed and verifies the fresh netns is administrable.group.rs: invokesensure_administrable_netnsearly, only under theLocalbackend, before the tokio runtime and reaper are set up.Also adds a small
running_as_root()helper (effective uid 0).