#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-3.0-or-later """Host-only ownership model for hybrid BigApp/JIT mapping composition.""" from __future__ import annotations from dataclasses import dataclass MAX_EXECUTABLE_SEGMENTS = 8 MAX_EVENTS = 256 MAX_TICKS = 256 CREATE_CHILD = "CREATE_CHILD" RESERVE_REGION = "RESERVE_REGION" CREATE_MIRROR = "CREATE_MIRROR" CREATE_JIT_MASTER = "CREATE_JIT_MASTER" MAP_EXECUTABLE = "MAP_EXECUTABLE" CREATE_JIT_ALIAS = "CREATE_JIT_ALIAS" MAP_HOST_ALIAS = "MAP_HOST_ALIAS" MAP_REMOTE_ALIAS = "MAP_REMOTE_ALIAS" COPY_ALIAS = "COPY_ALIAS" UNMAP_REMOTE_ALIAS = "UNMAP_REMOTE_ALIAS" UNMAP_HOST_ALIAS = "UNMAP_HOST_ALIAS" CLOSE_JIT_ALIAS = "CLOSE_JIT_ALIAS" CLOSE_JIT_MASTER = "CLOSE_JIT_MASTER" FINALIZE_IMAGE = "FINALIZE_IMAGE" RELEASE_MIRROR = "RELEASE_MIRROR" UNMAP_REGION = "UNMAP_REGION" KILL_AND_REAP_CHILD = "KILL_AND_REAP_CHILD" OK = "OK" ERROR = "ERROR" INDEXED = { CREATE_JIT_MASTER, MAP_EXECUTABLE, CREATE_JIT_ALIAS, MAP_HOST_ALIAS, MAP_REMOTE_ALIAS, COPY_ALIAS, UNMAP_REMOTE_ALIAS, UNMAP_HOST_ALIAS, CLOSE_JIT_ALIAS, CLOSE_JIT_MASTER, } OPERATIONS = INDEXED | { CREATE_CHILD, RESERVE_REGION, CREATE_MIRROR, FINALIZE_IMAGE, RELEASE_MIRROR, UNMAP_REGION, KILL_AND_REAP_CHILD, } class CompositionError(RuntimeError): """The synthetic ownership transaction cannot close safely.""" @dataclass(frozen=True) class CompositionPlan: executable_segments: int def __post_init__(self) -> None: if not isinstance(self.executable_segments, int) \ or isinstance(self.executable_segments, bool) \ or not 1 <= self.executable_segments <= MAX_EXECUTABLE_SEGMENTS: raise CompositionError("executable segment count is invalid") @dataclass(frozen=True) class FakeEvent: operation: str result: str segment: int = -1 ticks: int = 1 def __post_init__(self) -> None: if self.operation not in OPERATIONS or self.result not in {OK, ERROR}: raise CompositionError("event operation/result is invalid") if (self.operation in INDEXED) != (self.segment >= 0): raise CompositionError("event segment binding is invalid") if not isinstance(self.segment, int) or isinstance(self.segment, bool): raise CompositionError("event segment is invalid") if not isinstance(self.ticks, int) or isinstance(self.ticks, bool) \ or not 1 <= self.ticks <= MAX_TICKS: raise CompositionError("event ticks are invalid") class FakeFacade: """Exact fake script with no process, mapping, clock or device access.""" def __init__(self, events: tuple[FakeEvent, ...]) -> None: if not isinstance(events, tuple) or not 1 <= len(events) <= MAX_EVENTS \ or any(type(event) is not FakeEvent for event in events): raise CompositionError("fake composition script is invalid") self._events = list(events) self.ticks = 0 def invoke(self, operation: str, segment: int = -1, cleanup: bool = False) -> str: if not self._events: raise CompositionError("fake composition script is exhausted") event = self._events.pop(0) if event.operation != operation or event.segment != segment: raise CompositionError("fake composition ordering differs") if not cleanup and self.ticks + event.ticks > MAX_TICKS: raise CompositionError("composition deadline precedes operation") self.ticks += event.ticks return event.result @property def remaining(self) -> int: return len(self._events) @dataclass(frozen=True) class CompositionOutcome: classification: str success: bool child_alive: bool image_retained: bool resources_open: int fail_closed_termination: bool target_action_performed: bool = False firmware_behavior_proven: bool = False def _require(facade: FakeFacade, operation: str, segment: int = -1) -> None: if facade.invoke(operation, segment) != OK: raise CompositionError(f"{operation} failed") def run_composition(plan: CompositionPlan, facade: FakeFacade) -> CompositionOutcome: """Compose synthetic resources; cleanup failure requires child termination.""" if type(plan) is not CompositionPlan or type(facade) is not FakeFacade: raise CompositionError("composition boundary is invalid") child = region = mirror = committed = False masters: set[int] = set() aliases: set[int] = set() host_aliases: set[int] = set() remote_aliases: set[int] = set() primary_failed = cleanup_failed = terminated = False try: _require(facade, CREATE_CHILD) child = True _require(facade, RESERVE_REGION) region = True _require(facade, CREATE_MIRROR) mirror = True for segment in range(plan.executable_segments): _require(facade, CREATE_JIT_MASTER, segment) masters.add(segment) _require(facade, MAP_EXECUTABLE, segment) _require(facade, CREATE_JIT_ALIAS, segment) aliases.add(segment) _require(facade, MAP_HOST_ALIAS, segment) host_aliases.add(segment) _require(facade, MAP_REMOTE_ALIAS, segment) remote_aliases.add(segment) _require(facade, COPY_ALIAS, segment) _require(facade, UNMAP_REMOTE_ALIAS, segment) remote_aliases.remove(segment) _require(facade, UNMAP_HOST_ALIAS, segment) host_aliases.remove(segment) _require(facade, CLOSE_JIT_ALIAS, segment) aliases.remove(segment) _require(facade, CLOSE_JIT_MASTER, segment) masters.remove(segment) _require(facade, FINALIZE_IMAGE) _require(facade, RELEASE_MIRROR) mirror = False committed = True except Exception: primary_failed = True if primary_failed: for resources, operation in ( (remote_aliases, UNMAP_REMOTE_ALIAS), (host_aliases, UNMAP_HOST_ALIAS), (aliases, CLOSE_JIT_ALIAS), (masters, CLOSE_JIT_MASTER), ): for segment in sorted(resources, reverse=True): if facade.invoke(operation, segment, cleanup=True) != OK: cleanup_failed = True else: resources.remove(segment) if mirror: if facade.invoke(RELEASE_MIRROR, cleanup=True) != OK: cleanup_failed = True else: mirror = False if region: if facade.invoke(UNMAP_REGION, cleanup=True) != OK: cleanup_failed = True else: region = False if child: if facade.invoke(KILL_AND_REAP_CHILD, cleanup=True) != OK: raise CompositionError("fail-closed child termination failed") child = False terminated = True masters.clear() aliases.clear() host_aliases.clear() remote_aliases.clear() mirror = region = False if facade.remaining: raise CompositionError("fake composition script has unused operations") open_count = (int(mirror) + int(region) + len(masters) + len(aliases) + len(host_aliases) + len(remote_aliases)) if primary_failed: if child or open_count: raise CompositionError("failed composition retained ownership") classification = ("OFFLINE_FAIL_CLOSED_AFTER_CLEANUP_FAILURE" if cleanup_failed else "OFFLINE_COMPOSITION_ROLLED_BACK") return CompositionOutcome(classification, False, False, False, 0, terminated) if not committed or not child or not region or mirror or open_count != 1: raise CompositionError("successful composition invariants failed") return CompositionOutcome("OFFLINE_HYBRID_COMPOSITION_COMPLETE", True, True, True, 0, False)