sigaction.2: Document SA_EXPOSE_TAGBITS and the flag support detection protocol

Signed-off-by: Peter Collingbourne <pcc@google.com>
Signed-off-by: Alejandro Colomar <alx.manpages@gmail.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Peter Collingbourne 2021-08-08 10:41:12 +02:00 committed by Michael Kerrisk
parent 9b6cce9936
commit 7dd4af5158
1 changed files with 123 additions and 0 deletions

View File

@ -261,6 +261,44 @@ This flag is meaningful only when establishing a signal handler.
.\" .I sa_sigaction
.\" field was added in Linux 2.1.86.)
.\"
.TP
.B SA_UNSUPPORTED
Used to dynamically probe for flag bit support.
.IP
If an attempt to register a handler succeeds with this flag set in
.I act->sa_flags
alongside other flags that are potentially unsupported by the kernel,
and an immediately subsequent
.BR sigaction ()
call specifying the same signal number n and with non-NULL
.I oldact
yields
.B SA_UNSUPPORTED
.I clear
in
.IR oldact->sa_flags ,
then
.I oldact->sa_flags
may be used as a bitmask
describing which of the potentially unsupported flags are,
in fact, supported.
See the section "Dynamically probing for flag bit support"
below for more details.
.TP
.BR SA_EXPOSE_TAGBITS " (since Linux 5.11)"
Normally, when delivering a signal,
an architecture-specific set of tag bits are cleared from the
.I si_addr
field of
.IR siginfo_t .
If this flag is set,
an architecture-specific subset of the tag bits will be preserved in
.IR si_addr .
.IP
Programs that need to be compatible with Linux versions older than 5.11
must use
.B SA_UNSUPPORTED
to probe for support.
.SS The siginfo_t argument to a SA_SIGINFO handler
When the
.B SA_SIGINFO
@ -846,6 +884,91 @@ Triggered by a
.BR seccomp (2)
filter rule.
.RE
.SS Dynamically probing for flag bit support
The
.BR sigaction ()
call on Linux accepts unknown bits set in
.I act->sa_flags
without error.
The behavior of the kernel starting with Linux 5.11 is that a second
.BR sigaction ()
will clear unknown bits from
.IR oldact->sa_flags .
However, historically, a second
.BR sigaction ()
call would typically leave those bits set in
.IR oldact->sa_flags .
.PP
This means that support for new flags cannot be detected
simply by testing for a flag in
.IR sa_flags ,
and a program must test that
.B SA_UNSUPPORTED
has been cleared before relying on the contents of
.IR sa_flags .
.PP
Since the behavior of the signal handler cannot be guaranteed
unless the check passes,
it is wise to either block the affected signal
while registering the handler and performing the check in this case,
or where this is not possible,
for example if the signal is synchronous, to issue the second
.BR sigaction ()
in the signal handler itself.
.PP
In kernels that do not support a specific flag,
the kernel's behavior is as if the flag was not set,
even if the flag was set in
.IR act->sa_flags .
.PP
The flags
.BR SA_NOCLDSTOP ,
.BR SA_NOCLDWAIT ,
.BR SA_SIGINFO ,
.BR SA_ONSTACK ,
.BR SA_RESTART ,
.BR SA_NODEFER ,
.BR SA_RESETHAND ,
and, if defined by the architecture,
.B SA_RESTORER
may not be reliably probed for using this mechanism,
because they were introduced before Linux 5.11.
However, in general, programs may assume that these flags are supported,
since they have all been supported since Linux 2.6,
which was released in the year 2003.
.PP
The following example program exits with status 0 if
.B SA_EXPOSE_TAGBITS
is determined to be supported, and 1 otherwise.
.PP
.EX
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handler(int signo, siginfo_t *info, void *context) {
struct sigaction oldact;
if (sigaction(SIGSEGV, 0, &oldact) == 0 &&
!(oldact.sa_flags & SA_UNSUPPORTED) &&
(oldact.sa_flags & SA_EXPOSE_TAGBITS)) {
_exit(0);
} else {
_exit(1);
}
}
int main(void) {
struct sigaction act = {0};
act.sa_flags = SA_SIGINFO | SA_UNSUPPORTED | SA_EXPOSE_TAGBITS;
act.sa_sigaction = handler;
if (sigaction(SIGSEGV, &act, 0) != 0) {
perror("sigaction");
return 1;
}
raise(SIGSEGV);
}
.EE
.SH RETURN VALUE
.BR sigaction ()
returns 0 on success; on error, \-1 is returned, and