-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
sqlite3 type confusion and multiple frees #72048
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The first issue is a type confusion which resides in the sqlite3 module, in the if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist,
&factory)) {
return NULL;
} If the factory callable is given, it is called to initialize a cursor: cursor = PyObject_CallFunction(factory, "O", self); After this the cursor, which is a PyObject *, is cast directly to a if (cursor && self->row_factory != Py_None) {
Py_INCREF(self->row_factory);
Py_XSETREF(((pysqlite_Cursor *)cursor)->row_factory, self->row_factory);
} Here is a small script which is tested on Python-3.5.2, 64-bit, with --- begin script --- import sqlite3
conn = sqlite3.connect('poc2.db')
conn.row_factory = 12
conn.cursor(lambda x: "A"*0x10000) --- end script --- When run, this produces a segfault: (gdb) r ./poc2.py Program received signal SIGSEGV, Segmentation fault. An arbitrary word in memory is decremented. ------ The second issue exists in the function pysqlite_connection_set_isolation_level The problem is that the variable self->isolation_level is not cleared before The code looks like this: static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level)
{
...
Py_XDECREF(self->isolation_level);
...
} This call to Py_XDECREF can trigger an arbitrary amount of python code, e.g. via One way to fix this is to use Py_CLEAR instead. Here's a proof-of-concept script which results in a segfault here: --- begin script --- import sqlite3
class S(str):
def __del__(self):
conn.isolation_level = S("B")
conn = sqlite3.connect('poc6.db')
conn.isolation_level = S("A")
conn.isolation_level = "" --- end script --- When run it segfaults here, with Python-3.5.2 and --with-pydebug enabled: (gdb) r ./poc6.py Program received signal SIGSEGV, Segmentation fault. |
For the first issue, the doc says: The cursor method accepts a single optional parameter cursorClass. If supplied, this must be a custom cursor class that extends sqlite3.Cursor. So I think we should check the type and then raise TypeError. For the second issue, it seems it just hits the Py_CLEAR comments. bpo-27861 tries to fix this. Besides, it also alters Connection.cursor's doc since it now does not reflects the implementation. |
Please split bpo-27861.patch into two patches. It would be better if isolation_level wouldn't accept values other than None, "" (empty string), "deferred", "immediate", "exclusive". |
I considered that but don't why decide to preserve it. But now that you mention it, I'll do that later. |
issue27861_conn_cursor.patch tries to solve the first issue. |
issue27861_conn_isolation_level.patch now adds argument type and value check along with eliminating the potential sf. |
Agreed, there are two unrelated bugs. It would be better to discuss separate patches in separate issues. |
Thanks for the comments, Serhiy and palaviv. I left some questions in reply to them. |
About the first bug. Checking that a factory is a subclass of sqlite3.Cursor is not enough. I suppose that a subclass of sqlite3.Cursor with overridden __new__ could pass the check but cause a crash. class BadCursor(sqlite3.Cursor):
def __new__(cls, conn):
return None Docs should be changed as well as the code. As for the second bug, please open a separate issue. This is more complex issue. |
If decide to follow the behaviour of code rather than doc, it's a different story. issue27861_conn_cursor_v2.patch tries to solve the first issue. It now preserve the previous behaviour treating factory as a callable not a cursor type. |
Thanks for the comments Serhiy. v3 now fixs all that. |
LGTM except one style nit. |
It's a trivial personal style choice I think. Do what you want if you'd like to merge it. |
New changeset c046cbb24f98 by Serhiy Storchaka in branch '3.5': New changeset 97dbba8a6d4a by Serhiy Storchaka in branch '2.7': New changeset afcec2d11e9e by Serhiy Storchaka in branch 'default': |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: