1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00
samba-mirror/lib/fuzzing/decode_ndr_X_crash
Douglas Bagnall 3a840553cf lib/fuzzing/decode_ndr_X_crash: guess the pipe from filename
Usually we are dealing with a filename that tells you what the pipe is,
and there is no reason for this debug helper not to be convenient

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15625

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 8b6a584170)
2024-06-10 13:24:16 +00:00

146 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Interpret a file that crashes an fuzz_ndr_X binary.
#
# Copyright (C) Catalyst IT Ltd. 2019
import sys
import os
from base64 import b64encode
import struct
import argparse
import re
TYPE_MASK = 3
TYPES = ['struct', 'in', 'out']
FLAGS = [
(4, 'ndr64', '--ndr64'),
]
def print_if_verbose(*args, **kwargs):
if verbose:
print(*args, **kwargs)
def process_one_file(f):
print_if_verbose(f.name)
print_if_verbose('-' * len(f.name))
b = f.read()
flags, function = struct.unpack('<HH', b[:4])
if opnum is not None and opnum != function:
return
t = TYPES[flags & TYPE_MASK]
if ndr_type and ndr_type != t:
return
payload = b[4:]
data64 = b64encode(payload).decode('utf-8')
cmd = ['bin/ndrdump',
pipe,
str(function),
t,
'--base64-input',
'--input', data64,
]
for flag, name, option in FLAGS:
if flags & flag:
print_if_verbose("flag: %s" % name)
cmd.append(option)
print_if_verbose("length: %d\n" % len(payload))
print(' '.join(cmd))
print_if_verbose()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--pipe', default=None,
help=('pipe name (for output command line, '
'default is a guess or "$PIPE")'))
parser.add_argument('-t', '--type', default=None, choices=TYPES,
help='restrict to this type')
parser.add_argument('-o', '--opnum', default=None, type=int,
help='restrict to this function/struct number')
parser.add_argument('FILES', nargs='*', default=(),
help="read from these files")
parser.add_argument('-k', '--ignore-errors', action='store_true',
help='do not stop on errors')
parser.add_argument('-v', '--verbose', action='store_true',
help='say more')
parser.add_argument('-H', '--honggfuzz-file',
help="extract crashes from this honggfuzz report")
parser.add_argument('-f', '--crash-filter',
help="only print crashes matching this rexexp")
args = parser.parse_args()
global pipe, opnum, ndr_type, verbose
pipe = args.pipe
opnum = args.opnum
ndr_type = args.type
verbose = args.verbose
if not args.FILES and not args.honggfuzz_file:
parser.print_usage()
sys.exit(1)
for fn in args.FILES:
if pipe is None:
m = re.search(r'clusterfuzz-testcase.+-fuzz_ndr_([a-z]+)', fn)
if m is None:
pipe = '$PIPE'
else:
pipe = m.group(1)
if args.crash_filter is not None:
if not re.search(args.crash_filter, fn):
print_if_verbose(f"skipping {fn}")
continue
try:
if fn == '-':
process_one_file(sys.stdin)
else:
with open(fn, 'rb') as f:
process_one_file(f)
except Exception:
print_if_verbose("Error processing %s\n" % fn)
if args.ignore_errors:
continue
raise
if args.honggfuzz_file:
print_if_verbose(f"looking at {args.honggfuzz_file}")
with open(args.honggfuzz_file) as f:
pipe = None
crash = None
for line in f:
m = re.match(r'^\s*fuzzTarget\s*:\s*bin/fuzz_ndr_(\w+)\s*$', line)
if m:
pipe = m.group(1).split('_TYPE_', 1)[0]
print_if_verbose(f"found pipe {pipe}")
m = re.match(r'^FUZZ_FNAME: (\S+)$', line)
if m:
crash = m.group(1)
if args.crash_filter is not None:
if not re.search(args.crash_filter, crash):
print_if_verbose(f"skipping {crash}")
pipe = None
crash = None
continue
print_if_verbose(f"found crash {crash}")
if pipe is not None and crash is not None:
with open(crash, 'rb') as f:
process_one_file(f)
pipe = None
crash = None
main()