]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-42800: add audit hooks for f_code and tb_frame (GH-24182)
authorRyan Hileman <lunixbochs@gmail.com>
Thu, 29 Apr 2021 23:15:55 +0000 (16:15 -0700)
committerGitHub <noreply@github.com>
Thu, 29 Apr 2021 23:15:55 +0000 (00:15 +0100)
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.

Doc/extending/newtypes.rst
Doc/library/audit_events.rst
Doc/library/stdtypes.rst
Doc/reference/datamodel.rst
Include/structmember.h
Misc/ACKS
Misc/NEWS.d/next/Security/2021-01-09-17-07-36.bpo-42800._dtZvW.rst [new file with mode: 0644]
Objects/descrobject.c
Objects/frameobject.c
Objects/genobject.c
Python/traceback.c

index c078476aae80afaafc6055cfe38105cba5a9566a..545390c2e469c250a778a6102e0552c8adc0b61a 100644 (file)
@@ -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
index 367d56e4e37359cd04ee9def5abfb983be568a0f..8227a7955bef8127e03b70faac63bf18bc85e2f6 100644 (file)
@@ -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.
index b83d0d87f587fc3c380dbfca12a213b7ba4f06f5..c4e6b4d1186d0458359e25648b40a743c2686e0d 100644 (file)
@@ -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
index 1697330cb9153b7bf061c01d4a95c2f02fc887be..3a812eb21471a0d8267ce1611f7cf995ddefa98a 100644 (file)
@@ -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)
 
index b54f7081f458dd9c33a524874b4b3e90c3bbf954..955edd31c4ca54bbdb70174740784be65c76e7d0 100644 (file)
@@ -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 *);
index a18ddc65b79e8b97dc3390aeacddc7905664dc6e..99d39b5f38fd7678a76950a792bf2a2f8324d47e 100644 (file)
--- 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 (file)
index 0000000..d01c0c3
--- /dev/null
@@ -0,0 +1 @@
+Audit hooks are now fired for frame.f_code, traceback.tb_frame, and generator code/frame attribute access.
index 35fbffd914a94c72eafdde2e3c505ecc4ed694b0..297b8528a648d171eb2f33b817c8f83ccf1cf856 100644 (file)
@@ -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;
index 5920ed86fd923083af5648fd7f692c2fc32062e5..5c337467155f42d911fac36835177dd581f52372 100644 (file)
@@ -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},
index b02a5581a4042c42469612da3947ad99d7d0b2e0..a922d45de10a090158acda715f2ff4e3aed162bc 100644 (file)
@@ -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 */
 };
 
index 6c0cdfa7e7a2c1ef6b656574b765c2e56481eb31..5fa6e50d33b745572bbc5a9f8911be49c24b3439 100644 (file)
@@ -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 */