Module Name:    src
Committed By:   pooka
Date:           Thu Feb 17 12:23:58 UTC 2011

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

Log Message:
Hijack pathname-based system calls.  Now all paths starting with
/rump are hijacked to go to the rump server.  So you can e.g. start
a hijacked shell and cd to /rump:

$ cd /rump
$ pwd
/rump
$ ls -l dev/null
crwxr-xr-x  1 root  wheel  2, 2 Feb 17 12:35 dev/null
$ ls -l /dev/null
crw-rw-rw-  1 root  wheel  2, 2 Dec 22  2009 /dev/null
$ chmod 0 /dev/null
chmod: /dev/null: Operation not permitted
$ chmod 0 dev/null
$ ls -l /rump/dev/null
c---------  1 root  wheel  2, 2 Feb 17 12:35 /rump/dev/null

(of course the rump server must have vfs loaded for that to work)


To generate a diff of this commit:
cvs rdiff -u -r1.44 -r1.45 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.44 src/lib/librumphijack/hijack.c:1.45
--- src/lib/librumphijack/hijack.c:1.44	Wed Feb 16 19:26:58 2011
+++ src/lib/librumphijack/hijack.c	Thu Feb 17 12:23:58 2011
@@ -1,4 +1,4 @@
-/*      $NetBSD: hijack.c,v 1.44 2011/02/16 19:26:58 pooka Exp $	*/
+/*      $NetBSD: hijack.c,v 1.45 2011/02/17 12:23:58 pooka Exp $	*/
 
 /*-
  * Copyright (c) 2011 Antti Kantee.  All Rights Reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: hijack.c,v 1.44 2011/02/16 19:26:58 pooka Exp $");
+__RCSID("$NetBSD: hijack.c,v 1.45 2011/02/17 12:23:58 pooka Exp $");
 
 #define __ssp_weak_name(fun) _hijack_ ## fun
 
@@ -36,6 +36,7 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/poll.h>
+#include <sys/statvfs.h>
 
 #include <rump/rumpclient.h>
 #include <rump/rump_syscalls.h>
@@ -70,6 +71,20 @@
 	DUALCALL_CLOSE,
 	DUALCALL_POLLTS,
 	DUALCALL_KEVENT,
+	DUALCALL_STAT, DUALCALL_LSTAT, DUALCALL_FSTAT,
+	DUALCALL_CHMOD, DUALCALL_LCHMOD, DUALCALL_FCHMOD,
+	DUALCALL_CHOWN, DUALCALL_LCHOWN, DUALCALL_FCHOWN,
+	DUALCALL_OPEN,
+	DUALCALL_STATVFS1, DUALCALL_FSTATVFS1,
+	DUALCALL_CHDIR, DUALCALL_FCHDIR,
+	DUALCALL_LSEEK,
+	DUALCALL_GETDENTS,
+	DUALCALL_UNLINK, DUALCALL_SYMLINK, DUALCALL_READLINK,
+	DUALCALL_RENAME,
+	DUALCALL_MKDIR, DUALCALL_RMDIR,
+	DUALCALL_UTIMES, DUALCALL_LUTIMES, DUALCALL_FUTIMES,
+	DUALCALL_TRUNCATE, DUALCALL_FTRUNCATE,
+	DUALCALL_FSYNC, DUALCALL_FSYNC_RANGE,
 	DUALCALL__NUM
 };
 
@@ -84,12 +99,25 @@
 #define REALSELECT select
 #define REALPOLLTS pollts
 #define REALKEVENT kevent
+#define REALSTAT __stat30
+#define REALLSTAT __lstat30
+#define REALFSTAT __fstat30
+#define REALUTIMES utimes
+#define REALLUTIMES lutimes
+#define REALFUTIMES futimes
 #else
 #define REALSELECT _sys___select50
 #define REALPOLLTS _sys___pollts50
 #define REALKEVENT _sys___kevent50
+#define REALSTAT __stat50
+#define REALLSTAT __lstat50
+#define REALFSTAT __fstat50
+#define REALUTIMES __utimes50
+#define REALLUTIMES __lutimes50
+#define REALFUTIMES __futimes50
 #endif
 #define REALREAD _sys_read
+#define REALGETDENTS __getdents30
 
 int REALSELECT(int, fd_set *, fd_set *, fd_set *, struct timeval *);
 int REALPOLLTS(struct pollfd *, nfds_t,
@@ -97,6 +125,13 @@
 int REALKEVENT(int, const struct kevent *, size_t, struct kevent *, size_t,
 	       const struct timespec *);
 ssize_t REALREAD(int, void *, size_t);
+int REALSTAT(const char *, struct stat *);
+int REALLSTAT(const char *, struct stat *);
+int REALFSTAT(int, struct stat *);
+int REALGETDENTS(int, char *, size_t);
+int REALUTIMES(const char *, const struct timeval [2]);
+int REALLUTIMES(const char *, const struct timeval [2]);
+int REALFUTIMES(int, const struct timeval [2]);
 
 #define S(a) __STRING(a)
 struct sysnames {
@@ -128,6 +163,35 @@
 	{ DUALCALL_CLOSE,	"close",	RSYS_NAME(CLOSE)	},
 	{ DUALCALL_POLLTS,	S(REALPOLLTS),	RSYS_NAME(POLLTS)	},
 	{ DUALCALL_KEVENT,	S(REALKEVENT),	RSYS_NAME(KEVENT)	},
+	{ DUALCALL_STAT,	S(REALSTAT),	RSYS_NAME(STAT)		},
+	{ DUALCALL_LSTAT,	S(REALLSTAT),	RSYS_NAME(LSTAT)	},
+	{ DUALCALL_FSTAT,	S(REALFSTAT),	RSYS_NAME(FSTAT)	},
+	{ DUALCALL_CHOWN,	"chown",	RSYS_NAME(CHOWN)	},
+	{ DUALCALL_LCHOWN,	"lchown",	RSYS_NAME(LCHOWN)	},
+	{ DUALCALL_FCHOWN,	"fchown",	RSYS_NAME(FCHOWN)	},
+	{ DUALCALL_CHMOD,	"chmod",	RSYS_NAME(CHMOD)	},
+	{ DUALCALL_LCHMOD,	"lchmod",	RSYS_NAME(LCHMOD)	},
+	{ DUALCALL_FCHMOD,	"fchmod",	RSYS_NAME(FCHMOD)	},
+	{ DUALCALL_UTIMES,	S(REALUTIMES),	RSYS_NAME(UTIMES)	},
+	{ DUALCALL_LUTIMES,	S(REALLUTIMES),	RSYS_NAME(LUTIMES)	},
+	{ DUALCALL_FUTIMES,	S(REALFUTIMES),	RSYS_NAME(FUTIMES)	},
+	{ DUALCALL_OPEN,	"open",		RSYS_NAME(OPEN)		},
+	{ DUALCALL_STATVFS1,	"statvfs1",	RSYS_NAME(STATVFS1)	},
+	{ DUALCALL_FSTATVFS1,	"fstatvfs1",	RSYS_NAME(FSTATVFS1)	},
+	{ DUALCALL_CHDIR,	"chdir",	RSYS_NAME(CHDIR)	},
+	{ DUALCALL_FCHDIR,	"fchdir",	RSYS_NAME(FCHDIR)	},
+	{ DUALCALL_LSEEK,	"lseek",	RSYS_NAME(LSEEK)	},
+	{ DUALCALL_GETDENTS,	"__getdents30",	RSYS_NAME(GETDENTS)	},
+	{ DUALCALL_UNLINK,	"unlink",	RSYS_NAME(UNLINK)	},
+	{ DUALCALL_SYMLINK,	"symlink",	RSYS_NAME(SYMLINK)	},
+	{ DUALCALL_READLINK,	"readlink",	RSYS_NAME(READLINK)	},
+	{ DUALCALL_RENAME,	"rename",	RSYS_NAME(RENAME)	},
+	{ DUALCALL_MKDIR,	"mkdir",	RSYS_NAME(MKDIR)	},
+	{ DUALCALL_RMDIR,	"rmdir",	RSYS_NAME(RMDIR)	},
+	{ DUALCALL_TRUNCATE,	"truncate",	RSYS_NAME(TRUNCATE)	},
+	{ DUALCALL_FTRUNCATE,	"ftruncate",	RSYS_NAME(FTRUNCATE)	},
+	{ DUALCALL_FSYNC,	"fsync",	RSYS_NAME(FSYNC)	},
+	{ DUALCALL_FSYNC_RANGE,	"fsync_range",	RSYS_NAME(FSYNC_RANGE)	},
 };
 #undef S
 
@@ -184,6 +248,22 @@
 	return fun vars;						\
 }
 
+#define PATHCALL(type, name, rcname, args, proto, vars)			\
+type name args								\
+{									\
+	type (*fun) proto;						\
+									\
+	DPRINTF(("%s -> %s\n", __STRING(name), path));			\
+	if (path_isrump(path)) {					\
+		fun = syscalls[rcname].bs_rump;				\
+		path = path_host2rump(path);				\
+	} else {							\
+		fun = syscalls[rcname].bs_host;				\
+	}								\
+									\
+	return fun vars;						\
+}
+
 /*
  * This is called from librumpclient in case of LD_PRELOAD.
  * It ensures correct RTLD_NEXT.
@@ -208,6 +288,8 @@
 	return (void *)rv;
 }
 
+static int pwdinrump = 0;
+
 /* low calorie sockets? */
 static bool hostlocalsockets = true;
 
