RFC: ENOSYS vs SIGSYS for FreeBSD ABIs

John Baldwin <[email protected]> Sat, 18 Apr 2026 12:04:42 -0400
Newsgroups gmane.os.freebsd.architechture
Message-ID <[email protected]>
FreeBSD has a longstanding behavior of sending a SIGSYS signal to a thread
that invokes an invalid system call.  This behavior was inherited from BSD
from a commit from Mike Karels whose log message is "POSIX changes"
(https://svnweb.freebsd.org/csrg/sys/kern/kern_sig.c?revision=39513&view=markup).

 From what I can tell though, while POSIX documents both ENOSYS and SIGSYS,
it does not document the semantics of these (and the one reference I could
find to SIGSYS specifically noted that the semantics aren't documented since
there aren't any consistent semantics across systems).

Linux does not send SIGSYS for an invalid system call, but instead returns
ENOSYS which motivated several changes from kib@ a few years ago which,
amony other things, makes FreeBSD's behavior as there is now a sysctl to
determine if the FreeBSD ABIs raise SIGSYS or just return ENOSYS.

In my experience to date, I have generally found SIGSYS a pain.  While we
don't generally support forwards compatibility (newer world on older
kernel), it sometimes happens, and it's really annoying to have init, etc.
all die on boot (resulting in an instant panic in the case of init).
This is especially true if one is adding a new "advisory" system call for
which the program can still run fine if the syscall fails.  However, there
is not a really easy way to deal with this, particularly in library code.
Installing a handler for SIGSYS (or just ignoring it), means a library
has to stomp on process state that typically should be managed by the
main binary.  The other alternative is to try to do extra checks to determine
if a syscall might work before you invoke it, whether that's
kern.feature.foo sysctls (but that does mean invoking yet-another-syscall
before the one you actually care about), or AT_BSDFLAGS, etc.

On the other side, I have _never_ had SIGSYS be an aid.  It's only gotten
in the way.

Over in CheriBSD land we just got bitten by this (again) for a system call
that is purely advisory (permits adding a label to memory regions that you
can see in procstat -v, etc., but isn't needed for functionality) due to
some of the cross-threading we have between kernels and worlds which is why
this is top of my mind again.

Both OpenBSD and NetBSD still send SIGSYS.  To deal with SIGSYS in /sbin/init,
all of the BSDs imported a change from BSDI after 4.4BSD that ignored the
first 25 errors, but both FreeBSD and OpenBSD have removed that (NetBSD still
has it).  The log message for our removal claims that relying on ENOSYS vs
SIGSYS is harmful, but I'm less convinced that that is true.  You have to
have code invoking a system call that doesn't check for errors for SIGSYS
to actually be useful.

My (long-winded) proposal is to change the default setting of the sysctl kib@
added a few years ago such that we only return ENOSYS by default.  Folks who
really want SIGSYS could still opt-in via the sysctl/loader tunable, but I
feel that ENOSYS really is the better default behavior instead of SIGSYS.

-- 
John Baldwin