From owner-p4-projects@FreeBSD.ORG Sun Jun 14 18:03:44 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 0BCDA1065672; Sun, 14 Jun 2009 18:03:44 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BD692106566C for ; Sun, 14 Jun 2009 18:03:43 +0000 (UTC) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id A814A8FC0C for ; Sun, 14 Jun 2009 18:03:43 +0000 (UTC) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n5EI3hUl056291 for ; Sun, 14 Jun 2009 18:03:43 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n5EI3h92056289 for perforce@freebsd.org; Sun, 14 Jun 2009 18:03:43 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Date: Sun, 14 Jun 2009 18:03:43 GMT Message-Id: <200906141803.n5EI3h92056289@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to bb+lists.freebsd.perforce@cyrus.watson.org using -f From: Robert Watson To: Perforce Change Reviews Cc: Subject: PERFORCE change 164361 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Jun 2009 18:03:44 -0000 http://perforce.freebsd.org/chv.cgi?CH=164361 Change 164361 by rwatson@rwatson_freebsd_capabilities on 2009/06/14 18:02:59 Implement I/O functions for host and sandbox environment that allow sending and receiving arrays of file descriptors. This proves somewhat tricky to do robustly, as the recvmsg(2) API makes it hard to properly handle all error edge cases, but we do our best. Because 99% of the I/O functions are shared between host and sandbox, implement them in a common location. Update documentation. Affected files ... .. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.c#7 edit .. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#15 edit .. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_host.c#13 edit .. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_internal.h#1 add .. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_io.3#3 edit .. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_sandbox.c#6 edit Differences ... ==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.c#7 (text+ko) ==== @@ -30,16 +30,20 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.c#6 $ + * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.c#7 $ */ #include #include +#include #include +#include #include #include "libcapability.h" +#include "libcapability_internal.h" +#include "libcapability_sandbox_api.h" int lc_limitfd(int fd, cap_rights_t rights) @@ -59,3 +63,171 @@ close(fd_cap); return (0); } + +/* + * Given a 'struct msghdr' returned by a successful call to recvmsg(), + * extract up to the desired number of file descriptors (or clean up the + * mess if something goes wrong). + */ +int +_lc_receive_rights(struct msghdr *msg, int *fdp, int *fdcountp) +{ + int *cmsg_fdp, fdcount, i, scmrightscount; + struct cmsghdr *cmsg; + + /* + * Walk the complete control message chain to count received control + * messages and rights. If there is more than one rights message or + * there are too many file descriptors, re-walk and close them all + * and return an error. + */ + fdcount = 0; + scmrightscount = 0; + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) + continue; + fdcount += (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + scmrightscount++; + } + if (scmrightscount > 1 || fdcount > *fdcountp) { + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) + continue; + cmsg_fdp = (int *)CMSG_DATA(cmsg); + fdcount = (cmsg->cmsg_len - CMSG_LEN(0)) / + sizeof(int); + for (i = 0; i < fdcount; i++) + close(cmsg_fdp[i]); + } + errno = EBADMSG; + return (-1); + } + + /* + * Re-walk the control messages and copy out the file descriptor + * numbers, return success. No need to recalculate fdcount. + */ + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) + continue; + cmsg_fdp = (int *)CMSG_DATA(cmsg); + for (i = 0; i < fdcount; i++) + fdp[i] = cmsg_fdp[i]; + } + *fdcountp = fdcount; + return (0); +} + +ssize_t +_lc_send(int fd, const void *msg, size_t len, int flags) +{ + + if (fd == -1 || fd == 0) { + errno = ECHILD; + return (-1); + } + return (send(fd, msg, len, flags)); +} + +ssize_t +_lc_send_rights(int fd, const void *msg, size_t len, int flags, int *fdp, + int fdcount) +{ + char cmsgbuf[CMSG_SPACE(LIBCAPABILITY_SANDBOX_API_MAXRIGHTS * + sizeof(int))]; + struct cmsghdr *cmsg; + struct msghdr msghdr; + struct iovec iov; + int i; + + if (fdcount == 0) + return (_lc_send(fd, msg, len, flags)); + + if (fd == -1 || fd == 0) { + errno = ECHILD; + return (-1); + } + + if (fdcount > LIBCAPABILITY_SANDBOX_API_MAXRIGHTS) { + errno = EMSGSIZE; + return (-1); + } + + bzero(&iov, sizeof(iov)); + iov.iov_base = __DECONST(void *, msg); + iov.iov_len = len; + + bzero(&msghdr, sizeof(msghdr)); + bzero(&cmsgbuf, sizeof(cmsgbuf)); + cmsg = (struct cmsghdr *)cmsgbuf; + cmsg->cmsg_len = CMSG_SPACE(fdcount * sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + for (i = 0; i < fdcount; i++) + ((int *)CMSG_DATA(cmsg))[i] = fdp[i]; + + bzero(&msghdr, sizeof(msghdr)); + msghdr.msg_iov = &iov; + msghdr.msg_iovlen = 1; + msghdr.msg_control = cmsg; + msghdr.msg_controllen = cmsg->cmsg_len; + + return (sendmsg(fd, &msghdr, flags)); +} + +ssize_t +_lc_recv(int fd, void *buf, size_t len, int flags) +{ + + if (fd == -1 || fd == 0) { + errno = ESRCH; + return (-1); + } + return (recv(fd, buf, len, flags)); +} + +ssize_t +_lc_recv_rights(int fd, void *buf, size_t len, int flags, int *fdp, + int *fdcountp) +{ + char cmsgbuf[CMSG_SPACE(LIBCAPABILITY_SANDBOX_API_MAXRIGHTS * + sizeof(int))]; + struct msghdr msghdr; + struct iovec iov; + ssize_t retlen; + + if (*fdcountp == 0) + return (_lc_recv(fd, buf, len, flags)); + + if (fd == -1 || fd == 0) { + errno = ECHILD; + return (-1); + } + + if (*fdcountp > LIBCAPABILITY_SANDBOX_API_MAXRIGHTS) { + errno = EMSGSIZE; + return (-1); + } + + bzero(&iov, sizeof(iov)); + iov.iov_base = buf; + iov.iov_len = len; + + bzero(cmsgbuf, sizeof(cmsgbuf)); + bzero(&msghdr, sizeof(msghdr)); + msghdr.msg_control = cmsgbuf; + msghdr.msg_controllen = sizeof(cmsgbuf); + + retlen = recvmsg(fd, &msghdr, flags); + if (retlen < 0) + return (-1); + if (_lc_receive_rights(&msghdr, fdp, fdcountp) < 0) + return (-1); + return (retlen); +} ==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#15 (text+ko) ==== @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#14 $ + * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#15 $ */ #ifndef _LIBCAPABILITY_H_ @@ -100,8 +100,12 @@ * Message-passing APIs for the sandbox environment. */ ssize_t lcs_recv(struct lc_host *lchp, void *buf, size_t len, int flags); +ssize_t lcs_recv_rights(struct lc_host *lchp, void *buf, size_t len, + int flags, int *fdp, int *fdcountp); ssize_t lcs_send(struct lc_host *lchp, const void *msg, size_t len, int flags); +ssize_t lcs_send_rights(struct lc_host *lchp, const void *msg, size_t len, + int flags, int *fdp, int fdcount); /* * RPC APIs for the sandbox environment. ==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_host.c#13 (text+ko) ==== @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_host.c#12 $ + * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_host.c#13 $ */ #include @@ -49,6 +49,7 @@ #include #include "libcapability.h" +#include "libcapability_internal.h" #include "libcapability_sandbox_api.h" #define LIBCAPABILITY_CAPMASK_DEVNULL (CAP_EVENT | CAP_READ | CAP_WRITE) @@ -410,24 +411,32 @@ lch_send(struct lc_sandbox *lcsp, const void *msg, size_t len, int flags) { - if (lcsp->lcs_fd_sock == -1 || - lcsp->lcs_fd_sock == 0) { - errno = ECHILD; - return (-1); - } - return (send(lcsp->lcs_fd_sock, msg, len, flags)); + return (_lc_send(lcsp->lcs_fd_sock, msg, len, flags)); +} + +ssize_t +lch_send_rights(struct lc_sandbox *lcsp, const void *msg, size_t len, + int flags, int *fdp, int fdcount) +{ + + return (_lc_send_rights(lcsp->lcs_fd_sock, msg, len, flags, fdp, + fdcount)); } ssize_t lch_recv(struct lc_sandbox *lcsp, void *buf, size_t len, int flags) { - if (lcsp->lcs_fd_sock == -1 || - lcsp->lcs_fd_sock == 0) { - errno = ESRCH; - return (-1); - } - return (recv(lcsp->lcs_fd_sock, buf, len, flags)); + return (_lc_recv(lcsp->lcs_fd_sock, buf, len, flags)); +} + +ssize_t +lch_recv_rights(struct lc_sandbox *lcsp, void *buf, size_t len, int flags, + int *fdp, int *fdcountp) +{ + + return (_lc_recv_rights(lcsp->lcs_fd_sock, buf, len, flags, fdp, + fdcountp)); } /* ==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_io.3#3 (text+ko) ==== @@ -46,16 +46,24 @@ .In libcapability.h .Ft ssize_t .Fn lch_recv "struct lc_sandbox *lcsp, void *buf" "size_t len" "int flags" +.Ft ssize_t +.Fn lch_recv_rights "struct lc_sandbox *lcsp" "void *buf" "size_t len" "int flags" "int *fdp" "int *fdcountp" .Ft int .Fn lch_rpc "struct lc_sandbox *lcsp" "u_int32_t opno" "struct iovec *req" "int reqcount" "struct iovec *rep" "int repcount" "size_t *replenp" .Ft ssize_t .Fn lch_send "struct lc_sandbox *lcsp" "const void *msg" "size_t len" "int flags" .Ft ssize_t +.Fn lch_send_rights "struct lc_sandbox *lcsp" "const void *msg" "size_t len" "int flags" "int *fdp" "int fdcount" +.Ft ssize_t .Fn lcs_recv "struct lc_host *lchp" "void *buf" "size_t len" "int flags" +.Ft ssize_t +.Fn lcs_recv_rights "struct lc_host *lchp" "void *buf" "size_t len" "int flags" "int *fdp" "int *fdcountp" .Ft int .Fn lcs_recvrpc "struct lc_host *lchp" "u_int32_t *opnop" "u_int32_t *seqnop" "u_char **bufferp" "size_t *lenp" .Ft ssize_t .Fn lcs_send "struct lc_host *lchp" "const void *msg" "size_t len" "int flags" +.Ft ssize_t +.Fn lcs_send_rights "struct lc_host *lchp" "const void *msg" "size_t len" "int flags" "int *fdp" "int fdcount" .Ft int .Fn lcs_sendrpc "struct lc_host *lchp" "u_int32_t opno" "u_int32_t seqno" "struct iovec *rep" "int repcount" .Sh DESCRIPTION @@ -86,6 +94,24 @@ to avoid sandbox consumers from having to query sandbox socket file descriptors before use. .Pp +.Fn lch_recv_rights +and +.Fn lch_send_rights +are similar, but allow file descriptors to be attached the the messages +received and sent. +Both accept a pointer to a file descriptor array, +.Va fdp . +Callers to +.Fn lch_recv_rights +will pass in the length of the array via +.Va fdcountp , +whose value will be changed to the actual number of file descriptors +received. +Callers to +.Fn lch_send_rights +will pass in the number of file descriptors in the array via +Va fdcount . +.Pp .Fn lch_rpc provides a simple synchronous RPC facility, and is intended to be used in coordination with the @@ -120,6 +146,11 @@ .Xr send 2 to avoid sandboxes having to query host socket file descriptors before use. .Pp +.Fn lcs_recv_rights +and +.Fn lcs_send_rights +similarly allow receiving and sending file descriptors with messages. +.Pp .Fn lcs_recvrpc and .Fn lcs_sendrpc ==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_sandbox.c#6 (text+ko) ==== @@ -45,6 +45,7 @@ #include #include "libcapability.h" +#include "libcapability_internal.h" #include "libcapability_sandbox_api.h" struct lc_host { @@ -114,14 +115,32 @@ lcs_recv(struct lc_host *lchp, void *buf, size_t len, int flags) { - return (recv(lchp->lch_fd_sock, buf, len, flags)); + return (_lc_recv(lchp->lch_fd_sock, buf, len, flags)); +} + +ssize_t +lcs_recv_rights(struct lc_host *lchp, void *buf, size_t len, int flags, + int *fdp, int *fdcountp) +{ + + return (_lc_recv_rights(lchp->lch_fd_sock, buf, len, flags, fdp, + fdcountp)); } ssize_t lcs_send(struct lc_host *lchp, const void *msg, size_t len, int flags) { - return (send(lchp->lch_fd_sock, msg, len, flags)); + return (_lc_send(lchp->lch_fd_sock, msg, len, flags)); +} + +ssize_t +lcs_send_rights(struct lc_host *lchp, const void *msg, size_t len, + int flags, int *fdp, int fdcount) +{ + + return (_lc_send_rights(lchp->lch_fd_sock, msg, len, flags, fdp, + fdcount)); } /*