@@ -278,6 +360,11 @@
 
 	if (getenv_r("RUMPHIJACK__DUP2MASK", buf, sizeof(buf)) == 0) {
 		dup2mask = strtoul(buf, NULL, 10);
+		unsetenv("RUMPHIJACK__DUP2MASK");
+	}
+	if (getenv_r("RUMPHIJACK__PWDINRUMP", buf, sizeof(buf)) == 0) {
+		pwdinrump = strtoul(buf, NULL, 10);
+		unsetenv("RUMPHIJACK__PWDINRUMP");
 	}
 }
 
@@ -314,6 +401,37 @@
 
 #define assertfd(_fd_) assert(ISDUP2D(_fd_) || (_fd_) >= HIJACK_FDOFF)
 
+#define RUMPPREFIX "/rump"
+static int
+path_isrump(const char *path)
+{
+
+	if (*path == '/') {
+		if (strncmp(path, RUMPPREFIX, sizeof(RUMPPREFIX)-1) == 0)
+			return 1;
+		return 0;
+	} else {
+		return pwdinrump;
+	}
+}
+
+static const char *rootpath = "/";
+static const char *
+path_host2rump(const char *path)
+{
+	const char *rv;
+
+	if (*path == '/') {
+		rv = path + (sizeof(RUMPPREFIX)-1);
+		if (*rv == '\0')
+			rv = rootpath;
+	} else {
+		rv = path;
+	}
+
+	return rv;
+}
+
 static int
 dodup(int oldd, int minfd)
 {
@@ -340,6 +458,86 @@
 	return newd;
 }
 
