Thanks, this is helpful.
The key point we would like to clarify is different: whether the implementation-level serialization of calls made on the same es_client_t can itself stop making progress.
We have several independent termination reports showing the same stack pattern. In each occurrence, the ES client is terminated with:
code: 2
indicator: EndpointSecurity client terminated because it failed to respond to a message before its deadline
At the final process snapshot, three separate threads are simultaneously blocked in IOConnectCallStructMethod:
event-processing thread
es_respond_flags_result
IOConnectCallStructMethod
timer thread
es_respond_auth_result
IOConnectCallStructMethod
worker thread
es_mute_process_events
IOConnectCallStructMethod
Other parts of the process continue running and producing diagnostics, while no further ES-client diagnostic entries are emitted for approximately 6–15 seconds before the deadline termination.
You mentioned that there is a lock inside the user client that serializes most ES user-client calls. Could you please clarify whether this means serialization inside the user-space Endpoint Security library or a kernel-side IOKit user-client serialization point?
More specifically, can the kernel-side per-client serialization itself stop making progress in the following way?
es_mute_process_events() enters IOConnectCallStructMethod and does not return.
While that call remains in progress, es_respond_flags_result() and a fallback es_respond_auth_result() are called concurrently on the same es_client_t.
Both response calls then block in IOConnectCallStructMethod, potentially behind the first call.
No AUTH response completes before the message deadline, and the ES client is consequently terminated.
In other words, can an ES external method that stops returning hold or block the per-client serialization point required by subsequent response calls?
Or does the implementation guarantee that an in-progress es_mute_process_events() call cannot block the kernel-side path required by es_respond_*(), making the sequence above impossible by design?
The final process snapshots show all three calls blocked simultaneously, but they do not establish which call entered first or whether one call is holding a serialization point while the others are waiting behind it.
Topic:
Privacy & Security
SubTopic:
General
Tags: