svn commit: r340755 - stable/12/sys/compat/linux
Tijl Coosemans
tijl at FreeBSD.org
Thu Nov 22 09:41:46 UTC 2018
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);
}
More information about the svn-src-stable
mailing list