From 59c1d82cad7834f03a6360f53e4ae0580acfa30e Mon Sep 17 00:00:00 2001 From: ed Date: Wed, 22 Mar 2017 19:20:39 +0000 Subject: [PATCH] Make file descriptor passing for CloudABI's recvmsg() work. Similar to the change for sendmsg(), create a pointer size independent implementation of recvmsg() and let cloudabi32 and cloudabi64 call into it. In case userspace requests one or more file descriptors, call kern_recvit() in such a way that we get the control message headers in an mbuf. Iterate over all of the headers and copy the file descriptors to userspace. --- sys/compat/cloudabi/cloudabi_sock.c | 79 ++++++++++++++++++++++++- sys/compat/cloudabi/cloudabi_util.h | 9 ++- sys/compat/cloudabi32/cloudabi32_sock.c | 41 +++++-------- sys/compat/cloudabi64/cloudabi64_sock.c | 41 +++++-------- 4 files changed, 109 insertions(+), 61 deletions(-) diff --git a/sys/compat/cloudabi/cloudabi_sock.c b/sys/compat/cloudabi/cloudabi_sock.c index 64a72492b3b7..9d0e03691d1a 100644 --- a/sys/compat/cloudabi/cloudabi_sock.c +++ b/sys/compat/cloudabi/cloudabi_sock.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$"); #include /* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */ -void +static void cloudabi_convert_sockaddr(const struct sockaddr *sa, socklen_t sal, cloudabi_sockaddr_t *rsa) { @@ -246,6 +246,81 @@ cloudabi_sys_sock_stat_get(struct thread *td, return (copyout(&ss, uap->buf, sizeof(ss))); } +int +cloudabi_sock_recv(struct thread *td, cloudabi_fd_t fd, struct iovec *data, + size_t datalen, cloudabi_fd_t *fds, size_t fdslen, + cloudabi_msgflags_t flags, size_t *rdatalen, size_t *rfdslen, + cloudabi_sockaddr_t *peername, cloudabi_msgflags_t *rflags) +{ + struct sockaddr_storage ss; + struct msghdr hdr = { + .msg_name = &ss, + .msg_namelen = sizeof(ss), + .msg_iov = data, + .msg_iovlen = datalen, + }; + struct mbuf *control; + int error; + + /* Convert flags. */ + if (flags & CLOUDABI_MSG_PEEK) + hdr.msg_flags |= MSG_PEEK; + if (flags & CLOUDABI_MSG_WAITALL) + hdr.msg_flags |= MSG_WAITALL; + + control = NULL; + error = kern_recvit(td, fd, &hdr, UIO_SYSSPACE, + fdslen > 0 ? &control : NULL); + if (error != 0) + return (error); + + /* Convert return values. */ + *rdatalen = td->td_retval[0]; + td->td_retval[0] = 0; + *rfdslen = 0; + cloudabi_convert_sockaddr((struct sockaddr *)&ss, + MIN(hdr.msg_namelen, sizeof(ss)), peername); + *rflags = 0; + if (hdr.msg_flags & MSG_EOR) + *rflags |= CLOUDABI_MSG_EOR; + if (hdr.msg_flags & MSG_TRUNC) + *rflags |= CLOUDABI_MSG_TRUNC; + + /* Extract file descriptors from SCM_RIGHTS messages. */ + if (control != NULL) { + struct cmsghdr *chdr; + + hdr.msg_control = mtod(control, void *); + hdr.msg_controllen = control->m_len; + for (chdr = CMSG_FIRSTHDR(&hdr); chdr != NULL; + chdr = CMSG_NXTHDR(&hdr, chdr)) { + if (chdr->cmsg_level == SOL_SOCKET && + chdr->cmsg_type == SCM_RIGHTS) { + size_t nfds; + + nfds = (chdr->cmsg_len - CMSG_LEN(0)) / + sizeof(int); + if (nfds > fdslen) { + /* Unable to store file descriptors. */ + nfds = fdslen; + *rflags |= CLOUDABI_MSG_CTRUNC; + } + error = copyout(CMSG_DATA(chdr), fds, + nfds * sizeof(int)); + if (error != 0) { + m_free(control); + return (error); + } + fds += nfds; + fdslen -= nfds; + *rfdslen += nfds; + } + } + m_free(control); + } + return (0); +} + int cloudabi_sock_send(struct thread *td, cloudabi_fd_t fd, struct iovec *data, size_t datalen, const cloudabi_fd_t *fds, size_t fdslen, diff --git a/sys/compat/cloudabi/cloudabi_util.h b/sys/compat/cloudabi/cloudabi_util.h index 0dca3dc30592..e263d5574492 100644 --- a/sys/compat/cloudabi/cloudabi_util.h +++ b/sys/compat/cloudabi/cloudabi_util.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,10 +44,6 @@ int cloudabi_clock_time_get(struct thread *, cloudabi_clockid_t, /* Converts a FreeBSD errno to a CloudABI errno. */ cloudabi_errno_t cloudabi_convert_errno(int); -/* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */ -void cloudabi_convert_sockaddr(const struct sockaddr *, socklen_t, - cloudabi_sockaddr_t *); - /* Converts a file descriptor to a CloudABI file descriptor type. */ cloudabi_filetype_t cloudabi_convert_filetype(const struct file *); @@ -78,6 +74,9 @@ int cloudabi_futex_lock_wrlock(struct thread *, cloudabi_lock_t *, cloudabi_timestamp_t); /* Socket operations. */ +int cloudabi_sock_recv(struct thread *, cloudabi_fd_t, struct iovec *, size_t, + cloudabi_fd_t *, size_t, cloudabi_msgflags_t, size_t *, size_t *, + cloudabi_sockaddr_t *, cloudabi_msgflags_t *); int cloudabi_sock_send(struct thread *, cloudabi_fd_t, struct iovec *, size_t, const cloudabi_fd_t *, size_t, cloudabi_msgflags_t, size_t *); diff --git a/sys/compat/cloudabi32/cloudabi32_sock.c b/sys/compat/cloudabi32/cloudabi32_sock.c index e65f27c69393..1b01fc67214c 100644 --- a/sys/compat/cloudabi32/cloudabi32_sock.c +++ b/sys/compat/cloudabi32/cloudabi32_sock.c @@ -29,9 +29,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include #include #include @@ -48,53 +45,43 @@ int cloudabi32_sys_sock_recv(struct thread *td, struct cloudabi32_sys_sock_recv_args *uap) { - struct sockaddr_storage ss; cloudabi32_recv_in_t ri; cloudabi32_recv_out_t ro = {}; cloudabi32_iovec_t iovobj; - struct msghdr msghdr = {}; + struct iovec *iov; const cloudabi32_iovec_t *user_iov; - size_t i; + size_t i, rdatalen, rfdslen; int error; error = copyin(uap->in, &ri, sizeof(ri)); if (error != 0) return (error); - /* Convert results in cloudabi_recv_in_t to struct msghdr. */ + /* Convert iovecs to native format. */ if (ri.ri_data_len > UIO_MAXIOV) return (EINVAL); - msghdr.msg_iovlen = ri.ri_data_len; - msghdr.msg_iov = malloc(msghdr.msg_iovlen * sizeof(struct iovec), + iov = malloc(ri.ri_data_len * sizeof(struct iovec), M_SOCKET, M_WAITOK); user_iov = TO_PTR(ri.ri_data); - for (i = 0; i < msghdr.msg_iovlen; i++) { + for (i = 0; i < ri.ri_data_len; i++) { error = copyin(&user_iov[i], &iovobj, sizeof(iovobj)); if (error != 0) { - free(msghdr.msg_iov, M_SOCKET); + free(iov, M_SOCKET); return (error); } - msghdr.msg_iov[i].iov_base = TO_PTR(iovobj.buf); - msghdr.msg_iov[i].iov_len = iovobj.buf_len; + iov[i].iov_base = TO_PTR(iovobj.buf); + iov[i].iov_len = iovobj.buf_len; } - msghdr.msg_name = &ss; - msghdr.msg_namelen = sizeof(ss); - if (ri.ri_flags & CLOUDABI_MSG_PEEK) - msghdr.msg_flags |= MSG_PEEK; - if (ri.ri_flags & CLOUDABI_MSG_WAITALL) - msghdr.msg_flags |= MSG_WAITALL; - /* TODO(ed): Add file descriptor passing. */ - error = kern_recvit(td, uap->sock, &msghdr, UIO_SYSSPACE, NULL); - free(msghdr.msg_iov, M_SOCKET); + error = cloudabi_sock_recv(td, uap->sock, iov, ri.ri_data_len, + TO_PTR(ri.ri_fds), ri.ri_fds_len, ri.ri_flags, &rdatalen, + &rfdslen, &ro.ro_peername, &ro.ro_flags); + free(iov, M_SOCKET); if (error != 0) return (error); - /* Convert results in msghdr to cloudabi_recv_out_t. */ - ro.ro_datalen = td->td_retval[0]; - cloudabi_convert_sockaddr((struct sockaddr *)&ss, - MIN(msghdr.msg_namelen, sizeof(ss)), &ro.ro_peername); - td->td_retval[0] = 0; + ro.ro_datalen = rdatalen; + ro.ro_fdslen = rfdslen; return (copyout(&ro, uap->out, sizeof(ro))); } diff --git a/sys/compat/cloudabi64/cloudabi64_sock.c b/sys/compat/cloudabi64/cloudabi64_sock.c index 09b0156143c8..22ec664729ad 100644 --- a/sys/compat/cloudabi64/cloudabi64_sock.c +++ b/sys/compat/cloudabi64/cloudabi64_sock.c @@ -29,9 +29,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include #include #include @@ -48,53 +45,43 @@ int cloudabi64_sys_sock_recv(struct thread *td, struct cloudabi64_sys_sock_recv_args *uap) { - struct sockaddr_storage ss; cloudabi64_recv_in_t ri; cloudabi64_recv_out_t ro = {}; cloudabi64_iovec_t iovobj; - struct msghdr msghdr = {}; + struct iovec *iov; const cloudabi64_iovec_t *user_iov; - size_t i; + size_t i, rdatalen, rfdslen; int error; error = copyin(uap->in, &ri, sizeof(ri)); if (error != 0) return (error); - /* Convert results in cloudabi_recv_in_t to struct msghdr. */ + /* Convert iovecs to native format. */ if (ri.ri_data_len > UIO_MAXIOV) return (EINVAL); - msghdr.msg_iovlen = ri.ri_data_len; - msghdr.msg_iov = malloc(msghdr.msg_iovlen * sizeof(struct iovec), + iov = malloc(ri.ri_data_len * sizeof(struct iovec), M_SOCKET, M_WAITOK); user_iov = TO_PTR(ri.ri_data); - for (i = 0; i < msghdr.msg_iovlen; i++) { + for (i = 0; i < ri.ri_data_len; i++) { error = copyin(&user_iov[i], &iovobj, sizeof(iovobj)); if (error != 0) { - free(msghdr.msg_iov, M_SOCKET); + free(iov, M_SOCKET); return (error); } - msghdr.msg_iov[i].iov_base = TO_PTR(iovobj.buf); - msghdr.msg_iov[i].iov_len = iovobj.buf_len; + iov[i].iov_base = TO_PTR(iovobj.buf); + iov[i].iov_len = iovobj.buf_len; } - msghdr.msg_name = &ss; - msghdr.msg_namelen = sizeof(ss); - if (ri.ri_flags & CLOUDABI_MSG_PEEK) - msghdr.msg_flags |= MSG_PEEK; - if (ri.ri_flags & CLOUDABI_MSG_WAITALL) - msghdr.msg_flags |= MSG_WAITALL; - /* TODO(ed): Add file descriptor passing. */ - error = kern_recvit(td, uap->sock, &msghdr, UIO_SYSSPACE, NULL); - free(msghdr.msg_iov, M_SOCKET); + error = cloudabi_sock_recv(td, uap->sock, iov, ri.ri_data_len, + TO_PTR(ri.ri_fds), ri.ri_fds_len, ri.ri_flags, &rdatalen, + &rfdslen, &ro.ro_peername, &ro.ro_flags); + free(iov, M_SOCKET); if (error != 0) return (error); - /* Convert results in msghdr to cloudabi_recv_out_t. */ - ro.ro_datalen = td->td_retval[0]; - cloudabi_convert_sockaddr((struct sockaddr *)&ss, - MIN(msghdr.msg_namelen, sizeof(ss)), &ro.ro_peername); - td->td_retval[0] = 0; + ro.ro_datalen = rdatalen; + ro.ro_fdslen = rfdslen; return (copyout(&ro, uap->out, sizeof(ro))); }