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