David Watson added the comment:

I've rebased the patches onto all the currently released
branches, but since there are now so many variations required,
I've bundled the pass-unterminated and test patches into a single
set (enable-unterminated-*), and the return-unterminated and
addrlen-makesockaddr patches into another (fix-overrun-*), which
applies on top.

The fix-overrun patches can be applied on their own, but don't
include any tests.

The 3.5 branch has some more substantial changes which stop the
patches applying - I haven't looked into those yet.

----------
Added file: 
http://bugs.python.org/file39297/enable-unterminated-2.7-2015-05-05.diff
Added file: http://bugs.python.org/file39298/fix-overrun-2.7-2015-05-05.diff
Added file: 
http://bugs.python.org/file39299/enable-unterminated-3.2-2015-05-05.diff
Added file: http://bugs.python.org/file39300/fix-overrun-3.2-2015-05-05.diff
Added file: 
http://bugs.python.org/file39301/enable-unterminated-3.3-2015-05-05.diff
Added file: http://bugs.python.org/file39302/fix-overrun-3.3-2015-05-05.diff
Added file: 
http://bugs.python.org/file39303/enable-unterminated-3.4-2015-05-05.diff
Added file: http://bugs.python.org/file39304/fix-overrun-3.4-2015-05-05.diff

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue8372>
_______________________________________
# HG changeset patch
# Parent  376c2d81d0e2e8ec424d4aafabfbd75e42ea3804
Allow AF_UNIX pathnames up to the maximum 108 bytes on Linux,
since it does not require sun_path to be null terminated.

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1581,6 +1581,44 @@ class TestExceptions(unittest.TestCase):
         self.assertTrue(issubclass(socket.gaierror, socket.error))
         self.assertTrue(issubclass(socket.timeout, socket.error))
 
+@unittest.skipUnless(sys.platform.startswith('linux'), 'Linux specific test')
+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:
+            test_support.unlink(name)
+
+    def pathname(self, length):
+        # Return a pathname of the given length.
+        path = os.path.abspath(test_support.TESTFN)
+        return path + "a" * (length - len(path))
+
+    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)
+        os.stat(path)
+
 @unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
 class TestLinuxAbstractNamespace(unittest.TestCase):
 
@@ -1793,6 +1831,7 @@ def test_main():
         NetworkConnectionBehaviourTest,
     ])
     tests.append(BasicSocketPairTest)
+    tests.append(TestLinuxPathLen)
     tests.append(TestLinuxAbstractNamespace)
     tests.extend([TIPCTest, TIPCThreadableTest])
 
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1251,27 +1251,16 @@ getsockaddrarg(PySocketSockObject *s, Py
 
         addr = (struct sockaddr_un*)addr_ret;
 #ifdef linux
-        if (len > 0 && path[0] == 0) {
-            /* Linux abstract namespace extension */
-            if (len > sizeof addr->sun_path) {
-                PyErr_SetString(socket_error,
-                                "AF_UNIX path too long");
-                return 0;
-            }
-        }
-        else
-#endif /* linux */
-        {
-            /* regular NULL-terminated string */
-            if (len >= sizeof addr->sun_path) {
-                PyErr_SetString(socket_error,
-                                "AF_UNIX path too long");
-                return 0;
-            }
-            addr->sun_path[len] = 0;
+        if (len > sizeof(addr->sun_path)) {
+#else
+        if (len >= sizeof(addr->sun_path)) {
+#endif
+            PyErr_SetString(socket_error, "AF_UNIX path too long");
+            return 0;
         }
         addr->sun_family = s->sock_family;
         memcpy(addr->sun_path, path, len);
+        memset(addr->sun_path + len, 0, sizeof(addr->sun_path) - len);
 #if defined(PYOS_OS2)
         *len_ret = sizeof(*addr);
 #else
# HG changeset patch
# Parent  55bdf133669c579118bbd19b1e20c23a431614ea
When parsing addresses returned by accept(), etc., do not assume
null termination of sun_path in AF_UNIX addresses: rely instead
on the returned address length.  If this is longer then the
original buffer, ignore it and use the original length.

diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1027,13 +1027,22 @@ makebdaddr(bdaddr_t *bdaddr)
 
 /*ARGSUSED*/
 static PyObject *
-makesockaddr(int sockfd, struct sockaddr *addr, int addrlen, int proto)
+makesockaddr(int sockfd, struct sockaddr *addr, socklen_t addrlen,
+             socklen_t buflen, int proto)
 {
     if (addrlen == 0) {
         /* No address -- may be recvfrom() from known socket */
         Py_INCREF(Py_None);
         return Py_None;
     }
+    /* buflen is the length of the buffer containing the address, and
+       addrlen is either the same, or is the length returned by the OS
+       after writing an address into the buffer.  Some systems return
+       the length they would have written if there had been space
+       (e.g. when an oversized AF_UNIX address has its sun_path
+       truncated). */
+    if (addrlen > buflen)
+        addrlen = buflen;
 
 #ifdef __BEOS__
     /* XXX: BeOS version of accept() doesn't set family correctly */
@@ -1058,19 +1067,27 @@ makesockaddr(int sockfd, struct sockaddr
 #if defined(AF_UNIX)
     case AF_UNIX:
     {
+        Py_ssize_t len, splen;
         struct sockaddr_un *a = (struct sockaddr_un *) addr;
+
+        if (addrlen < offsetof(struct sockaddr_un, sun_path))
+            Py_RETURN_NONE;
+        else
+            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 PyString_FromStringAndSize(a->sun_path,
-                                              addrlen);
+        if (splen > 0 && a->sun_path[0] == 0) {
+            /* Linux abstract namespace */
+            len = splen;
         }
         else
 #endif /* linux */
         {
-            /* regular NULL-terminated string */
-            return PyString_FromString(a->sun_path);
+            /* Path text can occupy all of sun_path[], and therefore
+               lack null termination */
+            for (len = 0; len < splen && a->sun_path[len] != 0; len++)
+                ;
         }
+        return PyString_FromStringAndSize(a->sun_path, len);
     }
 #endif /* AF_UNIX */
 
@@ -1689,6 +1706,7 @@ sock_accept(PySocketSockObject *s)
     sock_addr_t addrbuf;
     SOCKET_T newfd;
     socklen_t addrlen;
+    socklen_t buflen;
     PyObject *sock = NULL;
     PyObject *addr = NULL;
     PyObject *res = NULL;
@@ -1696,6 +1714,7 @@ sock_accept(PySocketSockObject *s)
 
     if (!getsockaddrlen(s, &addrlen))
         return NULL;
+    buflen = addrlen;
     memset(&addrbuf, 0, addrlen);
 
     newfd = INVALID_SOCKET;
@@ -1731,7 +1750,7 @@ sock_accept(PySocketSockObject *s)
         goto finally;
     }
     addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                        addrlen, s->sock_proto);
+                        addrlen, buflen, s->sock_proto);
     if (addr == NULL)
         goto finally;
 
@@ -2229,16 +2248,18 @@ sock_getsockname(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2258,16 +2279,18 @@ sock_getpeername(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2598,11 +2621,13 @@ sock_recvfrom_guts(PySocketSockObject *s
     int timeout;
     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();
@@ -2640,7 +2665,7 @@ sock_recvfrom_guts(PySocketSockObject *s
     }
 
     if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                               addrlen, s->sock_proto)))
+                               addrlen, buflen, s->sock_proto)))
         return -1;
 
     return n;
