aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Seebach <peter.seebach@windriver.com>2010-12-02 14:29:36 -0600
committerPeter Seebach <peter.seebach@windriver.com>2010-12-02 14:48:59 -0600
commit9b582a4396c256abce2f31319bdf01ef30293320 (patch)
tree8416c1a34ec4a7757883d83689ff803968ecb1cb
parent5a5619f8dc1eedb6ce9f49c81fd1e39eca15fc1f (diff)
downloadpseudo-SEEBS_FORK_HACK.tar.gz
pseudo-SEEBS_FORK_HACK.tar.bz2
pseudo-SEEBS_FORK_HACK.zip
Major shift: Fix execl*(), allow enabling/disabling pseudo withSEEBS_FORK_HACK
an environment variable across fork(). This does a couple of things. One is, move the fork/vfork and execl* functions out of the standard wrapper environment. Having done that, the execl*() wrappers are rewritten so they can use real_execv*() when running in antimagic mode. This allows us to run pseudo entirely in antimagic mode. Which is handy, because we also add support for enabling/disabling antimagic mode in the child process on a fork, using an additional hook for this in the pseudo_client_init() routine. The redone fork() wrapper now calls pseudo_client_init() in the child process after a successful fork even if it's in antimagic mode already. This is not yet well-tested.
-rw-r--r--guts/README16
-rw-r--r--guts/execl.c42
-rw-r--r--guts/execle.c44
-rw-r--r--guts/execlp.c42
-rw-r--r--guts/vfork.c17
-rwxr-xr-xmakewrappers10
-rw-r--r--pseudo.19
-rw-r--r--pseudo.h1
-rw-r--r--pseudo_client.c20
-rw-r--r--pseudo_wrappers.c283
-rw-r--r--templates/wrapfuncs.c2
-rw-r--r--templates/wrapfuncs.h6
-rw-r--r--templates/wrapper_table6
-rw-r--r--wrapfuncs.in5
14 files changed, 343 insertions, 160 deletions
diff --git a/guts/README b/guts/README
index 8bfbfe6..0a1fe5f 100644
--- a/guts/README
+++ b/guts/README
@@ -83,7 +83,7 @@ wrappers:
close
dup
dup2
- excl* (all redirect through execve)
+ execl* (no guts implementations; see pseudo_wrappers.c)
execv
execve
execvp
@@ -97,7 +97,6 @@ wrappers:
fcntl
fork
link
- vfork
The following functions don't have any direct database interactions,
but are used to simulate the permissions system:
@@ -206,3 +205,16 @@ needed because we don't actually track or manage extended attributes, but
a few programs attempt to use *setxattr() to set regular permissions,
and only use a regular chmod if the *setxattr() call returns -1 and
sets errno to ENOTSUP.
+
+ fgetxattr
+ flistxattr
+ fremovexattr
+ fsetxattr
+ getxattr
+ lgetxattr
+ listxattr
+ llistxattr
+ lremovexattr
+ lsetxattr
+ removexattr
+ setxattr
diff --git a/guts/execl.c b/guts/execl.c
deleted file mode 100644
index ca2df70..0000000
--- a/guts/execl.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2010 Wind River Systems; see
- * guts/COPYRIGHT for information.
- *
- * static int
- * wrap_execl(const char *file, const char *arg, va_list ap) {
- * int rc = -1;
- */
-
- size_t i = 0;
- size_t alloc_size = 256;
- const char **argv = malloc(sizeof (const char *) * alloc_size);
- if (!argv) {
- pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n",
- (unsigned long) alloc_size);
- errno = ENOMEM;
- return -1;
- }
-
- argv[i++] = arg;
-
- while (argv[i-1]) {
- argv[i++] = va_arg (ap, const char *);
- if ( i > alloc_size - 1 ) {
- alloc_size = alloc_size + 256;
- argv = realloc(argv, sizeof (const char *) * alloc_size);
- if (!argv) {
- pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n",
- (unsigned long) alloc_size);
- errno = ENOMEM;
- return -1;
- }
- }
- }
-
- rc = wrap_execv (file, (char *const *) argv);
-
- free (argv);
-
-/* return rc;
- * }
- */
diff --git a/guts/execle.c b/guts/execle.c
deleted file mode 100644
index 5b44d78..0000000
--- a/guts/execle.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010 Wind River Systems; see
- * guts/COPYRIGHT for information.
- *
- * static int
- * wrap_execle(const char *file, const char *arg, va_list ap) {
- * int rc = -1;
- */
-
- size_t i = 0;
- size_t alloc_size = 256;
- const char **argv = malloc(sizeof (const char *) * alloc_size);
- char *const *envp;
- if (!argv) {
- pseudo_debug(1, "execle failed: couldn't allocate memory for %lu arguments\n",
- (unsigned long) alloc_size);
- errno = ENOMEM;
- return -1;
- }
-
- argv[i++] = arg;
-
- while (argv[i-1]) {
- argv[i++] = va_arg (ap, const char *);
- if ( i > alloc_size - 1 ) {
- alloc_size = alloc_size + 256;
- argv = realloc(argv, sizeof (const char *) * alloc_size);
- if (!argv) {
- pseudo_debug(1, "execle failed: couldn't allocate memory for %lu arguments\n",
- (unsigned long) alloc_size);
- errno = ENOMEM;
- return -1;
- }
- }
- }
- envp = va_arg (ap, char *const *);
-
- rc = wrap_execve (file, (char *const *) argv, envp);
-
- free (argv);
-
-/* return rc;
- * }
- */
diff --git a/guts/execlp.c b/guts/execlp.c
deleted file mode 100644
index d09a64d..0000000
--- a/guts/execlp.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2010 Wind River Systems; see
- * guts/COPYRIGHT for information.
- *
- * static int
- * wrap_execlp(const char *file, const char *arg, va_list ap) {
- * int rc = -1;
- */
-
- size_t i = 0;
- size_t alloc_size = 256;
- const char **argv = malloc(sizeof (const char *) * alloc_size);
- if (!argv) {
- pseudo_debug(1, "execlp failed: couldn't allocate memory for %lu arguments\n",
- (unsigned long) alloc_size);
- errno = ENOMEM;
- return -1;
- }
-
- argv[i++] = arg;
-
- while (argv[i-1]) {
- argv[i++] = va_arg (ap, const char *);
- if ( i > alloc_size - 1 ) {
- alloc_size = alloc_size + 256;
- argv = realloc(argv, sizeof (const char *) * alloc_size);
- if (!argv) {
- pseudo_debug(1, "execlp failed: couldn't allocate memory for %lu arguments\n",
- (unsigned long) alloc_size);
- errno = ENOMEM;
- return -1;
- }
- }
- }
-
- rc = wrap_execvp (file, (char *const *) argv);
-
- free (argv);
-
-/* return rc;
- * }
- */
diff --git a/guts/vfork.c b/guts/vfork.c
deleted file mode 100644
index 4e0f767..0000000
--- a/guts/vfork.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2008-2010 Wind River Systems; see
- * guts/COPYRIGHT for information.
- *
- * static int
- * wrap_vfork(void) {
- * int rc = -1;
- */
-
- /* like fakeroot, we really can't handle vfork's implications */
- rc = real_fork();
- if (rc == 0)
- pseudo_client_reset();
-
-/* return rc;
- * }
- */
diff --git a/makewrappers b/makewrappers
index 5ec58f8..2a17dbd 100755
--- a/makewrappers
+++ b/makewrappers
@@ -33,8 +33,6 @@ class ArgumentList:
self.variadic_decl = ""
self.variadic_start = ""
self.variadic_end = ""
- self.prologue_call_real = \
- "/* pass the call on to the underlying syscall */"
# (void) is an empty list, not a list of a single argument which is void
if text == "void":
return
@@ -68,11 +66,8 @@ class ArgumentList:
(self.variadic_arg.name,
self.variadic_arg.type)
else:
- self.variadic_end = "va_end(ap);\n"
- self.prologue_call_real = ('/* no way to pass a ... */'
- '\n\t\t\t\tassert(!"cannot chain '
- 'to real versions of variadic'
- 'functions");')
+ # lie blatantly; we don't handle this case
+ self.variadic = False
# for a wrap function, the outer foo() wrapper will convert to a va_list,
# but the inner wrap_foo() just passes the va_list through.
@@ -212,6 +207,7 @@ class Function:
self.dirfd = 'AT_FDCWD'
self.flags = '0'
self.paths_to_munge = []
+ self.nowrappers = None
# used for the copyright date when creating stub functions
self.date = datetime.date.today().year
diff --git a/pseudo.1 b/pseudo.1
index 7002023..2f85d7c 100644
--- a/pseudo.1
+++ b/pseudo.1
@@ -400,6 +400,15 @@ in the
.I var/pseudo
directory, while clients log to standard error.
.TP 8
+.B PSEUDO_DISABLE
+If this variable is set, the
+.I pseudo
+client library does not modify the behavior of called functions, though it
+continues to intercept them and block signals while processing them. This
+variable is reevaluated on every call to
+.I fork()
+or related functions.
+.TP 8
.B PSEUDO_ENOSYS_ABORT
If this variable is set, the
.I pseudo
diff --git a/pseudo.h b/pseudo.h
index 9b06651..897ad24 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -31,6 +31,7 @@ char * pseudo_get_value(const char * key);
extern void pseudo_debug_verbose(void);
extern void pseudo_debug_terse(void);
extern int pseudo_util_debug_fd;
+extern int pseudo_disabled;
#ifndef NDEBUG
extern int pseudo_debug_real(int, char *, ...) __attribute__ ((format (printf, 2, 3)));
#define pseudo_debug pseudo_debug_real
diff --git a/pseudo_client.c b/pseudo_client.c
index b169259..5b222e9 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -58,6 +58,8 @@ char *pseudo_chroot = NULL;
char *pseudo_passwd = NULL;
size_t pseudo_chroot_len = 0;
char *pseudo_cwd_rel = NULL;
+/* used for PSEUDO_DISABLE */
+int pseudo_disabled = 0;
static char **fd_paths = NULL;
static int nfds = 0;
@@ -317,6 +319,24 @@ pseudo_client_reset() {
close(connect_fd);
connect_fd = -1;
}
+
+ /* in child processes, PSEUDO_DISABLED may have come
+ * into existence, in which case we'd disable pseudo,
+ * or it may have gone away, in which case we'd enable
+ * pseudo.
+ */
+ if (getenv("PSEUDO_DISABLED")) {
+ if (!pseudo_disabled) {
+ pseudo_antimagic();
+ pseudo_disabled = 1;
+ }
+ } else {
+ if (pseudo_disabled) {
+ pseudo_magic();
+ pseudo_disabled = 0;
+ }
+ }
+
if (!pseudo_inited) {
char *env;
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index dbcfac8..f5f7aef 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -246,3 +246,286 @@ pseudo_populate_wrappers(void) {
return done;
}
+static char **
+execl_to_v(va_list ap, const char *argv0, char *const **envp) {
+ size_t i = 0;
+ size_t alloc_size = 256;
+
+ char **argv = malloc((sizeof *argv) * alloc_size);
+
+ if (!argv) {
+ pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n",
+ (unsigned long) alloc_size);
+ return NULL;
+ }
+ argv[i++] = (char *) argv0;
+
+ while (argv[i-1]) {
+ argv[i++] = va_arg(ap, char *const);
+ if (i > alloc_size - 1) {
+ alloc_size = alloc_size + 256;
+ argv = realloc(argv, (sizeof *argv) * alloc_size);
+ if (!argv) {
+ pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n",
+ (unsigned long) alloc_size);
+ return NULL;
+ }
+ }
+ }
+ if (envp) {
+ *envp = va_arg(ap, char **);
+ }
+ return argv;
+}
+
+/* The following wrappers require Special Handling */
+
+int
+execl(const char *file, const char *arg, ...) {
+ sigset_t saved;
+ va_list ap;
+ char **argv;
+
+ int rc = -1;
+
+ va_start(ap, arg);
+ argv = execl_to_v(ap, arg, 0);
+ va_end(ap);
+ if (!argv) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ pseudo_debug(4, "called: execl\n");
+ pseudo_sigblock(&saved);
+ if (pseudo_getlock()) {
+ errno = EBUSY;
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ return -1;
+ }
+ if (pseudo_populate_wrappers()) {
+ int save_errno;
+ if (antimagic > 0) {
+ if (real_execv) {
+ /* use execv to emulate */
+ rc = (*real_execv)(file, argv);
+ } else {
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execl");
+ }
+ } else {
+
+ /* exec*() use this to restore the sig mask */
+ pseudo_saved_sigmask = saved;
+ rc = wrap_execv(file, argv);
+ }
+
+ save_errno = errno;
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execl\n");
+ errno = save_errno;
+ free(argv);
+ return rc;
+ } else {
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execl\n");
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execl");
+ free(argv);
+ return rc;
+ }
+}
+
+int
+execlp(const char *file, const char *arg, ...) {
+ sigset_t saved;
+ va_list ap;
+ char **argv;
+
+ int rc = -1;
+
+ va_start(ap, arg);
+ argv = execl_to_v(ap, arg, 0);
+ va_end(ap);
+ if (!argv) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ pseudo_debug(4, "called: execlp\n");
+ pseudo_sigblock(&saved);
+ if (pseudo_getlock()) {
+ errno = EBUSY;
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ return -1;
+ }
+ if (pseudo_populate_wrappers()) {
+ int save_errno;
+ if (antimagic > 0) {
+ if (real_execvp) {
+ /* use execv to emulate */
+ rc = (*real_execvp)(file, argv);
+ } else {
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execlp");
+ }
+ } else {
+
+ /* exec*() use this to restore the sig mask */
+ pseudo_saved_sigmask = saved;
+ rc = wrap_execvp(file, argv);
+ }
+
+ save_errno = errno;
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execlp\n");
+ errno = save_errno;
+ free(argv);
+ return rc;
+ } else {
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execlp\n");
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execlp");
+ free(argv);
+ return rc;
+ }
+}
+
+int
+execle(const char *file, const char *arg, ...) {
+ sigset_t saved;
+ va_list ap;
+ char **argv;
+ char **envp;
+
+ int rc = -1;
+
+ va_start(ap, arg);
+ argv = execl_to_v(ap, arg, &envp);
+ va_end(ap);
+ if (!argv) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ pseudo_debug(4, "called: execle\n");
+ pseudo_sigblock(&saved);
+ if (pseudo_getlock()) {
+ errno = EBUSY;
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ return -1;
+ }
+ if (pseudo_populate_wrappers()) {
+ int save_errno;
+ if (antimagic > 0) {
+ if (real_execve) {
+ /* use execve to emulate */
+ rc = (*real_execve)(file, argv, envp);
+ } else {
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execl");
+ }
+ } else {
+
+ /* exec*() use this to restore the sig mask */
+ pseudo_saved_sigmask = saved;
+ rc = wrap_execve(file, argv, envp);
+ }
+
+ save_errno = errno;
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execle\n");
+ errno = save_errno;
+ free(argv);
+ return rc;
+ } else {
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execle\n");
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execle");
+ free(argv);
+ return rc;
+ }
+}
+
+int
+fork(void) {
+ sigset_t saved;
+
+ int rc = -1;
+
+ pseudo_debug(4, "called: fork\n");
+ pseudo_sigblock(&saved);
+ if (pseudo_getlock()) {
+ errno = EBUSY;
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ return -1;
+ }
+ if (pseudo_populate_wrappers()) {
+ int save_errno;
+ if (antimagic > 0) {
+ if (real_fork) {
+ /* pass the call on to the underlying syscall */
+ rc = (*real_fork)();
+ /* special case: we may want to enable or disable
+ * pseudo in the child process
+ */
+ if (rc == 0)
+ pseudo_client_reset();
+ } else {
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("fork");
+ }
+ } else {
+
+ /* exec*() use this to restore the sig mask */
+ pseudo_saved_sigmask = saved;
+ rc = wrap_fork();
+
+ }
+ save_errno = errno;
+
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: fork\n");
+ errno = save_errno;
+ return rc;
+ } else {
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: fork\n");
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("fork");
+
+ return rc;
+ }
+}
+
+int
+vfork(void) {
+ /* we don't provide support for the distinct semantics
+ * of vfork()
+ */
+ return fork();
+}
+
+static int (*real_fork)(void) = NULL;
+static int (*real_execlp)(const char *file, const char *arg, ...) = NULL;
+static int (*real_execl)(const char *file, const char *arg, ...) = NULL;
+static int (*real_execle)(const char *file, const char *arg, ...) = NULL;
+
+static int
+wrap_fork(void) {
+ int rc = -1;
+
+#include "guts/fork.c"
+
+ return rc;
+}
diff --git a/templates/wrapfuncs.c b/templates/wrapfuncs.c
index 935561b..c0170d9 100644
--- a/templates/wrapfuncs.c
+++ b/templates/wrapfuncs.c
@@ -34,7 +34,7 @@ ${name}(${decl_args}) {
int save_errno;
if (antimagic > 0) {
if (real_$name) {
- ${prologue_call_real}
+ /* call the real syscall */
${rc_assign} (*real_${name})(${call_args});
} else {
/* rc was initialized to the "failure" value */
diff --git a/templates/wrapfuncs.h b/templates/wrapfuncs.h
index 63ba903..665da14 100644
--- a/templates/wrapfuncs.h
+++ b/templates/wrapfuncs.h
@@ -8,3 +8,9 @@
/* ${comment} */
static ${type} wrap_${name}(${wrap_args});
static ${type} (*real_${name})(${decl_args});
+@footer
+/* special cases: functions with manually-written wrappers */
+
+/* int fork(void) */
+static int wrap_fork(void);
+static int (*real_fork)(void);
diff --git a/templates/wrapper_table b/templates/wrapper_table
index a16dca9..2419c7d 100644
--- a/templates/wrapper_table
+++ b/templates/wrapper_table
@@ -16,5 +16,11 @@ static struct {
(int (*)(void)) wrap_${name}
},
@footer
+ /* special cases: Functions which need manually-coded wrappers */
+ { /* int fork(void); */
+ "fork",
+ (int (**)(void)) &real_fork,
+ (int (*)(void)) wrap_fork
+ },
{ NULL, NULL, NULL },
};
diff --git a/wrapfuncs.in b/wrapfuncs.in
index 17742ac..eb9280e 100644
--- a/wrapfuncs.in
+++ b/wrapfuncs.in
@@ -32,8 +32,6 @@ int rmdir(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */
int chdir(const char *path);
int fchdir(int dirfd);
int fcntl(int fd, int cmd, ...{struct flock *lock});
-int fork(void);
-int vfork(void);
# just so we know the inums of symlinks
int symlink(const char *oldname, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */
int symlinkat(const char *oldname, int dirfd, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */
@@ -88,9 +86,6 @@ char *tmpnam(char *s);
int truncate(const char *path, off_t length);
int utime(const char *path, const struct utimbuf *buf);
int utimes(const char *path, const struct timeval *times);
-int execl(const char *file, const char *arg, ...);
-int execlp(const char *file, const char *arg, ...);
-int execle(const char *file, const char *arg, ...);
int execv(const char *file, char *const *argv);
int execve(const char *file, char *const *argv, char *const *envp);
int execvp(const char *file, char *const *argv);