Source-Changes-HG archive

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

[src/trunk]: src/lib A bunch of changes which essentially make sshd work with...



details:   https://anonhg.NetBSD.org/src/rev/937cffb2a0be
branches:  trunk
changeset: 762053:937cffb2a0be
user:      pooka <pooka%NetBSD.org@localhost>
date:      Mon Feb 14 14:56:23 2011 +0000

description:
A bunch of changes which essentially make sshd work with a hijacked
rump tcp/ip stack:

* sshd likes to fork and then re-exec itself
  ==> trap execve() and augment the env with the current parameters
      essential to a rump kernel (kernel communication fd, information
      about dup2'd file descriptors)

* sshd likes to play lots of games with pipes, socketpairs and dup{,2}()
  ==> make sure we do not close essential rump client descriptors:
      dup() them to a safe place, except for F_CLOSEM where we
      simply leave them alone.  also, partially solved by the above,
      make sure the process's set of rump kernel descriptors persists
      over exec()

* sshd likes to chdir() before exec
  ==> for unix-style rump_sp(7) sockets save the full path on the
      initial exec and use it afterwards.  thread the path through
      the environment in execve()

diffstat:

 lib/librumpclient/rumpclient.c |  158 ++++++++++++++++++++++++++++++++++++++--
 lib/librumpclient/rumpclient.h |   10 ++-
 lib/librumphijack/hijack.c     |   86 +++++++++++++++++++--
 lib/librumpuser/sp_common.c    |   11 ++-
 4 files changed, 245 insertions(+), 20 deletions(-)

diffs (truncated from 464 to 300 lines):

diff -r 23a4ad52680e -r 937cffb2a0be lib/librumpclient/rumpclient.c
--- a/lib/librumpclient/rumpclient.c    Mon Feb 14 14:15:25 2011 +0000
+++ b/lib/librumpclient/rumpclient.c    Mon Feb 14 14:56:23 2011 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: rumpclient.c,v 1.27 2011/02/09 14:29:58 pooka Exp $   */
+/*      $NetBSD: rumpclient.c,v 1.28 2011/02/14 14:56:23 pooka Exp $   */
 
 /*
  * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
@@ -198,6 +198,10 @@
                                        rv = host_kevent(kq, NULL, 0,
                                            kev, __arraycount(kev), NULL);
 
+                                       if (__predict_false(rv == -1)) {
+                                               goto cleanup;
+                                       }
+
                                        /*
                                         * XXX: don't know how this can
                                         * happen (timeout cannot expire
@@ -546,15 +550,19 @@
 
 /* dup until we get a "good" fd which does not collide with stdio */
 static int
-dupgood(int myfd)
+dupgood(int myfd, int mustchange)
 {
-       int ofds[3];
+       int ofds[4];
        int i;
 
-       for (i = 0; myfd <= 2 && myfd != -1; i++) {
+       for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
                assert(i < __arraycount(ofds));
                ofds[i] = myfd;
                myfd = host_dup(myfd);
+               if (mustchange) {
+                       i--; /* prevent closing old fd */
+                       mustchange = 0;
+               }
        }
 
        for (i--; i >= 0; i--) {
@@ -611,7 +619,7 @@
        free(clispc.spc_buf);
        clispc.spc_off = 0;
 
-       s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0));
+       s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0), 0);
        if (s == -1)
                return -1;
 
@@ -666,7 +674,7 @@
        clispc.spc_reconnecting = 0;
 
        /* setup kqueue, we want all signals and the fd */
-       if ((kq = dupgood(host_kqueue())) == -1) {
+       if ((kq = dupgood(host_kqueue(), 0)) == -1) {
                error = errno;
                if (noisy)
                        fprintf(stderr, "rump_sp: cannot setup kqueue");
@@ -742,9 +750,11 @@
 #undef FINDSYM
 #undef FINDSY2
 
-       if ((p = getenv("RUMP_SERVER")) == NULL) {
-               errno = ENOENT;
-               return -1;
+       if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
+               if ((p = getenv("RUMP_SERVER")) == NULL) {
+                       errno = ENOENT;
+                       return -1;
+               }
        }
 
        if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
@@ -754,6 +764,13 @@
 
        if (doinit() == -1)
                return -1;
+
+       if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
+               sscanf(p, "%d,%d", &clispc.spc_fd, &kq);
+               unsetenv("RUMPCLIENT__EXECFD");
+               return 0;
+       }
+
        if (doconnect(true) == -1)
                return -1;
 
@@ -839,3 +856,126 @@
 
        retrytimo = timeout;
 }
