es_event_open_t fflag showing O_SEARCH instead of FREAD/FWRITE on macOS 26 beta 4

Hello,

Starting with macOS 26 beta 4, I’ve noticed that the fflag field in es_event_open_t sometimes contains O_SEARCH instead of the expected FREAD or FWRITE values.

According to the documentation, fflag should represent the kernel-applied flags (e.g., FREAD, FWRITE), not the open(2) oflag values. However, in my tests, when intercepting ES_EVENT_TYPE_AUTH_OPEN events, the value appears to match O_SEARCH in certain cases.

Is this an intentional change in macOS 26, or could it be a bug in the current beta? If this is expected behavior, could you clarify under what conditions O_SEARCH or some oflag are returned?

Environment:

macOS 26 beta 4

Endpoint Security Framework

Thanks in advance for any clarification!

Answered by DTS Engineer in 853606022

According to the documentation, fflag should represent the kernel-applied flags (e.g., FREAD, FWRITE), not the open(2) O_SEARCH values.

That's not quite correct. It's not a case of "should", it's that they ARE the kernel's flags. More specifically, the ES system is simply passing up the exact values it "got" from the MAC system in the kernel, so whatever it passes up is in fact exactly what was moving through the kernel.

The documentation calls out FREAD/FWRITE, but that's primarily because they have different flags. If you compare the definitions of XNU fcntl.h (kernel) and libc fcntl.h (user space), you'll find that most of their definitions are identical, with FREAD/FWRITE being the most notable exceptions.

However, in my tests, when intercepting ES_EVENT_TYPE_AUTH_OPEN events, the value appears to match O_SEARCH in certain cases.

What is generating the event and what was it targeting? What's the full flag value you're receiving?

Is this an intentional change in macOS 26, or could it be a bug in the current beta?

I'm not sure. If you're getting O_SEARCH on directories, then I suspect that's normal behavior, but if you're getting it on files, then that's at least "odd". The typical behavior is that O_SEARCH on a file will fail with ENOTDIR before the MAC check (which is what calls out to the ES system) occurs, but there has been some reordering of MAC check calls, so it's possible there is an edge case that's moved the check "earlier".

If this is expected behavior, could you clarify under what conditions O_SEARCH or some oflag are returned?

Well, the direct answer is because someone passed O_SEARCH into open. More practically, what O_SEARCH actually provides is a file descriptor reference for a directory without also providing read access to its contents. In practice, the main reason for using O_SEARCH is to pass the open descriptor into one of the "at" function variants. As a concrete example, which you may be seeing a lot of, the "cp" command has tweaked its implementation to favor open objects with O_SEARCH and then pass them into file descriptor-based APIs instead of using paths.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Accepted Answer

According to the documentation, fflag should represent the kernel-applied flags (e.g., FREAD, FWRITE), not the open(2) O_SEARCH values.

That's not quite correct. It's not a case of "should", it's that they ARE the kernel's flags. More specifically, the ES system is simply passing up the exact values it "got" from the MAC system in the kernel, so whatever it passes up is in fact exactly what was moving through the kernel.

The documentation calls out FREAD/FWRITE, but that's primarily because they have different flags. If you compare the definitions of XNU fcntl.h (kernel) and libc fcntl.h (user space), you'll find that most of their definitions are identical, with FREAD/FWRITE being the most notable exceptions.

However, in my tests, when intercepting ES_EVENT_TYPE_AUTH_OPEN events, the value appears to match O_SEARCH in certain cases.

What is generating the event and what was it targeting? What's the full flag value you're receiving?

Is this an intentional change in macOS 26, or could it be a bug in the current beta?

I'm not sure. If you're getting O_SEARCH on directories, then I suspect that's normal behavior, but if you're getting it on files, then that's at least "odd". The typical behavior is that O_SEARCH on a file will fail with ENOTDIR before the MAC check (which is what calls out to the ES system) occurs, but there has been some reordering of MAC check calls, so it's possible there is an edge case that's moved the check "earlier".

If this is expected behavior, could you clarify under what conditions O_SEARCH or some oflag are returned?

