xref: /aosp_15_r20/external/tpm2-tss/script/gen_fuzz.py (revision 758e9fba6fc9adbf15340f70c73baee7b168b1c9)
1*758e9fbaSOystein Eftevaag#!/usr/bin/env python3
2*758e9fbaSOystein Eftevaag# SPDX-License-Identifier: BSD-2-Clause
3*758e9fbaSOystein Eftevaagimport os
4*758e9fbaSOystein Eftevaagimport argparse
5*758e9fbaSOystein Eftevaagimport itertools
6*758e9fbaSOystein Eftevaag
7*758e9fbaSOystein Eftevaag# Makefile-fuzz-generated.am is created from this template.
8*758e9fbaSOystein EftevaagMAKEFILE_FUZZ = '''# SPDX-License-Identifier: BSD-2-Clause
9*758e9fbaSOystein Eftevaag# Copyright (c) 2018 Intel Corporation
10*758e9fbaSOystein Eftevaag# All rights reserved.
11*758e9fbaSOystein Eftevaag
12*758e9fbaSOystein Eftevaagif ENABLE_TCTI_FUZZING
13*758e9fbaSOystein EftevaagTESTS_FUZZ = %s
14*758e9fbaSOystein Eftevaag%s
15*758e9fbaSOystein Eftevaagendif # ENABLE_TCTI_FUZZING
16*758e9fbaSOystein Eftevaag'''
17*758e9fbaSOystein Eftevaag# Each fuzz target in Makefile-fuzz-generated.am is created from this template.
18*758e9fbaSOystein EftevaagMAKEFILE_FUZZ_TARGET = '''
19*758e9fbaSOystein Eftevaagnoinst_PROGRAMS += test/fuzz/%s.fuzz
20*758e9fbaSOystein Eftevaagtest_fuzz_%s_fuzz_CPPFLAGS = $(FUZZ_CPPFLAGS)
21*758e9fbaSOystein Eftevaagtest_fuzz_%s_fuzz_LDADD    = $(FUZZLDADD)
22*758e9fbaSOystein Eftevaagnodist_test_fuzz_%s_fuzz_SOURCES  = test/fuzz/main-sapi.cpp \\
23*758e9fbaSOystein Eftevaag        test/fuzz/%s.fuzz.cpp
24*758e9fbaSOystein Eftevaag
25*758e9fbaSOystein EftevaagDISTCLEANFILES += test/fuzz/%s.fuzz.cpp'''
26*758e9fbaSOystein Eftevaag# Common include definitions needed for fuzzing an SAPI call
27*758e9fbaSOystein EftevaagSAPI_TEMPLATE_HEADER = '''/* SPDX-License-Identifier: BSD-2-Clause */
28*758e9fbaSOystein Eftevaag/***********************************************************************
29*758e9fbaSOystein Eftevaag * Copyright (c) 2018, Intel Corporation
30*758e9fbaSOystein Eftevaag *
31*758e9fbaSOystein Eftevaag * All rights reserved.
32*758e9fbaSOystein Eftevaag ***********************************************************************/
33*758e9fbaSOystein Eftevaag#ifdef HAVE_CONFIG_H
34*758e9fbaSOystein Eftevaag#include <config.h>
35*758e9fbaSOystein Eftevaag#endif
36*758e9fbaSOystein Eftevaag
37*758e9fbaSOystein Eftevaag#include <inttypes.h>
38*758e9fbaSOystein Eftevaag#include <stdbool.h>
39*758e9fbaSOystein Eftevaag#include <stdio.h>
40*758e9fbaSOystein Eftevaag#include <string.h>
41*758e9fbaSOystein Eftevaag#include <poll.h>
42*758e9fbaSOystein Eftevaag#include <stdarg.h>
43*758e9fbaSOystein Eftevaag
44*758e9fbaSOystein Eftevaag#include <setjmp.h>
45*758e9fbaSOystein Eftevaag
46*758e9fbaSOystein Eftevaagextern "C" {
47*758e9fbaSOystein Eftevaag#include "tss2_mu.h"
48*758e9fbaSOystein Eftevaag#include "tss2_sys.h"
49*758e9fbaSOystein Eftevaag#include "tss2_tcti_device.h"
50*758e9fbaSOystein Eftevaag
51*758e9fbaSOystein Eftevaag#include "tss2-tcti/tcti-common.h"
52*758e9fbaSOystein Eftevaag#include "tss2-tcti/tcti-device.h"
53*758e9fbaSOystein Eftevaag
54*758e9fbaSOystein Eftevaag#define LOGMODULE fuzz
55*758e9fbaSOystein Eftevaag#include "tss2_tcti.h"
56*758e9fbaSOystein Eftevaag#include "util/log.h"
57*758e9fbaSOystein Eftevaag#include "test.h"
58*758e9fbaSOystein Eftevaag#include "test-options.h"
59*758e9fbaSOystein Eftevaag#include "context-util.h"
60*758e9fbaSOystein Eftevaag#include "tss2-sys/sysapi_util.h"
61*758e9fbaSOystein Eftevaag#include "tcti/tcti-fuzzing.h"
62*758e9fbaSOystein Eftevaag}
63*758e9fbaSOystein Eftevaag
64*758e9fbaSOystein Eftevaagextern "C"
65*758e9fbaSOystein Eftevaagint
66*758e9fbaSOystein Eftevaagtest_invoke (
67*758e9fbaSOystein Eftevaag        TSS2_SYS_CONTEXT *sysContext)'''
68*758e9fbaSOystein Eftevaag# Template to call a SAPI _Complete function which takes no arguments
69*758e9fbaSOystein EftevaagSAPI_COMPLETE_TEMPLATE_NO_ARGS = SAPI_TEMPLATE_HEADER + '''
70*758e9fbaSOystein Eftevaag{
71*758e9fbaSOystein Eftevaag    %s (sysContext);
72*758e9fbaSOystein Eftevaag
73*758e9fbaSOystein Eftevaag    return EXIT_SUCCESS;
74*758e9fbaSOystein Eftevaag}
75*758e9fbaSOystein Eftevaag'''
76*758e9fbaSOystein Eftevaag# Template to call a SAPI _Complete function which takes arguments
77*758e9fbaSOystein EftevaagSAPI_COMPLETE_TEMPLATE_HAS_ARGS = SAPI_TEMPLATE_HEADER + '''
78*758e9fbaSOystein Eftevaag{
79*758e9fbaSOystein Eftevaag    %s
80*758e9fbaSOystein Eftevaag
81*758e9fbaSOystein Eftevaag    %s (
82*758e9fbaSOystein Eftevaag        sysContext,
83*758e9fbaSOystein Eftevaag        %s
84*758e9fbaSOystein Eftevaag    );
85*758e9fbaSOystein Eftevaag
86*758e9fbaSOystein Eftevaag    return EXIT_SUCCESS;
87*758e9fbaSOystein Eftevaag}
88*758e9fbaSOystein Eftevaag'''
89*758e9fbaSOystein Eftevaag# Template to call a SAPI _Prepare function
90*758e9fbaSOystein EftevaagSAPI_PREPARE_TEMPLATE_HAS_ARGS = SAPI_TEMPLATE_HEADER + '''
91*758e9fbaSOystein Eftevaag{
92*758e9fbaSOystein Eftevaag    int ret;
93*758e9fbaSOystein Eftevaag    %s
94*758e9fbaSOystein Eftevaag
95*758e9fbaSOystein Eftevaag    ret = fuzz_fill (
96*758e9fbaSOystein Eftevaag        sysContext,
97*758e9fbaSOystein Eftevaag        %d,
98*758e9fbaSOystein Eftevaag        %s
99*758e9fbaSOystein Eftevaag    );
100*758e9fbaSOystein Eftevaag    if (ret) {
101*758e9fbaSOystein Eftevaag        return ret;
102*758e9fbaSOystein Eftevaag    }
103*758e9fbaSOystein Eftevaag
104*758e9fbaSOystein Eftevaag    %s (
105*758e9fbaSOystein Eftevaag        sysContext,
106*758e9fbaSOystein Eftevaag        %s
107*758e9fbaSOystein Eftevaag    );
108*758e9fbaSOystein Eftevaag
109*758e9fbaSOystein Eftevaag    return EXIT_SUCCESS;
110*758e9fbaSOystein Eftevaag}
111*758e9fbaSOystein Eftevaag'''
112*758e9fbaSOystein Eftevaag
113*758e9fbaSOystein Eftevaagdef gen_file(function):
114*758e9fbaSOystein Eftevaag    '''
115*758e9fbaSOystein Eftevaag    Generate a cpp file used as the fuzz target given the function definition
116*758e9fbaSOystein Eftevaag    from a header file.
117*758e9fbaSOystein Eftevaag    '''
118*758e9fbaSOystein Eftevaag    # Parse the function name from the function definition
119*758e9fbaSOystein Eftevaag    function_name = function.split('\n')[0]\
120*758e9fbaSOystein Eftevaag                            .replace('TSS2_RC', '')\
121*758e9fbaSOystein Eftevaag                            .replace('(', '')\
122*758e9fbaSOystein Eftevaag                            .strip()
123*758e9fbaSOystein Eftevaag    # Parse the function arguments into an array. Do not include sysContext.
124*758e9fbaSOystein Eftevaag    args = [arg.strip() \
125*758e9fbaSOystein Eftevaag            for arg in function[function.index('(') + 1:function.index(');')]\
126*758e9fbaSOystein Eftevaag            .split(',') \
127*758e9fbaSOystein Eftevaag            if not 'TSS2_SYS_CONTEXT' in arg]
128*758e9fbaSOystein Eftevaag    # Prepare and Complete functions require different methods of generation.
129*758e9fbaSOystein Eftevaag    # Call the appropriate function to generate a cpp target specific to that
130*758e9fbaSOystein Eftevaag    # type of function.
131*758e9fbaSOystein Eftevaag    if '_Complete' in function_name:
132*758e9fbaSOystein Eftevaag        return gen_complete(function, function_name, args)
133*758e9fbaSOystein Eftevaag    if '_Prepare' in function_name:
134*758e9fbaSOystein Eftevaag        return gen_prepare(function, function_name, args)
135*758e9fbaSOystein Eftevaag    raise NotImplementedError('Unknown function type %r' % (function_name,))
136*758e9fbaSOystein Eftevaag
137*758e9fbaSOystein Eftevaagdef gen_complete(function, function_name, args):
138*758e9fbaSOystein Eftevaag    '''
139*758e9fbaSOystein Eftevaag    Generate the cpp fuzz target for a SAPI _Complete call
140*758e9fbaSOystein Eftevaag    '''
141*758e9fbaSOystein Eftevaag    if not args:
142*758e9fbaSOystein Eftevaag        # Fill in the no args template. Simple case.
143*758e9fbaSOystein Eftevaag        return function_name, SAPI_COMPLETE_TEMPLATE_NO_ARGS % (function_name)
144*758e9fbaSOystein Eftevaag    # Generate the cpp variable definitions.
145*758e9fbaSOystein Eftevaag    arg_definitions = (';\n' + ' ' * 4).join([
146*758e9fbaSOystein Eftevaag        arg.replace('*', '') for arg in args]) + ';'
147*758e9fbaSOystein Eftevaag    # Generate the cpp arguments. For arguments that are pointers find replace *
148*758e9fbaSOystein Eftevaag    # with & so that we pass a pointer to the definition which has been
149*758e9fbaSOystein Eftevaag    # allocated on the stack.
150*758e9fbaSOystein Eftevaag    arg_call = (',\n' + ' ' * 8).join([
151*758e9fbaSOystein Eftevaag        arg.replace('*', '&').split()[-1] for arg in args])
152*758e9fbaSOystein Eftevaag    # Fill in the template
153*758e9fbaSOystein Eftevaag    return function_name, SAPI_COMPLETE_TEMPLATE_HAS_ARGS % (arg_definitions,
154*758e9fbaSOystein Eftevaag                                                             function_name,
155*758e9fbaSOystein Eftevaag                                                             arg_call)
156*758e9fbaSOystein Eftevaag
157*758e9fbaSOystein Eftevaagdef gen_prepare(function, function_name, args):
158*758e9fbaSOystein Eftevaag    '''
159*758e9fbaSOystein Eftevaag    Generate the cpp fuzz target for a SAPI _Prepare call
160*758e9fbaSOystein Eftevaag    '''
161*758e9fbaSOystein Eftevaag    if not args:
162*758e9fbaSOystein Eftevaag        return function_name, None
163*758e9fbaSOystein Eftevaag    # Generate the cpp variable definitions. Make sure to initialize to empty
164*758e9fbaSOystein Eftevaag    # structs (works for initializing anything) or cpp compiler will complain.
165*758e9fbaSOystein Eftevaag    arg_definitions = (' = {0};\n' + ' ' * 4).join([
166*758e9fbaSOystein Eftevaag        arg.replace('*', '').replace('const', '') for arg in args]) + ' = {0};'
167*758e9fbaSOystein Eftevaag    # Generate the cpp arguments. For arguments that are pointers find replace *
168*758e9fbaSOystein Eftevaag    # with & so that we pass a pointer to the definition which has been
169*758e9fbaSOystein Eftevaag    # allocated on the stack.
170*758e9fbaSOystein Eftevaag    arg_call = (',\n' + ' ' * 8).join([
171*758e9fbaSOystein Eftevaag        arg.replace('*', '&').split()[-1] for arg in args])
172*758e9fbaSOystein Eftevaag    # Generate the call to fuzz_fill. The call should be the sysContext, double
173*758e9fbaSOystein Eftevaag    # the number of arguments for the _Prepare call, and then for each _Prepare
174*758e9fbaSOystein Eftevaag    # argument pass two to fuzz_fill, the sizeof the _Prepare argument, and a
175*758e9fbaSOystein Eftevaag    # pointer to it.
176*758e9fbaSOystein Eftevaag    fill_fuzz_args = (',\n' + ' ' * 8).join([
177*758e9fbaSOystein Eftevaag        ('sizeof (%s), &%s' % \
178*758e9fbaSOystein Eftevaag                tuple([arg.replace('*', '').split()[-1]] * 2)) \
179*758e9fbaSOystein Eftevaag        for arg in args])
180*758e9fbaSOystein Eftevaag    # Fill in the template
181*758e9fbaSOystein Eftevaag    return function_name, SAPI_PREPARE_TEMPLATE_HAS_ARGS % (arg_definitions,
182*758e9fbaSOystein Eftevaag                                                            len(args) * 2,
183*758e9fbaSOystein Eftevaag                                                            fill_fuzz_args,
184*758e9fbaSOystein Eftevaag                                                            function_name,
185*758e9fbaSOystein Eftevaag                                                            arg_call)
186*758e9fbaSOystein Eftevaag
187*758e9fbaSOystein Eftevaagdef functions_from_include(header):
188*758e9fbaSOystein Eftevaag    '''
189*758e9fbaSOystein Eftevaag    Parse out and yield each function definition from a header file.
190*758e9fbaSOystein Eftevaag    '''
191*758e9fbaSOystein Eftevaag    with open(header, 'r') as header_fd:
192*758e9fbaSOystein Eftevaag        current_function = ''
193*758e9fbaSOystein Eftevaag        for line in header_fd:
194*758e9fbaSOystein Eftevaag            # Functions we are interested in start with _Complete or _Prepare
195*758e9fbaSOystein Eftevaag            if '_Complete' in line or '_Prepare' in line:
196*758e9fbaSOystein Eftevaag                # Set the current_function to this line
197*758e9fbaSOystein Eftevaag                current_function = line
198*758e9fbaSOystein Eftevaag            elif current_function and ');' in line:
199*758e9fbaSOystein Eftevaag                # When we reach the closing parenthesis yield the function
200*758e9fbaSOystein Eftevaag                yield current_function + line.rstrip()
201*758e9fbaSOystein Eftevaag                current_function = ''
202*758e9fbaSOystein Eftevaag            elif current_function:
203*758e9fbaSOystein Eftevaag                # Add all the arguments to the function
204*758e9fbaSOystein Eftevaag                current_function += line
205*758e9fbaSOystein Eftevaag
206*758e9fbaSOystein Eftevaagdef gen_files(header):
207*758e9fbaSOystein Eftevaag    # Generate a fuzz target cpp file from each function in the header file
208*758e9fbaSOystein Eftevaag    for current_function in functions_from_include(header):
209*758e9fbaSOystein Eftevaag        function_name, contents = gen_file(current_function)
210*758e9fbaSOystein Eftevaag        # Skip the yield if there is no fuzz target that can be generated
211*758e9fbaSOystein Eftevaag        if contents is None:
212*758e9fbaSOystein Eftevaag            continue
213*758e9fbaSOystein Eftevaag        # Yield the function name and the contents of its generated file
214*758e9fbaSOystein Eftevaag        yield function_name, contents
215*758e9fbaSOystein Eftevaag
216*758e9fbaSOystein Eftevaagdef main():
217*758e9fbaSOystein Eftevaag    parser = argparse.ArgumentParser(description='Generate libfuzzer for sapi')
218*758e9fbaSOystein Eftevaag    parser.add_argument('--header', default='include/tss2/tss2_sys.h',
219*758e9fbaSOystein Eftevaag            help='Header file to look in (default include/tss2/tss2_sys.h)')
220*758e9fbaSOystein Eftevaag    args = parser.parse_args()
221*758e9fbaSOystein Eftevaag
222*758e9fbaSOystein Eftevaag    functions = dict(gen_files(args.header))
223*758e9fbaSOystein Eftevaag    # Write the generated target to the file for its function name
224*758e9fbaSOystein Eftevaag    for function_name, contents in functions.items():
225*758e9fbaSOystein Eftevaag        filepath = os.path.join('test', 'fuzz', function_name + '.fuzz.cpp')
226*758e9fbaSOystein Eftevaag        with open(filepath, 'w') as fuzzer_fd:
227*758e9fbaSOystein Eftevaag            fuzzer_fd.write(contents)
228*758e9fbaSOystein Eftevaag    # Fill in the Makefile-fuzz-generated.am template using the function names.
229*758e9fbaSOystein Eftevaag    # Create a list of the compiled fuzz targets
230*758e9fbaSOystein Eftevaag    files = ' \\\n    '.join(['test/fuzz/%s.fuzz' % (function) \
231*758e9fbaSOystein Eftevaag                              for function in functions])
232*758e9fbaSOystein Eftevaag    # Create the Makefile targets for each generated file
233*758e9fbaSOystein Eftevaag    targets = '\n'.join([MAKEFILE_FUZZ_TARGET % tuple(list(itertools.chain(\
234*758e9fbaSOystein Eftevaag            ([function] * 6)))) for function in functions])
235*758e9fbaSOystein Eftevaag    # Write out the Makefile-fuzz-generated.am file
236*758e9fbaSOystein Eftevaag    with open('Makefile-fuzz-generated.am', 'w') as makefile_fd:
237*758e9fbaSOystein Eftevaag        makefile_fd.write(MAKEFILE_FUZZ % (files, targets))
238*758e9fbaSOystein Eftevaag
239*758e9fbaSOystein Eftevaagif __name__ == '__main__':
240*758e9fbaSOystein Eftevaag    main()
241