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