source: test/pyregfi-smoketest.py @ 254

Last change on this file since 254 was 253, checked in by tim, 13 years ago

added preliminary interface to security descriptors in pyregfi
misc bug fixes

  • Property svn:executable set to *
File size: 9.3 KB
Line 
1#!/usr/bin/env python3
2
3import sys
4import gc
5import io
6import time
7import threading
8import pyregfi
9
10
11
12pyregfi.setLogMask((pyregfi.LOG_TYPES.INFO, pyregfi.LOG_TYPES.WARN, pyregfi.LOG_TYPES.ERROR))
13
14# Uses the HiveIterator to walk all keys
15# Gathers various (meaningless) statistics to exercise simple attribute access
16# and to hopefully smoke out any bugs that can be identified by changing stats
17def iterTallyNames(hive, fh):
18    key_count = 0
19    key_lens = 0
20    key_rawlens = 0
21    value_count = 0
22    value_lens = 0
23    value_rawlens = 0
24
25    for k in hive:
26        key_count += 1
27        if k.name != None:
28            key_lens += len(k.name)
29        if k.name_raw != None:
30            key_rawlens += len(k.name_raw)
31
32        for v in k.values:
33            value_count += 1
34            if v.name != None:
35                value_lens += len(v.name)
36            if v.name_raw != None:
37                value_rawlens += len(v.name_raw)
38
39    print("  Counts: keys=%d, values=%d" % (key_count, value_count))
40    print("  Total name length: keys=%d, values=%d" % (key_lens, value_lens))
41    print("  Total raw name lengths: keys=%d, values=%d" % (key_rawlens, value_rawlens))
42
43
44# walks up parents to obtain path, rather than using downward links like iterator
45def getCurrentPath(key):
46    if key == None:
47        return ''
48    path = []
49    p = key
50    while p != None:
51        path.append(p.name)
52        p = p.get_parent()
53    path.reverse()
54    del path[0]
55
56    return path
57
58# For each key in the hive, this traverses the parent links up to the root,
59# recording the path as it goes, and then uses the subtree/descend method
60# to find the same key again, verifying it is the same.  This test is currently
61# very slow because no key caching is used.
62def iterParentWalk(hive, fh):
63    i = 1
64    for k in hive:
65        path = getCurrentPath(k)
66        try:
67            hive_iter = hive.subtree(path)
68            if hive_iter.current_key() != k:
69                print("WARNING: k != current_key for path '%s'." % path)
70            else:
71                i += 1
72        except Exception as e:
73            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path,e.args,e))
74    print("   Successfully tested paths on %d keys." % i)
75
76
77# Uses the HiveIterator to walk all keys
78# Gathers various (meaningless) statistics about data/data_raw attributes
79def iterTallyData(hive, fh):
80    data_stat = 0.0
81    dataraw_stat = 0.0
82   
83    for k in hive:
84        for v in k.values:
85            d = v.fetch_data()
86            if d == None:
87                data_stat += 0.1
88            elif hasattr(d, "__len__"):
89                data_stat += len(d)
90            else:
91                data_stat += d/2.0**64
92
93            d = v.fetch_raw_data()
94            if d == None:
95                dataraw_stat += 0.1
96            else:
97                dataraw_stat += len(d)
98
99    print("  Data stat: %f" % data_stat)
100    print("  Raw data stat: %f" % dataraw_stat)
101
102
103recurseKey_stat = 0.0
104recurseValue_stat = 0.0
105def checkValues(key):
106    global recurseKey_stat
107    global recurseValue_stat
108    recurseKey_stat += (key.mtime.low^key.mtime.high - key.max_bytes_subkeyname) * key.flags
109    for v in key.values:
110        recurseValue_stat += (v.data_off - v.data_size) / (1.0 + v.flags) + v.data_in_offset
111        value = key.values[v.name]
112        if v != value:
113            print("WARNING: iterator value '%s' does not match dictionary value '%s'." 
114                  % (v.name, value.name))
115
116def recurseTree(cur, operation):
117    for k in cur.subkeys:
118        key = cur.subkeys[k.name]
119        if k != key:
120            print("WARNING: iterator subkey '%s' does not match dictionary subkey '%s'." 
121                  % (k.name, key.name))
122        del key
123        operation(k)
124        recurseTree(k, operation)
125
126# Retrieves all keys by recursion, rather than the iterator, and validates
127# list dictionary access.  Also builds nonsensical statistics as an excuse
128# to access various base structure attributes.
129def recurseKeyTally(hive, fh):
130    checkValues(hive.root)
131    recurseTree(hive.root, checkValues)
132    print("  Key stat: %f" % recurseKey_stat)
133    print("  Value stat: %f" % recurseValue_stat)
134
135
136# Iterates hive gathering stats about security and classname records
137def iterFetchRelated(hive, fh):
138    security_stat = 0.0
139    classname_stat = 0.0
140    modified_stat = 0.0
141
142    for k in hive:
143        cn = k.fetch_classname()
144        if cn == None:
145            classname_stat += 0.000001
146        elif type(cn) == bytearray:
147            classname_stat += len(cn)/2**32
148        else:
149            classname_stat += len(cn)
150
151        modified_stat += k.modified
152       
153    print("  Security stat: %f" % security_stat)
154    print("  Classname stat: %f" % classname_stat)
155    print("  Modified stat: %f" % modified_stat)
156
157
158
159def iterIterWalk(hive, fh):
160    sk_stat = 0.0
161    v_stat = 0.0
162    iter = pyregfi.HiveIterator(hive)
163    for k in iter:
164        path = iter.current_path()
165        try:
166            hive_iter = hive.subtree(path[1:])
167            sk = hive_iter.first_subkey()
168            while sk != None:
169                ssk = hive_iter.find_subkey(sk.name)
170                if ssk != None:
171                    sk_stat += len(ssk.name)
172                else:
173                    print("WARNING: ssk was None")
174                sk = hive_iter.next_subkey()
175
176            v = hive_iter.first_value()
177            while v != None:
178                vv = hive_iter.find_value(v.name)
179                if vv != None:
180                    v_stat += len(vv.name)
181                else:
182                    print("WARNING: vv was None")
183                v = hive_iter.next_value()
184
185        except Exception as e:
186            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path[1:],e.args,e))
187    print("   Subkey stat: %f" % sk_stat)
188    print("   Value stat: %f" % v_stat)
189
190
191def iterCallbackIO(hive, fh):
192    fh.seek(0)
193    new_fh = io.BytesIO(fh.read())
194    new_hive = pyregfi.Hive(new_fh)
195    for k in new_hive:
196        pass
197
198
199def threadIterMain(iter):
200    x = 0
201    try:
202        for k in iter:
203            #x += len(k.name) + len(k.subkeys)
204            pass
205    except Exception as e:
206        print("%s dying young: %s" % (threading.current_thread().name, repr(e)))
207        # Exceptions are thrown on iteration because python state gets out of
208        # whack.  That's fine, because we're really just interested in finding
209        # segfaults.  People should not use iterators without locks, but it
210        # should at least not segfault on them.
211        pass
212    print("%s finished" % threading.current_thread().name)
213
214def iterMultithread(hive, fh):
215    num_threads = 10
216    iter = pyregfi.HiveIterator(hive)
217    threads = []
218    for t in range(0,num_threads):
219        threads.append(threading.Thread(target=threadIterMain, args=(iter,)))
220    for t in threads:
221        t.start()
222    for t in threads:
223        t.join()
224
225
226def loopSecurity(hive, fh):
227    start = hive.root.fetch_security()
228    print(start.descriptor.group)
229    cur = start.next_security()
230
231    while cur != start:
232        print(start.descriptor.group)
233        cur = cur.next_security()
234
235   
236def iterSecurity(hive, fh):
237    stat = 0
238    for k in hive:
239        security = k.fetch_security()
240        stat += security.ref_count
241        stat += len(security.descriptor.owner)
242        stat += len(security.descriptor.group)
243        if security.descriptor.sacl:
244            for ace in security.descriptor.sacl:
245                stat += ace.flags
246                if ace.object:
247                    stat += ace.object.int
248                if ace.inherited_object:
249                    stat += ace.inherited_object.int
250
251        if security.descriptor.dacl:
252            for ace in security.descriptor.dacl:
253                stat += ace.flags
254                if ace.object:
255                    stat += ace.object.int
256                if ace.inherited_object:
257                    stat += ace.inherited_object.int
258    print("  Security stat: %d" % stat)
259
260tests = {
261    "iterTallyNames":iterTallyNames,
262    "iterParentWalk":iterParentWalk,
263    "iterTallyData":iterTallyData,
264    "recurseKeyTally":recurseKeyTally,
265    "iterFetchRelated":iterFetchRelated,
266    "iterIterWalk":iterIterWalk,
267    "iterCallbackIO":iterCallbackIO,
268    "iterMultithread":iterMultithread,
269    "loopSecurity":loopSecurity,
270    "iterSecurity":iterSecurity,
271    }
272
273def usage():
274    sys.stderr.write("USAGE: pyregfi-smoketest.py test1[,test2[,...]] hive1 [hive2 ...]\n")
275    sys.stderr.write("\tAvailable tests:\n")
276    for t in tests.keys():
277        sys.stderr.write("\t\t%s\n" % t)
278
279
280if len(sys.argv) < 3:
281    usage()
282    sys.exit(1)
283
284selected_tests = sys.argv[1].split(',')
285for st in selected_tests:
286    if st not in tests:
287        usage()
288        sys.stderr.write("ERROR: %s not a valid test type" % st)
289        sys.exit(1)
290
291files = []
292for f in sys.argv[2:]:
293    files.append((f, open(f,"rb")))
294
295
296start_time = time.time()
297for hname,fh in files:
298    hive = pyregfi.Hive(fh)
299    for tname in selected_tests:
300        t = tests[tname]
301        teststart = time.time()
302        tstr = "'%s' on '%s'" % (tname,hname)
303        print("##BEGIN %s:" % tstr)
304        t(hive, fh)
305        print("##END %s; runtime=%f; messages:" % (tstr, time.time() - teststart))
306        print(pyregfi.getLogMessages())
307        print
308        sys.stdout.flush()
309    fh.close()
310
311hive = None
312files = None
313tests = None
314gc.collect()
315print("### Tests Completed, runtime: %f ###" % (time.time() -  start_time))
316#print(gc.garbage)
Note: See TracBrowser for help on using the repository browser.