aboutsummaryrefslogtreecommitdiffstats
path: root/psp_out/phase5_triage.py
blob: ca3c09c68a0f4577dea59e0512b3ea4bd87657f0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
"""Phase 5: triage SEMANTIC deltas, prioritising LITERAL changes.

A security fix most often shows as a changed constant (bound tightened, mask
narrowed, size corrected) or a NEW comparison. Those are exactly what the old
mnemonic-only diff could not see, so they are ranked first.
"""
import json, glob, os, re, sys, collections
LIT=re.compile(r"\b(?:0[xX][0-9A-Fa-f]+|\d+)\b")
CMP=re.compile(r"(?:<=|>=|==|!=|<|>)")

def lits(t): return collections.Counter(LIT.findall(t))

def classify(o, n):
    lo, ln = lits(o), lits(n)
    gained = sorted((ln-lo).elements()); lost = sorted((lo-ln).elements())
    dcmp = len(CMP.findall(n)) - len(CMP.findall(o))
    dlen = len(n) - len(o)
    score = 0
    if gained or lost: score += 3
    if dcmp > 0: score += 3          # a comparison was ADDED -> candidate guard
    if abs(dlen) > 200: score += 1
    return dict(gained=gained[:8], lost=lost[:8], dcmp=dcmp, dlen=dlen, score=score)

if __name__=='__main__':
    diffs=json.load(open('phase4_diffs.json'))
    corp={os.path.basename(p)[:-5]: json.load(open(p)) for p in glob.glob('phase3/*.json')}
    fams=sys.argv[1:] or ['sos','hdcp','sys_drv','asd']
    rows=[]
    for pair, r in diffs.items():
        o,n = pair.split(' -> ')
        if not any(o.startswith(f+'_') for f in fams): continue
        for fn in r['changed']:
            if fn not in corp[o] or fn not in corp[n]: continue
            c=classify(corp[o][fn], corp[n][fn])
            if c['score']>0: rows.append((c['score'], pair, fn, c))
    rows.sort(key=lambda t:(-t[0], t[1]))
    print("SEMANTIC deltas with literal or comparison changes: %d\n"%len(rows))
    for sc,pair,fn,c in rows[:40]:
        po=pair.split(' -> ')[0].rsplit('_',1)[0].replace('sys_drv_','').replace('sos_','').replace('asd_','').replace('hdcp_','')
        pn=pair.split(' -> ')[1].rsplit('_',1)[0].replace('sys_drv_','').replace('sos_','').replace('asd_','').replace('hdcp_','')
        print("score=%d  %-11s->%-11s %-44s +cmp=%-3d dlen=%-6d"%(sc,po,pn,fn[:44],c['dcmp'],c['dlen']))
        if c['gained']: print("      gained literals: %s"%c['gained'])
        if c['lost']:   print("      lost   literals: %s"%c['lost'])