New submission from tehybel: The first issue is a type confusion which resides in the sqlite3 module, in the file connection.c. The function pysqlite_connection_cursor takes an optional argument, a factory callable:
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 pysqlite_Cursor without performing any type checking: 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 --with-pydebug enabled: --- 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. 0x00007ffff6496ad8 in pysqlite_connection_cursor (self=0x7ffff68cc370, args=<optimized out>, kwargs=<optimized out>) at /home/xx/Python-3.5.2/Modules/_sqlite/connection.c:322 warning: Source file is more recent than executable. 322 Py_XSETREF(((pysqlite_Cursor *)cursor)->row_factory, self->row_factory); (gdb) p cursor $13 = (PyObject *) 0xa46b90 (gdb) p self->row_factory $14 = (PyObject *) 0x8d05f0 <small_ints+816> (gdb) x/3i $pc => 0x7ffff6496ad8 <pysqlite_connection_cursor+221>: mov rax,QWORD PTR [rdi+0x10] 0x7ffff6496adc <pysqlite_connection_cursor+225>: sub rax,0x1 0x7ffff6496ae0 <pysqlite_connection_cursor+229>: mov QWORD PTR [rdi+0x10],rax (gdb) p $rdi $15 = 0x4141414141414141 An arbitrary word in memory is decremented. ------ The second issue exists in the function pysqlite_connection_set_isolation_level which resides in /Modules/_sqlite/connection.c. It can result in memory getting freed multiple times. The problem is that the variable self->isolation_level is not cleared before being DECREF'd. 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 self->isolation_level's __del__ method. That code could then call pysqlite_connection_set_isolation_level again, which would trigger another Py_XDECREF call on the same self->isolation_level, which can thus be freed an arbitrary number of times. 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 Starting program: /home/xx/Python-3.5.2/python ./poc6.py Program received signal SIGSEGV, Segmentation fault. _Py_ForgetReference (op=op@entry=0x7ffff6d81b80) at Objects/object.c:1757 1757 if (op == &refchain || (gdb) bt #0 _Py_ForgetReference (op=op@entry=0x7ffff6d81b80) at Objects/object.c:1757 #1 0x000000000049f8c0 in _Py_Dealloc (op=0x7ffff6d81b80) at Objects/object.c:1785 #2 0x000000000046ced8 in method_dealloc (im=im@entry=0x7ffff7f25de8) at Objects/classobject.c:198 #3 0x000000000049f8c5 in _Py_Dealloc (op=op@entry=0x7ffff7f25de8) at Objects/object.c:1786 ... ---------- components: Extension Modules messages: 273659 nosy: ghaering, tehybel priority: normal severity: normal status: open title: sqlite3 type confusion and multiple frees versions: Python 2.7, Python 3.5 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue27861> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com