Re: RFC: ENOSYS vs SIGSYS for FreeBSD ABIs

Jan Martin Mikkelsen <[email protected]> Wed, 22 Apr 2026 21:56:24 +0200
Newsgroups gmane.os.freebsd.architechture
Message-ID <[email protected]>
On 18 Apr 2026, at 18:04, John Baldwin <[email protected]> wrote:
>=20
> 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=3D39513&view=
=3Dmarkup).
>=20
> =46rom 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).
>=20
> 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.
>=20
> 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.
>=20
> On the other side, I have _never_ had SIGSYS be an aid.  It's only =
gotten
> in the way.
>=20
> 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.
>=20
> 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.
>=20
> 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.



I have had SIGSYS be an aid.

SIGSYS stops a process that attempts to use a system call that does not =
exist, without requiring a test. ENOSYS requires a user mode process to =
check every system call return value correctly, and then correctly =
decide what to do. Correctness on rare paths is not always there.

Using SIGSYS by default eliminates the class of failure when the user =
mode process failed to check and handle ENOSYS correctly. I think that =
is the core idea behind the statement =E2=80=9Crelying on ENOSYS vs =
SIGSYS is harmful.=E2=80=9D

Assume ENOSYS: What do you do if the system call you want doesn=E2=80=99t =
exist? Code a fallback strategy, like =E2=80=9Crename(2) isn=E2=80=99t =
there, I=E2=80=99ll try link(2) and then unlink(2)=E2=80=9D? Just say =
"it didn=E2=80=99t matter anyway=E2=80=9D? Or just kill the process as =
if SIGSYS was sent?

The arguments I read here are about special cases as a FreeBSD =
developer. People messing around with CURRENT are knowledgeable enough =
to change a sysctl without changing the default for everyone.

If I deploy a binary to a system that uses an unimplemented system call, =
I want that process to die quickly. Fail-fast. Explicitly handling these =
cases is not worth thinking about if you can just get SIGSYS.


Jan M.