DF-3637 / verify_df3637.py
#!/usr/bin/env python3 """DF-3637 source-level verification. Asserts the exact control-flow defect in sys/dev/netif/ath/ath/if_ath_tx.c: ath_tx_start() discards the error from ath_tx_normal_setup() and returns 0, leaking the ath_buf (10 descriptors + dmamap) after the mbuf was freed inside ath_tx_dmasetup(). """ import sys, re SRC = "sys/dev/netif/ath/ath/if_ath_tx.c" src = open(SRC).read().splitlines() def find(pat, start=0): for i in range(start, len(src)): if re.search(pat, src[i]): return i return -1 ok = True def check(name, cond, detail=""): global ok print("[%s] %s%s" % ("PASS" if cond else "FAIL", name, (" -- " + detail) if detail else "")) if not cond: ok = False # 1. r = ath_tx_normal_setup(...) ; if (r != 0) goto done; i_call = find(r"r = ath_tx_normal_setup\(") check("ath_tx_start calls ath_tx_normal_setup into r", i_call != -1, "line %d" % (i_call + 1)) i_chk = find(r"if \(r != 0\)", i_call) nxt = src[i_chk + 1].strip() if i_chk != -1 else "" check("failure branch jumps to done", i_chk != -1 and nxt == "goto done;", "line %d: %s / %s" % (i_chk + 1, src[i_chk].strip(), nxt)) # 2. done: return 0; (error swallowed) i_done = find(r"^done:$", i_chk) check("done: label exists after failure branch", i_done != -1, "line %d" % (i_done + 1)) ret = "\n".join(src[i_done:i_done + 4]) check("done: block returns literal 0 (r discarded)", "return 0;" in ret, "lines %d-%d" % (i_done + 1, i_done + 4)) # 3. ath_tx_dmasetup frees the mbuf on every error return i_ds = find(r"^ath_tx_dmasetup\(") seg = "\n".join(src[i_ds:i_ds + 80]) check("dmasetup error path frees mbuf before returning error", "ieee80211_free_mbuf(m0);" in seg and "return error;" in seg, "function at line %d" % (i_ds + 1)) # 4. caller treats 0 as success (ath_raw_xmit legacy path in same file) i_rx = find(r"if \(ath_tx_start\(sc, ni, bf, m\)\) \{") check("caller ath_raw_xmit branches on non-zero return", i_rx != -1, "line %d" % (i_rx + 1)) # 5. bf is obtained BEFORE and only returned on the error path the caller sees i_gb = find(r"bf = ath_getbuf\(sc, ATH_BUFTYPE_MGMT\);") check("ath_raw_xmit grabs bf via ath_getbuf before ath_tx_start", i_gb != -1 and i_gb < i_rx, "line %d" % (i_gb + 1)) seg2 = "\n".join(src[i_rx:i_rx + 10]) check("success path never returns bf (no ath_returnbuf on r==0)", "ath_returnbuf" not in seg2, "lines %d-%d" % (i_rx + 1, i_rx + 10)) print() print("DF-3637 CONFIRMED at source level" if ok else "DF-3637 NOT confirmed") sys.exit(0 if ok else 1) |