aboutsummaryrefslogtreecommitdiffstats
path: root/pseudo_wrappers.c
diff options
context:
space:
mode:
Diffstat (limited to 'pseudo_wrappers.c')
-rw-r--r--pseudo_wrappers.c361
1 files changed, 234 insertions, 127 deletions
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index ee1d3ea..414cc05 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -32,7 +32,7 @@
#include "pseudo_client.h"
static void pseudo_enosys(const char *);
-static int pseudo_populate_wrappers(void);
+static int pseudo_check_wrappers(void);
static volatile int antimagic = 0;
static pthread_mutex_t pseudo_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t pseudo_mutex_holder;
@@ -49,6 +49,69 @@ static sigset_t pseudo_saved_sigmask;
#include "pseudo_wrapper_table.c"
#include "pseudo_wrapfuncs.c"
+/* Constructor only exists in libpseudo */
+static void _libpseudo_init(void) __attribute__ ((constructor));
+
+static int _libpseudo_initted = 0;
+
+static void
+_libpseudo_init(void) {
+ pseudo_getlock();
+ pseudo_antimagic();
+ _libpseudo_initted = 1;
+
+ pseudo_init_util();
+ pseudo_init_wrappers();
+ pseudo_init_client();
+
+ pseudo_magic();
+ pseudo_droplock();
+}
+
+void
+pseudo_reinit_libpseudo(void) {
+ _libpseudo_init();
+}
+
+void
+pseudo_init_wrappers(void) {
+ int i;
+ static int done = 0;
+
+ pseudo_getlock();
+ pseudo_antimagic();
+
+ /* We only ever want to run this once, even though we might want to
+ * "re-init" at specific times...
+ */
+ if (!done) {
+ for (i = 0; pseudo_functions[i].name; ++i) {
+ if (*pseudo_functions[i].real == NULL) {
+ int (*f)(void);
+ char *e;
+ dlerror();
+ f = dlsym(RTLD_NEXT, pseudo_functions[i].name);
+ if ((e = dlerror()) != NULL) {
+ /* leave it NULL, which our implementation checks for */
+ pseudo_diag("No wrapper for %s: %s\n", pseudo_functions[i].name, e);
+ } else {
+ if (f)
+ *pseudo_functions[i].real = f;
+ }
+ }
+ }
+ done = 1;
+ }
+
+ /* Once the wrappers are setup, we can now use open... so
+ * setup the logfile, if necessary...
+ */
+ pseudo_logfile(NULL);
+
+ pseudo_magic();
+ pseudo_droplock();
+}
+
static void
pseudo_sigblock(sigset_t *saved) {
sigset_t blocked;
@@ -140,76 +203,12 @@ pseudo_dechroot(char *s, size_t len) {
}
static int
-pseudo_populate_wrappers(void) {
- int i;
- char *debug;
- static int done = 0;
- char *no_symlink_exp;
+pseudo_check_wrappers(void) {
+ if (!_libpseudo_initted)
+ pseudo_reinit_libpseudo();
- if (done)
- return done;
- pseudo_getlock();
- pseudo_antimagic();
- for (i = 0; pseudo_functions[i].name; ++i) {
- if (*pseudo_functions[i].real == NULL) {
- int (*f)(void);
- char *e;
- dlerror();
- f = dlsym(RTLD_NEXT, pseudo_functions[i].name);
- if ((e = dlerror()) != NULL) {
- /* leave it NULL, which our implementation checks for */
- pseudo_diag("No wrapper for %s: %s\n", pseudo_functions[i].name, e);
- } else {
- if (f)
- *pseudo_functions[i].real = f;
- }
- }
- }
- done = 1;
- debug = pseudo_get_value("PSEUDO_DEBUG");
- if (debug) {
- int level = atoi(debug);
- for (i = 0; i < level; ++i) {
- pseudo_debug_verbose();
- }
- }
- free(debug);
- no_symlink_exp = pseudo_get_value("PSEUDO_NOSYMLINKEXP");
- if (no_symlink_exp) {
- char *endptr;
- /* if the environment variable is not an empty string,
- * parse it; "0" means turn NOSYMLINKEXP off, "1" means
- * turn it on (disabling the feature). An empty string
- * or something we can't parse means to set the flag; this
- * is a safe default because if you didn't want the flag
- * set, you normally wouldn't set the environment variable
- * at all.
- */
- if (*no_symlink_exp) {
- pseudo_nosymlinkexp = strtol(no_symlink_exp, &endptr, 10);
- if (*endptr)
- pseudo_nosymlinkexp = 1;
- } else {
- pseudo_nosymlinkexp = 1;
- }
- } else {
- pseudo_nosymlinkexp = 0;
- }
- free(no_symlink_exp);
- /* if PSEUDO_DEBUG_FILE is set up, redirect logging there.
- */
- pseudo_logfile(NULL);
- /* must happen after wrappers are set up, because it can call
- * getcwd(), which needs wrappers, but must happen here so that
- * any attempt to use a path in a wrapper function will have a
- * value for cwd.
- */
- pseudo_client_reset();
- pseudo_debug(2, "(%s) set up wrappers\n", program_invocation_short_name);
- pseudo_magic();
- pseudo_droplock();
- return done;
-}
+ return _libpseudo_initted;
+}
static char **
execl_to_v(va_list ap, const char *argv0, char *const **envp) {
@@ -268,22 +267,12 @@ execl(const char *file, const char *arg, ...) {
sigprocmask(SIG_SETMASK, &saved, NULL);
return -1;
}
- if (pseudo_populate_wrappers()) {
+ if (pseudo_check_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);
- }
+
+ /* exec*() use this to restore the sig mask */
+ pseudo_saved_sigmask = saved;
+ rc = wrap_execv(file, argv);
save_errno = errno;
pseudo_droplock();
@@ -326,22 +315,12 @@ execlp(const char *file, const char *arg, ...) {
sigprocmask(SIG_SETMASK, &saved, NULL);
return -1;
}
- if (pseudo_populate_wrappers()) {
+ if (pseudo_check_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);
- }
+
+ /* exec*() use this to restore the sig mask */
+ pseudo_saved_sigmask = saved;
+ rc = wrap_execvp(file, argv);
save_errno = errno;
pseudo_droplock();
@@ -385,22 +364,12 @@ execle(const char *file, const char *arg, ...) {
sigprocmask(SIG_SETMASK, &saved, NULL);
return -1;
}
- if (pseudo_populate_wrappers()) {
+ if (pseudo_check_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);
- }
+
+ /* exec*() use this to restore the sig mask */
+ pseudo_saved_sigmask = saved;
+ rc = wrap_execve(file, argv, envp);
save_errno = errno;
pseudo_droplock();
@@ -421,6 +390,117 @@ execle(const char *file, const char *arg, ...) {
}
int
+execv(const char *file, char *const *argv) {
+ sigset_t saved;
+
+ int rc = -1;
+
+ pseudo_debug(4, "called: execv\n");
+ pseudo_sigblock(&saved);
+ if (pseudo_getlock()) {
+ errno = EBUSY;
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ return -1;
+ }
+ if (pseudo_check_wrappers()) {
+ int save_errno;
+
+ /* 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: execv\n");
+ errno = save_errno;
+ return rc;
+ } else {
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execv\n");
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execv");
+
+ return rc;
+ }
+}
+
+int
+execve(const char *file, char *const *argv, char *const *envp) {
+ sigset_t saved;
+
+ int rc = -1;
+
+ pseudo_debug(4, "called: execve\n");
+ pseudo_sigblock(&saved);
+ if (pseudo_getlock()) {
+ errno = EBUSY;
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ return -1;
+ }
+ if (pseudo_check_wrappers()) {
+ int save_errno;
+
+ /* 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: execve\n");
+ errno = save_errno;
+ return rc;
+ } else {
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execve\n");
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execve");
+
+ return rc;
+ }
+}
+
+int
+execvp(const char *file, char *const *argv) {
+ sigset_t saved;
+
+ int rc = -1;
+
+ pseudo_debug(4, "called: execvp\n");
+ pseudo_sigblock(&saved);
+ if (pseudo_getlock()) {
+ errno = EBUSY;
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ return -1;
+ }
+ if (pseudo_check_wrappers()) {
+ int save_errno;
+
+ /* 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: execvp\n");
+ errno = save_errno;
+ return rc;
+ } else {
+ pseudo_droplock();
+ sigprocmask(SIG_SETMASK, &saved, NULL);
+ pseudo_debug(4, "completed: execvp\n");
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("execvp");
+
+ return rc;
+ }
+}
+
+int
fork(void) {
sigset_t saved;
@@ -433,7 +513,7 @@ fork(void) {
sigprocmask(SIG_SETMASK, &saved, NULL);
return -1;
}
- if (pseudo_populate_wrappers()) {
+ if (pseudo_check_wrappers()) {
int save_errno;
rc = wrap_fork();
@@ -465,12 +545,6 @@ vfork(void) {
}
int
-wrap_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) {
- /* unused */
- return 0;
-}
-
-int
clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) {
sigset_t saved;
va_list ap;
@@ -486,7 +560,6 @@ clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) {
ctid = va_arg(ap, pid_t *);
va_end(ap);
-
pseudo_debug(4, "called: clone\n");
pseudo_sigblock(&saved);
if (pseudo_getlock()) {
@@ -494,7 +567,7 @@ clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) {
sigprocmask(SIG_SETMASK, &saved, NULL);
return -1;
}
- if (pseudo_populate_wrappers()) {
+ if (pseudo_check_wrappers()) {
int save_errno;
int save_disabled = pseudo_disabled;
/* because clone() doesn't actually continue in this function, we
@@ -532,15 +605,43 @@ clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) {
}
}
-static int (*real_fork)(void) = NULL;
-#if 0
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;
-#endif
+static int (*real_execv)(const char *file, char *const *argv) = NULL;
+static int (*real_execve)(const char *file, char *const *argv, char *const *envp) = NULL;
+static int (*real_execvp)(const char *file, char *const *argv) = NULL;
+static int (*real_fork)(void) = NULL;
static int (*real_clone)(int (*)(void *), void *, int, void *, ...) = NULL;
static int
+wrap_execv(const char *file, char *const *argv) {
+ int rc = -1;
+
+#include "guts/execv.c"
+
+ return rc;
+}
+
+static int
+wrap_execve(const char *file, char *const *argv, char *const *envp) {
+ int rc = -1;
+
+#include "guts/execve.c"
+
+ return rc;
+}
+
+static int
+wrap_execvp(const char *file, char *const *argv) {
+ int rc = -1;
+
+#include "guts/execvp.c"
+
+ return rc;
+}
+
+static int
wrap_fork(void) {
int rc = -1;
@@ -548,3 +649,9 @@ wrap_fork(void) {
return rc;
}
+
+int
+wrap_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) {
+ /* unused */
+ return 0;
+}