diff options
-rw-r--r-- | guts/README | 16 | ||||
-rw-r--r-- | guts/execl.c | 42 | ||||
-rw-r--r-- | guts/execle.c | 44 | ||||
-rw-r--r-- | guts/execlp.c | 42 | ||||
-rw-r--r-- | guts/vfork.c | 17 | ||||
-rwxr-xr-x | makewrappers | 10 | ||||
-rw-r--r-- | pseudo.1 | 9 | ||||
-rw-r--r-- | pseudo.h | 1 | ||||
-rw-r--r-- | pseudo_client.c | 20 | ||||
-rw-r--r-- | pseudo_wrappers.c | 283 | ||||
-rw-r--r-- | templates/wrapfuncs.c | 2 | ||||
-rw-r--r-- | templates/wrapfuncs.h | 6 | ||||
-rw-r--r-- | templates/wrapper_table | 6 | ||||
-rw-r--r-- | wrapfuncs.in | 5 |
14 files changed, 343 insertions, 160 deletions
diff --git a/guts/README b/guts/README index 8bfbfe6..0a1fe5f 100644 --- a/guts/README +++ b/guts/README @@ -83,7 +83,7 @@ wrappers: close dup dup2 - excl* (all redirect through execve) + execl* (no guts implementations; see pseudo_wrappers.c) execv execve execvp @@ -97,7 +97,6 @@ wrappers: fcntl fork link - vfork The following functions don't have any direct database interactions, but are used to simulate the permissions system: @@ -206,3 +205,16 @@ needed because we don't actually track or manage extended attributes, but a few programs attempt to use *setxattr() to set regular permissions, and only use a regular chmod if the *setxattr() call returns -1 and sets errno to ENOTSUP. + + fgetxattr + flistxattr + fremovexattr + fsetxattr + getxattr + lgetxattr + listxattr + llistxattr + lremovexattr + lsetxattr + removexattr + setxattr diff --git a/guts/execl.c b/guts/execl.c deleted file mode 100644 index ca2df70..0000000 --- a/guts/execl.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2010 Wind River Systems; see - * guts/COPYRIGHT for information. - * - * static int - * wrap_execl(const char *file, const char *arg, va_list ap) { - * int rc = -1; - */ - - size_t i = 0; - size_t alloc_size = 256; - const char **argv = malloc(sizeof (const char *) * alloc_size); - if (!argv) { - pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n", - (unsigned long) alloc_size); - errno = ENOMEM; - return -1; - } - - argv[i++] = arg; - - while (argv[i-1]) { - argv[i++] = va_arg (ap, const char *); - if ( i > alloc_size - 1 ) { - alloc_size = alloc_size + 256; - argv = realloc(argv, sizeof (const char *) * alloc_size); - if (!argv) { - pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n", - (unsigned long) alloc_size); - errno = ENOMEM; - return -1; - } - } - } - - rc = wrap_execv (file, (char *const *) argv); - - free (argv); - -/* return rc; - * } - */ diff --git a/guts/execle.c b/guts/execle.c deleted file mode 100644 index 5b44d78..0000000 --- a/guts/execle.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2010 Wind River Systems; see - * guts/COPYRIGHT for information. - * - * static int - * wrap_execle(const char *file, const char *arg, va_list ap) { - * int rc = -1; - */ - - size_t i = 0; - size_t alloc_size = 256; - const char **argv = malloc(sizeof (const char *) * alloc_size); - char *const *envp; - if (!argv) { - pseudo_debug(1, "execle failed: couldn't allocate memory for %lu arguments\n", - (unsigned long) alloc_size); - errno = ENOMEM; - return -1; - } - - argv[i++] = arg; - - while (argv[i-1]) { - argv[i++] = va_arg (ap, const char *); - if ( i > alloc_size - 1 ) { - alloc_size = alloc_size + 256; - argv = realloc(argv, sizeof (const char *) * alloc_size); - if (!argv) { - pseudo_debug(1, "execle failed: couldn't allocate memory for %lu arguments\n", - (unsigned long) alloc_size); - errno = ENOMEM; - return -1; - } - } - } - envp = va_arg (ap, char *const *); - - rc = wrap_execve (file, (char *const *) argv, envp); - - free (argv); - -/* return rc; - * } - */ diff --git a/guts/execlp.c b/guts/execlp.c deleted file mode 100644 index d09a64d..0000000 --- a/guts/execlp.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2010 Wind River Systems; see - * guts/COPYRIGHT for information. - * - * static int - * wrap_execlp(const char *file, const char *arg, va_list ap) { - * int rc = -1; - */ - - size_t i = 0; - size_t alloc_size = 256; - const char **argv = malloc(sizeof (const char *) * alloc_size); - if (!argv) { - pseudo_debug(1, "execlp failed: couldn't allocate memory for %lu arguments\n", - (unsigned long) alloc_size); - errno = ENOMEM; - return -1; - } - - argv[i++] = arg; - - while (argv[i-1]) { - argv[i++] = va_arg (ap, const char *); - if ( i > alloc_size - 1 ) { - alloc_size = alloc_size + 256; - argv = realloc(argv, sizeof (const char *) * alloc_size); - if (!argv) { - pseudo_debug(1, "execlp failed: couldn't allocate memory for %lu arguments\n", - (unsigned long) alloc_size); - errno = ENOMEM; - return -1; - } - } - } - - rc = wrap_execvp (file, (char *const *) argv); - - free (argv); - -/* return rc; - * } - */ diff --git a/guts/vfork.c b/guts/vfork.c deleted file mode 100644 index 4e0f767..0000000 --- a/guts/vfork.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2008-2010 Wind River Systems; see - * guts/COPYRIGHT for information. - * - * static int - * wrap_vfork(void) { - * int rc = -1; - */ - - /* like fakeroot, we really can't handle vfork's implications */ - rc = real_fork(); - if (rc == 0) - pseudo_client_reset(); - -/* return rc; - * } - */ diff --git a/makewrappers b/makewrappers index 5ec58f8..2a17dbd 100755 --- a/makewrappers +++ b/makewrappers @@ -33,8 +33,6 @@ class ArgumentList: self.variadic_decl = "" self.variadic_start = "" self.variadic_end = "" - self.prologue_call_real = \ - "/* pass the call on to the underlying syscall */" # (void) is an empty list, not a list of a single argument which is void if text == "void": return @@ -68,11 +66,8 @@ class ArgumentList: (self.variadic_arg.name, self.variadic_arg.type) else: - self.variadic_end = "va_end(ap);\n" - self.prologue_call_real = ('/* no way to pass a ... */' - '\n\t\t\t\tassert(!"cannot chain ' - 'to real versions of variadic' - 'functions");') + # lie blatantly; we don't handle this case + self.variadic = False # for a wrap function, the outer foo() wrapper will convert to a va_list, # but the inner wrap_foo() just passes the va_list through. @@ -212,6 +207,7 @@ class Function: self.dirfd = 'AT_FDCWD' self.flags = '0' self.paths_to_munge = [] + self.nowrappers = None # used for the copyright date when creating stub functions self.date = datetime.date.today().year @@ -400,6 +400,15 @@ in the .I var/pseudo directory, while clients log to standard error. .TP 8 +.B PSEUDO_DISABLE +If this variable is set, the +.I pseudo +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 +.I fork() +or related functions. +.TP 8 .B PSEUDO_ENOSYS_ABORT If this variable is set, the .I pseudo @@ -31,6 +31,7 @@ char * pseudo_get_value(const char * key); extern void pseudo_debug_verbose(void); extern void pseudo_debug_terse(void); extern int pseudo_util_debug_fd; +extern int pseudo_disabled; #ifndef NDEBUG extern int pseudo_debug_real(int, char *, ...) __attribute__ ((format (printf, 2, 3))); #define pseudo_debug pseudo_debug_real diff --git a/pseudo_client.c b/pseudo_client.c index b169259..5b222e9 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -58,6 +58,8 @@ char *pseudo_chroot = NULL; char *pseudo_passwd = NULL; size_t pseudo_chroot_len = 0; char *pseudo_cwd_rel = NULL; +/* used for PSEUDO_DISABLE */ +int pseudo_disabled = 0; static char **fd_paths = NULL; static int nfds = 0; @@ -317,6 +319,24 @@ pseudo_client_reset() { close(connect_fd); connect_fd = -1; } + + /* in child processes, PSEUDO_DISABLED may have come + * into existence, in which case we'd disable pseudo, + * or it may have gone away, in which case we'd enable + * pseudo. + */ + if (getenv("PSEUDO_DISABLED")) { + if (!pseudo_disabled) { + pseudo_antimagic(); + pseudo_disabled = 1; + } + } else { + if (pseudo_disabled) { + pseudo_magic(); + pseudo_disabled = 0; + } + } + if (!pseudo_inited) { char *env; diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c index dbcfac8..f5f7aef 100644 --- a/pseudo_wrappers.c +++ b/pseudo_wrappers.c @@ -246,3 +246,286 @@ pseudo_populate_wrappers(void) { return done; } +static char ** +execl_to_v(va_list ap, const char *argv0, char *const **envp) { + size_t i = 0; + size_t alloc_size = 256; + + char **argv = malloc((sizeof *argv) * alloc_size); + + if (!argv) { + pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n", + (unsigned long) alloc_size); + return NULL; + } + argv[i++] = (char *) argv0; + + while (argv[i-1]) { + argv[i++] = va_arg(ap, char *const); + if (i > alloc_size - 1) { + alloc_size = alloc_size + 256; + argv = realloc(argv, (sizeof *argv) * alloc_size); + if (!argv) { + pseudo_debug(1, "execl failed: couldn't allocate memory for %lu arguments\n", + (unsigned long) alloc_size); + return NULL; + } + } + } + if (envp) { + *envp = va_arg(ap, char **); + } + return argv; +} + +/* The following wrappers require Special Handling */ + +int +execl(const char *file, const char *arg, ...) { + sigset_t saved; + va_list ap; + char **argv; + + int rc = -1; + + va_start(ap, arg); + argv = execl_to_v(ap, arg, 0); + va_end(ap); + if (!argv) { + errno = ENOMEM; + return -1; + } + + pseudo_debug(4, "called: execl\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return -1; + } + if (pseudo_populate_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); + } + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: execl\n"); + errno = save_errno; + free(argv); + return rc; + } else { + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: execl\n"); + /* rc was initialized to the "failure" value */ + pseudo_enosys("execl"); + free(argv); + return rc; + } +} + +int +execlp(const char *file, const char *arg, ...) { + sigset_t saved; + va_list ap; + char **argv; + + int rc = -1; + + va_start(ap, arg); + argv = execl_to_v(ap, arg, 0); + va_end(ap); + if (!argv) { + errno = ENOMEM; + return -1; + } + + pseudo_debug(4, "called: execlp\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return -1; + } + if (pseudo_populate_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); + } + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: execlp\n"); + errno = save_errno; + free(argv); + return rc; + } else { + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: execlp\n"); + /* rc was initialized to the "failure" value */ + pseudo_enosys("execlp"); + free(argv); + return rc; + } +} + +int +execle(const char *file, const char *arg, ...) { + sigset_t saved; + va_list ap; + char **argv; + char **envp; + + int rc = -1; + + va_start(ap, arg); + argv = execl_to_v(ap, arg, &envp); + va_end(ap); + if (!argv) { + errno = ENOMEM; + return -1; + } + + pseudo_debug(4, "called: execle\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return -1; + } + if (pseudo_populate_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); + } + + save_errno = errno; + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: execle\n"); + errno = save_errno; + free(argv); + return rc; + } else { + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: execle\n"); + /* rc was initialized to the "failure" value */ + pseudo_enosys("execle"); + free(argv); + return rc; + } +} + +int +fork(void) { + sigset_t saved; + + int rc = -1; + + pseudo_debug(4, "called: fork\n"); + pseudo_sigblock(&saved); + if (pseudo_getlock()) { + errno = EBUSY; + sigprocmask(SIG_SETMASK, &saved, NULL); + return -1; + } + if (pseudo_populate_wrappers()) { + int save_errno; + if (antimagic > 0) { + if (real_fork) { + /* pass the call on to the underlying syscall */ + rc = (*real_fork)(); + /* special case: we may want to enable or disable + * pseudo in the child process + */ + if (rc == 0) + pseudo_client_reset(); + } else { + /* rc was initialized to the "failure" value */ + pseudo_enosys("fork"); + } + } else { + + /* exec*() use this to restore the sig mask */ + pseudo_saved_sigmask = saved; + rc = wrap_fork(); + + } + save_errno = errno; + + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: fork\n"); + errno = save_errno; + return rc; + } else { + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &saved, NULL); + pseudo_debug(4, "completed: fork\n"); + /* rc was initialized to the "failure" value */ + pseudo_enosys("fork"); + + return rc; + } +} + +int +vfork(void) { + /* we don't provide support for the distinct semantics + * of vfork() + */ + return fork(); +} + +static int (*real_fork)(void) = NULL; +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; + +static int +wrap_fork(void) { + int rc = -1; + +#include "guts/fork.c" + + return rc; +} diff --git a/templates/wrapfuncs.c b/templates/wrapfuncs.c index 935561b..c0170d9 100644 --- a/templates/wrapfuncs.c +++ b/templates/wrapfuncs.c @@ -34,7 +34,7 @@ ${name}(${decl_args}) { int save_errno; if (antimagic > 0) { if (real_$name) { - ${prologue_call_real} + /* call the real syscall */ ${rc_assign} (*real_${name})(${call_args}); } else { /* rc was initialized to the "failure" value */ diff --git a/templates/wrapfuncs.h b/templates/wrapfuncs.h index 63ba903..665da14 100644 --- a/templates/wrapfuncs.h +++ b/templates/wrapfuncs.h @@ -8,3 +8,9 @@ /* ${comment} */ static ${type} wrap_${name}(${wrap_args}); static ${type} (*real_${name})(${decl_args}); +@footer +/* special cases: functions with manually-written wrappers */ + +/* int fork(void) */ +static int wrap_fork(void); +static int (*real_fork)(void); diff --git a/templates/wrapper_table b/templates/wrapper_table index a16dca9..2419c7d 100644 --- a/templates/wrapper_table +++ b/templates/wrapper_table @@ -16,5 +16,11 @@ static struct { (int (*)(void)) wrap_${name} }, @footer + /* special cases: Functions which need manually-coded wrappers */ + { /* int fork(void); */ + "fork", + (int (**)(void)) &real_fork, + (int (*)(void)) wrap_fork + }, { NULL, NULL, NULL }, }; diff --git a/wrapfuncs.in b/wrapfuncs.in index 17742ac..eb9280e 100644 --- a/wrapfuncs.in +++ b/wrapfuncs.in @@ -32,8 +32,6 @@ int rmdir(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */ int chdir(const char *path); int fchdir(int dirfd); int fcntl(int fd, int cmd, ...{struct flock *lock}); -int fork(void); -int vfork(void); # just so we know the inums of symlinks int symlink(const char *oldname, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */ int symlinkat(const char *oldname, int dirfd, const char *newpath); /* flags=AT_SYMLINK_NOFOLLOW */ @@ -88,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 execl(const char *file, const char *arg, ...); -int execlp(const char *file, const char *arg, ...); -int execle(const char *file, const char *arg, ...); 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); |