# 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,