47 lines
2.5 KiB
Python
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()
|