Repository navigation
Open
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
Several extension modules don't fully emit the relevant audit events, leading to file read or process spawning without any traceability.
In particular:
- Calling a
_ctypes.CFuncPtrdoes not emitctypes.call_function. When combined with some known addresses, this can result in arbitrary functions in libc or python getting called. Such addresses could come fromid,ctypes.pythonapi._handle, passing abyrefpointer toctypes.cast, or probably still several other methods. Coincidentally, thectypes.castmethod would by audited by the samectypes.call_functiononce it is present. The downside is that it may also result in multiple audit hooks for functions likectypes.string_atthat have their own specialized audit hook event too. - Related, and maybe debatable, but constructing a
_ctypes.CFuncPtrmight fall under the audit eventctypes.cdata, as it is in spirit (though not in implementation) similar to calling a.from_address. An option might be to introducectypes.cdata/functionsimilar toctypes.cdata/bufferfor this. - The
readlinemodule can open and read a file throughreadline.read_history_filewithout having anopenaudit hook. Together withreadline.get_history_item, this can lead to unaudited file reads. A similar situation exists for some other functions in this library. - The
_posixsubprocess.fork_execfunction, and its only user in the standard library,multiprocessing.util.spawnv_passfdsperform a fork + exec without any audit hooks. One would expect eitheros.forkandos.execor the functionally similaros.posix_spawnhere.
I'm happy to make a quick PR for these and adjust any specific event types to be more consistent or more uniquely identifiable.
Quick example in code:
import sys, ctypes, multiprocessing.util, readline
collected = []
def collector(event, *_args):
collected.append(event)
sys.addaudithook(collector)
def test(fn, *args, **kw):
collected.clear()
fn(*args, **kw)
if collected: # Just check it's nonempty
print("Success")
else:
print("Fail")
test(ctypes.memmove, 0, 0, 0)
test(ctypes.CFUNCTYPE(ctypes.py_object), ctypes._memmove_addr)
test(readline.read_history_file, __file__)
test(multiprocessing.util.spawnv_passfds, b"/bin/id", [], [])CPython versions tested on:
3.11, 3.12, 3.13, CPython main branch
Operating systems tested on:
Linux
Linked PRs
Reacted by Hyunsik Jeong, Zhang Yuheng and Gregory P. Smith
Metadata
Metadata
Assignees
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
pythonGH-115322: Add missing audit hooks
gpshead commentedon Feb 22, 2024
The primary user of that is
subprocess, not justmultiprocessing's spawn start method.subprocessalready has an audit hook of its own viasys.audit: https://github.com/python/cpython/blob/main/Lib/subprocess.py#L1827Along those lines, it'd be simpler and consistent to just call sys.audit from within
multiprocessing.util.spawnv_passfds, but I think your point of this issue was more to see it consistently done at the extension module API level?There is symmetry in that the private
_winapi.CreateProcessAPI also triggers an audit hook in addition tosubprocess.Popenbefore it calls it so I'm okay with the concept of adding a_posixsubprocess.fork_execaudit event as your PR does.RobinJadoul commentedon Feb 22, 2024
Ah, yes, I have no idea how I missed subprocess when looking for callers...
It's indeed the goal to have some fewer "holes" or better coverage from the audit hooks here. That includes directly calling into the extension modules or callers that don't do their own hook (like the multiprocessing one).
In general, the closer to the actual operation happening, the less chance to miss it.
The new event was indeed based on the winapi ones.
Merge branch 'main' into pythongh-115322-missing-audit-hooks
Merge branch 'main' into pythongh-115322-missing-audit-hooks
devdanzin commentedon Oct 21, 2024
Should
_gdbm.open()also emit an audit event? It can be used to overwrite a file, besides creating a new one.RobinJadoul commentedon Oct 21, 2024
Looks like a good catch that should probably be covered too. It may need a bit of translation to not confuse existing consumers of the
openevent though, as the flags and mode are noticeably different in_gdbm.open.GH-115322: Add missing audit hooks (GH-115624)
pythonGH-115322: fix ctypes call_function audit hook on 32-bit platfo…
GH-115322: fix ctypes call_function audit hook on 32-bit platforms (G…