xref: /freebsd/tools/test/stress2/misc/fuzz.sh (revision d5b0e70f7e04d971691517ce1304d86a1e367e2e)
1#!/bin/sh
2
3#
4# Copyright (c) 2008 Peter Holm <pho@FreeBSD.org>
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# Stress test UFS2 file systems by introducing single bit errors in the FS
30# fsck should fix the FS no matter how damaged, but e.g. this panic has been seen:
31#
32# panic(c0912b65,dfe96000,0,c09e4060,ef48c778,...) at panic+0x14b
33# vm_fault(c1868000,dfe96000,1,0) at vm_fault+0x1e0
34# trap_pfault(ef48c894,0,dfe96000) at trap_pfault+0x137
35# trap(dfe90008,ef480028,c0690028,d0560000,dfe96000,...) at trap+0x341
36# calltrap() at calltrap+0x5
37# --- trap 0xc, eip = 0xc08785a6, esp = 0xef48c8d4, ebp = 0xef48c958 ---
38# generic_bcopy(c81cd570,d0508000,c5ead600,c87b81c0,0,...) at generic_bcopy+0x1a
39# ffs_mount(d0508000,c5ead600,0,c09b0860,c5ecfc3c,...) at ffs_mount+0xa14
40# vfs_domount(c5ead600,cd8c7280,ccb75080,0,...) at vfs_domount+0x687
41# vfs_donmount(c5ead600,0,ef48cc04) at vfs_donmount+0x2ef
42# kernel_mount(c5660960,0,bfbfec86,0,fffffffe,...) at kernel_mount+0x6d
43# ffs_cmount(c5660960,bfbfde50,0,c5ead600,c09b0860,...) at ffs_cmount+0x5d
44# mount(c5ead600,ef48cd04) at mount+0x156
45# syscall(3b,3b,3b,804abcf,bfbfe8e4,...) at syscall+0x22f
46
47[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
48
49. ../default.cfg
50
51D=$diskimage
52
53tst() {
54   rm -f $D
55   truncate -s 2M $D
56   mdconfig -a -t vnode -f $D -u $mdstart
57   newfs -b 8192 -f 1024 $newfs_flags /dev/md$mdstart > /dev/null 2>&1
58   mount /dev/md$mdstart $mntpoint
59   cp /etc/passwd /etc/group /etc/hosts $mntpoint
60   cp -r /usr/include/ufs $mntpoint
61   umount $mntpoint
62
63   for i in `jot 50`; do
64      ./fuzz -n 50 $D
65      if fsck -f -y /dev/md$mdstart 2>&1 | egrep "^[A-Z]" > /dev/null; then
66         if fsck -f -y /dev/md$mdstart 2>&1 | egrep "^[A-Z]" > /dev/null; then
67            if fsck -f -y /dev/md$mdstart 2>&1 | egrep "^[A-Z]" > /dev/null; then
68               echo "fsck is giving up in loop $i!"
69               break
70            fi
71         fi
72      fi
73      sync;sync;sync
74      if mount /dev/md$mdstart $mntpoint; then
75         ls -l $mntpoint > /dev/null
76         find $mntpoint  -exec dd if={} of=/dev/null bs=1m count=3 \; > /dev/null 2>&1
77         umount $mntpoint
78      else
79         echo "Giving up at loop $i"
80         break
81      fi
82   done
83   mdconfig -d -u $mdstart
84   rm -f $D
85}
86
87odir=`pwd`
88dir=/tmp
89
90cd $dir
91sed '1,/^EOF/d' < $odir/$0 > $dir/fuzz.c
92mycc -o fuzz -Wall fuzz.c
93rm -f fuzz.c
94
95for j in `jot 10`; do
96   date '+%T'
97   tst
98done
99rm -f fuzz
100
101exit
102
103EOF
104#include <sys/stat.h>
105
106#include <err.h>
107#include <fcntl.h>
108#include <stdio.h>
109#include <stdlib.h>
110#include <unistd.h>
111
112static void
113usage(void)
114{
115	fprintf(stderr, "%s {-n <num|-v} <file>\n", getprogname());
116	exit(1);
117}
118
119static long
120random_long(long mi, long ma)
121{
122	return (arc4random()  % (ma - mi + 1) + mi);
123}
124
125int
126main(int argc, char **argv)
127{
128	long pos;
129	int ch, fd, i, times = 1, verbose = 0;
130	unsigned char bit, buf, mask, old;
131	struct stat sb;
132
133	while ((ch = getopt(argc, argv, "n:v")) != -1) {
134		switch(ch) {
135		case 'n':	/* Bits to alter */
136			if (sscanf(optarg, "%d", &times) != 1)
137				usage();
138			break;
139		case 'v':	/* verbose flag */
140			verbose += 1;
141			break;
142		default:
143			usage();
144		}
145	}
146	argc -= optind;
147	argv += optind;
148
149	if (argc == 0)
150		usage();
151
152	if ((fd = open(argv[0], O_RDWR)) == -1)
153		err(1, "open(%s)", argv[0]);
154	if (fstat(fd, &sb) == -1)
155		err(1, "stat(%s)", argv[0]);
156
157	for (i = 0; i < times; i++) {
158		pos = random_long(0, sb.st_size - 1);
159		if (lseek(fd, pos, SEEK_SET) == -1)
160			err(1, "fseek(%d, %ld)", fd, pos);
161		if (read(fd, &buf, 1) != 1)
162			err(1, "read(%d)", fd);
163		bit = random_long(0,7);
164		mask = ~(1 << bit);
165		old = buf;
166		buf = (buf & mask) | (~buf & ~mask);
167		if (verbose > 0)
168			printf("Change %2x to %2x at %4ld "
169			    "by flipping bit %d\n",
170					old, buf, pos, bit);
171		if (lseek(fd, pos, SEEK_SET) == -1)
172			err(1, "fseek(%d, %ld)", fd, pos);
173		if (write(fd, &buf, 1) != 1)
174			err(1, "write(%d)", fd);
175	}
176	close(fd);
177
178	return (0);
179}
180