Commit 9aa60245 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

[2.7] bpo-30058: Fixed buffer overflow in select.kqueue.control(). (GH-1095). (#3976)

(cherry picked from commit de072100)
parent 356b6802
...@@ -205,6 +205,30 @@ class TestKQueue(unittest.TestCase): ...@@ -205,6 +205,30 @@ class TestKQueue(unittest.TestCase):
b.close() b.close()
kq.close() kq.close()
def test_issue30058(self):
# changelist must be an iterable
kq = select.kqueue()
a, b = socket.socketpair()
ev = select.kevent(a, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
kq.control([ev], 0)
# not a list
kq.control((ev,), 0)
# __len__ is not consistent with __iter__
class BadList:
def __len__(self):
return 0
def __iter__(self):
for i in range(100):
yield ev
kq.control(BadList(), 0)
# doesn't have __len__
kq.control(iter([ev]), 0)
a.close()
b.close()
kq.close()
def test_main(): def test_main():
test_support.run_unittest(TestKQueue) test_support.run_unittest(TestKQueue)
......
Fixed buffer overflow in select.kqueue.control().
...@@ -1537,7 +1537,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) ...@@ -1537,7 +1537,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
int i = 0; int i = 0;
PyObject *otimeout = NULL; PyObject *otimeout = NULL;
PyObject *ch = NULL; PyObject *ch = NULL;
PyObject *it = NULL, *ei = NULL; PyObject *seq = NULL, *ei = NULL;
PyObject *result = NULL; PyObject *result = NULL;
struct kevent *evl = NULL; struct kevent *evl = NULL;
struct kevent *chl = NULL; struct kevent *chl = NULL;
...@@ -1593,37 +1593,34 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) ...@@ -1593,37 +1593,34 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
} }
if (ch != NULL && ch != Py_None) { if (ch != NULL && ch != Py_None) {
it = PyObject_GetIter(ch); seq = PySequence_Fast(ch, "changelist is not iterable");
if (it == NULL) { if (seq == NULL) {
PyErr_SetString(PyExc_TypeError,
"changelist is not iterable");
return NULL; return NULL;
} }
nchanges = PyObject_Size(ch); if (PySequence_Fast_GET_SIZE(seq) > INT_MAX) {
if (nchanges < 0) { PyErr_SetString(PyExc_OverflowError,
"changelist is too long");
goto error; goto error;
} }
nchanges = (int)PySequence_Fast_GET_SIZE(seq);
chl = PyMem_New(struct kevent, nchanges); chl = PyMem_New(struct kevent, nchanges);
if (chl == NULL) { if (chl == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
goto error; goto error;
} }
i = 0; for (i = 0; i < nchanges; ++i) {
while ((ei = PyIter_Next(it)) != NULL) { ei = PySequence_Fast_GET_ITEM(seq, i);
if (!kqueue_event_Check(ei)) { if (!kqueue_event_Check(ei)) {
Py_DECREF(ei);
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"changelist must be an iterable of " "changelist must be an iterable of "
"select.kevent objects"); "select.kevent objects");
goto error; goto error;
} else {
chl[i++] = ((kqueue_event_Object *)ei)->e;
} }
Py_DECREF(ei); chl[i] = ((kqueue_event_Object *)ei)->e;
} }
Py_CLEAR(seq);
} }
Py_CLEAR(it);
/* event list */ /* event list */
if (nevents) { if (nevents) {
...@@ -1667,7 +1664,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) ...@@ -1667,7 +1664,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
PyMem_Free(chl); PyMem_Free(chl);
PyMem_Free(evl); PyMem_Free(evl);
Py_XDECREF(result); Py_XDECREF(result);
Py_XDECREF(it); Py_XDECREF(seq);
return NULL; return NULL;
} }
...@@ -1675,7 +1672,7 @@ PyDoc_STRVAR(kqueue_queue_control_doc, ...@@ -1675,7 +1672,7 @@ PyDoc_STRVAR(kqueue_queue_control_doc,
"control(changelist, max_events[, timeout=None]) -> eventlist\n\ "control(changelist, max_events[, timeout=None]) -> eventlist\n\
\n\ \n\
Calls the kernel kevent function.\n\ Calls the kernel kevent function.\n\
- changelist must be a list of kevent objects describing the changes\n\ - changelist must be an iterable of kevent objects describing the changes\n\
to be made to the kernel's watch list or None.\n\ to be made to the kernel's watch list or None.\n\
- max_events lets you specify the maximum number of events that the\n\ - max_events lets you specify the maximum number of events that the\n\
kernel will return.\n\ kernel will return.\n\
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment