1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause 5# 6# Copyright (c) 2019 Peter Holm 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# minherit() test scenario inspired by Jeff's collapse.sh test. 31# No problems seen. 32 33. ../default.cfg 34[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1 35 36dir=/tmp 37odir=`pwd` 38cd $dir 39sed '1,/^EOF/d' < $odir/$0 > $dir/minherit.c 40mycc -o minherit -Wall -Wextra -O0 -g minherit.c || exit 1 41rm -f minherit.c 42cd $odir 43 44(cd $odir/../testcases/swap; ./swap -t 5m -i 10 -l 50) & 45pid=$! 46cd /tmp 47$dir/minherit 48s=$? 49while pkill swap; do :; done 50wait $oid 51[ -f minherit.core -a $s -eq 0 ] && 52 { ls -l minherit.core; mv minherit.core $dir; s=1; } 53cd $odir 54 55rm -rf $dir/minherit 56exit $s 57 58EOF 59#include <sys/param.h> 60#include <sys/mman.h> 61#include <sys/stat.h> 62#include <sys/wait.h> 63 64#include <err.h> 65#include <errno.h> 66#include <fcntl.h> 67#include <stdatomic.h> 68#include <stdio.h> 69#include <stdlib.h> 70#include <string.h> 71#include <time.h> 72#include <unistd.h> 73 74static _Atomic(int) *share; 75 76#define ADRSPACE (1024 * 1024) 77#define CHILDREN 200 78#define PARALLEL 10 79#define RUNTIME (5 * 60) 80#define SYNC 0 81 82static void 83test(void) 84{ 85 pid_t pids[CHILDREN]; 86 off_t len; 87 void *p; 88 int i, ix, j, n, shared; 89 char *cp; 90 91 (void)atomic_fetch_add(&share[SYNC], 1); 92 while (atomic_load(&share[SYNC]) != PARALLEL) 93 ; 94 95 if ((p = mmap(NULL, ADRSPACE, PROT_READ | PROT_WRITE, 96 MAP_SHARED | MAP_ANON, -1, 0)) == MAP_FAILED) { 97 if (errno == ENOMEM) 98 return; 99 err(1, "mmap()"); 100 } 101 102 /* Pick a random bit of address space to change inherit on. */ 103 for (i = 0; i < ADRSPACE; i += len) { 104 shared = arc4random() & 0x1; 105 len = roundup2(arc4random() % ((ADRSPACE - i) / 4), 106 PAGE_SIZE); 107 if (minherit(p + i, len, shared ? INHERIT_SHARE : 108 INHERIT_COPY) != 0) 109 err(1, "minherit"); 110 } 111 112 n = arc4random() % CHILDREN + 1; 113 for (i = 0; i < n; i++) { 114 pids[i] = fork(); 115 if (pids[i] == -1) 116 err(1, "fork()"); 117 if (pids[i] == 0) { 118 usleep(arc4random() % 100); 119 for (j = 0; j < 10; j++) { 120 cp = p; 121 for (ix = 0; ix < ADRSPACE; ix += PAGE_SIZE) { 122 cp[ix] = 1; 123 if (arc4random() % 100 < 5) 124 usleep(arc4random() % 50); 125 } 126 } 127 _exit(0); 128 } 129 } 130 for (i = 0; i < n; i++) { 131 if (waitpid(pids[i], NULL, 0) == -1) 132 err(1, "waitpid(%d)", pids[i]); 133 } 134 135 _exit(0); 136} 137 138int 139main(void) 140{ 141 pid_t pids[PARALLEL]; 142 size_t len; 143 time_t start; 144 int e, i, status; 145 146 e = 0; 147 len = PAGE_SIZE; 148 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 149 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 150 err(1, "mmap"); 151 152 start = time(NULL); 153 while ((time(NULL) - start) < RUNTIME && e == 0) { 154 share[SYNC] = 0; 155 for (i = 0; i < PARALLEL; i++) { 156 if ((pids[i] = fork()) == 0) 157 test(); 158 if (pids[i] == -1) 159 err(1, "fork()"); 160 } 161 for (i = 0; i < PARALLEL; i++) { 162 if (waitpid(pids[i], &status, 0) == -1) 163 err(1, "waitpid(%d)", pids[i]); 164 if (status != 0) { 165 if (WIFSIGNALED(status)) 166 fprintf(stderr, 167 "pid %d exit signal %d\n", 168 pids[i], WTERMSIG(status)); 169 e = status; 170 break; 171 } 172 } 173 } 174 175 return (e); 176} 177