From a91ba89d85e21e465b9f99c90adc6b2f358b794d Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 5 Feb 2021 12:19:43 -0800 Subject: [PATCH] Fix sigsuspend() and sigprocmask() on OpenBSD Test reliability is now iron clad. --- examples/seq.c | 34 ++++++++++++++++++++ libc/calls/thunks/sigprocmask-sysv.S | 46 ++++++++++++++++++++++++++++ libc/calls/thunks/sigsuspend-sysv.S | 34 ++++++++++++++++++++ libc/sysv/calls/__sys_sigprocmask.s | 2 ++ libc/sysv/calls/__sys_sigsuspend.s | 2 ++ libc/sysv/calls/sys_sigprocmask.s | 2 -- libc/sysv/calls/sys_sigsuspend.s | 2 -- libc/sysv/consts.sh | 6 ++-- libc/sysv/consts/SIG_SETMASK.s | 2 +- libc/sysv/consts/SIG_UNBLOCK.s | 2 +- libc/sysv/syscalls.sh | 4 +-- tool/build/runitd.c | 25 +++++++++++++-- 12 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 examples/seq.c create mode 100644 libc/calls/thunks/sigprocmask-sysv.S create mode 100644 libc/calls/thunks/sigsuspend-sysv.S create mode 100644 libc/sysv/calls/__sys_sigprocmask.s create mode 100644 libc/sysv/calls/__sys_sigsuspend.s delete mode 100644 libc/sysv/calls/sys_sigprocmask.s delete mode 100644 libc/sysv/calls/sys_sigsuspend.s diff --git a/examples/seq.c b/examples/seq.c new file mode 100644 index 000000000..7e2782cc1 --- /dev/null +++ b/examples/seq.c @@ -0,0 +1,34 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/fmt/conv.h" +#include "libc/stdio/stdio.h" + +/** + * @fileoverview Prints sequence of numbers. + */ + +int main(int argc, char *argv[]) { + long a, b, i; + switch (argc) { + case 2: + a = 1; + b = strtol(argv[1], NULL, 0); + break; + case 3: + a = strtol(argv[1], NULL, 0); + b = strtol(argv[2], NULL, 0); + break; + default: + return 1; + } + for (i = a; i <= b; ++i) { + printf("%ld\n", i); + } +} diff --git a/libc/calls/thunks/sigprocmask-sysv.S b/libc/calls/thunks/sigprocmask-sysv.S new file mode 100644 index 000000000..a2c54ab70 --- /dev/null +++ b/libc/calls/thunks/sigprocmask-sysv.S @@ -0,0 +1,46 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/macros.h" + +/ Sets System Five process signal mask w/ standard ABI. +sys_sigprocmask: + push %rbp + mov %rsp,%rbp +#if SupportsOpenbsd() + testb IsOpenbsd() + jz 4f + test %rsi,%rsi + jnz 1f + mov $1,%edi # SIG_BLOCK on BSDs + jmp 2f +1: mov (%rsi),%esi # openbsd:byvalue +2: call __sys_sigprocmask + cmp $-1,%eax + je 5f + test %rdx,%rdx # original param not a result + jz 3f + mov %eax,(%rdx) # openbsd:byvalue +3: xor %eax,%eax + jmp 5f +#endif +4: call __sys_sigprocmask +5: pop %rbp + ret + .endfn sys_sigprocmask,globl diff --git a/libc/calls/thunks/sigsuspend-sysv.S b/libc/calls/thunks/sigsuspend-sysv.S new file mode 100644 index 000000000..55b5f9064 --- /dev/null +++ b/libc/calls/thunks/sigsuspend-sysv.S @@ -0,0 +1,34 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/macros.h" + +/ Pauses process w/ standard ABI. +sys_sigsuspend: + push %rbp + mov %rsp,%rbp +#if SupportsOpenbsd() + testb IsOpenbsd() + jz 1f + mov (%rdi),%edi # openbsd:byvalue +#endif +1: call __sys_sigsuspend + pop %rbp + ret + .endfn sys_sigsuspend,globl diff --git a/libc/sysv/calls/__sys_sigprocmask.s b/libc/sysv/calls/__sys_sigprocmask.s new file mode 100644 index 000000000..ac952a20b --- /dev/null +++ b/libc/sysv/calls/__sys_sigprocmask.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_sigprocmask 0x125030154203000e globl hidden diff --git a/libc/sysv/calls/__sys_sigsuspend.s b/libc/sysv/calls/__sys_sigsuspend.s new file mode 100644 index 000000000..8ff36b816 --- /dev/null +++ b/libc/sysv/calls/__sys_sigsuspend.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_sigsuspend 0x12606f155206f082 globl hidden diff --git a/libc/sysv/calls/sys_sigprocmask.s b/libc/sysv/calls/sys_sigprocmask.s deleted file mode 100644 index 4603afba1..000000000 --- a/libc/sysv/calls/sys_sigprocmask.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sys_sigprocmask 0x125030154203000e globl hidden diff --git a/libc/sysv/calls/sys_sigsuspend.s b/libc/sysv/calls/sys_sigsuspend.s deleted file mode 100644 index a0750958f..000000000 --- a/libc/sysv/calls/sys_sigsuspend.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sys_sigsuspend 0x12606f155206f082 globl hidden diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 0524a8c1b..f5294afbb 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -2145,10 +2145,10 @@ syscon misc MCAST_INCLUDE 1 1 1 0 0 0 syscon misc MCAST_EXCLUDE 0 2 2 0 0 0 syscon misc MCAST_MSFILTER 48 0 0 0 0 0 -syscon misc SIG_SETMASK 2 3 3 3 3 0 # bsd consensus -syscon misc SIG_UNBLOCK 1 2 2 2 2 0 # bsd consensus +syscon misc SIG_BLOCK 0 1 1 1 1 0 # bsd consensus; faked nt +syscon misc SIG_UNBLOCK 1 2 2 2 2 1 # bsd consensus; faked nt +syscon misc SIG_SETMASK 2 3 3 3 3 2 # bsd consensus; faked nt syscon misc SIG_ATOMIC_MIN -2147483648 -2147483648 -9223372036854775808 -2147483648 -2147483648 0 -syscon misc SIG_BLOCK 0 1 1 1 1 0 # bsd consensus syscon misc AREGTYPE 0 0 0 0 0 0 # consensus syscon misc B0 0 0 0 0 0 0 # consensus diff --git a/libc/sysv/consts/SIG_SETMASK.s b/libc/sysv/consts/SIG_SETMASK.s index 6e8347940..8962d2566 100644 --- a/libc/sysv/consts/SIG_SETMASK.s +++ b/libc/sysv/consts/SIG_SETMASK.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc SIG_SETMASK 2 3 3 3 3 0 +.syscon misc SIG_SETMASK 2 3 3 3 3 2 diff --git a/libc/sysv/consts/SIG_UNBLOCK.s b/libc/sysv/consts/SIG_UNBLOCK.s index c6167f1da..b9a50348a 100644 --- a/libc/sysv/consts/SIG_UNBLOCK.s +++ b/libc/sysv/consts/SIG_UNBLOCK.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc SIG_UNBLOCK 1 2 2 2 2 0 +.syscon misc SIG_UNBLOCK 1 2 2 2 2 1 diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index ad66d09ed..b0421c40e 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -49,7 +49,7 @@ scall sys_msync 0x115100041204101a globl hidden scall sys_mprotect 0x04a04a04a204a00a globl hidden scall sys_munmap 0x049049049204900b globl hidden scall sys_sigaction 0x15402e1a0202e00d globl hidden # rt_sigaction on Lunix; it's complicated on NetBSD -scall sys_sigprocmask 0x125030154203000e globl hidden # a.k.a. rt_sigprocmask +scall __sys_sigprocmask 0x125030154203000e globl hidden # a.k.a. rt_sigprocmask, openbsd:byvalue scall sys_ioctl 0x0360360362036010 globl hidden scall __sys_pread 0x0ad0ad1db2099011 globl hidden # a.k.a. pread64; netbsd+openbsd:pad scall __sys_pwrite 0x0ae0ae1dc209a012 globl hidden # a.k.a. pwrite64; netbsd+openbsd:pad @@ -163,7 +163,7 @@ scall sys_setresgid 0xfff11c138ffff077 globl hidden # polyfilled for xnu scall getresuid 0xfff119168ffff076 globl # semantics aren't well-defined scall getresgid 0xfff11b169ffff078 globl # semantics aren't well-defined scall sigpending 0x124034034203407f globl -scall sys_sigsuspend 0x12606f155206f082 globl hidden +scall __sys_sigsuspend 0x12606f155206f082 globl hidden # openbsd:byvalue scall sigaltstack 0x1191200352035083 globl scall sys_mknod 0x1c200e00e200e085 globl hidden scall mknodat 0x1cc14022fffff103 globl # FreeBSD 12+ diff --git a/tool/build/runitd.c b/tool/build/runitd.c index 221278a1c..e3e5319e6 100644 --- a/tool/build/runitd.c +++ b/tool/build/runitd.c @@ -46,6 +46,7 @@ #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/inaddr.h" #include "libc/sysv/consts/ipproto.h" +#include "libc/sysv/consts/itimer.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/sa.h" @@ -56,6 +57,7 @@ #include "libc/sysv/consts/sol.h" #include "libc/sysv/consts/w.h" #include "libc/testlib/testlib.h" +#include "libc/time/time.h" #include "libc/x/x.h" #include "third_party/getopt/getopt.h" #include "tool/build/runit.h" @@ -101,7 +103,7 @@ char *g_exepath; volatile bool g_interrupted; struct sockaddr_in g_servaddr; unsigned char g_buf[PAGESIZE]; -bool g_daemonize, g_sendready; +bool g_daemonize, g_sendready, g_alarmed; int g_timeout, g_devnullfd, g_servfd, g_clifd, g_exefd; void OnInterrupt(int sig) { @@ -238,6 +240,18 @@ void SendOutputFragmentMessage(int sock, enum RunitCommand kind, } } +void OnAlarm(int sig) { + g_alarmed = true; +} + +void SetDeadline(int seconds, int micros) { + g_alarmed = false; + LOGIFNEG1( + sigaction(SIGALRM, &(struct sigaction){.sa_handler = OnAlarm}, NULL)); + LOGIFNEG1(setitimer( + ITIMER_REAL, &(const struct itimerval){{0, 0}, {seconds, micros}}, NULL)); +} + void HandleClient(void) { const size_t kMinMsgSize = 4 + 1 + 4 + 4; const size_t kMaxNameSize = 32; @@ -308,6 +322,7 @@ void HandleClient(void) { /* run program, tee'ing stderr to both log and client */ DEBUGF("spawning %s", exename); + SetDeadline(1, 0); ignore.sa_flags = 0; ignore.sa_handler = SIG_IGN; LOGIFNEG1(sigemptyset(&ignore.sa_mask)); @@ -338,7 +353,13 @@ void HandleClient(void) { SendOutputFragmentMessage(g_clifd, kRunitStderr, g_buf, got); } while (waitpid(child, &wstatus, 0) == -1) { - if (errno == EINTR) continue; + if (errno == EINTR) { + if (g_alarmed) { + WARNF("killing %s which timed out"); + LOGIFNEG1(kill(child, SIGKILL)); + } + continue; + } FATALF("waitpid failed"); } if (WIFEXITED(wstatus)) {