Skip to content

Cygwin: Guard XSAVE allocation against broken CPUID emulation - #378

Open
LarsDammannCoherent wants to merge 1 commit into
msys2:msys2-3.6.10from
LarsDammannCoherent:protect-from-broken-cpuid
Open

LarsDammannCoherent wants to merge 1 commit into
msys2:msys2-3.6.10from
LarsDammannCoherent:protect-from-broken-cpuid

Conversation

@LarsDammannCoherent

@LarsDammannCoherent LarsDammannCoherent commented Oct 6, 2026 •

Copy link
Copy Markdown

Protect sigdelayed from CPUID emulation that leaves the upper 32 bits of RBX stale when querying the XSAVE area size.

If the upper half of RBX contains stale bits after CPUID, sigdelayed uses the full-width value of RBX and attempts a multi-gigabyte stack adjustment, causing an access violation. This was reproduced on a system with TwinCAT eXtended Automation Runtime (XAR) in RUN mode. The problem does not reproduce when TwinCAT XAR is in CONFIG mode.

The suspected cause is a TwinCAT CPUID virtualization handler that writes only the lower 32 bits of a saved register, leaving stale data in the upper half of RBX.

Reproduction

On an affected system, in powershell:

& 'C:\Program Files\Git\bin\sh.exe' -c 'v=$(echo Hello); echo $v'

With TwinCAT RUN mode enabled, the unpatched runtime exits with 0xC0000005 before producing output.
With TwinCAT in CONFIG mode, it prints Hello and exits with 0.

Change

Zero-extend EBX immediately after CPUID(0xD, 0) and before using RBX as a 64-bit value. This protects both the XSAVE stack adjustment and the subsequent XSAVE-buffer clearing operation. For conforming CPUID implementations, the upper 32 bits are already zero, so this change does not alter the result.

As supporting context, consider that Microsoft鈥檚 CPUID wrappers likewise expose each result only as a 32-bit value:

Tests

  • Reproduced the crash with the unpatched msys-2.0.dll and TwinCAT RUN mode
  • Confirmed the command works in CONFIG mode.
  • Got the msys-2.0.dll from this PR and replaced the one from my local git 2.54 and Visual Studio 2026 embedded MinGit 2.54
  • Confirmed that the above reproduce and git submodule commands work in git bash, both in TwinCAT RUN and CONFIG mode
  • Confirmed that Visual Studio can perform git submodule commands while TwinCAT is in RUN mode

CPUID(0xD, 0) returns the XSAVE area size in the low 32 bits of
RBX. A conforming implementation clears the upper 32 bits, but
broken CPUID emulation may leave the upper half of the register stale.

This was observed when TwinCAT eXtended Automation Runtime (XAR) was
running. Its kernel-level real-time component appears to intercept
CPUID and restore only the lower half of a saved register, allowing
stale upper bits to leak into unrelated processes.

MSYS2's sigdelayed uses the full-width RBX value both for XSAVE stack
allocation and, after copying it to RCX, for clearing the XSAVE
buffer. Stale upper bits can therefore turn a small allocation into a
multi-gigabyte stack adjustment and cause an access violation.

Zero-extend EBX immediately after CPUID, before using RBX as a 64-bit
value. This has no effect on conforming implementations and protects
against broken CPUID emulation.

Addresses: msys2#363

Signed-off-by: Lars Dammann <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant