aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.txt7
-rw-r--r--doc/program_flow29
-rw-r--r--ports/common/guts/execv.c7
-rw-r--r--ports/common/guts/execve.c7
-rw-r--r--ports/common/guts/execvp.c7
-rw-r--r--ports/common/guts/fork.c5
-rw-r--r--ports/linux/newclone/guts/clone.c5
-rw-r--r--ports/linux/oldclone/guts/clone.c5
-rw-r--r--pseudo.139
-rw-r--r--pseudo.c14
-rw-r--r--pseudo_client.c16
-rw-r--r--pseudo_util.c2
-rwxr-xr-xtest/test-chroot.sh27
-rwxr-xr-xtest/test-pseudo_disable-fork-env_i.sh (renamed from test/test-forkoff-env_i.sh)0
-rwxr-xr-xtest/test-pseudo_disable-fork.sh (renamed from test/test-forkoff.sh)0
-rwxr-xr-xtest/test-pseudo_unload-fork-env_i.sh29
-rwxr-xr-xtest/test-pseudo_unload-fork.sh18
-rwxr-xr-xtest/test-reexec-chroot.sh30
18 files changed, 197 insertions, 50 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 38af947..2c70277 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,10 @@
+2011-10-20:
+ * (mhatle) change from internal PSEUDO_RELOADED to external
+ PSEUDO_UNLOAD environment variable. Enable external programs
+ to have a safe and reliable way to unload pseudo on the next
+ exec*. PSEUDO_UNLOAD also will disable pseudo if we're in a
+ fork/clone situation in the same way PSEUDO_DISABLED=1 would.
+
2011-07-19:
* (seebs) initialize a variable in that "realpath" code.
diff --git a/doc/program_flow b/doc/program_flow
index 8991681..3a399a7 100644
--- a/doc/program_flow
+++ b/doc/program_flow
@@ -14,7 +14,7 @@ libpseudo execution flow:
setup pseudo_functions
setup pseudo_logfile
pseudo_client.c: pseudo_init_client()
- setup PSEUDO_DISBLED
+ setup PSEUDO_DISABLED
setup pseudo_prefix_dir_fd
setup pseudo_localstate_dir_fd
setup PSEUDO_NOSYMLINKEXP
@@ -28,26 +28,35 @@ libpseudo execution flow:
pseudo_check_wrappers():
pseudo_reinit_libpseudo if necessary
call wrap_exec*()
- if !PSEUDO_RELOADED
- pseudo_setupenv()
- else
- pseudo_setupenv()
+ pseudo_setupenv()
+ if PSEUDO_UNLOAD
pseudo_dropenv()
real_exec*()
fork()
- clone()
pseudo_check_wrappers():
pseudo_reinit_libpseudo if necessary
- call wrap_exec*()
- if !PSEUDO_RELOADED
+ call wrap_fork()
+ real_fork()
+ if (child)
pseudo_setupenv()
+ if !PSEUDO_UNLOAD
+ pseudo_reinit_libpseudo()
+ _libpseudo_init()
+ else
+ pseudo_dropenv()
+
+ clone()
+ pseudo_check_wrappers():
+ pseudo_reinit_libpseudo if necessary
+ call wrap_clone()
+ pseudo_setupenv()
+ if !PSEUDO_UNLOAD
pseudo_reinit_libpseudo()
_libpseudo_init()
else
- pseudo_setupenv()
pseudo_dropenv()
- real_*()
+ real_clone()
... normal function wrappers ... (templates/wrapfuncs.c):
pseudo_check_wrappers() || !real_*
diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c
index 15ad51e..763e1f9 100644
--- a/ports/common/guts/execv.c
+++ b/ports/common/guts/execv.c
@@ -18,12 +18,9 @@
free(path_guess);
}
- if (!pseudo_get_value("PSEUDO_RELOADED"))
- pseudo_setupenv();
- else {
- pseudo_setupenv();
+ pseudo_setupenv();
+ if (pseudo_get_value("PSEUDO_UNLOAD"))
pseudo_dropenv();
- }
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
diff --git a/ports/common/guts/execve.c b/ports/common/guts/execve.c
index a47b9a7..a003657 100644
--- a/ports/common/guts/execve.c
+++ b/ports/common/guts/execve.c
@@ -19,12 +19,9 @@
free(path_guess);
}
- if (!pseudo_get_value("PSEUDO_RELOADED"))
- new_environ = pseudo_setupenvp(envp);
- else {
- new_environ = pseudo_setupenvp(envp);
+ new_environ = pseudo_setupenvp(envp);
+ if (pseudo_get_value("PSEUDO_UNLOAD"))
new_environ = pseudo_dropenvp(new_environ);
- }
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
diff --git a/ports/common/guts/execvp.c b/ports/common/guts/execvp.c
index 419f41b..5e75be7 100644
--- a/ports/common/guts/execvp.c
+++ b/ports/common/guts/execvp.c
@@ -19,12 +19,9 @@
free(path_guess);
}
- if (!pseudo_get_value("PSEUDO_RELOADED"))
- pseudo_setupenv();
- else {
- pseudo_setupenv();
+ pseudo_setupenv();
+ if (pseudo_get_value("PSEUDO_UNLOAD"))
pseudo_dropenv();
- }
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
diff --git a/ports/common/guts/fork.c b/ports/common/guts/fork.c
index 76cac6f..df8abd7 100644
--- a/ports/common/guts/fork.c
+++ b/ports/common/guts/fork.c
@@ -11,11 +11,10 @@
* pseudo in the child process
*/
if (rc == 0) {
- if (!pseudo_get_value("PSEUDO_RELOADED")) {
- pseudo_setupenv();
+ pseudo_setupenv();
+ if (!pseudo_get_value("PSEUDO_UNLOAD")) {
pseudo_reinit_libpseudo();
} else {
- pseudo_setupenv();
pseudo_dropenv();
}
}
diff --git a/ports/linux/newclone/guts/clone.c b/ports/linux/newclone/guts/clone.c
index b3400c7..4b65036 100644
--- a/ports/linux/newclone/guts/clone.c
+++ b/ports/linux/newclone/guts/clone.c
@@ -12,11 +12,10 @@
* undo it later. UGH!
*/
pseudo_debug(1, "client resetting for clone(2) call\n");
- if (!pseudo_get_value("PSEUDO_RELOADED")) {
- pseudo_setupenv();
+ pseudo_setupenv();
+ if (!pseudo_get_value("PSEUDO_UNLOAD")) {
pseudo_reinit_libpseudo();
} else {
- pseudo_setupenv();
pseudo_dropenv();
}
/* call the real syscall */
diff --git a/ports/linux/oldclone/guts/clone.c b/ports/linux/oldclone/guts/clone.c
index 58ff4ad..e8b87e8 100644
--- a/ports/linux/oldclone/guts/clone.c
+++ b/ports/linux/oldclone/guts/clone.c
@@ -12,11 +12,10 @@
* undo it later. UGH!
*/
pseudo_debug(1, "client resetting for clone(2) call\n");
- if (!pseudo_get_value("PSEUDO_RELOADED")) {
- pseudo_setupenv();
+ pseudo_setupenv();
+ if (!pseudo_get_value("PSEUDO_UNLOAD")) {
pseudo_reinit_libpseudo();
} else {
- pseudo_setupenv();
pseudo_dropenv();
}
/* call the real syscall */
diff --git a/pseudo.1 b/pseudo.1
index aa32bbe..d2309ff 100644
--- a/pseudo.1
+++ b/pseudo.1
@@ -408,8 +408,9 @@ 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
.IR fork(2) ,\ clone(2)
-or related functions. If the value starts with a lowercase or uppercase s,
-the pseudo client disables all server spawning and communications, but still
+or related functions. If the value starts with a lowercase or uppercase
+.I s
+, the pseudo client disables all server spawning and communications, but still
operates locally. This means that no filesystem mode or permissions changes
are actually recorded or reported, but functions like
.I chown()
@@ -506,15 +507,6 @@ This variable is automatically set by the
.I pseudo
program when it is used as a launcher.
.TP 8
-.B PSEUDO_RELOADED
-This purely internal variable is used to track state while trying
-to re-execute to get rid of the
-.B LD_PRELOAD
-value when spawning a server. (The
-.I pseudo
-server itself cannot function running in the
-.I pseudo environment.)
-.TP 8
.B PSEUDO_TAG
If this variable is set in a client's environment, its value is
communicated to the server at the beginning of each client session,
@@ -526,6 +518,24 @@ associated with them; the tag value is per-client, not per-server.
These variables are used internally to pass information about the current
emulated user and group identity from one process to another.
.TP 8
+.B PSEUDO_UNLOAD
+This variable is reevaluated on every call to
+.IR fork(2) ,\ exec(3)
+or related functions. If the variable exists
+.RI libpseudo.so
+will be removed from
+.B LD_PRELOAD
+and
+.B PSEUDO_DISABLED
+behavior will also be triggered. For processes
+that simply
+.IR fork(2),
+the behavior will be the same as if
+.B PSEUDO_DISABLED
+was set. For new processes, after a call to
+.IR exec(3)\ or\ system(3)
+pseudo will not be loaded in the new process.
+.TP 8
.B SHELL
If set, this will be used when
.I pseudo
@@ -566,6 +576,13 @@ than it is otherwise. This is probably because nearly every operation
communication with the server, and probably some kind of database
activity.
+The
+.IR clone(2)
+wrapper unconditionallity restores the system environment. It also invokes
+the checks to see if the user has requested pseudo to be disabled or unloaded.
+Due to the semantics of clone, this causes both the parent and child processes
+to be disabled or unloaded.
+
.SH SEE ALSO
fakeroot(1), ld.so(8), pseudolog(1), sqlite3(1)
.SH FURTHER READING
diff --git a/pseudo.c b/pseudo.c
index 99ad1f1..4ea79c5 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -106,21 +106,29 @@ main(int argc, char *argv[]) {
if (ld_env && strstr(ld_env, "libpseudo")) {
pseudo_debug(2, "can't run daemon with libpseudo in %s\n", PRELINK_LIBRARIES);
- s = pseudo_get_value("PSEUDO_RELOADED");
+ s = pseudo_get_value("PSEUDO_UNLOAD");
if (s) {
pseudo_diag("I can't seem to make %s go away. Sorry.\n", PRELINK_LIBRARIES);
pseudo_diag("%s: %s\n", PRELINK_LIBRARIES, ld_env);
exit(EXIT_FAILURE);
}
free(s);
- pseudo_set_value("PSEUDO_RELOADED", "YES");
+ pseudo_set_value("PSEUDO_UNLOAD", "YES");
pseudo_setupenv();
pseudo_dropenv(); /* Drop PRELINK_LIBRARIES */
execv(argv[0], argv);
exit(EXIT_FAILURE);
}
- pseudo_set_value("PSEUDO_RELOADED", NULL);
+
+ /* Be sure to clean PSEUDO_UNLOAD so if we're asked to run any
+ * programs pseudo will be active in the process...
+ * (note: pseudo_set_value doesn't muck w/ the environment, thus
+ * the need for the unsetenv, which is safe because "pseudo"
+ * is the executable in this case!)
+ */
+ pseudo_set_value("PSEUDO_UNLOAD", NULL);
+ unsetenv("PSEUDO_UNLOAD");
/* we need cwd to canonicalize paths */
pseudo_client_getcwd();
diff --git a/pseudo_client.c b/pseudo_client.c
index 1108658..918e52f 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -161,6 +161,20 @@ pseudo_init_client(void) {
pseudo_set_value("PSEUDO_DISABLED", "0");
}
+ /* in child processes, PSEUDO_UNLOAD may become set to
+ * some truthy value, in which case we're being asked to
+ * remove pseudo from the LD_PRELOAD. We need to make sure
+ * this value gets loaded into the internal variables.
+ *
+ * If we've been told to unload, but are still available
+ * we need to act as if unconditionally disabled.
+ */
+ env = getenv("PSEUDO_UNLOAD");
+ if (env) {
+ pseudo_set_value("PSEUDO_UNLOAD", env);
+ pseudo_disabled=1;
+ }
+
/* Setup global items needed for pseudo to function... */
if (!pseudo_inited) {
/* Ensure that all of the values are reset */
@@ -641,7 +655,7 @@ client_spawn_server(void) {
}
/* and now, execute the server */
- pseudo_set_value("PSEUDO_RELOADED", "YES");
+ pseudo_set_value("PSEUDO_UNLOAD", "YES");
pseudo_setupenv();
pseudo_dropenv(); /* drop PRELINK_LIBRARIES */
diff --git a/pseudo_util.c b/pseudo_util.c
index ada6060..d4aab07 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -63,8 +63,8 @@ static struct pseudo_variables pseudo_env[] = {
{ "PSEUDO_TAG", 10, NULL },
{ "PSEUDO_ENOSYS_ABORT", 19, NULL },
{ "PSEUDO_NOSYMLINKEXP", 19, NULL },
- { "PSEUDO_RELOADED", 15, NULL },
{ "PSEUDO_DISABLED", 15, NULL },
+ { "PSEUDO_UNLOAD", 13, NULL },
{ NULL, 0, NULL } /* Magic terminator */
};
diff --git a/test/test-chroot.sh b/test/test-chroot.sh
new file mode 100755
index 0000000..02c9ff6
--- /dev/null
+++ b/test/test-chroot.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Return vals: 2 - invalid arg list
+# 1 - chroot failed
+# 0 - chroot succeeded
+cat > chroot_test.c << EOF
+#include <unistd.h>
+int main(int argc, char *argv[]) {
+ if (argc != 2)
+ return 2;
+ return (chroot(argv[1]) == -1);
+}
+EOF
+
+gcc -o chroot_test chroot_test.c
+
+./chroot_test `pwd`
+
+if [ "$?" = "0" ]
+then
+ #echo "Passed."
+ rm -f chroot_test chroot_test.c
+ exit 0
+fi
+#echo "Failed"
+rm -f chroot_test chroot_test.c
+exit 1
diff --git a/test/test-forkoff-env_i.sh b/test/test-pseudo_disable-fork-env_i.sh
index 1e679aa..1e679aa 100755
--- a/test/test-forkoff-env_i.sh
+++ b/test/test-pseudo_disable-fork-env_i.sh
diff --git a/test/test-forkoff.sh b/test/test-pseudo_disable-fork.sh
index 13a42a4..13a42a4 100755
--- a/test/test-forkoff.sh
+++ b/test/test-pseudo_disable-fork.sh
diff --git a/test/test-pseudo_unload-fork-env_i.sh b/test/test-pseudo_unload-fork-env_i.sh
new file mode 100755
index 0000000..d6658e0
--- /dev/null
+++ b/test/test-pseudo_unload-fork-env_i.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Verify normal operation...
+uid=`env -i id -u`
+gid=`env -i id -g`
+if [ $uid -ne 0 -o $gid -ne 0 ]; then
+ exit 1
+fi
+
+export PSEUDO_UNLOAD=1
+# Verify we dropped OUT of pseudo control, even with env -i
+# This checks that env -i replacement functionality still works
+# as expected
+uid=`env -i id -u`
+gid=`env -i id -g`
+if [ $uid -eq 0 -o $gid -eq 0 ]; then
+ exit 1
+fi
+
+export PSEUDO_UNLOAD=1
+# Verify that once PSEUDO_UNLOAD has been issued, that
+# we can't restore pseudo into memory
+uid=`env -i PSEUDO_DISABLED=0 id -u`
+gid=`env -i PSEUDO_DISABLED=0 id -g`
+if [ $uid -eq 0 -o $gid -eq 0 ]; then
+ exit 1
+fi
+
+exit 0
diff --git a/test/test-pseudo_unload-fork.sh b/test/test-pseudo_unload-fork.sh
new file mode 100755
index 0000000..9f79198
--- /dev/null
+++ b/test/test-pseudo_unload-fork.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Verify normal operation...
+uid=`id -u`
+gid=`id -g`
+if [ $uid -ne 0 -o $gid -ne 0 ]; then
+ exit 1
+fi
+
+export PSEUDO_UNLOAD=1
+# Verify we dropped OUT of pseudo control
+uid=`id -u`
+gid=`id -g`
+if [ $uid -eq 0 -o $gid -eq 0 ]; then
+ exit 1
+fi
+
+exit 0
diff --git a/test/test-reexec-chroot.sh b/test/test-reexec-chroot.sh
new file mode 100755
index 0000000..bde93f1
--- /dev/null
+++ b/test/test-reexec-chroot.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Test if we re-invoke pseudo that chroot still works
+
+# Return vals: 2 - invalid arg list
+# 1 - chroot failed
+# 0 - chroot succeeded
+cat > chroot_test.c << EOF
+#include <unistd.h>
+int main(int argc, char *argv[]) {
+ if (argc != 2)
+ return 2;
+ return (chroot(argv[1]) == -1);
+}
+EOF
+
+gcc -o chroot_test chroot_test.c
+
+# The following should just run chroot_test since pseudo is already loaded
+./bin/pseudo ./chroot_test `pwd`
+
+if [ "$?" = "0" ]
+then
+ #echo "Passed."
+ rm -f chroot_test chroot_test.c
+ exit 0
+fi
+#echo "Failed"
+rm -f chroot_test chroot_test.c
+exit 1