PERFORCE change 164361 for review

Robert Watson rwatson at FreeBSD.org
Sun Jun 14 18:03:44 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=164361

Change 164361 by rwatson at 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 <sys/types.h>
 #include <sys/capability.h>
+#include <sys/socket.h>
 
 #include <errno.h>
+#include <string.h>
 #include <unistd.h>
 
 #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 <sys/param.h>
@@ -49,6 +49,7 @@
 #include <unistd.h>
 
 #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 <string.h>
 
 #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));
 }
 
 /*


More information about the p4-projects mailing list