Source-Changes-HG archive

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

[src/trunk]: src/lib/librumphijack Begin work on a syscall hijacking library ...



details:   https://anonhg.NetBSD.org/src/rev/1d4e2a3c8518
branches:  trunk
changeset: 760572:1d4e2a3c8518
user:      pooka <pooka%NetBSD.org@localhost>
date:      Fri Jan 07 19:52:43 2011 +0000

description:
Begin work on a syscall hijacking library which can be LD_PRELOADed
to convince non-rumped applications to communicate with a rump
kernel instead of the host kernel.  The precision of what goes
where is not exactly surgical, but for example when wanting to
debug a web server's TCP/IP stack interaction, it might be enough.
When all you have is a hand grenade, all problems look like a ....
hmm?

There's still plenty to figure out.  For example, I'm not sure what
the user interface will be like.  Now it just attempts to hijack
network communication.  It also needs to sync with symbol renaming
in libc, and maybe autogenerate the non-schizophrenic wrappers
where the communication is heading to exactly one destination, lest
I'll be a mummmy by the time I finish writing them all.  As a fun
example of a non-non-schizophrenic one, consider poll().

Work in progress, but I managed to get two non-rumped netcats
talking to each other or fetching the index from a non-rumped
thttpd.  telnet works in one direction (i can read the data from
netcat, but anything i send back is not printed).  bozohttpd uses
dup2() which i haven't bothered to address yet, etcetc.

(not hooking this up the build for now)

diffstat:

 lib/librumphijack/Makefile      |   16 +
 lib/librumphijack/hijack.c      |  758 ++++++++++++++++++++++++++++++++++++++++
 lib/librumphijack/shlib_version |    4 +
 3 files changed, 778 insertions(+), 0 deletions(-)

diffs (truncated from 790 to 300 lines):

