Skip to content

Commit 24a4da0

Browse files
syz-introspector: more refactoring and cleaning up (#2039)
* adjust logging Signed-off-by: David Korczynski <[email protected]> * nit Signed-off-by: David Korczynski <[email protected]> * nit Signed-off-by: David Korczynski <[email protected]> --------- Signed-off-by: David Korczynski <[email protected]>
1 parent 76812f0 commit 24a4da0

File tree

5 files changed

+76
-93
lines changed

5 files changed

+76
-93
lines changed

tools/syz-introspector/src/fuzz_introspector_utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def cleanup_files(workdir: str = ""):
8080
os.remove('targetCalltree.txt')
8181

8282

83-
def get_all_c_files_mentioned_in_light(workdir, all_source) -> List[str]:
83+
def get_c_files_mentioned_in_light(workdir) -> List[str]:
8484
"""Gets C source files mention in light FI report."""
8585
with open(os.path.join(workdir, 'report.yaml'), 'r',
8686
encoding='utf-8') as f:
@@ -92,7 +92,7 @@ def get_all_c_files_mentioned_in_light(workdir, all_source) -> List[str]:
9292
return all_files
9393

9494

95-
def get_all_header_files_in_light(workdir, all_sources) -> List[str]:
95+
def get_all_header_files_in_light(workdir) -> List[str]:
9696
"""Gets list of header files in light introspector report and
9797
finds them in the target kernel folder."""
9898
all_header_files = []
@@ -108,7 +108,7 @@ def get_all_header_files_in_light(workdir, all_sources) -> List[str]:
108108
return all_header_files
109109

110110

111-
def extract_calltree_light(target_function, kernel_dir, workdir, target_dir):
111+
def extract_calltree_light(target_function, workdir, target_dir):
112112
"""Light introspector run"""
113113

114114
# logging.info('Analysing: %s' % (workdir))

tools/syz-introspector/src/main.py

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,10 @@ def parse_args() -> argparse.Namespace:
102102
return args
103103

104104

105-
def extract_source_loc_analysis(workdir: str, all_sources: List[str],
106-
report) -> None:
105+
def extract_source_loc_analysis(workdir: str, report) -> None:
107106
"""Extracts the lines of code in each C source code file."""
108-
all_c_files = fuzz_introspector_utils.get_all_c_files_mentioned_in_light(
109-
workdir, all_sources)
107+
all_c_files = fuzz_introspector_utils.get_c_files_mentioned_in_light(
108+
workdir)
110109
logger.info('[+] Source files:')
111110
source_files = []
112111
total_loc = 0
@@ -161,7 +160,7 @@ def get_possible_devnodes(ioctl_handlers):
161160
return all_devnodes
162161

163162

164-
def analyse_ioctl_handler(ioctl_handler, workdir, kernel_folder, target_path):
163+
def analyse_ioctl_handler(ioctl_handler, workdir, target_path):
165164
"""Extracts the calltree from a given ioctl handler and creates a Fuzz
166165
Introspector HTML report for it as well. The data will be written in a
167166
folder within the working directory.
@@ -180,8 +179,7 @@ def analyse_ioctl_handler(ioctl_handler, workdir, kernel_folder, target_path):
180179
# Extract the calltree. Do this by running an introspector run
181180
# to generate the calltree as well as analysis files.
182181
calltree = fuzz_introspector_utils.extract_calltree_light(
183-
ioctl_handler['func']['functionName'], kernel_folder, fi_data_dir,
184-
target_path)
182+
ioctl_handler['func']['functionName'], fi_data_dir, target_path)
185183

186184
if calltree:
187185
ioctl_handler['calltree'] = calltree
@@ -224,13 +222,12 @@ def analyse_ioctl_handler(ioctl_handler, workdir, kernel_folder, target_path):
224222
ioctl_handler['calltree'] = ''
225223

226224

227-
def extract_ioctls_in_driver(kernel_folder, report, workdir, all_sources,
228-
strict_ioctls):
225+
def extract_ioctls_in_driver(kernel_folder, report, workdir, strict_ioctls):
229226
"""Extracts ioctls defined/used in driver"""
230-
ioctls_defined = textual_source_analysis.extract_raw_ioctls_text_from_header_files(
227+
ioctls_defined = textual_source_analysis.extract_ioctls_from_files(
231228
report['header_files'], kernel_folder)
232-
c_files_in_driver = fuzz_introspector_utils.get_all_c_files_mentioned_in_light(
233-
workdir, all_sources)
229+
c_files_in_driver = fuzz_introspector_utils.get_c_files_mentioned_in_light(
230+
workdir)
234231
if strict_ioctls:
235232
refined_ioctls = []
236233
for ioctl in ioctls_defined:
@@ -269,28 +266,27 @@ def main() -> None:
269266
os.environ['FI_KERNEL_COV'] = args.coverage_report
270267

271268
# Extract source file structure.
272-
all_sources = identify_kernel_source_files(kernel_folder)
269+
identify_kernel_source_files(kernel_folder)
273270

274271
# Run base introspector. In this run there are no entrypoints analysed.
275272
run_light_fi(target_path, workdir)
276-
extract_source_loc_analysis(workdir, all_sources, report)
273+
extract_source_loc_analysis(workdir, report)
277274

278275
# Find all header files.
279276
logger.info('[+] Finding header files')
280-
report['header_files'] = syz_core.extract_header_files_referenced(
281-
workdir, all_sources)
282-
logger.info('Found a total of %d header files',
283-
len(report['header_files']))
277+
report['header_files'] = syz_core.extract_header_files_referenced(workdir)
278+
logger.debug('Found a total of %d header files',
279+
len(report['header_files']))
284280
for header_file in report['header_files']:
285-
logger.info('- %s', header_file)
281+
logger.debug('- %s', header_file)
286282

287283
new_headers = []
288284
logger.info('Refining header files')
289285
for header_file in report['header_files']:
290-
logger.info('r: %s', header_file)
286+
logger.debug('r: %s', header_file)
291287
vt = textual_source_analysis.find_file(header_file)
292288
if vt:
293-
logger.info('--- %s', vt)
289+
logger.debug('--- %s', vt)
294290
new_headers.append(vt)
295291
logger.info('Refined to %d', len(new_headers))
296292

@@ -301,15 +297,14 @@ def main() -> None:
301297
# Extract ioctls.
302298
logger.info('[+] Extracting raw ioctls')
303299
report['ioctls'] = extract_ioctls_in_driver(kernel_folder, report, workdir,
304-
all_sources,
305300
args.strict_ioctls)
301+
logger.info('[+] Found the following ioctls')
306302
for ioctl in report['ioctls']:
307303
logger.info('%s ::: %s', ioctl.raw_definition, ioctl.name)
308304

309305
logger.info('[+] Scanning for ioctl handler using text analysis')
310306
ioctl_handlers = syz_core.get_ioctl_handlers(report['ioctls'],
311-
kernel_folder, report,
312-
workdir)
307+
kernel_folder, workdir)
313308

314309
# Get possible set of devnodes.
315310
all_devnodes = get_possible_devnodes(ioctl_handlers)
@@ -318,8 +313,7 @@ def main() -> None:
318313

319314
# extract calltrees
320315
for ioctl_handler in report['ioctl_handlers']:
321-
analyse_ioctl_handler(ioctl_handler, workdir, kernel_folder,
322-
target_path)
316+
analyse_ioctl_handler(ioctl_handler, workdir, target_path)
323317

324318
logger.info('[+] Showing complexity of ioctl handlers')
325319
syz_core.interpret_complexity_of_ioctl_handlers(report['ioctl_handlers'])

tools/syz-introspector/src/syz_core.py

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,28 @@ def find_ioctl_first_case_uses(ioctl_handler, kernel_folder):
5353
for idx, line in enumerate(content.split('\n')):
5454
already_seen = set()
5555
for ioctl in ioctl_handler['ioctls']:
56-
if ioctl.name in line and ioctl.name not in already_seen and 'case' in line:
56+
if (ioctl.name in line and ioctl.name not in already_seen
57+
and 'case' in line):
5758
logger.debug("%s :: %d", line.replace("\n", ""), idx)
5859
already_seen.add(ioctl.name)
5960
pair_starts.append((ioctl.name, idx + 1))
6061
return pair_starts
6162

6263

63-
def extract_header_files_referenced(workdir, all_sources) -> Set[str]:
64+
def extract_header_files_referenced(workdir) -> Set[str]:
6465
"""extract the source of all header files from FI output."""
6566

6667
raw_header_file_references = fuzz_introspector_utils.get_all_header_files_in_light(
67-
workdir, all_sources)
68+
workdir)
6869

6970
all_files = set()
7071
for raw_file_reference in raw_header_file_references:
71-
logger.info('Header file -: %s', raw_file_reference)
72+
logger.debug('Header file -: %s', raw_file_reference)
7273
path2 = raw_file_reference.replace('file_location:',
7374
'').strip().split(':')[0].replace(
7475
"'", '')
7576
normalized = os.path.normpath(path2)
76-
logger.info('Adding %s', normalized)
77+
logger.debug('Adding %s', normalized)
7778
all_files.add(normalized)
7879

7980
logger.debug('Files found')
@@ -99,13 +100,13 @@ def extract_header_files_referenced(workdir, all_sources) -> Set[str]:
99100
'>', '').replace('<', '').replace('\"',
100101
'').replace(' ', '')
101102

102-
logger.info('Including: %s', header_included)
103+
logger.debug('Including: %s', header_included)
103104
new_files.add(header_included)
104105
all_files = all_files.union(new_files)
105106

106107
found_files = []
107108
for header_file in all_files:
108-
logger.info('Finding F1')
109+
logger.debug('Finding F1')
109110
valid_target = textual_source_analysis.find_file(header_file)
110111
if valid_target:
111112
found_files.append(valid_target)
@@ -115,8 +116,7 @@ def extract_header_files_referenced(workdir, all_sources) -> Set[str]:
115116
return found_files
116117

117118

118-
def extract_syzkaller_types_to_analyze(ioctls, syzkaller_description,
119-
typedict) -> Dict[str, str]:
119+
def extract_syzkaller_types_to_analyze(ioctls, typedict) -> Dict[str, str]:
120120
"""goes through ioctls_per_fp and syzkaller_description, and sets something
121121
in syzkaller_description and returns a set of types to analyse."""
122122

@@ -181,8 +181,8 @@ def extract_syzkaller_types_to_analyze(ioctls, syzkaller_description,
181181
target = '%s array[%s, %s]' % (field_name, arr_type,
182182
array_count)
183183
else:
184-
target = '%s %s' % (syz_name, syz_type)
185-
description_str += ' %s\n' % (target)
184+
target = f'{syz_name} {syz_type}'
185+
description_str += f' {target}\n'
186186

187187
description_str += '}'
188188
description_types[dtype] = description_str
@@ -201,7 +201,7 @@ def get_next_syzkaller_workdir():
201201

202202

203203
def write_syzkaller_description(ioctls, syzkaller_description, workdir,
204-
all_devnodes, header_file, target_path):
204+
all_devnodes, target_path):
205205
"""Writes a description-X.txt representing syzkaller description."""
206206

207207
# Ensure there are actually ioctls to generate
@@ -257,7 +257,7 @@ def write_syzkaller_description(ioctls, syzkaller_description, workdir,
257257
f.write('\n' * 2)
258258

259259
# Describe the types
260-
for st, text in syzkaller_description.items(): #['types']:
260+
for _, text in syzkaller_description.items(): #['types']:
261261
f.write(text)
262262
f.write('\n' * 2)
263263
return next_syz_descr
@@ -274,13 +274,12 @@ def get_function_containing_line_idx(line_idx, sorted_functions):
274274
return None
275275

276276

277-
def check_source_files_for_ioctl(kernel_folder, src_file, ioctls,
278-
all_files_with_func):
277+
def check_source_files_for_ioctl(src_file, ioctls, all_files_with_func):
279278
"""For a given set of of IOCTLs and a source file, finds the functions
280279
in the source file from the `all_files_with_func` that uses the IOCTLs."""
281280
all_ioctl_func_handlers = list()
282281

283-
logger.info('Finding F2')
282+
logger.info('Finding source files with ioctls usage.')
284283
target_file = textual_source_analysis.find_file(src_file)
285284
if not target_file:
286285
return []
@@ -323,14 +322,10 @@ def check_source_files_for_ioctl(kernel_folder, src_file, ioctls,
323322

324323
if len(functions_with_ioctls_in_them) > 0:
325324
logger.debug('Functions with ioctls in them')
326-
for interesting_func in functions_with_ioctls_in_them:
327-
all_ioctl_func_handlers.append(
328-
functions_with_ioctls_in_them[interesting_func])
329-
logger.debug(
330-
"- %s",
331-
functions_with_ioctls_in_them[interesting_func]['func'])
332-
for ioctl in functions_with_ioctls_in_them[interesting_func][
333-
'ioctls']:
325+
for func_obj in functions_with_ioctls_in_them.values():
326+
all_ioctl_func_handlers.append(func_obj)
327+
logger.debug("- %s", func_obj['func'])
328+
for ioctl in func_obj['ioctls']:
334329
logger.debug(' - %s', (ioctl.name))
335330

336331
return all_ioctl_func_handlers
@@ -375,7 +370,7 @@ def find_all_unlocked_ioctls(source_files_to_functions_mapping):
375370
return unlocked_ioctl_functions
376371

377372

378-
def get_ioctl_handlers(ioctls, kernel_folder, report, fi_data_dir):
373+
def get_ioctl_handlers(ioctls, kernel_folder, fi_data_dir):
379374
"""Finds the places in the source code where IOCTL commands are used."""
380375

381376
logger.info('Getting ioctl handlers')
@@ -408,8 +403,7 @@ def get_ioctl_handlers(ioctls, kernel_folder, report, fi_data_dir):
408403

409404
for src_file in source_files_to_functions_mapping:
410405
tmp_ioctl_handlers = check_source_files_for_ioctl(
411-
kernel_folder, src_file, ioctls,
412-
source_files_to_functions_mapping)
406+
src_file, ioctls, source_files_to_functions_mapping)
413407
ioctl_handlers += tmp_ioctl_handlers
414408

415409
for unlocked_ioctl_handler in unlocked_ioctl_handlers:
@@ -667,9 +661,8 @@ def extract_types_of_syzkaller_description(ioctls, fi_data_dir):
667661
type_dict['structs'] += struct_list
668662
type_dict['typedefs'] += typedefs
669663

670-
syzkaller_description = {'types': dict()}
671664
all_types_to_decipher = extract_syzkaller_types_to_analyze(
672-
ioctls, syzkaller_description, type_dict)
665+
ioctls, type_dict)
673666

674667
logger.info('All types extracted from struct to include in description:')
675668
logger.info(json.dumps(list(all_types_to_decipher), indent=2))
@@ -695,11 +688,8 @@ def create_and_dump_syzkaller_description(ioctls_per_fp, workdir: str,
695688

696689
syzkaller_description_types = {}
697690
all_ioctls = []
698-
for header_file, ioctls in header_files_to_ioctls.items():
699-
logger.info('Header file:')
700-
logger.info(header_file)
691+
for _, ioctls in header_files_to_ioctls.items():
701692
all_ioctls.extend(ioctls)
702-
703693
types_to_dump = extract_types_of_syzkaller_description(
704694
ioctls, fi_data_dir)
705695
for type_to_dump, type_text in types_to_dump.items():
@@ -710,7 +700,7 @@ def create_and_dump_syzkaller_description(ioctls_per_fp, workdir: str,
710700
logger.info('[+] Creating syzkaller description for ')
711701

712702
syzkaller_description_path = write_syzkaller_description(
713-
all_ioctls, syzkaller_description_types, workdir, all_devnodes, '',
703+
all_ioctls, syzkaller_description_types, workdir, all_devnodes,
714704
target_path)
715705
if syzkaller_description_path:
716706
logger.info('[+] - auto-generated description: %s',

tools/syz-introspector/src/syzkaller_util.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,26 @@
1616

1717
def convert_raw_type_to_syzkaller_type(raw_type) -> str:
1818
"""Converts type seen llvm ir/debug data to syzkaller type"""
19-
if raw_type == '__s32':
20-
return 'int32'
21-
if raw_type == '__u32':
22-
return 'int32'
23-
if raw_type == 'unsigned int':
24-
return 'int32'
25-
if raw_type == '__u64':
26-
return 'int64'
27-
if raw_type == 'int32_t' or raw_type == 'int':
28-
return 'int32'
29-
if raw_type == 'uint32_t':
30-
return 'int32'
31-
if raw_type == '__u64 *':
32-
return 'int64'
33-
if raw_type == 'char *':
34-
return 'int8'
35-
if raw_type == 'char':
36-
return 'int8'
37-
if raw_type == '__u16':
38-
return 'int16'
39-
return raw_type
19+
type_mapping = {
20+
'__u8': 'int8',
21+
'__s8': 'int8',
22+
'char': 'int8',
23+
'char *': 'int8',
24+
'__s16': 'int16',
25+
'__u16': 'int16',
26+
'short': 'int16',
27+
'__s32': 'int32',
28+
'__u32': 'int32',
29+
'int': 'int32',
30+
'int32_t': 'int32',
31+
'uint32_t': 'int32',
32+
'unsigned int': 'int32',
33+
'__s64': 'int64',
34+
'__u64': 'int64',
35+
'__u64 *': 'int64',
36+
}
37+
38+
return type_mapping.get(raw_type, raw_type)
4039

4140

4241
def get_type_ptr_of_syzkaller(ioctl) -> str:

0 commit comments

Comments
 (0)