Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Description
Enhancement Request:
The current version ofsqlite3.Connection.load_extension() takes in a single parameterpath. However, the underlying C APIsqlite3_load_extension has an additionalentrypoint argument that I think should be added to the Pythonload_extension function.
Currently inconnection.c, the entrypoint parameter is ignored with a null pointer:
cpython/Modules/_sqlite/connection.c
Line 1624 inf2e5a6e
| rc=sqlite3_load_extension(self->db,extension_name,0,&errmsg); |
Pitch
We add a new second optionalentrypoint parameter to theload_extension() Python function. If it is provided, it's passed along to the underlyingsqlite3_load_extension C function as the extension entrypoint.
importsqlite3db=sqlite3.connect(":memory:")db.enable_load_extension(True)# Currently, only a single path argument is supported on load_extension()db.load_extension("./lines0")# In this proposal, an optional 2nd entrypoint parameter would be addeddb.load_extension("./lines0","sqlite3_lines_no_read_init")db.enable_load_extension(False)
I've been buildingseveral SQLite extensions, some of which use different entrypoints to enable/disable security sensitive features. For example, insqlite-lines (A SQLite extension for reading files line-by-lines), there will be a secondary entrypoint calledsqlite3_lines_no_read_init that disables all functions that read the filesystem, for use inDatasette or other security-sensitive environments.
Many of these extensionsare also distributed as Python packages, so any extra customizable APIs for loading SQLite extensions is greatly appreciated!
Workaround
There technically is a workaround for this: A user can use theload_extension() SQL function to load an extension with an entrypoint, like so:
db=sqlite3.connect(":memory:")db.enable_load_extension(True)db.execute("select load_extension(?, ?)", ["path/to/extension","entrypoint"])
However, doing so will circumvent thesqlite3.load_extension auditing event, as that's only trigged on calls to the pythonConnection.load_extension() function.
There's also some limitations to the pure SQLload_extension() function, mentioned here:
The load_extension() function will fail if the extension attempts to modify or delete an SQL function or collating sequence. The extension can add new functions or collating sequences, but cannot modify or delete existing functions or collating sequences because those functions and/or collating sequences might be used elsewhere in the currently running SQL statement. To load an extension that changes or deletes functions or collating sequences, use thesqlite3_load_extension() C-language API.
Source:https://www.sqlite.org/lang_corefunc.html#load_extension
Also in general, it's recommended to avould the SQL load_extension() function altogether:
Security warning: It is recommended that extension loading be enabled using theSQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION method rather than this interface, so theload_extension() SQL function remains disabled. This will prevent SQL injections from giving attackers access to extension loading capabilities.
Source:https://www.sqlite.org/c3ref/enable_load_extension.html
It's also just a little awkward, having to "eject" to SQL to do something that the Python API could readily support.
Linked PRs
Metadata
Metadata
Assignees
Projects
Status