[Python-checkins] [3.6] bpo-30058: Fixed buffer overflow in select.kqueue.control(). (GH-1095) (#3973)

Serhiy Storchaka webhook-mailer at python.org
Thu Oct 12 16:20:46 EDT 2017


https://github.com/python/cpython/commit/c923da188bc055e4f3001a6daf1caf54f2b10e40
commit: c923da188bc055e4f3001a6daf1caf54f2b10e40
branch: 3.6
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: Serhiy Storchaka <storchaka at gmail.com>
date: 2017-10-12T23:20:44+03:00
summary:

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

(cherry picked from commit de072100775cc29e6cd93a75466cecbd1086f258)

files:
A Misc/NEWS.d/next/Library/2017-10-12-19-00-53.bpo-30058.cENtry.rst
M Lib/test/test_kqueue.py
M Modules/selectmodule.c

diff --git a/Lib/test/test_kqueue.py b/Lib/test/test_kqueue.py
index 9f49886878f..1099c759a79 100644
--- a/Lib/test/test_kqueue.py
+++ b/Lib/test/test_kqueue.py
@@ -208,6 +208,30 @@ def testPair(self):
         b.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):
         open_file = open(__file__, "rb")
         self.addCleanup(open_file.close)
diff --git a/Misc/NEWS.d/next/Library/2017-10-12-19-00-53.bpo-30058.cENtry.rst b/Misc/NEWS.d/next/Library/2017-10-12-19-00-53.bpo-30058.cENtry.rst
new file mode 100644
index 00000000000..fa1c8f4e74f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-10-12-19-00-53.bpo-30058.cENtry.rst
@@ -0,0 +1 @@
+Fixed buffer overflow in select.kqueue.control().
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index 07a20c85d76..4a7fe002f0b 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -2103,7 +2103,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
     int i = 0;
     PyObject *otimeout = NULL;
     PyObject *ch = NULL;
-    PyObject *it = NULL, *ei = NULL;
+    PyObject *seq = NULL, *ei = NULL;
     PyObject *result = NULL;
     struct kevent *evl = NULL;
     struct kevent *chl = NULL;
@@ -2149,37 +2149,34 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
     }
 
     if (ch != NULL && ch != Py_None) {
-        it = PyObject_GetIter(ch);
-        if (it == NULL) {
-            PyErr_SetString(PyExc_TypeError,
-                            "changelist is not iterable");
+        seq = PySequence_Fast(ch, "changelist is not iterable");
+        if (seq == NULL) {
             return NULL;
         }
-        nchanges = PyObject_Size(ch);
-        if (nchanges < 0) {
+        if (PySequence_Fast_GET_SIZE(seq) > INT_MAX) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "changelist is too long");
             goto error;
         }
+        nchanges = (int)PySequence_Fast_GET_SIZE(seq);
 
         chl = PyMem_New(struct kevent, nchanges);
         if (chl == NULL) {
             PyErr_NoMemory();
             goto error;
         }
-        i = 0;
-        while ((ei = PyIter_Next(it)) != NULL) {
+        for (i = 0; i < nchanges; ++i) {
+            ei = PySequence_Fast_GET_ITEM(seq, i);
             if (!kqueue_event_Check(ei)) {
-                Py_DECREF(ei);
                 PyErr_SetString(PyExc_TypeError,
                     "changelist must be an iterable of "
                     "select.kevent objects");
                 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 */
     if (nevents) {
@@ -2247,7 +2244,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args)
     PyMem_Free(chl);
     PyMem_Free(evl);
     Py_XDECREF(result);
-    Py_XDECREF(it);
+    Py_XDECREF(seq);
     return NULL;
 }
 
@@ -2255,7 +2252,7 @@ PyDoc_STRVAR(kqueue_queue_control_doc,
 "control(changelist, max_events[, timeout=None]) -> eventlist\n\
 \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\
 - max_events lets you specify the maximum number of events that the\n\
   kernel will return.\n\



More information about the Python-checkins mailing list