[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)
|
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):
|
def parse_env_flags(args, flags):
|
||||||
"""
|
"""
|
||||||
Look for flags set by environment variables.
|
Look for flags set by environment variables.
|
||||||
|
@ -424,36 +453,42 @@ def libfuzzer_parser(args):
|
||||||
if args.TARGET and args.TARGET not in TARGETS:
|
if args.TARGET and args.TARGET not in TARGETS:
|
||||||
raise RuntimeError('{} is not a valid target'.format(args.TARGET))
|
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
|
return args
|
||||||
|
|
||||||
|
|
||||||
def libfuzzer(args):
|
def libfuzzer(target, corpora=None, artifact=None, seed=None, extra_args=None):
|
||||||
try:
|
if corpora is None:
|
||||||
args = libfuzzer_parser(args)
|
corpora = abs_join(CORPORA_DIR, target)
|
||||||
except Exception as e:
|
if artifact is None:
|
||||||
print(e)
|
artifact = abs_join(CORPORA_DIR, '{}-crash'.format(target))
|
||||||
return 1
|
if seed is None:
|
||||||
target = abs_join(FUZZ_DIR, args.TARGET)
|
seed = abs_join(CORPORA_DIR, '{}-seed'.format(target))
|
||||||
|
if extra_args is None:
|
||||||
|
extra_args = []
|
||||||
|
|
||||||
corpora = [create(args.corpora)]
|
target = abs_join(FUZZ_DIR, target)
|
||||||
artifact = create(args.artifact)
|
|
||||||
seed = check(args.seed)
|
corpora = [create(corpora)]
|
||||||
|
artifact = create(artifact)
|
||||||
|
seed = check(seed)
|
||||||
|
|
||||||
corpora += [artifact]
|
corpora += [artifact]
|
||||||
if seed is not None:
|
if seed is not None:
|
||||||
corpora += [seed]
|
corpora += [seed]
|
||||||
|
|
||||||
cmd = [target, '-artifact_prefix={}/'.format(artifact)]
|
cmd = [target, '-artifact_prefix={}/'.format(artifact)]
|
||||||
cmd += corpora + args.extra
|
cmd += corpora + extra_args
|
||||||
print(' '.join(cmd))
|
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
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -518,39 +553,15 @@ def afl(args):
|
||||||
return 0
|
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):
|
def regression(args):
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
return 1
|
return 1
|
||||||
|
@ -673,6 +684,52 @@ def gen(args):
|
||||||
return 0
|
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):
|
def short_help(args):
|
||||||
name = args[0]
|
name = args[0]
|
||||||
print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name))
|
print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name))
|
||||||
|
@ -690,6 +747,8 @@ def help(args):
|
||||||
print("\tafl\t\tRun an AFL fuzzer")
|
print("\tafl\t\tRun an AFL fuzzer")
|
||||||
print("\tregression\tRun a regression test")
|
print("\tregression\tRun a regression test")
|
||||||
print("\tgen\t\tGenerate a seed corpus for a fuzzer")
|
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():
|
def main():
|
||||||
|
@ -705,13 +764,17 @@ def main():
|
||||||
if command == "build":
|
if command == "build":
|
||||||
return build(args)
|
return build(args)
|
||||||
if command == "libfuzzer":
|
if command == "libfuzzer":
|
||||||
return libfuzzer(args)
|
return libfuzzer_cmd(args)
|
||||||
if command == "regression":
|
if command == "regression":
|
||||||
return regression(args)
|
return regression(args)
|
||||||
if command == "afl":
|
if command == "afl":
|
||||||
return afl(args)
|
return afl(args)
|
||||||
if command == "gen":
|
if command == "gen":
|
||||||
return gen(args)
|
return gen(args)
|
||||||
|
if command == "minimize":
|
||||||
|
return minimize(args)
|
||||||
|
if command == "zip":
|
||||||
|
return zip_cmd(args)
|
||||||
short_help(args)
|
short_help(args)
|
||||||
print("Error: No such command {} (pass -h for help)".format(command))
|
print("Error: No such command {} (pass -h for help)".format(command))
|
||||||
return 1
|
return 1
|
||||||
|
|
Loading…
Reference in New Issue