Date: Thu, 22 Nov 2018 09:41:46 +0000 (UTC) From: Tijl Coosemans <tijl@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r340755 - stable/12/sys/compat/linux Message-ID: <201811220941.wAM9fk38065919@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: tijl Date: Thu Nov 22 09:41:45 2018 New Revision: 340755 URL: https://svnweb.freebsd.org/changeset/base/340755 Log: MFC r340631: Do proper copyin of control message data in the Linux sendmsg syscall. Instead of calling m_append with a user address, allocate an mbuf cluster and copy data into it using copyin. For the SCM_CREDS case, instead of zeroing a stack variable and appending that to the mbuf, zero part of the mbuf cluster directly. One mbuf cluster is also the size limit used by the FreeBSD sendmsg syscall (uipc_syscalls.c:sockargs()). PR: 217901 Reviewed by: kib Modified: stable/12/sys/compat/linux/linux_socket.c Directory Properties: stable/12/ (props changed) Modified: stable/12/sys/compat/linux/linux_socket.c ============================================================================== --- stable/12/sys/compat/linux/linux_socket.c Thu Nov 22 04:48:27 2018 (r340754) +++ stable/12/sys/compat/linux/linux_socket.c Thu Nov 22 09:41:45 2018 (r340755) @@ -1085,7 +1085,6 @@ linux_sendmsg_common(struct thread *td, l_int s, struc l_uint flags) { struct cmsghdr *cmsg; - struct cmsgcred cmcred; struct mbuf *control; struct msghdr msg; struct l_cmsghdr linux_cmsg; @@ -1096,6 +1095,7 @@ linux_sendmsg_common(struct thread *td, l_int s, struc struct sockaddr *sa; sa_family_t sa_family; void *data; + l_size_t len; int error; error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); @@ -1126,7 +1126,6 @@ linux_sendmsg_common(struct thread *td, l_int s, struc return (error); control = NULL; - cmsg = NULL; if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) { error = kern_getsockname(td, s, &sa, &datalen); @@ -1136,8 +1135,10 @@ linux_sendmsg_common(struct thread *td, l_int s, struc free(sa, M_SONAME); error = ENOBUFS; - cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK|M_ZERO); control = m_get(M_WAITOK, MT_CONTROL); + MCLGET(control, M_WAITOK); + data = mtod(control, void *); + datalen = 0; do { error = copyin(ptr_cmsg, &linux_cmsg, @@ -1149,10 +1150,14 @@ linux_sendmsg_common(struct thread *td, l_int s, struc if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) goto bad; + if (datalen + CMSG_HDRSZ > MCLBYTES) + goto bad; + /* * Now we support only SCM_RIGHTS and SCM_CRED, * so return EINVAL in any other cmsg_type */ + cmsg = data; cmsg->cmsg_type = linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); cmsg->cmsg_level = @@ -1170,35 +1175,34 @@ linux_sendmsg_common(struct thread *td, l_int s, struc if (sa_family != AF_UNIX) continue; - data = LINUX_CMSG_DATA(ptr_cmsg); - datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; + if (cmsg->cmsg_type == SCM_CREDS) { + len = sizeof(struct cmsgcred); + if (datalen + CMSG_SPACE(len) > MCLBYTES) + goto bad; - switch (cmsg->cmsg_type) - { - case SCM_RIGHTS: - break; - - case SCM_CREDS: - data = &cmcred; - datalen = sizeof(cmcred); - /* * The lower levels will fill in the structure */ - bzero(data, datalen); - break; + memset(CMSG_DATA(data), 0, len); + } else { + len = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; + if (datalen + CMSG_SPACE(len) < datalen || + datalen + CMSG_SPACE(len) > MCLBYTES) + goto bad; + + error = copyin(LINUX_CMSG_DATA(ptr_cmsg), + CMSG_DATA(data), len); + if (error != 0) + goto bad; } - cmsg->cmsg_len = CMSG_LEN(datalen); - - error = ENOBUFS; - if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg)) - goto bad; - if (!m_append(control, datalen, (c_caddr_t)data)) - goto bad; + cmsg->cmsg_len = CMSG_LEN(len); + data = (char *)data + CMSG_SPACE(len); + datalen += CMSG_SPACE(len); } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg))); - if (m_length(control, NULL) == 0) { + control->m_len = datalen; + if (datalen == 0) { m_freem(control); control = NULL; } @@ -1212,8 +1216,6 @@ linux_sendmsg_common(struct thread *td, l_int s, struc bad: m_freem(control); free(iov, M_IOV); - if (cmsg) - free(cmsg, M_LINUX); return (error); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201811220941.wAM9fk38065919>