This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""Validate the fail-closed Phase-1.0R launch-context analysis."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
from typing import Any
|
||||
|
||||
|
||||
PHASE = "PHASE_1_0R_LAUNCH_CONTEXT_ANALYSIS"
|
||||
STATUS = "NO_SOURCE_PROVEN_LAUNCH_CONTEXT_FIX_TARGET_CHANGE_BLOCKED"
|
||||
RA_SOURCE = "12cf1d783c41eb303987e49a5a920805a59ef7a4"
|
||||
RA_HEAD = "606909706f91d7213751c245081333f56c2cce89"
|
||||
SDK_COMMIT = "d2e2e585740362976a39fdd5ccf390f199a7bc37"
|
||||
SDL_COMMIT = "0baf4ac49382b537ba449901b5b6d0d189bb1fbb"
|
||||
ELFLDR_COMMIT = "197623058f509eddde18868dafcb92fdcac66464"
|
||||
MANAGER_COMMIT = "e23d94ff91233aa770e2342800c1467875bdef44"
|
||||
PACBREW_COMMIT = "c2abcfcb60f569128abd0e8e70ad03a67bee5ea7"
|
||||
AUTHORIZATION_FIELDS = (
|
||||
"target_build_authorized", "ps5_connection_authorized",
|
||||
"device_transfer_authorized", "device_execution_authorized",
|
||||
"result_receive_authorized", "installation_authorized",
|
||||
"autoload_authorized", "device_write_authorized", "automatic_retry",
|
||||
)
|
||||
|
||||
|
||||
def load_json(path: Path) -> dict[str, Any]:
|
||||
value = json.loads(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(value, dict):
|
||||
raise ValueError("launch-context manifest is not an object")
|
||||
return value
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def git(root: Path, *args: str) -> str:
|
||||
result = subprocess.run(
|
||||
["git", *args], cwd=root, capture_output=True, text=True, check=False)
|
||||
if result.returncode:
|
||||
raise RuntimeError(result.stderr.strip() or "git failed")
|
||||
return result.stdout
|
||||
|
||||
|
||||
def all_false(record: dict[str, Any], fields: tuple[str, ...]) -> bool:
|
||||
return all(record.get(field) is False for field in fields)
|
||||
|
||||
|
||||
def source_identities_are_exact(record: dict[str, Any]) -> bool:
|
||||
return record == {
|
||||
"retroarch_artifact_source_commit": RA_SOURCE,
|
||||
"retroarch_inspected_head": RA_HEAD,
|
||||
"sdk_commit": SDK_COMMIT,
|
||||
"sdl_commit": SDL_COMMIT,
|
||||
"hardened_elfldr_commit": ELFLDR_COMMIT,
|
||||
"controlled_payload_manager_commit": MANAGER_COMMIT,
|
||||
"pacbrew_commit": PACBREW_COMMIT,
|
||||
"lakesnes_reference_commit":
|
||||
"a2db690123649c7ffbc68a663af31efb3a41bf3f",
|
||||
}
|
||||
|
||||
|
||||
def sdl2main_is_lifecycle_only(record: dict[str, Any]) -> bool:
|
||||
return record == {
|
||||
"linked_by_exact_retroarch_artifact": False,
|
||||
"calls_hide_splash_before_sdl_main": True,
|
||||
"calls_load_exec_exit_after_sdl_main_returns": True,
|
||||
"adds_application_registration": False,
|
||||
"adds_title_identity": False,
|
||||
"adds_lnc_setup": False,
|
||||
"adds_videoout_ownership_setup": False,
|
||||
"pre_submit_difference": "EARLIER_HIDE_SPLASH_ONLY",
|
||||
"post_return_action": "LOAD_EXEC_EXIT",
|
||||
}
|
||||
|
||||
|
||||
def retroarch_path_is_exact(record: dict[str, Any]) -> bool:
|
||||
return record == {
|
||||
"sdk_crt1_linked": True,
|
||||
"sdl_video_backend_linked": True,
|
||||
"sdl2main_linked": False,
|
||||
"system_service_hide_splash_imported": True,
|
||||
"system_service_load_exec_imported": False,
|
||||
"sdl_video_hides_splash_before_videoout_open": True,
|
||||
}
|
||||
|
||||
|
||||
def launch_routes_are_fail_closed(record: dict[str, Any]) -> bool:
|
||||
direct = record.get("direct_raw_elf", {})
|
||||
manager = record.get("payload_manager_raw_elf", {})
|
||||
return (
|
||||
direct == {"constructor": "HARDENED_ELFLDR_SPAWN",
|
||||
"app_registration_found": False}
|
||||
and manager == {"constructor": "HARDENED_ELFLDR_SPAWN",
|
||||
"transport": "LOOPBACK_9021",
|
||||
"app_registration_found": False}
|
||||
and record.get("direct_and_manager_same_elfldr_spawn_path") is True
|
||||
and record.get("controlled_route_creates_distinct_app_context") is False
|
||||
and record.get("port_launcher_contract") == "PARTIAL_UNBOUND"
|
||||
and record.get("active_app_state_runtime") == "UNPROVEN"
|
||||
)
|
||||
|
||||
|
||||
def packaging_is_not_launcher_proof(record: dict[str, Any]) -> bool:
|
||||
return record == {
|
||||
"pacbrew_is_launcher": False,
|
||||
"pacbrew_classification": "PACKAGE_METADATA_ONLY",
|
||||
"homebrew_js_is_app_registration": False,
|
||||
"lakesnes_links_sdl2main": True,
|
||||
"lakesnes_launcher_implementation_bound": False,
|
||||
"official_port_runtime_success_used_as_hardware_evidence": False,
|
||||
}
|
||||
|
||||
|
||||
def runtime_observation_is_not_promoted(record: dict[str, Any]) -> bool:
|
||||
return record == {
|
||||
"lnc_log_classification": "OBSERVED_NONUNIQUE_CORRELATION",
|
||||
"lnc_exact_caller_observed": False,
|
||||
"lnc_log_accepted_as_root_cause": False,
|
||||
"first_submit_failure_remains": True,
|
||||
"visible_output_proven": False,
|
||||
"cleanup_proven": False,
|
||||
}
|
||||
|
||||
|
||||
def decision_is_blocked(record: dict[str, Any]) -> bool:
|
||||
return (
|
||||
record.get("root_cause_resolved") is False
|
||||
and record.get("sdl2main_change_allowed") is False
|
||||
and record.get("lnc_or_system_service_change_allowed") is False
|
||||
and record.get("submit_parameter_change_allowed") is False
|
||||
and record.get("new_videoout_call_allowed") is False
|
||||
and record.get("target_build_allowed") is False
|
||||
and record.get("device_action_allowed") is False
|
||||
and record.get("safe_next_steps") == [
|
||||
"OFFLINE_EXACT_HBLDR_SHSRV_PROVENANCE_AUDIT",
|
||||
"HOST_OR_SOFTWARE_ONLY_INTEGRATION",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def file_identity_is_exact(path: Path, record: dict[str, Any]) -> bool:
|
||||
return path.stat().st_size == record.get("size") and \
|
||||
sha256(path) == record.get("sha256")
|
||||
|
||||
|
||||
def validate(
|
||||
root: Path, retroarch_root: Path, sdk_root: Path, sdl_root: Path,
|
||||
elfldr_root: Path, manager_root: Path, pacbrew_root: Path,
|
||||
) -> list[str]:
|
||||
errors: list[str] = []
|
||||
try:
|
||||
record = load_json(
|
||||
root / "manifests/retroarch/phase-1.0r-launch-context-analysis.json")
|
||||
except (OSError, ValueError, json.JSONDecodeError) as error:
|
||||
return [str(error)]
|
||||
if record.get("phase") != PHASE or record.get("status") != STATUS:
|
||||
errors.append("phase/status mismatch")
|
||||
if record.get("start_commit") != "dbd2b2658bb12018a691c4a0edfb06c2a103848f":
|
||||
errors.append("start commit mismatch")
|
||||
if not all_false(record.get("authorizations", {}), AUTHORIZATION_FIELDS):
|
||||
errors.append("authorization remains active")
|
||||
if not source_identities_are_exact(record.get("source_identities", {})):
|
||||
errors.append("source identity mismatch")
|
||||
if not sdl2main_is_lifecycle_only(record.get("sdl2main", {})):
|
||||
errors.append("SDL2main semantics were promoted or changed")
|
||||
if not retroarch_path_is_exact(record.get("exact_retroarch_path", {})):
|
||||
errors.append("exact RetroArch linkage mismatch")
|
||||
if not launch_routes_are_fail_closed(record.get("launch_routes", {})):
|
||||
errors.append("launch route was promoted")
|
||||
if not packaging_is_not_launcher_proof(record.get("packaging_and_ports", {})):
|
||||
errors.append("packaging or descriptor was promoted to launcher proof")
|
||||
if not runtime_observation_is_not_promoted(record.get("runtime_observation", {})):
|
||||
errors.append("runtime observation was promoted")
|
||||
if not decision_is_blocked(record.get("decision", {})):
|
||||
errors.append("target change or device path is not blocked")
|
||||
performed = record.get("performed_actions", {})
|
||||
if set(performed) != {
|
||||
"target_source_changed", "target_artifact_created", "ps5_connected",
|
||||
"device_transfer_performed", "target_execution_performed",
|
||||
"result_received_from_device",
|
||||
} or not all(value is False for value in performed.values()):
|
||||
errors.append("performed-action boundary mismatch")
|
||||
tests = record.get("tests", {})
|
||||
if not (
|
||||
tests.get("chimera_gfx_ctest") == "64_OF_64_PASS"
|
||||
and tests.get("phase10r_guardrails") == 20
|
||||
and tests.get("safety_audit") == "PASS"
|
||||
and tests.get("secret_scan") == "PASS"
|
||||
and tests.get("network_required_by_tests") is False
|
||||
and tests.get("hardware_claim_from_host_test") is False
|
||||
):
|
||||
errors.append("test evidence mismatch")
|
||||
|
||||
repositories = (
|
||||
(retroarch_root, RA_HEAD, "RetroArch"),
|
||||
(sdk_root, SDK_COMMIT, "SDK"),
|
||||
(sdl_root, SDL_COMMIT, "SDL"),
|
||||
(elfldr_root, ELFLDR_COMMIT, "elfldr"),
|
||||
(manager_root, MANAGER_COMMIT, "Payload Manager"),
|
||||
(pacbrew_root, PACBREW_COMMIT, "PacBrew"),
|
||||
)
|
||||
try:
|
||||
for repository, commit, name in repositories:
|
||||
if git(repository, "rev-parse", "HEAD").strip() != commit:
|
||||
errors.append(f"{name} HEAD mismatch")
|
||||
if git(repository, "status", "--porcelain"):
|
||||
errors.append(f"{name} tree is dirty")
|
||||
|
||||
exact = record["exact_files"]
|
||||
paths = {
|
||||
"sdl2main": sdl_root / "src/main/ps5/SDL_ps5_main.c",
|
||||
"sdl_ps5_video": sdl_root / "src/video/ps5/SDL_ps5video.c",
|
||||
"sdk_crt": sdk_root / "crt/crt.c",
|
||||
"elfldr": elfldr_root / "elfldr.c",
|
||||
"elfldr_socket_server": elfldr_root / "socksrv.c",
|
||||
"payload_manager_launcher": manager_root / "src/ps5_launcher.c",
|
||||
"retroarch_makefile": retroarch_root / "Makefile.ps5",
|
||||
"artifact": retroarch_root / "build/phase10m/write-diag-a/retroarch_ps5_write_diag.elf",
|
||||
"linker_map": retroarch_root / "build/phase10m/write-diag-a/retroarch_ps5_write_diag.map",
|
||||
}
|
||||
for name, path in paths.items():
|
||||
if not file_identity_is_exact(path, exact[name]):
|
||||
errors.append(f"{name} file identity mismatch")
|
||||
|
||||
wrapper = paths["sdl2main"].read_text(encoding="utf-8")
|
||||
if not all(token in wrapper for token in (
|
||||
"sceSystemServiceHideSplashScreen();", "SDL_main(argc, argv);",
|
||||
'sceSystemServiceLoadExec("exit", 0);')):
|
||||
errors.append("SDL2main lifecycle source mismatch")
|
||||
if any(token in wrapper for token in ("sceLnc", "sceVideoOut", "AppId", "TitleId")):
|
||||
errors.append("unexpected registration/VideoOut token in SDL2main")
|
||||
|
||||
video = paths["sdl_ps5_video"].read_text(encoding="utf-8")
|
||||
video_init = video.find("static int PS5_VideoInit(_THIS)")
|
||||
hide = video.find("sceSystemServiceHideSplashScreen();", video_init)
|
||||
open_call = video.find("sceVideoOutOpen(0xff, 0, 0, NULL);", video_init)
|
||||
if video_init < 0 or hide < 0 or open_call < 0 or hide >= open_call:
|
||||
errors.append("SDL splash-hide/open ordering mismatch")
|
||||
|
||||
crt = paths["sdk_crt"].read_text(encoding="utf-8")
|
||||
if "_start(payload_args_t *args)" not in crt or \
|
||||
"main(argc, argv, environ)" not in crt:
|
||||
errors.append("SDK CRT entry contract mismatch")
|
||||
if any(token in crt for token in ("sceLnc", "sceVideoOut", "AppId")):
|
||||
errors.append("unexpected application registration in SDK CRT")
|
||||
|
||||
socksrv = paths["elfldr_socket_server"].read_text(encoding="utf-8")
|
||||
elfldr = paths["elfldr"].read_text(encoding="utf-8")
|
||||
if "payload_spawn(" not in socksrv or "elfldr_spawn(" not in socksrv:
|
||||
errors.append("elfldr raw route mismatch")
|
||||
if "rfork_thread(" not in elfldr or "execve(SceSpZeroConf" not in elfldr:
|
||||
errors.append("elfldr process constructor mismatch")
|
||||
|
||||
manager = paths["payload_manager_launcher"].read_text(encoding="utf-8")
|
||||
if "int ps5_launch_elf(" not in manager or \
|
||||
'inet_addr("127.0.0.1")' not in manager:
|
||||
errors.append("Payload Manager loopback launch mismatch")
|
||||
|
||||
makefile = paths["retroarch_makefile"].read_text(encoding="utf-8")
|
||||
if "libSDL2.a" not in makefile or "libSDL2main" in makefile:
|
||||
errors.append("RetroArch SDL linkage mismatch")
|
||||
link_map = paths["linker_map"].read_text(encoding="utf-8", errors="replace")
|
||||
if "crt1.o:(.text._start)" not in link_map or \
|
||||
"libSDL2.a(SDL_ps5video.c.o)" not in link_map:
|
||||
errors.append("linker-map source binding missing")
|
||||
if any(token in link_map for token in (
|
||||
"SDL_ps5_main", "libSDL2main", "sceSystemServiceLoadExec")):
|
||||
errors.append("linker map unexpectedly contains SDL2main")
|
||||
|
||||
recipe = (pacbrew_root / "SDL2/PKGBUILD").read_text(encoding="utf-8")
|
||||
if "ps5-payload-dev/SDL.git" not in recipe or \
|
||||
"sha256sums=('SKIP')" not in recipe:
|
||||
errors.append("PacBrew SDL recipe mismatch")
|
||||
|
||||
tracked = git(root, "ls-files").splitlines()
|
||||
if any(path.lower().endswith((".elf", ".self", ".sprx", ".pkg", ".map"))
|
||||
for path in tracked):
|
||||
errors.append("target artifact or linker map is tracked")
|
||||
except (OSError, RuntimeError, KeyError) as error:
|
||||
errors.append(str(error))
|
||||
return errors
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--root", type=Path, required=True)
|
||||
parser.add_argument("--retroarch-root", type=Path, required=True)
|
||||
parser.add_argument("--sdk-root", type=Path, required=True)
|
||||
parser.add_argument("--sdl-root", type=Path, required=True)
|
||||
parser.add_argument("--elfldr-root", type=Path, required=True)
|
||||
parser.add_argument("--manager-root", type=Path, required=True)
|
||||
parser.add_argument("--pacbrew-root", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
errors = validate(
|
||||
args.root.resolve(), args.retroarch_root.resolve(),
|
||||
args.sdk_root.resolve(), args.sdl_root.resolve(),
|
||||
args.elfldr_root.resolve(), args.manager_root.resolve(),
|
||||
args.pacbrew_root.resolve())
|
||||
if errors:
|
||||
for error in errors:
|
||||
print(f"ERROR: {error}")
|
||||
return 1
|
||||
print("Phase-1.0R launch-context analysis validation passed")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user