Path: funic!news.funet.fi!sunic!seunet!mcsun!uunet!decwrl!pa.dec.com!vixie From: vixie@pa.dec.com (Paul Vixie) Newsgroups: comp.sources.unix Subject: v25i003: crashme V1.8 - stress-test your U**X kernel Message-ID: <1991Dec3.054505.18671@PA.dec.com> Date: 3 Dec 91 05:45:05 GMT Sender: news@PA.dec.com (News) Organization: DEC Palo Alto Lines: 718 Approved: vixie@pa.dec.com Submitted-by: George J Carrette Posting-number: Volume 25, Issue 3 Archive-name: crashme [ I added "all", "clean", and "install" targets to the Makefile. --mod ] Crashme is a very simple program that tests the operating environment's robustness by invoking random data as if it were a procedure. The standard signals are caught and handled with a setjmp back to a loop which will try again to produce a fault by executing random data. [... note that] to really test a significant portion of an instruction set of a machine you have to let a test like this run for weeks on end. It was really quite suprising that so many machines crashed after only a few seconds. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'README' <<'END_OF_FILE' Notes for release 1.8 of Crashme. 27-SEP-1991 GJC@MITECH.COM X Many people have suggested that the output of previous versions was far too verbose, and that that was not only anoying but also effectively slowing down the program. Therefore there is a new argument available after the subprocess control argument, which is a verboseness level from 0 to 5. Using a level of 2 will print out only summary information about the runs. e.g. X X$ crashme +2000 666 50 00:30:00 2 Crashme: (c) Copyright 1990, 1991 George J. Carrette Version: 1.7 25-SEP-1991 Subprocess run for 1800 seconds (0 00:30:00) Test complete, total real time: 1801 seconds (0 00:30:01) exit status ... number of cases X 1100 ... 2 X 3522652 ... 4 X 1036 ... 1 X 1084 ... 7 X 1108 ... 19 X 1 ... 432 X 12 ... 137 X The table of exit status codes and frequencies is a new interesting aspect of the test. This test was run on a VMS system, so that we have a normal process exit 432 times, access violation 137 times, and reserved operand fault 19 times, etc. As the number of tries goes up (50 in this case) we would expect that the number of normal process exits to go down. X Here is some output supplied by nik@infonode.ingr.com on one of his machines. X Processor : Intergraph Clipper C300 RISC processor X 16Mb memory + 4k I cache and 4K D cache X Operating System: CLIX Version c.5.3.2 X derived from AT&T SVR 3.1 with BSD enhancements. X Crashme: (c) Copyright 1990, 1991 George J. Carrette Version: 1.7 25-SEP-1991 Subprocess run for 9000 seconds (0 02:30:00) Test complete, total real time: 9004 seconds (0 02:30:04) exit status ... number of cases X 136 ... 1 X 24576 ... 1 X 14 ... 1 X 138 ... 11 X 135 ... 27 X 140 ... 26 X 132 ... 430 X 139 ... 18 X 12800 ... 567 X The status values here could be decoded by reading the documentation for the "wait" system procedure, and looking up the correct part of the value in the sys_errlist[] array. That is left as an exersize for the reader. X X------------------------------------------------------------------------ X To compile, some systems may need #include . X Also, note the conditionalized code in bad_malloc. If your system only gets the signal "segmentation violation" then you may need to consider conditionalizations along this line. X However, on a machine with a segmented address space, that has X"instructions" in one segment and "data" in another, it is highly unlikely that the code for setting up and invoking the "void (*badboy)()" will have any interesting effect. Nothing other than an easily handled SIGSEGV will result in the inner testing loop. X Some INTEL 80386 and DEC PDP-11 systems would be examples of this situation. X X X X X X X X X X X END_OF_FILE if test 2845 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(293 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' DESTROOT= DESTPATH=usr/local X all: crashme X clean: X -rm -f *.o crashme core *~ *.BAK *.CKP X install: crashme crashme.1 X install -c -s crashme $(DESTROOT)/$(DESTPATH)/bin/crashme X install -c crashme.1 $(DESTROOT)/$(DESTPATH)/man/man1/crashme.1 X crashme: crashme.o X cc -o crashme crashme.o END_OF_FILE if test 293 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'crashme.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'crashme.1'\" else echo shar: Extracting \"'crashme.1'\" \(2430 characters\) sed "s/^X//" >'crashme.1' <<'END_OF_FILE' X.TH CRASHME 1C LOCAL X.SH NAME crashme \- test operating environment software robustness X.SH SYNOPSIS X.B crashme X[NBYTES] [SRAND] [NTRYS] [NSUB] [VERBOSE] X.SH DESCRIPTION X.I crashme is a very simple program that tests the operating environment's robustness by invoking random data as if it were a procedure. The standard signals are caught and handled with a setjmp back to a loop which will try again to produce a fault by executing random data. X X.RE X.SS COMMAND LINE OPTIONS X.TP 8 X.BI [NBYTES] The X.I [NBYTES] should be an integer, specifying the size of the random data string in bytes. If given negative then the bytes are printed instead of being executed. If given with an explicit plus sign then the storage for the bytes is freshly malloc'ed each time. This can have an effect on machines with seperate I and D cache mechanisms. X.TP X.BI [SRAND] The X.I [SRAND] is an input seed to the random number generator, passed to srand. X.TP X.BI [NTRIES] The X.I [NTRIES] is how many times to loop before exiting normally from the program. X.TP X.BI [NSUB] The X.I [NSUB] is optional, the number of vfork subprocesses running at once. If given as negative the number of vfork subprocesses to run, one after another. If given as a time hrs:mns:scs (hours, minutes, seconds) then one subprocess will be run to completion, followed by another, until the time limit has been reached. X When in sequential-subprocess mode there is a 3 minute time limit on each subprocess. This is to allow the instruction-set-space random walk to continue when a process bashes itself into an infinite loop. XFor example, the ntrys can be bashed to a very large number with nbytes bashed to zero. X The SRAND argument is incremented by one for each subprocess. X X.TP X.BI [VERBOSE] The X.I [VERBOSE] arg is optional. 0 is the least verbose, 5 the most. X X.SH EXAMPLE This is a suggested test, to run it for a least an hour. X crashme +2000 666 100 1:00:00 X X.SH FILES crashme.c X.PD X.SH DIAGNOSTICS When a signal is caught the number and nature of the signal is indicated. X.SH BUGS Not all signals are caught, and the state of the user program/process enviroment can be sufficiently damaged such that the program terminates before going through all [NTRIES] operations. X Beware: This program can crash your computer if the operating system or hardware of same is buggy. User data may be lost. X.SH AUTHOR George J Carrette. GJC\@MITECH.COM X.SH VERSION X1.8 27-SEP-1991 END_OF_FILE if test 2430 -ne `wc -c <'crashme.1'`; then echo shar: \"'crashme.1'\" unpacked with wrong size! fi # end of 'crashme.1' fi if test -f 'crashme.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'crashme.c'\" else echo shar: Extracting \"'crashme.c'\" \(13087 characters\) sed "s/^X//" >'crashme.c' <<'END_OF_FILE' X/* crashme: Create a string of random bytes and then jump to it. X crashme [nsub] */ X char *crashme_version = "1.8 27-SEP-1991"; X X/* X * COPYRIGHT (c) 1990, 1991 BY * X * GEORGE J. CARRETTE, CONCORD, MASSACHUSETTS. * X * ALL RIGHTS RESERVED * X Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X A signal handler is set up so that in most cases the machine exception generated by the illegal instructions, bad operands, etc in the procedure made up of random data are caught; and another round of randomness may be tried. Eventually a random instruction may corrupt the program or the machine state in such a way that the program must halt. This is a test of the robustness of the hardware/software for instruction fault handling. X Note: Running this program just a few times, using total CPU time of less than a few seconds SHOULD NOT GIVE YOU ANY CONFIDENCE in system robustness. Having it run for hours, with tens of thousands of cases would be a different thing. X Comments may be addressed to the author at GJC@MITECH.COM X See the documentation in crashme.1 or read this code for a description of command line arguments to this program. X Version Date Description X---------------------------------------------------------------------- X 1.0 early 1990 initial hack. X 1.1 19-SEP-1990 added more signals and an alarm to abort looping. X 1.2 25-JUN-1991 added [nsub] to vfork multiple subprocesses of self. X 1.3 14-AUG-1991 +nbytes malloc option, and -nsub option. X 1.4 29-AUG-1991 fix +nbytes (subproc). Add time-driven nprocs. SIGINT. X 1.5 3-SEP-1991 added alarm subprocess monitor to vfork_main. X 1.6 5-SEP-1991 some systems don't have vfork, so use fork by default. X 1.7 25-SEP-1991 verboseness level, exit summary report. X 1.8 -SEP-1991 address page protection issues on badboy. X Suggested test: At least let the thing run the length of your lunch break, in this case 1 hour, 10 minutes, and 30 seconds. X X crashme +2000 666 100 1:10:30 2 X X X CRASH REPORTS X Date, Machine Crashme Reported Crashme Ver Make Model OS Version Arguments by: X------------------------------------------------------------------------------ X10-JUL-90 1.0 SUN 4/110 4.1 1000 20 200 GJC@paradigm.com X10-JUL-90 1.0 SUN 4/280 4.0.3 1000 20 200 GJC@paradigm.com X31-JUL-90 1.0 DIGITAL DECstation 3100 100 10 10000 GAVRON@ARIZONA.EDU X31-JUL-90 1.0 IBM RT 100 10 10000 GAVRON@ARIZONA.EDU X 1-AUG-90 1.0 DIGITAL DECstation 5000 10000 230 1000 hudgens@scri.fsu.edu X 3-AUG-90 1.0 Alliant FX/2800 SJA@SIRIUS.HUT.FI X27-JUN-91 1.2 SUN 4/110 4.1.1 10 1000 10 LPH@PARADIGM.COM X27-JUN-91 1.2 SUN 4/110 4.1.1 1000 20 200 10 LPH@PARADIGM.COM X29-JUN-91 1.2 SUN 4/40C 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots X29-JUN-91 1.2 SUN 4/60 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots X29-JUN-91 1.2 SUN 4/100 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots X29-JUN-91 1.2 SUN 4/65 4.1.1 9 29748 5877 4 jon@uk.ac.oxford.robots X18-JUL-91 1.2 SGI Iris4d Unix 3.3.2 1000 $$ 1000 4 tsacas@ilog.ilog.fr X29-JUL-91 1.1 IBM RS/6000 AIX 1.3 script brandis@inf.ethz.ch X 5-SEP-91 1.6 IBM RS/6000-320 AIX 3.1.5 +2000 666 50 40:00:00 LPH X26-SEP-91 1.8 Nixdorf Targon/35 TOS3.3 script petri@ibr.cs.tu-bs.de X Notes: Crashme V1.0 {1000 20 200} used to down the SUN 4/110. V1.2 does *not* crash SUNOS 4.1.1 on the same arguments. Although using the extra argument for subprocesses it will crash, with the console reporting: X"Bad Trap, Bad Kernel Read Fault, Bus error. Reboot" X Script means invoking file with many calls to crashme such as this: X#/bin/csh crashme 1020 234 500 & crashme 394 38484 5723 & crashme 3784 474 474 & crashme 437 4747 38 & crashme 47848 4745 123 & crashme 4747 4747 3463 & crashme 474 46464 262 & crashme 37 3644 3723 & crashme 374 46464 22 & crashme 3747 464 363 & crashme 347 4747 44 & crashme 37374 374 66 & crashme 3737 474 4444 & X The 4-argument case of crashme could likely do as well as executing a script. X X*/ X X X#include X#include X#include X#include X X#ifdef pyr X#include X#include X#include X#include X#define strchr index X#endif X long nbytes,nseed,ntrys; long malloc_flag = 0; unsigned char *the_data; char *note_buffer; char *notes; X long verbose_level = 5; X void note(level) X long level; X{if (level > verbose_level) return; X strcat(note_buffer,"\n"); X fputs(note_buffer,stdout);} X jmp_buf again_buff; X void (*badboy)(); X unsigned char *bad_malloc(n) X long n; X{unsigned char *data; X data = (unsigned char *) malloc(n); X#ifdef pyr X if (mprotect(((int)data/PAGSIZ)*PAGSIZ, (n/PAGSIZ+1)*PAGSIZ, X PROT_READ|PROT_WRITE|PROT_EXEC)) X perror("mprotect"); X#endif X return(data);} X void again_handler(sig, code, scp, addr) X int sig, code; X struct sigcontext *scp; X char *addr; X{char *ss; X switch(sig) X {case SIGILL: ss = " illegal instruction"; break; X case SIGTRAP: ss = " trace trap"; break; X case SIGFPE: ss = " arithmetic exception"; break; X case SIGBUS: ss = " bus error"; break; X case SIGSEGV: ss = " segmentation violation"; break; X case SIGIOT: ss = " IOT instruction"; break; X case SIGEMT: ss = " EMT instruction"; break; X case SIGALRM: ss = " alarm clock"; break; X case SIGINT: ss = " interrupt"; break; X default: ss = "";} X sprintf(notes,"Got signal %d%s",sig,ss); X note(5); X longjmp(again_buff,3);} X set_up_signals() X{signal(SIGILL,again_handler); X signal(SIGTRAP,again_handler); X signal(SIGFPE,again_handler); X signal(SIGBUS,again_handler); X signal(SIGSEGV,again_handler); X signal(SIGIOT,again_handler); X signal(SIGEMT,again_handler); X signal(SIGALRM,again_handler); X signal(SIGINT,again_handler);} X compute_badboy() X{long j,n; X n = (nbytes < 0) ? - nbytes : nbytes; X if (malloc_flag == 1) X {the_data = bad_malloc(n); X badboy = (void (*)()) the_data;} X for(j=0;j> 7) & 0xFF; X if (nbytes < 0) X {sprintf(notes,"Dump of %ld bytes of data",n); X note(1); X for(j=0;j 0) X (*badboy)(); X else if (nbytes == 0) X while(1);} X char *subprocess_ind = "subprocess"; X main(argc,argv) X int argc; char **argv; X{long nsubs,hrs,mns,scs,tflag,j,m; X note_buffer = (char *) malloc(512); X notes = note_buffer; X if ((argc == 7) && X (strcmp(argv[6],subprocess_ind) == 0)) X {sprintf(note_buffer,"Subprocess %s: ",argv[4]); X notes = note_buffer + strlen(note_buffer); X verbose_level = atol(argv[5]); X sprintf(notes,"starting"); X note(3); X old_main(4,argv);} X else if (argc == 4) X old_main(4,argv); X else if ((argc == 5) || (argc == 6)) X {if (argc == 6) X verbose_level = atol(argv[5]); X copyright_note(1); X if (argc < 7) X m = argc; X else X m = 6; X strcpy(notes,"crashme"); X for(j=1;j [nsub] [verbose]"); X note(0);}} X copyright_note(n) X long n; X{sprintf(notes,"Crashme: (c) Copyright 1990, 1991 George J. Carrette"); X note(n); X sprintf(notes,"Version: %s",crashme_version); X note(n);} X old_main(argc,argv) X int argc; X char **argv; X{copyright_note(3); X nbytes = atol(argv[1]); X if (argv[1][0] == '+') malloc_flag = 1; X nseed = atol(argv[2]); X ntrys = atol(argv[3]); X sprintf(notes,"crashme %s%ld %ld %ld", X (malloc_flag == 0) ? "" : "+",nbytes,nseed,ntrys); X note(3); X if (malloc_flag == 0) X {the_data = bad_malloc((nbytes < 0) ? -nbytes : nbytes); X badboy = (void (*)()) the_data; X sprintf(notes,"Badboy at %d. 0x%X",badboy,badboy); X note(3);} X srand(nseed); X badboy_loop();} X badboy_loop() X{int i; X for(i=0;i= monitor_limit) X {sprintf(notes,"time limit reached on pid %d 0x%X. using kill.", X monitor_pid,monitor_pid); X note(3); X status = kill(monitor_pid,SIGKILL); X if (status < 0) X {sprintf(notes,"failed to kill process"); X note(3);} X monitor_active = 0;}}} X struct status_list X{long status; X long count; X struct status_list *next;}; X struct status_list *slist = NULL; X record_status(n) X long n; X{struct status_list *l; X for(l=slist;l != NULL; l = l->next) X if (n == l->status) X return(++l->count); X l = (struct status_list *) malloc(sizeof(struct status_list)); X l->count = 1; X l->status = n; X l->next = slist; X slist = l; X return(1);} X summarize_status() X{struct status_list *l; X sprintf(notes,"exit status ... number of cases"); X note(2); X for(l=slist;l != NULL; l = l->next) X {sprintf(notes,"exit status ... number of cases"); X sprintf(notes,"%11d ... %5d",l->status,l->count); X note(2);}} X vfork_main(tflag,nsubs,cmd,nb,sr,nt) X long tflag,nsubs,sr; X char *cmd,*nb,*nt; X{long j,status,pid,n,seq,total_time,dys,hrs,mns,scs; X char arg2[20],arg4[20],arg5[20]; X time_t before_time,after_time; X if (tflag == 1) X {seq = 1; X n = 100000000;} X else if (nsubs < 0) X {n = -nsubs; X seq = 1;} X else X {n = nsubs; X seq = 0;} X if (seq == 1) X {signal(SIGALRM,monitor_fcn); X alarm(monitor_period);} X time(&before_time); X sprintf(arg5,"%d",verbose_level); X for(j=0;j 0) X {monitor_active = 0; X sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status); X note(3); X record_status(status);}} X if (tflag == 1) X {time(&after_time); X total_time = after_time - before_time; X if (total_time >= nsubs) X {sprintf(notes,"Time limit reached after run %d",j+1); X note(2); X break;}}}} X if (seq == 0) X while((pid = wait(&status)) > 0) X {sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status); X note(3); X record_status(status);} X time(&after_time); X total_time = after_time - before_time; X scs = total_time; X mns = scs / 60; X hrs = mns / 60; X dys = hrs / 24; X scs = scs % 60; X mns = mns % 60; X hrs = hrs % 24; X sprintf(notes, X "Test complete, total real time: %d seconds (%d %02d:%02d:%02d)", X total_time,dys,hrs,mns,scs); X note(1); X summarize_status();} X END_OF_FILE if test 13087 -ne `wc -c <'crashme.c'`; then echo shar: \"'crashme.c'\" unpacked with wrong size! fi # end of 'crashme.c' fi if test -f 'crashme.opt' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'crashme.opt'\" else echo shar: Extracting \"'crashme.opt'\" \(84 characters\) sed "s/^X//" >'crashme.opt' <<'END_OF_FILE' X! VMS LINKER OPTIONS FILE IDENTIFICATION = "CRASHME V1.8" SYS$LIBRARY:VAXCRTL/SHARE END_OF_FILE if test 84 -ne `wc -c <'crashme.opt'`; then echo shar: \"'crashme.opt'\" unpacked with wrong size! fi # end of 'crashme.opt' fi if test -f 'descrip.mms' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'descrip.mms'\" else echo shar: Extracting \"'descrip.mms'\" \(690 characters\) sed "s/^X//" >'descrip.mms' <<'END_OF_FILE' X! VMS MAKEFILE (for MMS) X! X CFLAGS = /DEBUG/LIST/SHOW=(NOSOURCE)/MACHINE/OPTIMIZE=(NOINLINE)/STANDARD=PORTABLE X crashme.exe depends_on crashme.obj X link crashme.obj,crashme.opt/opt X ! re-execute the next line in your superior process: X crashme == "$" + f$env("DEFAULT") + "CRASHME" X crashme-dbg.exe depends_on crashme.obj X link/debug/exe=crashme-dbg.exe crashme.obj,crashme.opt/opt X X! note: do not use continuation character here. DIST_FILES = crashme.1,crashme.c,makefile,descrip.mms,crashme.opt,read.me,shar.db X crashme.shar depends_on $(DIST_FILES) X minishar crashme.shar shar.db X crashme.1_of_1 depends_on $(DIST_FILES) X define share_max_part_size 1000 X vms_share $(DIST_FILES) crashme END_OF_FILE if test 690 -ne `wc -c <'descrip.mms'`; then echo shar: \"'descrip.mms'\" unpacked with wrong size! fi # end of 'descrip.mms' fi echo shar: End of shell archive. exit 0