[fuzz] fuzz.py can minimize and zip corpora
* "minimize" minimizes the corpora into an output directory. * "zip" zips up the minimized corpora, which are ready to deploy.dev
parent
14946af10c
commit
1c23b64049
|
@ -82,6 +82,35 @@ def tmpdir():
|
|||
shutil.rmtree(dirpath, ignore_errors=True)
|
||||
|
||||
|
||||
def parse_targets(in_targets):
|
||||
targets = set()
|
||||
for target in in_targets:
|
||||
if not target:
|
||||
continue
|
||||
if target == 'all':
|
||||
targets = targets.union(TARGETS)
|
||||
elif target in TARGETS:
|
||||
targets.add(target)
|
||||
else:
|
||||
raise RuntimeError('{} is not a valid target'.format(target))
|
||||
return list(targets)
|
||||
|
||||
|
||||
def targets_parser(args, description):
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
nargs='*',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS)))
|
||||
args, extra = parser.parse_known_args(args)
|
||||
args.extra = extra
|
||||
|
||||
args.TARGET = parse_targets(args.TARGET)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def parse_env_flags(args, flags):
|
||||
"""
|
||||
Look for flags set by environment variables.
|
||||
|
@ -424,36 +453,42 @@ def libfuzzer_parser(args):
|
|||
if args.TARGET and args.TARGET not in TARGETS:
|
||||
raise RuntimeError('{} is not a valid target'.format(args.TARGET))
|
||||
|
||||
if not args.corpora:
|
||||
args.corpora = abs_join(CORPORA_DIR, args.TARGET)
|
||||
if not args.artifact:
|
||||
args.artifact = abs_join(CORPORA_DIR, '{}-crash'.format(args.TARGET))
|
||||
if not args.seed:
|
||||
args.seed = abs_join(CORPORA_DIR, '{}-seed'.format(args.TARGET))
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def libfuzzer(args):
|
||||
try:
|
||||
args = libfuzzer_parser(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
target = abs_join(FUZZ_DIR, args.TARGET)
|
||||
def libfuzzer(target, corpora=None, artifact=None, seed=None, extra_args=None):
|
||||
if corpora is None:
|
||||
corpora = abs_join(CORPORA_DIR, target)
|
||||
if artifact is None:
|
||||
artifact = abs_join(CORPORA_DIR, '{}-crash'.format(target))
|
||||
if seed is None:
|
||||
seed = abs_join(CORPORA_DIR, '{}-seed'.format(target))
|
||||
if extra_args is None:
|
||||
extra_args = []
|
||||
|
||||
corpora = [create(args.corpora)]
|
||||
artifact = create(args.artifact)
|
||||
seed = check(args.seed)
|
||||
target = abs_join(FUZZ_DIR, target)
|
||||
|
||||
corpora = [create(corpora)]
|
||||
artifact = create(artifact)
|
||||
seed = check(seed)
|
||||
|
||||
corpora += [artifact]
|
||||
if seed is not None:
|
||||
corpora += [seed]
|
||||
|
||||
cmd = [target, '-artifact_prefix={}/'.format(artifact)]
|
||||
cmd += corpora + args.extra
|
||||
cmd += corpora + extra_args
|
||||
print(' '.join(cmd))
|
||||
subprocess.call(cmd)
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
|
||||
def libfuzzer_cmd(args):
|
||||
try:
|
||||
args = libfuzzer_parser(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
libfuzzer(args.TARGET, args.corpora, args.artifact, args.seed, args.extra)
|
||||
return 0
|
||||
|
||||
|
||||
|
@ -518,39 +553,15 @@ def afl(args):
|
|||
return 0
|
||||
|
||||
|
||||
def regression_parser(args):
|
||||
description = """
|
||||
Runs one or more regression tests.
|
||||
The fuzzer should have been built with with
|
||||
LIB_FUZZING_ENGINE='libregression.a'.
|
||||
Takes input from CORPORA.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
nargs='*',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS)))
|
||||
args = parser.parse_args(args)
|
||||
|
||||
targets = set()
|
||||
for target in args.TARGET:
|
||||
if not target:
|
||||
continue
|
||||
if target == 'all':
|
||||
targets = targets.union(TARGETS)
|
||||
elif target in TARGETS:
|
||||
targets.add(target)
|
||||
else:
|
||||
raise RuntimeError('{} is not a valid target'.format(target))
|
||||
args.TARGET = list(targets)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def regression(args):
|
||||
try:
|
||||
args = regression_parser(args)
|
||||
description = """
|
||||
Runs one or more regression tests.
|
||||
The fuzzer should have been built with with
|
||||
LIB_FUZZING_ENGINE='libregression.a'.
|
||||
Takes input from CORPORA.
|
||||
"""
|
||||
args = targets_parser(args, description)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
|
@ -673,6 +684,52 @@ def gen(args):
|
|||
return 0
|
||||
|
||||
|
||||
def minimize(args):
|
||||
try:
|
||||
description = """
|
||||
Runs a libfuzzer fuzzer with -merge=1 to build a minimal corpus in
|
||||
TARGET_seed_corpus. All extra args are passed to libfuzzer.
|
||||
"""
|
||||
args = targets_parser(args, description)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
|
||||
for target in args.TARGET:
|
||||
# Merge the corpus + anything else into the seed_corpus
|
||||
corpus = abs_join(CORPORA_DIR, target)
|
||||
seed_corpus = abs_join(CORPORA_DIR, "{}_seed_corpus".format(target))
|
||||
extra_args = [corpus, "-merge=1"] + args.extra
|
||||
libfuzzer(target, corpora=seed_corpus, extra_args=extra_args)
|
||||
seeds = set(os.listdir(seed_corpus))
|
||||
# Copy all crashes directly into the seed_corpus if not already present
|
||||
crashes = abs_join(CORPORA_DIR, '{}-crash'.format(target))
|
||||
for crash in os.listdir(crashes):
|
||||
if crash not in seeds:
|
||||
shutil.copy(abs_join(crashes, crash), seed_corpus)
|
||||
seeds.add(crash)
|
||||
|
||||
|
||||
def zip_cmd(args):
|
||||
try:
|
||||
description = """
|
||||
Zips up the seed corpus.
|
||||
"""
|
||||
args = targets_parser(args, description)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
|
||||
for target in args.TARGET:
|
||||
# Zip the seed_corpus
|
||||
seed_corpus = abs_join(CORPORA_DIR, "{}_seed_corpus".format(target))
|
||||
seeds = [abs_join(seed_corpus, f) for f in os.listdir(seed_corpus)]
|
||||
zip_file = "{}.zip".format(seed_corpus)
|
||||
cmd = ["zip", "-q", "-j", "-9", zip_file]
|
||||
print(' '.join(cmd + [abs_join(seed_corpus, '*')]))
|
||||
subprocess.check_call(cmd + seeds)
|
||||
|
||||
|
||||
def short_help(args):
|
||||
name = args[0]
|
||||
print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name))
|
||||
|
@ -690,6 +747,8 @@ def help(args):
|
|||
print("\tafl\t\tRun an AFL fuzzer")
|
||||
print("\tregression\tRun a regression test")
|
||||
print("\tgen\t\tGenerate a seed corpus for a fuzzer")
|
||||
print("\tminimize\tMinimize the test corpora")
|
||||
print("\tzip\t\tZip the minimized corpora up")
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -705,13 +764,17 @@ def main():
|
|||
if command == "build":
|
||||
return build(args)
|
||||
if command == "libfuzzer":
|
||||
return libfuzzer(args)
|
||||
return libfuzzer_cmd(args)
|
||||
if command == "regression":
|
||||
return regression(args)
|
||||
if command == "afl":
|
||||
return afl(args)
|
||||
if command == "gen":
|
||||
return gen(args)
|
||||
if command == "minimize":
|
||||
return minimize(args)
|
||||
if command == "zip":
|
||||
return zip_cmd(args)
|
||||
short_help(args)
|
||||
print("Error: No such command {} (pass -h for help)".format(command))
|
||||
return 1
|
||||
|
|
Loading…
Reference in New Issue