Polyfill SA_RESETHAND on MacOS ARM64

This change solves the XNU crash loop mystery. Apple's documentation
claims to support this feature, but they only define the constant in
their header files. The kernel acknowledges thi SA_RESETHAND bit, by
clearing it from the sa_flags state, returns zero, and does nothing.
This commit is contained in:
Justine Tunney 2024-05-08 03:47:43 -07:00
parent 952b9009e8
commit 793393a341
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
3 changed files with 23 additions and 2 deletions

View file

@ -252,6 +252,12 @@ static int __sigaction(int sig, const struct sigaction *act,
rc = sys_sigaction(sig, ap, oldact, arg4, arg5);
} else {
rc = _sysret(__syslib->__sigaction(sig, ap, oldact));
// xnu silicon claims to support sa_resethand but it does nothing
// this can be tested, since it clears the bit from flags as well
if (!rc && oldact &&
(((struct sigaction_silicon *)ap)->sa_flags & SA_RESETHAND)) {
((struct sigaction_silicon *)oldact)->sa_flags |= SA_RESETHAND;
}
}
if (rc != -1) {
sigaction_native2cosmo((union metasigaction *)oldact);

View file

@ -30,6 +30,7 @@
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
@ -494,6 +495,8 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
struct __darwin_ucontext *xnuctx) {
#endif
// allocate signal frame on stack
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wframe-larger-than="
struct Goodies {
@ -502,10 +505,24 @@ privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
} g;
CheckLargeStackAllocation(&g, sizeof(g));
#pragma GCC pop_options
// handle signal
int rva, flags;
rva = __sighandrvas[sig];
if (rva >= kSigactionMinRva) {
flags = __sighandflags[sig];
#ifdef __aarch64__
// xnu silicon claims to support sa_resethand but it does nothing
// this can be tested, since it clears the bit from flags as well
if (flags & SA_RESETHAND) {
struct sigaction sa = {0};
__syslib->__sigaction(sig, &sa, 0);
__sighandflags[sig] = 0;
__sighandrvas[sig] = 0;
}
#endif
if (~flags & SA_SIGINFO) {
((sigaction_f)(__executable_start + rva))(sig, 0, 0);
} else {

View file

@ -394,8 +394,6 @@ relegated void __oncrash(int sig, struct siginfo *si, void *arg) {
BLOCK_CANCELATION;
SpinLock(&lock);
__oncrash_impl(sig, si, arg);
if (sig != SIGQUIT && sig != SIGTRAP)
_exit(1);
SpinUnlock(&lock);
ALLOW_CANCELATION;
}