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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#!/usr/bin/env python3
# wall2_resolver7.py - resolver6 + release-window injection + live-first ordering.
# Fixes the resolver6 zero-page overwrite: candidates are injected good-first
# (live_nz>0) and zero pages last, so the readable mapping wins by order if the
# service keeps the newest write.
# New: the GR init release windows (0x4b16000 size 0x1000 from the record page,
# and any {VA,0x1000} record alongside) are injected from the size-0x1000
# memdescs of the same page.
import subprocess, struct, time, sys, os
RAM = "/dev/shm/vgpu-guest-ram"
PARAM = "/sys/module/vgsp/parameters/sema_map_add"
LOG = "/tmp/opencode/wall2_resolver7.log"
WATCH_S = int(os.environ.get("W2_WATCH", "420"))
PAIRS = [(0x4480000, 0x44a0000), (0x4ca0000, 0x4cc0000)]
REL_WINS = [0x4b16000]
logf = open(LOG, "a", buffering=1)
def log(*a):
s = " ".join(str(x) for x in a)
print(s, flush=True)
logf.write("[%s] %s\n" % (time.strftime("%H:%M:%S"), s))
img = open(RAM, "rb", buffering=0)
def off2gpa(off): return off if off < 0x80000000 else 0x100000000+(off-0x80000000)
def gpa2off(pa):
if pa < 0x80000000: return pa
if pa < 0x180000000: return 0x80000000 + (pa - 0x100000000)
return None
def rd(pa, n):
off = gpa2off(pa)
if off is None: return None
img.seek(off); return img.read(n)
def inject(va, pa, ln=0x1000, ap=1):
cmd = "echo 0x%x,0x%x,0x%x,%d > %s" % (va, pa, ln, ap, PARAM)
r = subprocess.run(["sudo", "sh", "-c", cmd], capture_output=True, text=True)
if r.returncode == 0:
log("INJECT va=0x%x -> pa=0x%x" % (va, pa))
return True
log("inject FAIL rc=%d %s" % (r.returncode, r.stderr.strip()))
return False
def find_qpair(a, b):
img.seek(0, 2); fsz = img.tell()
pat = struct.pack("<QQ", a, b)
out = []
CH = 64 << 20
pos = 0
while pos < fsz:
img.seek(pos); d = img.read(min(CH, fsz - pos))
st = 0
while True:
i = d.find(pat, st)
if i < 0: break
st = i + 1
out.append(off2gpa(pos + i) & ~0xfff)
pos += CH
return out
def collect(page):
d = rd(page, 0x1000)
if not d: return None
descs = []
wins = []
for o in range(0, 0x1000 - 24, 8):
sz, fl = struct.unpack_from("<QQ", d, o)
pa = struct.unpack_from("<Q", d, o + 16)[0]
if fl == 0x03008000 and 0x1000 <= sz <= 0x400000 and \
0x100000000 <= pa < 0x180000000:
descs.append((o, sz, pa))
va2 = sz
if 0x4000000 <= va2 < 0x100000000 and (va2 & 0xfff) == 0:
sz2 = fl
if 0x1000 <= sz2 <= 0x1000000 and (sz2 & 0xfff) == 0:
wins.append((va2, sz2))
return descs, wins
def main():
log("=== resolver7 start (watch=%ds) ===" % WATCH_S)
injected = set()
deadline = time.time() + WATCH_S
while time.time() < deadline:
pages = set()
for (pva, rva) in PAIRS:
try:
pages |= set(find_qpair(pva, 0x20000)) & set(find_qpair(rva, 0x40000))
except Exception as e:
log("scan error:", e)
for page in sorted(pages):
got = collect(page)
if not got: continue
descs, wins = got
# push windows: inject live-first (nz>0 first, zeros last)
for (pva, _rva) in PAIRS:
cands = [(o, sz, pa) for (o, sz, pa) in descs if sz == 0x20000]
order = []
for (o, sz, pa) in cands:
pd = rd(pa, 0x40)
nz = sum(1 for b in pd if b) if pd else -1
log("pair=0x%x page=0x%x desc@0x%x pa=0x%x live_nz=%d" % (pva, page, o, pa, nz))
order.append((nz, o, pa))
order.sort(key=lambda t: t[0]) # zeros first, live last
for (nz, o, pa) in order:
key = (pva, page, o)
if key in injected: continue
if inject(pva, pa):
injected.add(key)
# release windows: any {VA, 0x1000} record on the page -> size-0x1000 descs
for (va, sz) in wins:
if va not in REL_WINS and not (0x4b00000 <= va <= 0x4b20000):
continue
for (o, dsz, pa) in descs:
if dsz != sz:
continue
key = (va, page, o)
if key in injected: continue
if inject(va, pa):
injected.add(key)
time.sleep(1)
log("=== resolver7 done: %d injection(s) ===" % len(injected))
return 0
if __name__ == "__main__":
sys.exit(main())
|