@@ -4202,7 +4227,8 @@ socket_getaddrinfo(PyObject *self, PyObj
         goto err;
     for (res = res0; res; res = res->ai_next) {
         PyObject *addr =
-            makesockaddr(-1, res->ai_addr, res->ai_addrlen, protocol);
+            makesockaddr(-1, res->ai_addr, res->ai_addrlen, res->ai_addrlen,
+                         protocol);
         if (addr == NULL)
             goto err;
         single = Py_BuildValue("iiisO", res->ai_family,
# HG changeset patch
# Parent  91096d27c802859992c11016864e3b22a0fbd141
Allow AF_UNIX pathnames up to the maximum 108 bytes on Linux,
since it does not require sun_path to be null terminated.

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1876,6 +1876,53 @@ class TestExceptions(unittest.TestCase):
         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
@@ -2194,6 +2241,7 @@ def test_main():
         tests.append(BasicSocketPairTest)
     if sys.platform == 'linux2':
         tests.append(TestLinuxAbstractNamespace)
+        tests.append(TestLinuxPathLen)
     if isTipcAvailable():
         tests.append(TIPCTest)
         tests.append(TIPCThreadableTest)
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1226,27 +1226,16 @@ getsockaddrarg(PySocketSockObject *s, Py
 
         addr = (struct sockaddr_un*)addr_ret;
 #ifdef linux
-        if (len > 0 && path[0] == 0) {
-            /* Linux abstract namespace extension */
-            if (len > sizeof addr->sun_path) {
-                PyErr_SetString(socket_error,
-                                "AF_UNIX path too long");
-                return 0;
-            }
-        }
-        else
-#endif /* linux */
-        {
-            /* regular NULL-terminated string */
-            if (len >= sizeof addr->sun_path) {
-                PyErr_SetString(socket_error,
-                                "AF_UNIX path too long");
-                return 0;
-            }
-            addr->sun_path[len] = 0;
+        if (len > sizeof(addr->sun_path)) {
+#else
+        if (len >= sizeof(addr->sun_path)) {
+#endif
+            PyErr_SetString(socket_error, "AF_UNIX path too long");
+            return 0;
         }
         addr->sun_family = s->sock_family;
         memcpy(addr->sun_path, path, len);
+        memset(addr->sun_path + len, 0, sizeof(addr->sun_path) - len);
 #if defined(PYOS_OS2)
         *len_ret = sizeof(*addr);
 #else
# HG changeset patch
# Parent  9e29c3d6767ce72e5bc902c47f66e896dd0f402f
When parsing addresses returned by accept(), etc., do not assume
null termination of sun_path in AF_UNIX addresses: rely instead
on the returned address length.  If this is longer then the
original buffer, ignore it and use the original length.

diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1008,13 +1008,22 @@ makebdaddr(bdaddr_t *bdaddr)
 
 /*ARGSUSED*/
 static PyObject *
-makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
+makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, socklen_t addrlen,
+             socklen_t buflen, int proto)
 {
     if (addrlen == 0) {
         /* No address -- may be recvfrom() from known socket */
         Py_INCREF(Py_None);
         return Py_None;
     }
+    /* buflen is the length of the buffer containing the address, and
+       addrlen is either the same, or is the length returned by the OS
+       after writing an address into the buffer.  Some systems return
+       the length they would have written if there had been space
+       (e.g. when an oversized AF_UNIX address has its sun_path
+       truncated). */
+    if (addrlen > buflen)
+        addrlen = buflen;
 
     switch (addr->sa_family) {
 
@@ -1034,18 +1043,28 @@ makesockaddr(SOCKET_T sockfd, struct soc
 #if defined(AF_UNIX)
     case AF_UNIX:
     {
+        Py_ssize_t len, splen;
         struct sockaddr_un *a = (struct sockaddr_un *) addr;
+
+        if (addrlen < offsetof(struct sockaddr_un, sun_path))
+            Py_RETURN_NONE;
+        else
+            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);
+        /* Backwards compatibility: return empty addresses as bytes */
+        if (splen == 0 || (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);
+            /* Path text can occupy all of sun_path[], and therefore
+               lack null termination */
+            for (len = 0; len < splen && a->sun_path[len] != 0; len++)
+                ;
         }
+        return PyUnicode_FromStringAndSize(a->sun_path, len);
     }
 #endif /* AF_UNIX */
 
@@ -1664,12 +1683,14 @@ sock_accept(PySocketSockObject *s)
     sock_addr_t addrbuf;
     SOCKET_T newfd = INVALID_SOCKET;
     socklen_t addrlen;
+    socklen_t buflen;
     PyObject *sock = NULL;
     PyObject *addr = NULL;
     PyObject *res = NULL;
     int timeout;
     if (!getsockaddrlen(s, &addrlen))
         return NULL;
+    buflen = addrlen;
     memset(&addrbuf, 0, addrlen);
 
     if (!IS_SELECTABLE(s))
@@ -1699,7 +1720,7 @@ sock_accept(PySocketSockObject *s)
     }
 
     addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                        addrlen, s->sock_proto);
+                        addrlen, buflen, s->sock_proto);
     if (addr == NULL)
         goto finally;
 
@@ -2149,16 +2170,18 @@ sock_getsockname(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2178,16 +2201,18 @@ sock_getpeername(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2456,11 +2481,13 @@ sock_recvfrom_guts(PySocketSockObject *s
     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();
@@ -2498,7 +2525,7 @@ sock_recvfrom_guts(PySocketSockObject *s
     }
 
     if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                               addrlen, s->sock_proto)))
+                               addrlen, buflen, s->sock_proto)))
         return -1;
 
     return n;
@@ -4063,7 +4090,8 @@ socket_getaddrinfo(PyObject *self, PyObj
     for (res = res0; res; res = res->ai_next) {
         PyObject *single;
         PyObject *addr =
-            makesockaddr(-1, res->ai_addr, res->ai_addrlen, protocol);
+            makesockaddr(-1, res->ai_addr, res->ai_addrlen, res->ai_addrlen,
+                         protocol);
         if (addr == NULL)
             goto err;
         single = Py_BuildValue("iiisO", res->ai_family,
# HG changeset patch
# Parent  ffc1f9d1c8b374edc6d1d5de41d18f0d3631cbf7
Allow AF_UNIX pathnames up to the maximum 108 bytes on Linux,
since it does not require sun_path to be null terminated.

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -4401,6 +4401,54 @@ class TestExceptions(unittest.TestCase):
         self.assertTrue(issubclass(socket.timeout, socket.error))
 
 @unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
+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)
+
+@unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
 class TestLinuxAbstractNamespace(unittest.TestCase):
 
     UNIX_PATH_MAX = 108
@@ -4896,6 +4944,7 @@ def test_main():
     ])
     tests.append(BasicSocketPairTest)
     tests.append(TestUnixDomain)
+    tests.append(TestLinuxPathLen)
     tests.append(TestLinuxAbstractNamespace)
     tests.extend([TIPCTest, TIPCThreadableTest])
     tests.extend([BasicCANTest, CANTest])
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1308,27 +1308,16 @@ getsockaddrarg(PySocketSockObject *s, Py
 
         addr = (struct sockaddr_un*)addr_ret;
 #ifdef linux
-        if (len > 0 && path[0] == 0) {
-            /* Linux abstract namespace extension */
-            if (len > sizeof addr->sun_path) {
-                PyErr_SetString(PyExc_OSError,
-                                "AF_UNIX path too long");
-                goto unix_out;
-            }
-        }
-        else
-#endif /* linux */
-        {
-            /* regular NULL-terminated string */
-            if (len >= sizeof addr->sun_path) {
-                PyErr_SetString(PyExc_OSError,
-                                "AF_UNIX path too long");
-                goto unix_out;
-            }
-            addr->sun_path[len] = 0;
+        if (len > sizeof(addr->sun_path)) {
+#else
+        if (len >= sizeof(addr->sun_path)) {
+#endif
+            PyErr_SetString(PyExc_OSError, "AF_UNIX path too long");
+            goto unix_out;
         }
         addr->sun_family = s->sock_family;
         memcpy(addr->sun_path, path, len);
+        memset(addr->sun_path + len, 0, sizeof(addr->sun_path) - len);
 #if defined(PYOS_OS2)
         *len_ret = sizeof(*addr);
 #else
# HG changeset patch
# Parent  920816bbee6a0f9e0d2a3b86d08b7c61784818a7
When parsing addresses returned by accept(), etc., do not assume
null termination of sun_path in AF_UNIX addresses: rely instead
on the returned address length.  If this is longer then the
original buffer, ignore it and use the original length.

diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1044,13 +1044,22 @@ makebdaddr(bdaddr_t *bdaddr)
 
 /*ARGSUSED*/
 static PyObject *
-makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
+makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, socklen_t addrlen,
+             socklen_t buflen, int proto)
 {
     if (addrlen == 0) {
         /* No address -- may be recvfrom() from known socket */
         Py_INCREF(Py_None);
         return Py_None;
     }
+    /* buflen is the length of the buffer containing the address, and
+       addrlen is either the same, or is the length returned by the OS
+       after writing an address into the buffer.  Some systems return
+       the length they would have written if there had been space
+       (e.g. when an oversized AF_UNIX address has its sun_path
+       truncated). */
+    if (addrlen > buflen)
+        addrlen = buflen;
 
     switch (addr->sa_family) {
 
@@ -1070,18 +1079,28 @@ makesockaddr(SOCKET_T sockfd, struct soc
 #if defined(AF_UNIX)
     case AF_UNIX:
     {
+        Py_ssize_t len, splen;
         struct sockaddr_un *a = (struct sockaddr_un *) addr;
+
+        if (addrlen < offsetof(struct sockaddr_un, sun_path))
+            Py_RETURN_NONE;
+        else
+            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);
+        /* Backwards compatibility: return empty addresses as bytes */
+        if (splen == 0 || (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_DecodeFSDefault(a->sun_path);
+            /* Path text can occupy all of sun_path[], and therefore
+               lack null termination */
+            for (len = 0; len < splen && a->sun_path[len] != 0; len++)
+                ;
         }
+        return PyUnicode_DecodeFSDefaultAndSize(a->sun_path, len);
     }
 #endif /* AF_UNIX */
 
@@ -2001,12 +2020,14 @@ sock_accept(PySocketSockObject *s)
     sock_addr_t addrbuf;
     SOCKET_T newfd = INVALID_SOCKET;
     socklen_t addrlen;
+    socklen_t buflen;
     PyObject *sock = NULL;
     PyObject *addr = NULL;
     PyObject *res = NULL;
     int timeout;
     if (!getsockaddrlen(s, &addrlen))
         return NULL;
+    buflen = addrlen;
     memset(&addrbuf, 0, addrlen);
 
     if (!IS_SELECTABLE(s))
@@ -2036,7 +2057,7 @@ sock_accept(PySocketSockObject *s)
     }
 
     addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                        addrlen, s->sock_proto);
+                        addrlen, buflen, s->sock_proto);
     if (addr == NULL)
         goto finally;
 
@@ -2486,16 +2507,18 @@ sock_getsockname(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2515,16 +2538,18 @@ sock_getpeername(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2793,11 +2818,13 @@ sock_recvfrom_guts(PySocketSockObject *s
     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();
@@ -2835,7 +2862,7 @@ sock_recvfrom_guts(PySocketSockObject *s
     }
 
     if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                               addrlen, s->sock_proto)))
+                               addrlen, buflen, s->sock_proto)))
         return -1;
 
     return n;
