From owner-p4-projects@FreeBSD.ORG Thu Jun 11 11:15:15 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 9CCC01065670; Thu, 11 Jun 2009 11:15:15 +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 5B187106564A for ; Thu, 11 Jun 2009 11:15:15 +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 4581E8FC1D for ; Thu, 11 Jun 2009 11:15:15 +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 n5BBFF0N042215 for ; Thu, 11 Jun 2009 11:15:15 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 n5BBFFjb042213 for perforce@freebsd.org; Thu, 11 Jun 2009 11:15:15 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Date: Thu, 11 Jun 2009 11:15:15 GMT Message-Id: <200906111115.n5BBFFjb042213@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 164089 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: Thu, 11 Jun 2009 11:15:16 -0000 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 #include #include #include +#include #include #include @@ -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 #include #include +#include #include #include @@ -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_ */