Add systemd-proc to randomly kill processes

This commit is contained in:
reykfloeter 2019-06-18 11:12:46 +02:00
parent 4efcc235d4
commit 7d27c64ba3
5 changed files with 150 additions and 13 deletions

View File

@ -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)~~

View File

@ -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

72
init/systemd-proc.c Normal file
View File

@ -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 <contact@reykfloeter.com>
*
* 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 <sys/types.h>
#include <sys/sysctl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#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);
}

View File

@ -25,6 +25,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/wait.h>
#include <stdlib.h>
@ -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);
}

View File

@ -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 }, \