Relevant area(s)
Linux, macOS, Windows
Brief description of your issue
There is no cross-backend contract for what PATH a sandboxed workload receives. Every backend
invents its own answer, and the answer also changes depending on whether process.env happens to
be non-empty. The result is that an identical config resolves different commands - or fails to
resolve them at all - depending on the backend and the host distribution.
This table shows what PATH equals in each scenario:
| Backend |
process.env omitted |
process.env set, no PATH= |
| Seatbelt (macOS) |
/usr/bin:/bin:/usr/sbin:/sbin (seatbelt_runner.rs:726) |
same default |
| LXC (Linux) |
inherits host PATH |
liblxc default /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin |
| Bubblewrap (Linux) |
none |
none |
| Windows AppContainer |
user registry Path via CreateEnvironmentBlock(bInherit=FALSE) |
none |
| Windows BaseContainer |
inherits wxc-exec's env (lpEnvironment = NULL) |
none |
Three distinct problems fall out of this:
1. Bubblewrap can leave PATH entirely unset. bwrap_command.rs:702 emits --clearenv
and never restores PATH. It is the only backend where a workload
can receive no PATH whatsoever in both columns. Command resolution then silently falls back to
whatever the host shell was compiled with, which is distro-dependent:
| bash build |
DEFAULT_PATH_VALUE |
Debian/Ubuntu (config-top.h:59) |
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin: |
Fedora/RHEL (bash.spec:142) |
/usr/local/bin:/usr/bin |
This is already failing in CI. Nightly run 33731889129 (main @ ad80e6b), Bubblewrap suite:
rhel-10 failed while debian-13, ubuntu-24.04 and ubuntu-26.04 passed, because an sbin
tool was unresolvable on RHEL only. Debian/Ubuntu are not passing because MXC is correct there -
they pass because they inherit a vendor fallback that happens to include sbin.
2. Adding one unrelated env variable silently changes PATH on 3 of 5 backends. Because the
posture is keyed on whether process.env is non-empty rather than on whether it contains PATH,
adding FOO=bar - a variable with nothing to do with PATH - changes command resolution:
- LXC (
lxc_bindings.rs:105): flips from KEEP_ENV to --clear-env, so PATH changes from
the host's to liblxc's default.
- Windows AppContainer / BaseContainer (
appcontainer_runner.rs:1030-1041,
base_container_runner.rs:96-106): flips from a full environment block to
build_explicit_entries, which is pure passthrough — so PATH goes from present to absent.
A user adding a single environment variable has no reason to expect their commands to stop
resolving. On Windows this is a strict replace semantic with no floor under it.
3. None of this is documented. docs/schema.md:102 describes env in a single line
("Environment variables as KEY=VALUE") and says nothing about clearing, defaults, or per-backend
divergence.
Steps to reproduce
- Build MXC for the platform under test (
./build.sh, ./build-mac.sh, or build.bat).
- Save a config that reports its own
PATH — no process.env:
"version": "0.8.0-alpha",
"containerId": "path-probe",
"containment": "bubblewrap",
"process": {
"commandLine": "bash -c 'echo \"PATH=[${PATH-<unset>}]\"; command -v iptables || echo NO_IPTABLES'"
}
- Run it: ./src/target/release/lxc-exec --experimental path-probe.json
- Add a single unrelated variable - "env": ["FOO=bar"] - and run again. Compare the reported PATH.
- Repeat both runs with containment set to lxc, and on macOS with seatbelt
(mxc-exec-mac) and on Windows with processContainer (wxc-exec.exe, using cmd /c echo %PATH%).
- Repeat step 2 on both a Debian/Ubuntu host and a RHEL 10 host.
Expected behavior
A single documented contract that holds on every backend.
Actual behavior
Five backends exhibit five different behaviors when process.env is omitted, and three of them
change behavior when an unrelated variable is added.
Relevant area(s)
Linux, macOS, Windows
Brief description of your issue
There is no cross-backend contract for what
PATHa sandboxed workload receives. Every backendinvents its own answer, and the answer also changes depending on whether
process.envhappens tobe non-empty. The result is that an identical config resolves different commands - or fails to
resolve them at all - depending on the backend and the host distribution.
This table shows what
PATHequals in each scenario:process.envomittedprocess.envset, noPATH=/usr/bin:/bin:/usr/sbin:/sbin(seatbelt_runner.rs:726)PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binPathviaCreateEnvironmentBlock(bInherit=FALSE)wxc-exec's env (lpEnvironment = NULL)Three distinct problems fall out of this:
1. Bubblewrap can leave
PATHentirely unset.bwrap_command.rs:702emits--clearenvand never restores
PATH. It is the only backend where a workloadcan receive no
PATHwhatsoever in both columns. Command resolution then silently falls back towhatever the host shell was compiled with, which is distro-dependent:
DEFAULT_PATH_VALUEconfig-top.h:59)/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:bash.spec:142)/usr/local/bin:/usr/binThis is already failing in CI. Nightly run 33731889129 (
main@ad80e6b), Bubblewrap suite:rhel-10failed whiledebian-13,ubuntu-24.04andubuntu-26.04passed, because ansbintool was unresolvable on RHEL only. Debian/Ubuntu are not passing because MXC is correct there -
they pass because they inherit a vendor fallback that happens to include
sbin.2. Adding one unrelated env variable silently changes
PATHon 3 of 5 backends. Because theposture is keyed on whether
process.envis non-empty rather than on whether it containsPATH,adding
FOO=bar- a variable with nothing to do withPATH- changes command resolution:lxc_bindings.rs:105): flips fromKEEP_ENVto--clear-env, soPATHchanges fromthe host's to liblxc's default.
appcontainer_runner.rs:1030-1041,base_container_runner.rs:96-106): flips from a full environment block tobuild_explicit_entries, which is pure passthrough — soPATHgoes from present to absent.A user adding a single environment variable has no reason to expect their commands to stop
resolving. On Windows this is a strict replace semantic with no floor under it.
3. None of this is documented.
docs/schema.md:102describesenvin a single line("Environment variables as KEY=VALUE") and says nothing about clearing, defaults, or per-backend
divergence.
Steps to reproduce
./build.sh,./build-mac.sh, orbuild.bat).PATH— noprocess.env:(mxc-exec-mac) and on Windows with processContainer (wxc-exec.exe, using cmd /c echo %PATH%).
Expected behavior
A single documented contract that holds on every backend.
Actual behavior
Five backends exhibit five different behaviors when process.env is omitted, and three of them
change behavior when an unrelated variable is added.