"""Protected power transaction fence. No kernel sleep command or time grant. The stock PID1 power service Requires+After the short-lived prepare owner. A failed/cancelled/timed-out dependency cannot execute sleep. The durable fence blocks replacement callers after prepare exits; a post-boundary return only permits a NEW D09-authorized lifetime and fresh automatic NTS. Trusted root and the separately appointed administrator remain outside the untrusted boundary. Direct root sysfs writes/ignore-dependencies are not claimed mediated. """ import fcntl import hashlib import json import os from pathlib import Path import select import signal import socket import stat import struct import subprocess import time CONFIG = Path('/etc/archipelago-c01/power.json') ROOT = Path('/var/lib/archipelago-c01-power') RUN = Path('/run/archipelago-c01-power') SOCKET = RUN/'retire.sock' STATE = ROOT/'state.json' TARGETS = ('systemd-suspend', 'systemd-hibernate', 'systemd-hybrid-sleep', 'systemd-suspend-then-hibernate') def require(value, message): if not value: raise ValueError(message) def clock(): return time.clock_gettime_ns(time.CLOCK_BOOTTIME) def canonical(value): return json.dumps(value,sort_keys=True,separators=(',',':')).encode() def protected(path, directory=False): for ancestor in [*reversed(path.parents),path]: meta=ancestor.lstat() require(meta.st_uid==0 and not meta.st_mode&0o022 and not stat.S_ISLNK(meta.st_mode), 'power custody changed') meta=path.stat() require(stat.S_ISDIR(meta.st_mode) if directory else stat.S_ISREG(meta.st_mode) and meta.st_nlink==1, 'power object type/link changed') def read(path): protected(path) with path.open('rb') as stream: raw=stream.read(16385) require(0'00-archipelago-c01.rules', 'earlier power authorization rule can bypass mediation') for target in TARGETS: path=Path('/etc/systemd/system')/(target+'.service.d/40-c01-power.conf') protected(path) require(path.read_text()==power_dropin(target),'mandatory power barrier changed') p=subprocess.run(['/usr/bin/systemctl','show',target+'.service','-p','Requires','-p','After','-p','ExecStopPost'], capture_output=True,text=True,timeout=3,check=True) fields=dict(line.split('=',1) for line in p.stdout.splitlines()) barrier=f'archipelago-c01-power-barrier@{target}.service' require(barrier in fields['Requires'].split() and barrier in fields['After'].split() and 'c01-power-return-v1' in fields['ExecStopPost'],'effective power dependency removed') p=subprocess.run(['/usr/bin/systemctl','show',barrier,'-p','Type','-p','RemainAfterExit','-p','ExecStart','-p','TimeoutStartUSec'], capture_output=True,text=True,timeout=3,check=True) effective=dict(line.split('=',1) for line in p.stdout.splitlines()) require(effective['Type']=='oneshot' and effective['RemainAfterExit']=='no' and effective['TimeoutStartUSec']=='infinity' and 'path=/usr/local/bin/archipelago ; argv[]=/usr/local/bin/archipelago c01-power-prepare-v1 ; ignore_errors=no' in effective['ExecStart'], 'effective barrier may bypass retirement') path=Path('/etc/systemd/system/archipelago-c01-power-barrier@.service') protected(path);require(path.read_text()==barrier_unit(),'power barrier executable/lifetime changed') path=Path('/etc/systemd/system/archipelago-c01-power-observer.service') protected(path);require(path.read_text()==observer_unit(),'power return observer changed') path=Path('/etc/systemd/system/archipelago-c01-access-requalify.service') protected(path);require(path.read_text()==access_requalify_unit(),'access requalification owner changed') path=Path('/etc/systemd/system/archipelago-c01-power-boot.service') protected(path);require(path.read_text()==boot_unit(),'power boot owner changed') for path in (Path('/sys/power/state'),Path('/sys/power/disk'),Path('/dev/snapshot')): if path.exists(): meta=path.stat();require(meta.st_uid==0 and not meta.st_mode&0o022,'untrusted direct power writer') require(not (ROOT/'state.next').exists(),'uncertain power state requires reconciliation') return digest class Lease: """Persistent transaction exclusion, not a time/admission attestation.""" def __init__(self, value): self.config=verify_contract(value) self.fd=lock('lifetime.lock',fcntl.LOCK_SH) try: state=read(STATE) require(state['configuration_sha256']==self.config and state['phase'] in ('Open','RecoveryRequired'), 'power transition fences new lifetime') self.sequence=state['sequence'];self.process=identity(os.getpid()) except BaseException:self.close();raise def request(self): state=read(STATE) require(state['configuration_sha256']==self.config,'power configuration replaced') if state['sequence']==self.sequence and state['phase'] in ('Open','RecoveryRequired'): return None require(state['phase']=='Draining' and state['supervisor']==self.process,'unappointed power transition') return state def connect(self, state): channel=socket.socket(socket.AF_UNIX,socket.SOCK_SEQPACKET|socket.SOCK_CLOEXEC) channel.settimeout(3);channel.connect(str(SOCKET)) peer=struct.unpack('3i',channel.getsockopt(socket.SOL_SOCKET,socket.SO_PEERCRED,12)) require(peer==(state['coordinator']['pid'],0,0) and identity(peer[0])==state['coordinator'], 'power coordinator replaced') return channel def close(self): if self.fd is not None: os.close(self.fd);self.fd=None class PinnedGroup: def __init__(self,path,pidfd=None,owner=0): protected(path.parent,True) meta=path.lstat() require(stat.S_ISDIR(meta.st_mode) and meta.st_uid in (0,owner) and not meta.st_mode&0o022, 'power retirement group custody') self.path=path;self.fd=os.open(path,os.O_PATH|os.O_DIRECTORY|os.O_NOFOLLOW|os.O_CLOEXEC) self.events=os.open('cgroup.events',os.O_RDONLY|os.O_CLOEXEC,dir_fd=self.fd) self.pidfd=pidfd def empty(self): if self.pidfd is not None and not select.select([self.pidfd],[],[],0)[0]: return False if os.readlink(f'/proc/self/fd/{self.fd}')==str(self.path)+' (deleted)': return True try: os.lseek(self.events,0,0) return dict(line.split() for line in os.read(self.events,4096).decode().splitlines()).get('populated')=='0' except OSError: if os.readlink(f'/proc/self/fd/{self.fd}')==str(self.path)+' (deleted)': return True raise def close(self): os.close(self.fd);os.close(self.events) if self.pidfd is not None:os.close(self.pidfd) def prepare(): from c01_supervisor import CONFIG as LAUNCH, root_json import c01_runtime, c01_runtime_view target=target_for_current() require(target=='systemd-suspend','hibernation/suspend-then-hibernate not qualified') value,_=root_json(LAUNCH);digest=verify_contract(value) admin=lock('owner.lock',fcntl.LOCK_EX) keeper=listener=connection=runtime=None pinned=[] try: state=read(STATE) require(state['phase'] in ('Open','RecoveryRequired') and state['configuration_sha256']==digest, 'previous power transaction remains unresolved') current=show('archipelago.service');pid=int(current['MainPID']) require(pid>1,'live epoch supervisor required; retirement authority unavailable') parent=identity(pid) if pid else None if pid: pin=os.pidfd_open(pid) require(group(pid)==Path('/sys/fs/cgroup/system.slice/archipelago.service/supervisor'), 'foreign supervisor group') status=dict(line.split(':',1) for line in Path(f'/proc/{pid}/status').read_text().splitlines() if ':' in line) require(status['Uid'].split()==['0']*4 and status['Gid'].split()==['0']*4 and status['NoNewPrivs'].strip()=='1', 'power supervisor credentials/elevation') with Path(f'/proc/{pid}/exe').open('rb') as executable: require(hashlib.file_digest(executable,'sha256').hexdigest()==value['native_sha256'],'foreign power supervisor executable') require(identity(pid)==parent and not select.select([pin],[],[],0)[0],'power supervisor replaced') pinned.append(PinnedGroup(group(pid).parent,pin)) config,config_digest=c01_runtime.load_config() if show('archipelago-runtime-broker.service')['ActiveState']=='active': runtime=c01_runtime_view.RuntimeLease(config['manager_uid'],config['manager_gid'],config['runtime_uid'],config['runtime_gid'],config_digest) path=Path('/sys/fs/cgroup')/config['user_cgroup'].lstrip('/') require(config['runtime_uid']==1000, 'runtime retirement scope') if runtime is not None: require(Path(runtime.identity['cgroup']).is_relative_to(path),'runtime worker escaped appointment') manager=int(show('user@1000.service')['MainPID']) if manager: require(manager>1 and group(manager).is_relative_to(path),'runtime manager identity') pinned.append(PinnedGroup(path,os.pidfd_open(manager),owner=1000)) access_pid=int(show('archipelago-c01-access.service')['MainPID']) require(access_pid>1,'live access owner required before power retirement') pinned.append(PinnedGroup(Path('/sys/fs/cgroup/system.slice/archipelago-c01-access.service'),os.pidfd_open(access_pid))) protected(RUN,True) require(not SOCKET.exists(),'unreconciled power endpoint') listener=socket.socket(socket.AF_UNIX,socket.SOCK_SEQPACKET|socket.SOCK_CLOEXEC) listener.bind(str(SOCKET));os.chmod(SOCKET,0o600);listener.listen(1);listener.settimeout(30) state={**state,'sequence':state['sequence']+1,'phase':'Draining','target':target, 'nonce':os.urandom(32).hex(),'coordinator':identity(os.getpid()),'supervisor':parent, 'boot_id':Path('/proc/sys/kernel/random/boot_id').read_text().strip(), 'barrier_boottime_ns':clock()} write(state) if pid: signal.pidfd_send_signal(pinned[0].pidfd,signal.SIGUSR1) connection,_=listener.accept();connection.settimeout(30) require(struct.unpack('3i',connection.getsockopt(socket.SOL_SOCKET,socket.SO_PEERCRED,12))==(pid,0,0), 'foreign retirement sender') receipt=json.loads(connection.recv(8192)) require(receipt=={'nonce':state['nonce'],'epoch_revoked':True,'callers_reaped':True},'epoch/caller retirement unproved') end=clock()+30_000_000_000 while pid and not pinned[0].empty(): require(clock()