[Python-checkins] bpo-43762: Add audit events for loading of sqlite3 extensions (GH-25246)

zooba webhook-mailer at python.org
Mon Apr 26 19:16:50 EDT 2021


https://github.com/python/cpython/commit/7244c0060dc3ef909f34b0791c3e7490b0340d5e
commit: 7244c0060dc3ef909f34b0791c3e7490b0340d5e
branch: master
author: Erlend Egeberg Aasland <erlend.aasland at innova.no>
committer: zooba <steve.dower at microsoft.com>
date: 2021-04-27T00:16:46+01:00
summary:

bpo-43762: Add audit events for loading of sqlite3 extensions (GH-25246)

files:
A Misc/NEWS.d/next/Security/2021-04-07-12-57-41.bpo-43762.7lMtpT.rst
M Doc/library/sqlite3.rst
M Doc/whatsnew/3.10.rst
M Lib/test/audit-tests.py
M Lib/test/test_audit.py
M Modules/_sqlite/connection.c
M Modules/_sqlite/module.c

diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
index 6bdf4ed0d81bcc..d0f28db12fda16 100644
--- a/Doc/library/sqlite3.rst
+++ b/Doc/library/sqlite3.rst
@@ -225,6 +225,7 @@ Module functions and constants
    be found in the `SQLite URI documentation <https://www.sqlite.org/uri.html>`_.
 
    .. audit-event:: sqlite3.connect database sqlite3.connect
+   .. audit-event:: sqlite3.connect/handle connection_handle sqlite3.connect
 
    .. versionchanged:: 3.4
       Added the *uri* parameter.
@@ -232,6 +233,9 @@ Module functions and constants
    .. versionchanged:: 3.7
       *database* can now also be a :term:`path-like object`, not only a string.
 
+   .. versionchanged:: 3.10
+      Added the ``sqlite3.connect/handle`` auditing event.
+
 
 .. function:: register_converter(typename, callable)
 
@@ -467,8 +471,13 @@ Connection Objects
 
       Loadable extensions are disabled by default. See [#f1]_.
 
+      .. audit-event:: sqlite3.enable_load_extension connection,enabled sqlite3.enable_load_extension
+
       .. versionadded:: 3.2
 
+      .. versionchanged:: 3.10
+         Added the ``sqlite3.enable_load_extension`` auditing event.
+
       .. literalinclude:: ../includes/sqlite3/load_extension.py
 
    .. method:: load_extension(path)
@@ -479,8 +488,13 @@ Connection Objects
 
       Loadable extensions are disabled by default. See [#f1]_.
 
+      .. audit-event:: sqlite3.load_extension connection,path sqlite3.load_extension
+
       .. versionadded:: 3.2
 
+      .. versionchanged:: 3.10
+         Added the ``sqlite3.load_extension`` auditing event.
+
    .. attribute:: row_factory
 
       You can change this attribute to a callable that accepts the cursor and the
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 1d9c03c439f335..91ad8ec1adb6eb 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -1080,6 +1080,14 @@ ssl
 Add a *timeout* parameter to the :func:`ssl.get_server_certificate` function.
 (Contributed by Zackery Spytz in :issue:`31870`.)
 
+sqlite3
+-------
+
+Add audit events for :func:`~sqlite3.connect/handle`,
+:meth:`~sqlite3.Connection.enable_load_extension`, and
+:meth:`~sqlite3.Connection.load_extension`.
+(Contributed by Erlend E. Aasland in :issue:`43762`.)
+
 sys
 ---
 
diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py
index 2addf9762eae49..ed42451b8f08af 100644
--- a/Lib/test/audit-tests.py
+++ b/Lib/test/audit-tests.py
@@ -359,6 +359,27 @@ def hook(event, args):
         conn.close()
 
 
+def test_sqlite3():
+    import sqlite3
+
+    def hook(event, *args):
+        if event.startswith("sqlite3."):
+            print(event, *args)
+
+    sys.addaudithook(hook)
+    cx = sqlite3.connect(":memory:")
+
+    # Configured without --enable-loadable-sqlite-extensions
+    if hasattr(sqlite3.Connection, "enable_load_extension"):
+        cx.enable_load_extension(False)
+        try:
+            cx.load_extension("test")
+        except sqlite3.OperationalError:
+            pass
+        else:
+            raise RuntimeError("Expected sqlite3.load_extension to fail")
+
+
 if __name__ == "__main__":
     from test.support import suppress_msvcrt_asserts
 
diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py
index 456a5daceb9f10..4ba62c408526d3 100644
--- a/Lib/test/test_audit.py
+++ b/Lib/test/test_audit.py
@@ -130,6 +130,7 @@ def test_gc(self):
             ["gc.get_objects", "gc.get_referrers", "gc.get_referents"]
         )
 
+
     def test_http(self):
         import_helper.import_module("http.client")
         returncode, events, stderr = self.run_python("test_http_client")
@@ -145,5 +146,27 @@ def test_http(self):
             self.assertIn('HTTP', events[1][2])
 
 
+    def test_sqlite3(self):
+        try:
+            import sqlite3
+        except ImportError:
+            return
+        returncode, events, stderr = self.run_python("test_sqlite3")
+        if returncode:
+            self.fail(stderr)
+
+        if support.verbose:
+            print(*events, sep='\n')
+        actual = [ev[0] for ev in events]
+        expected = ["sqlite3.connect", "sqlite3.connect/handle"]
+
+        if hasattr(sqlite3.Connection, "enable_load_extension"):
+            expected += [
+                "sqlite3.enable_load_extension",
+                "sqlite3.load_extension",
+            ]
+        self.assertEqual(actual, expected)
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Security/2021-04-07-12-57-41.bpo-43762.7lMtpT.rst b/Misc/NEWS.d/next/Security/2021-04-07-12-57-41.bpo-43762.7lMtpT.rst
new file mode 100644
index 00000000000000..aa392656807e11
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2021-04-07-12-57-41.bpo-43762.7lMtpT.rst
@@ -0,0 +1,3 @@
+Add audit events for :func:`sqlite3.connect/handle`,
+:meth:`sqlite3.Connection.enable_load_extension`, and
+:meth:`sqlite3.Connection.load_extension`. Patch by Erlend E. Aasland.
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index 150291cb72396d..5f8e41b6169a76 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -1154,6 +1154,11 @@ pysqlite_connection_enable_load_extension_impl(pysqlite_Connection *self,
 {
     int rc;
 
+    if (PySys_Audit("sqlite3.enable_load_extension",
+                    "OO", self, onoff ? Py_True : Py_False) < 0) {
+        return NULL;
+    }
+
     if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
         return NULL;
     }
@@ -1185,6 +1190,10 @@ pysqlite_connection_load_extension_impl(pysqlite_Connection *self,
     int rc;
     char* errmsg;
 
+    if (PySys_Audit("sqlite3.load_extension", "Os", self, extension_name) < 0) {
+        return NULL;
+    }
+
     if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
         return NULL;
     }
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index 8dbfa7b38a1f9c..2f323fcd00141f 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -96,6 +96,14 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
     }
 
     result = PyObject_Call(factory, args, kwargs);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    if (PySys_Audit("sqlite3.connect/handle", "O", self) < 0) {
+        Py_DECREF(result);
+        return NULL;
+    }
 
     return result;
 }



More information about the Python-checkins mailing list