xref: /freebsd/tools/test/stress2/misc/fuzz.sh (revision dd41de95a84d979615a2ef11df6850622bf6184e)
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   bsdlabel -w md$mdstart auto
58   newfs -b 8192 -f 1024 $newfs_flags /dev/md${mdstart}$part > /dev/null 2>&1
59   mount /dev/md${mdstart}$part $mntpoint
60   cp /etc/passwd /etc/group /etc/hosts $mntpoint
61   cp -r /usr/include/ufs $mntpoint
62   umount $mntpoint
63
64   for i in `jot 50`; do
65      ./fuzz -n 50 $D
66      if fsck -f -y /dev/md${mdstart}$part 2>&1 | egrep "^[A-Z]" > /dev/null; then
67         if fsck -f -y /dev/md${mdstart}$part 2>&1 | egrep "^[A-Z]" > /dev/null; then
68            if fsck -f -y /dev/md${mdstart}$part 2>&1 | egrep "^[A-Z]" > /dev/null; then
69               echo "fsck is giving up in loop $i!"
70               break
71            fi
72         fi
73      fi
74      sync;sync;sync
75      if mount /dev/md${mdstart}$part $mntpoint; then
76         ls -l $mntpoint > /dev/null
77         find $mntpoint  -exec dd if={} of=/dev/null bs=1m count=3 \; > /dev/null 2>&1
78         umount $mntpoint
79      else
80         echo "Giving up at loop $i"
81         break
82      fi
83   done
84   mdconfig -d -u $mdstart
85   rm -f $D
86}
87
88odir=`pwd`
89dir=/tmp
90
91cd $dir
92sed '1,/^EOF/d' < $odir/$0 > $dir/fuzz.c
93mycc -o fuzz -Wall fuzz.c
94rm -f fuzz.c
95
96for j in `jot 10`; do
97   date '+%T'
98   tst
99done
100rm -f fuzz
101
102exit
103
104EOF
105#include <sys/stat.h>
106
107#include <err.h>
108#include <fcntl.h>
109#include <stdio.h>
110#include <stdlib.h>
111#include <unistd.h>
112
113static void
114usage(void)
115{
116	fprintf(stderr, "%s {-n <num|-v} <file>\n", getprogname());
117	exit(1);
118}
119
120static long
121random_long(long mi, long ma)
122{
123	return (arc4random()  % (ma - mi + 1) + mi);
124}
125
126int
127main(int argc, char **argv)
128{
129	long pos;
130	int ch, fd, i, times = 1, verbose = 0;
131	unsigned char bit, buf, mask, old;
132	struct stat sb;
133
134	while ((ch = getopt(argc, argv, "n:v")) != -1) {
135		switch(ch) {
136		case 'n':	/* Bits to alter */
137			if (sscanf(optarg, "%d", &times) != 1)
138				usage();
139			break;
140		case 'v':	/* verbose flag */
141			verbose += 1;
142			break;
143		default:
144			usage();
145		}
146	}
147	argc -= optind;
148	argv += optind;
149
150	if (argc == 0)
151		usage();
152
153	if ((fd = open(argv[0], O_RDWR)) == -1)
154		err(1, "open(%s)", argv[0]);
155	if (fstat(fd, &sb) == -1)
156		err(1, "stat(%s)", argv[0]);
157
158	for (i = 0; i < times; i++) {
159		pos = random_long(0, sb.st_size - 1);
160		if (lseek(fd, pos, SEEK_SET) == -1)
161			err(1, "fseek(%d, %ld)", fd, pos);
162		if (read(fd, &buf, 1) != 1)
163			err(1, "read(%d)", fd);
164		bit = random_long(0,7);
165		mask = ~(1 << bit);
166		old = buf;
167		buf = (buf & mask) | (~buf & ~mask);
168		if (verbose > 0)
169			printf("Change %2x to %2x at %4ld "
170			    "by flipping bit %d\n",
171					old, buf, pos, bit);
172		if (lseek(fd, pos, SEEK_SET) == -1)
173			err(1, "fseek(%d, %ld)", fd, pos);
174		if (write(fd, &buf, 1) != 1)
175			err(1, "write(%d)", fd);
176	}
177	close(fd);
178
179	return (0);
180}
181