* [PATCH] parisc: Fix double SIGFPE crash
@ 2025-05-03 16:38 deller
2025-05-03 17:18 ` John David Anglin
0 siblings, 1 reply; 2+ messages in thread
From: deller @ 2025-05-03 16:38 UTC (permalink / raw)
To: linux-parisc; +Cc: Helge Deller, John David Anglin, Camm Maguire
From: Helge Deller <deller@gmx.de>
Camm noticed that on parisc a SIGFPE exception may triggger a second
SIGFPE in the glibc part of the signal handler which then finally leads
to a crash of the program.
This can easily be reproduced with this test program which will abort in the
second SIGFPE.
root@parisc:~# cat fpe.c
static void fpe_func(int sig, siginfo_t *i, void *v) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGFPE);
sigprocmask(SIG_UNBLOCK, &set, NULL);
printf("GOT signal %d with si_code %ld\n", sig, i->si_code);
}
int main() {
struct sigaction action = {
.sa_sigaction = fpe_func,
.sa_flags = SA_RESTART|SA_SIGINFO };
sigaction(SIGFPE, &action, 0);
feenableexcept(FE_OVERFLOW);
return printf("%lf\n",1.7976931348623158E308*1.7976931348623158E308);
}
root@parisc:~# gcc fpe.c -lm
root@parisc:~# ./a.out
Floating point exception
root@parisc:~# strace -f ./a.out
execve("./a.out", ["./a.out"], 0xf9ac7034 /* 20 vars */) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
...
rt_sigaction(SIGFPE, {sa_handler=0x1110a, sa_mask=[], sa_flags=SA_RESTART|SA_SIGINFO}, NULL, 8) = 0
--- SIGFPE {si_signo=SIGFPE, si_code=FPE_FLTOVF, si_addr=0x1078f} ---
--- SIGFPE {si_signo=SIGFPE, si_code=FPE_FLTOVF, si_addr=0xf8f21237} ---
+++ killed by SIGFPE +++
Floating point exception
Fix this by clearing the Trap (T) bit in the FP status register before
returning to the signal handler in userspace.
Signed-off-by: Helge Deller <deller@gmx.de>
Suggested-by: John David Anglin <dave.anglin@bell.net>
Reported-by: Camm Maguire <camm@maguirefamily.org>
---
arch/parisc/math-emu/driver.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c
index 34495446e051..15f183cbe915 100644
--- a/arch/parisc/math-emu/driver.c
+++ b/arch/parisc/math-emu/driver.c
@@ -97,9 +97,19 @@ handle_fpe(struct pt_regs *regs)
memcpy(regs->fr, frcopy, sizeof regs->fr);
if (signalcode != 0) {
- force_sig_fault(signalcode >> 24, signalcode & 0xffffff,
- (void __user *) regs->iaoq[0]);
- return -1;
+ int sig = signalcode >> 24;
+
+ if (sig == SIGFPE) {
+ /*
+ * Clear floating point trap bit to avoid trapping
+ * again on the first fstd/fld access in the userspace
+ * signal handler.
+ */
+ regs->fr[0] &= ~(1ULL << 38);
+ }
+ force_sig_fault(sig, signalcode & 0xffffff,
+ (void __user *) regs->iaoq[0]);
+ return -1;
}
return signalcode ? -1 : 0;
--
2.47.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] parisc: Fix double SIGFPE crash
2025-05-03 16:38 [PATCH] parisc: Fix double SIGFPE crash deller
@ 2025-05-03 17:18 ` John David Anglin
0 siblings, 0 replies; 2+ messages in thread
From: John David Anglin @ 2025-05-03 17:18 UTC (permalink / raw)
To: deller, linux-parisc; +Cc: Helge Deller, Camm Maguire
Hi Helge,
Maybe the comment can be improved.
The signal handler crashes with a second SIGFPE because glibc uses a double-word
floating-point store to atomically update function descriptors. As a result of lazy
binding, we hit a floating-point store in fpe_func almost immediately.
When the T bit is set, an assist exception trap occurs when when the co-processor
encounters *any* floating-point instruction except for a double store of register %fr0.
The latter cancels all pending traps.
Dave
On 2025-05-03 12:38 p.m., deller@kernel.org wrote:
> From: Helge Deller <deller@gmx.de>
>
> Camm noticed that on parisc a SIGFPE exception may triggger a second
> SIGFPE in the glibc part of the signal handler which then finally leads
> to a crash of the program.
> This can easily be reproduced with this test program which will abort in the
> second SIGFPE.
>
> root@parisc:~# cat fpe.c
>
> static void fpe_func(int sig, siginfo_t *i, void *v) {
> sigset_t set;
> sigemptyset(&set);
> sigaddset(&set, SIGFPE);
> sigprocmask(SIG_UNBLOCK, &set, NULL);
> printf("GOT signal %d with si_code %ld\n", sig, i->si_code);
> }
>
> int main() {
> struct sigaction action = {
> .sa_sigaction = fpe_func,
> .sa_flags = SA_RESTART|SA_SIGINFO };
> sigaction(SIGFPE, &action, 0);
> feenableexcept(FE_OVERFLOW);
> return printf("%lf\n",1.7976931348623158E308*1.7976931348623158E308);
> }
>
> root@parisc:~# gcc fpe.c -lm
> root@parisc:~# ./a.out
> Floating point exception
>
> root@parisc:~# strace -f ./a.out
> execve("./a.out", ["./a.out"], 0xf9ac7034 /* 20 vars */) = 0
> getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
> ...
> rt_sigaction(SIGFPE, {sa_handler=0x1110a, sa_mask=[], sa_flags=SA_RESTART|SA_SIGINFO}, NULL, 8) = 0
> --- SIGFPE {si_signo=SIGFPE, si_code=FPE_FLTOVF, si_addr=0x1078f} ---
> --- SIGFPE {si_signo=SIGFPE, si_code=FPE_FLTOVF, si_addr=0xf8f21237} ---
> +++ killed by SIGFPE +++
> Floating point exception
>
> Fix this by clearing the Trap (T) bit in the FP status register before
> returning to the signal handler in userspace.
>
> Signed-off-by: Helge Deller <deller@gmx.de>
> Suggested-by: John David Anglin <dave.anglin@bell.net>
> Reported-by: Camm Maguire <camm@maguirefamily.org>
> ---
> arch/parisc/math-emu/driver.c | 16 +++++++++++++---
> 1 file changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c
> index 34495446e051..15f183cbe915 100644
> --- a/arch/parisc/math-emu/driver.c
> +++ b/arch/parisc/math-emu/driver.c
> @@ -97,9 +97,19 @@ handle_fpe(struct pt_regs *regs)
>
> memcpy(regs->fr, frcopy, sizeof regs->fr);
> if (signalcode != 0) {
> - force_sig_fault(signalcode >> 24, signalcode & 0xffffff,
> - (void __user *) regs->iaoq[0]);
> - return -1;
> + int sig = signalcode >> 24;
> +
> + if (sig == SIGFPE) {
> + /*
> + * Clear floating point trap bit to avoid trapping
> + * again on the first fstd/fld access in the userspace
> + * signal handler.
> + */
> + regs->fr[0] &= ~(1ULL << 38);
> + }
> + force_sig_fault(sig, signalcode & 0xffffff,
> + (void __user *) regs->iaoq[0]);
> + return -1;
> }
>
> return signalcode ? -1 : 0;
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-05-03 17:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-03 16:38 [PATCH] parisc: Fix double SIGFPE crash deller
2025-05-03 17:18 ` John David Anglin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).