PERFORCE change 164089 for review
Robert Watson
rwatson at FreeBSD.org
Thu Jun 11 11:15:16 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=164089
Change 164089 by rwatson at 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_ */
More information about the p4-projects
mailing list