[Python-checkins] cpython (3.4): Issue #27759: Fix selectors incorrectly retain invalid file descriptors.

yury.selivanov python-checkins at python.org
Thu Oct 6 14:06:36 EDT 2016


https://hg.python.org/cpython/rev/8cc1fca83fb8
changeset:   104337:8cc1fca83fb8
branch:      3.4
parent:      103949:ccfea26e6582
user:        Yury Selivanov <yury at magic.io>
date:        Thu Oct 06 14:03:03 2016 -0400
summary:
  Issue #27759: Fix selectors incorrectly retain invalid file descriptors.

(Backported to 3.4 as this bug might be exploited to for DoS)

files:
  Lib/selectors.py           |  26 +++++++++++++++++---------
  Lib/test/test_selectors.py |  23 +++++++++++++++++++++++
  Misc/NEWS                  |   3 +++
  3 files changed, 43 insertions(+), 9 deletions(-)


diff --git a/Lib/selectors.py b/Lib/selectors.py
--- a/Lib/selectors.py
+++ b/Lib/selectors.py
@@ -399,7 +399,11 @@
                 epoll_events |= select.EPOLLIN
             if events & EVENT_WRITE:
                 epoll_events |= select.EPOLLOUT
-            self._epoll.register(key.fd, epoll_events)
+            try:
+                self._epoll.register(key.fd, epoll_events)
+            except BaseException:
+                super().unregister(fileobj)
+                raise
             return key
 
         def unregister(self, fileobj):
@@ -465,14 +469,18 @@
 
         def register(self, fileobj, events, data=None):
             key = super().register(fileobj, events, data)
-            if events & EVENT_READ:
-                kev = select.kevent(key.fd, select.KQ_FILTER_READ,
-                                    select.KQ_EV_ADD)
-                self._kqueue.control([kev], 0, 0)
-            if events & EVENT_WRITE:
-                kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
-                                    select.KQ_EV_ADD)
-                self._kqueue.control([kev], 0, 0)
+            try:
+                if events & EVENT_READ:
+                    kev = select.kevent(key.fd, select.KQ_FILTER_READ,
+                                        select.KQ_EV_ADD)
+                    self._kqueue.control([kev], 0, 0)
+                if events & EVENT_WRITE:
+                    kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
+                                        select.KQ_EV_ADD)
+                    self._kqueue.control([kev], 0, 0)
+            except BaseException:
+                super().unregister(fileobj)
+                raise
             return key
 
         def unregister(self, fileobj):
diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py
--- a/Lib/test/test_selectors.py
+++ b/Lib/test/test_selectors.py
@@ -5,6 +5,7 @@
 import signal
 import socket
 import sys
+import tempfile
 from test import support
 from time import sleep
 import unittest
@@ -447,6 +448,16 @@
 
     SELECTOR = getattr(selectors, 'EpollSelector', None)
 
+    def test_register_file(self):
+        # epoll(7) returns EPERM when given a file to watch
+        s = self.SELECTOR()
+        with tempfile.NamedTemporaryFile() as f:
+            with self.assertRaises(IOError):
+                s.register(f, selectors.EVENT_READ)
+            # the SelectorKey has been removed
+            with self.assertRaises(KeyError):
+                s.get_key(f)
+
 
 @unittest.skipUnless(hasattr(selectors, 'KqueueSelector'),
                      "Test needs selectors.KqueueSelector)")
@@ -454,6 +465,18 @@
 
     SELECTOR = getattr(selectors, 'KqueueSelector', None)
 
+    def test_register_bad_fd(self):
+        # a file descriptor that's been closed should raise an OSError
+        # with EBADF
+        s = self.SELECTOR()
+        bad_f = support.make_bad_fd()
+        with self.assertRaises(OSError) as cm:
+            s.register(bad_f, selectors.EVENT_READ)
+        self.assertEqual(cm.exception.errno, errno.EBADF)
+        # the SelectorKey has been removed
+        with self.assertRaises(KeyError):
+            s.get_key(bad_f)
+
 
 def test_main():
     tests = [DefaultSelectorTestCase, SelectSelectorTestCase,
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -29,6 +29,9 @@
   HTTP_PROXY variable when REQUEST_METHOD environment is set, which indicates
   that the script is in CGI mode.
 
+- Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
+  Patch by Mark Williams.
+
 Tests
 -----
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list