Skip to content

Commit 9aa6024

Browse files
[2.7] bpo-30058: Fixed buffer overflow in select.kqueue.control(). (GH-1095). (#3976)
(cherry picked from commit de07210)
1 parent 356b680 commit 9aa6024

File tree

3 files changed

+38
-16
lines changed

3 files changed

+38
-16
lines changed

‎Lib/test/test_kqueue.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,30 @@ def testPair(self):
205205
b.close()
206206
kq.close()
207207

208+
def test_issue30058(self):
209+
# changelist must be an iterable
210+
kq = select.kqueue()
211+
a, b = socket.socketpair()
212+
ev = select.kevent(a, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
213+
214+
kq.control([ev], 0)
215+
# not a list
216+
kq.control((ev,), 0)
217+
# __len__ is not consistent with __iter__
218+
class BadList:
219+
def __len__(self):
220+
return 0
221+
def __iter__(self):
222+
for i in range(100):
223+
yield ev
224+
kq.control(BadList(), 0)
225+
# doesn't have __len__
226+
kq.control(iter([ev]), 0)
227+
228+
a.close()
229+
b.close()
230+
kq.close()
231+
208232
def test_main():
209233
test_support.run_unittest(TestKQueue)
210234

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
@@ -1537,7 +1537,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
15371537
int i = 0;
15381538
PyObject *otimeout = NULL;
15391539
PyObject *ch = NULL;
1540-
PyObject *it = NULL, *ei = NULL;
1540+
PyObject *seq = NULL, *ei = NULL;
15411541
PyObject *result = NULL;
15421542
struct kevent *evl = NULL;
15431543
struct kevent *chl = NULL;
@@ -1593,37 +1593,34 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
15931593
}
15941594

15951595
if (ch != NULL && ch != Py_None) {
1596-
it = PyObject_GetIter(ch);
1597-
if (it == NULL) {
1598-
PyErr_SetString(PyExc_TypeError,
1599-
"changelist is not iterable");
1596+
seq = PySequence_Fast(ch, "changelist is not iterable");
1597+
if (seq == NULL) {
16001598
return NULL;
16011599
}
1602-
nchanges = PyObject_Size(ch);
1603-
if (nchanges < 0) {
1600+
if (PySequence_Fast_GET_SIZE(seq) > INT_MAX) {
1601+
PyErr_SetString(PyExc_OverflowError,
1602+
"changelist is too long");
16041603
goto error;
16051604
}
1605+
nchanges = (int)PySequence_Fast_GET_SIZE(seq);
16061606

16071607
chl = PyMem_New(struct kevent, nchanges);
16081608
if (chl == NULL) {
16091609
PyErr_NoMemory();
16101610
goto error;
16111611
}
1612-
i = 0;
1613-
while ((ei = PyIter_Next(it)) != NULL) {
1612+
for (i = 0; i < nchanges; ++i) {
1613+
ei = PySequence_Fast_GET_ITEM(seq, i);
16141614
if (!kqueue_event_Check(ei)) {
1615-
Py_DECREF(ei);
16161615
PyErr_SetString(PyExc_TypeError,
16171616
"changelist must be an iterable of "
16181617
"select.kevent objects");
16191618
goto error;
1620-
} else {
1621-
chl[i++] = ((kqueue_event_Object *)ei)->e;
16221619
}
1623-
Py_DECREF(ei);
1620+
chl[i] = ((kqueue_event_Object *)ei)->e;
16241621
}
1622+
Py_CLEAR(seq);
16251623
}
1626-
Py_CLEAR(it);
16271624

16281625
/* event list */
16291626
if (nevents) {
@@ -1667,15 +1664,15 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
16671664
PyMem_Free(chl);
16681665
PyMem_Free(evl);
16691666
Py_XDECREF(result);
1670-
Py_XDECREF(it);
1667+
Py_XDECREF(seq);
16711668
return NULL;
16721669
}
16731670

16741671
PyDoc_STRVAR(kqueue_queue_control_doc,
16751672
"control(changelist, max_events[, timeout=None]) -> eventlist\n\
16761673
\n\
16771674
Calls the kernel kevent function.\n\
1678-
- changelist must be a list of kevent objects describing the changes\n\
1675+
- changelist must be an iterable of kevent objects describing the changes\n\
16791676
to be made to the kernel's watch list or None.\n\
16801677
- max_events lets you specify the maximum number of events that the\n\
16811678
kernel will return.\n\

0 commit comments

Comments
 (0)