From de1a8b720a8cc5a6dab5e293d322a43d7ecb5c69 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sat, 31 Jan 2009 22:57:30 +0000 Subject: [PATCH] - Issue #5104: The socket module now raises OverflowError when 16-bit port and protocol numbers are supplied outside the allowed 0-65536 range on bind() and getservbyport(). --- Lib/test/test_socket.py | 40 ++++++++++++++++++++++++++++++++-------- Misc/NEWS | 4 ++++ Modules/socketmodule.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 2980889e939..66664b44ed5 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -356,6 +356,9 @@ class GeneralModuleTests(unittest.TestCase): eq(socket.getservbyport(port, 'tcp'), service) if udpport is not None: eq(socket.getservbyport(udpport, 'udp'), service) + # Make sure getservbyport does not accept out of range ports. + self.assertRaises(OverflowError, socket.getservbyport, -1) + self.assertRaises(OverflowError, socket.getservbyport, 65536) def testDefaultTimeout(self): # Testing default timeout @@ -456,15 +459,23 @@ class GeneralModuleTests(unittest.TestCase): # XXX The following don't test module-level functionality... - def testSockName(self): - # Testing getsockname(). Use a temporary socket to elicit an unused - # ephemeral port that we can use later in the test. - tempsock = socket.socket() - tempsock.bind(("0.0.0.0", 0)) - (host, port) = tempsock.getsockname() - tempsock.close() - del tempsock + def _get_unused_port(self, bind_address='0.0.0.0'): + """Use a temporary socket to elicit an unused ephemeral port. + Args: + bind_address: Hostname or IP address to search for a port on. + + Returns: A most likely to be unused port. + """ + tempsock = socket.socket() + tempsock.bind((bind_address, 0)) + host, port = tempsock.getsockname() + tempsock.close() + return port + + def testSockName(self): + # Testing getsockname() + port = self._get_unused_port() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(("0.0.0.0", port)) name = sock.getsockname() @@ -504,6 +515,19 @@ class GeneralModuleTests(unittest.TestCase): self.assertEqual(sock.proto, 0) sock.close() + def test_getsockaddrarg(self): + host = '0.0.0.0' + port = self._get_unused_port(bind_address=host) + big_port = port + 65536 + neg_port = port - 65536 + sock = socket.socket() + try: + self.assertRaises(OverflowError, sock.bind, (host, big_port)) + self.assertRaises(OverflowError, sock.bind, (host, neg_port)) + sock.bind((host, port)) + finally: + sock.close() + def test_sock_ioctl(self): if os.name != "nt": return diff --git a/Misc/NEWS b/Misc/NEWS index bce220754c1..c403b61ae49 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -383,6 +383,10 @@ Library - Issue #4861: ctypes.util.find_library(): Robustify. Fix library detection on biarch systems. Try to rely on ldconfig only, without using objdump and gcc. +- Issue #5104: The socket module now raises OverflowError when 16-bit port and + protocol numbers are supplied outside the allowed 0-65536 range on bind() + and getservbyport(). + Tools/Demos ----------- diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index c1e3cfe175d..fc85bcc894a 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1259,6 +1259,12 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, PyMem_Free(host); if (result < 0) return 0; + if (port < 0 || port > 0xffff) { + PyErr_SetString( + PyExc_OverflowError, + "getsockaddrarg: port must be 0-65535."); + return 0; + } addr->sin_family = AF_INET; addr->sin_port = htons((short)port); *len_ret = sizeof *addr; @@ -1291,6 +1297,12 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, PyMem_Free(host); if (result < 0) return 0; + if (port < 0 || port > 0xffff) { + PyErr_SetString( + PyExc_OverflowError, + "getsockaddrarg: port must be 0-65535."); + return 0; + } addr->sin6_family = s->sock_family; addr->sin6_port = htons((short)port); addr->sin6_flowinfo = flowinfo; @@ -1417,6 +1429,12 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, "Hardware address must be 8 bytes or less"); return 0; } + if (protoNumber < 0 || protoNumber > 0xffff) { + PyErr_SetString( + PyExc_OverflowError, + "getsockaddrarg: protoNumber must be 0-65535."); + return 0; + } addr = (struct sockaddr_ll*)addr_ret; addr->sll_family = AF_PACKET; addr->sll_protocol = htons((short)protoNumber); @@ -3446,13 +3464,19 @@ otherwise any protocol will match."); static PyObject * socket_getservbyport(PyObject *self, PyObject *args) { - unsigned short port; + int port; char *proto=NULL; struct servent *sp; - if (!PyArg_ParseTuple(args, "H|s:getservbyport", &port, &proto)) + if (!PyArg_ParseTuple(args, "i|s:getservbyport", &port, &proto)) return NULL; + if (port < 0 || port > 0xffff) { + PyErr_SetString( + PyExc_OverflowError, + "getservbyport: port must be 0-65535."); + return NULL; + } Py_BEGIN_ALLOW_THREADS - sp = getservbyport(htons(port), proto); + sp = getservbyport(htons((short)port), proto); Py_END_ALLOW_THREADS if (sp == NULL) { PyErr_SetString(socket_error, "port/proto not found");