xref: /freebsd/tools/test/stress2/misc/syscall4.sh (revision 6be3386466ab79a84b48429ae66244f21526d3df)
1#!/bin/sh
2
3#
4# Copyright (c) 2011-2013 Peter Holm
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# Threaded syscall(2) fuzz test inspired by the iknowthis test suite
30# by Tavis Ormandy <taviso  cmpxchg8b com>
31
32# Usage: syscall4.sh [syscall number]
33#	Without an argument random syscall numbers are tested.
34#	With an argument only the specified syscall number is tested.
35
36# Sample problems found:
37# Thread stuck in stopprof.
38# http://people.freebsd.org/~pho/stress/log/kostik732.txt
39# Fixed by r275121.
40
41# panic: td 0xcbe1ac40 is not suspended.
42# https://people.freebsd.org/~pho/stress/log/kostik807.txt
43# Fixed by r282944.
44
45[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
46
47. ../default.cfg
48
49odir=`pwd`
50cd /tmp
51sed '1,/^EOF/d' < $odir/$0 > syscall4.c
52sed -i '' -e "s#MNTPOINT#$mntpoint#" syscall4.c
53rm -f /tmp/syscall4
54mycc -o syscall4 -Wall -Wextra -O2 -g syscall4.c -lpthread || exit 1
55rm -f syscall4.c
56
57kldstat -v | grep -q sysvmsg  || $stress2tools/kldload.sh sysvmsg
58kldstat -v | grep -q sysvsem  || $stress2tools/kldload.sh sysvsem
59kldstat -v | grep -q sysvshm  || $stress2tools/kldload.sh sysvshm
60kldstat -v | grep -q aio      || $stress2tools/kldload.sh aio
61kldstat -v | grep -q mqueuefs || $stress2tools/kldload.sh mqueuefs
62
63mount | grep -q "on $mntpoint " && umount -f $mntpoint
64[ -c /dev/md$mdstart ] && mdconfig -d -u $mdstart
65
66mdconfig -a -t swap -s 2g -u $mdstart || exit 1
67bsdlabel -w md$mdstart auto
68newfs $newfs_flags -n md${mdstart}$part > /dev/null
69mount /dev/md${mdstart}$part $mntpoint
70chmod 777 $mntpoint
71
72[ -z "$noswap" ] &&
73    daemon sh -c "(cd $odir/../testcases/swap; ./swap -t 10m -i 20 -k)" > \
74    /dev/null
75sleeptime=${sleeptime:-12}
76st=`date '+%s'`
77while [ $((`date '+%s'` - st)) -lt $((10 * sleeptime)) ]; do
78	(cd $mntpoint; /tmp/syscall4 $* 1>>stdout 2>>stderr) &
79	start=`date '+%s'`
80	while [ $((`date '+%s'` - start)) -lt $sleeptime ]; do
81		pgrep syscall4 > /dev/null || break
82		sleep .5
83	done
84	while pkill -9 syscall4; do :; done
85	wait
86	ipcs | grep nobody | awk '/^(q|m|s)/ {print " -" $1, $2}' |
87	    xargs -L 1 ipcrm
88done
89while pkill -9 swap; do :; done
90while pkill -9 syscall4; do :; done
91
92for i in `jot 10`; do
93	mount | grep -q md${mdstart}$part  && \
94		umount $mntpoint && mdconfig -d -u $mdstart && break
95	sleep 10
96done
97if mount | grep -q md${mdstart}$part; then
98	fstat $mntpoint
99	echo "umount $mntpoint failed"
100	exit 1
101fi
102rm -f /tmp/syscall4
103exit 0
104EOF
105#include <sys/types.h>
106#include <sys/event.h>
107#include <sys/resource.h>
108#include <sys/socket.h>
109#include <sys/stat.h>
110#include <sys/syscall.h>
111#include <sys/wait.h>
112
113#include <err.h>
114#include <errno.h>
115#include <fcntl.h>
116#include <fts.h>
117#include <libutil.h>
118#include <pthread.h>
119#if defined(__FreeBSD__)
120#include <pthread_np.h>
121#define	__NP__
122#endif
123#include <pwd.h>
124#include <signal.h>
125#include <stdint.h>
126#include <stdio.h>
127#include <stdlib.h>
128#include <string.h>
129#include <unistd.h>
130
131static int ignore[] = {
132	SYS_syscall,
133	SYS_exit,
134	SYS_fork,
135	11,			/* 11 is obsolete execv */
136	SYS_reboot,
137	SYS_vfork,
138	109,			/* 109 is old sigblock */
139	111,			/* 111 is old sigsuspend */
140	SYS_shutdown,
141	SYS___syscall,
142	216,			/* custom syscall */
143	SYS_rfork,
144	SYS_sigsuspend,
145	SYS_mac_syscall,
146	SYS_sigtimedwait,
147	SYS_sigwaitinfo,
148	SYS_thr_new,		/* Page fault seen */
149};
150
151static int fd[900], fds[2], kq, socketpr[2];
152#ifndef nitems
153#define nitems(x) (sizeof((x)) / sizeof((x)[0]))
154#endif
155#define N 4096
156#define MAGIC 1664
157#define RUNTIME 120
158#define THREADS 50
159
160static uint32_t r[N];
161static int magic1, syscallno, magic2;
162
163static int
164random_int(int mi, int ma)
165{
166        return (arc4random()  % (ma - mi + 1) + mi);
167}
168
169static void
170hand(int i __unused) {	/* handler */
171	exit(1);
172}
173
174static unsigned long
175makearg(void)
176{
177	unsigned int i;
178	unsigned long val;
179
180	val = arc4random();
181	i   = arc4random() % 100;
182	if (i < 20)
183		val = val & 0xff;
184	if (i >= 20 && i < 40)
185		val = val & 0xffff;
186	if (i >= 40 && i < 60)
187		val = (unsigned long)(r) | (val & 0xffff);
188#if defined(__LP64__)
189	if (i >= 60) {
190		val = (val << 32) | arc4random();
191		if (i > 80)
192			val = val & 0x00007fffffffffffUL;
193	}
194#endif
195
196	return(val);
197}
198
199static void *
200test(void *arg __unused)
201{
202	FTS *fts;
203	FTSENT *p;
204	time_t start;
205	int ftsoptions, i, numfiles;
206	char *args[] = {
207	    "/dev",
208	    "/proc",
209	    "MNTPOINT",
210	    "mnt2",
211	    ".",
212	    NULL,
213	};
214
215#ifdef __NP__
216	pthread_set_name_np(pthread_self(), __func__);
217#endif
218	numfiles = 0;
219	ftsoptions = FTS_PHYSICAL;
220	start = time(NULL);
221	while (time(NULL) - start < 2) {
222		for (i = 0; i < N; i++)
223			r[i] = arc4random();
224
225		if (pipe(fds) == -1)
226			err(1, "pipe()");
227		if (socketpair(PF_UNIX, SOCK_SEQPACKET, 0, socketpr) == -1)
228			err(1, "socketpair()");
229		kq = kqueue();
230
231		if ((fts = fts_open(args, ftsoptions, NULL)) == NULL)
232			err(1, "fts_open");
233
234		i = 0;
235		while ((p = fts_read(fts)) != NULL) {
236			if (fd[i] > 0)
237				close(fd[i]);
238			if ((fd[i] = open(p->fts_path, O_RDWR)) == -1)
239				if ((fd[i] = open(p->fts_path, O_WRONLY)) ==
240				    -1)
241					if ((fd[i] = open(p->fts_path,
242					    O_RDONLY)) == -1)
243						continue;
244			i++;
245			i = i % nitems(fd);
246			if (numfiles++ < 10) {
247				fprintf(stderr, "%d: pts_path = %s\n",
248				    numfiles, p->fts_path);
249			}
250		}
251
252		if (fts_close(fts) == -1)
253			warn("fts_close()");
254		sleep(1);
255		close(socketpr[0]);
256		close(socketpr[1]);
257		close(fds[0]);
258		close(fds[1]);
259		close(kq);
260	}
261	return(NULL);
262}
263
264static void *
265calls(void *arg __unused)
266{
267	time_t start;
268	int i, j, num;
269	unsigned long arg1, arg2, arg3, arg4, arg5, arg6, arg7;
270
271#ifdef __NP__
272	pthread_set_name_np(pthread_self(), __func__);
273#endif
274	start = time(NULL);
275	for (i = 0; time(NULL) - start < 10; i++) {
276		num = syscallno;
277		while (num == 0) {
278			num = random_int(0, SYS_MAXSYSCALL);
279			for (j = 0; j < (int)nitems(ignore); j++)
280				if (num == ignore[j]) {
281					num = 0;
282					break;
283				}
284		}
285		arg1 = makearg();
286		arg2 = makearg();
287		arg3 = makearg();
288		arg4 = makearg();
289		arg5 = makearg();
290		arg6 = makearg();
291		arg7 = makearg();
292
293#if 0		/* Debug mode */
294		fprintf(stderr, "%2d : syscall(%3d, %lx, %lx, %lx, %lx, %lx,"
295		   " %lx, %lx)\n",
296			i, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
297		sleep(2);
298#endif
299		alarm(1);
300		syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
301		num = 0;
302		if (magic1 != MAGIC || magic2 != MAGIC)
303			exit(1);
304	}
305
306	return (NULL);
307}
308
309int
310main(int argc, char **argv)
311{
312	struct passwd *pw;
313	struct rlimit limit;
314	pthread_t rp, cp[THREADS];
315	time_t start;
316	int e, j;
317
318	magic1 = magic2 = MAGIC;
319	if ((pw = getpwnam("nobody")) == NULL)
320		err(1, "failed to resolve nobody");
321
322	if (getenv("USE_ROOT") && argc == 2)
323		fprintf(stderr, "Running syscall4 as root for %s.\n",
324				argv[1]);
325	else {
326		if (setgroups(1, &pw->pw_gid) ||
327		    setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
328		    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
329			err(1, "Can't drop privileges to \"nobody\"");
330		endpwent();
331	}
332
333	limit.rlim_cur = limit.rlim_max = 1000;
334#if defined(RLIMIT_NPTS)
335	if (setrlimit(RLIMIT_NPTS, &limit) < 0)
336		err(1, "setrlimit");
337#endif
338
339	signal(SIGALRM, hand);
340	signal(SIGILL,  hand);
341	signal(SIGFPE,  hand);
342	signal(SIGSEGV, hand);
343	signal(SIGBUS,  hand);
344	signal(SIGURG,  hand);
345	signal(SIGSYS,  hand);
346	signal(SIGTRAP, hand);
347
348	if (argc > 2) {
349		fprintf(stderr, "usage: %s [syscall-num]\n", argv[0]);
350		exit(1);
351	}
352	if (argc == 2) {
353		syscallno = atoi(argv[1]);
354		for (j = 0; j < (int)nitems(ignore); j++)
355			if (syscallno == ignore[j])
356				errx(0, "syscall #%d is on the ignore list.",
357				    syscallno);
358	}
359
360	if (daemon(1, 1) == -1)
361		err(1, "daemon()");
362
363	system("touch aaa bbb ccc; mkdir -p ddd");
364	start = time(NULL);
365	while ((time(NULL) - start) < RUNTIME) {
366		if (fork() == 0) {
367			if ((e = pthread_create(&rp, NULL, test, NULL)) != 0)
368				errc(1, e, "pthread_create");
369			usleep(1000);
370			for (j = 0; j < THREADS; j++)
371				if ((e = pthread_create(&cp[j], NULL, calls,
372				    NULL)) != 0)
373					errc(1, e, "pthread_create");
374			for (j = 0; j < THREADS; j++)
375				pthread_join(cp[j], NULL);
376
377			if ((e = pthread_kill(rp, SIGINT)) != 0)
378				errc(1, e, "pthread_kill");
379			exit(0);
380		}
381		wait(NULL);
382		usleep(10000);
383	}
384
385	return (0);
386}
387