| #!/usr/bin/env python3 |
| # SPDX-License-Identifier: BSD-2-Clause |
| import os |
| import argparse |
| import itertools |
| |
| # Makefile-fuzz-generated.am is created from this template. |
| MAKEFILE_FUZZ = '''# SPDX-License-Identifier: BSD-2-Clause |
| # Copyright (c) 2018 Intel Corporation |
| # All rights reserved. |
| |
| if ENABLE_TCTI_FUZZING |
| TESTS_FUZZ = %s |
| %s |
| endif # ENABLE_TCTI_FUZZING |
| ''' |
| # Each fuzz target in Makefile-fuzz-generated.am is created from this template. |
| MAKEFILE_FUZZ_TARGET = ''' |
| noinst_PROGRAMS += test/fuzz/%s.fuzz |
| test_fuzz_%s_fuzz_CPPFLAGS = $(FUZZ_CPPFLAGS) |
| test_fuzz_%s_fuzz_LDADD = $(FUZZLDADD) |
| nodist_test_fuzz_%s_fuzz_SOURCES = test/fuzz/main-sapi.cpp \\ |
| test/fuzz/%s.fuzz.cpp |
| |
| DISTCLEANFILES += test/fuzz/%s.fuzz.cpp''' |
| # Common include definitions needed for fuzzing an SAPI call |
| SAPI_TEMPLATE_HEADER = '''/* SPDX-License-Identifier: BSD-2-Clause */ |
| /*********************************************************************** |
| * Copyright (c) 2018, Intel Corporation |
| * |
| * All rights reserved. |
| ***********************************************************************/ |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <inttypes.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <poll.h> |
| #include <stdarg.h> |
| |
| #include <setjmp.h> |
| |
| extern "C" { |
| #include "tss2_mu.h" |
| #include "tss2_sys.h" |
| #include "tss2_tcti_device.h" |
| |
| #include "tss2-tcti/tcti-common.h" |
| #include "tss2-tcti/tcti-device.h" |
| |
| #define LOGMODULE fuzz |
| #include "tss2_tcti.h" |
| #include "util/log.h" |
| #include "test.h" |
| #include "test-options.h" |
| #include "context-util.h" |
| #include "tss2-sys/sysapi_util.h" |
| #include "tcti/tcti-fuzzing.h" |
| } |
| |
| extern "C" |
| int |
| test_invoke ( |
| TSS2_SYS_CONTEXT *sysContext)''' |
| # Template to call a SAPI _Complete function which takes no arguments |
| SAPI_COMPLETE_TEMPLATE_NO_ARGS = SAPI_TEMPLATE_HEADER + ''' |
| { |
| %s (sysContext); |
| |
| return EXIT_SUCCESS; |
| } |
| ''' |
| # Template to call a SAPI _Complete function which takes arguments |
| SAPI_COMPLETE_TEMPLATE_HAS_ARGS = SAPI_TEMPLATE_HEADER + ''' |
| { |
| %s |
| |
| %s ( |
| sysContext, |
| %s |
| ); |
| |
| return EXIT_SUCCESS; |
| } |
| ''' |
| # Template to call a SAPI _Prepare function |
| SAPI_PREPARE_TEMPLATE_HAS_ARGS = SAPI_TEMPLATE_HEADER + ''' |
| { |
| int ret; |
| %s |
| |
| ret = fuzz_fill ( |
| sysContext, |
| %d, |
| %s |
| ); |
| if (ret) { |
| return ret; |
| } |
| |
| %s ( |
| sysContext, |
| %s |
| ); |
| |
| return EXIT_SUCCESS; |
| } |
| ''' |
| |
| def gen_file(function): |
| ''' |
| Generate a cpp file used as the fuzz target given the function definition |
| from a header file. |
| ''' |
| # Parse the function name from the function definition |
| function_name = function.split('\n')[0]\ |
| .replace('TSS2_RC', '')\ |
| .replace('(', '')\ |
| .strip() |
| # Parse the function arguments into an array. Do not include sysContext. |
| args = [arg.strip() \ |
| for arg in function[function.index('(') + 1:function.index(');')]\ |
| .split(',') \ |
| if not 'TSS2_SYS_CONTEXT' in arg] |
| # Prepare and Complete functions require different methods of generation. |
| # Call the appropriate function to generate a cpp target specific to that |
| # type of function. |
| if '_Complete' in function_name: |
| return gen_complete(function, function_name, args) |
| if '_Prepare' in function_name: |
| return gen_prepare(function, function_name, args) |
| raise NotImplementedError('Unknown function type %r' % (function_name,)) |
| |
| def gen_complete(function, function_name, args): |
| ''' |
| Generate the cpp fuzz target for a SAPI _Complete call |
| ''' |
| if not args: |
| # Fill in the no args template. Simple case. |
| return function_name, SAPI_COMPLETE_TEMPLATE_NO_ARGS % (function_name) |
| # Generate the cpp variable definitions. |
| arg_definitions = (';\n' + ' ' * 4).join([ |
| arg.replace('*', '') for arg in args]) + ';' |
| # Generate the cpp arguments. For arguments that are pointers find replace * |
| # with & so that we pass a pointer to the definition which has been |
| # allocated on the stack. |
| arg_call = (',\n' + ' ' * 8).join([ |
| arg.replace('*', '&').split()[-1] for arg in args]) |
| # Fill in the template |
| return function_name, SAPI_COMPLETE_TEMPLATE_HAS_ARGS % (arg_definitions, |
| function_name, |
| arg_call) |
| |
| def gen_prepare(function, function_name, args): |
| ''' |
| Generate the cpp fuzz target for a SAPI _Prepare call |
| ''' |
| if not args: |
| return function_name, None |
| # Generate the cpp variable definitions. Make sure to initialize to empty |
| # structs (works for initializing anything) or cpp compiler will complain. |
| arg_definitions = (' = {0};\n' + ' ' * 4).join([ |
| arg.replace('*', '').replace('const', '') for arg in args]) + ' = {0};' |
| # Generate the cpp arguments. For arguments that are pointers find replace * |
| # with & so that we pass a pointer to the definition which has been |
| # allocated on the stack. |
| arg_call = (',\n' + ' ' * 8).join([ |
| arg.replace('*', '&').split()[-1] for arg in args]) |
| # Generate the call to fuzz_fill. The call should be the sysContext, double |
| # the number of arguments for the _Prepare call, and then for each _Prepare |
| # argument pass two to fuzz_fill, the sizeof the _Prepare argument, and a |
| # pointer to it. |
| fill_fuzz_args = (',\n' + ' ' * 8).join([ |
| ('sizeof (%s), &%s' % \ |
| tuple([arg.replace('*', '').split()[-1]] * 2)) \ |
| for arg in args]) |
| # Fill in the template |
| return function_name, SAPI_PREPARE_TEMPLATE_HAS_ARGS % (arg_definitions, |
| len(args) * 2, |
| fill_fuzz_args, |
| function_name, |
| arg_call) |
| |
| def functions_from_include(header): |
| ''' |
| Parse out and yield each function definition from a header file. |
| ''' |
| with open(header, 'r') as header_fd: |
| current_function = '' |
| for line in header_fd: |
| # Functions we are interested in start with _Complete or _Prepare |
| if '_Complete' in line or '_Prepare' in line: |
| # Set the current_function to this line |
| current_function = line |
| elif current_function and ');' in line: |
| # When we reach the closing parenthesis yield the function |
| yield current_function + line.rstrip() |
| current_function = '' |
| elif current_function: |
| # Add all the arguments to the function |
| current_function += line |
| |
| def gen_files(header): |
| # Generate a fuzz target cpp file from each function in the header file |
| for current_function in functions_from_include(header): |
| function_name, contents = gen_file(current_function) |
| # Skip the yield if there is no fuzz target that can be generated |
| if contents is None: |
| continue |
| # Yield the function name and the contents of its generated file |
| yield function_name, contents |
| |
| def main(): |
| parser = argparse.ArgumentParser(description='Generate libfuzzer for sapi') |
| parser.add_argument('--header', default='include/tss2/tss2_sys.h', |
| help='Header file to look in (default include/tss2/tss2_sys.h)') |
| args = parser.parse_args() |
| |
| functions = dict(gen_files(args.header)) |
| # Write the generated target to the file for its function name |
| for function_name, contents in functions.items(): |
| filepath = os.path.join('test', 'fuzz', function_name + '.fuzz.cpp') |
| with open(filepath, 'w') as fuzzer_fd: |
| fuzzer_fd.write(contents) |
| # Fill in the Makefile-fuzz-generated.am template using the function names. |
| # Create a list of the compiled fuzz targets |
| files = ' \\\n '.join(['test/fuzz/%s.fuzz' % (function) \ |
| for function in functions]) |
| # Create the Makefile targets for each generated file |
| targets = '\n'.join([MAKEFILE_FUZZ_TARGET % tuple(list(itertools.chain(\ |
| ([function] * 6)))) for function in functions]) |
| # Write out the Makefile-fuzz-generated.am file |
| with open('Makefile-fuzz-generated.am', 'w') as makefile_fd: |
| makefile_fd.write(MAKEFILE_FUZZ % (files, targets)) |
| |
| if __name__ == '__main__': |
| main() |