]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
authorYury Selivanov <yury@magic.io>
Thu, 6 Oct 2016 18:03:03 +0000 (14:03 -0400)
committerYury Selivanov <yury@magic.io>
Thu, 6 Oct 2016 18:03:03 +0000 (14:03 -0400)
(Backported to 3.4 as this bug might be exploited to for DoS)

Lib/selectors.py
Lib/test/test_selectors.py
Misc/NEWS

index 7b6da298639977fc7a7f12a75817cd9a23b4703f..8936ab665c454288a25d2202e35c5b44818310c4 100644 (file)
@@ -399,7 +399,11 @@ if hasattr(select, 'epoll'):
                 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 @@ if hasattr(select, 'kqueue'):
 
         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):
index 952fda6c69ecd55c9c2ce1b9609c03349572cd61..28cd948d62eab66129c04af8e6a1c7076fe34c68 100644 (file)
@@ -5,6 +5,7 @@ import selectors
 import signal
 import socket
 import sys
+import tempfile
 from test import support
 from time import sleep
 import unittest
@@ -447,6 +448,16 @@ class EpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
 
     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 @@ class KqueueSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
 
     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,
index aad29d98a6a5c9bda0da172a95d984168642f17a..6aeb2ec08a57b8d0f8e9360a976f5360413410a4 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -29,6 +29,9 @@ Library
   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
 -----