Files
Snapintosh/tools/test-audit-shared-detach.py
T
Acelogic 1510d8c6ce Snapintosh public release
An EL2 monitor/hypervisor and toolchain that boots macOS 27 on the ASUS A16
(Snapdragon X2 Elite), with an Adreno Metal plug-in and IOGPU kext, and
air2ir3, an AIR to Mesa ir3 shader compiler.

MIT, with GPL-2.0 components listed in LICENSE and THIRD_PARTY_NOTICES.md.
No Apple, Qualcomm, ASUS or Microsoft binaries are included.
2026-10-21 21:26:36 -04:00

81 lines
5.0 KiB
Python
Executable File

#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
"""Source retirement must have history plus live empty-table evidence."""
from pathlib import Path
import runpy,struct,unittest
ROOT=Path(__file__).resolve().parents[1]
u=runpy.run_path(str(ROOT/'tools/test-audit-unnest.py'))
d=runpy.run_path(str(ROOT/'tools/audit-shared-detach.py'))
BASE=u['BASE'];SHARED=u['SHARED'];START=u['START']
class SharedDetachAuditTests(unittest.TestCase):
def fixture(self,fmt=0):
data,read,kw,nb,words,dst,src,pte=u['UnnestAuditTests']().fixture(fmt)
group=4 if fmt else 1;page=4096 if fmt else 16384;span=1<<(2*(12 if fmt else 14)-3)
child=pte&~0x3fff;parent=src&~0x3fff
old=struct.unpack_from('<H',data,((parent-BASE)>>14)*16+8)[0]
# Fixture only: remove leaf data before the independently checked
# source retirement. Full production ownership is audited separately.
data[child-BASE:child-BASE+0x4000]=bytes(0x4000)
struct.pack_into('<HH',data,((child-BASE)>>14)*16+6,0,0)
struct.pack_into('<H',data,((parent-BASE)>>14)*16+8,old-1)
for i in range(group):
struct.pack_into('<Q',data,src-BASE+i*8,0)
struct.pack_into('<Q',data,dst-BASE+i*8,0)
off=(((dst&~0x3fff)-BASE)>>14)*16+8
count=struct.unpack_from('<H',data,off)[0];struct.pack_into('<H',data,off,count-(group-1))
words=[1,group,group,u['USER'],SHARED,START,group*span//page,0,fmt,START,span,group,group,group,(1<<group)-1]+[0]*31
row=[SHARED,START,src,child,fmt,2,old,1]
blob=bytearray(8+4096*64);struct.pack_into('<9Q',blob,0,1,*row)
return data,read,nb,words,blob,row
def test_source_retirement_is_explicit(self):
data,read,nb,words,blob,row=self.fixture()
report=d['audit_shared_detaches'](read,blob,frame_map=BASE,frame_low=BASE)
# Two bindings at release, one after a later verified unbind.
struct.pack_into('<Q',blob,8+7*8,2)
report=d['audit_shared_detaches'](read,blob,frame_map=BASE,frame_low=BASE)
self.assertEqual(report['current_bindings'],1)
with self.assertRaises(ValueError):u['audit'](read,struct.pack('<46Q',*words),frame_map=BASE,frame_low=BASE)
out=u['audit'](read,struct.pack('<46Q',*words),frame_map=BASE,frame_low=BASE,detachments=report['records'])
self.assertTrue(out['current_removed_descriptors'][0]['source_detached'])
nest=u['n']['nest'](read,nb,frame_map=BASE,frame_low=BASE,
ownership={'nested_descriptors':1},removed=1,detachments=report['records'])
self.assertEqual(nest['last_retired_descriptors'],1)
def test_reused_child_accepted(self):
# The monitor refuses a detach unless the table is all zero; after it
# XNU may re-link the frame or RETYPE it to data and fill it (seen at
# 25 min on the A16), so neither state is evidence of a bad detach.
for kind in range(2):
data,read,nb,words,blob,row=self.fixture();child=row[3]
if kind==0:struct.pack_into('<H',data,((child-BASE)>>14)*16+6,1)
else:
data[((child-BASE)>>14)*16+2]=11;data[child-BASE:child-BASE+0x4000]=b'\xa5'*0x4000
with self.subTest(kind=kind):
d['audit_shared_detaches'](read,blob,frame_map=BASE,frame_low=BASE)
def test_live_corruption_rejected(self):
for kind in range(6):
data,read,nb,words,blob,row=self.fixture();child=row[3];src=row[2]
if kind==0:struct.pack_into('<Q',data,src-BASE,child|3)
elif kind==1:data[((child-BASE)>>14)*16]=1 # in-flight state
elif kind==2:data[child-BASE+0x3fff]=1
elif kind==3:struct.pack_into('<H',data,((SHARED-BASE)>>14)*16+4,0xfffa)
elif kind==4:blob[-1]=1
else:struct.pack_into('<Q',blob,8+5*8,3)
with self.subTest(kind=kind),self.assertRaises(ValueError):
d['audit_shared_detaches'](read,blob,frame_map=BASE,frame_low=BASE)
def test_four_k_group_and_ring(self):
data,read,nb,words,blob,row=self.fixture(1)
report=d['audit_shared_detaches'](read,blob,frame_map=BASE,frame_low=BASE)
out=u['audit'](read,struct.pack('<46Q',*words),frame_map=BASE,frame_low=BASE,detachments=report['records'])
self.assertEqual(len(out['current_removed_descriptors']),4)
self.assertTrue(all(r['source_detached'] for r in out['current_removed_descriptors']))
out=u['n']['nest'](read,nb,frame_map=BASE,frame_low=BASE,
ownership={'nested_descriptors':1},removed=4,detachments=report['records'])
self.assertEqual(out['last_retired_descriptors'],4)
record=struct.pack('<8Q',*row)
wrapped=struct.pack('<Q',4097)+record*4096
self.assertEqual(d['audit_shared_detaches'](read,wrapped,frame_map=BASE,frame_low=BASE)['retained_records'],4096)
def test_empty(self):
def forbidden(*args):raise AssertionError('empty must not read')
self.assertEqual(d['audit_shared_detaches'](forbidden,bytes(8+4096*64),frame_map=BASE,frame_low=BASE)['calls'],0)
if __name__=='__main__':unittest.main()