+int
+open(const char *path, int flags, ...)
+{
+	int (*op_open)(const char *, int, ...);
+	bool isrump;
+	va_list ap;
+	int fd;
+
+	if (path_isrump(path)) {
+		path = path_host2rump(path);
+		op_open = GETSYSCALL(rump, OPEN);
+		isrump = true;
+	} else {
+		op_open = GETSYSCALL(host, OPEN);
+		isrump = false;
+	}
+
+	va_start(ap, flags);
+	fd = op_open(path, flags, va_arg(ap, mode_t));
+	va_end(ap);
+
+	if (isrump)
+		fd = fd_rump2host(fd);
+	return fd;
+}
+
+int
+chdir(const char *path)
+{
+	int (*op_chdir)(const char *);
+	bool isrump;
+	int rv;
+
+	if (path_isrump(path)) {
+		op_chdir = GETSYSCALL(rump, CHDIR);
+		isrump = true;
+		path = path_host2rump(path);
+	} else {
+		op_chdir = GETSYSCALL(host, CHDIR);
+		isrump = false;
+	}
+
+	rv = op_chdir(path);
+	if (rv == 0) {
+		if (isrump)
+			pwdinrump = true;
+		else
+			pwdinrump = false;
+	}
+
+	return rv;
+}
+
+int
+fchdir(int fd)
+{
+	int (*op_fchdir)(int);
+	bool isrump;
+	int rv;
+
+	if (fd_isrump(fd)) {
+		op_fchdir = GETSYSCALL(rump, FCHDIR);
+		isrump = true;
+		fd = fd_host2rump(fd);
+	} else {
+		op_fchdir = GETSYSCALL(host, FCHDIR);
+		isrump = false;
+	}
+
+	rv = op_fchdir(fd);
+	if (rv == 0) {
+		if (isrump)
+			pwdinrump = true;
+		else
+			pwdinrump = false;
+	}
+
+	return rv;
+}
+
 int __socket30(int, int, int);
 int
 __socket30(int domain, int type, int protocol)
