Skip to content

mliberman/bun-appcontainer-repro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bun-appcontainer-repro

This is a minimal standalone reproduction of a libuv bug that surfaces in Bun-compiled executables on Windows: child_process.spawn({ stdio: "pipe" }) hangs forever when it's called from a Bun process running inside an AppContainer sandbox.

The root cause is in libuv's uv__pipe_server, which creates a named pipe in the global \Device\NamedPipe\ namespace and retries on ERROR_ACCESS_DENIED. That retry loop makes sense outside a sandbox, where the error is typically transient, but AppContainers are permanently denied access to the global pipe namespace — so the loop spins indefinitely. A fix needs to detect the AppContainer case and use the \\.\pipe\LOCAL\ namespace, which AppContainers are allowed to use.

Files

  • launch-in-appcontainer.cpp — This is the host launcher, built with MSVC (cl). It creates an AppContainer profile, grants the sandbox read+execute access on the directory containing the child executable, spawns the child inside with its stdio inherited from the launcher, and cleans up the profile and the granted ACL on exit.
  • repro.ts — This is the bug reproduction itself. It logs before, calls child_process.spawn with stdio: "pipe", and then logs after. When run outside a sandbox it prints both lines as expected; when run inside an AppContainer, it hangs indefinitely at before because libuv's named-pipe server retries forever on the ERROR_ACCESS_DENIED that AppContainers return for the global pipe namespace.
  • control.ts — This is a control test that also runs inside the sandbox: it logs start, waits one second, and then logs end. Its job is to confirm that the launcher itself, the inherited stdio plumbing, and Bun's event loop all work correctly under AppContainer, which isolates the bug demonstrated by repro.ts to child_process.spawn specifically.

Run it

Needs bun on PATH and a Bun checkout (for scripts/vs-shell.ps1, which locates MSVC).

# Build the launcher. Substitute your local Bun checkout for path/to/bun.
pwsh -File path/to/bun/scripts/vs-shell.ps1 cl -nologo -W3 -EHsc launch-in-appcontainer.cpp

# Compile the Bun scripts into standalone exes.
bun build --compile control.ts --outfile control.exe
bun build --compile repro.ts   --outfile repro.exe

# Control — sandboxed timer that prints "start" then "end" a second later.
# Confirms the launcher, stdio plumbing, and Bun's event loop all work inside
# an AppContainer. Should succeed.
./launch-in-appcontainer.exe ./control.exe

# Baseline — repro.exe outside the sandbox, prints "before" then "after".
./repro.exe

# Repro — sandboxed child_process.spawn hangs at "before". The launcher's 10s
# timeout terminates the child and exits 124.
./launch-in-appcontainer.exe ./repro.exe

References

  • Ninja PR #2354 — prior art for the same bug in Ninja's subprocess code; Microsoft reviewer recommended the GetTokenInformation(TokenIsAppContainer) gating pattern used in the proposed fix.
  • CreateNamedPipeW — documents the \\.\pipe\LOCAL\ requirement for AppContainer.
  • Implementing an AppContainer — Win32 APIs used by launch-in-appcontainer.cpp (CreateAppContainerProfile, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors