Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Jun 2009 11:15:15 GMT
From:      Robert Watson <rwatson@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 164089 for review
Message-ID:  <200906111115.n5BBFFjb042213@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=164089

Change 164089 by rwatson@rwatson_freebsd_capabilities on 2009/06/11 11:15:13

	Implement a simple and not entirely complete libcapability PRC
	(lcrpc) scheme to allow sandboxes to offer services and hosts to
	consume them.  There's further socket/signal/etc work to do here,
	and no marshalling is implemented (so rpcgen could be used or the
	like if desired).

Affected files ...

.. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#10 edit
.. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_host.c#8 edit
.. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_sandbox.c#4 edit
.. //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_sandbox_api.h#3 edit

Differences ...

==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#10 (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#9 $
+ * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#10 $
  */
 
 #ifndef _LIBCAPABILITY_H_
@@ -66,9 +66,12 @@
 int	lch_getprocdesc(struct lc_sandbox *lcsp, int *fdp);
 
 /*
- * I/O interfaces for capability mode sandboxs.
+ * I/O interfaces for the host environment.
  */
+struct iovec;
 ssize_t	lch_recv(struct lc_sandbox *lcsp, void *buf, size_t len, int flags);
+int	lch_rpc(struct lc_sandbox *lcsp, u_int32_t opno, struct iovec *req,
+	    int reqcount, struct iovec *rep, int repcount, size_t *replenp);
 ssize_t	lch_send(struct lc_sandbox *lcsp, const void *msg, size_t len,
 	    int flags);
 
@@ -78,7 +81,11 @@
 int	lcs_get(struct lc_host **lchpp);
 int	lcs_getsock(struct lc_host *lchp, int *fdp);
 ssize_t	lcs_recv(struct lc_host *lchp, void *buf, size_t len, int flags);
+int	lcs_recvrpc(struct lc_host *lchp, u_int32_t *opnop,
+	    u_int32_t *seqnop, u_char **bufferp, size_t *lenp);
 ssize_t	lcs_send(struct lc_host *lchp, const void *msg, size_t len,
 	    int flags);
+int	lcs_sendrpc(struct lc_host *lchp, u_int32_t opno, u_int32_t seqno,
+	    struct iovec *rep, int repcount);
 
 #endif /* !_LIBCAPABILITY_H_ */

==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_host.c#8 (text+ko) ====

@@ -30,13 +30,14 @@
  * 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#7 $
+ * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_host.c#8 $
  */
 
 #include <sys/types.h>
 #include <sys/capability.h>
 #include <sys/procdesc.h>
 #include <sys/socket.h>
+#include <sys/uio.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -362,7 +363,7 @@
 
 	if (lcap->lcs_fd_sock == -1 ||
 	    lcap->lcs_fd_sock == 0) {
-		errno = ESRCH;
+		errno = ECHILD;
 		return (-1);
 	}
 	return (send(lcap->lcs_fd_sock, msg, len, flags));
@@ -379,3 +380,106 @@
 	}
 	return (recv(lcap->lcs_fd_sock, buf, len, flags));
 }
+
+/*
+ * Simple libcapability RPC facility (lcrpc): send a request, get back a
+ * reply (up to the size bound of the buffers passed in).  The caller is
+ * responsible for retransmitting if the sandbox fails.
+ *
+ * Right now sequence numbers are unimplemented -- that's fine because we
+ * don't need retransmission, and are synchronous.  However, it might not be
+ * a bad idea to use them anyway.
+ */
+int
+lch_rpc(struct lc_sandbox *lcap, u_int32_t opno, struct iovec *req,
+    int reqcount, struct iovec *rep, int repcount, size_t *replenp)
+{
+	struct lcrpc_request_hdr req_hdr;
+	struct lcrpc_reply_hdr rep_hdr;
+	size_t left, off, space, totlen, want;
+	ssize_t len;
+	int i;
+
+	bzero(&req_hdr, sizeof(req_hdr));
+	req_hdr.lcrpc_reqhdr_magic = LCRPC_REQUEST_HDR_MAGIC;
+	req_hdr.lcrpc_reqhdr_seqno = 0;
+	req_hdr.lcrpc_reqhdr_opno = opno;
+	for (i = 0; i < reqcount; i++)
+		req_hdr.lcrpc_reqhdr_datalen += req[i].iov_len;
+	for (i = 0; i < repcount; i++)
+		req_hdr.lcrpc_reqhdr_maxrepdatalen += rep[i].iov_len;
+
+	/*
+	 * Send our header.
+	 */
+	len = lch_send(lcap, &req_hdr, sizeof(req_hdr), 0);
+	if (len < 0)
+		return (-1);
+	if (len != sizeof(req_hdr)) {
+		errno = ECHILD;
+		return (-1);
+	}
+
+	/*
+	 * Send the user request.
+	 */
+	for (i = 0; i < reqcount; i++) {
+		len = lch_send(lcap, req[i].iov_base, req[i].iov_len, 0);
+		if (len < 0)
+			return (-1);
+		if ((size_t)len != req[i].iov_len) {
+			errno = ECHILD;
+			return (-1);
+		}
+	}
+
+	/*
+	 * Receive our header and validate.
+	 */
+	len = lch_recv(lcap, &rep_hdr, sizeof(rep_hdr), MSG_WAITALL);
+	if (len < 0)
+		return (-1);
+	if (len != sizeof(rep_hdr)) {
+		errno = ECHILD;
+		return (-1);
+	}
+
+	if (rep_hdr.lcrpc_rephdr_magic != LCRPC_REPLY_HDR_MAGIC ||
+	    rep_hdr.lcrpc_rephdr_seqno != 0 ||
+	    rep_hdr.lcrpc_rephdr_opno != opno ||
+	    rep_hdr.lcrpc_rephdr_datalen > req_hdr.lcrpc_reqhdr_maxrepdatalen) {
+		errno = EBADRPC;
+		return (-1);
+	}
+
+	/*
+	 * Receive the user data.  Notice that we can partially overwrite the
+	 * user buffer but still receive an error.
+	 */
+	totlen = 0;
+	for (i = 0; i < repcount; i++) {
+		off = 0;
+		while (totlen < rep_hdr.lcrpc_rephdr_datalen) {
+			space = rep[i].iov_len - off;
+			left = rep_hdr.lcrpc_rephdr_datalen - totlen;
+			want = (space > left) ? space : left;
+			len = lch_recv(lcap,
+			    (u_char *)((uintptr_t)rep[i].iov_base + off),
+			    want, MSG_WAITALL);
+			if (len < 0)
+				return (-1);
+			if ((size_t)len != want) {
+				errno = ECHILD;
+				return (-1);
+			}
+			off += len;
+			totlen += len;
+			if (rep[i].iov_len == off)
+				break;
+		}
+		if (totlen == rep_hdr.lcrpc_rephdr_datalen)
+			break;
+	}
+	*replenp = totlen;
+	return (0);
+}

==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_sandbox.c#4 (text+ko) ====

@@ -37,6 +37,7 @@
 #include <sys/types.h>
 #include <sys/capability.h>
 #include <sys/socket.h>
+#include <sys/uio.h>
 
 #include <errno.h>
 #include <limits.h>
@@ -122,3 +123,107 @@
 
 	return (send(lchp->lch_fd_sock, msg, len, flags));
 }
+
+/*
+ * libcapability RPC facility (lcrpc) sandbox routines.  Since arguments are
+ * variable size, space is allocated by the RPC code rather than the caller,
+ * who is expected to free it with free(3) if desired.
+ */
+int
+lcs_recvrpc(struct lc_host *lchp, u_int32_t *opnop, u_int32_t *seqnop,
+    u_char **bufferp, size_t *lenp)
+{
+	struct lcrpc_request_hdr req_hdr;
+	size_t totlen;
+	ssize_t len;
+	u_char *buffer;
+	int error;
+
+	len = lcs_recv(lchp, &req_hdr, sizeof(req_hdr), MSG_WAITALL);
+	if (len < 0)
+		return (-1);
+	if (len != sizeof(req_hdr)) {
+		errno = EBADMSG;
+		return (-1);
+	}
+
+	if (req_hdr.lcrpc_reqhdr_magic != LCRPC_REQUEST_HDR_MAGIC) {
+		errno = EBADMSG;
+		return (-1);
+	}
+
+	/*
+	 * XXXRW: Should we check that the receive data fits in the address
+	 * space of the sandbox?
+	 *
+	 * XXXRW: If malloc() fails, we should drain the right amount of data
+	 * from the socket so that the next RPC will succeed.  Possibly we
+	 * should also reply with an error from this layer to the sender?
+	 * What about if there are other socket errors, such as EINTR?
+	 */
+	buffer = malloc(req_hdr.lcrpc_reqhdr_datalen);
+	if (buffer == NULL)
+		return (-1);
+
+	/*
+	 * XXXRW: Likewise, how to handle failure at this stage?
+	 */
+	totlen = 0;
+	while (totlen < req_hdr.lcrpc_reqhdr_datalen) {
+		len = lcs_recv(lchp, buffer + totlen,
+		    req_hdr.lcrpc_reqhdr_datalen - totlen, MSG_WAITALL);
+		if (len < 0) {
+			error = errno;
+			free(buffer);
+			return (-1);
+		}
+		totlen += len;
+	}
+	*bufferp = buffer;
+	*lenp = totlen;
+	*opnop = req_hdr.lcrpc_reqhdr_opno;
+	*seqnop = req_hdr.lcrpc_reqhdr_seqno;
+	return (0);
+}
+
+int
+lcs_sendrpc(struct lc_host *lchp, u_int32_t opno, u_int32_t seqno,
+    struct iovec *rep, int repcount)
+{
+	struct lcrpc_reply_hdr rep_hdr;
+	ssize_t len;
+	int i;
+
+	bzero(&rep_hdr, sizeof(rep_hdr));
+	rep_hdr.lcrpc_rephdr_magic = LCRPC_REPLY_HDR_MAGIC;
+	rep_hdr.lcrpc_rephdr_seqno = seqno;
+	rep_hdr.lcrpc_rephdr_opno = opno;
+	rep_hdr.lcrpc_rephdr_datalen = 0;
+	for (i = 0; i < repcount; i++)
+		rep_hdr.lcrpc_rephdr_datalen += rep[i].iov_len;
+
+	/*
+	 * Send our header.
+	 */
+	len = lcs_send(lchp, &rep_hdr, sizeof(rep_hdr), 0);
+	if (len < 0)
+		return (-1);
+	if (len != sizeof(rep_hdr)) {
+		errno = EPIPE;
+		return (-1);
+	}
+
+	/*
+	 * Send user data.
+	 */
+	for (i = 0; i < repcount; i++) {
+		len = lcs_send(lchp, rep[i].iov_base, rep[i].iov_len, 0);
+		if (len < 0)
+			return (-1);
+		if ((size_t)len != rep[i].iov_len) {
+			errno = EPIPE;
+			return (-1);
+		}
+	}
+	return (0);
+}

==== //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_sandbox_api.h#3 (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_sandbox_api.h#2 $
+ * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_sandbox_api.h#3 $
  */
 
 #ifndef _LIBCAPABILITY_SANDBOX_API_H_
@@ -43,4 +43,33 @@
 #define	LIBCAPABILITY_SANDBOX_API_ENV	"LIBCAPABILITY_SANDBOX"
 #define	LIBCAPABILITY_SANDBOX_API_SOCK	"sock"
 
+/*
+ * Simple libcapability RPC facility (lcrpc) definitions.
+ */
+#define	LCRPC_REQUEST_HDR_MAGIC	0x29ee2d7eb9143d98
+struct lcrpc_request_hdr {
+	u_int64_t	lcrpc_reqhdr_magic;
+	u_int32_t	lcrpc_reqhdr_seqno;
+	u_int32_t	lcrpc_reqhdr_opno;
+	u_int64_t	lcrpc_reqhdr_datalen;
+	u_int64_t	lcrpc_reqhdr_maxrepdatalen;
+	u_int64_t	_lcrpc_reqhdr_spare3;
+	u_int64_t	_lcrpc_reqhdr_spare2;
+	u_int64_t	_lcrpc_reqhdr_spare1;
+	u_int64_t	_lcrpc_reqhdr_spare0;
+} __packed;
+
+#define	LCRPC_REPLY_HDR_MAGIC	0x37cc2e29f5cce29b
+struct lcrpc_reply_hdr {
+	u_int64_t	lcrpc_rephdr_magic;
+	u_int32_t	lcrpc_rephdr_seqno;
+	u_int32_t	lcrpc_rephdr_opno;
+	u_int64_t	lcrpc_rephdr_datalen;
+	u_int64_t	_lcrpc_rephdr_spare4;
+	u_int64_t	_lcrpc_rephdr_spare3;
+	u_int64_t	_lcrpc_rephdr_spare2;
+	u_int64_t	_lcrpc_rephdr_spare1;
+	u_int64_t	_lcrpc_rephdr_spare0;
+} __packed;
+
 #endif /* !_LIBCAPABILITY_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906111115.n5BBFFjb042213>