shithub: fuzz

ref: 51b862e3da2d706f415254ddf3b6074c59ffbcef
dir: fuzz/main.c

View raw version
#include "fuzz.h"

// Global variables are bad
Biobuf*	logbp;		// Bio buffer of the log file, initialized in main
Biobuf*	stdout;		// ^^ for stdout ;; fd=1
Biobuf*	hjbp;		// ^^ for #s/hjfs.cmd
Lock	loglck;		// Lock for logger
Lock	rnglck;		// Lock for rng
char*	logname = "./fuzz.log";	// Name of log file


// Commandline usage warning
void
usage(void)
{
	fprint(2, "usage: %s [-s seed] [-n rounds] calls\n", argv0);
	exits("usage");
}


/* Prototypes */
void	initsctable(void);
int		name2index(char*);


// A kernel fuzzer for the Plan 9 kernel
void
main(int argc, char *argv[])
{
	int nrounds = -1, i;
	List tofuzz = mklist() ; // List of syscall table ID's to fuzz
	stdout = Bfdopen(1, OWRITE);
	long fuzz_seed = truerand();

	ARGBEGIN{
		case 'n':
			// Number of rounds to iterate fuzzing for
			nrounds = atoi(EARGF(usage()));
			break;
		case 's':
			// Seed to fuzz from
			fuzz_seed = atol(EARGF(usage()));
			break;
		default:
			usage();
	}ARGEND

	// Initialize the table of all system calls
	initsctable();
	
	// If no system calls are specified, throw usage()
	if(argc < 1)
		usage();

	// If the call name '?' is specified as the first argument, print all call names
	if(strcmp(*argv, "?") == 0){
		int i;
		for(i = 0; i < NCALLS; i++)
			Bprint(stdout, "%s\n", callnames[i]);
		exits("Listing all known system calls");
	}
	
	// Set up buffered output
	int logfd = create(logname, OWRITE, 0777);
	if(logfd < 0)
		sysfatal("Error: Failed to create/open log file %s.", logname);

	logbp = Bfdopen(logfd, OWRITE);
	
	int hjfd = open("#s/hjfs.cmd", OWRITE);
	hjbp = Bfdopen(hjfd, OWRITE);
	
	// Acquire a list of calls specified by spaces (fuzz -n 1 read write seek)
	for(;*argv;argv++){
		int index;
		if((index = name2index(*argv)) > 0){
		
			debug("DEBUG index %d matched to \"%s\"\n", index, *argv);
			
			dolog("Loading call: %s\n", *argv);
			ladd(&tofuzz, &syscalls[index]); // Might be dangerous, pls fix
		}else
			sysfatal("Error: Invalid system call: %s", *argv);
	}

	srand(fuzz_seed);
	dolog("== Seed Value: %d ==\n", fuzz_seed);

	// Operate for the desired number of rounds, -1 is infinite
	for(i = 0; i < nrounds || nrounds < 0; i++){
		int j;
		dolog("== Begin round %d ==\n\n", i);
		
		debug("DEBUG: i: %d nrounds: %d\n", i, nrounds);
		
		for(j = 0; j < tofuzz.size; j++){
		
			debug("DEBUG: tofuzz.size: %d\n", tofuzz.size);
			
			caller *fcall = (caller*) lget(&tofuzz, j);
			dolog("­­ Fuzzing: %s ­­\n", fcall->name);
			
			fuzz(fcall); // Fuzz, syncs the disk
		}	
	}

	Bprint(stdout, "Fuzz ending…\n");

	// Clean up
	Bflush(logbp);
	Bterm(logbp);
	close(logfd);

	Bflush(stdout);
	Bterm(stdout);

	Bflush(hjbp);
	Bterm(hjbp);
	close(hjfd);

	exits(nil);
}


// Initialize the syscall table -- hopefully deprecated by a lex/yacc builder
void
initsctable(void)
{
	int i;
	for(i = 0; i < NCALLS; i++){
		syscalls[i].c = (call)i;
		syscalls[i].name = callnames[i]; // Pointer points to callnames
		syscalls[i].round = -1;
		syscalls[i].seed = -1;
		mkinlist(&(syscalls[i].inputs), (call)i);
	}
}

// Given a syscall name, return the index it occurs -- or -1 if not found
int
name2index(char* name)
{
	int i;
	for(i = 0; i < NCALLS; i++){
		if(strcmp(syscalls[i].name, name) == 0)
			return i;
	}
	return -1;
}


/* Exported in fuzz.h ↓ */


// Perform locked logging operation -- wraps print
void
dolog(char *fmt, ...)
{
	va_list args;
	va_start(args, fmt);

	lock(&loglck);
	Bvprint(logbp, fmt, args);
	unlock(&loglck);

	va_end(args);
}

// Perform a debug mode print (if built with -DDEBUG)
void
debug(char *fmt, ...)
{
	#ifdef DEBUG
	va_list args;
	va_start(args, fmt);

	Bvprint(stdout, fmt, args);

	va_end(args);
	#endif
}

// Thread-safe sleepable random number generator
int
rng(void)
{
	ulong x;
	lock(&rnglck);
	// Generate a number: 0 ≤ x ≤ MAXINT
	x = nrand(MAXINT);
	unlock(&rnglck);
	return x;
}