SA_RESETHAND breaks SA_SIGINFO on ARM
| Originator: | landon.j.fuller | ||
| Number: | rdar://11839803 | Date Originated: | 10-Jul-2012 11:09 AM |
| Status: | Open | Resolved: | |
| Product: | Mac OS X | Product Version: | 12A269 |
| Classification: | Serious Bug | Reproducible: | Always |
10-Jul-2012 11:09 AM Landon Fuller:
Summary:
When a signal handler is registered with SA_RESETHAND|SA_SIGINFO, xnu will reset the handler flags prior to signal dispatch, and the Libc's __sigtramp will be called with a sigstyle of UC_TRAD. If SA_RESETHAND is not specified, then __sigtramp is called with a sigstyle of UC_FLAVOR.
On x86-64, the Libc __sigtramp implementation ignores the sigstyle argument and provides the SA_SIGINFO arguments to the signal handler; this appears to result in the code working by accident on Mac OS X.
I do not have access to the ARM xnu or Libc implementations, but empirically and in contrast to Mac OS X, SA_RESETHAND causes an invalid siginfo_t argument to be passed to a SA_SIGINFO-registered handler.
Steps to Reproduce:
Test code that will demonstrate this bug. It will output the pointer value of the siginfo_t argument, and then attempt to dereference it.
#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
// not async-safe. it's demo code.
static void signal_handler (int signal, siginfo_t *info, void *uap) {
fprintf(stderr, "signal=%d, siginfo=%p, uap=%p\n", signal, info, uap);
// The following may crash
fprintf(stderr, "si_signo=%d\n", signal, info->si_signo);
exit(0);
}
void configure_handler () {
/* Configure action */
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO|SA_RESETHAND;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = &signal_handler;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
}
int main (int argc, char *argv[]) {
configure_handler();
*((uint8_t*)NULL) = 0;
return 0;
}
Compile with
gcc test.c -o test
Expected Results:
Here are the expected results on an assortment of platforms:
darwin-i386:
signal=10, siginfo=0xc00e0950, uap=0xc00e0990
si_signo=10
darwin-x86_64:
signal=11, siginfo=0x7fff647847e0, uap=0x7fff64784848
si_signo=11
freebsd-x86_64:
signal=11, siginfo=0x7fffffffd7c0, uap=0x7fffffffd450
si_signo=11
linux_x86_64:
signal=11, siginfo=0x7fff1b9de5b0, uap=0x7fff1b9de480
si_signo=11
Actual Results:
On darwin-armv7, we get the following result:
> ./test
signal=11, siginfo=0x1, uap=0xb
[crashes here]
The siginfo and uap arguments are clearly garbage. If we remove SA_RESETHAND, the code works as expected, but obviously we lose the functionality of SA_RESETHAND:
> ./test
signal=11, siginfo=0x2fdffbf8, uap=0x2fdffc3c
si_signo=11
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
Just to clarify spec issues -- the interpretation I provided matches the behavior of:
Linux
FreeBSD (https://svnweb.freebsd.org/base?view=revision&revision=275120 -- this commit fixes the behavior after it was accidentally broken ~10 months back)
Solaris (http://fxr.watson.org/fxr/source/common/os/sig.c?v=OPENSOLARIS#L1371)
POSIX.1-2008 states:
SA_SIGINFO:
This seems unassailable on its own.
SA_RESETHAND:
"If set, the disposition of the signal shall be reset to SIG_DFL and the SA_SIGINFO flag shall be cleared on entry to the signal handler."
"Otherwise, the disposition of the signal shall not be modified on entry to the signal handler."
The interpretation of this seems pretty clear, but for the sake of argument, let's pretend that "the SA_SIGINFO flag shall be cleared on entry to the signal handler" actually means that the signal handler should be called as if the flag was cleared.
If that was the case, then wouldn't resetting the signal's disposition to "SIG_DFL" also apply? And if so, then the signal handler wouldn't be called at all.
This hypothetical interpretation would also be in direct conflict with the spec on the behavior of SA_SIGINFO specified above.
Any remaining perceived ambiguity in the specification can be put to rest with Occam's Razor; does POSIX intentionally knee-cap SA_RESETHAND by specifying a useless behavioral quirk that is internally inconsistent with POSIX's SA_SIGINFO specification? And is this interpretation correct despite being in conflict with Linux, Solaris, and FreeBSD?
22-Jun-2015 01:40 PM
Apple just closed the bug as follows:
There are no plans to address this.
We are now closing this report.
If you have questions about the resolution, or if this is still a critical issue for you, then please update your bug report with that information.
Please be sure to regularly check new Apple releases for any updates that might affect this issue.
Looking at the ARM __sigtramp disassembly, it checks if sigstyle == 1. If so, it leaves r1 and r2 with stale data. r1 will have #1 as a constant, matching the siginfo=0x1 output demonstrated above. r2 will be left with the signo value in place, matching the uap=0xb when signal=11 output demonstrated above.
Thus, it appears that ARM, like darwin x86/x86-64, has sigstyle set to the non-siginfo constant when control is passed to __sigtramp, but unlike x86/x86-32, the ARM __sigtramp conditionally skips populating the siginfo and uap argument values.