Issue #27759: Fix selectors incorrectly retain invalid file descriptors.

(Backported to 3.4 as this bug might be exploited to for DoS)
This commit is contained in:
Yury Selivanov 2016-10-06 14:03:03 -04:00
parent 26d998cfdd
commit cb9424f643
3 changed files with 43 additions and 9 deletions

View File

@ -399,7 +399,11 @@ def register(self, fileobj, events, data=None):
epoll_events |= select.EPOLLIN epoll_events |= select.EPOLLIN
if events & EVENT_WRITE: if events & EVENT_WRITE:
epoll_events |= select.EPOLLOUT 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 return key
def unregister(self, fileobj): def unregister(self, fileobj):
@ -465,14 +469,18 @@ def fileno(self):
def register(self, fileobj, events, data=None): def register(self, fileobj, events, data=None):
key = super().register(fileobj, events, data) key = super().register(fileobj, events, data)
if events & EVENT_READ: try:
kev = select.kevent(key.fd, select.KQ_FILTER_READ, if events & EVENT_READ:
select.KQ_EV_ADD) kev = select.kevent(key.fd, select.KQ_FILTER_READ,
self._kqueue.control([kev], 0, 0) select.KQ_EV_ADD)
if events & EVENT_WRITE: self._kqueue.control([kev], 0, 0)
kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, if events & EVENT_WRITE:
select.KQ_EV_ADD) kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
self._kqueue.control([kev], 0, 0) select.KQ_EV_ADD)
self._kqueue.control([kev], 0, 0)
except BaseException:
super().unregister(fileobj)
raise
return key return key
def unregister(self, fileobj): def unregister(self, fileobj):

View File

@ -5,6 +5,7 @@
import signal import signal
import socket import socket
import sys import sys
import tempfile
from test import support from test import support
from time import sleep from time import sleep
import unittest import unittest
@ -447,6 +448,16 @@ class EpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
SELECTOR = getattr(selectors, 'EpollSelector', None) 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'), @unittest.skipUnless(hasattr(selectors, 'KqueueSelector'),
"Test needs selectors.KqueueSelector)") "Test needs selectors.KqueueSelector)")
@ -454,6 +465,18 @@ class KqueueSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
SELECTOR = getattr(selectors, 'KqueueSelector', None) 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(): def test_main():
tests = [DefaultSelectorTestCase, SelectSelectorTestCase, tests = [DefaultSelectorTestCase, SelectSelectorTestCase,

View File

@ -29,6 +29,9 @@ Library
HTTP_PROXY variable when REQUEST_METHOD environment is set, which indicates HTTP_PROXY variable when REQUEST_METHOD environment is set, which indicates
that the script is in CGI mode. that the script is in CGI mode.
- Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
Patch by Mark Williams.
Tests Tests
----- -----