Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/librumphijack A simple dup2-enforced affine transformati...



details:   https://anonhg.NetBSD.org/src/rev/0ac88833bf11
branches:  trunk
changeset: 762785:0ac88833bf11
user:      pooka <pooka%NetBSD.org@localhost>
date:      Mon Feb 28 19:57:36 2011 +0000

description:
A simple dup2-enforced affine transformation isn't enough when
dealing with dup2() from a rump kernel fd to a host kernel fd.
Consider:

s1 = socket();
s2 = socket();
dup2(s2, 0);

Instead, maintain a real mapping table (and get on my knees and
pray i don't have to touch this hair-splitting code ever again).

Apparently bourne shell scripts from a rump kernel fs work now
(sh script.sh; ./script.sh doesn't work for obvious "IT'S THE WRONG
FS NAMESPACE" reasons).  No test regressions either, so I'm a
happy camper.

diffstat:

 lib/librumphijack/hijack.c |  265 +++++++++++++++++++++++++++++++-------------
 1 files changed, 188 insertions(+), 77 deletions(-)

diffs (truncated from 453 to 300 lines):

diff -r f2486c08d203 -r 0ac88833bf11 lib/librumphijack/hijack.c
--- a/lib/librumphijack/hijack.c        Mon Feb 28 18:28:20 2011 +0000
+++ b/lib/librumphijack/hijack.c        Mon Feb 28 19:57:36 2011 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: hijack.c,v 1.70 2011/02/27 11:32:12 pooka Exp $       */
+/*      $NetBSD: hijack.c,v 1.71 2011/02/28 19:57:36 pooka Exp $       */
 
 /*-
  * Copyright (c) 2011 Antti Kantee.  All Rights Reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: hijack.c,v 1.70 2011/02/27 11:32:12 pooka Exp $");
+__RCSID("$NetBSD: hijack.c,v 1.71 2011/02/28 19:57:36 pooka Exp $");
 
 #define __ssp_weak_name(fun) _hijack_ ## fun
 
@@ -232,23 +232,89 @@
 } syscalls[DUALCALL__NUM];
 #define GETSYSCALL(which, name) syscalls[DUALCALL_##name].bs_##which
 
-pid_t  (*host_fork)(void);
-int    (*host_daemon)(int, int);
-int    (*host_execve)(const char *, char *const[], char *const[]);
-void * (*host_mmap)(void *, size_t, int, int, int, off_t);
+static pid_t   (*host_fork)(void);
+static int     (*host_daemon)(int, int);
+static int     (*host_execve)(const char *, char *const[], char *const[]);
+static void *  (*host_mmap)(void *, size_t, int, int, int, off_t);
+
+static bool    fd_isrump(int);
+static bool    path_isrump(const char *);
+
+/*
+ * Maintain a mapping table for the usual dup2 suspects.
+ */
+/* note: you cannot change this without editing the env-passing code */
+#define DUP2HIGH 2
+static uint32_t dup2vec[DUP2HIGH+1];
+#define DUP2BIT (1<<31)
+#define DUP2ALIAS (1<<30)
+#define DUP2FDMASK ((1<<30)-1)
+
+static bool
+isdup2d(int fd)
+{
+
+       return fd <= DUP2HIGH && fd >= 0 && dup2vec[fd] & DUP2BIT;
+}
+
+static int
+mapdup2(int hostfd)
+{
+
+       _DIAGASSERT(isdup2d(hostfd));
+       return dup2vec[hostfd] & DUP2FDMASK;
+}
+
+static int
+unmapdup2(int rumpfd)
+{
+       int i;
 
-/* ok, we need *two* bits per dup2'd fd to track fd+HIJACKOFF aliases */
-static uint32_t dup2mask;
-#define ISDUP2D(fd) (((fd) < 16) && (1<<(fd) & dup2mask))
-#define SETDUP2(fd) \
-    do { if ((fd) < 16) dup2mask |= (1<<(fd)); } while (/*CONSTCOND*/0)
-#define CLRDUP2(fd) \
-    do { if ((fd) < 16) dup2mask &= ~(1<<(fd)); } while (/*CONSTCOND*/0)
-#define ISDUP2ALIAS(fd) (((fd) < 16) && (1<<((fd)+16) & dup2mask))
-#define SETDUP2ALIAS(fd) \
-    do { if ((fd) < 16) dup2mask |= (1<<((fd)+16)); } while (/*CONSTCOND*/0)
-#define CLRDUP2ALIAS(fd) \
-    do { if ((fd) < 16) dup2mask &= ~(1<<((fd)+16)); } while (/*CONSTCOND*/0)
+       for (i = 0; i <= DUP2HIGH; i++) {
+               if (dup2vec[i] & DUP2BIT && (dup2vec[i] & DUP2FDMASK) == rumpfd)
+                       return i;
+       }
+       return -1;
+}
+
+static void
+setdup2(int hostfd, int rumpfd)
+{
+
+       if (hostfd > DUP2HIGH) {
+               _DIAGASSERT(0);
+               return;
+       }
+
+       dup2vec[hostfd] = DUP2BIT | DUP2ALIAS | rumpfd;
+}
+
+static void
+clrdup2(int hostfd)
+{
+
+       if (hostfd > DUP2HIGH) {
+               _DIAGASSERT(0);
+               return;
+       }
+
+       dup2vec[hostfd] = 0;
+}
+
+static bool
+killdup2alias(int rumpfd)
+{
+       int hostfd;
+
+       if ((hostfd = unmapdup2(rumpfd)) == -1)
+               return false;
+
+       if (dup2vec[hostfd] & DUP2ALIAS) {
+               dup2vec[hostfd] &= ~DUP2ALIAS;
+               return true;
+       }
+       return false;
+}
 
 //#define DEBUGJACK
 #ifdef DEBUGJACK
@@ -258,7 +324,7 @@
 {
        va_list ap;
 
-       if (ISDUP2D(STDERR_FILENO))
+       if (isdup2d(STDERR_FILENO))
                return;
 
        va_start(ap, fmt);
@@ -266,6 +332,28 @@
        va_end(ap);
 }
 
+static const char *
+whichfd(int fd)
+{
+
+       if (fd == -1)
+               return "-1";
+       else if (fd_isrump(fd))
+               return "rump";
+       else
+               return "host";
+}
+
+static const char *
+whichpath(const char *path)
+{
+
+       if (path_isrump(path))
+               return "rump";
+       else
+               return "host";
+}
+
 #else
 #define DPRINTF(x)
 #endif
@@ -275,7 +363,7 @@
 {                                                                      \
        type (*fun) proto;                                              \
                                                                        \
-       DPRINTF(("%s -> %d\n", __STRING(name), fd));                    \
+       DPRINTF(("%s -> %d (%s)\n", __STRING(name), fd, whichfd(fd)));  \
        if (fd_isrump(fd)) {                                            \
                fun = syscalls[rcname].bs_rump;                         \
                fd = fd_host2rump(fd);                                  \
@@ -291,7 +379,8 @@
 {                                                                      \
        type (*fun) proto;                                              \
                                                                        \
-       DPRINTF(("%s -> %s\n", __STRING(name), path));                  \
+       DPRINTF(("%s -> %s (%s)\n", __STRING(name), path,               \
+           whichpath(path)));                                          \
        if (path_isrump(path)) {                                        \
                fun = syscalls[rcname].bs_rump;                         \
                path = path_host2rump(path);                            \
@@ -500,9 +589,13 @@
                }
        }
 
-       if (getenv_r("RUMPHIJACK__DUP2MASK", buf, sizeof(buf)) == 0) {
-               dup2mask = strtoul(buf, NULL, 10);
-               unsetenv("RUMPHIJACK__DUP2MASK");
+       if (getenv_r("RUMPHIJACK__DUP2INFO", buf, sizeof(buf)) == 0) {
+               if (sscanf(buf, "%u,%u,%u",
+                   &dup2vec[0], &dup2vec[1], &dup2vec[2]) != 3) {
+                       warnx("invalid dup2mask: %s", buf);
+                       memset(dup2vec, 0, sizeof(dup2vec));
+               }
+               unsetenv("RUMPHIJACK__DUP2INFO");
        }
        if (getenv_r("RUMPHIJACK__PWDINRUMP", buf, sizeof(buf)) == 0) {
                pwdinrump = true;
@@ -510,35 +603,47 @@
        }
 }
 
-/* XXX: need runtime selection.  low for now due to FD_SETSIZE */
+/* Need runtime selection.  low for now due to FD_SETSIZE */
 #define HIJACK_FDOFF 128
+
 static int
 fd_rump2host(int fd)
 {
 
        if (fd == -1)
                return fd;
+       return fd + HIJACK_FDOFF;
+}
 
-       if (!ISDUP2D(fd))
-               fd += HIJACK_FDOFF;
+static int
+fd_rump2host_withdup(int fd)
+{
+       int hfd;
 
-       return fd;
+       _DIAGASSERT(fd != -1);
+       hfd = unmapdup2(fd);
+       if (hfd != -1) {
+               _DIAGASSERT(hfd <= DUP2HIGH);
+               return hfd;
+       }
+       return fd_rump2host(fd);
 }
 
 static int
 fd_host2rump(int fd)
 {
 
-       if (!ISDUP2D(fd))
-               fd -= HIJACK_FDOFF;
-       return fd;
+       if (!isdup2d(fd))
+               return fd - HIJACK_FDOFF;
+       else
+               return mapdup2(fd);
 }
 
 static bool
 fd_isrump(int fd)
 {
 
-       return ISDUP2D(fd) || fd >= HIJACK_FDOFF;
+       return isdup2d(fd) || fd >= HIJACK_FDOFF;
 }
 
 #define assertfd(_fd_) assert(ISDUP2D(_fd_) || (_fd_) >= HIJACK_FDOFF)
@@ -614,7 +719,7 @@
        int (*op_close)(int) = GETSYSCALL(host, CLOSE);
        int ofd, i;
 
-       for (i = 1; ISDUP2D(fd); i++) {
+       for (i = 1; isdup2d(fd); i++) {
                ofd = fd;
                fd = op_fcntl(ofd, F_DUPFD, i);
                op_close(ofd);
@@ -631,6 +736,8 @@
        va_list ap;
        int fd;
 
+       DPRINTF(("open -> %s (%s)\n", path, whichpath(path)));
+
        if (path_isrump(path)) {
                path = path_host2rump(path);
                op_open = GETSYSCALL(rump, OPEN);
@@ -648,6 +755,8 @@
                fd = fd_rump2host(fd);
        else
                fd = fd_dupgood(fd);
+
+       DPRINTF(("open <- %d (%s)\n", fd, whichfd(fd)));
        return fd;
 }
 
@@ -854,13 +963,12 @@
        return rv;
 }
 
-#include <syslog.h>
 int
 fcntl(int fd, int cmd, ...)
 {
        int (*op_fcntl)(int, int, ...);
        va_list ap;
-       int rv, minfd, i;
+       int rv, minfd, i, maxdup2;
 
        DPRINTF(("fcntl -> %d (cmd %d)\n", fd, cmd));
 
@@ -890,23 +998,21 @@
 
                /*
                 * Additionally, we want to do a rump closem, but only



Home | Main Index | Thread Index | Old Index