3"""Supervise injected image-selftest failures without reusable PID authority."""
5from __future__
import annotations
16from collections.abc
import Callable
17from contextlib
import suppress
18from dataclasses
import dataclass
19from pathlib
import Path
20from typing
import NoReturn
22MANAGED_SIGNALS = (signal.SIGHUP, signal.SIGINT, signal.SIGTERM)
23DEADLINE_SECONDS = 10.0
25CONTROLLER_ARG_COUNT = 8
26SUPERVISOR_ARG_COUNT = 7
27HIDDEN_SELFTEST_ARG_COUNT = 4
28ROOT_SELFTEST_ARG_COUNT = 3
29WATCHDOG_TIMEOUT_SECONDS = 30.0
30SELFTEST_WATCHDOG_TIMEOUT_SECONDS = 1.0
33WRITE_ATTEMPT_MULTIPLIER = 2
35INJECTED_FAILURE_STATUS = 1
36PUBLIC_REFUSAL_STATUS = 125
37INTEGRITY_REFUSAL_STATUS = 126
40MIN_POPULATED_GROUP_MEMBERS = 2
41ENTRY_MAX_BYTES = 1024 * 1024
43ENTRY_MODES = (0o700, 0o755)
45CASES_MAX_BYTES = 128 * 1024
47CASES_RAW_SHA256 =
"897a5be60eec486f9f9615fead84db22f8526dba189df305f561bc1c7b5e49e7"
48CASES_ARG =
"--cases-fd"
50PROCESS_MAX_BYTES = 64 * 1024
51PROCESS_READ_STEPS = 17
52PROCESS_RAW_SHA256 =
"7dbb7b6fa4c477d8baea6ed43f2f1bb87a1555015dda5984fed1efb614b182f8"
53PROCESS_ARG =
"--process-fd"
55SUITE_ROOT_PREFIX =
"ra8-devcontainer-image-selftest."
56SUITE_ROOT_SUFFIX_LENGTH = 32
62@dataclass(frozen=True)
63class SupervisorRequest:
64 """Describe one immutable public supervision request."""
73@dataclass(frozen=True)
74class ControllerLaunch:
75 """Bind one controller's entry, status, deadline, and test-only controls."""
79 watchdog_timeout: float
80 missing_entry_selftest: bool =
False
81 entry_mutator: Callable[[],
None] |
None =
None
82 pre_open_mutator: Callable[[],
None] |
None =
None
85@dataclass(frozen=True)
86class SupervisionControls:
87 """Describe optional private observations without widening the public CLI."""
89 test_descriptor: int |
None =
None
90 pause_before_bound: bool =
False
91 watchdog_timeout: float = WATCHDOG_TIMEOUT_SECONDS
92 missing_entry_selftest: bool =
False
93 entry_mutator: Callable[[],
None] |
None =
None
94 pre_open_mutator: Callable[[],
None] |
None =
None
97def _refuse_entry(message: str) -> NoReturn:
98 """Raise one uniform entry-authority refusal."""
99 raise RuntimeError(message)
102def _entry_digest(descriptor: int) -> str:
103 """Hash one bounded entry descriptor without reopening its pathname."""
104 digest = hashlib.sha256()
106 for _step
in range(ENTRY_READ_STEPS):
107 chunk = os.pread(descriptor, 4096, total)
111 if total > ENTRY_MAX_BYTES:
112 message =
"entry exceeds its byte bound"
113 _refuse_entry(message)
116 message =
"entry read exceeded its step bound"
117 _refuse_entry(message)
118 return digest.hexdigest()
121def _read_cases_source(descriptor: int) -> bytes:
122 """Read one bounded authenticated cases module without using its pathname."""
123 metadata = os.fstat(descriptor)
125 stat.S_ISREG(metadata.st_mode)
126 and metadata.st_nlink == 1
127 and metadata.st_uid == os.getuid()
128 and metadata.st_gid == os.getgid()
129 and stat.S_IMODE(metadata.st_mode) == CASES_MODE
130 and 0 < metadata.st_size <= CASES_MAX_BYTES
133 message =
"supervisor cases metadata is unsafe"
134 _refuse_entry(message)
137 for _step
in range(CASES_READ_STEPS):
138 chunk = os.pread(descriptor, 4096, offset)
143 source = b
"".join(parts)
144 if len(source) != metadata.st_size
or len(source) > CASES_MAX_BYTES:
145 message =
"supervisor cases read is incomplete"
146 _refuse_entry(message)
150def _read_process_source(descriptor: int) -> bytes:
151 """Read the bounded authenticated process module without its pathname."""
152 metadata = os.fstat(descriptor)
154 stat.S_ISREG(metadata.st_mode)
155 and metadata.st_nlink == 1
156 and metadata.st_uid == os.getuid()
157 and metadata.st_gid == os.getgid()
158 and stat.S_IMODE(metadata.st_mode) == PROCESS_MODE
159 and 0 < metadata.st_size <= PROCESS_MAX_BYTES
162 message =
"supervisor process metadata is unsafe"
163 _refuse_entry(message)
166 for _step
in range(PROCESS_READ_STEPS):
167 chunk = os.pread(descriptor, 4096, offset)
172 source = b
"".join(parts)
173 if len(source) != metadata.st_size
or len(source) > PROCESS_MAX_BYTES:
174 message =
"supervisor process read is incomplete"
175 _refuse_entry(message)
179def _entry_metadata_is_safe(metadata: os.stat_result) -> bool:
180 """Apply the complete reusable entry metadata predicate."""
182 stat.S_ISREG(metadata.st_mode)
183 and metadata.st_nlink == 1
184 and metadata.st_uid == os.getuid()
185 and metadata.st_gid == os.getgid()
186 and stat.S_IMODE(metadata.st_mode)
in ENTRY_MODES
187 and 0 < metadata.st_size <= ENTRY_MAX_BYTES
191def _suite_root_metadata_is_safe(metadata: os.stat_result) -> bool:
192 """Apply the complete private suite-root metadata predicate."""
194 stat.S_ISDIR(metadata.st_mode)
195 and metadata.st_uid == os.getuid()
196 and metadata.st_gid == os.getgid()
197 and stat.S_IMODE(metadata.st_mode) == PRIVATE_MODE
201def _suite_root_path_is_safe(root: Path, metadata: os.stat_result) -> bool:
202 """Require one direct canonical-/tmp random suite-root pathname."""
204 canonical = CANONICAL_TMP.resolve(strict=
True)
205 resolved = root.resolve(strict=
True)
208 suffix = root.name.removeprefix(SUITE_ROOT_PREFIX)
211 and root.parent == canonical
213 and len(suffix) == SUITE_ROOT_SUFFIX_LENGTH
214 and all(character
in "0123456789abcdef" for character
in suffix)
215 and _suite_root_metadata_is_safe(metadata)
219def _open_suite_root_authority(root: Path) -> tuple[int, tuple[int, int]]:
220 """Bind a suite root before any receipt path is derived from it."""
221 before = root.lstat()
222 if not _suite_root_path_is_safe(root, before):
223 message =
"suite root path is unsafe"
224 _refuse_entry(message)
225 descriptor = os.open(root, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
227 after = os.fstat(descriptor)
228 identity = (after.st_dev, after.st_ino)
229 if not _suite_root_metadata_is_safe(after)
or identity != (
233 message =
"suite root identity changed while opening"
234 _refuse_entry(message)
235 except BaseException:
239 return descriptor, identity
242def _close_suite_root_authority(descriptor: int, root: Path, identity: tuple[int, int]) -> bool:
243 """Revalidate and close one retained root only after process cleanup."""
246 opened = os.fstat(descriptor)
247 current = root.lstat()
249 _suite_root_metadata_is_safe(opened)
250 and _suite_root_path_is_safe(root, current)
251 and (opened.st_dev, opened.st_ino) == identity
252 and (current.st_dev, current.st_ino) == identity
261def _anchored_root_path(descriptor: int) -> Path:
262 """Name one retained root descriptor without reopening its pathname."""
263 return Path(f
"/proc/self/fd/{descriptor}")
266def _anchored_root_descriptor(path: Path) -> int:
267 """Recover the retained root descriptor from one anchored child path."""
268 parent = str(path.parent)
269 prefix =
"/proc/self/fd/"
270 suffix = parent.removeprefix(prefix)
271 if parent == f
"{prefix}{suffix}" and suffix.isdigit()
and path.name
not in (
"",
".",
".."):
273 message =
"receipt path is not rooted in a retained descriptor"
274 _refuse_entry(message)
277def _open_entry_authority(
278 path: str, pre_open_mutator: Callable[[],
None] |
None =
None
279) -> tuple[int, tuple[int, int], str]:
280 """Bind one trusted regular entry by metadata, inode, and initial digest."""
281 before = os.lstat(path)
282 if pre_open_mutator
is not None:
284 descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
286 after = os.fstat(descriptor)
287 identity = (after.st_dev, after.st_ino)
288 safe = _entry_metadata_is_safe(before)
and _entry_metadata_is_safe(after)
289 safe = safe
and (before.st_dev, before.st_ino) == identity
291 message =
"entry metadata is unsafe"
292 _refuse_entry(message)
293 return descriptor, identity, _entry_digest(descriptor)
294 except BaseException:
299def _write_exact(descriptor: int, payload: bytes, declared_max: int) ->
None:
300 """Write every payload byte with a finite progress and interruption bound."""
301 if declared_max < 0
or len(payload) > declared_max:
302 message =
"receipt payload exceeds its declared bound"
303 raise ValueError(message)
307 max_attempts = max(1,
min(len(payload), declared_max)) * WRITE_ATTEMPT_MULTIPLIER
309 while offset < len(payload):
311 if attempts > max_attempts:
312 raise OSError(errno.EIO,
"receipt write made no bounded progress")
314 accepted = os.write(descriptor, payload[offset:])
315 except OSError
as error:
316 if error.errno == errno.EINTR:
319 remaining = len(payload) - offset
320 if accepted <= 0
or accepted > remaining:
321 raise OSError(errno.EIO,
"receipt write returned invalid progress")
325def _write_exclusive(path: Path, value: str) ->
None:
326 """Write one non-link receipt without replacing an existing object."""
327 descriptor = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
329 payload = value.encode(
"ascii")
330 _write_exact(descriptor, payload, ENTRY_MAX_BYTES)
336def _write_bound_receipt(path: Path, value: str) ->
None:
337 """Write the child PID through one pre-created regular receipt."""
338 descriptor = os.open(path, os.O_WRONLY | os.O_NOFOLLOW)
340 metadata = os.fstat(descriptor)
342 not stat.S_ISREG(metadata.st_mode)
343 or metadata.st_nlink != 1
344 or metadata.st_uid != os.getuid()
345 or stat.S_IMODE(metadata.st_mode) != RECEIPT_MODE
347 message =
"bound receipt metadata is unsafe"
348 raise RuntimeError(message)
349 os.ftruncate(descriptor, 0)
350 payload = value.encode(
"ascii")
351 _write_exact(descriptor, payload, RECEIPT_MAX_BYTES)
357def _write_status_atomic(path: Path, value: str) ->
None:
358 """Publish a complete status without replacing a pre-existing final path."""
359 temporary = path.with_name(f
"{path.name}.tmp.{os.getpid()}")
360 _write_exclusive(temporary, value)
362 os.link(temporary, path, follow_symlinks=
False)
364 temporary.unlink(missing_ok=
True)
367def _reset_managed_signals() -> None:
368 """Give the nested Bash fresh dispositions after controller isolation."""
369 for managed
in MANAGED_SIGNALS:
370 signal.signal(managed, signal.SIG_DFL)
373def _spawn_payload(entry_authority: str, private_descriptors: tuple[int, ...]) -> int:
374 """Fork the fixed Bash payload from a bound descriptor or explicit negative."""
375 if entry_authority ==
"missing-entry-selftest":
376 entry =
"/proc/self/fd/2147483647"
378 descriptor = int(entry_authority)
379 metadata = os.fstat(descriptor)
380 if not _entry_metadata_is_safe(metadata):
381 message =
"controller entry descriptor is unsafe"
382 _refuse_entry(message)
383 entry = f
"/proc/self/fd/{descriptor}"
386 for private_descriptor
in private_descriptors:
387 with suppress(OSError):
388 os.close(private_descriptor)
389 _reset_managed_signals()
404def _poll_payload(child: int) -> int |
None:
405 """Return and reap one terminal payload, or report that it is still live."""
406 waited, raw_status = os.waitpid(child, os.WNOHANG)
407 return None if waited == 0
else os.waitstatus_to_exitcode(raw_status)
410def _controller_status_root_is_safe(
411 status_receipt: Path, root_descriptor: int, expected_identity: str
413 """Bind the private controller to its inherited suite-root descriptor."""
415 metadata = os.fstat(root_descriptor)
416 resolved = _anchored_root_path(root_descriptor).resolve(strict=
True)
419 identity = f
"{metadata.st_dev}:{metadata.st_ino}"
421 status_receipt.parent == _anchored_root_path(root_descriptor)
422 and _suite_root_metadata_is_safe(metadata)
423 and _suite_root_path_is_safe(resolved, metadata)
424 and identity == expected_identity
429 entry_authority: str,
430 status_receipt: Path,
431 death_descriptor: int,
432 root_authority: tuple[int, str],
433 watchdog_timeout: float,
435 """Publish nested status while enforcing parent death and a fixed deadline."""
436 process = os.getpid()
437 root_descriptor, root_identity = root_authority
439 process != os.getpgrp()
440 or process != os.getsid(0)
441 or not _controller_status_root_is_safe(status_receipt, root_descriptor, root_identity)
444 for managed
in MANAGED_SIGNALS:
445 signal.signal(managed, signal.SIG_IGN)
446 signal.pthread_sigmask(signal.SIG_UNBLOCK, MANAGED_SIGNALS)
448 steps = int(watchdog_timeout / POLL_SECONDS) + 1
450 child = _spawn_payload(entry_authority, (death_descriptor, root_descriptor))
451 for _step
in range(steps):
452 ready, _, _ = select.select((death_descriptor,), (), (), POLL_SECONDS)
454 os.read(death_descriptor, 1)
457 child_status = _poll_payload(child)
458 if child_status
is not None:
459 _write_status_atomic(status_receipt, f
"{child_status}\n")
462 for private_descriptor
in (death_descriptor, root_descriptor):
463 with suppress(OSError):
464 os.close(private_descriptor)
465 os.killpg(os.getpgrp(), signal.SIGKILL)
469def _wait_status(path: Path) -> int:
470 """Return a status within the controller watchdog plus cleanup margin."""
471 deadline = time.monotonic() + WATCHDOG_TIMEOUT_SECONDS + DEADLINE_SECONDS
472 while time.monotonic() < deadline:
474 descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
475 except FileNotFoundError:
476 time.sleep(POLL_SECONDS)
479 metadata = os.fstat(descriptor)
480 if metadata.st_nlink != 1:
481 time.sleep(POLL_SECONDS)
484 stat.S_ISREG(metadata.st_mode)
485 and metadata.st_uid == os.getuid()
486 and stat.S_IMODE(metadata.st_mode) == RECEIPT_MODE
487 and metadata.st_size == STATUS_SIZE
489 value = os.read(descriptor, 3)
492 if safe
and value == b
"1\n":
494 message =
"controller status receipt is malformed"
495 raise RuntimeError(message)
496 message =
"controller status receipt timed out"
497 raise TimeoutError(message)
500def _install_interruption_handlers(supervisor: BoundGroup) ->
None:
501 """Install managed-signal handlers that retry bound cleanup before exit."""
503 def interrupted(signum: int, _frame: object) ->
None:
504 signal.pthread_sigmask(signal.SIG_BLOCK, MANAGED_SIGNALS)
505 for managed
in MANAGED_SIGNALS:
506 signal.signal(managed, signal.SIG_IGN)
507 cleaned = supervisor.contain()
508 os._exit(128 + signum
if cleaned
else 1)
510 for managed
in MANAGED_SIGNALS:
511 signal.signal(managed, interrupted)
515 request: SupervisorRequest,
516 controls: SupervisionControls |
None =
None,
518 """Run one injected failure with pre-spawn signal deferral and exact cleanup."""
519 supervisor = BoundGroup()
520 active = controls
if controls
is not None else SupervisionControls()
521 owned_test_descriptor = active.test_descriptor
522 if not supervisor.enable_subreaper():
523 return INTEGRITY_REFUSAL_STATUS
524 old_mask = signal.pthread_sigmask(signal.SIG_BLOCK, MANAGED_SIGNALS)
525 _install_interruption_handlers(supervisor)
527 source_descriptor = int(Path(__file__).name)
528 launch = ControllerLaunch(
531 active.watchdog_timeout,
532 active.missing_entry_selftest,
533 active.entry_mutator,
534 active.pre_open_mutator,
536 supervisor.spawn(source_descriptor, launch)
537 if supervisor.pid
is None:
539 if owned_test_descriptor
is not None:
541 owned_test_descriptor,
542 f
"{supervisor.pid}\n".encode(
"ascii"),
545 os.close(owned_test_descriptor)
546 owned_test_descriptor =
None
547 if active.pause_before_bound:
548 time.sleep(
min(DEADLINE_SECONDS * 2, active.watchdog_timeout * 2))
550 _write_bound_receipt(request.bound, f
"{supervisor.pid}\n")
551 if request.mode ==
"signal-pre-bind":
552 os.kill(os.getpid(), signal.SIGTERM)
553 signal.pthread_sigmask(signal.SIG_SETMASK, old_mask)
554 _write_exclusive(request.outer, f
"{supervisor.pid}\n")
555 child_status = _wait_status(request.status)
556 supervisor.require_running(
"after publishing status")
557 time.sleep(POLL_SECONDS * 2)
558 supervisor.require_running(
"through the observation interval")
559 except (OSError, RuntimeError, TimeoutError):
560 cleaned = supervisor.cleanup()
561 return PUBLIC_REFUSAL_STATUS
if cleaned
else INTEGRITY_REFUSAL_STATUS
563 cleaned = supervisor.cleanup()
564 return child_status
if cleaned
else INTEGRITY_REFUSAL_STATUS
566 if owned_test_descriptor
is not None:
567 with suppress(OSError):
568 os.close(owned_test_descriptor)
570 signal.pthread_sigmask(signal.SIG_SETMASK, old_mask)
573def _dispatch_controller(argv: list[str]) -> int |
None:
574 """Dispatch the private controller and stat-parser modes."""
575 if len(argv) == CONTROLLER_ARG_COUNT
and argv[1] ==
"--controller":
576 watchdog_timeout = float(argv[7])
577 if watchdog_timeout
not in (WATCHDOG_TIMEOUT_SECONDS, SELFTEST_WATCHDOG_TIMEOUT_SECONDS):
583 (int(argv[5]), argv[6]),
589def _load_cases_dispatch(descriptor: int) -> Callable[[list[str]], int |
None]:
590 """Load the authenticated source-only cases dispatcher from its bound FD."""
592 source = _read_cases_source(descriptor)
593 digest = hashlib.sha256(source).hexdigest()
594 if digest != CASES_RAW_SHA256:
595 message =
"supervisor cases digest drifted"
596 _refuse_entry(message)
598 "__name__":
"_ra8_supervisor_cases",
599 "__file__": f
"/proc/self/fd/{descriptor}",
600 "_RA8_SUPERVISOR_CASES_VERSION": 1,
603 compile(source, namespace[
"__file__"],
"exec"), namespace
605 grant = namespace.pop(
"_RA8_SUPERVISOR_CASES_VERSION",
None)
606 if grant != 1
or "_RA8_SUPERVISOR_CASES_VERSION" in namespace:
607 message =
"supervisor cases load grant was not consumed"
608 _refuse_entry(message)
609 if hashlib.sha256(_read_cases_source(descriptor)).hexdigest() != digest:
610 message =
"supervisor cases changed while loading"
611 _refuse_entry(message)
612 dispatch = namespace.get(
"dispatch_supervisor_cases")
613 if not callable(dispatch):
614 message =
"supervisor cases dispatcher is absent"
615 _refuse_entry(message)
616 if dispatch.__globals__
is not namespace:
617 message =
"supervisor cases dispatcher escaped its private namespace"
618 _refuse_entry(message)
624def _load_process_api(descriptor: int) -> tuple[object, ...]:
625 """Load the authenticated source-only process primitives from a bound FD."""
626 module_name =
"_ra8_supervisor_process"
629 source = _read_process_source(descriptor)
630 digest = hashlib.sha256(source).hexdigest()
631 if digest != PROCESS_RAW_SHA256:
632 message =
"supervisor process digest drifted"
633 _refuse_entry(message)
634 if module_name
in sys.modules:
635 message =
"supervisor process module name is already occupied"
636 _refuse_entry(message)
637 module = types.ModuleType(module_name)
638 namespace = module.__dict__
639 namespace[
"__file__"] = f
"/proc/self/fd/{descriptor}"
640 namespace[
"_RA8_SUPERVISOR_PROCESS_VERSION"] = 1
641 sys.modules[module_name] = module
643 compile(source, namespace[
"__file__"],
"exec"), namespace
645 grant = namespace.pop(
"_RA8_SUPERVISOR_PROCESS_VERSION",
None)
646 if grant != 1
or "_RA8_SUPERVISOR_PROCESS_VERSION" in namespace:
647 message =
"supervisor process load grant was not consumed"
648 _refuse_entry(message)
649 if hashlib.sha256(_read_process_source(descriptor)).hexdigest() != digest:
650 message =
"supervisor process changed while loading"
651 _refuse_entry(message)
652 return _validate_process_api(module_name, namespace, module)
654 if module
is not None and sys.modules.get(module_name)
is module:
655 del sys.modules[module_name]
659def _validate_process_api(
660 module_name: str, namespace: dict[str, object], module: types.ModuleType
661) -> tuple[object, ...]:
662 """Validate the exact process API and its digest-bound namespace."""
670 "_child_table_is_empty",
671 "_enable_child_subreaper",
673 api = tuple(namespace.get(name)
for name
in names)
674 classes, functions = api[:2], api[2:]
675 if not all(isinstance(value, type)
for value
in classes)
or not all(
676 isinstance(value, types.FunctionType)
for value
in functions
678 _refuse_entry(
"supervisor process API is incomplete")
680 value
for value
in vars(api[1]).values()
if isinstance(value, types.FunctionType)
682 escaped = any(value.__module__ != namespace[
"__name__"]
for value
in classes)
683 escaped = escaped
or any(value.__globals__
is not namespace
for value
in functions)
684 escaped = escaped
or any(value.__globals__
is not namespace
for value
in methods)
685 escaped = escaped
or sys.modules.get(module_name)
is not module
687 _refuse_entry(
"supervisor process API escaped its private namespace")
691def _install_process_api(api: tuple[object, ...]) ->
None:
692 """Install the exact authenticated process API before any case dispatch."""
693 if "_ra8_supervisor_process" in sys.modules:
694 message =
"supervisor process module residue remained after loading"
695 _refuse_entry(message)
696 global ProcessIdentity
698 global _bind_process, _child_table_is_empty, _direct_children
699 global _enable_child_subreaper, _group_members, _stat_group
707 _child_table_is_empty,
708 _enable_child_subreaper,
712def _wait_group_populated(group: int) -> bool:
713 """Wait for a controller and its payload to share one bound group."""
714 deadline = time.monotonic() + 2
715 while time.monotonic() < deadline:
716 members = _group_members(group)
717 if members
is not None and len(members) >= MIN_POPULATED_GROUP_MEMBERS:
719 time.sleep(POLL_SECONDS)
723def _wait_group_gone(group: int) -> bool:
724 """Wait a bounded interval for one controller group to disappear."""
725 deadline = time.monotonic() + DEADLINE_SECONDS
726 while time.monotonic() < deadline:
727 if _group_members(group) == set():
729 time.sleep(POLL_SECONDS)
733def _cleanup_retry_authorities() -> tuple[dict[str, object], object, object, object, object] | None:
734 """Bind process cleanup globals and the separate supervisor namespace."""
735 cleanup_method = vars(BoundGroup).get(
"cleanup")
736 if not isinstance(cleanup_method, types.FunctionType):
738 cleanup_globals = cleanup_method.__globals__
739 main_globals = globals()
740 if cleanup_globals
is main_globals:
743 cleanup_globals.get(
"_group_members"),
744 cleanup_globals.get(
"DEADLINE_SECONDS"),
745 main_globals.get(
"_group_members"),
746 main_globals.get(
"DEADLINE_SECONDS"),
748 if values[0]
is not _group_members
or values[1] != DEADLINE_SECONDS:
750 if values[2]
is not _group_members
or values[3] != DEADLINE_SECONDS:
752 return (cleanup_globals, *values)
755def _census_retry_probe(
756 supervisor: BoundGroup,
757 authorities: tuple[dict[str, object], object, object, object, object],
758 main_globals: dict[str, object],
759 original_killpg: Callable[[int, int],
None],
761 """Inject one census failure and verify that cleanup retains authority."""
762 cleanup_globals, original_members, original_deadline, _, _ = authorities
763 skipped_signal =
False
765 def fail_bound_census(group: int) -> set[int] |
None:
766 return None if group == supervisor.pid
else original_members(group)
768 def skip_first_group_kill(group: int, sent_signal: int) ->
None:
769 nonlocal skipped_signal
770 if group == supervisor.pid
and sent_signal == signal.SIGKILL
and not skipped_signal:
771 skipped_signal =
True
773 original_killpg(group, sent_signal)
775 main_globals[
"_group_members"], main_globals[
"DEADLINE_SECONDS"] = (
779 wrong_namespace_ignored = (
780 cleanup_globals[
"_group_members"]
is original_members
781 and cleanup_globals[
"DEADLINE_SECONDS"] == original_deadline
783 cleanup_globals[
"_group_members"], cleanup_globals[
"DEADLINE_SECONDS"] = (
787 os.killpg = skip_first_group_kill
788 first_cleanup = supervisor.cleanup()
789 retained_members = original_members(supervisor.pid)
792 and wrong_namespace_ignored
793 and not supervisor.reaped
795 and supervisor.entry_descriptor
is not None
796 and retained_members
is not None
797 and len(retained_members) >= MIN_POPULATED_GROUP_MEMBERS
801def _census_cleanup_retry_selftest(entry: str, root: Path) -> bool:
802 """Retain authority after failed census, then retry cleanup to completion."""
803 supervisor = BoundGroup()
805 authorities = _cleanup_retry_authorities()
806 if authorities
is None:
808 cleanup_globals, original_members, original_deadline, main_members, main_deadline = authorities
809 main_globals = globals()
810 original_killpg = os.killpg
812 if not supervisor.enable_subreaper():
814 launch = ControllerLaunch(
815 entry, root /
"supervisor-cleanup-retry.status", SELFTEST_WATCHDOG_TIMEOUT_SECONDS
817 supervisor.spawn(int(Path(__file__).name), launch)
818 if supervisor.pid
is None or supervisor.death_write
is None:
820 held_death = os.dup(supervisor.death_write)
821 if not _wait_group_populated(supervisor.pid):
823 retained = _census_retry_probe(
830 cleanup_globals[
"_group_members"], cleanup_globals[
"DEADLINE_SECONDS"] = (
834 main_globals[
"_group_members"], main_globals[
"DEADLINE_SECONDS"] = (
838 os.killpg = original_killpg
839 if held_death
is not None:
841 cleaned = supervisor.contain()
842 group_absent = supervisor.pid
is None or _wait_group_gone(supervisor.pid)
843 return retained
and cleaned
and supervisor.entry_descriptor
is None and group_absent
846def _public_supervision(request_argv: list[str]) -> int:
847 """Validate and run one public request after cases authentication."""
848 if len(request_argv) != SUPERVISOR_ARG_COUNT
or request_argv[5]
not in (
853 if not Path(
"/proc/self/stat").is_file():
855 request = SupervisorRequest(
857 Path(request_argv[2]),
858 Path(request_argv[3]),
859 Path(request_argv[4]),
862 root = request.bound.parent
863 receipts = (request.bound, request.outer, request.status)
864 if any(receipt.parent != root
or receipt.name
in (
"",
".",
"..")
for receipt
in receipts):
865 return PUBLIC_REFUSAL_STATUS
867 descriptor, identity = _open_suite_root_authority(root)
868 except (OSError, RuntimeError):
869 return PUBLIC_REFUSAL_STATUS
870 if f
"{identity[0]}:{identity[1]}" != request_argv[6]:
871 _close_suite_root_authority(descriptor, root, identity)
872 return PUBLIC_REFUSAL_STATUS
873 anchored = _anchored_root_path(descriptor)
874 anchored_request = SupervisorRequest(
876 anchored / request.bound.name,
877 anchored / request.outer.name,
878 anchored / request.status.name,
882 result = _supervise(anchored_request)
884 root_integrity = _close_suite_root_authority(descriptor, root, identity)
885 return result
if root_integrity
else INTEGRITY_REFUSAL_STATUS
888def _dispatch_authorized(
889 process_descriptor: int, cases_descriptor: int, request_argv: list[str]
891 """Dispatch one hidden or public mode after authenticating its cases FD."""
893 process_api = _load_process_api(process_descriptor)
894 _install_process_api(process_api)
895 cases_dispatch = _load_cases_dispatch(cases_descriptor)
896 except (OSError, RuntimeError, SyntaxError, UnicodeDecodeError):
897 return PUBLIC_REFUSAL_STATUS
898 hidden_status = _dispatch_controller(request_argv)
899 cases_status = cases_dispatch(request_argv)
900 if hidden_status
is None:
901 hidden_status = cases_status
902 if hidden_status
is not None:
904 return _public_supervision(request_argv)
907def main(argv: list[str]) -> int:
908 """Dispatch private controllers or requests with an authenticated cases FD."""
909 controller_status = _dispatch_controller(argv)
910 if controller_status
is not None:
911 return controller_status
913 len(argv) >= ROOT_SELFTEST_ARG_COUNT + 2
914 and argv[1] == PROCESS_ARG
915 and argv[2].isdigit()
916 and argv[3] == CASES_ARG
917 and argv[4].isdigit()
921 return _dispatch_authorized(int(argv[2]), int(argv[4]), [argv[0], *argv[5:]])
924if __name__ ==
"__main__":
925 raise SystemExit(
main(sys.argv))
void main(void)
The application entry point Reset_Handler hands control to.
#define min(x, y)
Untyped minimum shim used by the SOUP's buffer clamping.