175422Srwatson/*-
275422Srwatson * Copyright (c) 2001 Robert N. M. Watson
375422Srwatson * All rights reserved.
475422Srwatson *
575422Srwatson * Redistribution and use in source and binary forms, with or without
675422Srwatson * modification, are permitted provided that the following conditions
775422Srwatson * are met:
875422Srwatson * 1. Redistributions of source code must retain the above copyright
975422Srwatson *    notice, this list of conditions and the following disclaimer.
1075422Srwatson * 2. Redistributions in binary form must reproduce the above copyright
1175422Srwatson *    notice, this list of conditions and the following disclaimer in the
1275422Srwatson *    documentation and/or other materials provided with the distribution.
1375422Srwatson *
1475422Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1575422Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1675422Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1775422Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1875422Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1975422Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2075422Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2175422Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2275422Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2375422Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2475422Srwatson * SUCH DAMAGE.
2575422Srwatson *
2675422Srwatson * $FreeBSD$
2775422Srwatson */
2875422Srwatson
2975485Srwatson#include <sys/param.h>
3075485Srwatson#include <sys/uio.h>
3175422Srwatson#include <sys/ptrace.h>
3275422Srwatson#include <sys/time.h>
3375422Srwatson#include <sys/resource.h>
3475422Srwatson#include <sys/syscall.h>
3575422Srwatson#include <sys/wait.h>
3675485Srwatson#include <sys/ktrace.h>
3775422Srwatson
3875422Srwatson#include <assert.h>
3975422Srwatson#include <errno.h>
4075422Srwatson#include <signal.h>
4175422Srwatson#include <stdio.h>
4275422Srwatson#include <string.h>
4375422Srwatson#include <unistd.h>
4475422Srwatson
4575422Srwatson/*
4675422Srwatson * Relevant parts of a process credential.
4775422Srwatson */
4875422Srwatsonstruct cred {
4975422Srwatson	uid_t	cr_euid, cr_ruid, cr_svuid;
5075422Srwatson	int	cr_issetugid;
5175422Srwatson};
5275422Srwatson
5375422Srwatson/*
5475422Srwatson * Description of a scenario.
5575422Srwatson */
5675422Srwatsonstruct scenario {
5775422Srwatson	struct cred	*sc_cred1, *sc_cred2;	/* credentials of p1 and p2 */
5875482Srwatson	int		sc_canptrace_errno;	/* desired ptrace failure */
5975485Srwatson	int		sc_canktrace_errno;	/* desired ktrace failure */
6075447Srwatson	int		sc_cansighup_errno;	/* desired SIGHUP failure */
6175447Srwatson	int		sc_cansigsegv_errno;	/* desired SIGSEGV failure */
6275422Srwatson	int		sc_cansee_errno;	/* desired getprio failure */
6375422Srwatson	int		sc_cansched_errno;	/* desired setprio failure */
6475422Srwatson	char		*sc_name;		/* test name */
6575422Srwatson};
6675422Srwatson
6775422Srwatson/*
6875422Srwatson * Table of relevant credential combinations.
6975422Srwatson */
7075422Srwatsonstatic struct cred creds[] = {
7175422Srwatson/*		euid	ruid	svuid	issetugid	*/
7275422Srwatson/* 0 */ {	0,	0,	0,	0 },	/* privileged */
7375422Srwatson/* 1 */ {	0,	0,	0,	1 },	/* privileged + issetugid */
7475422Srwatson/* 2 */ {	1000,	1000,	1000,	0 },	/* unprivileged1 */
7575422Srwatson/* 3 */ {	1000,	1000,	1000,	1 },	/* unprivileged1 + issetugid */
7675422Srwatson/* 4 */ {	1001,	1001,	1001,	0 },	/* unprivileged2 */
7775422Srwatson/* 5 */ {	1001,	1001,	1001,	1 },	/* unprivileged2 + issetugid */
7875422Srwatson/* 6 */ {	1000,	0,	0,	0 },	/* daemon1 */
7975422Srwatson/* 7 */ {	1000,	0,	0,	1 },	/* daemon1 + issetugid */
8075422Srwatson/* 8 */ {	1001,	0,	0,	0 },	/* daemon2 */
8175422Srwatson/* 9 */ {	1001,	0,	0,	1 },	/* daemon2 + issetugid */
8275422Srwatson/* 10 */{	0,	1000,	1000,	0 },	/* setuid1 */
8375422Srwatson/* 11 */{	0, 	1000,	1000,	1 },	/* setuid1 + issetugid */
8475422Srwatson/* 12 */{	0,	1001,	1001,	0 },	/* setuid2 */
8575422Srwatson/* 13 */{	0,	1001,	1001,	1 },	/* setuid2 + issetugid */
8675422Srwatson};
8775422Srwatson
8875422Srwatson/*
8975422Srwatson * Table of scenarios.
9075422Srwatson */
9175422Srwatsonstatic const struct scenario scenarios[] = {
9275485Srwatson/*	cred1		cred2		ptrace	ktrace, sighup	sigsegv	see	sched	name */
9375486Srwatson/* privileged on privileged */
9475485Srwatson{	&creds[0],	&creds[0],	0,	0,	0,	0,	0,	0,	"0. priv on priv"},
9575485Srwatson{	&creds[0],	&creds[1],	0,	0,	0,	0,	0,	0,	"1. priv on priv"},
9675485Srwatson{	&creds[1],	&creds[0],	0,	0,	0,	0,	0,	0,	"2. priv on priv"},
9775485Srwatson{	&creds[1],	&creds[1],	0,	0,	0,	0,	0,	0,	"3. priv on priv"},
9875422Srwatson/* privileged on unprivileged */
9975485Srwatson{	&creds[0],	&creds[2],	0,	0,	0,	0,	0,	0,	"4. priv on unpriv1"},
10075485Srwatson{	&creds[0],	&creds[3],	0,	0,	0,	0,	0,	0,	"5. priv on unpriv1"},
10175485Srwatson{	&creds[1],	&creds[2],	0,	0,	0,	0,	0,	0,	"6. priv on unpriv1"},
10275485Srwatson{	&creds[1],	&creds[3],	0,	0,	0,	0,	0,	0,	"7. priv on unpriv1"},
10375422Srwatson/* unprivileged on privileged */
10475485Srwatson{	&creds[2],	&creds[0],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"8. unpriv1 on priv"},
10575485Srwatson{	&creds[2],	&creds[1],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"9. unpriv1 on priv"},
10675485Srwatson{	&creds[3],	&creds[0],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"10. unpriv1 on priv"},
10775485Srwatson{	&creds[3],	&creds[1],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"11. unpriv1 on priv"},
10875422Srwatson/* unprivileged on same unprivileged */
10975485Srwatson{	&creds[2],	&creds[2],	0,	0,	0,	0,	0,	0,	"12. unpriv1 on unpriv1"},
11075485Srwatson{	&creds[2],	&creds[3],	EPERM,	EPERM,	0,	EPERM,	0,	0,	"13. unpriv1 on unpriv1"},
11175485Srwatson{	&creds[3],	&creds[2],	0,	0,	0,	0,	0,	0,	"14. unpriv1 on unpriv1"},
11275485Srwatson{	&creds[3],	&creds[3],	EPERM,	EPERM,	0,	EPERM,	0,	0,	"15. unpriv1 on unpriv1"},
11375422Srwatson/* unprivileged on different unprivileged */
11475485Srwatson{	&creds[2],	&creds[4],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"16. unpriv1 on unpriv2"},
11575485Srwatson{	&creds[2],	&creds[5],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"17. unpriv1 on unpriv2"},
11675485Srwatson{	&creds[3],	&creds[4],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"18. unpriv1 on unpriv2"},
11775485Srwatson{	&creds[3],	&creds[5],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"19. unpriv1 on unpriv2"},
11875422Srwatson/* unprivileged on daemon, same */
11975485Srwatson{	&creds[2],	&creds[6],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"20. unpriv1 on daemon1"},
12075485Srwatson{	&creds[2],	&creds[7],	EPERM,	EPERM,	EPERM,	EPERM,	0, 	EPERM,	"21. unpriv1 on daemon1"},
12175485Srwatson{	&creds[3],	&creds[6],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"22. unpriv1 on daemon1"},
12275485Srwatson{	&creds[3],	&creds[7],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"23. unpriv1 on daemon1"},
12375422Srwatson/* unprivileged on daemon, different */
12475485Srwatson{	&creds[2],	&creds[8],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"24. unpriv1 on daemon2"},
12575485Srwatson{	&creds[2],	&creds[9],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"25. unpriv1 on daemon2"},
12675485Srwatson{	&creds[3],	&creds[8],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"26. unpriv1 on daemon2"},
12775485Srwatson{	&creds[3],	&creds[9],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"27. unpriv1 on daemon2"},
12875422Srwatson/* unprivileged on setuid, same */
12975485Srwatson{	&creds[2],	&creds[10],	EPERM,	EPERM,	0,	0,	0,	0,	"28. unpriv1 on setuid1"},
13075485Srwatson{	&creds[2],	&creds[11],	EPERM,	EPERM,	0,	EPERM,	0,	0,	"29. unpriv1 on setuid1"},
13175485Srwatson{	&creds[3],	&creds[10],	EPERM,	EPERM,	0,	0,	0,	0,	"30. unpriv1 on setuid1"},
13275485Srwatson{	&creds[3],	&creds[11],	EPERM,	EPERM,	0,	EPERM,	0,	0,	"31. unpriv1 on setuid1"},
13375422Srwatson/* unprivileged on setuid, different */
13475485Srwatson{	&creds[2],	&creds[12],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"32. unpriv1 on setuid2"},
13575485Srwatson{	&creds[2],	&creds[13],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"33. unpriv1 on setuid2"},
13675485Srwatson{	&creds[3],	&creds[12],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"34. unpriv1 on setuid2"},
13775485Srwatson{	&creds[3],	&creds[13],	EPERM,	EPERM,	EPERM,	EPERM,	0,	EPERM,	"35. unpriv1 on setuid2"},
13875422Srwatson};
13975422Srwatsonint scenarios_count = sizeof(scenarios) / sizeof(struct scenario);
14075422Srwatson
14175422Srwatson/*
14275422Srwatson * Convert an error number to a compact string representation.  For now,
14375422Srwatson * implement only the error numbers we are likely to see.
14475422Srwatson */
14575422Srwatsonstatic char *
14675422Srwatsonerrno_to_string(int error)
14775422Srwatson{
14875422Srwatson
14975422Srwatson	switch (error) {
15075422Srwatson	case EPERM:
15175422Srwatson		return ("EPERM");
15275422Srwatson	case EACCES:
15375422Srwatson		return ("EACCES");
15475422Srwatson	case EINVAL:
15575422Srwatson		return ("EINVAL");
15675422Srwatson	case ENOSYS:
15775422Srwatson		return ("ENOSYS");
15875422Srwatson	case ESRCH:
15975422Srwatson		return ("ESRCH");
16075447Srwatson	case EOPNOTSUPP:
16175447Srwatson		return ("EOPNOTSUPP");
16275422Srwatson	case 0:
16375422Srwatson		return ("0");
16475422Srwatson	default:
16575485Srwatson		printf("%d\n", error);
16675422Srwatson		return ("unknown");
16775422Srwatson	}
16875422Srwatson}
16975422Srwatson
17075422Srwatson/*
17175422Srwatson * Return a process credential describing the current process.
17275422Srwatson */
17375422Srwatsonstatic int
17475422Srwatsoncred_get(struct cred *cred)
17575422Srwatson{
17675422Srwatson	int error;
17775422Srwatson
17875422Srwatson	error = getresuid(&cred->cr_ruid, &cred->cr_euid, &cred->cr_svuid);
17975422Srwatson	if (error)
18075422Srwatson		return (error);
18175422Srwatson
18275422Srwatson	cred->cr_issetugid = issetugid();
18375422Srwatson
18475422Srwatson	return (0);
18575422Srwatson}
18675422Srwatson
18775422Srwatson/*
18875422Srwatson * Userland stub for __setsugid() to take into account possible presence
18975422Srwatson * in C library, kernel, et al.
19075422Srwatson */
19175422Srwatsonint
19275422Srwatsonsetugid(int flag)
19375422Srwatson{
19475422Srwatson
19575422Srwatson#ifdef SETSUGID_SUPPORTED
19675422Srwatson	return (__setugid(flag));
19775422Srwatson#else
19875422Srwatson#ifdef SETSUGID_SUPPORTED_BUT_NO_LIBC_STUB
19975422Srwatson	return (syscall(374, flag));
20075422Srwatson#else
20175422Srwatson	return (ENOSYS);
20275422Srwatson#endif
20375422Srwatson#endif
20475422Srwatson}
20575422Srwatson
20675422Srwatson/*
20775422Srwatson * Set the current process's credentials to match the passed credential.
20875422Srwatson */
20975422Srwatsonstatic int
21075422Srwatsoncred_set(struct cred *cred)
21175422Srwatson{
21275422Srwatson	int error;
21375422Srwatson
21475422Srwatson	error = setresuid(cred->cr_ruid, cred->cr_euid, cred->cr_svuid);
21575422Srwatson	if (error)
21675422Srwatson		return (error);
21775422Srwatson
21875422Srwatson	error = setugid(cred->cr_issetugid);
21975422Srwatson	if (error) {
22075422Srwatson		perror("__setugid");
22175422Srwatson		return (error);
22275422Srwatson	}
22375422Srwatson
22475422Srwatson#ifdef CHECK_CRED_SET
22575422Srwatson	{
22675422Srwatson		uid_t ruid, euid, svuid;
22775422Srwatson		error = getresuid(&ruid, &euid, &svuid);
22875422Srwatson		if (error) {
22975422Srwatson			perror("getresuid");
23075422Srwatson			return (-1);
23175422Srwatson		}
23275422Srwatson		assert(ruid == cred->cr_ruid);
23375422Srwatson		assert(euid == cred->cr_euid);
23475422Srwatson		assert(svuid == cred->cr_svuid);
23575422Srwatson		assert(cred->cr_issetugid == issetugid());
23675422Srwatson	}
23775422Srwatson#endif /* !CHECK_CRED_SET */
23875422Srwatson
23975422Srwatson	return (0);
24075422Srwatson}
24175422Srwatson
24275422Srwatson/*
24375422Srwatson * Print the passed process credential to the passed I/O stream.
24475422Srwatson */
24575422Srwatsonstatic void
24675422Srwatsoncred_print(FILE *output, struct cred *cred)
24775422Srwatson{
24875422Srwatson
24975422Srwatson	fprintf(output, "(e:%d r:%d s:%d P_SUGID:%d)", cred->cr_euid,
25075422Srwatson	    cred->cr_ruid, cred->cr_svuid, cred->cr_issetugid);
25175422Srwatson}
25275422Srwatson
25375422Srwatson#define	LOOP_PTRACE	0
25475485Srwatson#define	LOOP_KTRACE	1
25575485Srwatson#define	LOOP_SIGHUP	2
25675485Srwatson#define	LOOP_SIGSEGV	3
25775485Srwatson#define	LOOP_SEE	4
25875485Srwatson#define	LOOP_SCHED	5
25975422Srwatson#define	LOOP_MAX	LOOP_SCHED
26075422Srwatson
26175422Srwatson/*
26275422Srwatson * Enact a scenario by looping through the four test cases for the scenario,
26375422Srwatson * spawning off pairs of processes with the desired credentials, and
26475422Srwatson * reporting results to stdout.
26575422Srwatson */
26675422Srwatsonstatic int
26775422Srwatsonenact_scenario(int scenario)
26875422Srwatson{
26975422Srwatson	pid_t pid1, pid2;
27075485Srwatson	char *name, *tracefile;
27175422Srwatson	int error, desirederror, loop;
27275422Srwatson
27375422Srwatson	for (loop = 0; loop < LOOP_MAX+1; loop++) {
27475422Srwatson		/*
27575422Srwatson		 * Spawn the first child, target of the operation.
27675422Srwatson		 */
27775422Srwatson		pid1 = fork();
27875422Srwatson		switch (pid1) {
27975422Srwatson		case -1:
28075422Srwatson			return (-1);
28175422Srwatson		case 0:
28275422Srwatson			/* child */
28375422Srwatson			error = cred_set(scenarios[scenario].sc_cred2);
28475422Srwatson			if (error) {
28575422Srwatson				perror("cred_set");
28675422Srwatson				return (error);
28775422Srwatson			}
28875422Srwatson			/* 200 seconds should be plenty of time. */
28975422Srwatson			sleep(200);
29075422Srwatson			exit(0);
29175422Srwatson		default:
29275422Srwatson			/* parent */
293132296Srwatson			break;
29475422Srwatson		}
29575422Srwatson
29675422Srwatson		/*
29775422Srwatson		 * XXX
29875422Srwatson		 * This really isn't ideal -- give proc 1 a chance to set
29975422Srwatson		 * its credentials, or we may get spurious errors.  Really,
30075422Srwatson		 * some for of IPC should be used to allow the parent to
30175422Srwatson		 * wait for the first child to be ready before spawning
30275422Srwatson		 * the second child.
30375422Srwatson		 */
30475422Srwatson		sleep(1);
30575422Srwatson
30675422Srwatson		/*
30775422Srwatson		 * Spawn the second child, source of the operation.
30875422Srwatson		 */
30975422Srwatson		pid2 = fork();
31075422Srwatson		switch (pid2) {
31175422Srwatson		case -1:
31275422Srwatson			return (-1);
31375422Srwatson
31475422Srwatson		case 0:
31575422Srwatson			/* child */
31675422Srwatson			error = cred_set(scenarios[scenario].sc_cred1);
31775422Srwatson			if (error) {
31875422Srwatson				perror("cred_set");
31975422Srwatson				return (error);
32075422Srwatson			}
32175422Srwatson
32275422Srwatson			/*
32375422Srwatson			 * Initialize errno to zero so as to catch any
32475422Srwatson			 * generated errors.  In each case, perform the
32575422Srwatson			 * operation.  Preserve the error number for later
32675422Srwatson			 * use so it doesn't get stomped on by any I/O.
32775422Srwatson			 * Determine the desired error for the given case
32875422Srwatson			 * by extracting it from the scenario table.
32975422Srwatson			 * Initialize a function name string for output
33075422Srwatson			 * prettiness.
33175422Srwatson			 */
33275422Srwatson			errno = 0;
33375422Srwatson			switch (loop) {
33475422Srwatson			case LOOP_PTRACE:
33575422Srwatson				error = ptrace(PT_ATTACH, pid1, NULL, 0);
33675422Srwatson				error = errno;
33775422Srwatson				name = "ptrace";
33875422Srwatson				desirederror =
33975482Srwatson				    scenarios[scenario].sc_canptrace_errno;
34075422Srwatson				break;
34175485Srwatson			case LOOP_KTRACE:
34275485Srwatson				tracefile = mktemp("/tmp/testuid_ktrace.XXXXXX");
34375485Srwatson				if (tracefile == NULL) {
34475485Srwatson					error = errno;
34575485Srwatson					perror("mktemp");
34675485Srwatson					break;
34775485Srwatson				}
34875485Srwatson				error = ktrace(tracefile, KTROP_SET,
34975485Srwatson				    KTRFAC_SYSCALL, pid1);
35075485Srwatson				error = errno;
35175485Srwatson				name = "ktrace";
35275485Srwatson				desirederror =
35375485Srwatson				    scenarios[scenario].sc_canktrace_errno;
35475485Srwatson				unlink(tracefile);
35575485Srwatson				break;
35675447Srwatson			case LOOP_SIGHUP:
35775422Srwatson				error = kill(pid1, SIGHUP);
35875422Srwatson				error = errno;
35975447Srwatson				name = "sighup";
36075422Srwatson				desirederror =
36175447Srwatson				    scenarios[scenario].sc_cansighup_errno;
36275422Srwatson				break;
36375447Srwatson			case LOOP_SIGSEGV:
36475447Srwatson				error = kill(pid1, SIGSEGV);
36575447Srwatson				error = errno;
36675447Srwatson				name = "sigsegv";
36775447Srwatson				desirederror =
36875447Srwatson				    scenarios[scenario].sc_cansigsegv_errno;
36975447Srwatson				break;
37075422Srwatson			case LOOP_SEE:
37175422Srwatson				getpriority(PRIO_PROCESS, pid1);
37275422Srwatson				error = errno;
37375422Srwatson				name = "see";
37475422Srwatson				desirederror =
37575422Srwatson				    scenarios[scenario].sc_cansee_errno;
37675422Srwatson				break;
37775422Srwatson			case LOOP_SCHED:
37875422Srwatson				error = setpriority(PRIO_PROCESS, pid1,
37975422Srwatson				   0);
38075422Srwatson				error = errno;
38175422Srwatson				name = "sched";
38275422Srwatson				desirederror =
38375422Srwatson				    scenarios[scenario].sc_cansched_errno;
38475422Srwatson				break;
38575422Srwatson			default:
38675422Srwatson				name = "broken";
38775422Srwatson			}
38875422Srwatson
38975422Srwatson			if (error != desirederror) {
39075422Srwatson				fprintf(stdout,
39175422Srwatson				    "[%s].%s: expected %s, got %s\n  ",
39275422Srwatson				    scenarios[scenario].sc_name, name,
39375422Srwatson				    errno_to_string(desirederror),
39475422Srwatson				    errno_to_string(error));
39575422Srwatson				cred_print(stdout,
39675422Srwatson				    scenarios[scenario].sc_cred1);
39775422Srwatson				cred_print(stdout,
39875422Srwatson				    scenarios[scenario].sc_cred2);
39975422Srwatson				fprintf(stdout, "\n");
40075422Srwatson			}
40175422Srwatson
40275422Srwatson			exit(0);
40375422Srwatson
40475422Srwatson		default:
40575422Srwatson			/* parent */
406132296Srwatson			break;
40775422Srwatson		}
40875422Srwatson
40975422Srwatson		error = waitpid(pid2, NULL, 0);
41075422Srwatson		/*
41175422Srwatson		 * Once pid2 has died, it's safe to kill pid1, if it's still
41275422Srwatson		 * alive.  Mask signal failure in case the test actually
41375422Srwatson		 * killed pid1 (not unlikely: can occur in both signal and
41475422Srwatson		 * ptrace cases).
41575422Srwatson		 */
41675422Srwatson		kill(pid1, SIGKILL);
41775422Srwatson		error = waitpid(pid2, NULL, 0);
41875422Srwatson	}
41975422Srwatson
42075422Srwatson	return (0);
42175422Srwatson}
42275422Srwatson
42375422Srwatsonvoid
42475422Srwatsonenact_scenarios(void)
42575422Srwatson{
42675422Srwatson	int i, error;
42775422Srwatson
42875422Srwatson	for (i = 0; i < scenarios_count; i++) {
42975422Srwatson		error = enact_scenario(i);
43075422Srwatson		if (error)
43175422Srwatson			perror("enact_scenario");
43275422Srwatson	}
43375422Srwatson}
434