Re: sending SIGFPE via kill() returns wrong values in si_pid and si_uid

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Rolf Eike Beer <eike-kernel@xxxxxxxxx> writes:

> This originally came up as a failure in the testsuite of strace on Gentoo 
> (T5120, 64 bit kernel, 32 bit userspace) and was reported here: 
> https://bugs.gentoo.org/643060. This was then reported upstream here: 
> https://github.com/strace/strace/issues/21 . I'll paste the relevant parts of
> those bugs here.
>
> The test program is as follows (done by Dmitry V. Levin): 
>
> #include <assert.h>
> #include <signal.h>
> #include <stdio.h>
> #include <unistd.h>
>
> static void
> handler(int sig, siginfo_t *info, void *ucontext)
> {
>
> fprintf(stderr, "sig=%d, si_signo=%d, si_pid=%d, si_uid=%d\n",
> 	sig, info->si_signo, info->si_pid, info->si_uid);
> }
>
> static void
> setup(int sig, sigset_t *mask)
> {
>
> static const struct sigaction act = { .sa_sigaction = handler, .sa_flags = SA_SIGINFO };
> assert(!sigaction(sig, &act, NULL));
> assert(!sigaddset(mask, sig));
> }
>
> static void
> test(int sig)
> {
>
> assert(!raise(sig));
> assert(!kill(getpid(), sig));
> }
>
> int
> main(void)
> {
>
> sigset_t mask;
> assert(!sigemptyset(&mask));
>
> setup(SIGFPE, &mask);
> setup(SIGTERM, &mask);
>
> assert(!sigprocmask(SIG_UNBLOCK, &mask, NULL));
>
> test(SIGFPE);
> test(SIGTERM);
>
> return 0;
> }
>
> Running this on sparc64 userspace works fine:
>
> sig=8, si_signo=8, si_pid=135186, si_uid=1008
> sig=8, si_signo=8, si_pid=135186, si_uid=1008
> sig=15, si_signo=15, si_pid=135186, si_uid=1008
> sig=15, si_signo=15, si_pid=135186, si_uid=1008
>
> However, on sparc32 things go wrong:
>
> sig=8, si_signo=8, si_pid=135192, si_uid=1008
> sig=8, si_signo=8, si_pid=1008, si_uid=0
> sig=15, si_signo=15, si_pid=135192, si_uid=1008
> sig=15, si_signo=15, si_pid=135192, si_uid=1008
>
> When digging the code up and down I came up with this patch, which fixes the 
> issue for me:
>
> diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
> index 54a6159b9cd8..a05e271e0924 100644
> --- a/arch/sparc/kernel/signal32.c
> +++ b/arch/sparc/kernel/signal32.c
> @@ -87,7 +87,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, 
>         err = __put_user(from->si_signo, &to->si_signo);
>         err |= __put_user(from->si_errno, &to->si_errno);
>         err |= __put_user(from->si_code, &to->si_code);
> -       if (from->si_code < 0)
> +       if (SI_FROMUSER(from))
>                 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
>         else {
>                 switch (siginfo_layout(from->si_signo, from->si_code)) {
>
> I suspect it was broken by cc731525f26af85a1c3537da41e0abd1d35e0bdb as it is 
> reported that it worked in 4.5.0. Looking at that commit other archs (at least 
> arm64, mips, parisc, powerpc, s390, tile, x86) have the same code, but 
> different default-cases. From a quick glance arm64, parisc, and x86 do not 
> have a default case anymore since that commit, while the others do not seem to 
> have changed their default case. However it could be that siginfo_layout() 
> behaves slightly different than the mask code used before in the switch 
> statements. I'm currently building a 4.14.9 kernel for my HP C8000, will 
> report the test results once that is done.

That is definitely the wrong fix.
However it does verify that your si_code is SI_USER.

The issue is that sparc has ambiguous signal handling, and
si_code of 0 combined with the signal SIGFPE could be either
a real floating point signal or a signal sent with kill.

As it is pointless to send yourself a signal with kill I choose to
preserve the floating point signal.   That is the test is not actually
testing floating point SIGFPE so I don't know that it makes much sense.

I do have some further fixes that I was planning on testing and applying
but I ran out of time to finish last year so I will see about digging
those up.  It is definitely wrong to allow sending SIGFPE to yourself
whent si_code == SI_USER when SIGFPE_FIXME is defined.  I should fix
that as well.

Ideally someone will go through sparc and look at
arch/sparc/kernel/traps_32.c:do_fpe_trap and
arch/sparc/kernel/traps_64.c:do_fpe_common and see if they can remove
the need for FPE_FIXME (aka SI_USER, aka 0).

Eric
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Development]     [DCCP]     [Linux ARM Development]     [Linux]     [Photo]     [Yosemite Help]     [Linux ARM Kernel]     [Linux SCSI]     [Linux x86_64]     [Linux Hams]

  Powered by Linux