forked from github/verilator
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
|
||||
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
|
||||
|
||||
=== --debug
|
||||
|
4
nodist/fuzzer/.gitignore
vendored
Normal file
4
nodist/fuzzer/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
wrapper
|
||||
dictionary/
|
||||
in*
|
||||
lex.yy.cc
|
48
nodist/fuzzer/actual_fail
Executable file
48
nodist/fuzzer/actual_fail
Executable file
@ -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()
|
17
nodist/fuzzer/all
Executable file
17
nodist/fuzzer/all
Executable file
@ -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
|
68
nodist/fuzzer/generate_dictionary
Executable file
68
nodist/fuzzer/generate_dictionary
Executable file
@ -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()
|
12
nodist/fuzzer/run
Executable file
12
nodist/fuzzer/run
Executable file
@ -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 @@
|
23
nodist/fuzzer/setup_root
Executable file
23
nodist/fuzzer/setup_root
Executable file
@ -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
|
31
nodist/fuzzer/setup_user
Executable file
31
nodist/fuzzer/setup_user
Executable file
@ -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
|
26
nodist/fuzzer/wrapper.cpp
Normal file
26
nodist/fuzzer/wrapper.cpp
Normal file
@ -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
Block a user