Skip to content

[ASan] XPCConnectionTerminationWatchdog may kill an unrelated process after its pid is reused - #77405

Open
ddkilzer wants to merge 1 commit into
WebKit:mainfrom
ddkilzer:eng/ASan-XPCConnectionTerminationWatchdog-may-kill-an
Open

ddkilzer wants to merge 1 commit into
WebKit:mainfrom
ddkilzer:eng/ASan-XPCConnectionTerminationWatchdog-may-kill-an

Conversation

@ddkilzer

@ddkilzer ddkilzer commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

a497ee1

[ASan] XPCConnectionTerminationWatchdog may kill an unrelated process after its pid is reused
<https://bugs.webkit.org/show_bug.cgi?id=327960>
<rdar://190319872>

Reviewed by NOBODY (OOPS!).

In ASan builds, `terminateWithReason()` kills the process with
`terminate_with_reason()`, which takes a pid.  The termination watchdog
calls it 30 seconds after the connection was cancelled, so if the
child process already exited and its pid was reused, the watchdog
kills an unrelated process.  `xpc_connection_kill()`, used in other
builds, does not have this problem.

Call `terminate_with_reason()` only if `proc_pidpath_audittoken()`
succeeds for the connection's audit token, which fails once the
process that the token identifies has exited, and fall back to
`xpc_connection_kill()` otherwise.  The iOS Simulator SDKs lack
`<libproc.h>`, so those builds skip the check and keep calling
`terminate_with_reason()` to preserve their crash reports.

No new tests since this change is not directly testable.

* Source/WebKit/Platform/cocoa/XPCUtilities.mm:
(WebKit::terminateWithReason):

a497ee1

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows Apple Internal
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win ⏳ 🛠 ios-apple
✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ✅ 🧪 win-tests ⏳ 🛠 mac-apple
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe ⏳ 🛠 vision-apple
✅ 🧪 ios-wk2-wpt ⏳ 🧪 api-mac-debug
loading 🧪 api-ios ✅ 🧪 mac-wk2 ✅ 🛠 gtk3-gcc
✅ 🛠 ios-safer-cpp loading 🧪 mac-AS-debug-wk2 ✅ 🛠 gtk
✅ 🛠 vision ✅ 🧪 gtk-wk2
✅ 🛠 vision-sim ⏳ 🧪 mac-intel-wk2 ✅ 🧪 api-gtk
✅ 🧪 vision-wk2 ✅ 🛠 mac-safer-cpp ✅ 🛠 playstation
✅ 🛠 tv ✅ 🧪 mac-site-isolation
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@ddkilzer
ddkilzer requested a review from cdumez as a code owner October 17, 2026 20:20
@ddkilzer ddkilzer self-assigned this Oct 17, 2026
@ddkilzer ddkilzer added the WebKit Process Model Bugs related to WebKit's multi-process architecture label Oct 17, 2026
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Oct 17, 2026
@ddkilzer
ddkilzer marked this pull request as draft October 17, 2026 20:37
@ddkilzer ddkilzer removed the merging-blocked Applied to prevent a change from being merged label Oct 17, 2026
@ddkilzer
ddkilzer force-pushed the eng/ASan-XPCConnectionTerminationWatchdog-may-kill-an branch from c1aac06 to a743947 Compare October 17, 2026 20:44
@ddkilzer
ddkilzer marked this pull request as ready for review October 17, 2026 20:53
… after its pid is reused

<https://bugs.webkit.org/show_bug.cgi?id=327960>
<rdar://190319872>

Reviewed by NOBODY (OOPS!).

In ASan builds, `terminateWithReason()` kills the process with
`terminate_with_reason()`, which takes a pid.  The termination watchdog
calls it 30 seconds after the connection was cancelled, so if the
child process already exited and its pid was reused, the watchdog
kills an unrelated process.  `xpc_connection_kill()`, used in other
builds, does not have this problem.

Call `terminate_with_reason()` only if `proc_pidpath_audittoken()`
succeeds for the connection's audit token, which fails once the
process that the token identifies has exited, and fall back to
`xpc_connection_kill()` otherwise.  The iOS Simulator SDKs lack
`<libproc.h>`, so those builds skip the check and keep calling
`terminate_with_reason()` to preserve their crash reports.

No new tests since this change is not directly testable.

* Source/WebKit/Platform/cocoa/XPCUtilities.mm:
(WebKit::terminateWithReason):
@ddkilzer
ddkilzer force-pushed the eng/ASan-XPCConnectionTerminationWatchdog-may-kill-an branch from a743947 to a497ee1 Compare October 18, 2026 03:02
if (invalidMessageName)
code |= static_cast<uint64_t>(std::to_underlying(*invalidMessageName)) << 8;
if (!terminate_with_reason(xpc_connection_get_pid(connection), OS_REASON_WEBKIT, code, reason, 0))
bool isSameProcess = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: maybe we should move the mutable isSameProcess and its inner #if into a small helper. Non blocking.

if (!terminate_with_reason(xpc_connection_get_pid(connection), OS_REASON_WEBKIT, code, reason, 0))
bool isSameProcess = true;
#if HAVE(LIBPROC)
// terminate_with_reason() signals by pid, and the watchdog fires 30s after the connection

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the '30s after the connection was cancelled' part of the comment is correct. The timer is armed from terminate(), shutDownProcess() or the destructor, so I think its more accurate to say 'after the watchdog was armed'.

code |= static_cast<uint64_t>(std::to_underlying(*invalidMessageName)) << 8;
if (!terminate_with_reason(xpc_connection_get_pid(connection), OS_REASON_WEBKIT, code, reason, 0))
bool isSameProcess = true;
#if HAVE(LIBPROC)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where HAVE(LIBPROC) is false the hazard remains. That includes iOS Simulator, where processes are host processes. We can add a FIXME and mention it in the commit message. Non blocking.

std::array<char, PROC_PIDPATHINFO_MAXSIZE> path;
isSameProcess = proc_pidpath_audittoken(&auditToken, path.data(), path.size()) > 0;
#endif
if (isSameProcess && !terminate_with_reason(xpc_connection_get_pid(connection), OS_REASON_WEBKIT, code, reason, 0))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use audit_token_to_pid(auditToken) for the terminate_with_reason pid instead of a second xpc_connection_get_pid. As written, the check can pass while xpc_connection_get_pid returns 0 on a cancelled connection.

@zakariaridouh zakariaridouh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+ with some nits and comments

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

Labels

WebKit Process Model Bugs related to WebKit's multi-process architecture

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants