David Watson added the comment:

Attaching patches for 3.5.

----------
Added file: 
http://bugs.python.org/file39309/enable-unterminated-3.5-2015-05-06.diff
Added file: http://bugs.python.org/file39310/fix-overrun-3.5-2015-05-06.diff

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue8372>
_______________________________________
# HG changeset patch
# Parent  5f2ae82157af71456c4837ff2838d1f0f01e759e
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
@@ -4477,6 +4477,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
@@ -5303,6 +5351,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
@@ -1460,27 +1460,17 @@ getsockaddrarg(PySocketSockObject *s, Py
 
         addr = (struct sockaddr_un*)addr_ret;
 #ifdef linux
-        if (path.len > 0 && *(const char *)path.buf == 0) {
-            /* Linux abstract namespace extension */
-            if ((size_t)path.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 ((size_t)path.len >= sizeof addr->sun_path) {
-                PyErr_SetString(PyExc_OSError,
-                                "AF_UNIX path too long");
-                goto unix_out;
-            }
-            addr->sun_path[path.len] = 0;
+        if ((size_t)path.len > sizeof(addr->sun_path)) {
+#else
+        if ((size_t)path.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.buf, path.len);
+        memset(addr->sun_path + path.len, 0,
+               sizeof(addr->sun_path) - path.len);
         *len_ret = path.len + offsetof(struct sockaddr_un, sun_path);
         retval = 1;
     unix_out:
# HG changeset patch
# Parent  ac51dc99c1bd722e1b24b4bfa14520082e01f1a8
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
@@ -1129,13 +1129,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) {
 
@@ -1155,18 +1164,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 */
 
@@ -2212,6 +2231,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;
@@ -2219,6 +2239,7 @@ sock_accept(PySocketSockObject *s)
 
     if (!getsockaddrlen(s, &addrlen))
         return NULL;
+    buflen = addrlen;
     memset(&addrbuf, 0, addrlen);
 
     if (!IS_SELECTABLE(s))
@@ -2256,7 +2277,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;
 
@@ -2720,16 +2741,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);
 }
 
@@ -2749,16 +2772,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);
 }
 
@@ -3017,12 +3042,14 @@ sock_recvfrom_guts(PySocketSockObject *s
 {
     sock_addr_t addrbuf;
     socklen_t addrlen;
+    socklen_t buflen;
     struct sock_recvfrom ctx;
 
     *addr = NULL;
 
     if (!getsockaddrlen(s, &addrlen))
         return -1;
+    buflen = addrlen;
 
     if (!IS_SELECTABLE(s)) {
         select_error();
@@ -3037,7 +3064,7 @@ sock_recvfrom_guts(PySocketSockObject *s
     if (sock_call(s, 0, sock_recvfrom_impl, &ctx) < 0)
         return -1;
 
-    *addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+    *addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, buflen,
                          s->sock_proto);
     if (*addr == NULL)
         return -1;
@@ -3277,8 +3304,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;
@@ -5560,7 +5586,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