Index: Lib/test/test_socket.py =================================================================== --- Lib/test/test_socket.py (révision 84499) +++ Lib/test/test_socket.py (copie de travail) @@ -1391,6 +1391,53 @@ self.assertTrue(issubclass(socket.gaierror, socket.error)) self.assertTrue(issubclass(socket.timeout, socket.error)) +class TestLinuxPathLen(unittest.TestCase): + + # Test AF_UNIX path length limits on Linux. + + UNIX_PATH_MAX = 108 + + def setUp(self): + self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.to_unlink = [] + + def tearDown(self): + self.sock.close() + for name in self.to_unlink: + support.unlink(name) + + def pathEncodingArgs(self): + # Return the encoding and error handler used to encode/decode + # pathnames. + encoding = sys.getfilesystemencoding() + if encoding is None: + encoding = sys.getdefaultencoding() + return encoding, "surrogateescape" + + def pathname(self, length): + # Return a bytes pathname of the given length. + path = os.path.abspath(support.TESTFN) + path_bytes = path.encode(*self.pathEncodingArgs()) + return path_bytes + b"a" * (length - len(path_bytes)) + + def testPathTooLong(self): + # Check we can't bind to a path longer than the assumed maximum. + path = self.pathname(self.UNIX_PATH_MAX + 1) + with self.assertRaisesRegexp(socket.error, "AF_UNIX path too long"): + self.sock.bind(path) + self.to_unlink.append(path) + + def testMaxPathLen(self): + # Test binding to a path of the maximum length and reading the + # address back. In this case, sun_path is not null terminated, + # and makesockaddr() used to read past the end of it. + path = self.pathname(self.UNIX_PATH_MAX) + self.sock.bind(path) + self.to_unlink.append(path) + self.assertEqual(self.sock.getsockname(), + path.decode(*self.pathEncodingArgs())) + os.stat(path) + class TestLinuxAbstractNamespace(unittest.TestCase): UNIX_PATH_MAX = 108 @@ -1582,6 +1629,7 @@ tests.append(BasicSocketPairTest) if sys.platform == 'linux2': tests.append(TestLinuxAbstractNamespace) + tests.append(TestLinuxPathLen) if isTipcAvailable(): tests.append(TIPCTest) tests.append(TIPCThreadableTest) Index: Modules/socketmodule.c =================================================================== --- Modules/socketmodule.c (révision 84499) +++ Modules/socketmodule.c (copie de travail) @@ -962,18 +962,23 @@ #if defined(AF_UNIX) case AF_UNIX: { + Py_ssize_t len, splen; struct sockaddr_un *a = (struct sockaddr_un *) addr; + splen = addrlen - offsetof(struct sockaddr_un, sun_path); #ifdef linux - if (a->sun_path[0] == 0) { /* Linux abstract namespace */ - addrlen -= offsetof(struct sockaddr_un, sun_path); - return PyBytes_FromStringAndSize(a->sun_path, addrlen); + if (splen > 0 && a->sun_path[0] == 0) { + /* Linux abstract namespace */ + return PyBytes_FromStringAndSize(a->sun_path, splen); } else #endif /* linux */ { - /* regular NULL-terminated string */ - return PyUnicode_FromString(a->sun_path); + /* String, up to null terminator if present */ + for (len = 0; len < splen && a->sun_path[len] != 0; + len++) + ; } + return PyUnicode_FromStringAndSize(a->sun_path, len); } #endif /* AF_UNIX */ @@ -1579,6 +1584,7 @@ sock_addr_t addrbuf; SOCKET_T newfd = INVALID_SOCKET; socklen_t addrlen; + socklen_t buflen; PyObject *sock = NULL; PyObject *addr = NULL; PyObject *res = NULL; @@ -1586,6 +1592,7 @@ if (!getsockaddrlen(s, &addrlen)) return NULL; + buflen = addrlen; memset(&addrbuf, 0, addrlen); if (!IS_SELECTABLE(s)) @@ -1612,7 +1619,8 @@ } addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), - addrlen, s->sock_proto); + (addrlen > buflen) ? buflen : addrlen, + s->sock_proto); if (addr == NULL) goto finally; @@ -2062,16 +2070,19 @@ sock_addr_t addrbuf; int res; socklen_t addrlen; + socklen_t buflen; if (!getsockaddrlen(s, &addrlen)) return NULL; + buflen = addrlen; memset(&addrbuf, 0, addrlen); Py_BEGIN_ALLOW_THREADS res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen); Py_END_ALLOW_THREADS if (res < 0) return s->errorhandler(); - return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, + return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), + (addrlen > buflen) ? buflen : addrlen, s->sock_proto); } @@ -2091,16 +2102,19 @@ sock_addr_t addrbuf; int res; socklen_t addrlen; + socklen_t buflen; if (!getsockaddrlen(s, &addrlen)) return NULL; + buflen = addrlen; memset(&addrbuf, 0, addrlen); Py_BEGIN_ALLOW_THREADS res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen); Py_END_ALLOW_THREADS if (res < 0) return s->errorhandler(); - return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, + return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), + (addrlen > buflen) ? buflen : addrlen, s->sock_proto); } @@ -2361,11 +2375,13 @@ int timeout; Py_ssize_t n = -1; socklen_t addrlen; + socklen_t buflen; *addr = NULL; if (!getsockaddrlen(s, &addrlen)) return -1; + buflen = addrlen; if (!IS_SELECTABLE(s)) { select_error(); @@ -2401,7 +2417,8 @@ } if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), - addrlen, s->sock_proto))) + (addrlen > buflen) ? buflen : addrlen, + s->sock_proto))) return -1; return n;