266 lines
7.9 KiB
Python
266 lines
7.9 KiB
Python
|
|
#!/usr/bin/env python
|
||
|
|
# -*- coding:utf-8 -*-
|
||
|
|
#
|
||
|
|
# Copyright (c) 2021 Huawei Device Co., Ltd.
|
||
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
|
# you may not use this file except in compliance with the License.
|
||
|
|
# You may obtain a copy of the License at
|
||
|
|
#
|
||
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
#
|
||
|
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
|
# See the License for the specific language governing permissions and
|
||
|
|
# limitations under the License.
|
||
|
|
#
|
||
|
|
|
||
|
|
from __future__ import print_function
|
||
|
|
import argparse
|
||
|
|
import os
|
||
|
|
import re
|
||
|
|
import sys
|
||
|
|
import subprocess
|
||
|
|
import zipfile
|
||
|
|
import errno
|
||
|
|
import pipes
|
||
|
|
import traceback
|
||
|
|
import time
|
||
|
|
import copy
|
||
|
|
import shutil
|
||
|
|
from pprint import pprint
|
||
|
|
|
||
|
|
from tools.colored import Colored
|
||
|
|
from tools.templates import GN_ENTRY_TEMPLATE
|
||
|
|
from tools.templates import PROJECT_GN_TEMPLATE
|
||
|
|
from tools.templates import PROJECT_DEMO_TEMPLATE
|
||
|
|
from tools.templates import PROJECT_HEADER_TEMPLATE
|
||
|
|
from tools.templates import PROJECT_XML_TEMPLATE
|
||
|
|
from tools.run_result import RunResult
|
||
|
|
|
||
|
|
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||
|
|
SOURCE_ROOT_DIR = os.path.dirname(
|
||
|
|
os.path.dirname(
|
||
|
|
os.path.dirname(os.path.dirname(CURRENT_DIR))
|
||
|
|
)
|
||
|
|
)
|
||
|
|
SOURCE_OUT_DIR = os.path.join(SOURCE_ROOT_DIR, "out")
|
||
|
|
|
||
|
|
TDD_BUILD_GN_PATH = os.path.join(
|
||
|
|
SOURCE_ROOT_DIR,
|
||
|
|
"test/testfwk/developer_test/BUILD.gn"
|
||
|
|
)
|
||
|
|
###project name must end with _fuzzer. eg. my_fuzzer,extrator_fuzzer.
|
||
|
|
VALID_PROJECT_NAME_REGEX = re.compile(r'^[a-zA-Z0-9_-]+(_fuzzer)+$')
|
||
|
|
|
||
|
|
|
||
|
|
def _add_environment_args(parser):
|
||
|
|
"""Add common environment args."""
|
||
|
|
parser.add_argument(
|
||
|
|
'-t',
|
||
|
|
'--target_platform',
|
||
|
|
default='phone',
|
||
|
|
choices=["phone", "ivi", "plato"],
|
||
|
|
help="set target_platform value, default:phone")
|
||
|
|
|
||
|
|
parser.add_argument(
|
||
|
|
'-f',
|
||
|
|
'--filter',
|
||
|
|
default=None,
|
||
|
|
help="subsystem filter")
|
||
|
|
|
||
|
|
|
||
|
|
def _get_command_string(command):
|
||
|
|
"""Returns a shell escaped command string."""
|
||
|
|
return ' '.join(pipes.quote(part) for part in command)
|
||
|
|
|
||
|
|
|
||
|
|
def parse_projects_path():
|
||
|
|
path_list = []
|
||
|
|
with open(TDD_BUILD_GN_PATH, 'r') as gn_file:
|
||
|
|
for line in gn_file.readlines()[4:]:
|
||
|
|
striped_str = line.strip()
|
||
|
|
if striped_str.endswith("]"):
|
||
|
|
break
|
||
|
|
path_list.append(striped_str.split(":")[0][3:])
|
||
|
|
return path_list
|
||
|
|
|
||
|
|
|
||
|
|
def _get_fuzzer_yaml_config(fuzzer_name):
|
||
|
|
project_yaml_path = os.path.join(
|
||
|
|
CURRENT_DIR,
|
||
|
|
"projects",
|
||
|
|
fuzzer_name,
|
||
|
|
"project.yaml")
|
||
|
|
if not os.path.exists(project_yaml_path):
|
||
|
|
return
|
||
|
|
#log run stdout to fuzzlog dir
|
||
|
|
with open(project_yaml_path) as filehandle:
|
||
|
|
yaml_config = yaml.safe_load(filehandle)
|
||
|
|
return yaml_config
|
||
|
|
|
||
|
|
|
||
|
|
#generate template fuzzer project
|
||
|
|
def generate(args):
|
||
|
|
print("project name %s." % args.project_name)
|
||
|
|
print("project path %s." % args.project_path)
|
||
|
|
color_logger = Colored.get_project_logger()
|
||
|
|
|
||
|
|
if not VALID_PROJECT_NAME_REGEX.match(args.project_name):
|
||
|
|
print('Invalid project name.', file=sys.stderr)
|
||
|
|
return 1
|
||
|
|
|
||
|
|
template_args = {
|
||
|
|
'project_name': args.project_name,
|
||
|
|
'author': "",
|
||
|
|
'email': ""
|
||
|
|
}
|
||
|
|
|
||
|
|
project_dir_path = os.path.join(args.project_path, args.project_name)
|
||
|
|
print("project_dir_path %s." % project_dir_path)
|
||
|
|
try:
|
||
|
|
os.mkdir(project_dir_path)
|
||
|
|
except OSError as os_exception:
|
||
|
|
if os_exception.errno != errno.EEXIST:
|
||
|
|
raise
|
||
|
|
print(color_logger.red('%s already exists.' % project_dir_path),
|
||
|
|
file=sys.stderr)
|
||
|
|
return 1
|
||
|
|
color_logger.green('Writing new files to %s' % project_dir_path)
|
||
|
|
|
||
|
|
file_path = os.path.join(project_dir_path, 'project.xml')
|
||
|
|
with open(file_path, 'w') as filehandle:
|
||
|
|
filehandle.write(PROJECT_XML_TEMPLATE % template_args)
|
||
|
|
|
||
|
|
file_path = os.path.join(project_dir_path, "%s.cpp" % args.project_name)
|
||
|
|
with open(file_path, 'w') as filehandle:
|
||
|
|
filehandle.write(PROJECT_DEMO_TEMPLATE % template_args)
|
||
|
|
|
||
|
|
file_path = os.path.join(project_dir_path, "%s.h" % args.project_name)
|
||
|
|
with open(file_path, 'w') as filehandle:
|
||
|
|
filehandle.write(PROJECT_HEADER_TEMPLATE % template_args)
|
||
|
|
file_path = os.path.join(project_dir_path, "BUILD.gn")
|
||
|
|
with open(file_path, 'w') as filehandle:
|
||
|
|
filehandle.write(PROJECT_GN_TEMPLATE % template_args)
|
||
|
|
|
||
|
|
corpus_dir = os.path.join(project_dir_path, 'corpus')
|
||
|
|
if not os.path.exists(corpus_dir):
|
||
|
|
os.mkdir(corpus_dir)
|
||
|
|
with open(os.path.join(corpus_dir, 'init'), 'w') as filehandle:
|
||
|
|
filehandle.write("FUZZ")
|
||
|
|
|
||
|
|
|
||
|
|
#complie fuzzer project
|
||
|
|
def make(args, stdout=None):
|
||
|
|
"""make fuzzer module."""
|
||
|
|
color_logger = Colored.get_project_logger()
|
||
|
|
|
||
|
|
pre_cmd = ['cd', SOURCE_ROOT_DIR]
|
||
|
|
build_target_platform = "build_platform=\"%s\""
|
||
|
|
|
||
|
|
build_script = [
|
||
|
|
'./build.sh',
|
||
|
|
'--gn-args',
|
||
|
|
'build_example=true',
|
||
|
|
'--build-target'
|
||
|
|
]
|
||
|
|
build_script.append(args.project_name)
|
||
|
|
build_script.append("--gn-args")
|
||
|
|
build_script.append(build_target_platform % args.build_platform)
|
||
|
|
build_script.append("--product-name")
|
||
|
|
build_script.append(args.build_platform)
|
||
|
|
build_script.append("--export-para")
|
||
|
|
build_script.append("PYCACHE_ENABLE:true")
|
||
|
|
build_script.append("--export-para")
|
||
|
|
build_script.append("BUILD_AOSP:false")
|
||
|
|
print("BUILD_SCRIPT %s" % build_script)
|
||
|
|
final_cmd = "%s && %s" % (
|
||
|
|
_get_command_string(pre_cmd),
|
||
|
|
_get_command_string(build_script)
|
||
|
|
)
|
||
|
|
|
||
|
|
color_logger.green('Running:%s' % final_cmd)
|
||
|
|
|
||
|
|
subsystem_src_flag_file_path = os.path.join(
|
||
|
|
SOURCE_OUT_DIR,
|
||
|
|
"release/current_build_fuzz_target.txt"
|
||
|
|
)
|
||
|
|
if not os.path.exists(os.path.dirname(subsystem_src_flag_file_path)):
|
||
|
|
os.makedirs(os.path.dirname(subsystem_src_flag_file_path))
|
||
|
|
with open(subsystem_src_flag_file_path, "wb") as file_handle:
|
||
|
|
file_handle.write(args.project_name.encode())
|
||
|
|
|
||
|
|
try:
|
||
|
|
if stdout:
|
||
|
|
ret = subprocess.check_call(build_script, cwd=SOURCE_ROOT_DIR,
|
||
|
|
stdout=stdout)
|
||
|
|
else:
|
||
|
|
ret = subprocess.check_call(build_script, cwd=SOURCE_ROOT_DIR)
|
||
|
|
return ret
|
||
|
|
except subprocess.CalledProcessError:
|
||
|
|
print("*" * 50)
|
||
|
|
print("*" * 50)
|
||
|
|
print(
|
||
|
|
'fuzzers {} build failed.'.format(args.project_name),
|
||
|
|
file=sys.stdout
|
||
|
|
)
|
||
|
|
return -1
|
||
|
|
|
||
|
|
|
||
|
|
def report(args):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
def coverage_all(args):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
parser = argparse.ArgumentParser(
|
||
|
|
'fuzzer_helper.py',
|
||
|
|
description='hydra-fuzz helpers'
|
||
|
|
)
|
||
|
|
subparsers = parser.add_subparsers(dest='command')
|
||
|
|
|
||
|
|
generate_parser = subparsers.add_parser(
|
||
|
|
'generate',
|
||
|
|
help='Generate files for new project.name must end with "_fuzzer".')
|
||
|
|
generate_parser.add_argument('project_name')
|
||
|
|
generate_parser.add_argument('project_path')
|
||
|
|
_add_environment_args(generate_parser)
|
||
|
|
|
||
|
|
make_parser = subparsers.add_parser(
|
||
|
|
'make', help='Build a single fuzzer module project. ')
|
||
|
|
make_parser.add_argument('project_name')
|
||
|
|
make_parser.add_argument('build_platform')
|
||
|
|
_add_environment_args(make_parser)
|
||
|
|
|
||
|
|
report_parser = subparsers.add_parser(
|
||
|
|
'report', help='Report fuzzer log'
|
||
|
|
)
|
||
|
|
_add_environment_args(report_parser)
|
||
|
|
report_parser.add_argument(
|
||
|
|
'subfunc',
|
||
|
|
default="list",
|
||
|
|
choices=["list", "coverage", "all"]
|
||
|
|
)
|
||
|
|
report_parser.add_argument(
|
||
|
|
"-i",
|
||
|
|
"--id",
|
||
|
|
required=False,
|
||
|
|
help="report ID, e.g. empty_fuzzer.20200211184850"
|
||
|
|
)
|
||
|
|
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
if args.command == 'generate':
|
||
|
|
return generate(args)
|
||
|
|
elif args.command == 'make':
|
||
|
|
return make(args)
|
||
|
|
|
||
|
|
elif args.command == 'report':
|
||
|
|
report(args)
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|