Summary
Inside a rootless bubblewrap sandbox, a cache-enabled task cannot spawn child processes. Every spawn/spawnSync/execFile fails with EPERM before the child runs. Setting cache: false on the same task, with nothing else changed, makes it work.
The path is absolute and executable in both cases, so this is not PATH resolution.
Reproduction
Sandbox is entered as:
bwrap --die-with-parent --new-session \
--unshare-user --unshare-pid --unshare-ipc --unshare-uts --unshare-cgroup --unshare-net \
--cap-drop ALL \
--clearenv --setenv PATH /runtime/bin \
--ro-bind <toolchain-image> /runtime \
--tmpfs /tmp --dev /dev --proc /proc \
--bind <checkout> /workspace \
-- /runtime/bin/sh -c 'cd /workspace && vp run -r test'
There is no /usr/bin, /bin or /usr/lib in the sandbox; everything is under /runtime.
Any cached task whose command spawns a child reproduces it:
execFileSync("/tmp/shell/sh", ["-n"], { input: script });
| task config |
spawn |
{ command: 'vp test' } |
EPERM |
{ command: 'vp test', cache: false } |
works |
In one vp run -r test over a workspace, the packages I had flipped to cache: false spawned fine while the packages still cached failed in the same run, same sandbox, same commit. Flipping two packages took the spawn failures from 74 to 0.
Observed
Error: spawnSync /tmp/shell/sh EPERM
Error: spawn EPERM
Nothing is printed by the child. git subprocesses fail the same way one level down:
fatal: cannot exec 'git-receive-pack': Operation not permitted
Environment
- vite-plus 0.3.0
- Linux x86_64, glibc
- rootless bubblewrap, seccomp, unprivileged user namespaces
Notes
Not #569/#576 — 0.3.0 has both. LD_PRELOAD is unset going in, so not #340.
Guess: fspy_preload_unix has to inject into each child, and this sandbox is --cap-drop ALL with /usr/lib unmounted, so either the preload object is unreachable in the child's mount namespace or something it does on init is denied — and the exec is refused instead of tracking degrading.
Falling back to caching without file tracking would be better than failing the spawn. Today the only workaround is disabling the cache for the whole package.
Happy to run patches or a debug build against the sandbox.
Summary
Inside a rootless bubblewrap sandbox, a cache-enabled task cannot spawn child processes. Every
spawn/spawnSync/execFilefails withEPERMbefore the child runs. Settingcache: falseon the same task, with nothing else changed, makes it work.The path is absolute and executable in both cases, so this is not PATH resolution.
Reproduction
Sandbox is entered as:
There is no
/usr/bin,/binor/usr/libin the sandbox; everything is under/runtime.Any cached task whose command spawns a child reproduces it:
{ command: 'vp test' }EPERM{ command: 'vp test', cache: false }In one
vp run -r testover a workspace, the packages I had flipped tocache: falsespawned fine while the packages still cached failed in the same run, same sandbox, same commit. Flipping two packages took the spawn failures from 74 to 0.Observed
Nothing is printed by the child.
gitsubprocesses fail the same way one level down:Environment
Notes
Not #569/#576 — 0.3.0 has both.
LD_PRELOADis unset going in, so not #340.Guess:
fspy_preload_unixhas to inject into each child, and this sandbox is--cap-drop ALLwith/usr/libunmounted, so either the preload object is unreachable in the child's mount namespace or something it does on init is denied — and the exec is refused instead of tracking degrading.Falling back to caching without file tracking would be better than failing the spawn. Today the only workaround is disabling the cache for the whole package.
Happy to run patches or a debug build against the sandbox.