Skip to content

Commit fec2c34

Browse files
EliahKaganclaude
andcommitted
Add a diagnostic job demonstrating the TokenOwner mechanism
Temporarily add a `diag-token` job to `.github/workflows/cygwin-test.yml` that creates a directory through four code paths and reports its NTFS Owner. The intent is to empirically establish the cause of the Owner asymmetry that will be described in detail by a later commit on this chain: a Cygwin or Cygwin-derived runtime (`cygwin1.dll` for Cygwin git; `msys-2.0.dll` loaded by Git for Windows's bundled MSYS2 `sh.exe`) rewrites the process token's `TokenOwner` field at DLL initialization, and `CreateProcessW` propagates that mutation to every descendant. The four tests are: | Test | Chain | Predicted Owner | | ---- | ---------------------------------------------- | ------------------------ | | A | PowerShell `New-Item` | `BUILTIN\Administrators` | | D | Cygwin `mkdir` | `runneradmin` (197108) | | F | Cygwin bash -> Git for Windows `git init` | `runneradmin` (197108) | | G | PowerShell -> Git Bash -> PowerShell `New-Item`| `runneradmin` (197108) | A is the Win32 baseline. The kernel-default `TokenOwner` for `runneradmin`'s full administrative token is `BUILTIN\Administrators`, because `runneradmin` is the built-in local Administrator (RID 500) and `FilterAdministratorToken=0` exempts it from UAC token filtering. D is the Cygwin baseline. Cygwin's `cygheap_user::init` calls `NtSetInformationToken(TokenOwner, &user_sid, ...)` at DLL init, and the resulting Owner reflects the rewritten token. F is the load-bearing case. The child is a Win32 binary that loads no Cygwin runtime of its own. It produces a user-owned `.git`, proving that the rewrite performed by the parent Cygwin bash propagates through `CreateProcessW`'s token duplication to a Win32 descendant. G strengthens the case: the first and last links are pure Win32 (a fresh PowerShell using its own `New-Item` builtin), and only the middle link is a Cygwin-family runtime (Git for Windows's bundled MSYS2 `bash.exe`, linked against `msys-2.0.dll`). The directory is still user-owned, proving the mechanism does not depend on git, on shell-dispatch via `git submodule`, or on any property of the final-link binary -- only on whether *some* process in the ancestry has loaded a Cygwin-family runtime. This `diag-token` job, like the `reproduce-safe-dir` matrix added in the previous commit, is temporary and should be removed before this work is integrated. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f4ce395 commit fec2c34

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

.github/workflows/cygwin-test.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,73 @@ jobs:
102102
run: |
103103
pytest --color=yes -p no:sugar --instafail -vv ${{ matrix.additional-pytest-args }}
104104
105+
diag-token:
106+
runs-on: windows-latest
107+
108+
env: *cygwin-env
109+
110+
defaults: *cygwin-defaults
111+
112+
steps:
113+
- *force-lf
114+
- *checkout
115+
- *install-cygwin
116+
117+
- name: PowerShell-side token state and file-creation tests
118+
shell: pwsh
119+
run: |
120+
$repo = "D:\a\GitPython\GitPython"
121+
Write-Host "==================== whoami /all (PowerShell) ===================="
122+
whoami /all
123+
Write-Host ""
124+
Write-Host "==================== Test A: PowerShell New-Item directory ===================="
125+
$td = "$repo\test-pwsh-mkdir"
126+
New-Item -ItemType Directory -Path $td -Force | Out-Null
127+
$acl = Get-Acl -LiteralPath $td
128+
Write-Host "Owner of $td : $($acl.Owner)"
129+
Remove-Item $td -Force
130+
Write-Host ""
131+
Write-Host "==================== Test G: PowerShell -> Git Bash -> PowerShell New-Item ===================="
132+
$td4 = "$repo\test-pwsh-bash-pwsh-mkdir"
133+
$scriptPath = "$repo\inner-mkdir.ps1"
134+
"New-Item -ItemType Directory -Path '$td4' -Force | Out-Null" |
135+
Set-Content -Path $scriptPath -Encoding utf8
136+
$env:MSYS2_ARG_CONV_EXCL = '*'
137+
try {
138+
& "C:\Program Files\Git\bin\bash.exe" -c "powershell.exe -NoProfile -ExecutionPolicy Bypass -File '$scriptPath'" 2>&1 | Out-Null
139+
} finally {
140+
Remove-Item Env:MSYS2_ARG_CONV_EXCL -ErrorAction SilentlyContinue
141+
}
142+
if (Test-Path -LiteralPath $td4) {
143+
$acl = Get-Acl -LiteralPath $td4
144+
Write-Host "Owner of $td4 (PowerShell -> bash -> PowerShell New-Item) : $($acl.Owner)"
145+
Remove-Item $td4 -Force
146+
} else {
147+
Write-Host "Owner of $td4 (PowerShell -> bash -> PowerShell New-Item) : (directory not created)"
148+
}
149+
Remove-Item $scriptPath -Force -ErrorAction SilentlyContinue
150+
151+
- name: Cygwin-side token state and file-creation tests
152+
run: |
153+
set +e
154+
echo "==================== id (Cygwin) ===================="
155+
id
156+
echo
157+
echo "==================== Test D: Cygwin mkdir ===================="
158+
td="$(pwd)/test-cygwin-mkdir"
159+
mkdir "$td"
160+
echo "Owner: $(stat -c '%U(%u)' "$td")"
161+
rmdir "$td"
162+
echo
163+
echo "==================== Test F: Cygwin-spawned Git for Windows git init ===================="
164+
td3="$(pwd)/test-cygwin-spawns-wingit"
165+
mkdir "$td3"
166+
( cd "$td3" && /cygdrive/c/Program\ Files/Git/bin/git.exe init -q )
167+
echo "Owner of $td3 (Cygwin-mkdir) : $(stat -c '%U(%u)' "$td3")"
168+
echo "Owner of $td3/.git (Cygwin->Win git init): $(stat -c '%U(%u)' "$td3/.git")"
169+
rm -rf "$td3"
170+
true
171+
105172
reproduce-safe-dir:
106173
strategy:
107174
matrix:

0 commit comments

Comments
 (0)