diff options
-rw-r--r-- | ChangeLog.txt | 3 | ||||
-rw-r--r-- | ports/common/guts/execv.c | 1 | ||||
-rw-r--r-- | pseudo_client.c | 18 | ||||
-rw-r--r-- | pseudo_client.h | 8 | ||||
-rw-r--r-- | pseudo_util.c | 46 | ||||
-rw-r--r-- | pseudo_wrappers.c | 18 |
6 files changed, 66 insertions, 28 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index 5d2e118..ede9969 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,6 @@ +2016-03-09: + * (seebs) workaround for bash redefining getenv/unsetenv/etc. + 2016-03-02: * (seebs) more server launch rework and updates * (seebs) make dup/dup2 less verbose in client diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c index 6093e44..c071626 100644 --- a/ports/common/guts/execv.c +++ b/ports/common/guts/execv.c @@ -19,6 +19,7 @@ pseudo_setupenv(); if (pseudo_has_unload(NULL)) { + /* and here we attach */ pseudo_dropenv(); } /* if exec() fails, we may end up taking signals unexpectedly... diff --git a/pseudo_client.c b/pseudo_client.c index 371a5b8..6a08df3 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -105,6 +105,9 @@ gid_t pseudo_egid; gid_t pseudo_sgid; gid_t pseudo_fgid; +int (*pseudo_real_fork)(void) = fork; +int (*pseudo_real_execv)(const char *, char * const *) = execv; + #define PSEUDO_ETC_FILE(filename, realname, flags) pseudo_etc_file(filename, realname, flags, passwd_paths, npasswd_paths) /* helper function to make a directory, just like mkdir -p. @@ -939,7 +942,7 @@ client_spawn_server(void) { FILE *fp; char * pseudo_pidfile; - if ((server_pid = fork()) != 0) { + if ((server_pid = pseudo_real_fork()) != 0) { if (server_pid == -1) { pseudo_diag("couldn't fork server: %s\n", strerror(errno)); return 1; @@ -1041,14 +1044,13 @@ client_spawn_server(void) { */ pseudo_client_logging = 0; - /* execve will call setupenv, then call dropenv if - * PSEUDO_UNLOAD is set. We call execve, not execv, due - * to unsetenv changing the responses given by getenv, - * but not changing the contents of the variable environ, - * in some cases. + /* manual setup of environment, so we can call real-execv + * instead of the wrapper. */ - pseudo_set_value("PSEUDO_UNLOAD", "1"); - execve(argv[0], argv, environ); + pseudo_set_value("PSEUDO_UNLOAD", "YES"); + pseudo_setupenv(); + pseudo_dropenv(); + pseudo_real_execv(argv[0], argv); pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno)); exit(1); } diff --git a/pseudo_client.h b/pseudo_client.h index e732bae..68e5160 100644 --- a/pseudo_client.h +++ b/pseudo_client.h @@ -58,6 +58,14 @@ extern int pseudo_pwd_lck_close(void); extern FILE *pseudo_pwd; extern FILE *pseudo_grp; +/* pseudo_wrappers will try to initialize these */ +extern int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf); +extern int (*pseudo_real_unsetenv)(const char *); +extern char * (*pseudo_real_getenv)(const char *); +extern int (*pseudo_real_setenv)(const char *, const char *, int); +extern int (*pseudo_real_fork)(void); +extern int (*pseudo_real_execv)(const char *, char * const *); + /* support related to chroot/getcwd/etc. */ extern int pseudo_client_getcwd(void); extern int pseudo_client_chroot(const char *); diff --git a/pseudo_util.c b/pseudo_util.c index be07951..0c156cf 100644 --- a/pseudo_util.c +++ b/pseudo_util.c @@ -81,6 +81,16 @@ typedef struct { char *data; } pseudo_evlog_entry; +/* so bash overrides getenv/unsetenv/etcetera, preventing them from + * actually modifying environ, so we have pseudo_wrappers try to dlsym + * the right values. This could fail, in which case we'd get null + * pointers, and we'll just call whatever the linker gives us and + * hope for the best. + */ +#define SETENV(x, y, z) (pseudo_real_setenv ? pseudo_real_setenv : setenv)(x, y, z) +#define GETENV(x) (pseudo_real_getenv ? pseudo_real_getenv : getenv)(x) +#define UNSETENV(x) (pseudo_real_unsetenv ? pseudo_real_unsetenv : unsetenv)(x) + #define PSEUDO_EVLOG_ENTRIES 250 #define PSEUDO_EVLOG_LENGTH 256 static pseudo_evlog_entry event_log[PSEUDO_EVLOG_ENTRIES]; @@ -102,6 +112,10 @@ static int pseudo_util_initted = -1; /* Not yet run */ /* bypass wrapper logic on path computations */ int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf) = NULL; +/* bash workaround */ +int (*pseudo_real_unsetenv)(const char *) = unsetenv; +char * (*pseudo_real_getenv)(const char *) = getenv; +int (*pseudo_real_setenv)(const char *, const char *, int) = setenv; #if 0 static void @@ -126,7 +140,7 @@ pseudo_has_unload(char * const *envp) { size_t i = 0; /* Is it in the caller environment? */ - if (NULL != getenv(unload)) + if (NULL != GETENV(unload)) return 1; /* Is it in the environment cache? */ @@ -161,7 +175,7 @@ pseudo_get_value(const char *key) { /* Check if the environment has it and we don't ... * 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)) + if (pseudo_env[i].key && !pseudo_env[i].value && GETENV(pseudo_env[i].key)) pseudo_init_util(); if (pseudo_env[i].value) @@ -215,8 +229,8 @@ pseudo_init_util(void) { 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)); + if (GETENV(pseudo_env[i].key)) + pseudo_set_value(pseudo_env[i].key, GETENV(pseudo_env[i].key)); } pseudo_util_initted = 0; @@ -820,7 +834,7 @@ pseudo_fix_path(const char *base, const char *path, size_t rootlen, size_t basel * we don't try to fix the library path. */ void pseudo_dropenv() { - char *ld_preload = getenv(PRELINK_LIBRARIES); + char *ld_preload = GETENV(PRELINK_LIBRARIES); if (ld_preload) { ld_preload = without_libpseudo(ld_preload); @@ -828,9 +842,9 @@ void pseudo_dropenv() { pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES); } if (ld_preload && strlen(ld_preload)) { - setenv(PRELINK_LIBRARIES, ld_preload, 1); + SETENV(PRELINK_LIBRARIES, ld_preload, 1); } else { - unsetenv(PRELINK_LIBRARIES); + UNSETENV(PRELINK_LIBRARIES); } } } @@ -886,14 +900,14 @@ pseudo_setupenv() { while (pseudo_env[i].key) { if (pseudo_env[i].value) { - setenv(pseudo_env[i].key, pseudo_env[i].value, 0); + SETENV(pseudo_env[i].key, pseudo_env[i].value, 0); pseudo_debug(PDBGF_ENV | PDBGF_VERBOSE, "pseudo_env: %s => %s\n", pseudo_env[i].key, pseudo_env[i].value); } i++; } - const char *ld_library_path = getenv(PRELINK_PATH); + const char *ld_library_path = GETENV(PRELINK_PATH); char *libdir_path = pseudo_libdir_path(NULL); if (!ld_library_path) { size_t len = strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1; @@ -902,7 +916,7 @@ pseudo_setupenv() { pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH); } snprintf(newenv, len, "%s:%s64", libdir_path, libdir_path); - setenv(PRELINK_PATH, newenv, 1); + SETENV(PRELINK_PATH, newenv, 1); } else if (!strstr(ld_library_path, libdir_path)) { size_t len = strlen(ld_library_path) + 1 + strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1; char *newenv = malloc(len); @@ -910,26 +924,26 @@ pseudo_setupenv() { pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH); } snprintf(newenv, len, "%s:%s:%s64", ld_library_path, libdir_path, libdir_path); - setenv(PRELINK_PATH, newenv, 1); + SETENV(PRELINK_PATH, newenv, 1); } else { /* nothing to do, ld_library_path exists and contains * our preferred path */ } - char *ld_preload = getenv(PRELINK_LIBRARIES); + char *ld_preload = GETENV(PRELINK_LIBRARIES); if (ld_preload) { ld_preload = with_libpseudo(ld_preload, libdir_path); if (!ld_preload) { pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES); } - setenv(PRELINK_LIBRARIES, ld_preload, 1); + SETENV(PRELINK_LIBRARIES, ld_preload, 1); free(ld_preload); } else { ld_preload = with_libpseudo("", libdir_path); if (!ld_preload) { pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES); } - setenv(PRELINK_LIBRARIES, ld_preload, 1); + SETENV(PRELINK_LIBRARIES, ld_preload, 1); free(ld_preload); } @@ -940,9 +954,9 @@ pseudo_setupenv() { #if PSEUDO_PORT_DARWIN - char *force_flat = getenv("DYLD_FORCE_FLAT_NAMESPACE"); + char *force_flat = GETENV("DYLD_FORCE_FLAT_NAMESPACE"); if (!force_flat) { - setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1); + SETENV("DYLD_FORCE_FLAT_NAMESPACE", "1", 1); } #endif } diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c index 353a5a4..4a38bef 100644 --- a/pseudo_wrappers.c +++ b/pseudo_wrappers.c @@ -86,16 +86,15 @@ extern struct timeval *pseudo_wrapper_time; #define PROFILE_DONE do {} while(0) #endif +/* later, the init code can change these to refer to the real calls and + * skip the wrappers. + */ #ifdef PSEUDO_XATTRDB extern ssize_t (*pseudo_real_lgetxattr)(const char *, const char *, void *, size_t); extern ssize_t (*pseudo_real_fgetxattr)(int, const char *, void *, size_t); extern int (*pseudo_real_lsetxattr)(const char *, const char *, const void *, size_t, int); extern int (*pseudo_real_fsetxattr)(int, const char *, const void *, size_t, int); #endif -/* later, the init code can change these to refer to the real calls and - * skip the wrappers. - */ -extern int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf); static void _libpseudo_init(void) { @@ -178,6 +177,17 @@ pseudo_init_wrappers(void) { pseudo_real_fsetxattr = real_fsetxattr; #endif pseudo_real_lstat = base_lstat; + /* bash has its own local copies of these which it uses + * instead of ours... + */ + pseudo_real_unsetenv = dlsym(RTLD_NEXT, "unsetenv"); + pseudo_real_getenv = dlsym(RTLD_NEXT, "getenv"); + pseudo_real_setenv = dlsym(RTLD_NEXT, "setenv"); + /* and these are used so the client's server spawn can bypass + * wrappers. + */ + pseudo_real_fork = dlsym(RTLD_NEXT, "fork"); + pseudo_real_execv = dlsym(RTLD_NEXT, "execv"); /* Once the wrappers are setup, we can now use open... so * setup the logfile, if necessary... |