+
+int
+rumpclient__closenotify(int *fdp, enum rumpclient_closevariant variant)
+{
+       int fd = *fdp;
+       int untilfd, rv;
+       int newfd;
+
+       switch (variant) {
+       case RUMPCLIENT_CLOSE_FCLOSEM:
+               untilfd = MAX(clispc.spc_fd, kq);
+               for (; fd <= untilfd; fd++) {
+                       if (fd == clispc.spc_fd || fd == kq)
+                               continue;
+                       rv = host_close(fd);
+                       if (rv == -1)
+                               return -1;
+               }
+               *fdp = fd;
+               break;
+
+       case RUMPCLIENT_CLOSE_CLOSE:
+       case RUMPCLIENT_CLOSE_DUP2:
+               if (fd == clispc.spc_fd) {
+                       struct kevent kev[2];
+
+                       newfd = dupgood(clispc.spc_fd, 1);
+                       if (newfd == -1)
+                               return -1;
+                       /*
+                        * now, we have a new socket number, so change
+                        * the file descriptor that kqueue is
+                        * monitoring.  remove old and add new.
+                        */
+                       EV_SET(&kev[0], clispc.spc_fd,
+                           EVFILT_READ, EV_DELETE, 0, 0, 0);
+                       EV_SET(&kev[1], newfd,
+                           EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
+                       if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) {
+                               int sverrno = errno;
+                               host_close(newfd);
+                               errno = sverrno;
+                               return -1;
+                       }
+                       clispc.spc_fd = newfd;
+               }
+               if (fd == kq) {
+                       newfd = dupgood(kq, 1);
+                       if (newfd == -1)
+                               return -1;
+                       kq = newfd;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * Process is about to exec.  Save info about our existing connection
+ * in the env.  rumpclient will check for this info in init().
+ * This is mostly for the benefit of rumphijack, but regular applications
+ * may use it as well.
+ */
+int
+rumpclient__exec_augmentenv(char *const oenv1[], char *const oenv2[],
+       char ***newenvp)
+{
+       char buf[4096];
+       char **newenv;
+       char *envstr, *envstr2;
+       size_t nelem1, nelem2;
+
+       snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
+           clispc.spc_fd, kq);
+       envstr = malloc(strlen(buf)+1);
+       if (envstr == NULL) {
+               return ENOMEM;
+       }
+       strcpy(envstr, buf);
+
+       /* do we have a fully parsed url we want to forward in the env? */
+       if (*parsedurl != '\0') {
+               snprintf(buf, sizeof(buf),
+                   "RUMP__PARSEDSERVER=%s", parsedurl);
+               envstr2 = malloc(strlen(buf)+1);
+               if (envstr2 == NULL) {
+                       free(envstr);
+                       return ENOMEM;
+               }
+               strcpy(envstr2, buf);
+       } else {
+               envstr2 = NULL;
+       }
+
+       nelem1 = 0;
+       if (oenv1) {
+               for (; oenv1[nelem1]; nelem1++)
+                       continue;
+       }
+       nelem2 = 0;
+       if (oenv2) {
+               for (; oenv2[nelem2]; nelem2++)
+                       continue;
+       }
+
+       newenv = malloc(sizeof(*newenv) * nelem1+nelem2+3);
+       if (newenv == NULL) {
+               free(envstr2);
+               free(envstr);
+               return ENOMEM;
+       }
+       memcpy(&newenv[0], oenv1, sizeof(*oenv1) * nelem1);
+       memcpy(&newenv[nelem1], oenv2, sizeof(*oenv2) * nelem2);
+
+       newenv[nelem1+nelem2] = envstr;
+       newenv[nelem1+nelem2+1] = envstr2;
+       newenv[nelem1+nelem2+2] = NULL;
+
+       *newenvp = newenv;
+
+       return 0;
+}
diff -r 23a4ad52680e -r 937cffb2a0be lib/librumpclient/rumpclient.h
--- a/lib/librumpclient/rumpclient.h    Mon Feb 14 14:15:25 2011 +0000
+++ b/lib/librumpclient/rumpclient.h    Mon Feb 14 14:56:23 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rumpclient.h,v 1.5 2011/02/07 14:49:32 pooka Exp $     */
+/*     $NetBSD: rumpclient.h,v 1.6 2011/02/14 14:56:23 pooka Exp $     */
 
 /*-
  * Copyright (c) 2010 Antti Kantee.  All Rights Reserved.
@@ -44,6 +44,14 @@
 #define RUMPCLIENT_RETRYCONN_DIE ((time_t)-3)
 void rumpclient_setconnretry(time_t);
 
+enum rumpclient_closevariant {
+       RUMPCLIENT_CLOSE_CLOSE,
+       RUMPCLIENT_CLOSE_DUP2,
+       RUMPCLIENT_CLOSE_FCLOSEM
+};
+int rumpclient__closenotify(int *, enum rumpclient_closevariant);
+int rumpclient__exec_augmentenv(char *const[], char *const[], char ***);
+
 __END_DECLS
 
 #endif /* _RUMP_RUMPCLIENT_H_ */
diff -r 23a4ad52680e -r 937cffb2a0be lib/librumphijack/hijack.c
--- a/lib/librumphijack/hijack.c        Mon Feb 14 14:15:25 2011 +0000
+++ b/lib/librumphijack/hijack.c        Mon Feb 14 14:56:23 2011 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: hijack.c,v 1.38 2011/02/12 10:25:46 pooka Exp $       */
+/*      $NetBSD: hijack.c,v 1.39 2011/02/14 14:56:23 pooka Exp $       */
 
 /*-
  * Copyright (c) 2011 Antti Kantee.  All Rights Reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: hijack.c,v 1.38 2011/02/12 10:25:46 pooka Exp $");
+__RCSID("$NetBSD: hijack.c,v 1.39 2011/02/14 14:56:23 pooka Exp $");
 
 #define __ssp_weak_name(fun) _hijack_ ## fun
 
@@ -140,9 +140,10 @@
 
 pid_t  (*host_fork)(void);
 int    (*host_daemon)(int, int);
+int    (*host_execve)(const char *, char *const[], char *const[]);
 
 static unsigned dup2mask;
-#define ISDUP2D(fd) (1<<(fd) & dup2mask)
+#define ISDUP2D(fd) ((fd < 32) && (1<<(fd) & dup2mask))
 
 //#define DEBUGJACK
 #ifdef DEBUGJACK
@@ -217,6 +218,7 @@
        rumpclient_dlsym = hijackdlsym;
        host_fork = dlsym(RTLD_NEXT, "fork");
        host_daemon = dlsym(RTLD_NEXT, "daemon");
+       host_execve = dlsym(RTLD_NEXT, "execve");
 
        /*
         * In theory cannot print anything during lookups because
@@ -273,6 +275,10 @@
                        rumpclient_setconnretry(timeout);
                }
        }
+
+       if (getenv_r("RUMPHIJACK__DUP2MASK", buf, sizeof(buf)) == 0) {
+               dup2mask = atoi(buf);
+       }
 }
 
 /* XXX: need runtime selection.  low for now due to FD_SETSIZE */
@@ -397,6 +403,10 @@
                op_fcntl = GETSYSCALL(rump, FCNTL);
        } else {
                op_fcntl = GETSYSCALL(host, FCNTL);
+               if (cmd == F_CLOSEM)
+                       if (rumpclient__closenotify(&fd,
+                           RUMPCLIENT_CLOSE_FCLOSEM) == -1)
+                               return -1;
        }
 



Home | Main Index | Thread Index | Old Index