PEP 578: Update with feedback (#1023)
* Note about naming style * Add note about using package name * Avoid embedding null characters * Add socket event argument to socket events
This commit is contained in:
parent
fd54e6e509
commit
4ab33c63f1
77
pep-0578.rst
77
pep-0578.rst
|
@ -118,9 +118,6 @@ send and receive audit hook messages::
|
||||||
# Raise an event with all auditing hooks
|
# Raise an event with all auditing hooks
|
||||||
int PySys_Audit(const char *event, PyObject *args);
|
int PySys_Audit(const char *event, PyObject *args);
|
||||||
|
|
||||||
# Internal API used during Py_Finalize() - not publicly accessible
|
|
||||||
void _Py_ClearAuditHooks(void);
|
|
||||||
|
|
||||||
The new Python APIs for receiving and raising audit hooks are::
|
The new Python APIs for receiving and raising audit hooks are::
|
||||||
|
|
||||||
# Add an auditing hook
|
# Add an auditing hook
|
||||||
|
@ -133,7 +130,9 @@ The new Python APIs for receiving and raising audit hooks are::
|
||||||
Hooks are added by calling ``PySys_AddAuditHook()`` from C at any time,
|
Hooks are added by calling ``PySys_AddAuditHook()`` from C at any time,
|
||||||
including before ``Py_Initialize()``, or by calling
|
including before ``Py_Initialize()``, or by calling
|
||||||
``sys.addaudithook()`` from Python code. Hooks cannot be removed or
|
``sys.addaudithook()`` from Python code. Hooks cannot be removed or
|
||||||
replaced.
|
replaced. For CPython, hooks added from C are global, while hooks added
|
||||||
|
from Python are only for the current interpreter. Global hooks are
|
||||||
|
executed before interpreter hooks.
|
||||||
|
|
||||||
When events of interest are occurring, code can either call
|
When events of interest are occurring, code can either call
|
||||||
``PySys_Audit()`` from C (while the GIL is held) or ``sys.audit()``. The
|
``PySys_Audit()`` from C (while the GIL is held) or ``sys.audit()``. The
|
||||||
|
@ -141,41 +140,54 @@ string argument is the name of the event, and the tuple contains
|
||||||
arguments. A given event name should have a fixed schema for arguments,
|
arguments. A given event name should have a fixed schema for arguments,
|
||||||
which should be considered a public API (for each x.y version release),
|
which should be considered a public API (for each x.y version release),
|
||||||
and thus should only change between feature releases with updated
|
and thus should only change between feature releases with updated
|
||||||
documentation.
|
documentation. To minimize overhead and simplify handling in native code
|
||||||
|
hook implementations, named arguments are not supported.
|
||||||
|
|
||||||
For maximum compatibility, events using the same name as an event in
|
For maximum compatibility, events using the same name as an event in
|
||||||
the reference interpreter CPython should make every attempt to use
|
the reference interpreter CPython should make every attempt to use
|
||||||
compatible arguments. Including the name or an abbreviation of the
|
compatible arguments. Including the name or an abbreviation of the
|
||||||
implementation in implementation-specific event names will also help
|
implementation in implementation-specific event names will also help
|
||||||
prevent collisions. For example, a ``pypy.jit_invoked`` event is clearly
|
prevent collisions. For example, a ``pypy.jit_invoked`` event is clearly
|
||||||
distinguised from an ``ipy.jit_invoked`` event.
|
distinguished from an ``ipy.jit_invoked`` event. Events raised from
|
||||||
|
Python modules should include their module or package name in the event
|
||||||
|
name.
|
||||||
|
|
||||||
|
While event names may be arbitrary UTF-8 strings, for consistency across
|
||||||
|
implementations it is recommended to use valid Python dotted names and
|
||||||
|
avoid encoding specific details in the name. For example, an ``import``
|
||||||
|
event with the module name ``spam`` as an argument is preferable to a
|
||||||
|
``spam module imported`` event with no arguments. Avoid using embedded
|
||||||
|
null characters or you may upset those who implement hooks using C.
|
||||||
|
|
||||||
When an event is audited, each hook is called in the order it was added
|
When an event is audited, each hook is called in the order it was added
|
||||||
with the event name and tuple. If any hook returns with an exception
|
(as much as is possible), passing the event name and arguments. If any
|
||||||
set, later hooks are ignored and *in general* the Python runtime should
|
hook returns with an exception set, later hooks are ignored and *in
|
||||||
terminate. This is intentional to allow hook implementations to decide
|
general* the Python runtime should terminate - exceptions from hooks are
|
||||||
how to respond to any particular event. The typical responses will be to
|
not intended to be handled or treated as expected occurrences. This
|
||||||
log the event, abort the operation with an exception, or to immediately
|
allows hook implementations to decide how to respond to any particular
|
||||||
terminate the process with an operating system exit call.
|
event. The typical responses will be to log the event, abort the
|
||||||
|
operation with an exception, or to immediately terminate the process with
|
||||||
|
an operating system exit call.
|
||||||
|
|
||||||
When an event is audited but no hooks have been set, the ``audit()``
|
When an event is audited but no hooks have been set, the ``audit()``
|
||||||
function should impose minimal overhead. Ideally, each argument is a
|
function should impose minimal overhead. Ideally, each argument is a
|
||||||
reference to existing data rather than a value calculated just for the
|
reference to existing data rather than a value calculated just for the
|
||||||
auditing call.
|
auditing call.
|
||||||
|
|
||||||
As hooks may be Python objects, they need to be freed during
|
As hooks may be Python objects, they need to be freed during
|
||||||
``Py_Finalize()``. To do this, we add an internal API
|
interpreter or runtime finalization. These should not be triggered at
|
||||||
``_Py_ClearAuditHooks()`` that releases any Python hooks and any
|
any other time, and should raise an event hook to ensure that any
|
||||||
memory held. This is an internal function with no public export, and
|
unexpected calls are observed.
|
||||||
we recommend it raise its own audit event for all current hooks to
|
|
||||||
ensure that unexpected calls are observed.
|
|
||||||
|
|
||||||
Below in `Suggested Audit Hook Locations`_, we recommend some important
|
Below in `Suggested Audit Hook Locations`_, we recommend some important
|
||||||
operations that should raise audit events.
|
operations that should raise audit events. In general, events should be
|
||||||
|
raised at the lowest possible level. Given the choice between raising an
|
||||||
|
event from Python code or native code, raising from native code should be
|
||||||
|
preferred.
|
||||||
|
|
||||||
Python implementations should document which operations will raise
|
Python implementations should document which operations will raise
|
||||||
audit events, along with the event schema. It is intentional that
|
audit events, along with the event schema. It is intentional that
|
||||||
``sys.addaudithook(print)`` be a trivial way to display all messages.
|
``sys.addaudithook(print)`` is a trivial way to display all messages.
|
||||||
|
|
||||||
Verified Open Hook
|
Verified Open Hook
|
||||||
------------------
|
------------------
|
||||||
|
@ -186,8 +198,13 @@ execute bit in the permissions field, a verified hash of the file
|
||||||
contents to detect potential code tampering, or file system path
|
contents to detect potential code tampering, or file system path
|
||||||
restrictions. These are an important security mechanism for ensuring
|
restrictions. These are an important security mechanism for ensuring
|
||||||
that only code that has been approved for a given environment is
|
that only code that has been approved for a given environment is
|
||||||
executed. Currently, Python has no way to integrate with operating
|
executed.
|
||||||
system support when launching scripts or importing modules.
|
|
||||||
|
Most kernels offer ways to restrict or audit binaries loaded and executed
|
||||||
|
by the kernel. File types owned by Python appear as regular data and
|
||||||
|
these features do not apply. This open hook allows Python embedders to
|
||||||
|
integrate with operating system support when launching scripts or
|
||||||
|
importing Python code.
|
||||||
|
|
||||||
The new public C API for the verified open hook is::
|
The new public C API for the verified open hook is::
|
||||||
|
|
||||||
|
@ -309,8 +326,8 @@ see which operations provide audit events.
|
||||||
``PySys_AddAuditHook``, ``sys.addaudithook``, "", "Detect when new
|
``PySys_AddAuditHook``, ``sys.addaudithook``, "", "Detect when new
|
||||||
audit hooks are being added.
|
audit hooks are being added.
|
||||||
"
|
"
|
||||||
``PyFile_SetOpenCodeHook``, ``setopencodehook``, "", "
|
``PyFile_SetOpenCodeHook``, ``cpython.PyFile_SetOpenCodeHook``, "
|
||||||
Detects any attempt to set the ``open_code`` hook.
|
", "Detects any attempt to set the ``open_code`` hook.
|
||||||
"
|
"
|
||||||
"``compile``, ``exec``, ``eval``, ``PyAst_CompileString``,
|
"``compile``, ``exec``, ``eval``, ``PyAst_CompileString``,
|
||||||
``PyAST_obj2mod``", ``compile``, "``(code, filename_or_none)``", "
|
``PyAST_obj2mod``", ``compile``, "``(code, filename_or_none)``", "
|
||||||
|
@ -328,9 +345,9 @@ see which operations provide audit events.
|
||||||
file. All arguments other than the module name may be ``None`` if
|
file. All arguments other than the module name may be ``None`` if
|
||||||
they are not used or available.
|
they are not used or available.
|
||||||
"
|
"
|
||||||
"``open``", ``open``, "``(path, mode, flags)``", "Detect when a file
|
"``open``", ``io.open``, "``(path, mode, flags)``", "Detect when a
|
||||||
is about to be opened. *path* and *mode* are the usual parameters to
|
file is about to be opened. *path* and *mode* are the usual parameters
|
||||||
``open`` if available, while *flags* is provided instead of *mode*
|
to ``open`` if available, while *flags* is provided instead of *mode*
|
||||||
in some cases.
|
in some cases.
|
||||||
"
|
"
|
||||||
``PyEval_SetProfile``, ``sys.setprofile``, "", "Detect when code is
|
``PyEval_SetProfile``, ``sys.setprofile``, "", "Detect when code is
|
||||||
|
@ -400,9 +417,9 @@ see which operations provide audit events.
|
||||||
"
|
"
|
||||||
"``socket.bind``, ``socket.connect``, ``socket.connect_ex``,
|
"``socket.bind``, ``socket.connect``, ``socket.connect_ex``,
|
||||||
``socket.getaddrinfo``, ``socket.getnameinfo``, ``socket.sendmsg``,
|
``socket.getaddrinfo``, ``socket.getnameinfo``, ``socket.sendmsg``,
|
||||||
``socket.sendto``", ``socket.address``, "``(address,)``", "Detect
|
``socket.sendto``", ``socket.address``, "``(socket, address,)``", "
|
||||||
access to network resources. The address is unmodified from the
|
Detect access to network resources. The address is unmodified from
|
||||||
original call.
|
the original call.
|
||||||
"
|
"
|
||||||
"``member_get``, ``func_get_code``, ``func_get_[kw]defaults``
|
"``member_get``, ``func_get_code``, ``func_get_[kw]defaults``
|
||||||
",``object.__getattr__``,"``(object, attr)``","Detect access to
|
",``object.__getattr__``,"``(object, attr)``","Detect access to
|
||||||
|
|
Loading…
Reference in New Issue