Skip to content

fix stale job metadata after PID reuse - #149

Closed
clxxrlove wants to merge 1 commit into
roothide:v2.4.9.xfrom
clxxrlove:v2.4.9.x
Closed

clxxrlove wants to merge 1 commit into
roothide:v2.4.9.xfrom
clxxrlove:v2.4.9.x

Conversation

@clxxrlove

Copy link
Copy Markdown

Problem

The launchd hook records each successfully spawned process as:

PID -> p_uniqueid

However, get_job_cache() previously returned the stored value without checking whether the process currently using that PID still had the same p_uniqueid.

The job metadata cache had a separate problem: it stored path and bundle identifier by PID only.

As a result:

  • If process A exited and its PID was reused by an unregistered process B, B could be treated as if it were A's registered launchd job.
  • If B was registered normally, the C++ job cache was updated, but the Objective-C metadata cache could still return A's path and identifier.

Change

This patch makes the existing p_uniqueid value part of cache validation:

  • get_job_cache(pid) now compares the registered unique ID with the unique ID of the process currently using that PID.
  • A failed identity lookup is not considered a cache hit.
  • Cached path and identifier dictionaries now include the unique ID they belong to.
  • Metadata cached for an older process is ignored and replaced when the PID is registered for a new process instance.
  • After reading path and identifier information, the unique ID is checked again before the metadata is cached. If the process exited or the PID was reused during the lookup, the result is discarded.
  • Callers handle a rejected lookup conservatively instead of dereferencing a null identifier.

The cache remains keyed by PID and bounded by the PID space. This does not add process-exit monitoring; stale entries are rejected lazily by validating the current process identity when they are accessed.

Validation

  • Built libjailbreak.dylib and launchdhook.dylib for arm64 and arm64e.
  • Ran Clang static analysis on both modified translation units.
  • Ran a host regression harness covering:
    • registered process A lookup;
    • PID reuse by unregistered process B;
    • PID reuse followed by registration of B;
    • process identity changing while metadata is being collected;
    • process identity lookup failure.

The original implementation returned stale metadata in the reuse test. The patched implementation rejected it and returned metadata for B only after B was registered.

English is not my first language, and I used a translation tool while writing this PR. Please let me know if anything is unclear, and I’ll be happy to clarify.

@roothider

Copy link
Copy Markdown

1: These scenarios will not actually come to pass.

2: Clearly, AI cannot understand the intent behind its design.

@clxxrlove

Copy link
Copy Markdown
Author

@roothider Thank you for the clarification.

My concern came from the absence of explicit cache invalidation and from the metadata cache being keyed only by PID. However, I understand that my regression harness modeled PID reuse at the cache level and did not prove that this state is reachable through launchd’s actual process and XPC lifecycle.

Could you clarify which lifecycle guarantee prevents these scenarios—for example, whether the relevant PID cannot be reused while the cache is alive, or whether every queried PID is guaranteed to refer to the same live process instance that was registered? I would like to understand the intended design and avoid proposing an unnecessary change.

If the state is genuinely unreachable, I’ll close the PR.

@roothider

Copy link
Copy Markdown

The kernel does not reuse the unique ID, and the unique ID does not change during exec (xpcproxy).
Yes you can close this PR❤️

@clxxrlove

Copy link
Copy Markdown
Author

@roothider Understood. Thank you for the explanation and for taking the time to review the PR. I’ll close it and look for another issue to work on. Have a nice day 👍

@clxxrlove clxxrlove closed this Sep 9, 2026
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