Skip to content

Commit c923da1

Browse files
miss-islingtonserhiy-storchaka
authored andcommitted
[3.6] bpo-30058: Fixed buffer overflow in select.kqueue.control(). (GH-1095) (#3973)
(cherry picked from commit de07210)
1 parent f8d42ea commit c923da1

3 files changed

Lines changed: 38 additions & 16 deletions

File tree

Lib/test/test_kqueue.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,30 @@ def testPair(self):
208208
b.close()
209209
kq.close()
210210

211+
def test_issue30058(self):
212+
# changelist must be an iterable
213+
kq = select.kqueue()
214+
a, b = socket.socketpair()
215+
ev = select.kevent(a, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
216+
217+
kq.control([ev], 0)
218+
# not a list
219+
kq.control((ev,), 0)
220+
# __len__ is not consistent with __iter__
221+
class BadList:
222+
def __len__(self):
223+
return 0
224+
def __iter__(self):
225+
for i in range(100):
226+
yield ev
227+
kq.control(BadList(), 0)
228+
# doesn't have __len__
229+
kq.control(iter([ev]), 0)
230+
231+
a.close()
232+
b.close()
233+
kq.close()
234+
211235
def test_close(self):
212236
open_file = open(__file__, "rb")
213237
self.addCleanup(open_file.close)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed buffer overflow in select.kqueue.control().

Modules/selectmodule.c

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,7 +2103,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
21032103
int i = 0;
21042104
PyObject *otimeout = NULL;
21052105
PyObject *ch = NULL;
2106-
PyObject *it = NULL, *ei = NULL;
2106+
PyObject *seq = NULL, *ei = NULL;
21072107
PyObject *result = NULL;
21082108
struct kevent *evl = NULL;
21092109
struct kevent *chl = NULL;
@@ -2149,37 +2149,34 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
21492149
}
21502150

21512151
if (ch != NULL && ch != Py_None) {
2152-
it = PyObject_GetIter(ch);
2153-
if (it == NULL) {
2154-
PyErr_SetString(PyExc_TypeError,
2155-
"changelist is not iterable");
2152+
seq = PySequence_Fast(ch, "changelist is not iterable");
2153+
if (seq == NULL) {
21562154
return NULL;
21572155
}
2158-
nchanges = PyObject_Size(ch);
2159-
if (nchanges < 0) {
2156+
if (PySequence_Fast_GET_SIZE(seq) > INT_MAX) {
2157+
PyErr_SetString(PyExc_OverflowError,
2158+
"changelist is too long");
21602159
goto error;
21612160
}
2161+
nchanges = (int)PySequence_Fast_GET_SIZE(seq);
21622162

21632163
chl = PyMem_New(struct kevent, nchanges);
21642164
if (chl == NULL) {
21652165
PyErr_NoMemory();
21662166
goto error;
21672167
}
2168-
i = 0;
2169-
while ((ei = PyIter_Next(it)) != NULL) {
2168+
for (i = 0; i < nchanges; ++i) {
2169+
ei = PySequence_Fast_GET_ITEM(seq, i);
21702170
if (!kqueue_event_Check(ei)) {
2171-
Py_DECREF(ei);
21722171
PyErr_SetString(PyExc_TypeError,
21732172
"changelist must be an iterable of "
21742173
"select.kevent objects");
21752174
goto error;
2176-
} else {
2177-
chl[i++] = ((kqueue_event_Object *)ei)->e;
21782175
}
2179-
Py_DECREF(ei);
2176+
chl[i] = ((kqueue_event_Object *)ei)->e;
21802177
}
2178+
Py_CLEAR(seq);
21812179
}
2182-
Py_CLEAR(it);
21832180

21842181
/* event list */
21852182
if (nevents) {
@@ -2247,15 +2244,15 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
22472244
PyMem_Free(chl);
22482245
PyMem_Free(evl);
22492246
Py_XDECREF(result);
2250-
Py_XDECREF(it);
2247+
Py_XDECREF(seq);
22512248
return NULL;
22522249
}
22532250

22542251
PyDoc_STRVAR(kqueue_queue_control_doc,
22552252
"control(changelist, max_events[, timeout=None]) -> eventlist\n\
22562253
\n\
22572254
Calls the kernel kevent function.\n\
2258-
- changelist must be a list of kevent objects describing the changes\n\
2255+
- changelist must be an iterable of kevent objects describing the changes\n\
22592256
to be made to the kernel's watch list or None.\n\
22602257
- max_events lets you specify the maximum number of events that the\n\
22612258
kernel will return.\n\

0 commit comments

Comments
 (0)