Commit de072100 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

bpo-30058: Fixed buffer overflow in select.kqueue.control(). (#1095)

parent b7cbfe49
...@@ -208,6 +208,30 @@ class TestKQueue(unittest.TestCase): ...@@ -208,6 +208,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_close(self): def test_close(self):
open_file = open(__file__, "rb") open_file = open(__file__, "rb")
self.addCleanup(open_file.close) self.addCleanup(open_file.close)
......
Fixed buffer overflow in select.kqueue.control().
...@@ -2102,7 +2102,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) ...@@ -2102,7 +2102,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;
...@@ -2148,37 +2148,34 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) ...@@ -2148,37 +2148,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) {
...@@ -2246,7 +2243,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) ...@@ -2246,7 +2243,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;
} }
...@@ -2254,7 +2251,7 @@ PyDoc_STRVAR(kqueue_queue_control_doc, ...@@ -2254,7 +2251,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