From d852b31a8bb6bddce0694da9cd326ee50b873ce5 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Sun, 30 Apr 2017 20:33:04 +0000 Subject: [PATCH] alpha, cris, mips, ppc, sh, sparc: fix decoding of sigsuspend syscall On some architectures old sigsuspend syscall takes the signal mask from the 3rd argument, on some from the 1st. And, if it wasn't peculiar enough, the signal mask is passed by value on all architectures except mips where it's passed by reference. * signal.c (SYS_FUNC(sigsuspend)): Take the signal mask from the last argument. * linux/alpha/syscallent.h (sigsuspend): Set nargs to 1. * linux/crisv10/syscallent.h: Likewise. * linux/mips/syscallent-o32.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/powerpc64/syscallent.h: Likewise. * linux/sh/syscallent.h: Likewise. * linux/sh64/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. * linux/sparc64/syscallent.h: Likewise. * tests/sigsuspend.c: New file. * tests/gen_tests.in (sigsuspend): New entry. * tests/pure_executables.list: Add sigsuspend. * tests/.gitignore: Likewise. * NEWS: Mention this fix. --- NEWS | 2 + linux/alpha/syscallent.h | 2 +- linux/crisv10/syscallent.h | 2 +- linux/mips/syscallent-o32.h | 2 +- linux/powerpc/syscallent.h | 2 +- linux/powerpc64/syscallent.h | 2 +- linux/sh/syscallent.h | 2 +- linux/sh64/syscallent.h | 2 +- linux/sparc/syscallent.h | 2 +- linux/sparc64/syscallent.h | 2 +- signal.c | 7 ++- tests/.gitignore | 1 + tests/gen_tests.in | 1 + tests/pure_executables.list | 1 + tests/sigsuspend.c | 113 +++++++++++++++++++++++++++++++++++ 15 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 tests/sigsuspend.c diff --git a/NEWS b/NEWS index dd6bd88b..b109d98d 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,8 @@ Noteworthy changes in release ?.?? (????-??-??) * Bug fixes * Fixed decoding of flags argument of preadv2 and pwritev2 syscalls on x32. * Fixed the number of arguments and tracing flags of alpha specific syscalls. + * Fixed decoding of old sigsuspend syscall on alpha, cris, mips, powerpc, + powerpc64, sh, sh64, sparc, and sparc64. * Fixed decoding of netlink messages received within struct msghdr. * Worked around a bug in miscompiled aarch64 kernels leading to the 3rd argument of sched_getattr syscall being not quite 32-bit. diff --git a/linux/alpha/syscallent.h b/linux/alpha/syscallent.h index d9367cff..6ea965b1 100644 --- a/linux/alpha/syscallent.h +++ b/linux/alpha/syscallent.h @@ -137,7 +137,7 @@ [108] = { 5, 0, SEN(printargs), "osf_old_sigvec" }, /* not implemented */ [109] = { 5, 0, SEN(printargs), "osf_old_sigblock" }, /* not implemented */ [110] = { 5, 0, SEN(printargs), "osf_old_sigsetmask" }, /* not implemented */ -[111] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[111] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [112] = { 2, 0, SEN(printargs), "osf_sigstack" }, [113] = { 3, TN, SEN(recvmsg), "recvmsg" }, [114] = { 3, TN, SEN(sendmsg), "sendmsg" }, diff --git a/linux/crisv10/syscallent.h b/linux/crisv10/syscallent.h index 0f77fe54..c384a8bc 100644 --- a/linux/crisv10/syscallent.h +++ b/linux/crisv10/syscallent.h @@ -70,7 +70,7 @@ [ 69] = { 1, TS, SEN(sigsetmask), "ssetmask" }, [ 70] = { 2, 0, SEN(setreuid16), "setreuid" }, [ 71] = { 2, 0, SEN(setregid16), "setregid" }, -[ 72] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[ 72] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [ 73] = { 1, TS, SEN(sigpending), "sigpending" }, [ 74] = { 2, 0, SEN(sethostname), "sethostname" }, [ 75] = { 2, 0, SEN(setrlimit), "setrlimit" }, diff --git a/linux/mips/syscallent-o32.h b/linux/mips/syscallent-o32.h index b319f07a..c4752514 100644 --- a/linux/mips/syscallent-o32.h +++ b/linux/mips/syscallent-o32.h @@ -72,7 +72,7 @@ [4069] = { 1, TS, SEN(sigsetmask), "ssetmask" }, [4070] = { 2, 0, SEN(setreuid), "setreuid" }, [4071] = { 2, 0, SEN(setregid), "setregid" }, -[4072] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[4072] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [4073] = { 1, TS, SEN(sigpending), "sigpending" }, [4074] = { 2, 0, SEN(sethostname), "sethostname" }, [4075] = { 2, 0, SEN(setrlimit), "setrlimit" }, diff --git a/linux/powerpc/syscallent.h b/linux/powerpc/syscallent.h index 90a9103b..69c2ac18 100644 --- a/linux/powerpc/syscallent.h +++ b/linux/powerpc/syscallent.h @@ -98,7 +98,7 @@ [ 69] = { 1, TS, SEN(sigsetmask), "ssetmask" }, [ 70] = { 2, 0, SEN(setreuid), "setreuid" }, [ 71] = { 2, 0, SEN(setregid), "setregid" }, -[ 72] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[ 72] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [ 73] = { 1, TS, SEN(sigpending), "sigpending" }, [ 74] = { 2, 0, SEN(sethostname), "sethostname" }, [ 75] = { 2, 0, SEN(setrlimit), "setrlimit" }, diff --git a/linux/powerpc64/syscallent.h b/linux/powerpc64/syscallent.h index 23962bd0..ce99ae62 100644 --- a/linux/powerpc64/syscallent.h +++ b/linux/powerpc64/syscallent.h @@ -98,7 +98,7 @@ [ 69] = { 1, TS, SEN(sigsetmask), "ssetmask" }, [ 70] = { 2, 0, SEN(setreuid), "setreuid" }, [ 71] = { 2, 0, SEN(setregid), "setregid" }, -[ 72] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[ 72] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [ 73] = { 1, TS, SEN(sigpending), "sigpending" }, [ 74] = { 2, 0, SEN(sethostname), "sethostname" }, [ 75] = { 2, 0, SEN(setrlimit), "setrlimit" }, diff --git a/linux/sh/syscallent.h b/linux/sh/syscallent.h index eea14365..072aea28 100644 --- a/linux/sh/syscallent.h +++ b/linux/sh/syscallent.h @@ -100,7 +100,7 @@ [ 69] = { 1, TS, SEN(sigsetmask), "ssetmask" }, [ 70] = { 2, 0, SEN(setreuid16), "setreuid" }, [ 71] = { 2, 0, SEN(setregid16), "setregid" }, -[ 72] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[ 72] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [ 73] = { 1, TS, SEN(sigpending), "sigpending" }, [ 74] = { 2, 0, SEN(sethostname), "sethostname" }, [ 75] = { 2, 0, SEN(setrlimit), "setrlimit" }, diff --git a/linux/sh64/syscallent.h b/linux/sh64/syscallent.h index 2fb15bb9..043c20e6 100644 --- a/linux/sh64/syscallent.h +++ b/linux/sh64/syscallent.h @@ -98,7 +98,7 @@ [ 69] = { 1, TS, SEN(sigsetmask), "ssetmask" }, [ 70] = { 2, 0, SEN(setreuid16), "setreuid" }, [ 71] = { 2, 0, SEN(setregid16), "setregid" }, -[ 72] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[ 72] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [ 73] = { 1, TS, SEN(sigpending), "sigpending" }, [ 74] = { 2, 0, SEN(sethostname), "sethostname" }, [ 75] = { 2, 0, SEN(setrlimit), "setrlimit" }, diff --git a/linux/sparc/syscallent.h b/linux/sparc/syscallent.h index 82e2a81b..c64b4461 100644 --- a/linux/sparc/syscallent.h +++ b/linux/sparc/syscallent.h @@ -199,7 +199,7 @@ [198] = { 3, TS, SEN(sigaction), "sigaction" }, [199] = { 0, TS, SEN(siggetmask), "sgetmask" }, [200] = { 1, TS, SEN(sigsetmask), "ssetmask" }, -[201] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[201] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [202] = { 2, TF|TLST|TSTA, SEN(lstat), "oldlstat" }, [203] = { 1, TF, SEN(uselib), "uselib" }, [204] = { 3, TD, SEN(readdir), "readdir" }, diff --git a/linux/sparc64/syscallent.h b/linux/sparc64/syscallent.h index 7a6f914d..b0308a55 100644 --- a/linux/sparc64/syscallent.h +++ b/linux/sparc64/syscallent.h @@ -197,7 +197,7 @@ [198] = { 3, TS, SEN(sigaction), "sigaction" }, [199] = { 0, TS, SEN(siggetmask), "sgetmask" }, [200] = { 1, TS, SEN(sigsetmask), "ssetmask" }, -[201] = { 3, TS, SEN(sigsuspend), "sigsuspend" }, +[201] = { 1, TS, SEN(sigsuspend), "sigsuspend" }, [202] = { 2, TF|TLST|TSTA, SEN(lstat), "oldlstat" }, [203] = { 1, TF, SEN(uselib), "uselib" }, [204] = { 3, TD, SEN(readdir), "readdir" }, diff --git a/signal.c b/signal.c index ef6dbc2e..04ed10cb 100644 --- a/signal.c +++ b/signal.c @@ -385,7 +385,12 @@ SYS_FUNC(siggetmask) SYS_FUNC(sigsuspend) { - tprintsigmask_val("", tcp->u_arg[2]); +#ifdef MIPS + print_sigset_addr_len(tcp, tcp->u_arg[tcp->s_ent->nargs - 1], + current_wordsize); +#else + tprintsigmask_val("", tcp->u_arg[tcp->s_ent->nargs - 1]); +#endif return RVAL_DECODED; } diff --git a/tests/.gitignore b/tests/.gitignore index d0a28737..722b5e03 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -329,6 +329,7 @@ siginfo signal_receive signalfd4 sigreturn +sigsuspend sleep socketcall splice diff --git a/tests/gen_tests.in b/tests/gen_tests.in index f7be3752..24a2d3f1 100644 --- a/tests/gen_tests.in +++ b/tests/gen_tests.in @@ -284,6 +284,7 @@ siginfo -e trace=none signal_receive -a16 -e trace=kill signalfd4 sigreturn -esignal='!USR1' +sigsuspend -a19 -esignal=none socketcall -a20 splice stat -a32 -v -P stat.sample -P /dev/full diff --git a/tests/pure_executables.list b/tests/pure_executables.list index 7e474b53..ca7c6b79 100755 --- a/tests/pure_executables.list +++ b/tests/pure_executables.list @@ -271,6 +271,7 @@ sigaltstack siginfo signalfd4 sigreturn +sigsuspend socketcall splice stat diff --git a/tests/sigsuspend.c b/tests/sigsuspend.c new file mode 100644 index 00000000..a796380b --- /dev/null +++ b/tests/sigsuspend.c @@ -0,0 +1,113 @@ +/* + * Check decoding of sigsuspend syscall. + * + * Copyright (c) 2017 Dmitry V. Levin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" +#include + +#ifdef __NR_sigsuspend + +# include +# include +# include +# include +# include +# include +# include + +# ifdef MIPS +# define SIGNAL_MASK_BY_REF 1 +# else +# define SIGNAL_MASK_BY_REF 0 +# endif + +static long +k_sigsuspend(const kernel_ulong_t arg1, + const kernel_ulong_t arg2, + const kernel_ulong_t arg3) +{ + return syscall(__NR_sigsuspend, arg1, arg2, arg3); +} + +static int signo; + +static void +handler(int i) +{ + signo = i; +} + +int +main(void) +{ + union { + sigset_t libc_mask; + unsigned long old_mask; + } u; + unsigned long mask1, mask2; + + sigemptyset(&u.libc_mask); + sigaddset(&u.libc_mask, SIGUSR1); + mask1 = u.old_mask; + + sigemptyset(&u.libc_mask); + sigaddset(&u.libc_mask, SIGUSR2); + mask2 = u.old_mask; + + sigaddset(&u.libc_mask, SIGUSR1); + if (sigprocmask(SIG_SETMASK, &u.libc_mask, NULL)) + perror_msg_and_fail("sigprocmask"); + + const struct sigaction sa = { .sa_handler = handler }; + if (sigaction(SIGUSR1, &sa, NULL) || sigaction(SIGUSR2, &sa, NULL)) + perror_msg_and_fail("sigaction"); + + raise(SIGUSR1); + raise(SIGUSR2); + +#if SIGNAL_MASK_BY_REF + k_sigsuspend((uintptr_t) &mask1, 0xdeadbeef, (uintptr_t) &mask2); +#else + k_sigsuspend(mask1, 0xdeadbeef, mask2); +#endif + if (EINTR != errno) + perror_msg_and_skip("sigsuspend"); + + printf("sigsuspend([%s]) = ? ERESTARTNOHAND" + " (To be restarted if no handler)\n", + signo == SIGUSR2 ? "USR1" : "USR2"); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("__NR_sigsuspend") + +#endif -- 2.40.0