Skip to content

Commit cfd5a75

Browse files
frontends: python: enable fuzz-introspector compliant output (#294)
Outputs the data from the static module into data format that is accepted by the post-processing backend of fuzz-introspector. I have verified locally this works, i.e. the HTML reports can be generated, using a slightly modified version of post-processing. The diffs needed here will be pushed next (after cleanup). Ref: #280
1 parent 9f72672 commit cfd5a75

File tree

1 file changed

+73
-10
lines changed

1 file changed

+73
-10
lines changed

frontends/python/main.py

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,39 +83,102 @@ def run_fuzz_pass(fuzzer, package):
8383
cg.analyze()
8484

8585
formatter = formats.Fuzz(cg)
86-
output = formatter.generate()
86+
cg_extended = formatter.generate()
87+
88+
calltree = convert_to_fuzzing_cfg(cg_extended)
89+
if calltree == None:
90+
print("Could not convert calltree to string. Exiting")
91+
sys.exit(1)
92+
93+
translated_cg = translate_cg(cg_extended, fuzzer)
94+
95+
fuzzer_name = os.path.basename(fuzzer).replace(".py", "")
96+
dump_fuzz_logic(fuzzer_name, translated_cg, calltree)
97+
98+
def translate_cg(cg_extended, fuzzer_filename):
99+
"""Converts the PyCG data into fuzz-introspector data"""
100+
new_dict = dict()
101+
new_dict['Fuzzer filename'] = fuzzer_filename
102+
new_dict['All functions'] = dict()
103+
new_dict['All functions']['Function list name'] = "All functions"
104+
new_dict['All functions']['Elements'] = []
105+
106+
# TODO: do the implementation necessary to carry these out.
107+
for elem in cg_extended['cg']:
108+
elem_dict = cg_extended['cg'][elem]
109+
d = dict()
110+
d['functionName'] = elem
111+
d['functionSourceFile'] = elem_dict['meta']['modname']
112+
d['linkageType'] = "pythonLinkage"
113+
if 'lineno' in elem_dict['meta']:
114+
d['functionLinenumber'] = elem_dict['meta']['lineno']
115+
else:
116+
d['functionLinenumber'] = -1
117+
d['functionDepth'] = 0
118+
d['returnType'] = "N/A"
119+
d['argCount'] = 0
120+
d['argTypes'] = []
121+
d['constantsTouched'] = []
122+
d['argNames'] = []
123+
d['BBCount'] = 0
124+
d['ICount'] = 0
125+
d['EdgeCount'] = 0
126+
d['CyclomaticComplexity'] = 0
127+
d['functionsReached'] = []
128+
d['functionUses'] = 13
129+
d['BranchProfiles'] = []
130+
new_dict['All functions']['Elements'].append(d)
131+
return new_dict
132+
133+
134+
def dump_fuzz_logic(fuzzer_name, cg_extended, calltree):
135+
import yaml
136+
calltree_file = fuzzer_name + ".data"
137+
fuzzer_func_data = fuzzer_name + ".data.yaml"
138+
139+
with open(calltree_file, "w+") as cf:
140+
cf.write(calltree)
141+
142+
with open(fuzzer_func_data, "w+") as ffdf:
143+
ffdf.write(yaml.dump(cg_extended))
87144

88-
convert_to_fuzzing_cfg(output)
89145

90146
def convert_to_fuzzing_cfg(cg_extended):
91147
"""Utility to translate the CG to something fuzz-introspector post-processing
92148
can use"""
93149
print("Printing CFG output")
94150
if "ep" not in cg_extended:
95151
print("No entrypoints found")
96-
return
152+
return None
97153

98154
# Extract fuzzer entrypoint and print calltree.
99155
ep_key = cg_extended['ep']['mod'] + "." + cg_extended['ep']['name']
100156
ep_node = cg_extended['cg'][ep_key]
101157
print(json.dumps(cg_extended, indent=4))
102-
print_calltree(cg_extended['cg'], ep_key, set())
158+
calltree = "Call tree\n"
159+
calltree += get_calltree_as_str(cg_extended['cg'], ep_key, set())
160+
print(calltree)
161+
return calltree
103162

104-
def print_calltree(cg_extended, k, s1, depth=0, lineno=-1, themod="", ext_mod=""):
163+
def get_calltree_as_str(cg_extended, k, s1, depth=0, lineno=-1, themod="", ext_mod=""):
105164
"""Prints a calltree where k is the key in the cg of the root"""
106165

107-
if depth > 20:
108-
return
109-
print("%s%s src_mod=%s src_linenumber=%d dst_mod=%s"%(" "*(depth*2), k, themod, lineno, ext_mod))
166+
#strline = "%s%s src_mod=%s src_linenumber=%d dst_mod=%s\n"%(" "*(depth*2), k, themod, lineno, ext_mod)
167+
if themod == "":
168+
themod="/"
169+
strline = "%s%s %s %d\n"%(" "*(depth*2), k, themod, lineno)
170+
#strline = "%s%s src_mod=%s src_linenumber=%d dst_mod=%s\n"%(" "*(depth*2), k, themod, lineno, ext_mod)
171+
#print("%s%s src_mod=%s src_linenumber=%d dst_mod=%s"%(" "*(depth*2), k, themod, lineno, ext_mod))
110172
sorted_keys = sorted(cg_extended[k]['dsts'], key=lambda x: x['lineno'])
111173

112174
# Avoid deep recursions
113175
if k in s1:
114-
return
176+
return strline
115177

116178
s1.add(k)
117179
for dst in cg_extended[k]['dsts']:
118-
print_calltree(cg_extended, dst['dst'], s1, depth+1, dst['lineno'], dst['mod'], dst['ext_mod'])
180+
strline += get_calltree_as_str(cg_extended, dst['dst'], s1, depth+1, dst['lineno'], dst['mod'], dst['ext_mod'])
119181

182+
return strline
120183
if __name__ == "__main__":
121184
main()

0 commit comments

Comments
 (0)