summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Hileman <lunixbochs@gmail.com>2021-04-29 23:15:55 (GMT)
committerGitHub <noreply@github.com>2021-04-29 23:15:55 (GMT)
commit9a2c2a9ec3140b6c54c9ef9d994311f114128ee3 (patch)
treefbc87fa594de1ab3f8151dc74786add7eac3e1b3
parent088a15c49d99ecb4c3bef93f8f40dd513c6cae3b (diff)
downloadcpython-9a2c2a9ec3140b6c54c9ef9d994311f114128ee3.zip
cpython-9a2c2a9ec3140b6c54c9ef9d994311f114128ee3.tar.gz
cpython-9a2c2a9ec3140b6c54c9ef9d994311f114128ee3.tar.bz2
bpo-42800: add audit hooks for f_code and tb_frame (GH-24182)
Accessing the following attributes will now fire PEP 578 style audit hooks as ("object.__getattr__", obj, name): * PyTracebackObject: tb_frame * PyFrameObject: f_code * PyGenObject: gi_code, gi_frame * PyCoroObject: cr_code, cr_frame * PyAsyncGenObject: ag_code, ag_frame Add an AUDIT_READ attribute flag aliased to READ_RESTRICTED. Update obsolete flag documentation.
-rw-r--r--Doc/extending/newtypes.rst15
-rw-r--r--Doc/library/audit_events.rst2
-rw-r--r--Doc/library/stdtypes.rst3
-rw-r--r--Doc/reference/datamodel.rst6
-rw-r--r--Include/structmember.h1
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS.d/next/Security/2021-01-09-17-07-36.bpo-42800._dtZvW.rst1
-rw-r--r--Objects/descrobject.c2
-rw-r--r--Objects/frameobject.c2
-rw-r--r--Objects/genobject.c12
-rw-r--r--Python/traceback.c2
11 files changed, 32 insertions, 15 deletions
diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst
index c078476..545390c 100644
--- a/Doc/extending/newtypes.rst
+++ b/Doc/extending/newtypes.rst
@@ -287,18 +287,23 @@ combined using bitwise-OR.
+===========================+==============================================+
| :const:`READONLY` | Never writable. |
+---------------------------+----------------------------------------------+
-| :const:`READ_RESTRICTED` | Not readable in restricted mode. |
-+---------------------------+----------------------------------------------+
-| :const:`WRITE_RESTRICTED` | Not writable in restricted mode. |
-+---------------------------+----------------------------------------------+
-| :const:`RESTRICTED` | Not readable or writable in restricted mode. |
+| :const:`AUDIT_READ` | Emit an ``object.__getattr__`` |
+| | :ref:`audit events <audit-events>` before |
+| | reading. |
+---------------------------+----------------------------------------------+
+.. versionchanged:: 3.10
+ :const:`RESTRICTED`, :const:`READ_RESTRICTED` and :const:`WRITE_RESTRICTED`
+ are deprecated. However, :const:`READ_RESTRICTED` is an alias for
+ :const:`AUDIT_READ`, so fields that specify either :const:`RESTRICTED` or
+ :const:`READ_RESTRICTED` will also raise an audit event.
+
.. index::
single: READONLY
single: READ_RESTRICTED
single: WRITE_RESTRICTED
single: RESTRICTED
+ single: AUDIT_READ
An interesting advantage of using the :c:member:`~PyTypeObject.tp_members` table to build
descriptors that are used at runtime is that any attribute defined this way can
diff --git a/Doc/library/audit_events.rst b/Doc/library/audit_events.rst
index 367d56e..8227a79 100644
--- a/Doc/library/audit_events.rst
+++ b/Doc/library/audit_events.rst
@@ -7,7 +7,7 @@ Audit events table
This table contains all events raised by :func:`sys.audit` or
:c:func:`PySys_Audit` calls throughout the CPython runtime and the
-standard library. These calls were added in 3.8.0 or later.
+standard library. These calls were added in 3.8.0 or later (see :pep:`578`).
See :func:`sys.addaudithook` and :c:func:`PySys_AddAuditHook` for
information on handling these events.
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index b83d0d8..c4e6b4d 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -5195,6 +5195,9 @@ environment. Code objects are returned by the built-in :func:`compile` function
and can be extracted from function objects through their :attr:`__code__`
attribute. See also the :mod:`code` module.
+Accessing ``__code__`` raises an :ref:`auditing event <auditing>`
+``object.__getattr__`` with arguments ``obj`` and ``"__code__"``.
+
.. index::
builtin: exec
builtin: eval
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 1697330..3a812eb 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1005,6 +1005,9 @@ Internal types
:attr:`f_lasti` gives the precise instruction (this is an index into the
bytecode string of the code object).
+ Accessing ``f_code`` raises an :ref:`auditing event <auditing>`
+ ``object.__getattr__`` with arguments ``obj`` and ``"f_code"``.
+
.. index::
single: f_trace (frame attribute)
single: f_trace_lines (frame attribute)
@@ -1089,6 +1092,9 @@ Internal types
:keyword:`try` statement with no matching except clause or with a
finally clause.
+ Accessing ``tb_frame`` raises an :ref:`auditing event <auditing>`
+ ``object.__getattr__`` with arguments ``obj`` and ``"tb_frame"``.
+
.. index::
single: tb_next (traceback attribute)
diff --git a/Include/structmember.h b/Include/structmember.h
index b54f708..955edd3 100644
--- a/Include/structmember.h
+++ b/Include/structmember.h
@@ -62,6 +62,7 @@ typedef struct PyMemberDef {
#define PY_WRITE_RESTRICTED 4
#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED)
+#define AUDIT_READ READ_RESTRICTED
/* Current API, use this */
PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *);
diff --git a/Misc/ACKS b/Misc/ACKS
index a18ddc6..99d39b5 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -723,6 +723,7 @@ Kevan Heydon
Wouter van Heyst
Kelsey Hightower
Jason Hildebrand
+Ryan Hileman
Aaron Hill
Joel Hillacre
Richie Hindle
diff --git a/Misc/NEWS.d/next/Security/2021-01-09-17-07-36.bpo-42800._dtZvW.rst b/Misc/NEWS.d/next/Security/2021-01-09-17-07-36.bpo-42800._dtZvW.rst
new file mode 100644
index 0000000..d01c0c3
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2021-01-09-17-07-36.bpo-42800._dtZvW.rst
@@ -0,0 +1 @@
+Audit hooks are now fired for frame.f_code, traceback.tb_frame, and generator code/frame attribute access.
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 35fbffd..297b852 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -164,7 +164,7 @@ member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type)
if (descr_check((PyDescrObject *)descr, obj, &res))
return res;
- if (descr->d_member->flags & READ_RESTRICTED) {
+ if (descr->d_member->flags & AUDIT_READ) {
if (PySys_Audit("object.__getattr__", "Os",
obj ? obj : Py_None, descr->d_member->name) < 0) {
return NULL;
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 5920ed8..5c33746 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -13,7 +13,7 @@
static PyMemberDef frame_memberlist[] = {
{"f_back", T_OBJECT, OFF(f_back), READONLY},
- {"f_code", T_OBJECT, OFF(f_code), READONLY},
+ {"f_code", T_OBJECT, OFF(f_code), READONLY|AUDIT_READ},
{"f_builtins", T_OBJECT, OFF(f_builtins), READONLY},
{"f_globals", T_OBJECT, OFF(f_globals), READONLY},
{"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0},
diff --git a/Objects/genobject.c b/Objects/genobject.c
index b02a558..a922d45 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -741,8 +741,8 @@ static PyGetSetDef gen_getsetlist[] = {
};
static PyMemberDef gen_memberlist[] = {
- {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY},
- {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY},
+ {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY|AUDIT_READ},
+ {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|AUDIT_READ},
{NULL} /* Sentinel */
};
@@ -978,8 +978,8 @@ static PyGetSetDef coro_getsetlist[] = {
};
static PyMemberDef coro_memberlist[] = {
- {"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY},
- {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY},
+ {"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY|AUDIT_READ},
+ {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|AUDIT_READ},
{"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin), READONLY},
{NULL} /* Sentinel */
};
@@ -1360,10 +1360,10 @@ static PyGetSetDef async_gen_getsetlist[] = {
};
static PyMemberDef async_gen_memberlist[] = {
- {"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), READONLY},
+ {"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), READONLY|AUDIT_READ},
{"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async),
READONLY},
- {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY},
+ {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY|AUDIT_READ},
{NULL} /* Sentinel */
};
diff --git a/Python/traceback.c b/Python/traceback.c
index 6c0cdfa..5fa6e50 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -147,7 +147,7 @@ static PyMethodDef tb_methods[] = {
};
static PyMemberDef tb_memberlist[] = {
- {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY},
+ {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY|AUDIT_READ},
{"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
{"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
{NULL} /* Sentinel */