@@ -628,26 +826,56 @@
 {
 	char buf[128];
 	char *dup2str;
+	char *pwdinrumpstr;
 	char **newenv;
 	size_t nelem;
 	int rv, sverrno;
+	int bonus = 1, i = 0;
 
-	snprintf(buf, sizeof(buf), "RUMPHIJACK__DUP2MASK=%u", dup2mask);
-	dup2str = malloc(strlen(buf)+1);
-	if (dup2str == NULL)
-		return ENOMEM;
-	strcpy(dup2str, buf);
+	if (dup2mask) {
+		snprintf(buf, sizeof(buf), "RUMPHIJACK__DUP2MASK=%u", dup2mask);
+		dup2str = malloc(strlen(buf)+1);
+		if (dup2str == NULL)
+			return ENOMEM;
+		strcpy(dup2str, buf);
+		bonus++;
+	} else {
+		dup2str = NULL;
+	}
+
+	if (pwdinrump) {
+		snprintf(buf, sizeof(buf), "RUMPHIJACK__PWDINRUMP=%u",
+		    pwdinrump);
+		pwdinrumpstr = malloc(strlen(buf)+1);
+		if (pwdinrumpstr == NULL) {
+			free(dup2str);
+			return ENOMEM;
+		}
+		strcpy(pwdinrumpstr, buf);
+		bonus++;
+	} else {
+		pwdinrumpstr = NULL;
+	}
 
 	for (nelem = 0; envp && envp[nelem]; nelem++)
 		continue;
-	newenv = malloc(sizeof(*newenv) * nelem+2);
+	newenv = malloc(sizeof(*newenv) * nelem+bonus);
 	if (newenv == NULL) {
 		free(dup2str);
+		free(pwdinrumpstr);
 		return ENOMEM;
 	}
 	memcpy(newenv, envp, nelem*sizeof(*newenv));
-	newenv[nelem] = dup2str;
-	newenv[nelem+1] = NULL;
+	if (dup2str) {
+		newenv[nelem+i] = dup2str;
+		i++;
+	}
+	if (pwdinrumpstr) {
+		newenv[nelem+i] = pwdinrumpstr;
+		i++;
+	}
+	newenv[nelem+i] = NULL;
+	_DIAGASSERT(i < bonus);
 
 	rv = rumpclient_exec(path, argv, newenv);
 
@@ -1127,3 +1355,138 @@
 	(int fd, const struct iovec *iov, int iovcnt),			\
 	(int, const struct iovec *, int),				\
 	(fd, iov, iovcnt))
