Files
archy/scripts/c01_runtime_endpoints.py

85 lines
4.1 KiB
Python

#!/usr/bin/python3 -I -S
"""Re-admit only appointed runtime producers; no RPC or caller argv/paths."""
import os
from pathlib import Path
import stat
import sys
import time
import types
if __name__=='__main__':
for name in ('c01_network','c01_endpoints','runtime_uplink','c01_uplink','c01_network_mdns','c01_retained_producer','c01_network_plan','c01_network_owner','c01_kiosk_endpoints'):
source=Path(__file__).resolve().with_name(name+'.py')
for item in (source,*source.parents):
m=item.lstat()
if m.st_uid or m.st_mode&0o022 or stat.S_ISLNK(m.st_mode):raise ValueError('unprotected runtime endpoint code')
module=types.ModuleType(name);module.__file__=str(source);sys.modules[name]=module
exec(compile(source.read_bytes(),str(source),'exec'),module.__dict__)
import c01_network_owner as network
import c01_retained_producer
from c01_kiosk_endpoints import request,PRODUCERS
def discover(policy,route):
end=time.monotonic()+2
group=Path('/sys/fs/cgroup'+route['target_cgroup'])
projection=policy.manifests[route['projection_sha256']]
selector=projection.get('producer',{'kind':'exact'})
try:
if selector['kind']=='retained-container-v1':groups=[group,group/'runtime',Path('/sys/fs/cgroup'+c01_retained_producer.payload_group(selector,route['target_cgroup']))]
elif selector['kind']=='exact':groups=[group]
else:groups=[p for p in group.iterdir() if p.name.startswith('libpod-payload-') and p.is_dir()]
except FileNotFoundError:return None
if len(groups)>16:raise ValueError('runtime producer cgroup bound')
candidates=[]
for current in groups:
try:pids=(current/'cgroup.procs').read_text().split()
except FileNotFoundError:continue
if len(pids)>256:raise ValueError('runtime producer process bound')
for text in pids:
if time.monotonic()>=end:raise TimeoutError('runtime endpoint discovery budget')
pid=int(text)
try:entries=list(Path(f'/proc/{pid}/fd').iterdir())
except FileNotFoundError:continue
if len(entries)>1024:raise ValueError('runtime descriptor bound')
for entry in entries:
if time.monotonic()>=end:raise TimeoutError('runtime endpoint discovery budget')
try:
if not os.readlink(entry).startswith('socket:['):continue
target=network.Target(policy,route,pid,int(entry.name))
except (OSError,ValueError):continue
try:candidates.append((pid,int(entry.name),os.fstat(target.listener.fileno()).st_ino,target.identity['start']))
finally:target.close()
# A prefork server's master/workers may share one kernel listening socket.
# Pin the oldest qualified holder, normally its master, not an arbitrary
# worker. A different socket remains ambiguous and is never substituted.
identities={inode for _,_,inode,_ in candidates}
if len(identities)>1:raise ValueError('ambiguous runtime producer')
return min(candidates,key=lambda item:(item[3],item[0],item[1]))[:2] if candidates else None
def tick(policy):
policy.check()
for name,route in policy.routes.items():
if route['target']!='runtime' or name in PRODUCERS:continue
status=request(policy,{'method':'inspect','name':name})
if status.get('name')!=name:raise ValueError('runtime status binding')
if status.get('producer') is not None:continue
candidate=discover(policy,route)
if candidate is None:continue
response=request(policy,{'method':'register','name':name,'pid':candidate[0],'fd':candidate[1],'previous':status['generation']})
if set(response)!={'registered','policy_sha256','generation'} or response['registered']!=name:raise ValueError('runtime registration reply')
def main():
if os.getresuid()!=(0,0,0) or os.getresgid()!=(0,0,0) or len(sys.argv)!=1:raise ValueError('fixed root runtime endpoint owner')
policy=network.Policy()
try:
while True:
tick(policy)
time.sleep(.5)
finally:policy.close()
if __name__=='__main__':main()