@@ -3071,8 +3098,7 @@ sock_recvmsg_guts(PySocketSockObject *s,
                            cmsg_list,
                            (int)msg.msg_flags,
                            makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                                        ((msg.msg_namelen > addrbuflen) ?
-                                         addrbuflen : msg.msg_namelen),
+                                        msg.msg_namelen, addrbuflen,
                                         s->sock_proto));
     if (retval == NULL)
         goto err_closefds;
@@ -5066,7 +5092,8 @@ socket_getaddrinfo(PyObject *self, PyObj
     for (res = res0; res; res = res->ai_next) {
         PyObject *single;
         PyObject *addr =
-            makesockaddr(-1, res->ai_addr, res->ai_addrlen, protocol);
+            makesockaddr(-1, res->ai_addr, res->ai_addrlen, res->ai_addrlen,
+                         protocol);
         if (addr == NULL)
             goto err;
         single = Py_BuildValue("iiisO", res->ai_family,
# HG changeset patch
# Parent  71ec881d834720532cb88af0c489e43f5f48bcf9
Allow AF_UNIX pathnames up to the maximum 108 bytes on Linux,
since it does not require sun_path to be null terminated.

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -4585,6 +4585,54 @@ class TestExceptions(unittest.TestCase):
         self.assertTrue(issubclass(socket.timeout, OSError))
 
 @unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
+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)
+
+@unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
 class TestLinuxAbstractNamespace(unittest.TestCase):
 
     UNIX_PATH_MAX = 108
@@ -5137,6 +5185,7 @@ def test_main():
     ])
     tests.append(BasicSocketPairTest)
     tests.append(TestUnixDomain)
