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
|
#!/usr/bin/env python3
# find_push.py - locate the client's CPU mapping that owns the GR ring page
# (GPA 0x12C600000 as content-located on the host) and print the CPU VA<->
# GPU VA correspondence for the low GPU VAs (0x4ca0000 etc).
import os, struct, sys, subprocess, mmap, time
RING_GPA = 0x12C600000
PUSH_GVA = 0x4ca0000
RING_GVA = 0x4cc0000
def pids():
out = subprocess.run(["pgrep", "-x", "vk_frame"], capture_output=True).stdout
return [int(x) for x in out.split()]
def read_pagemap(pid, va):
try:
with open("/proc/%d/pagemap" % pid, "rb") as f:
f.seek((va // 4096) * 8)
d = f.read(8)
if len(d) < 8:
return None
e = int.from_bytes(d, "little")
if not (e >> 63) & 1:
return None
return (e & ((1 << 55) - 1)) << 12
except OSError:
return None
def main():
for pid in pids():
print("pid=%d" % pid)
try:
maps = open("/proc/%d/maps" % pid).read().splitlines()
except OSError:
continue
for line in maps:
p = line.split()
if len(p) < 6 or "nvidia" not in p[-1]:
continue
lo, hi = [int(x, 16) for x in p[0].split("-")]
if hi - lo > 0x1000000:
continue
# scan pages; look for RING_GPA
for va in range(lo, hi, 0x10000):
for off in range(0, 0x10000, 0x1000):
pa = read_pagemap(pid, va + off)
if pa == RING_GPA:
print("FOUND ring page: cpu_va=0x%x (map 0x%x-0x%x %s)" % (va+off, lo, hi, p[-1]))
delta_cpu = (va + off) - RING_GVA
push_cpu = PUSH_GVA + delta_cpu
print(" delta_cpu = 0x%x" % delta_cpu)
for gva in (PUSH_GVA, PUSH_GVA+0x1000, 0x4ca059c, 0x4ca0980, 0x4ca5870, 0x4903000):
cva = gva + delta_cpu
pa2 = read_pagemap(pid, cva & ~0xfff)
print(" gva=0x%x -> cpu=0x%x -> pa=%s" % (gva, cva, hex(pa2) if pa2 else None))
return
print(" ring GPA 0x%x not found in this pid's mappings" % RING_GPA)
main()
|