code wiki / _hdl_build / _gpu_dxg_r1_recon2.nx

_gpu_dxg_r1_recon2.nx source

↩ module page · 107 lines · 6048 B

1// _gpu_dxg_r1_recon2.nx -- R1 recon pass 2. nr=0x09 (LX_DXQUERYADAPTERINFO, code 0xC0184709) is 2// PINNED LIVE (it returns -EINVAL=-22 = handler reached, vs -ENOTTY=-25 for unknown nrs). Now we 3// figure out WHY EINVAL on type=8 and find the type/size that returns a real string. 4// 5// Sweeps, on the adapter[0] ENUM handle (0x40000000): 6// (1) type 0..40 with a big buffer + size=1568 -- report ret per type (find which != EINVAL). 7// (2) for type=8 (ADAPTERREGISTRYINFO), sweep private_data_size {0,4,520,1568,1572,4096} to see 8// if EINVAL is a size check. 9// (3) try a NULL private_data (size 0) per type -- some dxgkrnl types only validate size. 10// (4) ALSO try KMTQAITYPE_ADAPTERADDRESS(=6)/ADAPTERGUID(=4)/UMDRIVERNAME(=1) which are the 11// lightest host round-trips, to learn whether WSL dxgkrnl services ANY query type at all. 12// AUTHOR=ORGAN / NO-WAVE / raw syscalls only. license_tier: ORIGINAL 13import "nx_syscalls.nx" 14 15const DXG_LX_DXENUMADAPTERS2: i64 = 0xC0104714 16const QAI_CODE: i64 = 0xC0184709 // _IOWR(0x47, 0x09, 24) -- pinned live in pass 1 17 18func p(s: *u8) -> i64 { var nn: i64=0; while s[nn]!=(0 as u8){nn=nn+1} sys_write(1,s,nn); return 0 } 19func n(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 } 20func x(v: i64) -> i64 { p("0x" as *u8); let bb:*u8=sys_mmap(20); var k:i64=0; var m:i64=v; if m==0{bb[0]=48;k=1}; while m>0{ let d:i64=m&15; if d<10{bb[k]=(48+d) as u8}else{bb[k]=(87+d) as u8}; m=(m>>4); k=k+1 } var i:i64=0; let o:*u8=sys_mmap(20); while i<k{o[i]=bb[k-1-i];i=i+1} sys_write(1,o,k); return 0 } 21 22func print_utf16(base: *u8, off: i64) -> i64 { 23 let out: *u8 = sys_mmap(600); var i: i64 = 0; var cnt: i64 = 0 24 while i < 260 { 25 let lo: i64 = base[off + i*2] as i64; let hi: i64 = base[off + i*2 + 1] as i64 26 let cu: i64 = lo | (hi << 8) 27 if cu == 0 { i = 260 } 28 else { if cu >= 0x20 { if cu <= 0x7e { out[cnt] = cu as u8 } else { out[cnt] = 63 as u8 } } else { out[cnt] = 63 as u8 } cnt = cnt + 1; i = i + 1 } 29 } 30 sys_write(1, out, cnt); return cnt 31} 32 33// raw bytes hexdump of first `cnt` bytes of priv (to SEE what came back even if not UTF-16) 34func dump_hex(base: *u8, cnt: i64) -> i64 { 35 var i: i64 = 0 36 while i < cnt { let b: i64 = base[i] as i64; if b < 16 { p("0" as *u8) } x(b); p(" " as *u8); i = i + 1 } 37 return 0 38} 39 40func query(fd: i64, handle: i64, qtype: i64, priv: *u8, psize: i64) -> i64 { 41 var z: i64 = 0; while z < 2048 { priv[z] = 0 as u8; z = z + 1 } 42 let req: *u8 = sys_mmap(64); var y: i64 = 0; while y < 64 { req[y] = 0 as u8; y = y + 1 } 43 let h: *i64 = (req as i64 + 0) as *i64 44 h[0] = (handle & 0xffffffff) | ((qtype & 0xffffffff) << 32) 45 let pd: *i64 = (req as i64 + 8) as *i64; pd[0] = priv as i64 46 let pds: *i64 = (req as i64 + 16) as *i64; pds[0] = psize & 0xffffffff 47 return sys_ioctl(fd, QAI_CODE, req as i64) 48} 49 50func main() -> i64 { 51 p("=== R1 RECON pass2: why EINVAL on QueryAdapterInfo, find the working type/size ===\n" as *u8) 52 let fd: i64 = sys_openat_rd("/dev/dxg" as *u8) 53 if fd < 0 { p("open fail\n" as *u8); sys_exit(1); return 1 } 54 55 let ainfo: *u8 = sys_mmap(4096); var z: i64 = 0; while z < 4096 { ainfo[z] = 0 as u8; z = z + 1 } 56 let ereq: *u8 = sys_mmap(64); var y: i64 = 0; while y < 64 { ereq[y] = 0 as u8; y = y + 1 } 57 ereq[0] = 8 as u8; let r8: *i64 = (ereq as i64 + 8) as *i64; r8[0] = ainfo as i64 58 let eret: i64 = sys_ioctl(fd, DXG_LX_DXENUMADAPTERS2, ereq as i64) 59 let nc: i64 = (ereq[0] as i64)|((ereq[1] as i64)<<8)|((ereq[2] as i64)<<16)|((ereq[3] as i64)<<24) 60 if eret != 0 { p("enum fail\n" as *u8); sys_exit(1); return 1 } 61 let h0: i64 = (ainfo[0] as i64)|((ainfo[1] as i64)<<8)|((ainfo[2] as i64)<<16)|((ainfo[3] as i64)<<24) 62 p("enum ok num_adapters=" as *u8); n(nc); p(" adapter[0] handle=" as *u8); x(h0); p("\n" as *u8) 63 64 let priv: *u8 = sys_mmap(8192) 65 66 // (1) sweep type 0..40, size=1568 on enum handle 67 p("\n-- type sweep (handle=enum0, size=1568) -- (ret!=-22 is interesting)\n" as *u8) 68 var t: i64 = 0 69 while t <= 40 { 70 let qret: i64 = query(fd, h0, t, priv, 1568) 71 if qret != -22 { p(" type=" as *u8); n(t); p(" ret=" as *u8); n(qret); p(" <== NOT EINVAL" as *u8) 72 if qret == 0 { p(" string=\"" as *u8); print_utf16(priv, 0); p("\" head-bytes: " as *u8); dump_hex(priv, 16) } 73 p("\n" as *u8) 74 } 75 t = t + 1 76 } 77 p("(types not listed above all returned -22 EINVAL)\n" as *u8) 78 79 // (2) type=8 size sweep 80 p("\n-- type=8 (ADAPTERREGISTRYINFO) size sweep, enum handle --\n" as *u8) 81 let sizes: *i64 = sys_mmap(64) 82 sizes[0]=0; sizes[1]=4; sizes[2]=8; sizes[3]=520; sizes[4]=1568; sizes[5]=1572; sizes[6]=4096 83 var si: i64 = 0 84 while si < 7 { 85 let qret: i64 = query(fd, h0, 8, priv, sizes[si]) 86 p(" size=" as *u8); n(sizes[si]); p(" ret=" as *u8); n(qret) 87 if qret == 0 { p(" string=\"" as *u8); print_utf16(priv, 0); p("\"" as *u8) } 88 p("\n" as *u8) 89 si = si + 1 90 } 91 92 // (3) NULL private_data, size 0, type 8 (does it then validate handle only?) 93 p("\n-- type=8 NULL priv size=0 --\n" as *u8) 94 let req: *u8 = sys_mmap(64); var y2: i64 = 0; while y2 < 64 { req[y2] = 0 as u8; y2 = y2 + 1 } 95 let h: *i64 = (req as i64 + 0) as *i64; h[0] = (h0 & 0xffffffff) | ((8 as i64) << 32) 96 let qn: i64 = sys_ioctl(fd, QAI_CODE, req as i64) 97 p(" null-priv ret=" as *u8); n(qn); p("\n" as *u8) 98 99 // (4) bogus handle 0xdeadbeef, type=8, size=1568 -- to confirm EINVAL is handle-validation 100 p("\n-- bogus handle 0xdeadbeef type=8 size=1568 (tamper) --\n" as *u8) 101 let qb: i64 = query(fd, 0xdeadbeef, 8, priv, 1568) 102 p(" bogus-handle ret=" as *u8); n(qb); p("\n" as *u8) 103 104 sys_close(fd) 105 p("\n=== R1 RECON pass2 DONE ===\n" as *u8) 106 return 0 107}