+    tests.append(TestLinuxPathLen)
     tests.append(TestLinuxAbstractNamespace)
     tests.extend([TIPCTest, TIPCThreadableTest])
     tests.extend([BasicCANTest, CANTest])
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1247,27 +1247,16 @@ getsockaddrarg(PySocketSockObject *s, Py
 
         addr = (struct sockaddr_un*)addr_ret;
 #ifdef linux
-        if (len > 0 && path[0] == 0) {
-            /* Linux abstract namespace extension */
-            if (len > sizeof addr->sun_path) {
-                PyErr_SetString(PyExc_OSError,
-                                "AF_UNIX path too long");
-                goto unix_out;
-            }
-        }
-        else
-#endif /* linux */
-        {
-            /* regular NULL-terminated string */
-            if (len >= sizeof addr->sun_path) {
-                PyErr_SetString(PyExc_OSError,
-                                "AF_UNIX path too long");
-                goto unix_out;
-            }
-            addr->sun_path[len] = 0;
+        if (len > sizeof(addr->sun_path)) {
+#else
+        if (len >= sizeof(addr->sun_path)) {
+#endif
+            PyErr_SetString(PyExc_OSError, "AF_UNIX path too long");
+            goto unix_out;
         }
         addr->sun_family = s->sock_family;
         memcpy(addr->sun_path, path, len);
+        memset(addr->sun_path + len, 0, sizeof(addr->sun_path) - len);
         *len_ret = len + offsetof(struct sockaddr_un, sun_path);
         retval = 1;
     unix_out:
# HG changeset patch
# Parent  b47c6fffbd04edcc55de5424d38e8bacba811f68
When parsing addresses returned by accept(), etc., do not assume
null termination of sun_path in AF_UNIX addresses: rely instead
on the returned address length.  If this is longer then the
original buffer, ignore it and use the original length.

diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -983,13 +983,22 @@ makebdaddr(bdaddr_t *bdaddr)
 
 /*ARGSUSED*/
 static PyObject *
-makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
+makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, socklen_t addrlen,
+             socklen_t buflen, int proto)
 {
     if (addrlen == 0) {
         /* No address -- may be recvfrom() from known socket */
         Py_INCREF(Py_None);
         return Py_None;
     }
+    /* buflen is the length of the buffer containing the address, and
+       addrlen is either the same, or is the length returned by the OS
+       after writing an address into the buffer.  Some systems return
+       the length they would have written if there had been space
+       (e.g. when an oversized AF_UNIX address has its sun_path
+       truncated). */
+    if (addrlen > buflen)
+        addrlen = buflen;
 
     switch (addr->sa_family) {
 
@@ -1009,18 +1018,28 @@ makesockaddr(SOCKET_T sockfd, struct soc
 #if defined(AF_UNIX)
     case AF_UNIX:
     {
+        Py_ssize_t len, splen;
         struct sockaddr_un *a = (struct sockaddr_un *) addr;
+
+        if (addrlen < offsetof(struct sockaddr_un, sun_path))
+            Py_RETURN_NONE;
+        else
+            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);
+        /* Backwards compatibility: return empty addresses as bytes */
+        if (splen == 0 || (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_DecodeFSDefault(a->sun_path);
+            /* Path text can occupy all of sun_path[], and therefore
+               lack null termination */
+            for (len = 0; len < splen && a->sun_path[len] != 0; len++)
+                ;
         }
+        return PyUnicode_DecodeFSDefaultAndSize(a->sun_path, len);
     }
 #endif /* AF_UNIX */
 
@@ -1952,6 +1971,7 @@ sock_accept(PySocketSockObject *s)
     sock_addr_t addrbuf;
     SOCKET_T newfd = INVALID_SOCKET;
     socklen_t addrlen;
+    socklen_t buflen;
     PyObject *sock = NULL;
     PyObject *addr = NULL;
     PyObject *res = NULL;
@@ -1963,6 +1983,7 @@ sock_accept(PySocketSockObject *s)
 
     if (!getsockaddrlen(s, &addrlen))
         return NULL;
+    buflen = addrlen;
     memset(&addrbuf, 0, addrlen);
 
     if (!IS_SELECTABLE(s))
@@ -2025,7 +2046,7 @@ sock_accept(PySocketSockObject *s)
     }
 
     addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                        addrlen, s->sock_proto);
+                        addrlen, buflen, s->sock_proto);
     if (addr == NULL)
         goto finally;
 
@@ -2469,16 +2490,18 @@ sock_getsockname(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2498,16 +2521,18 @@ sock_getpeername(PySocketSockObject *s)
     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,
                         s->sock_proto);
 }
 
@@ -2736,11 +2761,13 @@ sock_recvfrom_guts(PySocketSockObject *s
     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();
@@ -2775,7 +2802,7 @@ sock_recvfrom_guts(PySocketSockObject *s
     }
 
     if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                               addrlen, s->sock_proto)))
+                               addrlen, buflen, s->sock_proto)))
         return -1;
 
     return n;
@@ -3011,8 +3038,7 @@ sock_recvmsg_guts(PySocketSockObject *s,
                            cmsg_list,
                            (int)msg.msg_flags,
                            makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
-                                        ((msg.msg_namelen > addrbuflen) ?
-                                         addrbuflen : msg.msg_namelen),
+                                        msg.msg_namelen, addrbuflen,
                                         s->sock_proto));
     if (retval == NULL)
         goto err_closefds;
@@ -5264,7 +5290,8 @@ socket_getaddrinfo(PyObject *self, PyObj
     for (res = res0; res; res = res->ai_next) {
         PyObject *single;
         PyObject *addr =
-            makesockaddr(-1, res->ai_addr, res->ai_addrlen, protocol);
+            makesockaddr(-1, res->ai_addr, res->ai_addrlen, res->ai_addrlen,
+                         protocol);
         if (addr == NULL)
             goto err;
         single = Py_BuildValue("iiisO", res->ai_family,
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to