3"""Authenticated entry and descriptor regressions for the image supervisor."""
5from __future__
import annotations
15from contextlib
import suppress
16from pathlib
import Path
25SUITE_ROOT_SUFFIX_LENGTH = 32
26STAT_SELFTEST_ARG_COUNT = 2
27TEST_PROCESS_GROUP = 42
32if globals().get(
"_RA8_SUPERVISOR_CASES_VERSION") != CASES_LOAD_VERSION:
33 message =
"supervisor cases module is source-only"
34 raise RuntimeError(message)
35MAIN_API = vars(__main__)
36DEADLINE_SECONDS = MAIN_API[
"DEADLINE_SECONDS"]
37ENTRY_MAX_BYTES = MAIN_API[
"ENTRY_MAX_BYTES"]
38HARDLINK_COUNT = MAIN_API[
"HARDLINK_COUNT"]
39INTEGRITY_REFUSAL_STATUS = MAIN_API[
"INTEGRITY_REFUSAL_STATUS"]
40POLL_SECONDS = MAIN_API[
"POLL_SECONDS"]
41PUBLIC_REFUSAL_STATUS = MAIN_API[
"PUBLIC_REFUSAL_STATUS"]
42RECEIPT_MODE = MAIN_API[
"RECEIPT_MODE"]
43RECEIPT_MAX_BYTES = MAIN_API[
"RECEIPT_MAX_BYTES"]
44SELFTEST_WATCHDOG_TIMEOUT_SECONDS = MAIN_API[
"SELFTEST_WATCHDOG_TIMEOUT_SECONDS"]
45STALL_STATUS = MAIN_API[
"STALL_STATUS"]
46BoundGroup = MAIN_API[
"BoundGroup"]
47ControllerLaunch = MAIN_API[
"ControllerLaunch"]
48ProcessIdentity = MAIN_API[
"ProcessIdentity"]
49SupervisionControls = MAIN_API[
"SupervisionControls"]
50SupervisorRequest = MAIN_API[
"SupervisorRequest"]
51_bind_process = MAIN_API[
"_bind_process"]
52_close_suite_root_authority = MAIN_API[
"_close_suite_root_authority"]
53_controller = MAIN_API[
"_controller"]
54_group_members = MAIN_API[
"_group_members"]
55_stat_group = MAIN_API[
"_stat_group"]
56_wait_group_populated = MAIN_API[
"_wait_group_populated"]
57_wait_group_gone = MAIN_API[
"_wait_group_gone"]
58_census_cleanup_retry_selftest = MAIN_API[
"_census_cleanup_retry_selftest"]
59_open_entry_authority = MAIN_API[
"_open_entry_authority"]
60_open_suite_root_authority = MAIN_API[
"_open_suite_root_authority"]
61_supervise = MAIN_API[
"_supervise"]
62_write_exclusive = MAIN_API[
"_write_exclusive"]
63_write_exact = MAIN_API[
"_write_exact"]
64_anchored_root_path = MAIN_API[
"_anchored_root_path"]
65SUPERVISOR_PROGRAM = __main__.__file__
68def _bind_group_leader(pid: int) -> ProcessIdentity |
None:
69 """Bind one live session/group leader before an emergency fallback."""
70 authority = _bind_process(pid)
71 if authority
is None or authority.group != pid
or authority.session != pid:
76def _wait_direct_child_status(child: int) -> int |
None:
77 """Wait boundedly and reap one exact direct child without releasing its PID early."""
78 deadline = time.monotonic() + DEADLINE_SECONDS
79 while time.monotonic() < deadline:
80 result = os.waitid(os.P_PID, child, os.WEXITED | os.WNOHANG | os.WNOWAIT)
81 if result
is not None:
82 _, raw_status = os.waitpid(child, 0)
83 return os.waitstatus_to_exitcode(raw_status)
84 time.sleep(POLL_SECONDS)
88def _identity_is_current(authority: ProcessIdentity) -> bool:
89 """Revalidate one unreaped leader immediately before emergency cleanup."""
90 return _bind_process(authority.pid) == authority
93def _emergency_group_cleanup(authority: ProcessIdentity) -> bool:
94 """Remove a failed watchdog group only while its exact leader stays bound."""
95 if _wait_group_gone(authority.group):
97 if not _identity_is_current(authority):
99 with suppress(ProcessLookupError):
100 os.killpg(authority.group, signal.SIGKILL)
101 return _wait_group_gone(authority.group)
104def _receive_controller_identity(descriptor: int) -> ProcessIdentity |
None:
105 """Bind the controller named by one private runner pipe."""
106 ready, _, _ = select.select((descriptor,), (), (), 2)
109 value = os.read(descriptor, 32).strip()
110 if not value.isdigit():
112 return _bind_group_leader(int(value))
115def _inject_observation_failure() -> None:
116 """Raise the controlled observation error used by the cleanup direction."""
117 message =
"injected controller observation failure"
118 raise OSError(message)
121def _suite_root_is_safe(root: Path, expected_identity: str) -> bool:
122 """Bind one direct canonical-/tmp suite root before any case side effect."""
124 canonical = CANONICAL_TMP.resolve(strict=
True)
125 metadata = root.lstat()
126 suffix = root.name.removeprefix(
"ra8-devcontainer-image-selftest.")
127 identity = f
"{metadata.st_dev}:{metadata.st_ino}"
128 resolved = root.resolve(strict=
True)
133 and root.parent == canonical
135 and len(suffix) == SUITE_ROOT_SUFFIX_LENGTH
136 and all(character
in "0123456789abcdef" for character
in suffix)
137 and stat.S_ISDIR(metadata.st_mode)
138 and metadata.st_uid == os.getuid()
139 and metadata.st_gid == os.getgid()
140 and stat.S_IMODE(metadata.st_mode) == PRIVATE_MODE
141 and identity == expected_identity
145def _entry_belongs_to_root(entry: Path, root: Path) -> bool:
146 """Require one private mode-0700 regular payload directly under its suite."""
148 metadata = entry.lstat()
153 and entry.parent == root
154 and 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) == PRIVATE_MODE
162def _bound_phase_matches(bound: Path, authority: ProcessIdentity, phase: str) -> bool:
163 """Prove the requested publication boundary before killing the runner."""
164 deadline = time.monotonic() + 2
165 expected = b
"" if phase ==
"pre-bound" else f
"{authority.pid}\n".encode(
"ascii")
166 while time.monotonic() < deadline:
168 value = bound.read_bytes()
171 if value == expected:
173 if phase ==
"pre-bound" or value:
175 time.sleep(POLL_SECONDS)
179def _supervisor_sigkill_case(entry: str, root: Path, phase: str) -> bool:
180 """Prove pipe EOF removes a controller group after supervisor SIGKILL."""
181 bound = root / f
"supervisor-sigkill-{phase}.bound"
182 outer = root / f
"supervisor-sigkill-{phase}.outer"
183 status = root / f
"supervisor-sigkill-{phase}.status"
184 descriptor = os.open(
186 os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW,
190 read_descriptor, write_descriptor = os.pipe2(os.O_CLOEXEC)
193 os.close(read_descriptor)
194 request = SupervisorRequest(entry, bound, outer, status,
"normal")
195 controls = SupervisionControls(
196 test_descriptor=write_descriptor,
197 pause_before_bound=phase ==
"pre-bound",
199 os._exit(_supervise(request, controls))
200 os.close(write_descriptor)
201 authority: ProcessIdentity |
None =
None
202 runner_reaped =
False
203 watchdog_succeeded =
False
205 authority = _receive_controller_identity(read_descriptor)
206 if authority
is not None and _bound_phase_matches(bound, authority, phase):
207 os.kill(runner, signal.SIGKILL)
208 os.waitpid(runner, 0)
210 watchdog_succeeded = _wait_group_gone(authority.group)
212 os.close(read_descriptor)
213 if not runner_reaped:
214 with suppress(ProcessLookupError):
215 os.kill(runner, signal.SIGKILL)
216 with suppress(ChildProcessError):
217 os.waitpid(runner, 0)
218 if authority
is not None and not watchdog_succeeded:
219 _emergency_group_cleanup(authority)
220 return watchdog_succeeded
223def _supervisor_sigkill_selftest(entry: str, root: Path) -> int:
224 """Exercise the parent-death watchdog before and after public binding."""
225 phases = (
"pre-bound",
"post-bound")
226 return 0
if all(_supervisor_sigkill_case(entry, root, phase)
for phase
in phases)
else 1
229def _hardlink_bound_selftest(entry: str, root: Path) -> int:
230 """Prove hardlink refusal preserves data and leaves no controller group."""
231 victim = root /
"supervisor-hardlink-bound.victim"
232 bound = root /
"supervisor-hardlink-bound.bound"
233 outer = root /
"supervisor-hardlink-bound.outer"
234 status = root /
"supervisor-hardlink-bound.status"
235 _write_exclusive(victim,
"preserve\n")
236 os.link(victim, bound, follow_symlinks=
False)
237 read_descriptor, write_descriptor = os.pipe2(os.O_CLOEXEC)
240 os.close(read_descriptor)
241 request = SupervisorRequest(entry, bound, outer, status,
"normal")
242 controls = SupervisionControls(test_descriptor=write_descriptor)
243 os._exit(_supervise(request, controls))
244 os.close(write_descriptor)
245 authority: ProcessIdentity |
None =
None
247 runner_status: int |
None =
None
248 hardlink_runner_reaped =
False
250 authority = _receive_controller_identity(read_descriptor)
251 if authority
is not None:
252 group_absent = _wait_group_gone(authority.group)
253 runner_status = _wait_direct_child_status(runner)
254 hardlink_runner_reaped = runner_status
is not None
256 os.close(read_descriptor)
257 if not hardlink_runner_reaped:
258 with suppress(ProcessLookupError):
259 os.kill(runner, signal.SIGKILL)
260 with suppress(ChildProcessError):
261 os.waitpid(runner, 0)
262 if authority
is not None and not group_absent:
263 _emergency_group_cleanup(authority)
264 preserved = victim.read_bytes() == b
"preserve\n" and victim.stat().st_nlink == HARDLINK_COUNT
265 return 0
if group_absent
and runner_status == PUBLIC_REFUSAL_STATUS
and preserved
else 1
268def _watchdog_expiry_runner(
271 identity_descriptor: int,
272 proof_descriptor: int,
273 release_descriptor: int,
275 """Hold supervisor ownership until the observing parent releases this runner."""
276 supervisor = BoundGroup()
277 source_descriptor = int(Path(SUPERVISOR_PROGRAM).name)
279 if not supervisor.enable_subreaper():
280 return INTEGRITY_REFUSAL_STATUS
281 launch = ControllerLaunch(entry, status, SELFTEST_WATCHDOG_TIMEOUT_SECONDS)
282 supervisor.spawn(source_descriptor, launch)
283 if supervisor.pid
is None:
284 return INTEGRITY_REFUSAL_STATUS
287 f
"{supervisor.pid}\n".encode(
"ascii"),
290 deadline = time.monotonic() + DEADLINE_SECONDS
292 while time.monotonic() < deadline:
293 result = os.waitid(os.P_PID, supervisor.pid, os.WEXITED | os.WNOHANG | os.WNOWAIT)
294 if result
is not None:
295 killed = result.si_code == os.CLD_KILLED
and result.si_status == signal.SIGKILL
297 time.sleep(POLL_SECONDS)
298 contained = supervisor.contain()
301 b
"K\n" if killed
and contained
else b
"F\n",
304 ready, _, _ = select.select((release_descriptor,), (), (), DEADLINE_SECONDS * 2)
305 return STALL_STATUS
if ready
else INTEGRITY_REFUSAL_STATUS
307 os.close(identity_descriptor)
308 os.close(proof_descriptor)
309 os.close(release_descriptor)
313def _watchdog_expiry_selftest(entry: str, root: Path) -> int:
314 """Prove a live but stalled supervisor cannot retain its controller group."""
315 status = root /
"supervisor-watchdog-expiry.status"
316 read_descriptor, write_descriptor = os.pipe2(os.O_CLOEXEC)
317 proof_read, proof_write = os.pipe2(os.O_CLOEXEC)
318 release_read, release_write = os.pipe2(os.O_CLOEXEC)
321 os.close(read_descriptor)
323 os.close(release_write)
324 result = _watchdog_expiry_runner(entry, status, write_descriptor, proof_write, release_read)
326 os.close(write_descriptor)
327 os.close(proof_write)
328 os.close(release_read)
329 authority: ProcessIdentity |
None =
None
330 watchdog_succeeded =
False
331 runner_reaped =
False
333 authority = _receive_controller_identity(read_descriptor)
334 if authority
is not None:
335 ready, _, _ = select.select((proof_read,), (), (), DEADLINE_SECONDS)
336 killed_receipt = ready
and os.read(proof_read, 2) == b
"K\n"
337 members = _group_members(authority.group)
339 os.waitid(os.P_PID, runner, os.WEXITED | os.WNOHANG | os.WNOWAIT)
is None
341 pre_release_proven = killed_receipt
and members
is not None
342 pre_release_proven = pre_release_proven
and members <= {authority.pid}
343 if pre_release_proven
and runner_is_live:
344 os.close(release_write)
346 runner_status = _wait_direct_child_status(runner)
347 runner_reaped = runner_status
is not None
348 expected = runner_status == STALL_STATUS
349 watchdog_succeeded = expected
and _wait_group_gone(authority.group)
351 os.close(read_descriptor)
353 if release_write >= 0:
354 os.close(release_write)
355 if not runner_reaped:
356 with suppress(ProcessLookupError):
357 os.kill(runner, signal.SIGKILL)
358 with suppress(ChildProcessError):
359 os.waitpid(runner, 0)
360 if authority
is not None and not watchdog_succeeded:
361 _emergency_group_cleanup(authority)
362 return 0
if watchdog_succeeded
else 1
365def _missing_entry_selftest(root: Path) -> int:
366 """Prove payload exec failure is published and its group is removed."""
367 bound = root /
"supervisor-missing-entry.bound"
368 outer = root /
"supervisor-missing-entry.outer"
369 status = root /
"supervisor-missing-entry.status"
370 descriptor = os.open(bound, os.O_WRONLY | os.O_CREAT | os.O_EXCL, RECEIPT_MODE)
372 request = SupervisorRequest(str(root /
"absent-entry"), bound, outer, status,
"normal")
373 controls = SupervisionControls(missing_entry_selftest=
True)
374 result = _supervise(request, controls)
375 bound_value = bound.read_bytes().strip()
376 if not bound_value.isdigit():
378 group = int(bound_value)
379 exec_failure_proven = result == PUBLIC_REFUSAL_STATUS
and status.read_bytes() == b
"127\n"
380 return 0
if exec_failure_proven
and _wait_group_gone(group)
else 1
383def _write_entry_fixture(path: Path, body: str) ->
None:
384 """Publish one private executable used only by entry-authority tests."""
385 _write_exclusive(path, body)
389def _entry_mutation_case(root: Path, mode: str) -> bool:
390 """Prove replacement uses the opened inode and in-place change is detected."""
391 entry = root / f
"entry-{mode}.sh"
392 saved = root / f
"entry-{mode}.saved"
393 marker = root / f
"entry-{mode}.forged"
394 bound = root / f
"entry-{mode}.bound"
395 outer = root / f
"entry-{mode}.outer"
396 status = root / f
"entry-{mode}.status"
397 _write_entry_fixture(entry,
"#!/bin/bash\nexit 1\n")
398 _write_exclusive(bound,
"")
399 marker_path = marker.resolve(strict=
False)
400 forged = f
"#!/bin/bash\nprintf forged >{marker_path}\nexit 0\n"
402 def mutate() -> None:
403 if mode
in (
"replace",
"pre-open-replace"):
405 _write_entry_fixture(entry, forged)
406 elif mode ==
"grow-in-place":
407 os.truncate(entry, ENTRY_MAX_BYTES + 1)
409 entry.write_text(forged, encoding=
"ascii")
412 request = SupervisorRequest(str(entry), bound, outer, status,
"normal")
414 SupervisionControls(pre_open_mutator=mutate)
415 if mode ==
"pre-open-replace"
416 else SupervisionControls(entry_mutator=mutate)
418 result = _supervise(request, controls)
419 if mode ==
"pre-open-replace":
420 return result == PUBLIC_REFUSAL_STATUS
and not marker.exists()
421 if mode
in (
"replace",
"grow-in-place"):
422 return result == INTEGRITY_REFUSAL_STATUS
and not marker.exists()
423 return result == INTEGRITY_REFUSAL_STATUS
and marker.read_bytes() == b
"forged"
426def _entry_refusal_case(root: Path, mode: str) -> bool:
427 """Prove unsafe path and metadata shapes fail before controller spawn."""
428 entry = root / f
"entry-refusal-{mode}.sh"
429 target = root / f
"entry-refusal-{mode}.target"
430 bound = root / f
"entry-refusal-{mode}.bound"
431 _write_entry_fixture(target,
"#!/bin/bash\nexit 1\n")
432 if mode ==
"symlink":
433 entry.symlink_to(target.name)
434 elif mode ==
"hardlink":
435 os.link(target, entry, follow_symlinks=
False)
440 elif mode ==
"owner":
441 os.chown(entry, 1, os.getgid())
442 elif mode ==
"group":
443 os.chown(entry, os.getuid(), 1)
445 entry.write_bytes(b
"")
446 elif mode ==
"oversize":
447 os.truncate(entry, ENTRY_MAX_BYTES + 1)
448 _write_exclusive(bound,
"")
449 request = SupervisorRequest(
452 root / f
"entry-refusal-{mode}.outer",
453 root / f
"entry-refusal-{mode}.status",
456 return _supervise(request) == PUBLIC_REFUSAL_STATUS
and bound.read_bytes() == b
""
459def _root_argument_directions(root: Path, identity: str) -> bool:
460 """Exercise safe root refusal directions without changing root metadata."""
462 _suite_root_is_safe(root, identity)
463 and not _suite_root_is_safe(Path(
"/"), identity)
464 and not _suite_root_is_safe(Path(root.name), identity)
465 and not _suite_root_is_safe(root,
"0:0")
469def _entry_binding_selftest(root: Path, original_root: Path, identity: str) -> int:
470 """Exercise both live entry mutations and every rejected metadata shape."""
471 mutation_modes = (
"pre-open-replace",
"replace",
"in-place",
"grow-in-place")
472 mutations = all(_entry_mutation_case(root, mode)
for mode
in mutation_modes)
473 refusal_modes = [
"symlink",
"hardlink",
"mode",
"zero",
"oversize"]
475 refusal_modes.extend((
"owner",
"group"))
476 refusals = all(_entry_refusal_case(root, mode)
for mode
in refusal_modes)
477 roots = _root_argument_directions(original_root, identity)
478 return 0
if roots
and mutations
and refusals
else 1
481def _controller_kill_observed(child: subprocess.Popen[bytes]) -> bool:
482 """Observe one controller terminal while its leader remains unreaped."""
483 deadline = time.monotonic() + DEADLINE_SECONDS
484 while time.monotonic() < deadline:
485 result = os.waitid(os.P_PID, child.pid, os.WEXITED | os.WNOHANG | os.WNOWAIT)
486 if result
is not None:
487 return result.si_code == os.CLD_KILLED
and result.si_status == signal.SIGKILL
488 time.sleep(POLL_SECONDS)
492def _wait_forked_group_terminal(process: int) -> bool:
493 """Retain one forked group leader unreaped through its absence proof."""
494 deadline = time.monotonic() + DEADLINE_SECONDS
495 while time.monotonic() < deadline:
496 result = os.waitid(os.P_PID, process, os.WEXITED | os.WNOHANG | os.WNOWAIT)
497 if result
is not None:
498 members = _group_members(process)
499 return members
is not None and members <= {process}
500 time.sleep(POLL_SECONDS)
504def _controller_isolation_selftest(root: Path, identity: str) -> int:
505 """Prove a raw non-session-leader controller refuses before any effect."""
506 status = root /
"supervisor-controller-isolation.status"
507 identity_read, identity_write = os.pipe2(os.O_CLOEXEC)
508 result_read, result_write = os.pipe2(os.O_CLOEXEC)
511 os.close(identity_read)
512 os.close(result_read)
516 f
"{os.getpid()}\n".encode(
"ascii"),
519 contender = os.fork()
521 root_authority = (int(root.name), identity)
522 os._exit(_controller(
"99", status, CLOSED_DESCRIPTOR, root_authority, 1.0))
523 _, raw_status = os.waitpid(contender, 0)
526 f
"{os.waitstatus_to_exitcode(raw_status)}\n".encode(
"ascii"),
530 os.close(identity_write)
531 os.close(result_write)
532 authority: ProcessIdentity |
None =
None
533 broker_reaped =
False
537 authority = _receive_controller_identity(identity_read)
538 ready, _, _ = select.select((result_read,), (), (), DEADLINE_SECONDS)
540 refusal = os.read(result_read, 16).strip()
541 terminal = _wait_forked_group_terminal(broker)
543 os.waitpid(broker, 0)
546 authority
is not None
550 and not status.exists()
552 return 0
if safe
else 1
554 os.close(identity_read)
555 os.close(result_read)
556 if not broker_reaped:
557 if authority
is not None and _identity_is_current(authority):
558 with suppress(ProcessLookupError):
559 os.killpg(authority.group, signal.SIGKILL)
560 _wait_forked_group_terminal(broker)
561 with suppress(ChildProcessError):
562 os.waitpid(broker, 0)
565def _refused_controller_launch(root_descriptor: int, identity: str, status: Path) -> bool:
566 """Run one isolated raw controller expected to refuse before forking."""
567 source_descriptor = int(Path(SUPERVISOR_PROGRAM).name)
568 child = subprocess.Popen(
578 str(CLOSED_DESCRIPTOR),
579 str(root_descriptor),
581 str(SELFTEST_WATCHDOG_TIMEOUT_SECONDS),
583 pass_fds=(source_descriptor, root_descriptor),
584 start_new_session=
True,
587 result = child.wait(timeout=DEADLINE_SECONDS)
588 except subprocess.TimeoutExpired:
589 os.killpg(child.pid, signal.SIGKILL)
590 child.wait(timeout=DEADLINE_SECONDS)
592 return result == USAGE_STATUS
and not status.exists()
595def _controller_root_refusal_selftest(root: Path) -> bool:
596 """Refuse wrong identity and non-suite directory FDs before effects."""
597 root_descriptor = int(root.name)
598 wrong = _refused_controller_launch(
599 root_descriptor,
"0:0", root /
"controller-wrong-identity.status"
601 sibling = root /
"controller-sibling"
602 sibling.mkdir(mode=PRIVATE_MODE)
603 descriptor = os.open(sibling, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
605 metadata = os.fstat(descriptor)
606 sibling_identity = f
"{metadata.st_dev}:{metadata.st_ino}"
607 sibling_root = _anchored_root_path(descriptor)
608 refused = _refused_controller_launch(
609 descriptor, sibling_identity, sibling_root /
"controller-sibling.status"
614 return wrong
and refused
617def _reap_cleanup_retry_selftest(entry: str, root: Path) -> bool:
618 """Retain a terminal leader when its first exact reap fails, then retry."""
619 supervisor = BoundGroup()
620 original_reap = vars(BoundGroup)[
"_reap"]
624 def fail_reap(_authority: BoundGroup) -> bool:
628 if not supervisor.enable_subreaper():
630 launch = ControllerLaunch(
631 entry, root /
"supervisor-reap-retry.status", SELFTEST_WATCHDOG_TIMEOUT_SECONDS
633 supervisor.spawn(int(Path(SUPERVISOR_PROGRAM).name), launch)
634 if supervisor.pid
is not None and _wait_group_populated(supervisor.pid):
635 type.__setattr__(BoundGroup,
"_reap", fail_reap)
636 first_cleanup = supervisor.cleanup()
639 and not supervisor.reaped
640 and not supervisor.cleaning
641 and supervisor.entry_descriptor
is not None
644 type.__setattr__(BoundGroup,
"_reap", original_reap)
645 cleaned = supervisor.contain()
646 group_absent = supervisor.pid
is None or _wait_group_gone(supervisor.pid)
647 return retained
and cleaned
and supervisor.entry_descriptor
is None and group_absent
650def _cleanup_retry_selftest(entry: str, root: Path) -> int:
651 """Exercise independent census and reap retry directions."""
652 census = _census_cleanup_retry_selftest(entry, root)
653 reaping = _reap_cleanup_retry_selftest(entry, root)
654 writes = _receipt_write_selftest()
655 permanent = _permanent_containment_failure_selftest()
656 return 0
if census
and reaping
and writes
and permanent
else 1
659def _closed_controller_command(
660 entry_authority: str,
662 death_descriptor: int,
663 root_descriptor: int,
666 """Build the fixed controller command used by closed-descriptor cases."""
676 str(death_descriptor),
677 str(root_descriptor),
679 str(SELFTEST_WATCHDOG_TIMEOUT_SECONDS),
683def _closed_controller_descriptor_selftest(entry: str, root: Path, mode: str) -> int:
684 """Prove invalid entry/death descriptors cannot bypass group cleanup."""
685 status = root / f
"supervisor-closed-{mode}.status"
686 source_descriptor = int(Path(SUPERVISOR_PROGRAM).name)
687 root_descriptor = int(root.name)
688 root_metadata = os.fstat(root_descriptor)
689 root_identity = f
"{root_metadata.st_dev}:{root_metadata.st_ino}"
690 inherited = [source_descriptor, root_descriptor]
691 supervisor = BoundGroup()
692 death_descriptor: int |
None = CLOSED_DESCRIPTOR
693 death_write: int |
None =
None
694 entry_authority =
"98"
695 observation_injected =
False
697 if not supervisor.enable_subreaper():
699 if mode
in (
"death",
"observation"):
700 descriptor, identity, digest = _open_entry_authority(entry)
701 supervisor.entry_descriptor = descriptor
702 supervisor.entry_path = entry
703 supervisor.entry_identity = identity
704 supervisor.entry_digest = digest
705 inherited.append(descriptor)
706 entry_authority = str(descriptor)
708 death_descriptor, death_write = os.pipe2(os.O_CLOEXEC)
709 inherited.append(death_descriptor)
710 command = _closed_controller_command(
711 entry_authority, status, death_descriptor, root_descriptor, root_identity
713 child = subprocess.Popen(
715 pass_fds=tuple(inherited),
716 start_new_session=
True,
718 supervisor.bind_spawned_child(child)
719 if mode ==
"observation":
720 observation_injected =
True
721 _inject_observation_failure()
722 if death_write
is not None:
723 os.close(death_write)
724 os.close(death_descriptor)
725 death_write, death_descriptor =
None,
None
726 observed = _controller_kill_observed(child)
727 cleaned = supervisor.cleanup()
729 succeeded = observation_injected
and supervisor.pid
is not None
730 return 0
if succeeded
and supervisor.contain()
else 1
732 if mode ==
"observation":
734 return 0
if observed
and cleaned
and child.returncode == -signal.SIGKILL
else 1
736 for descriptor
in (death_write, death_descriptor):
737 if descriptor
is not None and descriptor != CLOSED_DESCRIPTOR:
738 with suppress(OSError):
743def _validated_case_paths(
744 argv: list[str], entry_modes: set[str], root_modes: set[str]
745) -> tuple[Path |
None, Path |
None, int |
None]:
746 """Validate one case root and optional entry before any side effect."""
747 mode = argv[1]
if len(argv) > 1
else ""
748 entry: Path |
None =
None
749 root: Path |
None =
None
750 error_status: int |
None =
None
751 if mode
in entry_modes:
752 if len(argv) != HIDDEN_ARG_COUNT:
755 entry, root = Path(argv[2]), Path(argv[3])
756 if not _suite_root_is_safe(root, argv[4])
or not _entry_belongs_to_root(entry, root):
758 elif mode
in root_modes:
759 if len(argv) != ROOT_ARG_COUNT:
763 if not _suite_root_is_safe(root, argv[3]):
765 return entry, root, error_status
768def _run_supervisor_case(
775 """Run one already validated supervisor regression."""
779 "--selftest-parent-death",
780 "--selftest-watchdog-expiry",
781 "--selftest-hardlink-bound",
782 "--selftest-closed-death-fd",
783 "--selftest-closed-entry-fd",
784 "--selftest-observation-failure",
785 "--selftest-cleanup-retry",
791 if mode ==
"--selftest-parent-death":
792 status = _supervisor_sigkill_selftest(str(entry), root)
793 elif mode ==
"--selftest-watchdog-expiry":
794 status = _watchdog_expiry_selftest(str(entry), root)
795 elif mode ==
"--selftest-hardlink-bound":
796 status = _hardlink_bound_selftest(str(entry), root)
797 elif mode ==
"--selftest-closed-death-fd":
798 status = _closed_controller_descriptor_selftest(str(entry), root,
"death")
799 elif mode ==
"--selftest-closed-entry-fd":
800 status = _closed_controller_descriptor_selftest(str(entry), root,
"entry")
801 elif mode ==
"--selftest-observation-failure":
802 status = _closed_controller_descriptor_selftest(str(entry), root,
"observation")
803 elif mode ==
"--selftest-cleanup-retry":
804 status = _cleanup_retry_selftest(str(entry), root)
805 elif mode ==
"--selftest-missing-entry":
806 status = _missing_entry_selftest(root)
807 elif mode ==
"--selftest-entry-binding":
808 status = _entry_binding_selftest(root, original_root, root_identity)
809 elif mode ==
"--selftest-controller-isolation":
810 isolated = _controller_isolation_selftest(root, root_identity) == 0
811 root_refused = _controller_root_refusal_selftest(root)
812 status = 0
if isolated
and root_refused
else 1
816def _open_validated_root(root: Path, expected_identity: str) -> tuple[int, tuple[int, int]] |
None:
817 """Open the exact caller-bound root or refuse before case effects."""
819 descriptor, opened_identity = _open_suite_root_authority(root)
820 except (OSError, RuntimeError):
822 if f
"{opened_identity[0]}:{opened_identity[1]}" != expected_identity:
823 _close_suite_root_authority(descriptor, root, opened_identity)
825 return descriptor, opened_identity
828def _nonroot_case_status(argv: list[str], mode: str) -> int |
None:
829 """Run the authenticated stat-parser case that requires no suite root."""
830 if len(argv) != STAT_SELFTEST_ARG_COUNT
or mode !=
"--selftest-stat-parser":
832 raw = b
"1 (non-ascii-\xff) S 0 42 42 " + (b
"0 " * 15) + b
"99"
833 return 0
if _stat_group(raw) == TEST_PROCESS_GROUP
else 1
836def dispatch_supervisor_cases(argv: list[str]) -> int |
None:
837 """Dispatch one authenticated entry or descriptor regression."""
839 "--selftest-parent-death",
840 "--selftest-watchdog-expiry",
841 "--selftest-hardlink-bound",
842 "--selftest-closed-death-fd",
843 "--selftest-closed-entry-fd",
844 "--selftest-observation-failure",
845 "--selftest-cleanup-retry",
848 "--selftest-missing-entry",
849 "--selftest-entry-binding",
850 "--selftest-controller-isolation",
852 mode = argv[1]
if len(argv) > 1
else ""
853 entry, root, error_status = _validated_case_paths(argv, entry_modes, root_modes)
854 if error_status
is not None:
856 if mode
in entry_modes
and (entry
is None or root
is None):
858 if mode
in root_modes
and root
is None:
861 return _nonroot_case_status(argv, mode)
862 expected_identity = argv[4]
if mode
in entry_modes
else argv[3]
863 root_authority = _open_validated_root(root, expected_identity)
864 if root_authority
is None:
866 descriptor, opened_identity = root_authority
867 anchored_root = _anchored_root_path(descriptor)
868 anchored_entry = anchored_root / entry.name
if entry
is not None else None
872 status = _run_supervisor_case(
873 mode, anchored_entry, anchored_root, root, expected_identity
875 except (OSError, RuntimeError, TimeoutError, subprocess.SubprocessError):
877 status = PUBLIC_REFUSAL_STATUS
879 root_integrity = _close_suite_root_authority(descriptor, root, opened_identity)
880 if not root_integrity:
881 status = INTEGRITY_REFUSAL_STATUS
883 status = PUBLIC_REFUSAL_STATUS
887def _receipt_write_selftest() -> bool:
888 """Prove exact receipt writes complete and reject impossible progress."""
889 original_write = os.write
891 def scripted(actions: tuple[str, ...], payload: bytes, expect_success: bool) -> bool:
892 read_descriptor, write_descriptor = os.pipe2(os.O_CLOEXEC)
895 def fake_write(descriptor: int, value: bytes) -> int:
896 nonlocal action_index
897 action = actions[
min(action_index, len(actions) - 1)]
899 if action ==
"eintr":
900 raise InterruptedError(errno.EINTR,
"injected interruption")
903 if action ==
"partial":
904 return original_write(descriptor, value[:1])
905 return original_write(descriptor, value)
907 os.write = fake_write
911 _write_exact(write_descriptor, payload, RECEIPT_MAX_BYTES)
913 except (OSError, ValueError):
915 if succeeded != expect_success:
918 return os.read(read_descriptor, len(payload)) == payload
921 os.write = original_write
922 os.close(read_descriptor)
923 os.close(write_descriptor)
926 partial = scripted((
"partial",), payload, expect_success=
True)
927 interrupted = scripted((
"eintr",
"partial",
"eintr",
"partial"), payload, expect_success=
True)
928 zero = scripted((
"zero",), payload, expect_success=
False)
929 excess_eintr = scripted((
"eintr",), payload, expect_success=
False)
930 return partial
and interrupted
and zero
and excess_eintr
933def _permanent_containment_observer(mode: str, terminate_early: bool =
False) -> bool:
934 """Prove contain remains fail-stopped under permanent census or reap failure."""
935 process_globals = BoundGroup.cleanup.__globals__
939 time.sleep(POLL_SECONDS * 10)
941 supervisor = BoundGroup()
942 supervisor.children_contained =
False
944 supervisor.subreaper =
True
945 process_globals[
"_direct_children"] =
lambda:
None
947 supervisor.pid = 999999
948 supervisor.child = object()
949 supervisor.leader_terminal =
True
950 type.__setattr__(BoundGroup,
"_reap",
lambda _authority:
False)
953 deadline = time.monotonic() + 0.25
956 while time.monotonic() < deadline:
957 waited, _status = os.waitpid(observer, os.WNOHANG)
961 time.sleep(POLL_SECONDS)
964 with suppress(ProcessLookupError):
965 os.kill(observer, signal.SIGKILL)
966 with suppress(ChildProcessError):
967 os.waitpid(observer, 0)
971def _permanent_containment_failure_selftest() -> bool:
972 """Keep permanent cleanup uncertainty fail-stopped until external containment."""
973 census = _permanent_containment_observer(
"census")
974 reaping = _permanent_containment_observer(
"reap")
975 early_terminal =
not _permanent_containment_observer(
"census", terminate_early=
True)
976 return census
and reaping
and early_terminal
#define min(x, y)
Untyped minimum shim used by the SOUP's buffer clamping.