1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 for (;;) 78 pause(); 79 80 return (NULL); 81} 82 83static void 84test(void) { 85 pthread_t thr; 86 struct procctl_reaper_kill killemall; 87 pid_t pid; 88 time_t start; 89 int data[20], e, n, m; 90 91 n = m = 0; 92 if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == -1) 93 err(EXIT_FAILURE, "Fail to acquire the reaper"); 94 start = time(NULL); 95 while (time(NULL) - start < RUNTIME) { 96 m++; 97 share[0] = 0; 98 if ((pid = fork()) == 0) { 99 e = pthread_create(&thr, NULL, tr, NULL); 100 if (e != 0) 101 errc(1, e, "pthread_create"); 102 share[0] = 1; 103 setproctitle("child"); 104 usleep(arc4random() % 200); 105 if (arc4random() % 100 < 2) 106 raise(SIGSEGV); 107 _exit(0); 108 } 109 arc4random_buf(data, sizeof(data)); 110 while (share[0] == 0) 111 usleep(10); 112 killemall.rk_sig = SIGTERM; 113 killemall.rk_flags = 0; 114 flip(&killemall, sizeof(killemall)); 115 if (procctl(P_PID, getpid(), PROC_REAP_KILL, 116 &killemall) == 0) 117 n++; 118 if (waitpid(pid, NULL, 0) != pid) 119 err(1, "waitpid()"); 120 } 121#if defined(DEBUG) 122 fprintf(stderr, "n = %d out of %d\n", n, m); 123#endif 124 _exit(0); 125} 126 127int 128main(void) { 129 pid_t pids[PARALLEL]; 130 size_t len; 131 int i; 132 133 len = PAGE_SIZE; 134 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 135 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 136 err(1, "mmap"); 137 for (i = 0; i < PARALLEL; i++) { 138 if ((pids[i] = fork()) == 0) 139 test(); 140 } 141 for (i = 0; i < PARALLEL; i++) 142 if (waitpid(pids[i], NULL, 0) != pids[i]) 143 err(1, "waitpid()"); 144} 145EOF 146cc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -lpthread || exit 1 147rm /tmp/$prog.c 148 149here=`pwd` 150cd /tmp 151./$prog; s=$? 152cd $here 153 154rm -f /tmp/$prog /tmp/$prog.core 155exit $s 156