Repository navigation
Description
Relevant area(s)
Linux, Windows
Brief description of your issue
Summary
MSYS2/Cygwin-based executables (git-bash, and anything else linking msys-2.0.dll)
cannot run under the processcontainer backend. The process launches successfully,
but the MSYS runtime aborts during initialization when it tries to create its shared
state directory in the session-global object namespace, which AppContainer processes
cannot write.
This is not a policy or configuration problem — no filesystem, capability, or UI
setting can grant it.
Environment
- MXC:
main - Windows 11 25H2 (build 26200)
- Selected tier:
appcontainer-dacl(T3);--probereports
baseContainerApiPresent: true,bfsCompiledIn: false - git-bash / MSYS2 runtime 3.6.5 (
x86_64-pc-msys)
Steps to reproduce
Repro
Config:
{
"version": "0.8.0-alpha",
"containment": "processcontainer",
"process": {
"commandLine": "\"C:\\tools\\git-bash\\bin\\bash.exe\" --version",
"cwd": "C:\\tools\\git-bash",
"timeout": 30000
},
"filesystem": {
"readonlyPaths": ["C:\\tools\\git-bash", "C:\\Windows"],
"readwritePaths": []
},
"fallback": { "allowDaclMutation": true },
"ui": { "disable": false }
}wxc-exec.exe config.json
Expected behavior
bash.exe --version
GNU bash, version 5.2.37(1)-release (x86_64-pc-msys)
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Actual behavior
Observed
0 [main] bash (NNNN) C:\tools\git-bash\usr\bin\bash.exe: *** fatal error -
NtCreateDirectoryObject(\BaseNamedObjects\msys-2.0S5-<hash>): 0xC0000022
Exit code: -1073741502 (0xC0000142)
0xC0000022 is STATUS_ACCESS_DENIED; 0xC0000142 is STATUS_DLL_INIT_FAILED.
Root cause
msys-2.0.dll passes an absolute NT path to NtCreateDirectoryObject.
AppContainer's named-object redirection lives in user-mode kernelbase
(BaseGetNamedObjectDirectory) and only covers the Win32 named-object APIs — it does
not rewrite absolute NT paths. The call therefore reaches the real global
\BaseNamedObjects and fails the DIRECTORY_CREATE_SUBDIRECTORY access check
(SeChangeNotifyPrivilege bypasses traverse, not create).
Verified by direct probe from inside the container, same container SID:
| Path | Result |
|---|---|
\BaseNamedObjects\test |
0xC0000022 |
\Sessions\1\AppContainerNamedObjects\<SID>\test |
STATUS_SUCCESS |
The container's own namespace is writable; only the global one is denied.
An API trace of bash -c "echo hi | tr a-z A-Z" shows the full dependency is small —
exactly two absolute paths, with every child object created relative to the resulting
directory handle:
CreateDir Root=0x0 "\BaseNamedObjects\msys-2.0S5-<hash>"
CreateDir Root=0x0 "\Sessions\BNOLINKS\1\msys-2.0S5-<hash>"
CreateSection Root=0x124 "shared.5"
CreateSection Root=0x124 "cygpid.<pid>" <- fork
CreateMutant Root=0x124 "cygpipe.input.mutex.<pid>-0x1" <- pipe
CreateMutant Root=0x124 "sig_send.<pid>" <- signals
CreateSymlink Root=0x124 "winpid.<winpid>"
Ruled out
- Not Win32k. Identical failure with
ui.disable: false. - Not filesystem policy.
\BaseNamedObjectsis an object-manager path; no
readonlyPaths/readwritePathsentry reaches it. Granting read-write on the
install directory changes nothing. - Not ACLs. The install tree already carries
ALL APPLICATION PACKAGES:(OI)(CI)(RX). - Not tier-specific. Same result on
appcontainer-dacl; the object namespace
boundary is a property of AppContainer, not of the tier.
Impact
Any MSYS2/Cygwin-based tool is unusable under processcontainer. This includes
git-bash, which is a common developer shell on Windows.
docs/learning-mode/capabilities.md already classifies \BaseNamedObjects as
unsupportedObjectType ("outside the supported diagnostic model"), so even with
captureDenials enabled this denial is filtered out of the actionable output and
appears only in verbose logging.
Activity
github-actions commentedon Aug 28, 2026
Triage summary
Container-Process— this is aprocesscontainer/ AppContainer backend issue on Windows.@jsidewhiteand@bbonaby(AppContainer / process isolation area).Needs-Triagehas been removed.The root cause is well-documented in the issue: AppContainer's named-object redirection (via
BaseGetNamedObjectDirectory) only covers Win32 APIs and does not rewrite absolute NT paths.msys-2.0.dllcallsNtCreateDirectoryObjectwith an absolute\BaseNamedObjects\...path, which bypasses the redirection and hits the global namespace access check.Maintainers: Comment
/investigateto check whether this issue or bug is valid against the most current code. Copilot will also produce a report with the changes that will be needed. For a small, unambiguous documentation or test fix, it may also create one draft PR.jsidewhite commentedon Sep 14, 2026
For Tier 1 to support,
get_session_parent_dir()to use a non-global namespaceSalah Khan (@SalahKhan-MSFT)
jsidewhite commentedon Sep 14, 2026
I tried to workaround it by ACL'ing the global object, but it didn't pan out.
11 remaining items
Cygwin: sec: grant ALL APPLICATION PACKAGES in _everyone_sd
xoviat commentedon Oct 28, 2026
working on this here: https://github.com/xoviat/cygwin/tree/mxc
xoviat commentedon Oct 28, 2026
it would be nice if the OS team could make processcontainer available on windows server github runners
Cygwin: sec: grant ALL APPLICATION PACKAGES in _everyone_sd
xoviat commentedon Oct 29, 2026
Root cause found and fixed — plus two things that may help the OS side
The chain behind this issue turned out to be one missing ACE in the Cygwin/MSYS runtime, with everything else downstream:
_everyone_sd()(winsup/cygwin/sec/helper.cc) granted only World (S-1-1-0). AppContainer processes are not covered by "Everyone", so every open of the runtime's named objects from inside the container was denied (0xC0000022) — including thewinpid.<N>symbolic link thatcygwin_pid()opens to map Windows PIDs to Cygwin PIDs.cygwin_pid()therefore returned 0 in the parent, sofork()returned 0 to the parent: both processes took the child branch. A pipeline ran its first element twice,trnever started, and script tails were lost.0xC00000B1(echo: write error, exit3328) — which is why the failure looked like named-object "degradation" rather than an access check.Fixes (all in
winsup/cygwin, shipped as a patch against this tree)sec/helper.cc:_everyone_sdnow adds an ALL APPLICATION PACKAGES (S-1-15-2-1) ACE;sec_acladditionally grants the confined token's logon SID (restricted tokens keep it enabled even when the user SID is deny-only) and the AppContainer package SID. This also fixes the signal-pipeWin32 error 5from Windows confinement after async fix: MSYS private-pipe DACL mismatch and named-object refusal; AllocConsole alone is insufficient buhuikongpan/dsh-win-gitbash#10.mm/shared.cc: shared-object parent directories fall back into the container's private namespace (\Sessions\<n>\AppContainerNamedObjects\<package SID>); DACL-less sections get an explicit descriptor (hardened sandboxes silently rewrite NULL DACLs and then deny siblings); an unmappable borrowed handle falls back to name-based reopen.fhandler/pipe.cc: absolute NT pipe names (opening the\Device\NamedPiperoot is denied in-container), CreatePipe-anonymous naming, create withoutOBJ_INHERIT+SetHandleInformationafterwards, re-duplicate pipe handles in fork fixup,sec_userfor pipe SAs.wincap.cc: fork-friendly capabilities only from the real kernel image (in_this_image).One PSEC gotcha worth documenting
PSEC force-relocates images that have not opted into ASLR per process, which breaks Cygwin's fork (it reconstructs the parent's address space in the child and needs identical layouts). Every image taking part in a fork — not just the runtime DLL — must carry the
DYNAMICBASEPE flag; a pristine Git-for-Windows install fails fork with0xC0000142in the child even with a patchedmsys-2.0.dll. We ship a tiny tool to set the flag (tools/ci/peflag.py), but if PSEC could keep non-opted images at stable per-file bases — or fail with a clearer diagnostic — that would save the next person a lot of time.Availability on GitHub runners (re: the note above)
Confirmed today:
windows-2022/windows-2025(Server SKUs) reportWindows ProcessContainer is unavailable: PSEC is not enabled, so the backend cannot run there at all. Thewindows-11-armimage (Windows 11 client) does have PSEC enabled and runs the ProcessContainer fine under x64 emulation — that is where our full verification runs in CI.Verification
tools/final-verify.shruns Git Bash inside the ProcessContainer and asserts fork/exec, pipelines, file I/O and job control (11 checks):Green locally (x64 Windows 11) and on the
windows-11-armCI image. The fixes live in themxcbranch linked above; builtmsys-2.0.dll/cygwin1.dllare attached to thev0.1.0release of that repository, and the DLL can be dropped into a Git-for-Windows install (plus the PE flag) to work in the container today.JimmyMederos commentedon Nov 2, 2026
Another data point from a second product, plus a question about getting the fix into stock runtimes.
We build SE Code, an open-source coding agent harness, and run each agent command in a ProcessContainer via
mxc-sdk1.0.1 (see our console use case in #1544). On Windows 11 25H2 build 26200.9457 with stock Git for Windows 2.49.0.windows.1 (msys-2.0.dll3.5.7), we hit the same failure through an indirect chain: native PowerShell → nativegit.exe→ Git'susr/bin/sh.exeduring a localgit fetch:git statusandgit commitin the same container succeed; the failure only appears once an MSYS descendant starts. That matters for harnesses: checking whether the initial command is Bash doesn't catch it, so today the only option we can offer users is an explicit per-command escape that drops filesystem and network containment, which is exactly what we'd like to avoid.xoviat, thanks for the root-cause write-up; the missing
S-1-15-2-1ACE explains everything we saw. Two questions:winsup/cygwinpatches headed to Cygwin upstream (and from there to MSYS2 / Git for Windows)? Asking users to drop a patchedmsys-2.0.dllinto their Git install and re-flag PE images isn't something we can ship, but a stock runtime that works in AppContainer would let us keep containment on by default.DYNAMICBASEimages breaking Cygwin fork seems worth either keeping stable per-file bases or emitting a clear diagnostic, as suggested above. A supported way to detect "this runtime cannot initialize in a container" before running the command would also help harnesses explain the failure instead of surfacing0xC0000022.Happy to test candidate builds of either on our host.
xoviat commentedon Nov 2, 2026
JimmyMederos I've been trying to get in touch with an msys2 maintainer, but I haven't received a response yet. I am willing to submit the patches but it would like a comment from an msys2 maintainer on the direction before I push patches to cygwin. I tried on chat, but will open an issue for this.
xoviat commentedon Nov 2, 2026
Also, it would be nice to get thoughts from a Windows OS developer to confirm that I'm on the right track.