From ea9448bd9db6545769f3ebdc1ff9233a0fbfdcc5 Mon Sep 17 00:00:00 2001 From: Arthur Chan Date: Mon, 3 Feb 2025 08:05:42 +0000 Subject: [PATCH] Analyser: Porting easy-params-far-reach from webapp to separate analyser Signed-off-by: Arthur Chan --- .../far_reach_low_coverage_analyser.py | 47 ++++++++++++++++--- src/fuzz_introspector/cli.py | 10 ++++ src/fuzz_introspector/commands.py | 6 ++- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/fuzz_introspector/analyses/far_reach_low_coverage_analyser.py b/src/fuzz_introspector/analyses/far_reach_low_coverage_analyser.py index ca6be5849..59d50dbca 100644 --- a/src/fuzz_introspector/analyses/far_reach_low_coverage_analyser.py +++ b/src/fuzz_introspector/analyses/far_reach_low_coverage_analyser.py @@ -70,17 +70,23 @@ def set_json_string_result(self, string): def set_flags(self, exclude_static_functions: bool, only_referenced_functions: bool, only_header_functions: bool, - only_interesting_functions: bool): + only_interesting_functions: bool, + only_easy_fuzz_params: bool): """Configure the flags from the CLI.""" self.exclude_static_functions = exclude_static_functions self.only_referenced_functions = only_referenced_functions self.only_header_functions = only_header_functions self.only_interesting_functions = only_interesting_functions + self.only_easy_fuzz_params = only_easy_fuzz_params def set_max_functions(self, max_functions: int): """Configure the max functions to return from CLI.""" self.max_functions = max_functions + def set_min_complexity(self, min_complexity: int): + """Configure the min complexity of functions to return from CLI.""" + self.min_complexity = min_complexity + def set_introspection_project( self, introspection_project: analysis.IntrospectionProject): """Configure the introspection project wrapper for retrieving @@ -101,9 +107,12 @@ def analysis_func(self, 'only_referenced_functions: %s, ' 'only_header_functions: %s, ' 'only_interesting_functions: %s, ' - 'max_functions: %d', self.exclude_static_functions, - self.only_referenced_functions, self.only_header_functions, - self.only_interesting_functions, self.max_functions) + 'only_easy_fuzz_params: %s, ' + 'min_complexity: %d, max_functions: %d', + self.exclude_static_functions, self.only_referenced_functions, + self.only_header_functions, self.only_interesting_functions, + self.only_easy_fuzz_params, self.min_complexity, + self.max_functions) result_list: List[Dict[str, Any]] = [] @@ -147,6 +156,11 @@ def analysis_func(self, function)): continue + # Check for functions with easy fuzz parameters + if (self.only_easy_fuzz_params + and not self._is_function_with_easy_fuzz_params(function)): + continue + result_list.append( function.to_dict( proj_profile.get_func_hit_percentage( @@ -194,8 +208,15 @@ def _get_functions_of_interest( coverage = proj_profile.get_func_hit_percentage( function.function_name) - if coverage < 20.0: - filtered_functions.append(function) + # Skip high coverage + if coverage > 20.0: + continue + + # Skip low complexity by configured value + if function.cyclomatic_complexity < self.min_complexity: + continue + + filtered_functions.append(function) # Sort the filtered functions filtered_functions.sort(key=lambda x: ( @@ -229,3 +250,17 @@ def _is_interesting_function_with_fuzz_keywords( return True return False + + def _is_function_with_easy_fuzz_params( + self, function: function_profile.FunctionProfile) -> bool: + """Internal helper to determine if the function only contains + parameters that are easy to fuzz.""" + if len(function.arg_types) == 2: + return ('char *' in function.arg_types[0] + and 'int' in function.arg_types[1]) + + if len(function.arg_types) == 1: + return ('char *' in function.arg_types[0] + or 'string' in function.arg_types[0]) + + return False diff --git a/src/fuzz_introspector/cli.py b/src/fuzz_introspector/cli.py index c1ca64ef4..2a1e893e1 100644 --- a/src/fuzz_introspector/cli.py +++ b/src/fuzz_introspector/cli.py @@ -207,11 +207,21 @@ def get_cmdline_parser() -> argparse.ArgumentParser: action='store_true', help=('Excluding functions without interesting fuzz keywords, like' 'parse or deserialise')) + far_reach_low_coverage_analyser_parser.add_argument( + '--only-easy-fuzz-params', + action='store_true', + help=('Only include functions with easy fuzz parameters, like char*' + 'int, or string')) far_reach_low_coverage_analyser_parser.add_argument( '--max-functions', default=30, type=int, help='The max number of functions returned by this analysis.') + far_reach_low_coverage_analyser_parser.add_argument( + '--min-complexity', + default=0, + type=int, + help='The min cyclomatic complexity of the functions returned.') far_reach_low_coverage_analyser_parser.add_argument( '--target-dir', type=str, diff --git a/src/fuzz_introspector/commands.py b/src/fuzz_introspector/commands.py index b35eb1611..3f11c37cf 100644 --- a/src/fuzz_introspector/commands.py +++ b/src/fuzz_introspector/commands.py @@ -251,15 +251,19 @@ def analyse(args) -> int: only_referenced_functions = args.only_referenced_functions only_header_functions = args.only_header_functions only_interesting_functions = args.only_interesting_functions + only_easy_fuzz_params = args.only_easy_fuzz_params max_functions = args.max_functions + min_complexity = args.min_complexity introspection_proj.load_debug_report(out_dir) target_analyser.set_flags(exclude_static_functions, only_referenced_functions, only_header_functions, - only_interesting_functions) + only_interesting_functions, + only_easy_fuzz_params) target_analyser.set_max_functions(max_functions) + target_analyser.set_min_complexity(min_complexity) target_analyser.set_introspection_project(introspection_proj) # Run the analyser