Skip to content
Browse files

Implement PSEUDO_UNLOAD, replacing existing PSEUDO_RELOADED semantics.

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.

Rename the PSEUDO_DISABLED tests, and create a similar set for the new
PSEUDO_UNLOAD.

Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
  • Loading branch information...
1 parent 4a646c8 commit 6177474388f243c9ff783da074a531ef8fd173fd Mark Hatle committed with wr-seebs
View
7 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.
View
29 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_*
View
7 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.
View
7 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.
View
7 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.
View
5 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();
}
}
View
5 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 */
View
5 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 */
View
39 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
View
14 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();
View
16 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 */
View
2 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 */
};
View
27 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
View
0 test/test-forkoff-env_i.sh → test/test-pseudo_disable-fork-env_i.sh
File renamed without changes.
View
0 test/test-forkoff.sh → test/test-pseudo_disable-fork.sh
File renamed without changes.
View
29 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
View
18 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
View
30 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

0 comments on commit 6177474

Please sign in to comment.
Something went wrong with that request. Please try again.