+
+FDCALL(int, REALFSTAT, DUALCALL_FSTAT,					\
+	(int fd, struct stat *sb),					\
+	(int, struct stat *),						\
+	(fd, sb))
+
+FDCALL(int, fstatvfs1, DUALCALL_FSTATVFS1,				\
+	(int fd, struct statvfs *buf, int flags),			\
+	(int, struct statvfs *, int),					\
+	(fd, buf, flags))
+
+FDCALL(off_t, lseek, DUALCALL_LSEEK,					\
+	(int fd, off_t offset, int whence),				\
+	(int, off_t, int),						\
+	(fd, offset, whence))
+
+FDCALL(int, REALGETDENTS, DUALCALL_GETDENTS,				\
+	(int fd, char *buf, size_t nbytes),				\
+	(int, char *, size_t),						\
+	(fd, buf, nbytes))
+
+FDCALL(int, fchown, DUALCALL_FCHOWN,					\
+	(int fd, uid_t owner, gid_t group),				\
+	(int, uid_t, gid_t),						\
+	(fd, owner, group))
+
+FDCALL(int, fchmod, DUALCALL_FCHMOD,					\
+	(int fd, mode_t mode),						\
+	(int, mode_t),							\
+	(fd, mode))
+
+FDCALL(int, ftruncate, DUALCALL_FTRUNCATE,				\
+	(int fd, off_t length),						\
+	(int, off_t),							\
+	(fd, length))
+
+FDCALL(int, fsync, DUALCALL_FSYNC,					\
+	(int fd),							\
+	(int),								\
+	(fd))
+
+FDCALL(int, fsync_range, DUALCALL_FSYNC_RANGE,				\
+	(int fd, int how, off_t start, off_t length),			\
+	(int, int, off_t, off_t),					\
+	(fd, how, start, length))
+
+FDCALL(int, futimes, DUALCALL_FUTIMES,					\
+	(int fd, const struct timeval *tv),				\
+	(int, const struct timeval *),					\
+	(fd, tv))
+
+/*
+ * path-based selectors
+ */
+
+PATHCALL(int, REALSTAT, DUALCALL_STAT,					\
+	(const char *path, struct stat *sb),				\
+	(const char *, struct stat *),					\
+	(path, sb))
+
+PATHCALL(int, REALLSTAT, DUALCALL_LSTAT,				\
+	(const char *path, struct stat *sb),				\
+	(const char *, struct stat *),					\
+	(path, sb))
+
+PATHCALL(int, chown, DUALCALL_CHOWN,					\
+	(const char *path, uid_t owner, gid_t group),			\
+	(const char *, uid_t, gid_t),					\
+	(path, owner, group))
+
+PATHCALL(int, lchown, DUALCALL_LCHOWN,					\
+	(const char *path, uid_t owner, gid_t group),			\
+	(const char *, uid_t, gid_t),					\
+	(path, owner, group))
+
+PATHCALL(int, chmod, DUALCALL_CHMOD,					\
+	(const char *path, mode_t mode),				\
+	(const char *, mode_t),						\
+	(path, mode))
+
+PATHCALL(int, lchmod, DUALCALL_LCHMOD,					\
+	(const char *path, mode_t mode),				\
+	(const char *, mode_t),						\
+	(path, mode))
+
+PATHCALL(int, statvfs1, DUALCALL_STATVFS1,				\
+	(const char *path, struct statvfs *buf, int flags),		\
+	(const char *, struct statvfs *, int),				\
+	(path, buf, flags))
+
+PATHCALL(int, unlink, DUALCALL_UNLINK,					\
+	(const char *path),						\
+	(const char *),							\
+	(path))
+
+PATHCALL(int, symlink, DUALCALL_SYMLINK,				\
+	(const char *path, const char *target),				\
+	(const char *, const char *),					\
+	(path, target))
+
+PATHCALL(int, readlink, DUALCALL_READLINK,				\
+	(const char *path, char *buf, size_t bufsiz),			\
+	(const char *, char *, size_t),					\
+	(path, buf, bufsiz))
+
+/* XXX: cross-kernel renames need to be blocked */
+PATHCALL(int, rename, DUALCALL_RENAME,					\
+	(const char *path, const char *to),				\
+	(const char *, const char *),					\
+	(path, to))
+
+PATHCALL(int, mkdir, DUALCALL_MKDIR,					\
+	(const char *path, mode_t mode),				\
+	(const char *, mode_t),						\
+	(path, mode))
+
+PATHCALL(int, rmdir, DUALCALL_RMDIR,					\
+	(const char *path),						\
+	(const char *),							\
+	(path))
+
+PATHCALL(int, utimes, DUALCALL_UTIMES,					\
+	(const char *path, const struct timeval *tv),			\
+	(const char *, const struct timeval *),				\
+	(path, tv))
+
+PATHCALL(int, lutimes, DUALCALL_LUTIMES,				\
+	(const char *path, const struct timeval *tv),			\
+	(const char *, const struct timeval *),				\
+	(path, tv))
+
+PATHCALL(int, truncate, DUALCALL_TRUNCATE,				\
+	(const char *path, off_t length),				\
+	(const char *, off_t),						\
+	(path, length))

Reply via email to