]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-43762: Add audit events for loading of sqlite3 extensions (GH-25246)
authorErlend Egeberg Aasland <erlend.aasland@innova.no>
Mon, 26 Apr 2021 23:16:46 +0000 (01:16 +0200)
committerGitHub <noreply@github.com>
Mon, 26 Apr 2021 23:16:46 +0000 (00:16 +0100)
Doc/library/sqlite3.rst
Doc/whatsnew/3.10.rst
Lib/test/audit-tests.py
Lib/test/test_audit.py
Misc/NEWS.d/next/Security/2021-04-07-12-57-41.bpo-43762.7lMtpT.rst [new file with mode: 0644]
Modules/_sqlite/connection.c
Modules/_sqlite/module.c

index 6bdf4ed0d81bcc7add804236b9a939e82b1978ed..d0f28db12fda16e59a75deec1a5290dc48093e49 100644 (file)
@@ -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
index 1d9c03c439f335a42767539f43f2222e9e275456..91ad8ec1adb6ebdc5e1f5e7a747ad42196222be1 100644 (file)
@@ -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
 ---
 
index 2addf9762eae49780ef0a3febb67d0465e247a84..ed42451b8f08af29bc36d47e66091c72c20ff625 100644 (file)
@@ -359,6 +359,27 @@ def test_http_client():
         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
 
index 456a5daceb9f10a867fc37459f95769040002fe0..4ba62c408526d35f2325952c8e5252ca6c8274ef 100644 (file)
@@ -130,6 +130,7 @@ class AuditTest(unittest.TestCase):
             ["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 @@ class AuditTest(unittest.TestCase):
             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 (file)
index 0000000..aa39265
--- /dev/null
@@ -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.
index 150291cb72396d05a0e7ae34cc49b54f73c7b8e3..5f8e41b6169a7651d851adca7bc48694582046ba 100644 (file)
@@ -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;
     }
index 8dbfa7b38a1f9c4196e64aa53f9ca9353560d19e..2f323fcd00141ffec41a1431a29f1f40163939be 100644 (file)
@@ -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;
 }