Repository navigation
"open" audit event "mode" does not contain information for os.open calls #158916
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Oct 6, 2026 - addedextension-modulesC modules in the Modules dirC modules in the Modules dir
on Oct 6, 2026 Docs for os.open say:
Raises an auditing event open with arguments path, mode, flags.
If we are not forwarding the mode appropriately this indeed seems wrong. Can you check why? or are you interested in making a PR?
In my brief attempt to use the
openaudit event, in order to be useful it needs to return auditing data consistently acrossopen()andos.open().If this bug report is treated as a code bug and not a documentation bug, then it seems like you'd want
os.open()to report amodewhich is abstracted based on the translation of theos.O_RDONLY, os.O_WRONLY... etcflags into amodestring liker, w, ....However just looking at that list I immediately notice that "b" and "t" have no meaning in
os.open(). I just tested anopen("bla","wb")call however, and it actually only triggers an audit event of:
open ('bla', 'w', 524865)
So it should probably be noted somewhere that "b" and "t" are stripped from the audit event (which is actually fine by me since they don't have a lot of use in terms of auditing what the program is actually doing).Another point of confusion here is the https://docs.python.org/3/builtins/functions.html#open documentation says:
Raises an auditing event open with arguments path, mode, flags.
But there are no
flagsat all in theopen()call at all. What the audit even is currently using is theflagsfrom the underlyingos.open()that eventually gets called down below somewhere.I've never done any work on python internals, but this last part strikes me as especially strange here because if the audit event is using
os.open()information already, it's odd that it wouldn't just get themodecorrect there.I am on mobile so I cannot check, but the audit event name has been shared by multiple functions so this can be easily missed
Now, we use mode whether for the mode 'r' or the mode passed to os.open() (AFAIU the docs) It is not about flags being translated into a mode. os.open() accepts a mode param as well and a flags. So if we pass one, we should see it in the event. The meaning of mode for open/io.open() will however be different I think.
What matters is to know if the one raising the audit event is open itself or the underlying call to io.open() for instance (and where in the stack).
I think we can have inconsistent translations or we are raising the audit before we derive the appropriate flags.
cc @vstinner
Well, ok it's technically true that
os.open()andopen()both have a function parameter calledmodebut the meanings are unrelated. The former specifies the ACL bits for the file system and is only applicable for file creation (and does nothing to the file handle), while the latter determines reading/writing/etc for the file handle.It would be helpful for the docs to also be more clear regarding which of those two completely different
modes are being intended. It seemingly is always intended to reference only theopen()mode.The
os.open()use ofmodecould conceivably have some usefulness in auditing I suppose, but currently it seems to be entirely absent from the audit system. That would seem to warrant a separate issue tracker if someone wants that feature though.Hum. I wrote a script:
import sys import os def hook(event, args): if 'open' in event: print("EVENT", event, args) sys.addaudithook(hook) print(f"os.O_CLOEXEC = {os.O_CLOEXEC}") open(__file__).close() fd = os.open(__file__, os.O_RDONLY); os.close(fd)
Output:
os.O_CLOEXEC = 524288 EVENT open ('/home/vstinner/python/main/x.py', 'r', 524288) EVENT open ('/home/vstinner/python/main/x.py', None, 524288)open() logs
'r'mode, whereas os.open() doesn't log the mode (left asNone).os.open() documentation says:
Raises an auditing event open with arguments path, mode, flags.
I don't know how this audit event was designed. @zooba might know better about this.
One of the principles was to pass through arguments directly (after type checks), so without going through history at all, I would guess that's why it's different. Calculating the equivalent string for
os.openwould take non-zero time, and passing a non-string technically isn't wrong but would be a surprising change.If there's a very quick way to pass a suitable static string (e.g. if it is either
rorwbased on a single test) then I see no harm in adding that.But it wouldn't surprise me if the information is passed through in flags.
OS_RDONLYshould be zero, so you won't see it, but other flags should be in the event, I thought.
Bug report
This was originally reported in bug #116429 although it was not specifically pointed out there.
The "open" audit event "mode" does not contain information for
os.opencalls. It is alwaysNone. (This is unfortunate because I was hoping to run an audit report on all files being opened either for reading or for writing separately, and due to this limitation you can't do that.)The https://docs.python.org/3/library/audit_events.html documentation states the
modefield is there foros.open. Without some documentation note to the contrary, one would expect the field to exist and contain valid information.CPython versions tested on:
3.16
Operating systems tested on:
No response