Skip to content
This repository was archived by the owner on Oct 30, 2026. It is now read-only.

Stop checkra1n when palera1n is abandoned - #8

Merged
henrikklee merged 1 commit into
OrchardLinux:mainfrom
dl-alexandre:kill-checkra1n-with-palera1n
Oct 29, 2026
Merged

henrikklee merged 1 commit into
OrchardLinux:mainfrom
dl-alexandre:kill-checkra1n-with-palera1n

Conversation

@dl-alexandre

Copy link
Copy Markdown
Contributor

Problem

apple/boot.py runs palera1n -p -k <pongo> with subprocess.run(..., timeout=120). When that times out, Python SIGKILLs palera1n, but palera1n isn't the process doing the work. It posix_spawns checkra1n and only waitpids on it, so checkra1n survives as an orphan. It keeps writing to Orchard's palera1n log, and after each checkm8 timeout it waits for DFU again (Device reconnected in DFU mode, starting over).

I hit this on an iPad 6 (J71b) with a Linux host. One install attempt timed out at 20:58 because the cable wasn't replugged in time. That palera1n-*.log kept growing until 21:16. During that time, every DFU entry (21:14:08, 21:14:54, 21:15:50) was exploited again by the orphan. The last one booted Pongo, so the next orchard launch failed with:

orchard: Expected dfu at the selected port; found pongo

To anyone running Orchard, the device just seems to leave DFU on its own.

Change

run_process_group() replaces subprocess.run(check=True) for the bootstrap. It starts palera1n with start_new_session=True and, if Orchard stops waiting for any reason (timeout or KeyboardInterrupt), SIGKILLs the whole process group, checkra1n included, before re-raising. The success and non-zero-exit paths behave as before (CalledProcessError), and so does the RuntimeError('... outcome unknown ...') wrapping and the no-retry policy.

Testing

  • test_bootstrap_timeout_stops_spawned_children runs a stand-in for palera1n that backgrounds a long-lived child, then checks that the child is gone after the timeout. The same scenario with plain subprocess.run(timeout=...) leaves the child running, which I checked separately. The test passed 25 out of 25 runs.
  • test_bootstrap_failure_is_reported covers non-zero exit and success.
  • test_adapter_boot_sequence_timeouts_and_no_retry_are_preserved now mocks run_process_group instead of subprocess.run. I couldn't run it locally: my venv's orchard_hardware 0.1.10 has no profiles, which fails with or without this change.

Not covered here: if Orchard itself is killed with SIGTERM, the Python handlers never run, so palera1n's group can still be left behind.

🤖 Generated with Claude Code

palera1n posix_spawns checkra1n and only waits for it. When the Pongo
bootstrap timed out, subprocess.run killed palera1n alone; checkra1n
kept running and re-exploited the next device that entered DFU, so a
later `orchard launch` found Pongo where it expected DFU.

Run palera1n in its own process group and kill the whole group when
Orchard stops waiting for it (timeout or interrupt).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@henrikklee
henrikklee merged commit 2107726 into OrchardLinux:main Oct 29, 2026
henrikklee pushed a commit that referenced this pull request Oct 29, 2026
#8 ran the install/launch Pongo bootstrap in its own process group, but
`orchard run` has a separate palera1n call that still used
subprocess.run. When it timed out, checkra1n kept running and would
exploit the next DFU entry. Use run_process_group there too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants