Files
archy/tests/regression/c01-role-views.py

47 lines
2.5 KiB
Python

"""Real authority mount-view probe; no key contents, grants or ready messages."""
import ctypes,json,os
from pathlib import Path
import subprocess,sys,time
sys.path.insert(0,'/opt/c01-fixture/scripts')
import c01_views as views
import c01_children as lifecycle
assert os.geteuid()==0 and Path('/run/.containerenv').exists()
libc=ctypes.CDLL(None,use_errno=True)
assert libc.prctl(4,0,0,0,0)==0 and libc.prctl(38,1,0,0,0)==0
launch=json.loads(Path('/etc/archipelago-c01/launch.json').read_text())
epoch=json.loads(Path('/etc/archipelago-c01/epoch.json').read_text())
sources={}
for name,path in [('authority',launch['authority_backing']),('epoch',epoch['backing'])]:
fd=views.require_private_backing(path);sources[name]=views.PinnedSource.capture(fd,path)
original=subprocess.run
def measured(command,**kwargs):
result=original(command,**kwargs)
if command[0]=='/usr/bin/mount':
print(json.dumps({'mount_argv':command,'exit':result.returncode,
'stderr':result.stderr.decode(errors='replace')[:2048]}),flush=True)
return result
def child(control):
status=dict(line.split(':',1) for line in Path('/proc/self/status').read_text().splitlines() if ':' in line)
print(json.dumps({k:status[k].strip() for k in ('Uid','Gid','CapInh','CapEff','CapPrm','CapBnd','NoNewPrivs','Seccomp')}),flush=True)
views.subprocess.run=measured
mounts=views.PrivateMounts()
for target in ('/run','/home','/root','/tmp','/var/tmp'):mounts.cover(target,0o755 if target=='/run' else 0o700)
base=Path('/run/archipelago-c01');base.mkdir(mode=0o755);base.chmod(0o755)
for name,source in sources.items():
target=Path('/run/archipelago-c01')/name;target.mkdir(mode=0o700,parents=True)
mounts.idmapped_directory(source,target,launch['runtime_uid'],61002,launch['runtime_gid'],61002)
lifecycle.drop_credentials(61002,61002,os.getppid())
status=dict(line.split(':',1) for line in Path('/proc/self/status').read_text().splitlines() if ':' in line)
assert all(int(status[name],16)==0 for name in ('CapEff','CapPrm','CapInh','CapAmb'))
for name in sources:
fd=os.open(base/name,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW)
assert os.fstat(fd).st_uid==61002;os.close(fd)
print('ACTUAL_AUTHORITY_VIEWS_VERIFIED',flush=True)
children=lifecycle.Children()
try:
children.spawn('authority',child,tuple(source.fd for source in sources.values()))
while children.children:children.poll();time.sleep(.01)
assert children.results['authority']==0,children.results
finally:children.close()