aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Hatle <mark.hatle@windriver.com>2010-12-08 15:33:30 -0600
committerPeter Seebach <peter.seebach@windriver.com>2010-12-13 15:01:49 -0600
commiteba97c46608e776088a86d9d8db25d07e8de09ac (patch)
treeb04c5c61dd4ed181adf0f3810d13de75b37dea09
parent048cd003f3330f0811a48f79cd9d65bf022757a9 (diff)
downloadpseudo-eba97c46608e776088a86d9d8db25d07e8de09ac.tar.gz
pseudo-eba97c46608e776088a86d9d8db25d07e8de09ac.tar.bz2
pseudo-eba97c46608e776088a86d9d8db25d07e8de09ac.zip
Further amend the system to enable/disable sudo during fork/exec.
2010-12-09: * (mhatle) Add doc/program_flow to attempt to explain startup/running * (mhatle) guts/* minor cleanup * (mhatle) Reorganize into a new constructor for libpseudo ONLY pseudo main() now manually calls the util init new / revised init for client, wrappers and utils * (mhatle) Add central "reinit" function * (mhatle) Add manul execv* functions * (mhatle) rename pseudo_populate_wrappers to pseudo_check_wrappers Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
-rw-r--r--ChangeLog.txt10
-rw-r--r--doc/program_flow63
-rw-r--r--guts/clone.c4
-rw-r--r--guts/execv.c4
-rw-r--r--guts/execve.c4
-rw-r--r--guts/execvp.c4
-rw-r--r--guts/fork.c2
-rw-r--r--pseudo.c9
-rw-r--r--pseudo.h8
-rw-r--r--pseudo_client.c306
-rw-r--r--pseudo_client.h2
-rw-r--r--pseudo_util.c44
-rw-r--r--pseudo_wrappers.c361
-rw-r--r--templates/wrapfuncs.c2
-rw-r--r--templates/wrapfuncs.h11
-rw-r--r--templates/wrapper_table15
-rw-r--r--wrapfuncs.in3
17 files changed, 539 insertions, 313 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index d1e18fc..9832e4a 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,13 @@
+2010-12-09:
+ * (mhatle) Add doc/program_flow to attempt to explain startup/running
+ * (mhatle) guts/* minor cleanup
+ * (mhatle) Reorganize into a new constructor for libpseudo ONLY
+ pseudo main() now manually calls the util init
+ new / revised init for client, wrappers and utils
+ * (mhatle) Add central "reinit" function
+ * (mhatle) Add manul execv* functions
+ * (mhatle) rename pseudo_populate_wrappers to pseudo_check_wrappers
+
2010-12-08:
* (mhatle) Add guts/clone.c to cleanup the clone support
* (mhatle) guts/clone.c only run setupenv and reinit when NOT PSEUDO_RELOADED
diff --git a/doc/program_flow b/doc/program_flow
new file mode 100644
index 0000000..b0680a0
--- /dev/null
+++ b/doc/program_flow
@@ -0,0 +1,63 @@
+This is a quick attempt at documenting the basic program flow for both the main
+pseudo executable and the pseudo wrapper library. The key thing to note is
+that there are key init functions. These functions are designed to be
+re-invoked if it becomes necessary to reset the system environment.
+
+libpseudo execution flow:
+ # on startup #
+
+ pseudo_wrappers.c: (constructor) _libpseudo_init()
+ pseudo_util.c: pseudo_init_util()
+ copy environment
+ setup PSEUDO_DEBUG levels
+ pseudo_wrappers.c: pseudo_init_wrappers()
+ setup pseudo_functions
+ setup pseudo_logfile
+ pseudo_client.c: pseudo_init_client()
+ setup PSEUDO_DISBLED
+ setup pseudo_prefix_dir_fd
+ setup pseudo_localstate_dir_fd
+ setup PSEUDO_NOSYMLINKEXP
+ setup PSEUDO_UIDS
+ setup PSEUDO_GIDS
+ setup PSEUDO_CHROOT
+ setup PSEUDO_PASSWD
+
+ # regular program execution #
+ exec*()
+ pseudo_check_wrappers():
+ pseudo_reinit_libpseudo if necessary
+ call wrap_exec*()
+ if !PSEUDO_RELOADED
+ pseudo_setupenv()
+ else
+ pseudo_setupenv()
+ pseudo_dropenv()
+ real_exec*()
+
+ fork()
+ clone()
+ pseudo_populate_wrappers():
+ pseudo_reinit_libpseudo if necessary
+ call wrap_exec*()
+ if !PSEUDO_RELOADED
+ pseudo_setupenv()
+ pseudo_reinit_libpseudo()
+ _libpseudo_init()
+ else
+ pseudo_setupenv()
+ pseudo_dropenv()
+ real_*()
+
+ ... normal function wrappers ...
+
+pseudo execution flow:
+ pseudo.c: main()
+ pseudo_util.c: pseudo_init_util()
+ <see above>
+ check LD_PRELOAD
+ process arguments
+ setup PSEUDO_OPTS
+ ...
+ startup server
+
diff --git a/guts/clone.c b/guts/clone.c
index 61c8bf9..8299c54 100644
--- a/guts/clone.c
+++ b/guts/clone.c
@@ -14,8 +14,8 @@
pseudo_debug(1, "client resetting for clone(2) call\n");
if (real_clone) {
if (!pseudo_get_value("PSEUDO_RELOADED")) {
- pseudo_setupenv();
- pseudo_client_reinit();
+ pseudo_setupenv();
+ pseudo_reinit_libpseudo();
} else {
pseudo_setupenv();
pseudo_dropenv();
diff --git a/guts/execv.c b/guts/execv.c
index cc37e0a..a72556b 100644
--- a/guts/execv.c
+++ b/guts/execv.c
@@ -12,7 +12,9 @@
* <CHROOT>/bin/sh. This allows use of basic utilities. This
* design will likely be revisited.
*/
- pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0);
+ if (antimagic == 0) {
+ pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0);
+ }
if (!pseudo_get_value("PSEUDO_RELOADED"))
pseudo_setupenv();
diff --git a/guts/execve.c b/guts/execve.c
index febcf80..fafc154 100644
--- a/guts/execve.c
+++ b/guts/execve.c
@@ -13,7 +13,9 @@
* <CHROOT>/bin/sh. This allows use of basic utilities. This
* design will likely be revisited.
*/
- pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0);
+ if (antimagic == 0) {
+ pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0);
+ }
if (!pseudo_get_value("PSEUDO_RELOADED"))
new_environ = pseudo_setupenvp(envp);
diff --git a/guts/execvp.c b/guts/execvp.c
index 67eaff0..a3ce05b 100644
--- a/guts/execvp.c
+++ b/guts/execvp.c
@@ -13,7 +13,9 @@
* <CHROOT>/bin/sh. This allows use of basic utilities. This
* design will likely be revisited.
*/
- pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0);
+ if (antimagic == 0) {
+ pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0);
+ }
if (!pseudo_get_value("PSEUDO_RELOADED"))
pseudo_setupenv();
diff --git a/guts/fork.c b/guts/fork.c
index 8febd13..b7fd239 100644
--- a/guts/fork.c
+++ b/guts/fork.c
@@ -14,7 +14,7 @@
if (rc == 0) {
if (!pseudo_get_value("PSEUDO_RELOADED")) {
pseudo_setupenv();
- pseudo_client_reinit();
+ pseudo_reinit_libpseudo();
} else {
pseudo_setupenv();
pseudo_dropenv();
diff --git a/pseudo.c b/pseudo.c
index b9b05d0..350ad6b 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -79,14 +79,7 @@ main(int argc, char *argv[]) {
opts[0] = '\0';
- s = pseudo_get_value("PSEUDO_DEBUG");
- if (s) {
- int level = atoi(s);
- for (o = 0; o < level; ++o) {
- pseudo_debug_verbose();
- }
- }
- free(s);
+ pseudo_init_util();
if (ld_env && strstr(ld_env, "libpseudo")) {
pseudo_debug(2, "can't run daemon with libpseudo in LD_PRELOAD\n");
diff --git a/pseudo.h b/pseudo.h
index 38b663a..a101597 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -20,6 +20,11 @@
#include <stdlib.h>
#include <fcntl.h>
+/* List of magic initialization functions... */
+extern void pseudo_init_wrappers(void);
+extern void pseudo_init_util(void);
+extern void pseudo_init_client(void);
+
void pseudo_dump_env(char **envp);
int pseudo_set_value(const char *key, const char *value);
char *pseudo_get_value(const char *key);
@@ -61,9 +66,6 @@ extern ssize_t pseudo_path_max(void);
extern int pseudo_etc_file(const char *filename, char *realname, int flags, char **search, int dircount);
#define PSEUDO_ETC_FILE(name, realname, flags) pseudo_etc_file((name), (realname), (flags), (char *[]) { pseudo_chroot, pseudo_passwd }, 2)
-/* refresh environment variables from internals */
-extern void pseudo_reinit_environment(void);
-
extern char *pseudo_version;
#ifndef PSEUDO_BINDIR
diff --git a/pseudo_client.c b/pseudo_client.c
index 8bad083..cd784f9 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -78,6 +78,169 @@ gid_t pseudo_egid;
gid_t pseudo_sgid;
gid_t pseudo_fgid;
+void
+pseudo_init_client(void) {
+ char *env;
+
+ pseudo_antimagic();
+ pseudo_new_pid();
+ if (connect_fd != -1) {
+ close(connect_fd);
+ connect_fd = -1;
+ }
+
+ /* in child processes, PSEUDO_DISABLED may have become set to
+ * some truthy value, in which case we'd disable pseudo,
+ * or it may have gone away, in which case we'd enable
+ * pseudo (and cause it to reinit the defaults).
+ */
+ env = getenv("PSEUDO_DISABLED");
+ if (!env) pseudo_get_value("PSEUDO_DISABLED");
+ if (env) {
+ int actually_disabled = 1;
+ switch (*env) {
+ case '0':
+ case 'f':
+ case 'F':
+ case 'n':
+ case 'N':
+ actually_disabled = 0;
+ break;
+ }
+ if (actually_disabled) {
+ if (!pseudo_disabled) {
+ pseudo_antimagic();
+ pseudo_disabled = 1;
+ }
+ pseudo_set_value("PSEUDO_DISABLED", "1");
+ } else {
+ if (pseudo_disabled) {
+ pseudo_magic();
+ pseudo_disabled = 0;
+ pseudo_inited = 0; /* Re-read the initial values! */
+ }
+ pseudo_set_value("PSEUDO_DISABLED", "0");
+ }
+ } else {
+ pseudo_set_value("PSEUDO_DISABLED", "0");
+ }
+
+ /* Setup global items needed for pseudo to function... */
+ if (!pseudo_inited) {
+ char *pseudo_path = 0;
+
+ /* Ensure that all of the values are reset */
+ server_pid = 0;
+ pseudo_prefix_dir_fd = -1;
+ pseudo_localstate_dir_fd = -1;
+ pseudo_pwd_fd = -1;
+ pseudo_pwd_lck_fd = -1;
+ pseudo_pwd_lck_name = NULL;
+ pseudo_pwd = NULL;
+ pseudo_grp_fd = -1;
+ pseudo_grp = NULL;
+ pseudo_cwd = NULL;
+ pseudo_cwd_len = 0;
+ pseudo_chroot = NULL;
+ pseudo_passwd = NULL;
+ pseudo_chroot_len = 0;
+ pseudo_cwd_rel = NULL;
+ pseudo_nosymlinkexp = 0;
+
+ pseudo_path = pseudo_prefix_path(NULL);
+ if (pseudo_prefix_dir_fd == -1) {
+ if (pseudo_path) {
+ pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
+ pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, MOVE_FD);
+ } else {
+ pseudo_diag("No prefix available to to find server.\n");
+ exit(1);
+ }
+ if (pseudo_prefix_dir_fd == -1) {
+ pseudo_diag("Can't open prefix path (%s) for server: %s\n",
+ pseudo_path,
+ strerror(errno));
+ exit(1);
+ }
+ }
+ free(pseudo_path);
+ pseudo_path = pseudo_localstatedir_path(NULL);
+ if (pseudo_localstate_dir_fd == -1) {
+ if (pseudo_path) {
+ pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
+ pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, MOVE_FD);
+ } else {
+ pseudo_diag("No prefix available to to find server.\n");
+ exit(1);
+ }
+ if (pseudo_localstate_dir_fd == -1) {
+ pseudo_diag("Can't open prefix path (%s) for server: %s\n",
+ pseudo_path,
+ strerror(errno));
+ exit(1);
+ }
+ }
+ free(pseudo_path);
+
+ env = pseudo_get_value("PSEUDO_NOSYMLINKEXP");
+ if (env) {
+ 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 (*env) {
+ pseudo_nosymlinkexp = strtol(env, &endptr, 10);
+ if (*endptr)
+ pseudo_nosymlinkexp = 1;
+ } else {
+ pseudo_nosymlinkexp = 1;
+ }
+ } else {
+ pseudo_nosymlinkexp = 0;
+ }
+ free(env);
+ env = pseudo_get_value("PSEUDO_UIDS");
+ if (env)
+ sscanf(env, "%d,%d,%d,%d",
+ &pseudo_ruid, &pseudo_euid,
+ &pseudo_suid, &pseudo_fuid);
+ free(env);
+
+ env = pseudo_get_value("PSEUDO_GIDS");
+ if (env)
+ sscanf(env, "%d,%d,%d,%d",
+ &pseudo_rgid, &pseudo_egid,
+ &pseudo_sgid, &pseudo_fuid);
+ free(env);
+
+ env = pseudo_get_value("PSEUDO_CHROOT");
+ if (env) {
+ pseudo_chroot = strdup(env);
+ if (pseudo_chroot) {
+ pseudo_chroot_len = strlen(pseudo_chroot);
+ } else {
+ pseudo_diag("can't store chroot path (%s)\n", env);
+ }
+ }
+ free(env);
+
+ env = pseudo_get_value("PSEUDO_PASSWD");
+ if (env) {
+ pseudo_passwd = strdup(env);
+ }
+ free(env);
+
+ pseudo_inited = 1;
+ }
+ pseudo_client_getcwd();
+ pseudo_magic();
+}
+
static void
pseudo_file_close(int *fd, FILE **fp) {
if (!fp || !fd) {
@@ -311,149 +474,6 @@ pseudo_client_close(int fd) {
fd_paths[fd] = 0;
}
- void
-pseudo_client_reinit() {
- pseudo_debug(1, "called: pseudo_client_reinit\n");
- pseudo_inited = 0;
- pseudo_reinit_environment();
- pseudo_client_reset();
-}
-
-void
-pseudo_client_reset() {
- pseudo_antimagic();
- pseudo_new_pid();
- if (connect_fd != -1) {
- close(connect_fd);
- connect_fd = -1;
- }
-
- if (!pseudo_inited) {
- char *pseudo_path = 0;
- char *env;
-
- /* Ensure that all of the values are reset */
- server_pid = 0;
- pseudo_prefix_dir_fd = -1;
- pseudo_localstate_dir_fd = -1;
- pseudo_pwd_fd = -1;
- pseudo_pwd_lck_fd = -1;
- pseudo_pwd_lck_name = NULL;
- pseudo_pwd = NULL;
- pseudo_grp_fd = -1;
- pseudo_grp = NULL;
- pseudo_cwd = NULL;
- pseudo_cwd_len = 0;
- pseudo_chroot = NULL;
- pseudo_passwd = NULL;
- pseudo_chroot_len = 0;
- pseudo_cwd_rel = NULL;
-
- pseudo_path = pseudo_prefix_path(NULL);
- if (pseudo_prefix_dir_fd == -1) {
- if (pseudo_path) {
- pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
- pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, MOVE_FD);
- } else {
- pseudo_diag("No prefix available to to find server.\n");
- exit(1);
- }
- if (pseudo_prefix_dir_fd == -1) {
- pseudo_diag("Can't open prefix path (%s) for server: %s\n",
- pseudo_path,
- strerror(errno));
- exit(1);
- }
- }
- free(pseudo_path);
- pseudo_path = pseudo_localstatedir_path(NULL);
- if (pseudo_localstate_dir_fd == -1) {
- if (pseudo_path) {
- pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
- pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, MOVE_FD);
- } else {
- pseudo_diag("No prefix available to to find server.\n");
- exit(1);
- }
- if (pseudo_localstate_dir_fd == -1) {
- pseudo_diag("Can't open prefix path (%s) for server: %s\n",
- pseudo_path,
- strerror(errno));
- exit(1);
- }
- }
- free(pseudo_path);
-
- /* in child processes, PSEUDO_DISABLED may have become set to
- * some truthy value, in which case we'd disable pseudo,
- * or it may have gone away, in which case we'd enable
- * pseudo.
- */
- env = getenv("PSEUDO_DISABLED");
- if (!env) pseudo_get_value("PSEUDO_DISABLED");
- if (env) {
- int actually_disabled = 1;
- switch (*env) {
- case '0':
- case 'f':
- case 'F':
- case 'n':
- case 'N':
- actually_disabled = 0;
- break;
- }
- if (actually_disabled) {
- if (!pseudo_disabled) {
- pseudo_antimagic();
- pseudo_disabled = 1;
- }
- pseudo_set_value("PSEUDO_DISABLED", "1");
- } else {
- if (pseudo_disabled) {
- pseudo_magic();
- pseudo_disabled = 0;
- }
- pseudo_set_value("PSEUDO_DISABLED", "0");
- }
- }
-
- env = pseudo_get_value("PSEUDO_UIDS");
- if (env)
- sscanf(env, "%d,%d,%d,%d",
- &pseudo_ruid, &pseudo_euid,
- &pseudo_suid, &pseudo_fuid);
- free(env);
-
- env = pseudo_get_value("PSEUDO_GIDS");
- if (env)
- sscanf(env, "%d,%d,%d,%d",
- &pseudo_rgid, &pseudo_egid,
- &pseudo_sgid, &pseudo_fuid);
- free(env);
-
- env = pseudo_get_value("PSEUDO_CHROOT");
- if (env) {
- pseudo_chroot = strdup(env);
- if (pseudo_chroot) {
- pseudo_chroot_len = strlen(pseudo_chroot);
- } else {
- pseudo_diag("can't store chroot path (%s)\n", env);
- }
- }
- free(env);
-
- env = pseudo_get_value("PSEUDO_PASSWD");
- if (env) {
- pseudo_passwd = strdup(env);
- }
- free(env);
-
- pseudo_inited = 1;
- }
- pseudo_client_getcwd();
- pseudo_magic();
-}
-
/* spawn server */
static int
client_spawn_server(void) {
diff --git a/pseudo_client.h b/pseudo_client.h
index ea92f6a..4dc13d0 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -20,8 +20,6 @@
extern pseudo_msg_t *pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path, const struct stat64 *buf, ...);
extern void pseudo_antimagic(void);
extern void pseudo_magic(void);
-extern void pseudo_client_reinit(void);
-extern void pseudo_client_reset(void);
extern void pseudo_client_touchuid(void);
extern void pseudo_client_touchgid(void);
extern char *pseudo_client_fdpath(int fd);
diff --git a/pseudo_util.c b/pseudo_util.c
index 97c9911..dc55b0c 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -76,9 +76,7 @@ static struct pseudo_variables pseudo_env[] = {
* program starts playing with things, so we need to do our
* best to handle that case.
*/
-static int _pseudo_in_init = -1; /* Not yet run */
-
-static void _libpseudo_init(void) __attribute__ ((constructor));
+static int pseudo_util_initted = -1; /* Not yet run */
#if 0
static void
@@ -92,24 +90,18 @@ dump_env(char **envp) {
pseudo_debug(0,"dump_envp: {%d}%s=%s\n", (int) i, pseudo_env[i].key, pseudo_env[i].value);
}
- pseudo_debug(0, "dump_envp: _in_init %d\n", _pseudo_in_init);
+ pseudo_debug(0, "dump_envp: _in_init %d\n", pseudo_util_initted);
}
#endif
-void
-pseudo_reinit_environment(void) {
- _pseudo_in_init = 0;
- _libpseudo_init();
-}
-
/* Caller must free memory! */
char *
pseudo_get_value(const char *key) {
size_t i = 0;
char * value;
- if (_pseudo_in_init == -1)
- _libpseudo_init();
+ if (pseudo_util_initted == -1)
+ pseudo_init_util();
for (i = 0; pseudo_env[i].key && memcmp(pseudo_env[i].key, key, pseudo_env[i].key_len + 1); i++)
;
@@ -118,7 +110,7 @@ pseudo_get_value(const char *key) {
* if so, something went wrong... so we'll attempt to recover
*/
if (pseudo_env[i].key && !pseudo_env[i].value && getenv(pseudo_env[i].key))
- _libpseudo_init();
+ pseudo_init_util();
if (pseudo_env[i].value)
value = strdup(pseudo_env[i].value);
@@ -137,8 +129,8 @@ pseudo_set_value(const char *key, const char *value) {
int rc = 0;
size_t i = 0;
- if (_pseudo_in_init == -1)
- _libpseudo_init();
+ if (pseudo_util_initted == -1)
+ pseudo_init_util();
for (i = 0; pseudo_env[i].key && memcmp(pseudo_env[i].key, key, pseudo_env[i].key_len + 1); i++)
;
@@ -156,25 +148,37 @@ pseudo_set_value(const char *key, const char *value) {
} else
pseudo_env[i].value = NULL;
} else {
- if (!_pseudo_in_init) pseudo_diag("Unknown variable %s.\n", key);
+ if (!pseudo_util_initted) pseudo_diag("Unknown variable %s.\n", key);
rc = -EINVAL;
}
return rc;
}
-static void
-_libpseudo_init(void) {
+void
+pseudo_init_util(void) {
size_t i = 0;
+ char * env;
- _pseudo_in_init = 1;
+ pseudo_util_initted = 1;
for (i = 0; pseudo_env[i].key; i++) {
if (getenv(pseudo_env[i].key))
pseudo_set_value(pseudo_env[i].key, getenv(pseudo_env[i].key));
}
- _pseudo_in_init = 0;
+ pseudo_util_initted = 0;
+
+ /* Somewhere we have to set the debug level.. */
+ env = pseudo_get_value("PSEUDO_DEBUG");
+ if (env) {
+ int i;
+ int level = atoi(env);
+ for (i = 0; i < level; ++i) {
+ pseudo_debug_verbose();
+ }
+ }
+ free(env);
}
/* 5 = ridiculous levels of duplication
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;
+}
diff --git a/templates/wrapfuncs.c b/templates/wrapfuncs.c
index c0170d9..61065c5 100644
--- a/templates/wrapfuncs.c
+++ b/templates/wrapfuncs.c
@@ -30,7 +30,7 @@ ${name}(${decl_args}) {
sigprocmask(SIG_SETMASK, &saved, NULL);
${def_return}
}
- if (pseudo_populate_wrappers()) {
+ if (pseudo_check_wrappers()) {
int save_errno;
if (antimagic > 0) {
if (real_$name) {
diff --git a/templates/wrapfuncs.h b/templates/wrapfuncs.h
index 8088d09..403d261 100644
--- a/templates/wrapfuncs.h
+++ b/templates/wrapfuncs.h
@@ -14,5 +14,16 @@ static ${type} (*real_${name})(${decl_args});
/* int fork(void) */
static int wrap_fork(void);
static int (*real_fork)(void);
+/* int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) */
static int wrap_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);
static int (*real_clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);
+/* int execv(const char *file, char *const *argv) */
+static int wrap_execv(const char *file, char *const *argv);
+static int (*real_execv)(const char *file, char *const *argv);
+/* int execve(const char *file, char *const *argv, char *const *envp) */
+static int wrap_execve(const char *file, char *const *argv, char *const *envp);
+static int (*real_execve)(const char *file, char *const *argv, char *const *envp);
+/* int execvp(const char *file, char *const *argv) */
+static int wrap_execvp(const char *file, char *const *argv);
+static int (*real_execvp)(const char *file, char *const *argv);
+
diff --git a/templates/wrapper_table b/templates/wrapper_table
index f1a3220..dd9c249 100644
--- a/templates/wrapper_table
+++ b/templates/wrapper_table
@@ -27,5 +27,20 @@ static struct {
(int (**)(void)) &real_clone,
(int (*)(void)) wrap_clone
},
+ { /* int execv(const char *file, char *const *argv); */
+ "execv",
+ (int (**)(void)) &real_execv,
+ (int (*)(void)) wrap_execv
+ },
+ { /* int execve(const char *file, char *const *argv, char *const *envp); */
+ "execve",
+ (int (**)(void)) &real_execve,
+ (int (*)(void)) wrap_execve
+ },
+ { /* int execvp(const char *file, char *const *argv); */
+ "execvp",
+ (int (**)(void)) &real_execvp,
+ (int (*)(void)) wrap_execvp
+ },
{ NULL, NULL, NULL },
};
diff --git a/wrapfuncs.in b/wrapfuncs.in
index eb9280e..a30486b 100644
--- a/wrapfuncs.in
+++ b/wrapfuncs.in
@@ -86,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 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);
# for emulation of passwd utilities
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);