Skip to content

Fix XPC server crash on fire-and-forget messages - #2282

Open
1PoPTRoN wants to merge 1 commit into
apple:mainfrom
1PoPTRoN:fix/xpc-reply-no-reply-context-2281
Open

1PoPTRoN wants to merge 1 commit into
apple:mainfrom
1PoPTRoN:fix/xpc-reply-no-reply-context-2281

Conversation

@1PoPTRoN

Copy link
Copy Markdown

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

Fixes #2281.

XPCMessage.reply() force-unwrapped xpc_dictionary_create_reply(), which returns NULL for any message sent fire-and-forget via xpc_connection_send_message. Every path in XPCServer.handleMessage — all four error paths through replyWithError plus every success path built by the route handlers (88 reply() call sites across 13 files) — hits this, so one one-way dictionary from any same-uid process traps container-apiserver or any helper (container-runtime-linux, container-network-vmnet, container-core-images, machine-apiserver) with Fatal error: Unexpectedly found nil at XPCMessage.swift:60.

The fix keeps the reply() signature (no caller churn) but makes it non-trapping with an empty-dictionary fallback, adds a canReply check, and drops no-reply-context input in handleMessage/replyWithError after logging. Legitimate _with_reply traffic takes the identical code path as before.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs (no user-facing behavior change for legitimate traffic, so no doc updates)

Verification done on main @ 57f0b93, macOS 27.0, CommandLineTools Swift 6.4:

  • Live repro (anonymous XPC pair + one-way send, then reply() on the received dict): traps pre-fix (exit 133/SIGTRAP at XPCMessage.swift:60), passes post-fix with a usable fallback dictionary.
  • New ContainerXPCTests suite (4 tests: no-reply-context detection, no-trap regression, round-trip, live connection-pair repro). Note: this box has CLT only, so the swift-testing suite itself was validated via equivalent standalone harnesses linked against the built modules — please let CI run ContainerXPCTests under Xcode.
  • Full swift build green; swift format lint --strict clean on all touched files.

reply() force-unwrapped xpc_dictionary_create_reply, which returns NULL
for messages sent without reply context, trapping the apiserver or any
helper on a single one-way dictionary. Make reply() non-trapping with an
empty-dictionary fallback, add canReply, and drop no-reply-context input
in handleMessage/replyWithError after logging.

Adds ContainerXPCTests with regression coverage, including a live
connection-pair repro of the crash.

Fixes apple#2281
@1PoPTRoN

Copy link
Copy Markdown
Author

Hi @jglogan @katiewasnothere — I'm new around here and this is my first contribution, so please point me at anything I'm doing wrong. This one crashes container-apiserver (and every helper) on a single one-way dictionary, so I wanted eyes on it early.

I kept reply() non-failable with a fallback to avoid churning all 88 call sites, but I'm still learning the conventions here — happy to rework it however you'd like.

This branch has not been deployed

No deployments
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.

[Bug]: Force-unwrapped xpc_dictionary_create_reply crashes any XPC server on fire-and-forget input

1 participant