Hello @derEremit, an AI analysis of a anti-cheat vendor is something that flat out can't be used to initiate discussion on a public issue tracker. By its nature, this isn't something that can be productively discussed on this issue tracker.
Feel free to note your experience without the AI analysis on the game's compatibility report at #9164.
PROTON_LOGx1 2026-05PROTON_LOG=1x1 2026-05PROTON_LOG=1**:x1 2026-05ntdll.dllx1 2026-05
Component / version
ValveSoftware/winedlls/ntdll/unix/signal_x86_64.c, functionsigsys_handler(under#ifdef HAVE_SECCOMP)CONFIG_SECCOMP=y, observed on 7.0.9 PREEMPT_RT and 7.0.9 SCHED_BORE (kernel-preempt-model-independent)Summary
sigsys_handleradvances%ripby+0xb(= 11 bytes) under the assumption that the trappingsyscallinstruction lives inside one of Wine's own 11-byte NT syscall trampolines. This holds when the trapping code is in Wine'sntdll.dllthunks, where the trampoline begins 9 bytes before thesyscalland the next valid instruction starts 2 bytes after it (total trampoline length 11 bytes ⇒rip + 0xblands at the next instruction in the caller).The assumption breaks for guest PE code that emits raw
syscallinstructions outside of Wine's thunks — notably Denuvo Anti-Cheat, which uses rawsyscallinstructions inside its VM-based anti-tamper logic to bypass any potential ntdll hooking. For those,rip + 0xblands 9 bytes into the middle of the next Denuvo VM instruction (or, as observed below, onto a deliberately-placedjmpback torip, forming a tight livelock).What is observed
PROTON_LOG=1 trace from Arc Raiders (Steam App 1808500, Denuvo Anti-Cheat-protected UE5):
PioneerGame-d.exeis loaded at PE base0x140000000;rip = 0x14a849ef0is at file offset0xa849ef0(≈ 177 MB into the Denuvo-wrapped binary).rax = 0xffffffffis not a valid NT syscall index — a classic Denuvo anti-tamper bogus-syscall pattern.Root cause
The current
sigsys_handlerdoes (lightly elided):__wine_syscall_dispatcherperforms the NT syscall translation in user-space, then returns toframe->rip(= original%rip + 0xb).For Wine's own NT syscall thunks the
+0xbis correct: the thunk has a fixed 11-byte form ending in thesyscallinstruction's 2 bytes;rip + 0xblands at the first byte after the thunk.For raw
syscallinstructions in non-Wine PE code (Denuvo, VMProtect, custom DRM, etc.) the+0xbis wrong — it skips 11 bytes into whatever happens to live there. In Denuvo's case (this report), the bytes atrip + 11constitute (or eventually reach) ajmpback to the trappingrip, producing a livelock visible as 100M+ identical SIGSYS entries.Three observed failure modes from the same root cause:
ntsync_char_ioctl+0x638waiting for primitives the spinner is supposed to signal. Symptom = sustained microstutter until process kill. (Originally misdiagnosed as a kernelntsynclost-wakeup — seentsync_deadlock_report.md.)+0xblands on a slightly different decode and Denuvo's VM eventually executes an instruction reading from%rax(= bogus pointer like0xfffffffffffff280), triggeringSIGSEGVin user code. Symptom = hard game crash. (arc_segv_20260526_114343.txt.)+sehtrace logging slows the trap rate and the game limps along while filling~/steam-1808500.logat ~MB/s. Symptom = bimodal stutter (this report's primary trace).Suggested fix
Validate
raxagainst the syscall table before advancing%rip. For invalidrax, do not enter the dispatcher; instead setrax = STATUS_INVALID_PARAMETER(or similar) and advance%ripby only+2(sizeofsyscallinstruction).Sketch:
(
__wine_syscall_dispatcher_table_sizeis illustrative — the actual check should mirror whatever bounds-check__wine_syscall_dispatcherdoes internally.)This is consistent with the existing fast-path for
rax == 0xffff(theinstall_bpftest syscall), which already short-circuits without entering the dispatcher.Caveats
rip, the proposed fix bounds the trap rate but does not prevent the livelock. In that case the only remaining defense is to refuse to dispatch the same(rip, rax)pair more than N times per second — an explicit rate-limit onsigsys_handler. This is uglier but salvageable: even an N=10 limit would change a hard livelock into "Denuvo VM gets one trap response per 100 ms".Why this matters
Affects Wine/Proton compatibility with all Denuvo Anti-Cheat-protected titles that exercise the VM tripwire mid-session. Currently manifests as either:
Both have been widely reported under "Arc Raiders" specifically (ProtonDB, Proton issue tracker, r/linux_gaming), without prior identification of the root cause.
14_kernel_stacks.txt