Skip to content

Prevent jailbreakd deadlock that causes device reboots - #142

Draft
Mr-Tomahawk wants to merge 1 commit into
roothide:2.xfrom
Mr-Tomahawk:agent/prevent-jailbreakd-watchdog-reboot
Draft

Prevent jailbreakd deadlock that causes device reboots#142
Mr-Tomahawk wants to merge 1 commit into
roothide:2.xfrom
Mr-Tomahawk:agent/prevent-jailbreakd-watchdog-reboot

Conversation

@Mr-Tomahawk

Copy link
Copy Markdown

Summary

Prevent a launchd/jailbreakd spawn-patching deadlock that can block the system long enough for watchdogd to force a full device reboot.

Root cause

JBD_MSG_SPAWN_EXEC_START and JBD_MSG_SPAWN_EXEC_CANCEL currently run inline on jailbreakd's receive queue. If exec-patch registration stalls in spawnExecPatchAdd, jailbreakd cannot service a nested JBD_MSG_SPAWN_PATCH_CHILD request from launchd. Launchd waits synchronously for that reply, its event thread stops making progress, and the system watchdog eventually reboots the device.

This was diagnosed from repeated full-device watchdog panic stackshots with the same blocking chain:

watchdogd -> launchd event queue -> jailbreakd -> spawnExecPatchAdd

Changes

  • Move exec-patch start and cancel handling to a dedicated serial queue while preserving per-PID ordering.
  • Retain the exec path and deferred XPC reply across the asynchronous boundary.
  • Initialize exec-patch state before jailbreakd begins accepting requests.
  • Bound launchd's child-patch request to ten seconds so its existing failed-spawn cleanup can run instead of waiting indefinitely.
  • Keep the timeout helper in C with explicit XPC and dispatch ownership; this avoids adding duplicate Objective-C runtime classes to binaries that compile the shared client source.

JBD_MSG_SPAWN_PATCH_CHILD remains on jailbreakd's receive queue so launchd's nested request can complete while an exec registration is slow.

Impact

Without this change, the failure presents as a whole-device reboot rather than an isolated application or daemon crash. The first stage removes the receive-queue cycle; the bounded wait is a defensive fallback that returns failure to the existing launchd-side path, which terminates the still-suspended child and reports spawn error 202.

Validation

  • Built libjailbreak, jailbreakd, and systemhook successfully for arm64 and arm64e with Xcode 26.
  • git diff --check passes.
  • Existing unrelated Xcode 26 warnings remain; the changed sources introduce no build errors.

@roothider

Copy link
Copy Markdown

I/no one else has ever encountered this problem before. Can you tell me how to reproduce it?

@Mr-Tomahawk

Copy link
Copy Markdown
Author

For me this issue comes from playing Call of Duty Mobile on an iphone 7 with tweaks on. It's somewhat consistent but idk how else to reproduce. When I try to enter "battle royale" game mode, it would freeze at 99%, then my device would stop responding to any touches or button presses, then my device would fully restart. I can't repeat it on other devices and neither can my friends who use roothide. Most likely explanation is how bad the phone is, but regardless it's still a problem. I haven't rebooted once since I integrated this pr into my own build I'm currently using on that iphone 7

@roothider

Copy link
Copy Markdown

1: spawnExecPatchAdd itself does not wait; it add the request into the serial queue gExecPatchDataQueue and returns immediately. so I don't understand how it caused the deadlock.

2:JailbreakdXpcRequestWithTimeout is probably not a good idea; it might mask some real bugs.

@Mr-Tomahawk

Copy link
Copy Markdown
Author

im not sure about the rest but the timing change stopped the reboot for sure, changing it from 90 sec to 10. though it probably masks the real issue. if you want all my logs I'd be happy to send them privately to your email or discord just let me know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants