Re: [RFC] signal: per-thread control over alternate signal stack delivery for selected signals
Tim Parth <[email protected]> Tue, 21 Jul 2026 09:08:22 +0000
| Newsgroups | org.kernel.vger.linux-api,org.kernel.vger.linux-arch,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <AM6PR05MB490384CB834573A0AA94CCD1E1C22@AM6PR05MB4903.eurprd05.prod.outlook.com> |
Hi, gentle ping on this RFC after four weeks. Adding Oleg Nesterov to Cc becaus= e this concerns signal and sigaltstack semantics. The concrete question I am trying to resolve is whether the interaction bet= ween process-wide SA_ONSTACK and per-thread sigaltstack in processes hostin= g multiple language runtimes is expected to be handled entirely in userspac= e. In the reproducer, Go enables SA_ONSTACK on an existing CoreCLR signal hand= ler, causing CoreCLR's SIGRTMIN handler to run on a 16 KiB alternate stack = and overflow it. Increasing the stack is a practical mitigation for this pa= rticular case, but does not provide a way for independent runtimes to compo= se their stack requirements. Before attempting a proof-of-concept patch, I would appreciate guidance on = one point: Would an opt-in per-thread mechanism for excluding selected signals from SA= _ONSTACK delivery be considered a potentially acceptable UAPI direction, or= is such a mechanism fundamentally undesirable? If this discussion belongs on another list or should include particular mai= ntainers, please let me know. Thanks, Tim > -----Urspr=FCngliche Nachricht----- > Von: Tim Parth > Gesendet: Dienstag, 23. Juni 2026 08:30 > An: '[email protected]' <[email protected]> > Cc: [email protected]; [email protected] > Betreff: [RFC] signal: per-thread control over alternate signal stack del= ivery for > selected signals >=20 > Hi, >=20 > I am looking for guidance on a Linux signal ABI limitation that shows up = in > multi-runtime processes, specifically a .NET host loading a Go c-shared l= ibrary. >=20 > Disclaimer: I am reporting this from the application/runtime integration = side, > not as a kernel developer. I arrived here after tracing crashes in a .NET > application hosting a Go shared library through several runtime-specific = issues, > reproductions, and analyses. My understanding of the Linux signal subsyst= em > and ABI details is therefore limited, and I may be missing important deta= ils. >=20 > The technical summary below reflects my best understanding of the issue > based on the referenced investigations. I used AI-assisted editing to hel= p > structure and clarify this report, but the observations, reproducer, and > referenced analyses come from the linked investigations. >=20 > This is not a claim that the current kernel behavior violates the existin= g ABI. > Rather, I believe the current ABI lacks a way for multiple language runti= mes in > the same process to compose their signal and sigaltstack requirements saf= ely. >=20 > Observed failure > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > A .NET process loads a Go shared library built with -buildmode=3Dc-shared= and > calls it via P/Invoke. Under stress, the process crashes with SIGSEGV whi= le > CoreCLR is handling SIGRTMIN for runtime activation / GC suspension. >=20 > The reproducer is here: >=20 > https://github.com/egonelbre/csharp-go-interop-issue/tree/main/dotnet- > go-reproducer >=20 > Related runtime issues: >=20 > https://github.com/golang/go/issues/78883 > https://github.com/dotnet/runtime/issues/127320 >=20 > The .NET-side analysis shows that the crash happens inside CoreCLR's > inject_activation_handler path. The kernel delivered SIGRTMIN on the thre= ad's > alternate signal stack, and CoreCLR then ran a call chain deep enough to > overflow that stack. In the reported case the per-thread alternate stack > installed by CoreCLR was 16 KiB. Increasing it to around 49 KiB avoids th= e > crash in the provided stress test, but that is a runtime-specific mitigat= ion and > does not address the general ABI composition problem. >=20 > Current ABI interaction > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > The problematic interaction is: >=20 > 1. Signal disposition, including SA_ONSTACK, is per-process. > 2. sigaltstack is per-thread. > 3. On signal delivery, Linux uses the alternate signal stack if the handl= er has > SA_ONSTACK and the current thread has an alternate stack. > 4. The Go runtime documents that non-Go signal handlers must use > SA_ONSTACK, because Go may be running on limited stacks. For - > buildmode=3Dc-shared, when Go sees an existing signal handler it may turn= on > SA_ONSTACK and otherwise keep the existing handler. > 5. CoreCLR has internal signals such as SIGRTMIN whose handlers may need = a > different stack policy or a larger stack budget than the alternate stack = currently > registered on that thread. >=20 > The result is that one runtime can make a process-wide SA_ONSTACK decisio= n > that affects handlers and threads owned by another runtime. The other > runtime can install a larger per-thread sigaltstack, but that becomes an = arms > race and does not give a runtime any way to express which signals should = use > which stack policy on a particular thread. >=20 > Why existing mechanisms do not fully solve this > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > - Raising SIGSTKSZ or MINSIGSTKSZ does not solve the general issue. The > kernel can only know the signal frame requirements, not the maximum user- > space stack consumption of an arbitrary signal handler and everything it = calls. >=20 > - The kernel cannot automatically extend an alternate signal stack. >=20 > - Clearing SA_ONSTACK with sigaction is process-wide and can violate the > requirements of another runtime, for example Go's requirement that signal > handlers run on an alternate stack when Go code may be interrupted. >=20 > - SS_AUTODISARM helps with a different class of problems, such as avoidin= g > corruption when switching away from a signal handler, but it does not let= a > thread express "use an alternate stack for SIGSEGV but not for this runti= me- > internal suspension signal", nor does it provide separate stack policies = for > different signals. >=20 > Possible ABI direction > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > One possible direction would be an opt-in, per-thread signal-altstack pol= icy, > for example a prctl() or similar interface that lets a thread provide a s= ignal mask > for which SA_ONSTACK should be ignored on that thread: > PR_SET_SIGALTSTACK_EXCLUDE_MASK(sigset_t *mask, size_t sigsetsize) >=20 > The default mask would be empty, preserving current behavior. Signal deli= very > would then become, conceptually: >=20 > if (handler_has_SA_ONSTACK && > thread_has_altstack && > !signal_is_in_current_thread_altstack_exclude_mask) > deliver_on_altstack; > else > deliver_on_normal_stack; >=20 > This is only a sketch. I am not attached to this exact interface. Another= shape > might be preferable, such as a more general per-thread/per-signal alterna= te > stack policy or a way to associate alternate stack requirements with part= icular > signals. >=20 > Questions > =3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > 1. Is the signal maintainers' view that multi-runtime processes should so= lve > this entirely in userspace by agreeing on one sufficiently large per-thre= ad > sigaltstack? >=20 > 2. Would a per-thread/per-signal opt-in policy for alternate signal stack > delivery be considered acceptable as a Linux UAPI extension? >=20 > 3. If such a UAPI is plausible, is prctl() the right place, or would main= tainers > prefer a different interface? >=20 > 4. Which subsystem/list should own this discussion? I am sending this fir= st to > linux-api and LKML because this appears to be a userspace ABI issue aroun= d > signal delivery. >=20 > Environment from the reproducer report > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > - Architecture: x86_64 > - OS: Linux > - Example distro: Ubuntu 24.04 > - Go: go1.26.2 linux/amd64 > - .NET: 10.0.6 and runtime main were tested in the linked report > - Signal involved in the reproducer: SIGRTMIN > - Failure mode: SIGSEGV while running CoreCLR activation handling on the > alternate signal stack >=20 > Thanks, >=20 > Tim Parth