diff options
-rw-r--r-- | ChangeLog.txt | 10 | ||||
-rw-r--r-- | doc/program_flow | 63 | ||||
-rw-r--r-- | guts/clone.c | 4 | ||||
-rw-r--r-- | guts/execv.c | 4 | ||||
-rw-r--r-- | guts/execve.c | 4 | ||||
-rw-r--r-- | guts/execvp.c | 4 | ||||
-rw-r--r-- | guts/fork.c | 2 | ||||
-rw-r--r-- | pseudo.c | 9 | ||||
-rw-r--r-- | pseudo.h | 8 | ||||
-rw-r--r-- | pseudo_client.c | 306 | ||||
-rw-r--r-- | pseudo_client.h | 2 | ||||
-rw-r--r-- | pseudo_util.c | 44 | ||||
-rw-r--r-- | pseudo_wrappers.c | 361 | ||||
-rw-r--r-- | templates/wrapfuncs.c | 2 | ||||
-rw-r--r-- | templates/wrapfuncs.h | 11 | ||||
-rw-r--r-- | templates/wrapper_table | 15 | ||||
-rw-r--r-- | wrapfuncs.in | 3 |
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(); @@ -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"); @@ -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); |