Tests: Add fuzzing infrastructure.
Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
parent
6081c262f2
commit
77f79f0114
|
|
@ -716,6 +716,17 @@ enviroment can check their branches too by doing the following:
|
||||||
* Under a Travis CI project click More options > Settings in order to set up a
|
* Under a Travis CI project click More options > Settings in order to set up a
|
||||||
cron job on a particular branch
|
cron job on a particular branch
|
||||||
|
|
||||||
|
=== Fuzzing
|
||||||
|
|
||||||
|
There are scripts included to facilitate fuzzing of Verilator. These have
|
||||||
|
been successfully used to find a number of bugs in the frontend.
|
||||||
|
|
||||||
|
The scripts are based on using http://lcamtuf.coredump.cx/afl/[American fuzzy lop]
|
||||||
|
on a Debian-like system.
|
||||||
|
|
||||||
|
To get started, cd to "nodist/fuzzer/" and run "./all". A sudo password
|
||||||
|
may be required to setup the system for fuzzing.
|
||||||
|
|
||||||
== Debugging
|
== Debugging
|
||||||
|
|
||||||
=== --debug
|
=== --debug
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
wrapper
|
||||||
|
dictionary/
|
||||||
|
in*
|
||||||
|
lex.yy.cc
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
######################################################################
|
||||||
|
# DESCRIPTION: Fuzzer result checker
|
||||||
|
#
|
||||||
|
# Copyright 2019-2019 by Eric Rippey. This package is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||||
|
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# This script is designed to rerun examples to see whether they have
|
||||||
|
# unexpected types of output besides the ones that afl-fuzz detects as
|
||||||
|
# such.
|
||||||
|
|
||||||
|
from glob import glob
|
||||||
|
from subprocess import getstatusoutput
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
def interesting(s):
|
||||||
|
if 'assert' in s: return 1
|
||||||
|
if 'Assert' in s: return 1
|
||||||
|
if 'Aborted' in s: return 1
|
||||||
|
if 'terminate' in s:
|
||||||
|
if 'unterminated' in s:
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
if 'Segmentation' in s:
|
||||||
|
return 1
|
||||||
|
if 'internal error' in s:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
p = ArgumentParser()
|
||||||
|
p.add_argument('--dir',default='out1/queue')
|
||||||
|
args = p.parse_args()
|
||||||
|
|
||||||
|
for infile in glob(args.dir+'/*'):
|
||||||
|
# Input filenames are known not to contain spaces or other unusual
|
||||||
|
# characters, therefore this works.
|
||||||
|
status,output = getstatusoutput('../../bin/verilator_bin --cc '+infile)
|
||||||
|
if interesting(output):
|
||||||
|
print(infile)
|
||||||
|
print(status)
|
||||||
|
print(output)
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
######################################################################
|
||||||
|
# DESCRIPTION: Fuzzer one-line setup & run
|
||||||
|
#
|
||||||
|
# Copyright 2019-2019 by Eric Rippey. This package is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||||
|
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# Run all steps needed to configure and start fuzzer
|
||||||
|
# Note that this assumes the system is a Debian-like Linux distrubution
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
sudo ./setup_root
|
||||||
|
./setup_user
|
||||||
|
./run
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
######################################################################
|
||||||
|
# DESCRIPTION: Fuzzer dictionary generator
|
||||||
|
#
|
||||||
|
# Copyright 2019-2019 by Eric Rippey. This package is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||||
|
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# Attempts to pull a list of keywords out of the Flex input
|
||||||
|
# These are then put in a dictionary of "interesting" sequences
|
||||||
|
# This will be used to help the fuzzer pick interesting inputs more quickly.
|
||||||
|
|
||||||
|
from subprocess import getstatusoutput
|
||||||
|
from os import system
|
||||||
|
|
||||||
|
def take_while(f,a):
|
||||||
|
# any(a) => (a->bool)->[a]->[a]
|
||||||
|
# Does the same think as Haskell's takewhile.
|
||||||
|
out = []
|
||||||
|
for elem in a:
|
||||||
|
if f(elem):
|
||||||
|
out.append(elem)
|
||||||
|
else:
|
||||||
|
return out
|
||||||
|
return out
|
||||||
|
|
||||||
|
def skip_while(f,a):
|
||||||
|
# any(a) => (a->bool)->[a]->[a]
|
||||||
|
# Basically, the opposite thing from skipwhile
|
||||||
|
while len(a) and f(a[0]):
|
||||||
|
a = a[1:]
|
||||||
|
return a
|
||||||
|
|
||||||
|
def print_lines(a):
|
||||||
|
# printable(a) => [a]->void
|
||||||
|
for elem in a:
|
||||||
|
print(elem)
|
||||||
|
|
||||||
|
def write_file(filename,contents):
|
||||||
|
# str->str->void
|
||||||
|
f = open(filename,'w')
|
||||||
|
f.write(contents)
|
||||||
|
|
||||||
|
def parse_line(s):
|
||||||
|
# str->maybe str
|
||||||
|
if len(s)==0: return
|
||||||
|
part = skip_while(lambda x: x!='"',s)
|
||||||
|
if len(part)==0 or part[0]!='"': return None
|
||||||
|
literal_part = take_while(lambda x: x!='"',part[1:])
|
||||||
|
return ''.join(filter(lambda x: x!='\\',literal_part))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
status,output = getstatusoutput('flex -T ../../src/verilog.l')
|
||||||
|
assert status==0
|
||||||
|
|
||||||
|
lines = output.splitlines()
|
||||||
|
lines = take_while(lambda x: 'beginning dump of nfa' not in x,lines)
|
||||||
|
tokens = set(filter(lambda x: x,map(parse_line,lines)))
|
||||||
|
|
||||||
|
dirname = 'dictionary'
|
||||||
|
r = system('mkdir -p '+dirname)
|
||||||
|
assert(r==0)
|
||||||
|
for i,token in enumerate(tokens):
|
||||||
|
write_file(dirname+'/'+str(i),token)
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
######################################################################
|
||||||
|
# DESCRIPTION: Fuzzer run script
|
||||||
|
#
|
||||||
|
# Copyright 2019-2019 by Eric Rippey. This package is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||||
|
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# Actually do the fuzzing. Note that this will not terminate in any reasonable
|
||||||
|
# amount of time. However, it will give updates on its progress.
|
||||||
|
afl-fuzz -i in1 -o out1 -x dictionary ./wrapper --cc @@
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/bin/bash
|
||||||
|
######################################################################
|
||||||
|
# DESCRIPTION: Fuzzer setup to be run as root
|
||||||
|
#
|
||||||
|
# Copyright 2019-2019 by Eric Rippey. This package is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||||
|
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# This is the portion of the fuzzer setup that must be run as root.
|
||||||
|
# Note that this assumes a Debian-like distribution.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Get dependencies
|
||||||
|
apt-get install afl mdm
|
||||||
|
apt-get build-dep verilator
|
||||||
|
|
||||||
|
# Run a couple pieces of setup which should speed up the fuzzer
|
||||||
|
echo core >/proc/sys/kernel/core_pattern
|
||||||
|
|
||||||
|
cd /sys/devices/system/cpu
|
||||||
|
echo performance | tee cpu*/cpufreq/scaling_governor
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/bin/bash
|
||||||
|
######################################################################
|
||||||
|
# DESCRIPTION: Fuzzer setup to be run as a normal user
|
||||||
|
#
|
||||||
|
# Copyright 2019-2019 by Eric Rippey. This package is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||||
|
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# This is the portion of the setup for fuzzing that does not require root access.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Build instrumented version of verilator
|
||||||
|
pushd ../..
|
||||||
|
autoconf
|
||||||
|
AFL_HARDEN=1 CC=afl-gcc CXX=afl-g++ ./configure $(cd ..; pwd)
|
||||||
|
make clean
|
||||||
|
make -j $(ncpus)
|
||||||
|
popd
|
||||||
|
|
||||||
|
# Create a listing of likely snippets for the fuzzer to use.
|
||||||
|
# Not essential, but makes things likely to be found faster.
|
||||||
|
./generate_dictionary
|
||||||
|
|
||||||
|
# Set up input directory
|
||||||
|
mkdir in1
|
||||||
|
echo "module m; initial \$display(\"Hello world!\n\"); endmodule" > in1/1.v
|
||||||
|
|
||||||
|
# Compile wrapper program
|
||||||
|
AFL_HARDEN=1 CXX=afl-g++ make wrapper
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator fuzzing wrapper for verilator_bin
|
||||||
|
//
|
||||||
|
// Copyright 2019 by Eric Rippey. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
// The purpose of this script is to make sure that the results folder that
|
||||||
|
// is generated by running verilator does not change the results of
|
||||||
|
// subsequent runs.
|
||||||
|
|
||||||
|
// This does slow down the execution to some degree but makes the results
|
||||||
|
// more reliable.
|
||||||
|
|
||||||
|
int main(int argc, char **argv, char **envp) {
|
||||||
|
auto r = system("rm -rf obj_dir");
|
||||||
|
assert(r==0);
|
||||||
|
return execve("../../bin/verilator_bin",argv,envp);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue