Hello,
I am working on a DLP solution for macOS using the Endpoint Security framework. I have faced unexpected behavior regarding process identities. Upon receiving an ES_EVENT_TYPE_NOTIFY_EXEC event, my aplication caches the process details for future use by other internal components. This structure stores user identity tokens, including auid, euid, and ruid. However, I noticed that in subsequent ES_EVENT_TYPE_NOTIFY_CLOSE events for the exact same PID, the audit token arrives with a different audit uid, even though no ES_EVENT_TYPE_NOTIFY_EXIT event was triggered for this process.
Could you please help me clarify the following questions:
- In my case the initial value of audit uid is equal to AU_DEFAUDITID. What does it mean?
(ES_EVENT_TYPE_NOTIFY_EXEC and ES_EVENT_TYPE_NOTIFY_CLOSE are triggered by a file copy operation in Finder)
- How is audit uid changing possible? Is there any way to catch it via Endpoint Security?
Thank you in advance!
However, I noticed that in subsequent ES_EVENT_TYPE_NOTIFY_CLOSE events for the exact same PID, the audit token arrives with a different audit uid, even though no ES_EVENT_TYPE_NOTIFY_EXIT event was triggered for this process.
Is this only happening for some exec but not others? If so, then I think what you're seeing is the difference between posix_spawn and fork/exec. There's a thread here that talks about this in more detail, but the high-level detail is that posix_spawn's exec is called differently than a standard exec.
In my case the initial value of audit uid is equal to AU_DEFAUDITID. What does it mean?
It's basically, "this is not an audit token". Its actual definition is:
#define AU_DEFAUDITID (uid_t)(-1)
How is audit uid changing possible?
Assuming I'm right about posix_spawn's involvement, I think it's a "quirk" caused by differences in the details of the implementation. I'd need to dig into the code to be sure, but I think what's happening is that when posix_spawn runs, it first uses "fork" in the kernel to create a new process (including "claiming" its pid), then calls exec on that new process as well as finishing up its other configuration work. However, that new process doesn't actually run AT ALL during that process and, more importantly, if anything fails, posix_spawn just cleans up after itself by destroying everything it just made.
The tricky part here is that until that process finishes, I don't think the process really "exists.” posix_spawn has a pid that it got through fork and gave to exec, but the larger system doesn't know about the process AT ALL and if posix_spawn fails, the process won't really have ever "existed.”
Is there any way to catch it via Endpoint Security?
Assuming I'm right about what's going on, then one thing you can check/look at is comparing the es_message_t.process and es_event_exec_t.target. My guess is that this only happens when those two values don't match, which also means that you're inside posix_spawn. I'd also make a small test project that JUST called posix_spawn, as you may find that there's actually an event "point" where you're still in posix_spawn but the audit token changes.
In terms of "catching" it, if you're auth'ing exec, then you'll see every process that's ever created, so they can't "slip" past you. That change will also only occur once, as it’s a side effect of a very particular flow, not a normal action and certainly not something the process itself has any control over.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware