python: models: rename argument ldb to samdb
[samba.git] / lib / fuzzing / decode_ndr_X_crash
blobd90e7efe122331c070d6a1db3de5a5cadde771bb
1 #!/usr/bin/env python3
3 # Interpret a file that crashes an fuzz_ndr_X binary.
5 # Copyright (C) Catalyst IT Ltd. 2019
8 import sys
9 import os
10 from base64 import b64encode
11 import struct
12 import argparse
13 import re
15 TYPE_MASK = 3
16 TYPES = ['struct', 'in', 'out']
18 FLAGS = [
19     (4, 'ndr64', '--ndr64'),
23 def print_if_verbose(*args, **kwargs):
24     if verbose:
25         print(*args, **kwargs)
28 def process_one_file(f):
29     print_if_verbose(f.name)
30     print_if_verbose('-' * len(f.name))
32     b = f.read()
33     flags, function = struct.unpack('<HH', b[:4])
34     if opnum is not None and opnum != function:
35         return
37     t = TYPES[flags & TYPE_MASK]
38     if ndr_type and ndr_type != t:
39         return
41     payload = b[4:]
42     data64 = b64encode(payload).decode('utf-8')
44     cmd = ['bin/ndrdump',
45            pipe,
46            str(function),
47            t,
48            '--base64-input',
49            '--input', data64,
50     ]
52     for flag, name, option in FLAGS:
53         if flags & flag:
54             print_if_verbose("flag: %s" % name)
55             cmd.append(option)
57     print_if_verbose("length: %d\n" % len(payload))
58     print(' '.join(cmd))
59     print_if_verbose()
62 def main():
63     parser = argparse.ArgumentParser()
64     parser.add_argument('-p', '--pipe', default=None,
65                         help=('pipe name (for output command line, '
66                               'default is a guess or "$PIPE")'))
67     parser.add_argument('-t', '--type', default=None, choices=TYPES,
68                         help='restrict to this type')
69     parser.add_argument('-o', '--opnum', default=None, type=int,
70                         help='restrict to this function/struct number')
71     parser.add_argument('FILES', nargs='*', default=(),
72                         help="read from these files")
73     parser.add_argument('-k', '--ignore-errors', action='store_true',
74                         help='do not stop on errors')
75     parser.add_argument('-v', '--verbose', action='store_true',
76                         help='say more')
77     parser.add_argument('-H', '--honggfuzz-file',
78                         help="extract crashes from this honggfuzz report")
79     parser.add_argument('-f', '--crash-filter',
80                         help="only print crashes matching this rexexp")
82     args = parser.parse_args()
84     global pipe, opnum, ndr_type, verbose
85     pipe = args.pipe
86     opnum = args.opnum
87     ndr_type = args.type
88     verbose = args.verbose
90     if not args.FILES and not args.honggfuzz_file:
91         parser.print_usage()
92         sys.exit(1)
94     for fn in args.FILES:
95         if pipe is None:
96             m = re.search(r'clusterfuzz-testcase.+-fuzz_ndr_([a-z]+)', fn)
97             if m is None:
98                 pipe = '$PIPE'
99             else:
100                 pipe = m.group(1)
102         if args.crash_filter is not None:
103             if not re.search(args.crash_filter, fn):
104                 print_if_verbose(f"skipping {fn}")
105                 continue
106         try:
107             if fn == '-':
108                 process_one_file(sys.stdin)
109             else:
110                 with open(fn, 'rb') as f:
111                     process_one_file(f)
112         except Exception:
113             print_if_verbose("Error processing %s\n" % fn)
114             if args.ignore_errors:
115                 continue
116             raise
118     if args.honggfuzz_file:
119         print_if_verbose(f"looking at {args.honggfuzz_file}")
120         with open(args.honggfuzz_file) as f:
121             pipe = None
122             crash = None
123             for line in f:
124                 m = re.match(r'^\s*fuzzTarget\s*:\s*bin/fuzz_ndr_(\w+)\s*$', line)
125                 if m:
126                     pipe = m.group(1).split('_TYPE_', 1)[0]
127                     print_if_verbose(f"found pipe {pipe}")
128                 m = re.match(r'^FUZZ_FNAME: (\S+)$', line)
129                 if m:
130                     crash = m.group(1)
131                     if args.crash_filter is not None:
132                         if not re.search(args.crash_filter, crash):
133                             print_if_verbose(f"skipping {crash}")
134                             pipe = None
135                             crash = None
136                             continue
137                     print_if_verbose(f"found crash {crash}")
138                 if pipe is not None and crash is not None:
139                     with open(crash, 'rb') as f:
140                         process_one_file(f)
141                     pipe = None
142                     crash = None
145 main()