git: ac37e0edf97a - stable/13 - linux(4): Improve recvmsg() readability
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 17 Jun 2022 19:41:12 UTC
The branch stable/13 has been updated by dchagin: URL: https://cgit.FreeBSD.org/src/commit/?id=ac37e0edf97ace6a2dfc8271af94bdb096880cc2 commit ac37e0edf97ace6a2dfc8271af94bdb096880cc2 Author: Dmitry Chagin <dchagin@FreeBSD.org> AuthorDate: 2022-05-28 20:44:02 +0000 Commit: Dmitry Chagin <dchagin@FreeBSD.org> CommitDate: 2022-06-17 19:35:34 +0000 linux(4): Improve recvmsg() readability To improve recvmsg() readability SCM_ handlers moved to a separate functions. MFC after: 2 weeks (cherry picked from commit b408788d6b7edf91a6c4b9e2e8d1b34fe5d41525) --- sys/compat/linux/linux_socket.c | 154 +++++++++++++++++++++++++--------------- 1 file changed, 95 insertions(+), 59 deletions(-) diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 71f958b57298..4dee89d1ebd6 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -1532,26 +1532,90 @@ linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args) return (error); } +static int +recvmsg_scm_rights(struct thread *td, l_uint flags, socklen_t *datalen, + void **data, void **udata) +{ + int i, fd, fds, *fdp; + + if (flags & LINUX_MSG_CMSG_CLOEXEC) { + fds = *datalen / sizeof(int); + fdp = *data; + for (i = 0; i < fds; i++) { + fd = *fdp++; + (void)kern_fcntl(td, fd, F_SETFD, FD_CLOEXEC); + } + } + return (0); +} + +static int +recvmsg_scm_creds(socklen_t *datalen, void **data, void **udata) +{ + struct cmsgcred *cmcred; + struct l_ucred lu; + + cmcred = *data; + lu.pid = cmcred->cmcred_pid; + lu.uid = cmcred->cmcred_uid; + lu.gid = cmcred->cmcred_gid; + memmove(*data, &lu, sizeof(lu)); + *datalen = sizeof(lu); + return (0); +} +_Static_assert(sizeof(struct cmsgcred) >= sizeof(struct l_ucred), + "scm_creds sizeof l_ucred"); + +static int +recvmsg_scm_creds2(socklen_t *datalen, void **data, void **udata) +{ + struct sockcred2 *scred; + struct l_ucred lu; + + scred = *data; + lu.pid = scred->sc_pid; + lu.uid = scred->sc_uid; + lu.gid = scred->sc_gid; + memmove(*data, &lu, sizeof(lu)); + *datalen = sizeof(lu); + return (0); +} +_Static_assert(sizeof(struct sockcred2) >= sizeof(struct l_ucred), + "scm_creds2 sizeof l_ucred"); + +static int +recvmsg_scm_timestamp(socklen_t *datalen, void **data, void **udata) +{ + struct timeval *ftmvl; + l_timeval *ltv; + + if (*datalen != sizeof(struct timeval)) + return (EMSGSIZE); + + ftmvl = *data; + ltv = malloc(sizeof(*ltv), M_LINUX, M_WAITOK); + ltv->tv_sec = ftmvl->tv_sec; + ltv->tv_usec = ftmvl->tv_usec; + *data = *udata = ltv; + *datalen = sizeof(*ltv); + return (0); +} + static int linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, l_uint flags, struct msghdr *msg) { struct cmsghdr *cm; - struct cmsgcred *cmcred; - struct sockcred2 *scred; struct l_cmsghdr *linux_cmsg = NULL; - struct l_ucred linux_ucred; socklen_t datalen, maxlen, outlen; struct l_msghdr linux_msghdr; struct iovec *iov, *uiov; struct mbuf *control = NULL; struct mbuf **controlp; - struct timeval *ftmvl; struct sockaddr *sa; - l_timeval ltmvl; caddr_t outbuf; - void *data; - int error, i, fd, fds, *fdp; + void *data, *udata; + int error; error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr)); if (error != 0) @@ -1635,69 +1699,40 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, data = CMSG_DATA(cm); datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; + udata = NULL; switch (cm->cmsg_type) { case SCM_RIGHTS: - if (flags & LINUX_MSG_CMSG_CLOEXEC) { - fds = datalen / sizeof(int); - fdp = data; - for (i = 0; i < fds; i++) { - fd = *fdp++; - (void)kern_fcntl(td, fd, - F_SETFD, FD_CLOEXEC); - } - } + error = recvmsg_scm_rights(td, flags, + &datalen, &data, &udata); break; case SCM_CREDS: - /* - * Currently LOCAL_CREDS is never in - * effect for Linux so no need to worry - * about sockcred - */ - if (datalen != sizeof(*cmcred)) { - error = EMSGSIZE; - goto bad; - } - cmcred = (struct cmsgcred *)data; - bzero(&linux_ucred, sizeof(linux_ucred)); - linux_ucred.pid = cmcred->cmcred_pid; - linux_ucred.uid = cmcred->cmcred_uid; - linux_ucred.gid = cmcred->cmcred_gid; - data = &linux_ucred; - datalen = sizeof(linux_ucred); + error = recvmsg_scm_creds(&datalen, + &data, &udata); break; case SCM_CREDS2: - scred = data; - bzero(&linux_ucred, sizeof(linux_ucred)); - linux_ucred.pid = scred->sc_pid; - linux_ucred.uid = scred->sc_uid; - linux_ucred.gid = scred->sc_gid; - data = &linux_ucred; - datalen = sizeof(linux_ucred); + error = recvmsg_scm_creds2(&datalen, + &data, &udata); break; case SCM_TIMESTAMP: - if (datalen != sizeof(struct timeval)) { - error = EMSGSIZE; - goto bad; - } - ftmvl = (struct timeval *)data; - ltmvl.tv_sec = ftmvl->tv_sec; - ltmvl.tv_usec = ftmvl->tv_usec; - data = <mvl; - datalen = sizeof(ltmvl); + error = recvmsg_scm_timestamp(&datalen, + &data, &udata); break; } + if (error != 0) + goto bad; if (outlen + LINUX_CMSG_LEN(datalen) > maxlen) { if (outlen == 0) { error = EMSGSIZE; - goto bad; + goto err; } else { linux_msghdr.msg_flags |= LINUX_MSG_CTRUNC; m_dispose_extcontrolm(control); + free(udata, M_LINUX); goto out; } } @@ -1705,18 +1740,19 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); + if (error == 0) { + outbuf += L_CMSG_HDRSZ; + error = copyout(data, outbuf, datalen); + if (error == 0) { + outbuf += LINUX_CMSG_ALIGN(datalen); + outlen += LINUX_CMSG_LEN(datalen); + cm = CMSG_NXTHDR(msg, cm); + } + } +err: + free(udata, M_LINUX); if (error != 0) goto bad; - outbuf += L_CMSG_HDRSZ; - - error = copyout(data, outbuf, datalen); - if (error != 0) - goto bad; - - outbuf += LINUX_CMSG_ALIGN(datalen); - outlen += LINUX_CMSG_LEN(datalen); - - cm = CMSG_NXTHDR(msg, cm); } linux_msghdr.msg_controllen = outlen; }