1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause 5# 6# Copyright (c) 2022 Peter Holm <pho@FreeBSD.org> 7# 8# Redistribution and use in source and binary forms, with or without 9# modification, are permitted provided that the following conditions 10# are met: 11# 1. Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27# SUCH DAMAGE. 28# 29 30# procctl(2) fuzz test 31 32prog=`basename ${0%.sh}` 33cat > /tmp/$prog.c <<EOF 34#include <sys/param.h> 35#include <sys/mman.h> 36#include <sys/procctl.h> 37 38#include <err.h> 39#include <pthread.h> 40#include <signal.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <time.h> 44#include <unistd.h> 45 46static volatile u_int *share; 47 48#define PARALLEL 25 49#define RUNTIME 120 50 51static long 52random_long(long mi, long ma) 53{ 54 return (arc4random() % (ma - mi + 1) + mi); 55} 56 57static void 58flip(void *ap, size_t len) 59{ 60 unsigned char *cp; 61 int byte; 62 unsigned char bit, buf, mask, old __unused; 63 64 cp = (unsigned char *)ap; 65 byte = random_long(0, len); 66 bit = random_long(0,7); 67 mask = ~(1 << bit); 68 buf = cp[byte]; 69 old = cp[byte]; 70 buf = (buf & mask) | (~buf & ~mask); 71 cp[byte] = buf; 72} 73 74static void * 75tr(void *arg __unused) 76{ 77 usleep(arc4random() % 400); 78 79 return (NULL); 80} 81 82static void 83test(void) { 84 pthread_t thr; 85 struct procctl_reaper_kill killemall; 86 pid_t pid; 87 time_t start; 88 int data[20], e, n __unused, m; 89 90 n = m = 0; 91 if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == -1) 92 err(EXIT_FAILURE, "Fail to acquire the reaper"); 93 start = time(NULL); 94 while (time(NULL) - start < RUNTIME) { 95 m++; 96 share[0] = 0; 97 if ((pid = fork()) == 0) { 98 e = pthread_create(&thr, NULL, tr, NULL); 99 if (e != 0) 100 errc(1, e, "pthread_create"); 101 share[0] = 1; 102 setproctitle("child"); 103 usleep(arc4random() % 200); 104 if (arc4random() % 100 < 2) 105 raise(SIGSEGV); 106 _exit(0); 107 } 108 arc4random_buf(data, sizeof(data)); 109 while (share[0] == 0) 110 usleep(10); 111 killemall.rk_sig = SIGTERM; 112 killemall.rk_flags = 0; 113 flip(&killemall, sizeof(killemall)); 114 if (procctl(P_PID, getpid(), PROC_REAP_KILL, 115 &killemall) == 0) 116 n++; 117 if (waitpid(pid, NULL, 0) != pid) 118 err(1, "waitpid()"); 119 } 120#if defined(DEBUG) 121 fprintf(stderr, "n = %d out of %d\n", n, m); 122#endif 123 _exit(0); 124} 125 126int 127main(void) { 128 pid_t pids[PARALLEL]; 129 size_t len; 130 int i; 131 132 len = PAGE_SIZE; 133 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 134 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 135 err(1, "mmap"); 136 for (i = 0; i < PARALLEL; i++) { 137 if ((pids[i] = fork()) == 0) 138 test(); 139 } 140 for (i = 0; i < PARALLEL; i++) 141 if (waitpid(pids[i], NULL, 0) != pids[i]) 142 err(1, "waitpid()"); 143} 144EOF 145cc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -lpthread || exit 1 146rm /tmp/$prog.c 147 148here=`pwd` 149cd /tmp 150./$prog; s=$? 151cd $here 152 153rm -f /tmp/$prog /tmp/$prog.core 154exit $s 155