1*896809e2SPeter Holm#!/bin/sh 2*896809e2SPeter Holm 3*896809e2SPeter Holm# 4*896809e2SPeter Holm# SPDX-License-Identifier: BSD-2-Clause 5*896809e2SPeter Holm# 6*896809e2SPeter Holm# Copyright (c) 2023 Peter Holm <pho@FreeBSD.org> 7*896809e2SPeter Holm# 8*896809e2SPeter Holm# Redistribution and use in source and binary forms, with or without 9*896809e2SPeter Holm# modification, are permitted provided that the following conditions 10*896809e2SPeter Holm# are met: 11*896809e2SPeter Holm# 1. Redistributions of source code must retain the above copyright 12*896809e2SPeter Holm# notice, this list of conditions and the following disclaimer. 13*896809e2SPeter Holm# 2. Redistributions in binary form must reproduce the above copyright 14*896809e2SPeter Holm# notice, this list of conditions and the following disclaimer in the 15*896809e2SPeter Holm# documentation and/or other materials provided with the distribution. 16*896809e2SPeter Holm# 17*896809e2SPeter Holm# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*896809e2SPeter Holm# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*896809e2SPeter Holm# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*896809e2SPeter Holm# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*896809e2SPeter Holm# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*896809e2SPeter Holm# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*896809e2SPeter Holm# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*896809e2SPeter Holm# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*896809e2SPeter Holm# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*896809e2SPeter Holm# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*896809e2SPeter Holm# SUCH DAMAGE. 28*896809e2SPeter Holm# 29*896809e2SPeter Holm 30*896809e2SPeter Holm# killpg(2) version of reaper.sh. No problems seen. 31*896809e2SPeter Holm 32*896809e2SPeter Holm. ../default.cfg 33*896809e2SPeter Holm 34*896809e2SPeter Holmprog=$(basename "$0" .sh) 35*896809e2SPeter Holmcat > /tmp/$prog.c <<EOF 36*896809e2SPeter Holm#include <sys/param.h> 37*896809e2SPeter Holm#include <sys/mman.h> 38*896809e2SPeter Holm#include <sys/wait.h> 39*896809e2SPeter Holm 40*896809e2SPeter Holm#include <err.h> 41*896809e2SPeter Holm#include <errno.h> 42*896809e2SPeter Holm#include <pwd.h> 43*896809e2SPeter Holm#include <signal.h> 44*896809e2SPeter Holm#include <stdio.h> 45*896809e2SPeter Holm#include <stdlib.h> 46*896809e2SPeter Holm#include <time.h> 47*896809e2SPeter Holm#include <unistd.h> 48*896809e2SPeter Holm 49*896809e2SPeter Holmstatic volatile u_int *share; 50*896809e2SPeter Holm 51*896809e2SPeter Holm#define CONT 0 52*896809e2SPeter Holm#define GID 1 53*896809e2SPeter Holm#define SYNC 2 54*896809e2SPeter Holm#define MAXP 10000 55*896809e2SPeter Holm 56*896809e2SPeter Holmstatic void 57*896809e2SPeter Holmhand(int i __unused) { 58*896809e2SPeter Holm _exit(0); 59*896809e2SPeter Holm} 60*896809e2SPeter Holm 61*896809e2SPeter Holmstatic void 62*896809e2SPeter Holmlooper(void) 63*896809e2SPeter Holm{ 64*896809e2SPeter Holm struct sigaction sa; 65*896809e2SPeter Holm time_t start; 66*896809e2SPeter Holm struct passwd *pw; 67*896809e2SPeter Holm pid_t pids[MAXP]; 68*896809e2SPeter Holm int i, parallel; 69*896809e2SPeter Holm 70*896809e2SPeter Holm setproctitle("looper"); 71*896809e2SPeter Holm sa.sa_handler = SIG_IGN; 72*896809e2SPeter Holm sigemptyset(&sa.sa_mask); 73*896809e2SPeter Holm sa.sa_flags = 0; 74*896809e2SPeter Holm if (sigaction(SIGUSR1, &sa, NULL) == -1) 75*896809e2SPeter Holm err(1, "sigaction"); 76*896809e2SPeter Holm 77*896809e2SPeter Holm if ((pw = getpwnam("TUSER")) == NULL) 78*896809e2SPeter Holm err(1, "no such user: TUSER"); 79*896809e2SPeter Holm 80*896809e2SPeter Holm if (setgroups(1, &pw->pw_gid) || 81*896809e2SPeter Holm setegid(pw->pw_gid) || setgid(pw->pw_gid) || 82*896809e2SPeter Holm seteuid(pw->pw_uid) || setuid(pw->pw_uid)) 83*896809e2SPeter Holm err(1, "Can't drop privileges to \"TUSER\""); 84*896809e2SPeter Holm endpwent(); 85*896809e2SPeter Holm setpgrp(0, 0); 86*896809e2SPeter Holm share[GID] = getpgrp(); 87*896809e2SPeter Holm share[SYNC] = 1; 88*896809e2SPeter Holm start = time(NULL); 89*896809e2SPeter Holm while (time(NULL) - start < 120) { 90*896809e2SPeter Holm parallel = arc4random() % MAXP + 1; 91*896809e2SPeter Holm for (i = 0; i < parallel; i++) { 92*896809e2SPeter Holm if ((pids[i] = fork()) == 0) { 93*896809e2SPeter Holm sa.sa_handler = hand; 94*896809e2SPeter Holm sigemptyset(&sa.sa_mask); 95*896809e2SPeter Holm sa.sa_flags = 0; 96*896809e2SPeter Holm if (sigaction(SIGUSR1, &sa, NULL) == -1) 97*896809e2SPeter Holm err(1, "sigaction"); 98*896809e2SPeter Holm setproctitle("child"); 99*896809e2SPeter Holm for (;;) 100*896809e2SPeter Holm pause(); 101*896809e2SPeter Holm _exit(0); /* never reached */ 102*896809e2SPeter Holm } 103*896809e2SPeter Holm if (pids[i] == -1) 104*896809e2SPeter Holm err(1, "fork()"); 105*896809e2SPeter Holm } 106*896809e2SPeter Holm for (i = 0; i < parallel; i++) { 107*896809e2SPeter Holm if (waitpid(pids[i], NULL, 0) != pids[i]) 108*896809e2SPeter Holm err(1, "waitpid(%d) in looper", pids[i]); 109*896809e2SPeter Holm } 110*896809e2SPeter Holm } 111*896809e2SPeter Holm _exit(0); 112*896809e2SPeter Holm} 113*896809e2SPeter Holm 114*896809e2SPeter Holmstatic void 115*896809e2SPeter Holmkiller(void) 116*896809e2SPeter Holm{ 117*896809e2SPeter Holm int e, gid; 118*896809e2SPeter Holm 119*896809e2SPeter Holm while (share[SYNC] == 0) 120*896809e2SPeter Holm ; 121*896809e2SPeter Holm gid = share[GID]; 122*896809e2SPeter Holm while (share[CONT] == 1) { 123*896809e2SPeter Holm usleep(arc4random() % 50000); 124*896809e2SPeter Holm gid = share[GID]; 125*896809e2SPeter Holm if (gid != 0) { 126*896809e2SPeter Holm e = 0; 127*896809e2SPeter Holm while (e == 0) { 128*896809e2SPeter Holm if (killpg(gid, SIGUSR1) == -1) { 129*896809e2SPeter Holm e = 1; 130*896809e2SPeter Holm if (errno != ESRCH) 131*896809e2SPeter Holm err(1, "pgkill(%d)", gid); 132*896809e2SPeter Holm } 133*896809e2SPeter Holm usleep(5000 + arc4random() % 5000); 134*896809e2SPeter Holm } 135*896809e2SPeter Holm } 136*896809e2SPeter Holm } 137*896809e2SPeter Holm _exit(0); 138*896809e2SPeter Holm} 139*896809e2SPeter Holm 140*896809e2SPeter Holmint 141*896809e2SPeter Holmmain(void) 142*896809e2SPeter Holm{ 143*896809e2SPeter Holm size_t len; 144*896809e2SPeter Holm time_t start; 145*896809e2SPeter Holm int lpid, kpid, s1, s2; 146*896809e2SPeter Holm 147*896809e2SPeter Holm len = PAGE_SIZE; 148*896809e2SPeter Holm if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 149*896809e2SPeter Holm MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 150*896809e2SPeter Holm err(1, "mmap"); 151*896809e2SPeter Holm 152*896809e2SPeter Holm start = time(NULL); 153*896809e2SPeter Holm while (time(NULL) - start < 120) { 154*896809e2SPeter Holm share[CONT] = 1; 155*896809e2SPeter Holm share[GID] = 0; 156*896809e2SPeter Holm share[SYNC] = 0; 157*896809e2SPeter Holm if ((lpid = fork()) == 0) 158*896809e2SPeter Holm looper(); 159*896809e2SPeter Holm usleep(arc4random() % 100000); 160*896809e2SPeter Holm if ((kpid = fork()) == 0) 161*896809e2SPeter Holm killer(); 162*896809e2SPeter Holm 163*896809e2SPeter Holm if (waitpid(lpid, &s1, 0) != lpid) 164*896809e2SPeter Holm err(1, "waitpid looper"); 165*896809e2SPeter Holm usleep(arc4random() % 1000); 166*896809e2SPeter Holm share[CONT] = 0; 167*896809e2SPeter Holm waitpid(kpid, &s2, 0); 168*896809e2SPeter Holm } 169*896809e2SPeter Holm 170*896809e2SPeter Holm return (0); 171*896809e2SPeter Holm} 172*896809e2SPeter HolmEOF 173*896809e2SPeter Holmsed -i '' "s#TUSER#$testuser#" /tmp/$prog.c 174*896809e2SPeter Holmcc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1 175*896809e2SPeter Holmrm /tmp/$prog.c 176*896809e2SPeter Holm 177*896809e2SPeter Holmn=1 178*896809e2SPeter Holmstart=`date +%s` 179*896809e2SPeter Holmwhile true; do 180*896809e2SPeter Holm /tmp/$prog 181*896809e2SPeter Holm for i in `jot 50`; do 182*896809e2SPeter Holm pgrep -q $prog || break 183*896809e2SPeter Holm sleep .5 184*896809e2SPeter Holm done 185*896809e2SPeter Holm if pgrep -q $prog; then 186*896809e2SPeter Holm e=$((`date +%s` - start)) 187*896809e2SPeter Holm echo "Failed in loop #$n after $e seconds." 188*896809e2SPeter Holm pgrep "$prog|timeout" | xargs ps -jp 189*896809e2SPeter Holm pkill $prog 190*896809e2SPeter Holm rm -f /tmp/$prog 191*896809e2SPeter Holm exit 1 192*896809e2SPeter Holm fi 193*896809e2SPeter Holm [ $((`date +%s` - start)) -ge 600 ] && break 194*896809e2SPeter Holm n=$((n + 1)) 195*896809e2SPeter Holmdone 196*896809e2SPeter Holmrm /tmp/$prog 197*896809e2SPeter Holmexit 0 198