Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e991270

Browse files
dimaqqmiss-islington
authored andcommitted
bpo-35415: validate fileno argument to socket.socket (GH-10917)
https://bugs.python.org/issue35415
1 parent 05c1b38 commit e991270

3 files changed

Lines changed: 74 additions & 25 deletions

File tree

Lib/test/test_socket.py

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,18 +1700,15 @@ def test_socket_consistent_sock_type(self):
17001700
s.setblocking(False)
17011701
self.assertEqual(s.type, socket.SOCK_STREAM)
17021702

1703-
@unittest.skipIf(os.name == 'nt', 'Will not work on Windows')
17041703
def test_unknown_socket_family_repr(self):
17051704
# Test that when created with a family that's not one of the known
17061705
# AF_*/SOCK_* constants, socket.family just returns the number.
17071706
#
17081707
# To do this we fool socket.socket into believing it already has an
17091708
# open fd because on this path it doesn't actually verify the family and
17101709
# type and populates the socket object.
1711-
#
1712-
# On Windows this trick won't work, so the test is skipped.
1713-
fd, path = tempfile.mkstemp()
1714-
self.addCleanup(os.unlink, path)
1710+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1711+
fd = sock.detach()
17151712
unknown_family = max(socket.AddressFamily.__members__.values()) + 1
17161713

17171714
unknown_type = max(
@@ -1785,6 +1782,48 @@ def test_socket_fileno(self):
17851782
s.bind(os.path.join(tmpdir, 'socket'))
17861783
self._test_socket_fileno(s, socket.AF_UNIX, socket.SOCK_STREAM)
17871784

1785+
def test_socket_fileno_rejects_float(self):
1786+
with self.assertRaisesRegex(TypeError, "integer argument expected"):
1787+
socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=42.5)
1788+
1789+
def test_socket_fileno_rejects_other_types(self):
1790+
with self.assertRaisesRegex(TypeError, "integer is required"):
1791+
socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno="foo")
1792+
1793+
def test_socket_fileno_rejects_invalid_socket(self):
1794+
with self.assertRaisesRegex(ValueError, "negative file descriptor"):
1795+
socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=-1)
1796+
1797+
@unittest.skipIf(os.name == "nt", "Windows disallows -1 only")
1798+
def test_socket_fileno_rejects_negative(self):
1799+
with self.assertRaisesRegex(ValueError, "negative file descriptor"):
1800+
socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=-42)
1801+
1802+
def test_socket_fileno_requires_valid_fd(self):
1803+
WSAENOTSOCK = 10038
1804+
with self.assertRaises(OSError) as cm:
1805+
socket.socket(fileno=support.make_bad_fd())
1806+
self.assertIn(cm.exception.errno, (errno.EBADF, WSAENOTSOCK))
1807+
1808+
with self.assertRaises(OSError) as cm:
1809+
socket.socket(
1810+
socket.AF_INET,
1811+
socket.SOCK_STREAM,
1812+
fileno=support.make_bad_fd())
1813+
self.assertIn(cm.exception.errno, (errno.EBADF, WSAENOTSOCK))
1814+
1815+
def test_socket_fileno_requires_socket_fd(self):
1816+
with tempfile.NamedTemporaryFile() as afile:
1817+
with self.assertRaises(OSError):
1818+
socket.socket(fileno=afile.fileno())
1819+
1820+
with self.assertRaises(OSError) as cm:
1821+
socket.socket(
1822+
socket.AF_INET,
1823+
socket.SOCK_STREAM,
1824+
fileno=afile.fileno())
1825+
self.assertEqual(cm.exception.errno, errno.ENOTSOCK)
1826+
17881827

17891828
@unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.')
17901829
class BasicCANTest(unittest.TestCase):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Validate fileno= argument to socket.socket().

Modules/socketmodule.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5018,28 +5018,45 @@ sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
50185018
else
50195019
#endif
50205020
{
5021+
5022+
if (PyFloat_Check(fdobj)) {
5023+
PyErr_SetString(PyExc_TypeError,
5024+
"integer argument expected, got float");
5025+
return -1;
5026+
}
5027+
50215028
fd = PyLong_AsSocket_t(fdobj);
50225029
if (fd == (SOCKET_T)(-1) && PyErr_Occurred())
50235030
return -1;
5031+
#ifdef MS_WINDOWS
50245032
if (fd == INVALID_SOCKET) {
5025-
PyErr_SetString(PyExc_ValueError,
5026-
"can't use invalid socket value");
5033+
#else
5034+
if (fd < 0) {
5035+
#endif
5036+
PyErr_SetString(PyExc_ValueError, "negative file descriptor");
50275037
return -1;
50285038
}
50295039

5030-
if (family == -1) {
5031-
sock_addr_t addrbuf;
5032-
socklen_t addrlen = sizeof(sock_addr_t);
5040+
/* validate that passed file descriptor is valid and a socket. */
5041+
sock_addr_t addrbuf;
5042+
socklen_t addrlen = sizeof(sock_addr_t);
50335043

5034-
memset(&addrbuf, 0, addrlen);
5035-
if (getsockname(fd, SAS2SA(&addrbuf), &addrlen) == 0) {
5044+
memset(&addrbuf, 0, addrlen);
5045+
if (getsockname(fd, SAS2SA(&addrbuf), &addrlen) == 0) {
5046+
if (family == -1) {
50365047
family = SAS2SA(&addrbuf)->sa_family;
5037-
} else {
5048+
}
5049+
} else {
50385050
#ifdef MS_WINDOWS
5039-
PyErr_SetFromWindowsErrWithFilename(0, "family");
5051+
/* getsockname() on an unbound socket is an error on Windows.
5052+
Invalid descriptor and not a socket is same error code.
5053+
Error out if family must be resolved, or bad descriptor. */
5054+
if (family == -1 || CHECK_ERRNO(ENOTSOCK)) {
50405055
#else
5041-
PyErr_SetFromErrnoWithFilename(PyExc_OSError, "family");
5056+
/* getsockname() is not supported for SOL_ALG on Linux. */
5057+
if (family == -1 || CHECK_ERRNO(EBADF) || CHECK_ERRNO(ENOTSOCK)) {
50425058
#endif
5059+
set_error();
50435060
return -1;
50445061
}
50455062
}
@@ -5052,11 +5069,7 @@ sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
50525069
{
50535070
type = tmp;
50545071
} else {
5055-
#ifdef MS_WINDOWS
5056-
PyErr_SetFromWindowsErrWithFilename(0, "type");
5057-
#else
5058-
PyErr_SetFromErrnoWithFilename(PyExc_OSError, "type");
5059-
#endif
5072+
set_error();
50605073
return -1;
50615074
}
50625075
}
@@ -5072,11 +5085,7 @@ sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
50725085
{
50735086
proto = tmp;
50745087
} else {
5075-
#ifdef MS_WINDOWS
5076-
PyErr_SetFromWindowsErrWithFilename(0, "protocol");
5077-
#else
5078-
PyErr_SetFromErrnoWithFilename(PyExc_OSError, "protocol");
5079-
#endif
5088+
set_error();
50805089
return -1;
50815090
}
50825091
}

0 commit comments

Comments
 (0)