Well, the direct answer is because someone passed O_SEARCH into open. More practically, what O_SEARCH actually provides is a file descriptor reference for a directory without also providing read access to its contents. In practice, the main reason for using O_SEARCH is to pass the open descriptor into one of the "at" function variants. As a concrete example, which you may be seeing a lot of, the "cp" command has tweaked its implementation to favor open objects with O_SEARCH and then pass them into file descriptor-based APIs instead of using paths.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

''' 2025/07/21,13:38:35, EVENT, RTS, Auth_open(msg:), eventType: AUTH_OPEN filePath: /Library/Application Support/ahnlab/auth/ procPath: /bin/cp open fflag: 1074790400(0x4010000) // #define O_SEARCH (O_EXEC | O_DIRECTORY) /* open directory for search only */ '''

Hello,

Thnak you for your answer,

Starting with macOS 26 beta 4, I’ve noticed a change in AUTH_OPEN event behavior.

Previously (macOS 15 and earlier), when performing operation copy files, the es_event_open_t events were only triggered for the source file and target file, with fflag values such as FWRITE or FREAD.

However, on macOS 26 beta 4, before the file events occur, additional AUTH_OPEN events are triggered for the source and target directories, and in those cases, the fflag field contains O_SEARCH (e.g., 0x4010000) instead of the expected FREAD/FWRITE.

The documentation states that fflag should represent the kernel-applied mask, not the open(2) oflag values.

Is this an intentional change in macOS 26?

Should we now expect directory AUTH_OPEN events before file events?

If so, should fflag still be interpreted as before, or does it now represent oflag values in some cases?

Environment: macOS 26 beta 4 Endpoint Security Framework Observed during file copy operations (/bin/cp)

Thanks for any clarification!

The documentation states that fflag should represent the kernel-applied mask.

Yes, and they do. That is, flags returned by the fflag field come from the kernel's fcntl.h file., not the user space fcntl.h file..

not the open(2) oflag values.

The behavior here is exactly the same as before. O_SEARCH is a perfectly valid kernel flag. and it was occurring on macOS 15 as well as on macOS 26. I suspect the main reason you haven't seen it before is simply that it was primarily used by system daemon's you'd already muted and/or target paths you'd also muted.

Is this an intentional change in macOS 26?

It depends on which change you're talking about. If you're talking about EndpointSecurity or the kernel, then nothing actually changed. However, if you're talking about specific implementations like:

Environment: macOS 26 beta 4 Endpoint Security Framework Observed during file copy operations (/bin/cp)

Yes, that was absolutely a deliberate change. More specifically, you can open multiple files in the same directory in two different ways:

(1) Directly open the files

int fd = open("/foo/bar", O_RDONLY);
int fd2 = open("/foo/bar2", O_RDONLY);
int fd3 = open("/foo/bar3", O_RDONLY);

OR

(2) Open the directory, then openat the files:

int dd = open("/foo", O_SEARCH); 
int fd = openat(dd, "/bar", O_RDONLY);
int fd2 = openat(dd, "/bar2", O_RDONLY);
int fd3 = openat(dd, "/bar3", O_RDONLY);

Note that the second pattern is more secure when dealing with multiple files, since it guarantees that all three files came from the same source directory, minimizing TOC/TOU (Time of Check to Time of Use) race conditions.

And, yes, in macOS 26, cp's implementation changed from #1 to #2.

Should we now expect directory AUTH_OPEN events before file events?

Again, the problem here is with the word "expect". The EndpointSecurity system is simply telling you what happened, so you're now seeing different behavior because "what's happening" has changed. I think you probably will see more "O_SEARCH" opens but that simply because it's often the better approach, not because of any low-level/systemic change.

If so, should fflag still be interpreted as before, or does it now represent oflag values in some cases?

Again, the meaning of fflag has not changed at all. O_SEARCH has been a perfectly valid kernel open flag for a very long time. It just happened to be the case that you weren't monitoring the cases where the system was using it.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware.

es_event_open_t fflag showing O_SEARCH instead of FREAD/FWRITE on macOS 26 beta 4
 
 
Q