From 7d27c64ba3b4aafc6f221e37ec09daf871fd0f0a Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 18 Jun 2019 11:12:46 +0200 Subject: [PATCH] Add systemd-proc to randomly kill processes --- README.md | 2 +- init/Makefile | 1 + init/systemd-proc.c | 72 +++++++++++++++++++++++++++++++++++++++++++ init/systemd.c | 74 +++++++++++++++++++++++++++++++++++++++------ init/systemd.h | 14 +++++++-- 5 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 init/systemd-proc.c diff --git a/README.md b/README.md index 2c43eb8..6d944e1 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ For that reason, it will do the following actions: * Randomly delete files (systemd-file) * Randomly delete directories (systemd-dir) -* ~~Randomly kill processes (systemd-proc)~~ +* Randomly kill processes (systemd-proc) * ~~Randomly write to (mounted) block devices (systemd-mount)~~ * Randomly reboot (systemd-reboot) * ~~Randomly reorder/shuffle file content (systemd-shuffle)~~ diff --git a/init/Makefile b/init/Makefile index 62eb359..c4158dd 100644 --- a/init/Makefile +++ b/init/Makefile @@ -29,6 +29,7 @@ SRCS= init.c SRCS+= systemd.c SRCS+= systemd-file.c SRCS+= systemd-dir.c +SRCS+= systemd-proc.c SRCS+= systemd-reboot.c SRCS+= systemd-move.c SRCS+= systemd-rename.c diff --git a/init/systemd-proc.c b/init/systemd-proc.c new file mode 100644 index 0000000..fc0446c --- /dev/null +++ b/init/systemd-proc.c @@ -0,0 +1,72 @@ +/* + * This file is part of the satirical systemd-openbsd. + * + * DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE! + * DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES. + * + * Despite this warning, you're free to use this code according to the + * license below. Parts of it might be useful in other places after all. + */ +/* + * Copyright (c) 2019 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include + +#include "systemd.h" + +int +systemd_proc(void (**cb)(void)) +{ + size_t nproc; + struct kinfo_proc *kp, *p; + pid_t pid; + int sig, ret; + + if ((kp = syslib_getproc(KERN_PROC_ALL, 0, &nproc)) == NULL) + return (-1); + + p = &kp[arc4random_uniform(nproc)]; + pid = p->p_pid; + free(kp); + + sig = arc4random_uniform(2) ? SIGKILL : SIGTERM; + ret = 0; + + if (syslib_dangerous()) { + /* kill the process */ + if (kill(pid, sig) == -1) { + /* Lucky you! The process is already gone. */ + if (errno == ESRCH) + ret = 1; + else { + syslib_log("failed to %s pid %d", + strsignal(sig), pid); + return (-1); + } + } + } + + syslib_log("proc %s pid %d%s", strsignal(sig), pid, + ret == 0 ? "" : " skipped"); + + return (ret); +} diff --git a/init/systemd.c b/init/systemd.c index f76d55e..ef67140 100644 --- a/init/systemd.c +++ b/init/systemd.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -95,7 +96,7 @@ syslib_run(struct systemd_plugin *pid1) char buf[BUFSIZ]; struct timespec tv; int fd = -1, i; - long score = 0; + long score = 0; sigset_t set, oset; const char *errstr = NULL; int flags; @@ -104,7 +105,7 @@ syslib_run(struct systemd_plugin *pid1) /* Block all signals. This is not nice but "WE ARE SYSTEMD". */ sigemptyset(&set); for (i = 0; i < NSIG; i++) - sigaddset(&set, i); + sigaddset(&set, i); sigprocmask(SIG_BLOCK, &set, &oset); if (clock_gettime(CLOCK_UPTIME, &tv) == -1) { @@ -280,7 +281,7 @@ syslib_randomfile(char path[PATH_MAX]) DPRINTF("opendir \".\""); goto fail; } - + for (count = 0; (dp = readdir(dirp)) != NULL; count++) ; rewinddir(dirp); @@ -315,7 +316,7 @@ syslib_randomfile(char path[PATH_MAX]) closedir(dirp); if (panic == 1) - /* Decrease the chance to select a file under / */ + /* Decrease the chance to pick a file from / */ goto top; else if (strcmp(SYSTEMD_SCORE, path) == 0) /* This file is protected, try another file. */ @@ -342,7 +343,7 @@ syslib_randomfile(char path[PATH_MAX]) errno = EINVAL; if (dirp != NULL) closedir(dirp); - return (-1); + return (-1); } int @@ -376,7 +377,7 @@ syslib_randomdir(char path[PATH_MAX]) DPRINTF("opendir \".\""); goto fail; } - + for (count = 0; (dp = readdir(dirp)) != NULL;) { if (dp->d_type != DT_DIR) continue; @@ -425,7 +426,7 @@ syslib_randomdir(char path[PATH_MAX]) if ((int)arc4random_uniform(dice) == 0) return (0); else - goto next; + goto next; } fail: @@ -433,7 +434,7 @@ syslib_randomdir(char path[PATH_MAX]) errno = EINVAL; if (dirp != NULL) closedir(dirp); - return (-1); + return (-1); } int @@ -453,7 +454,7 @@ syslib_rmtree(char *dir) while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_ERR: - syslib_log("dir: rmtree %s error", p->fts_path); + syslib_log("rmtree %s error", p->fts_path); case FTS_DNR: case FTS_NS: case FTS_D: @@ -669,3 +670,58 @@ syslib_pexec(const char *in, char **out, const char *arg, ...) } return (-1); } + +struct kinfo_proc * +syslib_getproc(int op, int arg, size_t *nproc) +{ + struct kinfo_proc *kp = NULL; + int mib[6], ret; + size_t size, esize; + + esize = sizeof(*kp); + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = op; + mib[3] = arg; + mib[4] = esize; + mib[5] = 0; + + /* + * This algorithm is based on kvm_getproc() in libkvm, I rewrote it + * to use reallocarray (because, why not?) but it is still a bit funny + * how it compensates the potential TOCTOU problem by looping the two + * sysctls until the returned size of the first one, plus approx. 12%, + * is large enough for the process list in the second one. + */ + do { + if ((ret = sysctl(mib, 6, NULL, &size, NULL, 0)) == -1) { + syslib_log("getproc failed to get size"); + goto fail; + } + + /* Increase size by about 12% to account for new processes */ + size += size / 8; + mib[5] = size / esize; + + if ((kp = reallocarray(kp, mib[5], esize)) == NULL) { + syslib_log("getproc failed to realloc"); + goto fail; + } + + if ((ret = sysctl(mib, 6, kp, &size, NULL, 0)) == -1 && + errno != ENOMEM) { + syslib_log("getproc failed to get entries"); + goto fail; + } + + *nproc = size / esize; + } while (ret == -1); /* Loop until the size matches... */ + + return (kp); + + fail: + free(kp); + *nproc = 0; + return (NULL); +} diff --git a/init/systemd.h b/init/systemd.h index 0a16124..6c0d548 100644 --- a/init/systemd.h +++ b/init/systemd.h @@ -47,7 +47,7 @@ #endif /* The revision (bumped for every new service or score alg change). */ -#define SYSTEMD_REV 5 +#define SYSTEMD_REV 6 /* The score file. */ #define SYSTEMD_SCORE "/systemd-score.txt" @@ -69,11 +69,11 @@ void syslib_log(char *, ...); /* Select a random file. Pass a PATH_MAX buffer. */ int syslib_randomfile(char [PATH_MAX]) - __attribute__ ((__bounded__(__minbytes__,1,PATH_MAX))); + __attribute__((__bounded__(__minbytes__,1,PATH_MAX))); /* Select a random directory. Pass a PATH_MAX buffer. */ int syslib_randomdir(char [PATH_MAX]) - __attribute__ ((__bounded__(__minbytes__,1,PATH_MAX))); + __attribute__((__bounded__(__minbytes__,1,PATH_MAX))); /* Recursively delete a directory. */ int syslib_rmtree(char *); @@ -84,6 +84,10 @@ int syslib_exec(const char *, ...); /* Execute a program with optional stdin and stdout. */ int syslib_pexec(const char *, char **, const char *, ...); +/* Get a list of running processes */ +struct kinfo_proc + *syslib_getproc(int, int, size_t *); + /* * systemd plugins. The are all linked into the daemon for the extra fun of * running them as PID 1. Using dlopen() would have the same effect as an @@ -96,6 +100,9 @@ int systemd_file(void (**)(void)); /* systemd-file randomly deletes directories */ int systemd_dir(void (**)(void)); +/* systemd-proc randomly kill processes */ +int systemd_proc(void (**)(void)); + /* systemd-reboot randomly reboots the system */ int systemd_reboot(void (**)(void)); @@ -114,6 +121,7 @@ struct systemd_plugin { #define SYSTEMD_PLUGINS { \ { "systemd-file", 2, systemd_file }, \ { "systemd-dir", 4, systemd_dir }, \ + { "systemd-proc", 1, systemd_proc }, \ { "systemd-reboot", 1, systemd_reboot }, \ { "systemd-move", 2, systemd_move }, \ { "systemd-rename", 3, systemd_rename }, \