diff -r 3cf970e4b088 -r 1d4e2a3c8518 lib/librumphijack/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/librumphijack/Makefile        Fri Jan 07 19:52:43 2011 +0000
@@ -0,0 +1,16 @@
+#      $NetBSD: Makefile,v 1.1 2011/01/07 19:52:43 pooka Exp $
+#
+
+LIB=           rumphijack
+NOSTATICLIB=   dlfun
+NOPROFILE=     dlfun
+LIBDPLIBS+=    pthread /usr/lib
+
+SRCS=          hijack.c
+
+CPPFLAGS+=     -D_DIAGNOSTIC
+
+DBG=-g
+NOGCCERROR=1
+
+.include <bsd.lib.mk>
diff -r 3cf970e4b088 -r 1d4e2a3c8518 lib/librumphijack/hijack.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/librumphijack/hijack.c        Fri Jan 07 19:52:43 2011 +0000
@@ -0,0 +1,758 @@
+/*      $NetBSD: hijack.c,v 1.1 2011/01/07 19:52:43 pooka Exp $        */
+
+/*-
+ * Copyright (c) 2011 Antti Kantee.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: hijack.c,v 1.1 2011/01/07 19:52:43 pooka Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+
+#include <rump/rump.h>
+#include <rump/rumpclient.h>
+#include <rump/rump_syscalls.h>
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* XXX: need runtime selection.  low for now due to FD_SETSIZE */
+#define HIJACK_FDOFF 128
+
+enum { RUMPCALL_SOCKET, RUMPCALL_ACCEPT, RUMPCALL_BIND, RUMPCALL_CONNECT,
+       RUMPCALL_GETPEERNAME, RUMPCALL_GETSOCKNAME, RUMPCALL_LISTEN,
+       RUMPCALL_RECVFROM, RUMPCALL_RECVMSG,
+       RUMPCALL_SENDTO, RUMPCALL_SENDMSG,
+       RUMPCALL_GETSOCKOPT, RUMPCALL_SETSOCKOPT,
+       RUMPCALL_SHUTDOWN,
+       RUMPCALL_READ, RUMPCALL_READV,
+       RUMPCALL_WRITE, RUMPCALL_WRITEV,
+       RUMPCALL_IOCTL, RUMPCALL_FCNTL,
+       RUMPCALL_CLOSE,
+       RUMPCALL_SELECT, RUMPCALL_POLL, RUMPCALL_POLLTS,
+       RUMPCALL__NUM
+};
+
+const char *sysnames[] = {
+       "__socket30",
+       "accept",
+       "bind",
+       "connect",
+       "getpeername",
+       "getsockname",
+       "listen",
+       "recvfrom",
+       "recvmsg",
+       "sendto",
+       "sendmsg",
+       "getsockopt",
+       "setsockopt",
+       "shutdown",
+       "read",
+       "readv",
+       "write",
+       "writev",
+       "ioctl",
+       "fcntl",
+       "close",
+       "__select50",
+       "poll",
+       "__pollts50",
+};
+
+static ssize_t (*host_read)(int, void *, size_t);
+static ssize_t (*host_readv)(int, const struct iovec *, int);
+static ssize_t (*host_write)(int, const void *, size_t);
+static ssize_t (*host_writev)(int, const struct iovec *, int);
+static int     (*host_ioctl)(int, unsigned long, ...);
+static int     (*host_fcntl)(int, int, ...);
+static int     (*host_close)(int);
+static int     (*host_select)(int, fd_set *, fd_set *, fd_set *,
+                              struct timeval *);
+static int     (*host_poll)(struct pollfd *, nfds_t, int);
+#if 0
+static int     (*host_pollts)(struct pollfd *, nfds_t,
+                              const struct timespec *, const sigset_t *);
+#endif
+
+#define assertfd(_fd_) assert((_fd_) >= HIJACK_FDOFF)
+
+static void *rumpcalls[RUMPCALL__NUM];
+
+/*
+ * This is called from librumpclient in case of LD_PRELOAD.
+ * It ensures correct RTLD_NEXT.
+ */
+static void *
+hijackdlsym(void *handle, const char *symbol)
+{
+
+       return dlsym(handle, symbol);
+}
+
+static void __attribute__((constructor))
+rcinit(void)
+{
+       int (*rumpcinit)(void);
+       void **rumpcdlsym;
+       void *hand;
+       int i;
+
+       hand = dlopen("librumpclient.so", RTLD_LAZY|RTLD_GLOBAL);
+       if (!hand)
+               err(1, "cannot open librumpclient.so");
+       rumpcinit = dlsym(hand, "rumpclient_init");
+       _DIAGASSERT(rumpcinit);
+
+       rumpcdlsym = dlsym(hand, "rumpclient_dlsym");
+       *rumpcdlsym = hijackdlsym;
+
+       host_read = dlsym(RTLD_NEXT, "read");
+       host_readv = dlsym(RTLD_NEXT, "readv");
+       host_write = dlsym(RTLD_NEXT, "write");
+       host_writev = dlsym(RTLD_NEXT, "writev");
+       host_ioctl = dlsym(RTLD_NEXT, "ioctl");
+       host_fcntl = dlsym(RTLD_NEXT, "fcntl");
+       host_close = dlsym(RTLD_NEXT, "close");
+       host_select = dlsym(RTLD_NEXT, "select");
+       host_poll = dlsym(RTLD_NEXT, "poll");
+
+       for (i = 0; i < RUMPCALL__NUM; i++) {
+               char sysname[128];
+
+               snprintf(sysname, sizeof(sysname), "rump_sys_%s", sysnames[i]);
+               rumpcalls[i] = dlsym(hand, sysname);
+               if (!rumpcalls[i]) {
+                       fprintf(stderr, "%s\n", sysname);
+                       exit(1);
+               }
+       }
+
+       if (rumpcinit() == -1)
+               err(1, "rumpclient init");
+}
+
+#define ADJ(fd) (fd - HIJACK_FDOFF)
+//#define DEBUGJACK
+#ifdef DEBUGJACK
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+/*
+ * Following wrappers always call the rump kernel.
+ */
+
+int __socket30(int, int, int);
+int
+__socket30(int domain, int type, int protocol)
+{
+       int (*rc_socket)(int, int, int);
+       int fd;
+
+       DPRINTF(("socket\n"));
+       rc_socket = rumpcalls[RUMPCALL_SOCKET];
+       fd = rc_socket(domain, type, protocol);
+       if (fd != -1)
+               fd += HIJACK_FDOFF;
+       return fd;
+}
+
+int
+accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+       int (*rc_accept)(int, struct sockaddr *, socklen_t *);
+       int fd;
+
+       DPRINTF(("accept %d\n", s));
+       assertfd(s);
+       rc_accept = rumpcalls[RUMPCALL_ACCEPT];
+       fd = rc_accept(ADJ(s), addr, addrlen);
+       if (fd != -1)
+               fd += HIJACK_FDOFF;
+       return fd;
+}
+
+int
+bind(int s, const struct sockaddr *name, socklen_t namelen)
+{
+       int (*rc_bind)(int, const struct sockaddr *, socklen_t);
+
+       DPRINTF(("bind\n"));
+       assertfd(s);
+       rc_bind = rumpcalls[RUMPCALL_BIND];
+       return rc_bind(ADJ(s), name, namelen);
+}
+
+int
+connect(int s, const struct sockaddr *name, socklen_t namelen)
+{
+       int (*rc_connect)(int, const struct sockaddr *, socklen_t);
+
+       DPRINTF(("connect %d\n", s));
+       assertfd(s);
+       rc_connect = rumpcalls[RUMPCALL_CONNECT];
+       return rc_connect(ADJ(s), name, namelen);
+}
+
+int
+getpeername(int s, struct sockaddr *name, socklen_t *namelen)
+{
+       int (*rc_getpeername)(int, struct sockaddr *, socklen_t *);
+
+       DPRINTF(("getpeername\n"));
+       assertfd(s);
+       rc_getpeername = rumpcalls[RUMPCALL_GETPEERNAME];
+       return rc_getpeername(ADJ(s), name, namelen);
+}
+
+int
+getsockname(int s, struct sockaddr *name, socklen_t *namelen)
+{
+       int (*rc_getsockname)(int, struct sockaddr *, socklen_t *);
+
+       DPRINTF(("getsockname\n"));
+       assertfd(s);
+       rc_getsockname = rumpcalls[RUMPCALL_GETSOCKNAME];
+       return rc_getsockname(ADJ(s), name, namelen);
+}
+
+int
+listen(int s, int backlog)
+{
+       int (*rc_listen)(int, int);
+
+       DPRINTF(("listen\n"));
+       assertfd(s);
+       rc_listen = rumpcalls[RUMPCALL_LISTEN];
+       return rc_listen(ADJ(s), backlog);
+}
+
+ssize_t
+recv(int s, void *buf, size_t len, int flags)
+{
+
+       return recvfrom(s, buf, len, flags, NULL, NULL);
+}
+
+ssize_t
+recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
+       socklen_t *fromlen)
+{



Home | Main Index | Thread Index | Old Index