Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple changes; python 2 support, dictionary, mutator refactor #26

Merged
merged 15 commits into from Jan 19, 2020
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Add support for dictionary files

This commits adds the support for dictionaries
(https://llvm.org/docs/LibFuzzer.html#dictionaries), to help fuzzers increase
their coverage faster.

It seems that there is a bug in the _copy function, because the word is
correctly inserted, but it seems that the padding after it is wrong,
and I couldn't understand why. Although to be honest,
I didn't spent much time on it, since I'd like to have feedback
on this PR before investing more debug time.

The implementation is pretty crude, it silently ignore
invalid lines in the dictionary file, and is likely using
words in the corpus a bit too often.
  • Loading branch information
jvoisin authored and gerph committed Dec 16, 2019
commit acc996f11379e8209ea944b0074663114dba6e61
@@ -5,6 +5,8 @@
import struct
import hashlib

from . import dictionnary


INTERESTING8 = [-128, -1, 0, 1, 16, 32, 64, 100, 127]
INTERESTING16 = [-32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767]
@@ -351,8 +353,9 @@ class CorpusError(Exception):

class Corpus(object):

def __init__(self, dirs=None, max_input_size=4096, mutators_filter=None):
def __init__(self, dirs=None, max_input_size=4096, mutators_filter=None, dict_path=None):
self._inputs = []
self._dict = dictionnary.Dictionary(dict_path)
self._max_input_size = max_input_size
self._dirs = dirs if dirs else []
for i, path in enumerate(dirs):
@@ -457,7 +460,6 @@ def mutate(self, buf):
res = buf[:]
nm = self._rand_exp()
for i in range(nm):

# Select a mutator from those we can apply
# We'll try up to 20 times, but if we don't find a
# suitable mutator after that, we'll just give up.
@@ -0,0 +1,27 @@
import random
import re
import os

class Dictionary:
line_re = re.compile('"(.+)"$')

def __init__(self, dict_path=None):
if not dict_path or not os.path.exists(dict_path):
self._dict = list()
return

_dict = set()
with open(dict_path) as f:
for line in f:
line = line.lstrip()
if line.startswith('#'):
continue
word = self.line_re.search(line)
if word:
_dict.add(word.group(1))
self._dict = list(_dict)

def get_word(self):
if not self._dict:
return None
return random.choice(self._dict)
@@ -89,15 +89,16 @@ def __init__(self,
max_input_size=4096,
close_fd_mask=0,
runs=-1,
mutators_filter=None):
mutators_filter=None,
dict_path=None):
self._target = target
self._dirs = [] if dirs is None else dirs
self._exact_artifact_path = exact_artifact_path
self._rss_limit_mb = rss_limit_mb
self._timeout = timeout
self._regression = regression
self._close_fd_mask = close_fd_mask
self._corpus = corpus.Corpus(self._dirs, max_input_size, mutators_filter)
self._corpus = corpus.Corpus(self._dirs, max_input_size, mutators_filter, dict_path)
self._total_executions = 0
self._executions_in_sample = 0
self._last_sample_time = time.time()
@@ -17,16 +17,16 @@ def __call__(self, *args, **kwargs):
help='run the fuzzer through set of files for regression or reproduction')
parser.add_argument('--rss-limit-mb', type=int, default=2048, help='Memory usage in MB')
parser.add_argument('--max-input-size', type=int, default=4096, help='Max input size in bytes')
parser.add_argument('--dict', type=str, help='dictionary file')
parser.add_argument('--close-fd-mask', type=int, default=0, help='Indicate output streams to close at startup')
parser.add_argument('--runs', type=int, default=-1, help='Number of individual test runs, -1 (the default) to run indefinitely.')
parser.add_argument('--help-mutators', action='store_true', help='Display help on the mutators')
parser.add_argument('--mutator-filter', type=str, default=None, help='Filter for mutator types to use; prefix with ! to disable')
parser.add_argument('--timeout', type=int, default=30,
help='If input takes longer then this timeout the process is treated as failure case')
args = parser.parse_args()
f = fuzzer.Fuzzer(self.function, args.dirs, args.exact_artifact_path,
args.rss_limit_mb, args.timeout, args.regression, args.max_input_size,
args.close_fd_mask, args.runs, args.mutator_filter)
args.close_fd_mask, args.runs, args.mutator_filter, args.dict)

if args.help_mutators:
f.help_mutators()
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.