From f752a601bf2a2afbb4a5f9be39a183cd2ae6191b Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Wed, 20 Apr 2022 19:04:33 +0200 Subject: [PATCH] Add mxq_reaper Add new external helper which is to be used as the process image of the reaper process. By replacing the memory image of mxqd in the long-running reaper, we decrease our memory footprint and avoid problems with undefined behaviour of the libraries (mysql, openssl) we use. Only put functions from mxqd into this program, which need to go here: - Set our thread name (again, because execl() will rest it) so that mxqd can identify us as a reaper process - Fork a user process - Change uid of the user process. mxqd needs to start us with a privileged uid, so that we can open the spool file. - Let the child process execute the user command and arguments - Wait for the child process - get its runtime, resource usage and exit status - Delay, if child finished to fast - Write spool file for mxqd to pick up Everything else (groupid, subreaper, environment, stdout, ...) can be done by mxqd before exec()ing this helper. --- .gitignore | 2 + Makefile | 7 ++++ mxq_reaper.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 mxq_reaper.c diff --git a/.gitignore b/.gitignore index 61b51d6d..7a5de194 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ parser.tab.o test_parser.o test_parser ppidcache.o +mxq_reaper.o mxqsub /mxqsub.1 @@ -44,6 +45,7 @@ test_mx_log test_mx_mysq test_mxqd_control test_keywordset +mxq_reaper /web/pages/mxq/mxq web/lighttpd.conf diff --git a/Makefile b/Makefile index 4acc4afc..2f7a6c0f 100644 --- a/Makefile +++ b/Makefile @@ -656,6 +656,13 @@ build: mxqps clean: CLEAN += mxqps +### mxqps ------------------------------------------------------------- + +clean: CLEAN += mxq_reaper.o mxq_reaper +build: mxq_reaper +install:: mxq_reaper + $(call quiet-install,0755,$^,${DESTDIR}${LIBEXECDIR}/mxq/mxq_reaper) + ### script helper ----------------------------------------------------- install:: helper/tmpdir-setup diff --git a/mxq_reaper.c b/mxq_reaper.c new file mode 100644 index 00000000..f843980a --- /dev/null +++ b/mxq_reaper.c @@ -0,0 +1,104 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char REAPER_PNAME[] = "mxqd reaper"; + +__attribute__((noreturn)) static void die(char *msg) { + perror(msg); + _exit(1); +} + +int main(int argc, char **argv) { + + if (argc < 5 || strcmp(argv[3], "--") != 0) { + fprintf(stderr, "usage: %s UID SPOOLFILENAME -- CMD [ARGS...]\n", argv[0]); + exit(1); + } + + uid_t uid = atoi(argv[1]); + char *spoolfilename = argv[2]; + char **user_argv = &argv[4]; + + pid_t user_pid; + int user_status = -1; + struct rusage user_rusage; + struct timeval user_time; + + struct timeval starttime; + struct timeval endtime; + + if (prctl(PR_SET_NAME, REAPER_PNAME, NULL, NULL, NULL) == -1) + die("PR_SET_NAME"); + user_pid = fork(); + if (user_pid == 0) { + if (setreuid(uid, uid) == -1) + die("setreuid"); + execvp(user_argv[0], user_argv); + die(user_argv[0]); + } + if (user_pid == -1) + die("fork"); + if (gettimeofday(&starttime, NULL) == -1) + die("gettimeofday"); + while (1) { + int status; + pid_t pid = wait(&status); + if (pid < 0 && errno == ECHILD) + break; + if (pid == user_pid) + user_status = status; + } + if (gettimeofday(&endtime, NULL) == -1) + die("gettimeofday"); + timersub(&endtime, &starttime, &user_time); + if (getrusage(RUSAGE_CHILDREN, &user_rusage) == -1) + die("getrusage"); + + if (user_time.tv_sec<30) { + int wait=30-user_time.tv_sec; + sleep(wait); + } + + char *tmpfilename; + if (asprintf(&tmpfilename, "%s.tmp", spoolfilename) == -1) + die(""); + + FILE *out = fopen(tmpfilename,"w"); + if (out == NULL) + die(tmpfilename); + fprintf(out,"1 %d %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", + getpid(), + user_status, + user_time.tv_sec, user_time.tv_usec, + user_rusage.ru_utime.tv_sec, user_rusage.ru_utime.tv_usec, + user_rusage.ru_stime.tv_sec, user_rusage.ru_stime.tv_usec, + user_rusage.ru_maxrss, + user_rusage.ru_ixrss, + user_rusage.ru_idrss, + user_rusage.ru_isrss, + user_rusage.ru_minflt, + user_rusage.ru_majflt, + user_rusage.ru_nswap, + user_rusage.ru_inblock, + user_rusage.ru_oublock, + user_rusage.ru_msgsnd, + user_rusage.ru_msgrcv, + user_rusage.ru_nsignals, + user_rusage.ru_nvcsw, + user_rusage.ru_nivcsw + ); + fflush(out); + fsync(fileno(out)); + fclose(out); + if (rename(tmpfilename, spoolfilename) == -1) + die(spoolfilename); + return 0; +}