Module Name:    src
Committed By:   yamt
Date:           Fri Jun 29 13:20:25 UTC 2012

Modified Files:
        src/lib/librumphijack: hijack.c

Log Message:
implement descriptor passing.


To generate a diff of this commit:
cvs rdiff -u -r1.93 -r1.94 src/lib/librumphijack/hijack.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/librumphijack/hijack.c
diff -u src/lib/librumphijack/hijack.c:1.93 src/lib/librumphijack/hijack.c:1.94
--- src/lib/librumphijack/hijack.c:1.93	Mon Jun 25 22:32:47 2012
+++ src/lib/librumphijack/hijack.c	Fri Jun 29 13:20:25 2012
@@ -1,4 +1,4 @@
-/*      $NetBSD: hijack.c,v 1.93 2012/06/25 22:32:47 abs Exp $	*/
+/*      $NetBSD: hijack.c,v 1.94 2012/06/29 13:20:25 yamt Exp $	*/
 
 /*-
  * Copyright (c) 2011 Antti Kantee.  All Rights Reserved.
@@ -29,7 +29,7 @@
 #undef _FORTIFY_SOURCE
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: hijack.c,v 1.93 2012/06/25 22:32:47 abs Exp $");
+__RCSID("$NetBSD: hijack.c,v 1.94 2012/06/29 13:20:25 yamt Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -1335,6 +1335,122 @@ write(int fd, const void *buf, size_t bl
 }
 
 /*
+ * file descriptor passing
+ *
+ * we intercept sendmsg and recvmsg to convert file descriptors in
+ * control messages.  an attempt to send a descriptor from a different kernel
+ * is rejected.  (ENOTSUP)
+ */
+
+static int
+msg_convert(struct msghdr *msg, int (*func)(int))
+{
+	struct cmsghdr *cmsg;
+
+	for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
+	    cmsg = CMSG_NXTHDR(msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_RIGHTS) {
+			int *fdp = (void *)CMSG_DATA(cmsg);
+			const size_t size =
+			    cmsg->cmsg_len - __CMSG_ALIGN(sizeof(*cmsg));
+			const int nfds = size / sizeof(int);
+			const int * const efdp = fdp + nfds;
+
+			while (fdp < efdp) {
+				const int newval = func(*fdp);
+
+				if (newval < 0) {
+					return ENOTSUP;
+				}
+				*fdp = newval;
+				fdp++;
+			}
+		}
+	}
+	return 0;
+}
+
+ssize_t
+recvmsg(int fd, struct msghdr *msg, int flags)
+{
+	ssize_t (*op_recvmsg)(int, struct msghdr *, int);
+	ssize_t ret;
+	const bool isrump = fd_isrump(fd);
+
+	if (isrump) {
+		fd = fd_host2rump(fd);
+		op_recvmsg = GETSYSCALL(rump, RECVMSG);
+	} else {
+		op_recvmsg = GETSYSCALL(host, RECVMSG);
+	}
+	ret = op_recvmsg(fd, msg, flags);
+	if (ret == -1) {
+		return ret;
+	}
+	/*
+	 * convert descriptors in the message.
+	 */
+	if (isrump) {
+		msg_convert(msg, fd_rump2host);
+	} else {
+		msg_convert(msg, fd_host2host);
+	}
+	return ret;
+}
+
+static int
+fd_check_rump(int fd)
+{
+
+	return fd_isrump(fd) ? 0 : -1;
+}
+
+static int
+fd_check_host(int fd)
+{
+
+	return !fd_isrump(fd) ? 0 : -1;
+}
+
+ssize_t
+sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+	ssize_t (*op_sendmsg)(int, const struct msghdr *, int);
+	const bool isrump = fd_isrump(fd);
+	int error;
+
+	/*
+	 * reject descriptors from a different kernel.
+	 */
+	error = msg_convert(__UNCONST(msg),
+	    isrump ? fd_check_rump: fd_check_host);
+	if (error != 0) {
+		errno = error;
+		return -1;
+	}
+	/*
+	 * convert descriptors in the message to raw values.
+	 */
+	if (isrump) {
+		fd = fd_host2rump(fd);
+		/*
+		 * XXX we directly modify the given message assuming:
+		 * - cmsg is writable (typically on caller's stack)
+		 * - caller don't care cmsg's contents after calling sendmsg.
+		 *   (thus no need to restore values)
+		 *
+		 * it's safer to copy and modify instead.
+		 */
+		msg_convert(__UNCONST(msg), fd_host2rump);
+		op_sendmsg = GETSYSCALL(rump, SENDMSG);
+	} else {
+		op_sendmsg = GETSYSCALL(host, SENDMSG);
+	}
+	return op_sendmsg(fd, msg, flags);
+}
+
+/*
  * dup2 is special.  we allow dup2 of a rump kernel fd to 0-2 since
  * many programs do that.  dup2 of a rump kernel fd to another value
  * not >= fdoff is an error.
@@ -1949,16 +2065,6 @@ FDCALL(ssize_t, sendto, DUALCALL_SENDTO,
 	    const struct sockaddr *, socklen_t),			\
 	(fd, buf, len, flags, to, tolen))
 
-FDCALL(ssize_t, recvmsg, DUALCALL_RECVMSG, 				\
-	(int fd, struct msghdr *msg, int flags),			\
-	(int, struct msghdr *, int),					\
-	(fd, msg, flags))
-
-FDCALL(ssize_t, sendmsg, DUALCALL_SENDMSG, 				\
-	(int fd, const struct msghdr *msg, int flags),			\
-	(int, const struct msghdr *, int),				\
-	(fd, msg, flags))
-
 FDCALL(int, getsockopt, DUALCALL_GETSOCKOPT, 				\
 	(int fd, int level, int optn, void *optval, socklen_t *optlen),	\
 	(int, int, int, void *, socklen_t *),				\

Reply via email to