summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/scan_r673b.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-25 05:21:29 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-25 05:21:29 -0400
commit45978e9202412fb9fc6088718e9720f22ece7b30 (patch)
tree1c70d4967088965bff39d5863bfef88ace5aa72f /tools/guest-diag/wall2/scan_r673b.py
parente5eacffa9e4e0577b8fb109610286db83bf80ff3 (diff)
downloadopen-iov-45978e9202412fb9fc6088718e9720f22ece7b30.tar.gz
open-iov-45978e9202412fb9fc6088718e9720f22ece7b30.zip
wall-2 forensics tools: GR channel-init push localization (session 73)
Tools and findings from the live wall-2 campaign (r674/r675): the vk_frame client's GR channel-init push (va=0x4480000 len=1432) cannot be translated by the sema service, so no release is applied and vkCreateDevice fails -4. Captured: the RM window-record/memdesc layout (ring memdesc PA == the service's validated ring pa; push memdesc PA injected live and read by the service without a false-translation line), the CE-only shape of the service rescue matcher, the notrace status of nvidia/modeset kprobes (QEMU gdb hbreak works), and the ring-entry encoding from channelFillGpFifo/nvWriteGpEntry (neither runs for this channel's kick). New tools: wall2_resolver{2..5}.py, wall2_livecap{1..3}.py, RAM structure scanners (scan_r673*.py, trace_push674.py), gdb675*.gdb probes, plus a README with the ranked next steps.
Diffstat (limited to 'tools/guest-diag/wall2/scan_r673b.py')
-rw-r--r--tools/guest-diag/wall2/scan_r673b.py53
1 files changed, 53 insertions, 0 deletions
diff --git a/tools/guest-diag/wall2/scan_r673b.py b/tools/guest-diag/wall2/scan_r673b.py
new file mode 100644
index 0000000..11613b1
--- /dev/null
+++ b/tools/guest-diag/wall2/scan_r673b.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# r673: dump the full record page 0x101499000 and search RAM for the ring/push
+# VA structures to identify which record is the 16-page push (VA 0x4500000).
+import numpy as np, struct, os, time
+
+RAM="/dev/shm/vgpu-guest-ram"
+MASK=~0xfff & ((1<<64)-1)
+img=open(RAM,"rb")
+fsz=os.path.getsize(RAM)
+def gpa2off(pa):
+ if pa < 0x80000000: return pa
+ if pa < 0x180000000: return 0x80000000+(pa-0x100000000)
+ return None
+def off2gpa(off):
+ return off if off < 0x80000000 else 0x100000000+(off-0x80000000)
+def rd(pa,n):
+ off=gpa2off(pa)
+ if off is None or off+n>fsz: return None
+ img.seek(off); return img.read(n)
+
+print("== full record page 0x101499000 ==")
+d=rd(0x101499000,0x1000)
+nrec=0
+for o in range(0,0x1000,32):
+ p,f,pa,sz=struct.unpack_from("<QQQQ",d,o)
+ if p==0 and f==0 and pa==0 and sz==0: continue
+ nrec+=1
+ print(" rec[%3d] vmap=%016x flags=%016x pa=%012x size=0x%x" % (o//32,p,f,pa,sz))
+print("nonempty records:",nrec)
+
+print()
+print("== search RAM for qword 0x4520000 (ring VA) ==")
+t0=time.time(); CH=64<<20
+for pat_name,pat in (("0x4520000",0x4520000),("0x4500000",0x4500000)):
+ print("-- pattern %s --" % pat_name)
+ hits=[]
+ for pos in range(0,fsz,CH):
+ img.seek(pos); dd=img.read(min(CH,fsz-pos))
+ n=len(dd)//8
+ a=np.frombuffer(dd[:n*8],dtype=np.uint64)
+ idx=np.nonzero(a==np.uint64(pat))[0]
+ for i in idx:
+ hits.append(pos+int(i)*8)
+ print(" hits=%d (%.1fs)" % (len(hits),time.time()-t0))
+ for off in hits[:40]:
+ gpa=off2gpa(off); page=gpa&MASK
+ # show 32 bytes before/after
+ dd=rd(page,0x1000)
+ if not dd: continue
+ ro=gpa-page
+ s=max(0,ro-32); e=min(0x1000,ro+64)
+ print(" gpa=0x%x page=0x%x off=0x%x ctx=%s" % (gpa,page,ro,dd[s:e].hex()))
+ if len(hits)>40: print(" ... %d more" % (len(hits)-40))